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:
@@ -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',
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user