Add zwave_js ZWavePropertyBinarySensory (#45504)
This commit is contained in:
parent
d174c8265e
commit
666a94a8e1
6 changed files with 609 additions and 0 deletions
|
@ -252,6 +252,28 @@ NOTIFICATION_SENSOR_MAPPINGS: List[NotificationSensorMapping] = [
|
|||
},
|
||||
]
|
||||
|
||||
PROPERTY_DOOR_STATUS = "doorStatus"
|
||||
|
||||
|
||||
class PropertySensorMapping(TypedDict, total=False):
|
||||
"""Represent a property sensor mapping dict type."""
|
||||
|
||||
property_name: str # required
|
||||
on_states: List[str] # required
|
||||
device_class: str
|
||||
enabled: bool
|
||||
|
||||
|
||||
# Mappings for property sensors
|
||||
PROPERTY_SENSOR_MAPPINGS: List[PropertySensorMapping] = [
|
||||
{
|
||||
"property_name": PROPERTY_DOOR_STATUS,
|
||||
"on_states": ["open"],
|
||||
"device_class": DEVICE_CLASS_DOOR,
|
||||
"enabled": True,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable
|
||||
|
@ -266,6 +288,8 @@ async def async_setup_entry(
|
|||
|
||||
if info.platform_hint == "notification":
|
||||
entities.append(ZWaveNotificationBinarySensor(config_entry, client, info))
|
||||
elif info.platform_hint == "property":
|
||||
entities.append(ZWavePropertyBinarySensor(config_entry, client, info))
|
||||
else:
|
||||
# boolean sensor
|
||||
entities.append(ZWaveBooleanBinarySensor(config_entry, client, info))
|
||||
|
@ -356,3 +380,43 @@ class ZWaveNotificationBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
|
|||
mapping_info = mapping.copy()
|
||||
return mapping_info
|
||||
return {}
|
||||
|
||||
|
||||
class ZWavePropertyBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
|
||||
"""Representation of a Z-Wave binary_sensor from a property."""
|
||||
|
||||
def __init__(
|
||||
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
|
||||
) -> None:
|
||||
"""Initialize a ZWavePropertyBinarySensor entity."""
|
||||
super().__init__(config_entry, client, info)
|
||||
# check if we have a custom mapping for this value
|
||||
self._mapping_info = self._get_sensor_mapping()
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return if the sensor is on or off."""
|
||||
return self.info.primary_value.value in self._mapping_info["on_states"]
|
||||
|
||||
@property
|
||||
def device_class(self) -> Optional[str]:
|
||||
"""Return device class."""
|
||||
return self._mapping_info.get("device_class")
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
# We hide some more advanced sensors by default to not overwhelm users
|
||||
# unless explicitly stated in a mapping, assume deisabled by default
|
||||
return self._mapping_info.get("enabled", False)
|
||||
|
||||
@callback
|
||||
def _get_sensor_mapping(self) -> PropertySensorMapping:
|
||||
"""Try to get a device specific mapping for this sensor."""
|
||||
mapping_info = PropertySensorMapping()
|
||||
for mapping in PROPERTY_SENSOR_MAPPINGS:
|
||||
if mapping["property_name"] == self.info.primary_value.property_name:
|
||||
mapping_info = mapping.copy()
|
||||
break
|
||||
|
||||
return mapping_info
|
||||
|
|
|
@ -74,6 +74,24 @@ DISCOVERY_SCHEMAS = [
|
|||
property={"currentMode", "locked"},
|
||||
type={"number", "boolean"},
|
||||
),
|
||||
# door lock door status
|
||||
ZWaveDiscoverySchema(
|
||||
platform="binary_sensor",
|
||||
hint="property",
|
||||
device_class_generic={"Entry Control"},
|
||||
device_class_specific={
|
||||
"Door Lock",
|
||||
"Advanced Door Lock",
|
||||
"Secure Keypad Door Lock",
|
||||
"Secure Lockbox",
|
||||
},
|
||||
command_class={
|
||||
CommandClass.LOCK,
|
||||
CommandClass.DOOR_LOCK,
|
||||
},
|
||||
property={"doorStatus"},
|
||||
type={"any"},
|
||||
),
|
||||
# climate
|
||||
ZWaveDiscoverySchema(
|
||||
platform="climate",
|
||||
|
|
|
@ -7,3 +7,6 @@ LOW_BATTERY_BINARY_SENSOR = "binary_sensor.multisensor_6_low_battery_level"
|
|||
ENABLED_LEGACY_BINARY_SENSOR = "binary_sensor.z_wave_door_window_sensor_any"
|
||||
DISABLED_LEGACY_BINARY_SENSOR = "binary_sensor.multisensor_6_any"
|
||||
NOTIFICATION_MOTION_BINARY_SENSOR = "binary_sensor.multisensor_6_motion_sensor_status"
|
||||
PROPERTY_DOOR_STATUS_BINARY_SENSOR = (
|
||||
"binary_sensor.august_smart_lock_pro_3rd_gen_the_current_status_of_the_door"
|
||||
)
|
||||
|
|
|
@ -68,6 +68,12 @@ def lock_schlage_be469_state_fixture():
|
|||
return json.loads(load_fixture("zwave_js/lock_schlage_be469_state.json"))
|
||||
|
||||
|
||||
@pytest.fixture(name="lock_august_asl03_state", scope="session")
|
||||
def lock_august_asl03_state_fixture():
|
||||
"""Load the August Pro lock node state fixture data."""
|
||||
return json.loads(load_fixture("zwave_js/lock_august_asl03_state.json"))
|
||||
|
||||
|
||||
@pytest.fixture(name="climate_radio_thermostat_ct100_plus_state", scope="session")
|
||||
def climate_radio_thermostat_ct100_plus_state_fixture():
|
||||
"""Load the climate radio thermostat ct100 plus node state fixture data."""
|
||||
|
@ -170,6 +176,14 @@ def lock_schlage_be469_fixture(client, lock_schlage_be469_state):
|
|||
return node
|
||||
|
||||
|
||||
@pytest.fixture(name="lock_august_pro")
|
||||
def lock_august_asl03_fixture(client, lock_august_asl03_state):
|
||||
"""Mock a August Pro lock node."""
|
||||
node = Node(client, lock_august_asl03_state)
|
||||
client.driver.controller.nodes[node.node_id] = node
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(name="climate_radio_thermostat_ct100_plus")
|
||||
def climate_radio_thermostat_ct100_plus_fixture(
|
||||
client, climate_radio_thermostat_ct100_plus_state
|
||||
|
|
|
@ -9,6 +9,7 @@ from .common import (
|
|||
ENABLED_LEGACY_BINARY_SENSOR,
|
||||
LOW_BATTERY_BINARY_SENSOR,
|
||||
NOTIFICATION_MOTION_BINARY_SENSOR,
|
||||
PROPERTY_DOOR_STATUS_BINARY_SENSOR,
|
||||
)
|
||||
|
||||
|
||||
|
@ -84,3 +85,56 @@ async def test_notification_sensor(hass, multisensor_6, integration):
|
|||
assert state
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["device_class"] == DEVICE_CLASS_MOTION
|
||||
|
||||
|
||||
async def test_property_sensor_door_status(hass, lock_august_pro, integration):
|
||||
"""Test property binary sensor with sensor mapping (doorStatus)."""
|
||||
node = lock_august_pro
|
||||
|
||||
state = hass.states.get(PROPERTY_DOOR_STATUS_BINARY_SENSOR)
|
||||
assert state is not None
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
# open door
|
||||
event = Event(
|
||||
type="value updated",
|
||||
data={
|
||||
"source": "node",
|
||||
"event": "value updated",
|
||||
"nodeId": 6,
|
||||
"args": {
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "doorStatus",
|
||||
"newValue": "open",
|
||||
"prevValue": "closed",
|
||||
"propertyName": "doorStatus",
|
||||
},
|
||||
},
|
||||
)
|
||||
node.receive_event(event)
|
||||
state = hass.states.get(PROPERTY_DOOR_STATUS_BINARY_SENSOR)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
# close door
|
||||
event = Event(
|
||||
type="value updated",
|
||||
data={
|
||||
"source": "node",
|
||||
"event": "value updated",
|
||||
"nodeId": 6,
|
||||
"args": {
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "doorStatus",
|
||||
"newValue": "closed",
|
||||
"prevValue": "open",
|
||||
"propertyName": "doorStatus",
|
||||
},
|
||||
},
|
||||
)
|
||||
node.receive_event(event)
|
||||
state = hass.states.get(PROPERTY_DOOR_STATUS_BINARY_SENSOR)
|
||||
assert state.state == STATE_OFF
|
||||
|
|
456
tests/fixtures/zwave_js/lock_august_asl03_state.json
vendored
Normal file
456
tests/fixtures/zwave_js/lock_august_asl03_state.json
vendored
Normal file
|
@ -0,0 +1,456 @@
|
|||
{
|
||||
"nodeId": 6,
|
||||
"index": 0,
|
||||
"installerIcon": 768,
|
||||
"userIcon": 768,
|
||||
"status": 4,
|
||||
"ready": true,
|
||||
"deviceClass": {
|
||||
"basic": "Routing Slave",
|
||||
"generic": "Entry Control",
|
||||
"specific": "Secure Keypad Door Lock",
|
||||
"mandatorySupportedCCs": [
|
||||
"Basic",
|
||||
"Door Lock",
|
||||
"User Code",
|
||||
"Manufacturer Specific",
|
||||
"Security",
|
||||
"Version"
|
||||
],
|
||||
"mandatoryControlCCs": []
|
||||
},
|
||||
"isListening": false,
|
||||
"isFrequentListening": true,
|
||||
"isRouting": true,
|
||||
"maxBaudRate": 40000,
|
||||
"isSecure": true,
|
||||
"version": 4,
|
||||
"isBeaming": true,
|
||||
"manufacturerId": 831,
|
||||
"productId": 1,
|
||||
"productType": 1,
|
||||
"firmwareVersion": "1.59",
|
||||
"zwavePlusVersion": 1,
|
||||
"nodeType": 0,
|
||||
"roleType": 7,
|
||||
"deviceConfig": {
|
||||
"manufacturerId": 831,
|
||||
"manufacturer": "August Smart Locks",
|
||||
"label": "ASL-03",
|
||||
"description": "August Smart Lock Pro 3rd Gen",
|
||||
"devices": [
|
||||
{
|
||||
"productType": "0x0000",
|
||||
"productId": "0x0594"
|
||||
},
|
||||
{
|
||||
"productType": "0x0000",
|
||||
"productId": "0xdf29"
|
||||
},
|
||||
{
|
||||
"productType": "0x0001",
|
||||
"productId": "0x0001"
|
||||
}
|
||||
],
|
||||
"firmwareVersion": {
|
||||
"min": "0.0",
|
||||
"max": "255.255"
|
||||
}
|
||||
},
|
||||
"label": "ASL-03",
|
||||
"neighbors": [
|
||||
1,
|
||||
7,
|
||||
8,
|
||||
9
|
||||
],
|
||||
"interviewAttempts": 1,
|
||||
"endpoints": [
|
||||
{
|
||||
"nodeId": 6,
|
||||
"index": 0,
|
||||
"installerIcon": 768,
|
||||
"userIcon": 768
|
||||
}
|
||||
],
|
||||
"values": [
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "currentMode",
|
||||
"propertyName": "currentMode",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"min": 0,
|
||||
"max": 255,
|
||||
"label": "Current lock mode",
|
||||
"states": {
|
||||
"0": "Unsecured",
|
||||
"1": "UnsecuredWithTimeout",
|
||||
"16": "InsideUnsecured",
|
||||
"17": "InsideUnsecuredWithTimeout",
|
||||
"32": "OutsideUnsecured",
|
||||
"33": "OutsideUnsecuredWithTimeout",
|
||||
"254": "Unknown",
|
||||
"255": "Secured"
|
||||
}
|
||||
},
|
||||
"value": 255
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "targetMode",
|
||||
"propertyName": "targetMode",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": true,
|
||||
"min": 0,
|
||||
"max": 255,
|
||||
"label": "Target lock mode",
|
||||
"states": {
|
||||
"0": "Unsecured",
|
||||
"1": "UnsecuredWithTimeout",
|
||||
"16": "InsideUnsecured",
|
||||
"17": "InsideUnsecuredWithTimeout",
|
||||
"32": "OutsideUnsecured",
|
||||
"33": "OutsideUnsecuredWithTimeout",
|
||||
"254": "Unknown",
|
||||
"255": "Secured"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "outsideHandlesCanOpenDoor",
|
||||
"propertyName": "outsideHandlesCanOpenDoor",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Which outside handles can open the door (actual status)"
|
||||
},
|
||||
"value": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "insideHandlesCanOpenDoor",
|
||||
"propertyName": "insideHandlesCanOpenDoor",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Which inside handles can open the door (actual status)"
|
||||
},
|
||||
"value": [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "latchStatus",
|
||||
"propertyName": "latchStatus",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "The current status of the latch"
|
||||
},
|
||||
"value": "open"
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "boltStatus",
|
||||
"propertyName": "boltStatus",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "The current status of the bolt"
|
||||
},
|
||||
"value": "locked"
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "doorStatus",
|
||||
"propertyName": "doorStatus",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "The current status of the door"
|
||||
},
|
||||
"value": "closed"
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "lockTimeout",
|
||||
"propertyName": "lockTimeout",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Seconds until lock mode times out"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "operationType",
|
||||
"propertyName": "operationType",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": true,
|
||||
"min": 0,
|
||||
"max": 255,
|
||||
"label": "Lock operation type",
|
||||
"states": {
|
||||
"1": "Constant",
|
||||
"2": "Timed"
|
||||
}
|
||||
},
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "outsideHandlesCanOpenDoorConfiguration",
|
||||
"propertyName": "outsideHandlesCanOpenDoorConfiguration",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": true,
|
||||
"label": "Which outside handles can open the door (configuration)"
|
||||
},
|
||||
"value": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "insideHandlesCanOpenDoorConfiguration",
|
||||
"propertyName": "insideHandlesCanOpenDoorConfiguration",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": true,
|
||||
"label": "Which inside handles can open the door (configuration)"
|
||||
},
|
||||
"value": [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"commandClassName": "Door Lock",
|
||||
"commandClass": 98,
|
||||
"endpoint": 0,
|
||||
"property": "lockTimeoutConfiguration",
|
||||
"propertyName": "lockTimeoutConfiguration",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": true,
|
||||
"min": 0,
|
||||
"max": 65535,
|
||||
"label": "Duration of timed mode in seconds"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandClassName": "Notification",
|
||||
"commandClass": 113,
|
||||
"endpoint": 0,
|
||||
"property": "Access Control",
|
||||
"propertyKey": "Lock state",
|
||||
"propertyName": "Access Control",
|
||||
"propertyKeyName": "Lock state",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"min": 0,
|
||||
"max": 255,
|
||||
"label": "Lock state",
|
||||
"states": {
|
||||
"0": "idle",
|
||||
"11": "Lock jammed"
|
||||
},
|
||||
"ccSpecific": {
|
||||
"notificationType": 6
|
||||
}
|
||||
},
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"commandClassName": "Manufacturer Specific",
|
||||
"commandClass": 114,
|
||||
"endpoint": 0,
|
||||
"property": "manufacturerId",
|
||||
"propertyName": "manufacturerId",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"min": 0,
|
||||
"max": 65535,
|
||||
"label": "Manufacturer ID"
|
||||
},
|
||||
"value": 831
|
||||
},
|
||||
{
|
||||
"commandClassName": "Manufacturer Specific",
|
||||
"commandClass": 114,
|
||||
"endpoint": 0,
|
||||
"property": "productType",
|
||||
"propertyName": "productType",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"min": 0,
|
||||
"max": 65535,
|
||||
"label": "Product type"
|
||||
},
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"commandClassName": "Manufacturer Specific",
|
||||
"commandClass": 114,
|
||||
"endpoint": 0,
|
||||
"property": "productId",
|
||||
"propertyName": "productId",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"min": 0,
|
||||
"max": 65535,
|
||||
"label": "Product ID"
|
||||
},
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"commandClassName": "Battery",
|
||||
"commandClass": 128,
|
||||
"endpoint": 0,
|
||||
"property": "level",
|
||||
"propertyName": "level",
|
||||
"metadata": {
|
||||
"type": "number",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"unit": "%",
|
||||
"label": "Battery level"
|
||||
},
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"commandClassName": "Battery",
|
||||
"commandClass": 128,
|
||||
"endpoint": 0,
|
||||
"property": "isLow",
|
||||
"propertyName": "isLow",
|
||||
"metadata": {
|
||||
"type": "boolean",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Low battery level"
|
||||
},
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"commandClassName": "Version",
|
||||
"commandClass": 134,
|
||||
"endpoint": 0,
|
||||
"property": "libraryType",
|
||||
"propertyName": "libraryType",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Library type"
|
||||
},
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"commandClassName": "Version",
|
||||
"commandClass": 134,
|
||||
"endpoint": 0,
|
||||
"property": "protocolVersion",
|
||||
"propertyName": "protocolVersion",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Z-Wave protocol version"
|
||||
},
|
||||
"value": "4.61"
|
||||
},
|
||||
{
|
||||
"commandClassName": "Version",
|
||||
"commandClass": 134,
|
||||
"endpoint": 0,
|
||||
"property": "firmwareVersions",
|
||||
"propertyName": "firmwareVersions",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Z-Wave chip firmware versions"
|
||||
},
|
||||
"value": [
|
||||
"1.59"
|
||||
]
|
||||
},
|
||||
{
|
||||
"commandClassName": "Version",
|
||||
"commandClass": 134,
|
||||
"endpoint": 0,
|
||||
"property": "hardwareVersion",
|
||||
"propertyName": "hardwareVersion",
|
||||
"metadata": {
|
||||
"type": "any",
|
||||
"readable": true,
|
||||
"writeable": false,
|
||||
"label": "Z-Wave chip hardware version"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Add table
Reference in a new issue