1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 09:38:58 +01:00

Fix MatterValve state handling and allow None values for attributes (#164066)

This commit is contained in:
Ludovic BOUÉ
2026-02-25 15:57:05 +01:00
committed by GitHub
parent 70f5f2c1ee
commit 0563037c5a
3 changed files with 67 additions and 18 deletions
+19 -15
View File
@@ -69,34 +69,37 @@ class MatterValve(MatterEntity, ValveEntity):
def _update_from_device(self) -> None:
"""Update from device."""
self._calculate_features()
current_state: int
self._attr_is_opening = False
self._attr_is_closing = False
current_state: int | None
current_state = self.get_matter_attribute_value(
ValveConfigurationAndControl.Attributes.CurrentState
)
target_state: int
target_state: int | None
target_state = self.get_matter_attribute_value(
ValveConfigurationAndControl.Attributes.TargetState
)
if (
current_state == ValveStateEnum.kTransitioning
and target_state == ValveStateEnum.kOpen
if current_state is None:
self._attr_is_closed = None
elif current_state == ValveStateEnum.kTransitioning and (
target_state == ValveStateEnum.kOpen
):
self._attr_is_opening = True
self._attr_is_closing = False
elif (
current_state == ValveStateEnum.kTransitioning
and target_state == ValveStateEnum.kClosed
self._attr_is_closed = None
elif current_state == ValveStateEnum.kTransitioning and (
target_state == ValveStateEnum.kClosed
):
self._attr_is_opening = False
self._attr_is_closing = True
self._attr_is_closed = None
elif current_state == ValveStateEnum.kClosed:
self._attr_is_opening = False
self._attr_is_closing = False
self._attr_is_closed = True
else:
self._attr_is_opening = False
self._attr_is_closing = False
elif current_state == ValveStateEnum.kOpen:
self._attr_is_closed = False
else:
self._attr_is_closed = None
# handle optional position
if self.supported_features & ValveEntityFeature.SET_POSITION:
self._attr_current_valve_position = self.get_matter_attribute_value(
@@ -145,6 +148,7 @@ DISCOVERY_SCHEMAS = [
ValveConfigurationAndControl.Attributes.CurrentState,
ValveConfigurationAndControl.Attributes.TargetState,
),
allow_none_value=True,
optional_attributes=(ValveConfigurationAndControl.Attributes.CurrentLevel,),
device_type=(device_types.WaterValve,),
),
@@ -1,5 +1,5 @@
# serializer version: 1
# name: test_valves[mock_valve][valve.mock_valve-entry]
# name: test_valves[mock_valve][mock_valve][valve.mock_valve-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -35,7 +35,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_valves[mock_valve][valve.mock_valve-state]
# name: test_valves[mock_valve][mock_valve][valve.mock_valve-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'water',
+46 -1
View File
@@ -1,5 +1,6 @@
"""Test Matter valve."""
from typing import Any
from unittest.mock import MagicMock, call
from chip.clusters import Objects as clusters
@@ -18,13 +19,21 @@ from .common import (
)
@pytest.mark.usefixtures("matter_devices")
@pytest.fixture(name="attributes")
def attributes_fixture(request: pytest.FixtureRequest) -> dict[str, Any]:
"""Override node attributes for a parametrized test."""
return getattr(request, "param", {})
@pytest.mark.parametrize("node_fixture", ["mock_valve"])
async def test_valves(
hass: HomeAssistant,
matter_node: MatterNode,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test valves."""
assert matter_node
snapshot_matter_entities(hass, entity_registry, snapshot, Platform.VALVE)
@@ -152,3 +161,39 @@ async def test_valve(
command=clusters.ValveConfigurationAndControl.Commands.Close(),
)
matter_client.send_device_command.reset_mock()
@pytest.mark.parametrize("node_fixture", ["mock_valve"])
@pytest.mark.parametrize(
"attributes",
[{"1/129/4": None, "1/129/5": None}],
indirect=True,
)
async def test_valve_discovery_with_nullable_states(
hass: HomeAssistant,
matter_client: MagicMock,
matter_node: MatterNode,
) -> None:
"""Test valve discovery when CurrentState and TargetState are nullable."""
assert matter_node.node_id == 60
state = hass.states.get("valve.mock_valve")
assert state
assert state.state == "unknown"
assert state.attributes["friendly_name"] == "Mock Valve"
await hass.services.async_call(
"valve",
"open_valve",
{
"entity_id": "valve.mock_valve",
},
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.ValveConfigurationAndControl.Commands.Open(),
)