mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Add Valve platform to Matter integration (#123311)
* Create water_valve.py * Update water_valve.py ValveEntity * Update water_valve.py ValveDeviceClass * Update water_valve.py * Update water_valve.py OperationalStatus * Update water_valve.py * Update water_valve.py Commands * Update water_valve.py Platform.VALVE * Update water_valve.py * Update water_valve.py operational_status * Update water_valve.py current_valve_position * Update water_valve.py * Update water_valve.py * Update water_valve.py attributes * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Open command * Match Valve entity methods * Update water_valve.py * Update water_valve.py * Update water_valve.py * ruff-format * Update water_valve.py * Update water_valve.py * Update water_valve.py Attributes.CurrentLevel * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py async_set_valve_position * Update water_valve.py * Update water_valve.py Bitmaps * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update homeassistant/components/matter/water_valve.py Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> * Update homeassistant/components/matter/water_valve.py Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update discovery.py to add WaterValve * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update discovery.py * Update discovery.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Update water_valve.py * Rename water_valve.py to valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Update valve.py * Create test_valve.py * Update test_valve.py * Update test_valve.py * Update test_valve.py * Update test_valve.py * Update test_valve.py * Update test_valve.py * Update test_valve.py * Update test_valve.py * Update test_valve.py * Create valve.json * Update air-purifier.json * Revert "Update air-purifier.json" This reverts commit b68dce0ccc81bc6fb1db36191de1c296ce54cac3. * Update valve.json * Update valve.json * Update valve.json * Update test_valve.py * Update valve.json * Update test_valve.py * Update valve.json * Update valve.json * Update valve.json * Update test_valve.py * Update valve.py * Update valve.py * Update valve.py * add tests * cleanup * Clean up variable * Format * add tests for state updates * adjust * add tests for position --------- Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
0a44c9456c
commit
6d1e5886ec
@ -24,6 +24,7 @@ from .select import DISCOVERY_SCHEMAS as SELECT_SCHEMAS
|
||||
from .sensor import DISCOVERY_SCHEMAS as SENSOR_SCHEMAS
|
||||
from .switch import DISCOVERY_SCHEMAS as SWITCH_SCHEMAS
|
||||
from .update import DISCOVERY_SCHEMAS as UPDATE_SCHEMAS
|
||||
from .valve import DISCOVERY_SCHEMAS as VALVE_SCHEMAS
|
||||
|
||||
DISCOVERY_SCHEMAS: dict[Platform, list[MatterDiscoverySchema]] = {
|
||||
Platform.BINARY_SENSOR: BINARY_SENSOR_SCHEMAS,
|
||||
@ -39,6 +40,7 @@ DISCOVERY_SCHEMAS: dict[Platform, list[MatterDiscoverySchema]] = {
|
||||
Platform.SENSOR: SENSOR_SCHEMAS,
|
||||
Platform.SWITCH: SWITCH_SCHEMAS,
|
||||
Platform.UPDATE: UPDATE_SCHEMAS,
|
||||
Platform.VALVE: VALVE_SCHEMAS,
|
||||
}
|
||||
SUPPORTED_PLATFORMS = tuple(DISCOVERY_SCHEMAS)
|
||||
|
||||
|
@ -250,6 +250,11 @@
|
||||
"power": {
|
||||
"name": "Power"
|
||||
}
|
||||
},
|
||||
"valve": {
|
||||
"valve": {
|
||||
"name": "[%key:component::valve::title%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
|
152
homeassistant/components/matter/valve.py
Normal file
152
homeassistant/components/matter/valve.py
Normal file
@ -0,0 +1,152 @@
|
||||
"""Matter valve platform."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from matter_server.client.models import device_types
|
||||
|
||||
from homeassistant.components.valve import (
|
||||
ValveDeviceClass,
|
||||
ValveEntity,
|
||||
ValveEntityDescription,
|
||||
ValveEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .entity import MatterEntity
|
||||
from .helpers import get_matter
|
||||
from .models import MatterDiscoverySchema
|
||||
|
||||
ValveConfigurationAndControl = clusters.ValveConfigurationAndControl
|
||||
|
||||
ValveStateEnum = ValveConfigurationAndControl.Enums.ValveStateEnum
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Matter valve platform from Config Entry."""
|
||||
matter = get_matter(hass)
|
||||
matter.register_platform_handler(Platform.VALVE, async_add_entities)
|
||||
|
||||
|
||||
class MatterValve(MatterEntity, ValveEntity):
|
||||
"""Representation of a Matter Valve."""
|
||||
|
||||
_feature_map: int | None = None
|
||||
entity_description: ValveEntityDescription
|
||||
|
||||
async def send_device_command(
|
||||
self,
|
||||
command: clusters.ClusterCommand,
|
||||
) -> None:
|
||||
"""Send a command to the device."""
|
||||
await self.matter_client.send_device_command(
|
||||
node_id=self._endpoint.node.node_id,
|
||||
endpoint_id=self._endpoint.endpoint_id,
|
||||
command=command,
|
||||
)
|
||||
|
||||
async def async_open_valve(self) -> None:
|
||||
"""Open the valve."""
|
||||
await self.send_device_command(ValveConfigurationAndControl.Commands.Open())
|
||||
|
||||
async def async_close_valve(self) -> None:
|
||||
"""Close the valve."""
|
||||
await self.send_device_command(ValveConfigurationAndControl.Commands.Close())
|
||||
|
||||
async def async_set_valve_position(self, position: int) -> None:
|
||||
"""Move the valve to a specific position."""
|
||||
await self.send_device_command(
|
||||
ValveConfigurationAndControl.Commands.Open(targetLevel=position)
|
||||
)
|
||||
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
self._calculate_features()
|
||||
current_state: int
|
||||
current_state = self.get_matter_attribute_value(
|
||||
ValveConfigurationAndControl.Attributes.CurrentState
|
||||
)
|
||||
target_state: int
|
||||
target_state = self.get_matter_attribute_value(
|
||||
ValveConfigurationAndControl.Attributes.TargetState
|
||||
)
|
||||
if (
|
||||
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_opening = False
|
||||
self._attr_is_closing = True
|
||||
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
|
||||
self._attr_is_closed = False
|
||||
# handle optional position
|
||||
if self.supported_features & ValveEntityFeature.SET_POSITION:
|
||||
self._attr_current_valve_position = self.get_matter_attribute_value(
|
||||
ValveConfigurationAndControl.Attributes.CurrentLevel
|
||||
)
|
||||
|
||||
@callback
|
||||
def _calculate_features(
|
||||
self,
|
||||
) -> None:
|
||||
"""Calculate features for HA Valve platform from Matter FeatureMap."""
|
||||
feature_map = int(
|
||||
self.get_matter_attribute_value(
|
||||
ValveConfigurationAndControl.Attributes.FeatureMap
|
||||
)
|
||||
)
|
||||
# NOTE: the featuremap can dynamically change, so we need to update the
|
||||
# supported features if the featuremap changes.
|
||||
# work out supported features and presets from matter featuremap
|
||||
if self._feature_map == feature_map:
|
||||
return
|
||||
self._feature_map = feature_map
|
||||
self._attr_supported_features = ValveEntityFeature(0)
|
||||
if feature_map & ValveConfigurationAndControl.Bitmaps.Feature.kLevel:
|
||||
self._attr_supported_features |= ValveEntityFeature.SET_POSITION
|
||||
self._attr_reports_position = True
|
||||
else:
|
||||
self._attr_reports_position = False
|
||||
|
||||
self._attr_supported_features |= (
|
||||
ValveEntityFeature.CLOSE | ValveEntityFeature.OPEN
|
||||
)
|
||||
|
||||
|
||||
# Discovery schema(s) to map Matter Attributes to HA entities
|
||||
DISCOVERY_SCHEMAS = [
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.VALVE,
|
||||
entity_description=ValveEntityDescription(
|
||||
key="MatterValve",
|
||||
device_class=ValveDeviceClass.WATER,
|
||||
translation_key="valve",
|
||||
),
|
||||
entity_class=MatterValve,
|
||||
required_attributes=(
|
||||
ValveConfigurationAndControl.Attributes.CurrentState,
|
||||
ValveConfigurationAndControl.Attributes.TargetState,
|
||||
),
|
||||
optional_attributes=(ValveConfigurationAndControl.Attributes.CurrentLevel,),
|
||||
device_type=(device_types.WaterValve,),
|
||||
),
|
||||
]
|
260
tests/components/matter/fixtures/nodes/valve.json
Normal file
260
tests/components/matter/fixtures/nodes/valve.json
Normal file
@ -0,0 +1,260 @@
|
||||
{
|
||||
"node_id": 75,
|
||||
"date_commissioned": "2024-09-02T09:32:00.380607",
|
||||
"last_interview": "2024-09-02T09:32:00.380611",
|
||||
"interview_version": 6,
|
||||
"available": true,
|
||||
"is_bridge": false,
|
||||
"attributes": {
|
||||
"0/29/0": [
|
||||
{
|
||||
"0": 22,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"0/29/1": [29, 31, 40, 43, 48, 49, 50, 51, 60, 62, 63],
|
||||
"0/29/2": [],
|
||||
"0/29/3": [1],
|
||||
"0/29/65532": 0,
|
||||
"0/29/65533": 2,
|
||||
"0/29/65528": [],
|
||||
"0/29/65529": [],
|
||||
"0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/31/0": [
|
||||
{
|
||||
"1": 5,
|
||||
"2": 2,
|
||||
"3": [112233],
|
||||
"4": null,
|
||||
"254": 1
|
||||
}
|
||||
],
|
||||
"0/31/1": [],
|
||||
"0/31/2": 4,
|
||||
"0/31/3": 3,
|
||||
"0/31/4": 4,
|
||||
"0/31/65532": 0,
|
||||
"0/31/65533": 1,
|
||||
"0/31/65528": [],
|
||||
"0/31/65529": [],
|
||||
"0/31/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/40/0": 18,
|
||||
"0/40/1": "Mock",
|
||||
"0/40/2": 65521,
|
||||
"0/40/3": "Valve",
|
||||
"0/40/4": 32768,
|
||||
"0/40/5": "",
|
||||
"0/40/6": "**REDACTED**",
|
||||
"0/40/7": 0,
|
||||
"0/40/8": "TEST_VERSION",
|
||||
"0/40/9": 1,
|
||||
"0/40/10": "1.0",
|
||||
"0/40/11": "20200101",
|
||||
"0/40/12": "",
|
||||
"0/40/13": "",
|
||||
"0/40/14": "",
|
||||
"0/40/15": "TEST_SN",
|
||||
"0/40/16": false,
|
||||
"0/40/18": "A3586AC56A2CCCDB",
|
||||
"0/40/19": {
|
||||
"0": 3,
|
||||
"1": 65535
|
||||
},
|
||||
"0/40/21": 17039360,
|
||||
"0/40/22": 1,
|
||||
"0/40/65532": 0,
|
||||
"0/40/65533": 2,
|
||||
"0/40/65528": [],
|
||||
"0/40/65529": [],
|
||||
"0/40/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 21, 22,
|
||||
65528, 65529, 65531, 65532, 65533
|
||||
],
|
||||
"0/43/0": "en-US",
|
||||
"0/43/1": [
|
||||
"en-US",
|
||||
"de-DE",
|
||||
"fr-FR",
|
||||
"en-GB",
|
||||
"es-ES",
|
||||
"zh-CN",
|
||||
"it-IT",
|
||||
"ja-JP"
|
||||
],
|
||||
"0/43/65532": 0,
|
||||
"0/43/65533": 1,
|
||||
"0/43/65528": [],
|
||||
"0/43/65529": [],
|
||||
"0/43/65531": [0, 1, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/48/0": 0,
|
||||
"0/48/1": {
|
||||
"0": 60,
|
||||
"1": 900
|
||||
},
|
||||
"0/48/2": 0,
|
||||
"0/48/3": 2,
|
||||
"0/48/4": true,
|
||||
"0/48/65532": 0,
|
||||
"0/48/65533": 1,
|
||||
"0/48/65528": [1, 3, 5],
|
||||
"0/48/65529": [0, 2, 4],
|
||||
"0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/49/0": 1,
|
||||
"0/49/1": [
|
||||
{
|
||||
"0": "ZW5zMzM=",
|
||||
"1": true
|
||||
}
|
||||
],
|
||||
"0/49/2": 0,
|
||||
"0/49/3": 0,
|
||||
"0/49/4": true,
|
||||
"0/49/5": null,
|
||||
"0/49/6": null,
|
||||
"0/49/7": null,
|
||||
"0/49/65532": 4,
|
||||
"0/49/65533": 2,
|
||||
"0/49/65528": [],
|
||||
"0/49/65529": [],
|
||||
"0/49/65531": [0, 1, 2, 3, 4, 5, 6, 7, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/50/65532": 0,
|
||||
"0/50/65533": 1,
|
||||
"0/50/65528": [1],
|
||||
"0/50/65529": [0],
|
||||
"0/50/65531": [65528, 65529, 65531, 65532, 65533],
|
||||
"0/51/0": [
|
||||
{
|
||||
"0": "ens33",
|
||||
"1": true,
|
||||
"2": null,
|
||||
"3": null,
|
||||
"4": "AAwpp2CV",
|
||||
"5": ["wKgBjg=="],
|
||||
"6": [
|
||||
"/adI27DsyURo2mqau/5wuw==",
|
||||
"/adI27DsyUSOe4PwnMXbYg==",
|
||||
"KgEOCgKzOZD9M4Fh8k4Abg==",
|
||||
"KgEOCgKzOZCNpPnLBN7MTQ==",
|
||||
"/oAAAAAAAADvX1kMcjUM+w=="
|
||||
],
|
||||
"7": 2
|
||||
},
|
||||
{
|
||||
"0": "lo",
|
||||
"1": true,
|
||||
"2": null,
|
||||
"3": null,
|
||||
"4": "AAAAAAAA",
|
||||
"5": ["fwAAAQ=="],
|
||||
"6": ["AAAAAAAAAAAAAAAAAAAAAQ=="],
|
||||
"7": 0
|
||||
}
|
||||
],
|
||||
"0/51/1": 1,
|
||||
"0/51/2": 77,
|
||||
"0/51/3": 0,
|
||||
"0/51/4": 0,
|
||||
"0/51/5": [],
|
||||
"0/51/6": [],
|
||||
"0/51/7": [],
|
||||
"0/51/8": false,
|
||||
"0/51/65532": 0,
|
||||
"0/51/65533": 2,
|
||||
"0/51/65528": [2],
|
||||
"0/51/65529": [0, 1],
|
||||
"0/51/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 65528, 65529, 65531, 65532, 65533
|
||||
],
|
||||
"0/60/0": 0,
|
||||
"0/60/1": null,
|
||||
"0/60/2": null,
|
||||
"0/60/65532": 0,
|
||||
"0/60/65533": 1,
|
||||
"0/60/65528": [],
|
||||
"0/60/65529": [0, 1, 2],
|
||||
"0/60/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/62/0": [
|
||||
{
|
||||
"1": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRSxgkBwEkCAEwCUEEPt5xWN1i0R+dLM+MnDvosL8hjyrRoHq5ja+iCtZbpXTIXt17ueMKWDc7pgeEvHn9opOCiFvmqjEZ1L4hDk27MTcKNQEoARgkAgE2AwQCBAEYMAQUUPvMnV9FkGhfQedEwlqazBFbVfUwBRQ1L3KS8MJ5RVnuryNgRxdXueDAoxgwC0CA4m5xhFuvxC4iDehajKmbdNvZdo2alIbL8hGTor2jMFIPAowJeA0ZaS0+ocRsA6xxHRrpmmF095qUHbSONrPIGA==",
|
||||
"2": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEBjOABseGNfeoeNqgBxhNV78q8SfQP8putY2hpTVwmJVaWzyqw4F/OhdJRHTZjXkSV87jHOZ58ivEb3GjFiT+OTcKNQEpARgkAmAwBBQ1L3KS8MJ5RVnuryNgRxdXueDAozAFFM2vLItbAuvwSMsedKJS5Tw7Aa2pGDALQCPtpgnYiXc8JmJmEi25z0BIPFYaf27j9yhVSmm45vjpdSZd3p8uOGjHd23m8w/22q2eWvkzU02qTVLgnV42cgkY",
|
||||
"254": 1
|
||||
}
|
||||
],
|
||||
"0/62/1": [
|
||||
{
|
||||
"1": "BPUiJZj+BQknF7mbNOh2d9ZtKB+gQJLND+2qjIAAaMJb+2BW+xFhqDYYiA8p9YegdTb0wHA1NQY8TXMPyDwoP9Q=",
|
||||
"2": 4939,
|
||||
"3": 2,
|
||||
"4": 75,
|
||||
"5": "",
|
||||
"254": 1
|
||||
}
|
||||
],
|
||||
"0/62/2": 16,
|
||||
"0/62/3": 1,
|
||||
"0/62/4": [
|
||||
"FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEE9SIlmP4FCScXuZs06HZ31m0oH6BAks0P7aqMgABowlv7YFb7EWGoNhiIDyn1h6B1NvTAcDU1BjxNcw/IPCg/1DcKNQEpARgkAmAwBBTNryyLWwLr8EjLHnSiUuU8OwGtqTAFFM2vLItbAuvwSMsedKJS5Tw7Aa2pGDALQKL0AGnKE3ezVrBBzJA+9INd8GTFOC3oX/EeCpI4CSKlc7LijfauiDVtJ5gfqR0gf1TKLcWfSUe7mIIvXzzvg0UY"
|
||||
],
|
||||
"0/62/5": 1,
|
||||
"0/62/65532": 0,
|
||||
"0/62/65533": 1,
|
||||
"0/62/65528": [1, 3, 5, 8],
|
||||
"0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11],
|
||||
"0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/63/0": [],
|
||||
"0/63/1": [],
|
||||
"0/63/2": 4,
|
||||
"0/63/3": 3,
|
||||
"0/63/65532": 0,
|
||||
"0/63/65533": 2,
|
||||
"0/63/65528": [2, 5],
|
||||
"0/63/65529": [0, 1, 3, 4],
|
||||
"0/63/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/3/0": 0,
|
||||
"1/3/1": 0,
|
||||
"1/3/65532": 0,
|
||||
"1/3/65533": 2,
|
||||
"1/3/65528": [],
|
||||
"1/3/65529": [0, 64],
|
||||
"1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/4/0": 128,
|
||||
"1/4/65532": 1,
|
||||
"1/4/65533": 3,
|
||||
"1/4/65528": [0, 1, 2, 3],
|
||||
"1/4/65529": [0, 1, 2, 3, 4, 5],
|
||||
"1/4/65531": [0, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/29/0": [
|
||||
{
|
||||
"0": 66,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"1/29/1": [3, 4, 29, 129],
|
||||
"1/29/2": [],
|
||||
"1/29/3": [],
|
||||
"1/29/65532": 0,
|
||||
"1/29/65533": 2,
|
||||
"1/29/65528": [],
|
||||
"1/29/65529": [],
|
||||
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/129/0": 0,
|
||||
"1/129/1": 0,
|
||||
"1/129/2": 0,
|
||||
"1/129/3": null,
|
||||
"1/129/4": 0,
|
||||
"1/129/5": 0,
|
||||
"1/129/6": 0,
|
||||
"1/129/7": 0,
|
||||
"1/129/8": 100,
|
||||
"1/129/9": 0,
|
||||
"1/129/10": 0,
|
||||
"1/129/65532": 0,
|
||||
"1/129/65533": 1,
|
||||
"1/129/65528": [],
|
||||
"1/129/65529": [0, 1],
|
||||
"1/129/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 65528, 65529, 65531, 65532, 65533
|
||||
]
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
131
tests/components/matter/test_valve.py
Normal file
131
tests/components/matter/test_valve.py
Normal file
@ -0,0 +1,131 @@
|
||||
"""Test Matter valve."""
|
||||
|
||||
from unittest.mock import MagicMock, call
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from matter_server.client.models.node import MatterNode
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import (
|
||||
set_node_attribute,
|
||||
setup_integration_with_node_fixture,
|
||||
trigger_subscription_callback,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="valve_node")
|
||||
async def valve_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a valve node."""
|
||||
return await setup_integration_with_node_fixture(hass, "valve", matter_client)
|
||||
|
||||
|
||||
# This tests needs to be adjusted to remove lingering tasks
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
async def test_valve(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
valve_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test valve entity is created for a Matter ValveConfigurationAndControl Cluster."""
|
||||
entity_id = "valve.valve_valve"
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "closed"
|
||||
assert state.attributes["friendly_name"] == "Valve Valve"
|
||||
|
||||
# test close_valve action
|
||||
await hass.services.async_call(
|
||||
"valve",
|
||||
"close_valve",
|
||||
{
|
||||
"entity_id": entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=valve_node.node_id,
|
||||
endpoint_id=1,
|
||||
command=clusters.ValveConfigurationAndControl.Commands.Close(),
|
||||
)
|
||||
matter_client.send_device_command.reset_mock()
|
||||
|
||||
# test open_valve action
|
||||
await hass.services.async_call(
|
||||
"valve",
|
||||
"open_valve",
|
||||
{
|
||||
"entity_id": entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=valve_node.node_id,
|
||||
endpoint_id=1,
|
||||
command=clusters.ValveConfigurationAndControl.Commands.Open(),
|
||||
)
|
||||
matter_client.send_device_command.reset_mock()
|
||||
|
||||
# set changing state to 'opening'
|
||||
set_node_attribute(valve_node, 1, 129, 4, 2)
|
||||
set_node_attribute(valve_node, 1, 129, 5, 1)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "opening"
|
||||
|
||||
# set changing state to 'closing'
|
||||
set_node_attribute(valve_node, 1, 129, 4, 2)
|
||||
set_node_attribute(valve_node, 1, 129, 5, 0)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "closing"
|
||||
|
||||
# set changing state to 'open'
|
||||
set_node_attribute(valve_node, 1, 129, 4, 1)
|
||||
set_node_attribute(valve_node, 1, 129, 5, 0)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "open"
|
||||
|
||||
# add support for setting position by updating the featuremap
|
||||
set_node_attribute(valve_node, 1, 129, 65532, 2)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.attributes["current_position"] == 0
|
||||
|
||||
# update current position
|
||||
set_node_attribute(valve_node, 1, 129, 6, 50)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.attributes["current_position"] == 50
|
||||
|
||||
# test set_position action
|
||||
await hass.services.async_call(
|
||||
"valve",
|
||||
"set_valve_position",
|
||||
{
|
||||
"entity_id": entity_id,
|
||||
"position": 100,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=valve_node.node_id,
|
||||
endpoint_id=1,
|
||||
command=clusters.ValveConfigurationAndControl.Commands.Open(targetLevel=100),
|
||||
)
|
||||
matter_client.send_device_command.reset_mock()
|
Loading…
x
Reference in New Issue
Block a user