Add Matter discovery schemas for BooleanState sensors (#117870)
Co-authored-by: Stefan Agner <stefan@agner.ch> Co-authored-by: Franck Nijhof <frenck@frenck.nl> Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
This commit is contained in:
parent
cb563f25fa
commit
2ad5b1c3a6
4 changed files with 280 additions and 34 deletions
|
@ -7,6 +7,7 @@ from dataclasses import dataclass
|
|||
from chip.clusters import Objects as clusters
|
||||
from chip.clusters.Objects import uint
|
||||
from chip.clusters.Types import Nullable, NullValue
|
||||
from matter_server.client.models import device_types
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
|
@ -73,17 +74,6 @@ DISCOVERY_SCHEMAS = [
|
|||
vendor_id=(4107,),
|
||||
product_name=("Hue motion sensor",),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.BINARY_SENSOR,
|
||||
entity_description=MatterBinarySensorEntityDescription(
|
||||
key="ContactSensor",
|
||||
device_class=BinarySensorDeviceClass.DOOR,
|
||||
# value is inverted on matter to what we expect
|
||||
measurement_to_ha=lambda x: not x,
|
||||
),
|
||||
entity_class=MatterBinarySensor,
|
||||
required_attributes=(clusters.BooleanState.Attributes.StateValue,),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.BINARY_SENSOR,
|
||||
entity_description=MatterBinarySensorEntityDescription(
|
||||
|
@ -109,4 +99,50 @@ DISCOVERY_SCHEMAS = [
|
|||
# only add binary battery sensor if a regular percentage based is not available
|
||||
absent_attributes=(clusters.PowerSource.Attributes.BatPercentRemaining,),
|
||||
),
|
||||
# BooleanState sensors (tied to device type)
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.BINARY_SENSOR,
|
||||
entity_description=MatterBinarySensorEntityDescription(
|
||||
key="ContactSensor",
|
||||
device_class=BinarySensorDeviceClass.DOOR,
|
||||
# value is inverted on matter to what we expect
|
||||
measurement_to_ha=lambda x: not x,
|
||||
),
|
||||
entity_class=MatterBinarySensor,
|
||||
required_attributes=(clusters.BooleanState.Attributes.StateValue,),
|
||||
device_type=(device_types.ContactSensor,),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.BINARY_SENSOR,
|
||||
entity_description=MatterBinarySensorEntityDescription(
|
||||
key="WaterLeakDetector",
|
||||
translation_key="water_leak",
|
||||
device_class=BinarySensorDeviceClass.MOISTURE,
|
||||
),
|
||||
entity_class=MatterBinarySensor,
|
||||
required_attributes=(clusters.BooleanState.Attributes.StateValue,),
|
||||
device_type=(device_types.WaterLeakDetector,),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.BINARY_SENSOR,
|
||||
entity_description=MatterBinarySensorEntityDescription(
|
||||
key="WaterFreezeDetector",
|
||||
translation_key="water_freeze",
|
||||
device_class=BinarySensorDeviceClass.COLD,
|
||||
),
|
||||
entity_class=MatterBinarySensor,
|
||||
required_attributes=(clusters.BooleanState.Attributes.StateValue,),
|
||||
device_type=(device_types.WaterFreezeDetector,),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.BINARY_SENSOR,
|
||||
entity_description=MatterBinarySensorEntityDescription(
|
||||
key="RainSensor",
|
||||
translation_key="rain",
|
||||
device_class=BinarySensorDeviceClass.MOISTURE,
|
||||
),
|
||||
entity_class=MatterBinarySensor,
|
||||
required_attributes=(clusters.BooleanState.Attributes.StateValue,),
|
||||
device_type=(device_types.RainSensor,),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -45,6 +45,17 @@
|
|||
}
|
||||
},
|
||||
"entity": {
|
||||
"binary_sensor": {
|
||||
"water_leak": {
|
||||
"name": "Water leak"
|
||||
},
|
||||
"water_freeze": {
|
||||
"name": "Water freeze"
|
||||
},
|
||||
"rain": {
|
||||
"name": "Rain"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"thermostat": {
|
||||
"name": "Thermostat"
|
||||
|
|
185
tests/components/matter/fixtures/nodes/leak-sensor.json
Normal file
185
tests/components/matter/fixtures/nodes/leak-sensor.json
Normal file
|
@ -0,0 +1,185 @@
|
|||
{
|
||||
"node_id": 32,
|
||||
"date_commissioned": "2024-06-21T14:13:02.370603",
|
||||
"last_interview": "2024-06-21T14:14:49.941142",
|
||||
"interview_version": 6,
|
||||
"available": true,
|
||||
"is_bridge": true,
|
||||
"attributes": {
|
||||
"0/29/0": [
|
||||
{
|
||||
"0": 22,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"0/29/1": [29, 31, 40, 43, 44, 48, 49, 50, 51, 52, 56, 60, 62, 63],
|
||||
"0/29/2": [31],
|
||||
"0/29/3": [1, 2],
|
||||
"0/29/65528": [],
|
||||
"0/29/65529": [],
|
||||
"0/29/65530": [],
|
||||
"0/29/65531": [0, 1, 2, 3, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/29/65532": 0,
|
||||
"0/29/65533": 1,
|
||||
"0/31/65528": [],
|
||||
"0/31/65529": [],
|
||||
"0/31/65530": [],
|
||||
"0/31/65531": [0, 2, 3, 4, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/31/65532": 0,
|
||||
"0/31/65533": 1,
|
||||
"0/40/0": 1,
|
||||
"0/40/1": "Mock",
|
||||
"0/40/2": 65521,
|
||||
"0/40/3": "Water Leak Detector",
|
||||
"0/40/4": 32768,
|
||||
"0/40/5": "Water Leak Detector",
|
||||
"0/40/6": "",
|
||||
"0/40/7": 0,
|
||||
"0/40/8": "",
|
||||
"0/40/9": 234946562,
|
||||
"0/40/10": "14.1.0.2",
|
||||
"0/40/15": "",
|
||||
"0/40/17": true,
|
||||
"0/40/18": "",
|
||||
"0/40/19": {
|
||||
"0": 3,
|
||||
"1": 3
|
||||
},
|
||||
"0/40/65528": [],
|
||||
"0/40/65529": [],
|
||||
"0/40/65530": [],
|
||||
"0/40/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 17, 18, 19, 65528, 65529, 65530,
|
||||
65531, 65532, 65533
|
||||
],
|
||||
"0/40/65532": 0,
|
||||
"0/40/65533": 2,
|
||||
"0/43/0": "en",
|
||||
"0/43/1": ["en"],
|
||||
"0/43/65528": [],
|
||||
"0/43/65529": [],
|
||||
"0/43/65530": [],
|
||||
"0/43/65531": [0, 1, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/43/65532": 0,
|
||||
"0/43/65533": 1,
|
||||
"0/44/0": 1,
|
||||
"0/44/1": 4,
|
||||
"0/44/2": [],
|
||||
"0/44/65528": [],
|
||||
"0/44/65529": [],
|
||||
"0/44/65530": [],
|
||||
"0/44/65531": [0, 1, 2, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/44/65532": 0,
|
||||
"0/44/65533": 1,
|
||||
"0/48/0": 0,
|
||||
"0/48/1": {
|
||||
"0": 60,
|
||||
"1": 900
|
||||
},
|
||||
"0/48/2": 2,
|
||||
"0/48/3": 2,
|
||||
"0/48/4": false,
|
||||
"0/48/65528": [],
|
||||
"0/48/65529": [],
|
||||
"0/48/65530": [],
|
||||
"0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/48/65532": 0,
|
||||
"0/48/65533": 1,
|
||||
"0/49/3": 30,
|
||||
"0/49/65528": [],
|
||||
"0/49/65529": [],
|
||||
"0/49/65530": [],
|
||||
"0/49/65531": [3, 4, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/49/65532": 4,
|
||||
"0/49/65533": 1,
|
||||
"0/50/65528": [],
|
||||
"0/50/65529": [],
|
||||
"0/50/65530": [],
|
||||
"0/50/65531": [65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/50/65532": 0,
|
||||
"0/50/65533": 1,
|
||||
"0/51/1": 7,
|
||||
"0/51/2": 17,
|
||||
"0/51/8": false,
|
||||
"0/51/65528": [],
|
||||
"0/51/65529": [],
|
||||
"0/51/65530": [],
|
||||
"0/51/65531": [0, 1, 2, 8, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/51/65532": 0,
|
||||
"0/51/65533": 1,
|
||||
"0/52/65528": [],
|
||||
"0/52/65529": [],
|
||||
"0/52/65530": [],
|
||||
"0/52/65531": [65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/52/65532": 0,
|
||||
"0/52/65533": 1,
|
||||
"0/56/0": 1718979287000000,
|
||||
"0/56/1": 3,
|
||||
"0/56/7": 1718982887000000,
|
||||
"0/56/65528": [],
|
||||
"0/56/65529": [],
|
||||
"0/56/65530": [],
|
||||
"0/56/65531": [0, 1, 7, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/56/65532": 0,
|
||||
"0/56/65533": 2,
|
||||
"0/60/0": 0,
|
||||
"0/60/65528": [],
|
||||
"0/60/65529": [],
|
||||
"0/60/65530": [],
|
||||
"0/60/65531": [0, 1, 2, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/60/65532": 0,
|
||||
"0/60/65533": 1,
|
||||
"0/62/2": 5,
|
||||
"0/62/3": 3,
|
||||
"0/62/5": 3,
|
||||
"0/62/65528": [],
|
||||
"0/62/65529": [],
|
||||
"0/62/65530": [],
|
||||
"0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/62/65532": 0,
|
||||
"0/62/65533": 1,
|
||||
"0/63/65528": [],
|
||||
"0/63/65529": [],
|
||||
"0/63/65530": [],
|
||||
"0/63/65531": [65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/63/65532": 0,
|
||||
"0/63/65533": 2,
|
||||
"1/3/0": 0,
|
||||
"1/3/1": 0,
|
||||
"1/3/65528": [],
|
||||
"1/3/65529": [],
|
||||
"1/3/65530": [],
|
||||
"1/3/65531": [0, 1, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/3/65532": 0,
|
||||
"1/3/65533": 4,
|
||||
"1/4/65528": [],
|
||||
"1/4/65529": [],
|
||||
"1/4/65530": [],
|
||||
"1/4/65531": [0, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/4/65532": 0,
|
||||
"1/4/65533": 4,
|
||||
"1/29/0": [
|
||||
{
|
||||
"0": 67,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"1/29/1": [3, 4, 5, 29, 57, 69],
|
||||
"1/29/2": [],
|
||||
"1/29/3": [],
|
||||
"1/29/65528": [],
|
||||
"1/29/65529": [],
|
||||
"1/29/65530": [],
|
||||
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/29/65532": 0,
|
||||
"1/29/65533": 1,
|
||||
"1/69/0": true,
|
||||
"1/69/65528": [],
|
||||
"1/69/65529": [],
|
||||
"1/69/65530": [],
|
||||
"1/69/65531": [0, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/69/65532": 0,
|
||||
"1/69/65533": 1
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
|
@ -32,29 +32,6 @@ def binary_sensor_platform() -> Generator[None]:
|
|||
yield
|
||||
|
||||
|
||||
# This tests needs to be adjusted to remove lingering tasks
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
async def test_contact_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
eve_contact_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test contact sensor."""
|
||||
entity_id = "binary_sensor.eve_door_door"
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "on"
|
||||
|
||||
set_node_attribute(eve_contact_sensor_node, 1, 69, 0, True)
|
||||
await trigger_subscription_callback(
|
||||
hass, matter_client, data=(eve_contact_sensor_node.node_id, "1/69/0", True)
|
||||
)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
@pytest.fixture(name="occupancy_sensor_node")
|
||||
async def occupancy_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
|
@ -87,6 +64,43 @@ async def test_occupancy_sensor(
|
|||
assert state.state == "off"
|
||||
|
||||
|
||||
# This tests needs to be adjusted to remove lingering tasks
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize(
|
||||
("fixture", "entity_id"),
|
||||
[
|
||||
("eve-contact-sensor", "binary_sensor.eve_door_door"),
|
||||
("leak-sensor", "binary_sensor.water_leak_detector_water_leak"),
|
||||
],
|
||||
)
|
||||
async def test_boolean_state_sensors(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
fixture: str,
|
||||
entity_id: str,
|
||||
) -> None:
|
||||
"""Test if binary sensors get created from devices with Boolean State cluster."""
|
||||
node = await setup_integration_with_node_fixture(
|
||||
hass,
|
||||
fixture,
|
||||
matter_client,
|
||||
)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "on"
|
||||
|
||||
# invert the value
|
||||
cur_attr_value = node.get_attribute_value(1, 69, 0)
|
||||
set_node_attribute(node, 1, 69, 0, not cur_attr_value)
|
||||
await trigger_subscription_callback(
|
||||
hass, matter_client, data=(node.node_id, "1/69/0", not cur_attr_value)
|
||||
)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
# This tests needs to be adjusted to remove lingering tasks
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
async def test_battery_sensor(
|
||||
|
|
Loading…
Add table
Reference in a new issue