mirror of
https://github.com/home-assistant/core.git
synced 2026-02-26 12:55:16 +00:00
Fix Matter speaker mute toggle (#161128)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -46,30 +46,42 @@ async def async_setup_entry(
|
||||
class MatterSwitchEntityDescription(SwitchEntityDescription, MatterEntityDescription):
|
||||
"""Describe Matter Switch entities."""
|
||||
|
||||
inverted: bool = False
|
||||
|
||||
|
||||
class MatterSwitch(MatterEntity, SwitchEntity):
|
||||
"""Representation of a Matter switch."""
|
||||
|
||||
entity_description: MatterSwitchEntityDescription
|
||||
_platform_translation_key = "switch"
|
||||
|
||||
def _get_command_for_value(self, value: bool) -> ClusterCommand:
|
||||
"""Get the appropriate command for the desired value.
|
||||
|
||||
Applies inversion if needed (e.g., for inverted logic like mute).
|
||||
"""
|
||||
send_value = not value if self.entity_description.inverted else value
|
||||
return (
|
||||
clusters.OnOff.Commands.On()
|
||||
if send_value
|
||||
else clusters.OnOff.Commands.Off()
|
||||
)
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn switch on."""
|
||||
await self.send_device_command(
|
||||
clusters.OnOff.Commands.On(),
|
||||
)
|
||||
await self.send_device_command(self._get_command_for_value(True))
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn switch off."""
|
||||
await self.send_device_command(
|
||||
clusters.OnOff.Commands.Off(),
|
||||
)
|
||||
await self.send_device_command(self._get_command_for_value(False))
|
||||
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
self._attr_is_on = self.get_matter_attribute_value(
|
||||
self._entity_info.primary_attribute
|
||||
)
|
||||
value = self.get_matter_attribute_value(self._entity_info.primary_attribute)
|
||||
if self.entity_description.inverted:
|
||||
value = not value
|
||||
self._attr_is_on = value
|
||||
|
||||
|
||||
class MatterGenericCommandSwitch(MatterSwitch):
|
||||
@@ -121,9 +133,7 @@ class MatterGenericCommandSwitch(MatterSwitch):
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class MatterGenericCommandSwitchEntityDescription(
|
||||
SwitchEntityDescription, MatterEntityDescription
|
||||
):
|
||||
class MatterGenericCommandSwitchEntityDescription(MatterSwitchEntityDescription):
|
||||
"""Describe Matter Generic command Switch entities."""
|
||||
|
||||
# command: a custom callback to create the command to send to the device
|
||||
@@ -133,9 +143,7 @@ class MatterGenericCommandSwitchEntityDescription(
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class MatterNumericSwitchEntityDescription(
|
||||
SwitchEntityDescription, MatterEntityDescription
|
||||
):
|
||||
class MatterNumericSwitchEntityDescription(MatterSwitchEntityDescription):
|
||||
"""Describe Matter Numeric Switch entities."""
|
||||
|
||||
|
||||
@@ -146,11 +154,10 @@ class MatterNumericSwitch(MatterSwitch):
|
||||
|
||||
async def _async_set_native_value(self, value: bool) -> None:
|
||||
"""Update the current value."""
|
||||
send_value: Any = value
|
||||
if value_convert := self.entity_description.ha_to_device:
|
||||
send_value = value_convert(value)
|
||||
await self.write_attribute(
|
||||
value=send_value,
|
||||
)
|
||||
await self.write_attribute(value=send_value)
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn switch on."""
|
||||
@@ -248,19 +255,12 @@ DISCOVERY_SCHEMAS = [
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SWITCH,
|
||||
entity_description=MatterNumericSwitchEntityDescription(
|
||||
entity_description=MatterSwitchEntityDescription(
|
||||
key="MatterMuteToggle",
|
||||
translation_key="speaker_mute",
|
||||
device_to_ha={
|
||||
True: False, # True means volume is on, so HA should show mute as off
|
||||
False: True, # False means volume is off (muted), so HA should show mute as on
|
||||
}.get,
|
||||
ha_to_device={
|
||||
False: True, # HA showing mute as off means volume is on, so send True
|
||||
True: False, # HA showing mute as on means volume is off (muted), so send False
|
||||
}.get,
|
||||
inverted=True,
|
||||
),
|
||||
entity_class=MatterNumericSwitch,
|
||||
entity_class=MatterSwitch,
|
||||
required_attributes=(clusters.OnOff.Attributes.OnOff,),
|
||||
device_type=(device_types.Speaker,),
|
||||
),
|
||||
|
||||
@@ -232,3 +232,56 @@ async def test_evse_sensor(
|
||||
),
|
||||
timed_request_timeout_ms=3000,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("node_fixture", ["mock_speaker"])
|
||||
async def test_speaker_mute_uses_onoff_commands(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
matter_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test speaker mute switch uses On/Off commands instead of attribute writes."""
|
||||
|
||||
state = hass.states.get("switch.mock_speaker_mute")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
await hass.services.async_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
{"entity_id": "switch.mock_speaker_mute"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=matter_node.node_id,
|
||||
endpoint_id=1,
|
||||
command=clusters.OnOff.Commands.Off(),
|
||||
)
|
||||
|
||||
set_node_attribute(matter_node, 1, 6, 0, False)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get("switch.mock_speaker_mute")
|
||||
assert state
|
||||
assert state.state == "on"
|
||||
|
||||
await hass.services.async_call(
|
||||
"switch",
|
||||
"turn_off",
|
||||
{"entity_id": "switch.mock_speaker_mute"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert matter_client.send_device_command.call_count == 2
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=matter_node.node_id,
|
||||
endpoint_id=1,
|
||||
command=clusters.OnOff.Commands.On(),
|
||||
)
|
||||
|
||||
set_node_attribute(matter_node, 1, 6, 0, True)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get("switch.mock_speaker_mute")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
Reference in New Issue
Block a user