diff --git a/homeassistant/components/zwave_js/binary_sensor.py b/homeassistant/components/zwave_js/binary_sensor.py new file mode 100644 index 00000000000..9011d1a72b0 --- /dev/null +++ b/homeassistant/components/zwave_js/binary_sensor.py @@ -0,0 +1,354 @@ +"""Representation of Z-Wave binary sensors.""" + +import logging +from typing import Callable, List, Optional, TypedDict + +from zwave_js_server.client import Client as ZwaveClient +from zwave_js_server.const import CommandClass + +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_DOOR, + DEVICE_CLASS_GAS, + DEVICE_CLASS_HEAT, + DEVICE_CLASS_LOCK, + DEVICE_CLASS_MOISTURE, + DEVICE_CLASS_MOTION, + DEVICE_CLASS_POWER, + DEVICE_CLASS_PROBLEM, + DEVICE_CLASS_SAFETY, + DEVICE_CLASS_SMOKE, + DEVICE_CLASS_SOUND, + DOMAIN as BINARY_SENSOR_DOMAIN, + BinarySensorEntity, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect + +from .const import DATA_CLIENT, DATA_UNSUBSCRIBE, DOMAIN +from .discovery import ZwaveDiscoveryInfo +from .entity import ZWaveBaseEntity + +LOGGER = logging.getLogger(__name__) + + +NOTIFICATION_SMOKE_ALARM = 1 +NOTIFICATION_CARBON_MONOOXIDE = 2 +NOTIFICATION_CARBON_DIOXIDE = 3 +NOTIFICATION_HEAT = 4 +NOTIFICATION_WATER = 5 +NOTIFICATION_ACCESS_CONTROL = 6 +NOTIFICATION_HOME_SECURITY = 7 +NOTIFICATION_POWER_MANAGEMENT = 8 +NOTIFICATION_SYSTEM = 9 +NOTIFICATION_EMERGENCY = 10 +NOTIFICATION_CLOCK = 11 +NOTIFICATION_APPLIANCE = 12 +NOTIFICATION_HOME_HEALTH = 13 +NOTIFICATION_SIREN = 14 +NOTIFICATION_WATER_VALVE = 15 +NOTIFICATION_WEATHER = 16 +NOTIFICATION_IRRIGATION = 17 +NOTIFICATION_GAS = 18 + + +class NotificationSensorMapping(TypedDict, total=False): + """Represent a notification sensor mapping dict type.""" + + type: int # required + states: List[int] # required + device_class: str + enabled: bool + + +# Mappings for Notification sensors +NOTIFICATION_SENSOR_MAPPINGS: List[NotificationSensorMapping] = [ + { + # NotificationType 1: Smoke Alarm - State Id's 1 and 2 + # Assuming here that Value 1 and 2 are not present at the same time + "type": NOTIFICATION_SMOKE_ALARM, + "states": [1, 2], + "device_class": DEVICE_CLASS_SMOKE, + }, + { + # NotificationType 1: Smoke Alarm - All other State Id's + # Create as disabled sensors + "type": NOTIFICATION_SMOKE_ALARM, + "states": [3, 4, 5, 6, 7, 8], + "device_class": DEVICE_CLASS_SMOKE, + "enabled": False, + }, + { + # NotificationType 2: Carbon Monoxide - State Id's 1 and 2 + "type": NOTIFICATION_CARBON_MONOOXIDE, + "states": [1, 2], + "device_class": DEVICE_CLASS_GAS, + }, + { + # NotificationType 2: Carbon Monoxide - All other State Id's + "type": NOTIFICATION_CARBON_MONOOXIDE, + "states": [4, 5, 7], + "device_class": DEVICE_CLASS_GAS, + "enabled": False, + }, + { + # NotificationType 3: Carbon Dioxide - State Id's 1 and 2 + "type": NOTIFICATION_CARBON_DIOXIDE, + "states": [1, 2], + "device_class": DEVICE_CLASS_GAS, + }, + { + # NotificationType 3: Carbon Dioxide - All other State Id's + "type": NOTIFICATION_CARBON_DIOXIDE, + "states": [4, 5, 7], + "device_class": DEVICE_CLASS_GAS, + "enabled": False, + }, + { + # NotificationType 4: Heat - State Id's 1, 2, 5, 6 (heat/underheat) + "type": NOTIFICATION_HEAT, + "states": [1, 2, 5, 6], + "device_class": DEVICE_CLASS_HEAT, + }, + { + # NotificationType 4: Heat - All other State Id's + "type": NOTIFICATION_HEAT, + "states": [3, 4, 8, 10, 11], + "device_class": DEVICE_CLASS_HEAT, + "enabled": False, + }, + { + # NotificationType 5: Water - State Id's 1, 2, 3, 4 + "type": NOTIFICATION_WATER, + "states": [1, 2, 3, 4], + "device_class": DEVICE_CLASS_MOISTURE, + }, + { + # NotificationType 5: Water - All other State Id's + "type": NOTIFICATION_WATER, + "states": [5], + "device_class": DEVICE_CLASS_MOISTURE, + "enabled": False, + }, + { + # NotificationType 6: Access Control - State Id's 1, 2, 3, 4 (Lock) + "type": NOTIFICATION_ACCESS_CONTROL, + "states": [1, 2, 3, 4], + "device_class": DEVICE_CLASS_LOCK, + }, + { + # NotificationType 6: Access Control - State Id 22 (door/window open) + "type": NOTIFICATION_ACCESS_CONTROL, + "states": [22], + "device_class": DEVICE_CLASS_DOOR, + }, + { + # NotificationType 7: Home Security - State Id's 1, 2 (intrusion) + # Assuming that value 1 and 2 are not present at the same time + "type": NOTIFICATION_HOME_SECURITY, + "states": [1, 2], + "device_class": DEVICE_CLASS_SAFETY, + }, + { + # NotificationType 7: Home Security - State Id's 3, 4, 9 (tampering) + "type": NOTIFICATION_HOME_SECURITY, + "states": [3, 4, 9], + "device_class": DEVICE_CLASS_SAFETY, + }, + { + # NotificationType 7: Home Security - State Id's 5, 6 (glass breakage) + # Assuming that value 5 and 6 are not present at the same time + "type": NOTIFICATION_HOME_SECURITY, + "states": [5, 6], + "device_class": DEVICE_CLASS_SAFETY, + }, + { + # NotificationType 7: Home Security - State Id's 7, 8 (motion) + "type": NOTIFICATION_HOME_SECURITY, + "states": [7, 8], + "device_class": DEVICE_CLASS_MOTION, + }, + { + # NotificationType 8: Power management - Values 1...9 + "type": NOTIFICATION_POWER_MANAGEMENT, + "states": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "device_class": DEVICE_CLASS_POWER, + "enabled": False, + }, + { + # NotificationType 8: Power management - Values 10...15 + # Battery values (mutually exclusive) + "type": NOTIFICATION_POWER_MANAGEMENT, + "states": [10, 11, 12, 13, 14, 15], + "device_class": DEVICE_CLASS_BATTERY, + "enabled": False, + }, + { + # NotificationType 9: System - State Id's 1, 2, 6, 7 + "type": NOTIFICATION_SYSTEM, + "states": [1, 2, 6, 7], + "device_class": DEVICE_CLASS_PROBLEM, + "enabled": False, + }, + { + # NotificationType 10: Emergency - State Id's 1, 2, 3 + "type": NOTIFICATION_EMERGENCY, + "states": [1, 2, 3], + "device_class": DEVICE_CLASS_PROBLEM, + }, + { + # NotificationType 11: Clock - State Id's 1, 2 + "type": NOTIFICATION_CLOCK, + "states": [1, 2], + "enabled": False, + }, + { + # NotificationType 12: Appliance - All State Id's + "type": NOTIFICATION_APPLIANCE, + "states": list(range(1, 22)), + }, + { + # NotificationType 13: Home Health - State Id's 1,2,3,4,5 + "type": NOTIFICATION_APPLIANCE, + "states": [1, 2, 3, 4, 5], + }, + { + # NotificationType 14: Siren + "type": NOTIFICATION_SIREN, + "states": [1], + "device_class": DEVICE_CLASS_SOUND, + }, + { + # NotificationType 15: Water valve + # ignore non-boolean values + "type": NOTIFICATION_WATER_VALVE, + "states": [3, 4], + "device_class": DEVICE_CLASS_PROBLEM, + }, + { + # NotificationType 16: Weather + "type": NOTIFICATION_WEATHER, + "states": [1, 2], + "device_class": DEVICE_CLASS_PROBLEM, + }, + { + # NotificationType 17: Irrigation + # ignore non-boolean values + "type": NOTIFICATION_IRRIGATION, + "states": [1, 2, 3, 4, 5], + }, + { + # NotificationType 18: Gas + "type": NOTIFICATION_GAS, + "states": [1, 2, 3, 4], + "device_class": DEVICE_CLASS_GAS, + }, + { + # NotificationType 18: Gas + "type": NOTIFICATION_GAS, + "states": [6], + "device_class": DEVICE_CLASS_PROBLEM, + }, +] + + +async def async_setup_entry( + hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable +) -> None: + """Set up Z-Wave binary sensor from config entry.""" + client: ZwaveClient = hass.data[DOMAIN][config_entry.entry_id][DATA_CLIENT] + + @callback + def async_add_binary_sensor(info: ZwaveDiscoveryInfo) -> None: + """Add Z-Wave Binary Sensor.""" + entities: List[ZWaveBaseEntity] = [] + + if info.platform_hint == "notification": + entities.append(ZWaveNotificationBinarySensor(client, info)) + else: + # boolean sensor + entities.append(ZWaveBooleanBinarySensor(client, info)) + + async_add_entities(entities) + + hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append( + async_dispatcher_connect( + hass, f"{DOMAIN}_add_{BINARY_SENSOR_DOMAIN}", async_add_binary_sensor + ) + ) + + +class ZWaveBooleanBinarySensor(ZWaveBaseEntity, BinarySensorEntity): + """Representation of a Z-Wave binary_sensor.""" + + @property + def is_on(self) -> bool: + """Return if the sensor is on or off.""" + return bool(self.info.primary_value.value) + + @property + def device_class(self) -> Optional[str]: + """Return device class.""" + if self.info.primary_value.command_class == CommandClass.BATTERY: + return DEVICE_CLASS_BATTERY + return None + + @property + def entity_registry_enabled_default(self) -> bool: + """Return if the entity should be enabled when first added to the entity registry.""" + if self.info.primary_value.command_class == CommandClass.SENSOR_BINARY: + # Legacy binary sensors are phased out (replaced by notification sensors) + # Disable by default to not confuse users + if self.info.node.device_class.generic != "Binary Sensor": + return False + return True + + +class ZWaveNotificationBinarySensor(ZWaveBaseEntity, BinarySensorEntity): + """Representation of a Z-Wave binary_sensor from Notification CommandClass.""" + + def __init__(self, client: ZwaveClient, info: ZwaveDiscoveryInfo) -> None: + """Initialize a ZWaveNotificationBinarySensor entity.""" + super().__init__(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.""" + if self._mapping_info: + return self.info.primary_value.value in self._mapping_info["states"] + return bool(self.info.primary_value.value != 0) + + @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 + if not self._mapping_info: + # consider value for which we do not have a mapping as advanced. + return False + return self._mapping_info.get("enabled", True) + + @callback + def _get_sensor_mapping(self) -> NotificationSensorMapping: + """Try to get a device specific mapping for this sensor.""" + for mapping in NOTIFICATION_SENSOR_MAPPINGS: + if mapping["type"] != int( + self.info.primary_value.metadata.cc_specific["notificationType"] + ): + continue + for state_key in self.info.primary_value.metadata.states: + # make sure the key is int + state_key = int(state_key) + if state_key not in mapping["states"]: + continue + # match found + mapping_info = mapping.copy() + return mapping_info + return {} diff --git a/homeassistant/components/zwave_js/const.py b/homeassistant/components/zwave_js/const.py index e1a86115d50..28a4b076be9 100644 --- a/homeassistant/components/zwave_js/const.py +++ b/homeassistant/components/zwave_js/const.py @@ -3,7 +3,7 @@ DOMAIN = "zwave_js" NAME = "Z-Wave JS" -PLATFORMS = ["light", "sensor", "switch"] +PLATFORMS = ["binary_sensor", "light", "sensor", "switch"] DATA_CLIENT = "client" DATA_UNSUBSCRIBE = "unsubs" diff --git a/homeassistant/components/zwave_js/discovery.py b/homeassistant/components/zwave_js/discovery.py index 39e9dd8d561..6564aad1cd8 100644 --- a/homeassistant/components/zwave_js/discovery.py +++ b/homeassistant/components/zwave_js/discovery.py @@ -72,6 +72,24 @@ DISCOVERY_SCHEMAS = [ property={"currentValue"}, type={"number"}, ), + # binary sensors + ZWaveDiscoverySchema( + platform="binary_sensor", + hint="boolean", + command_class={ + CommandClass.SENSOR_BINARY, + CommandClass.BATTERY, + }, + type={"boolean"}, + ), + ZWaveDiscoverySchema( + platform="binary_sensor", + hint="notification", + command_class={ + CommandClass.NOTIFICATION, + }, + type={"number"}, + ), # generic text sensors ZWaveDiscoverySchema( platform="sensor", diff --git a/tests/components/zwave_js/common.py b/tests/components/zwave_js/common.py index 73d70d31669..0b9d7e1e89f 100644 --- a/tests/components/zwave_js/common.py +++ b/tests/components/zwave_js/common.py @@ -3,3 +3,7 @@ AIR_TEMPERATURE_SENSOR = "sensor.multisensor_6_air_temperature" ENERGY_SENSOR = "sensor.smart_plug_with_two_usb_ports_value_electric_consumed_2" POWER_SENSOR = "sensor.smart_plug_with_two_usb_ports_value_electric_consumed" SWITCH_ENTITY = "switch.smart_plug_with_two_usb_ports_current_value" +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" diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index ae62abaeb1a..173d9af2728 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -31,6 +31,12 @@ def multisensor_6_state_fixture(): return json.loads(load_fixture("zwave_js/multisensor_6_state.json")) +@pytest.fixture(name="ecolink_door_sensor_state", scope="session") +def ecolink_door_sensor_state_fixture(): + """Load the Ecolink Door/Window Sensor node state fixture data.""" + return json.loads(load_fixture("zwave_js/ecolink_door_sensor_state.json")) + + @pytest.fixture(name="hank_binary_switch_state", scope="session") def binary_switch_state_fixture(): """Load the hank binary switch node state fixture data.""" @@ -62,6 +68,14 @@ def multisensor_6_fixture(client, multisensor_6_state): return node +@pytest.fixture(name="ecolink_door_sensor") +def legacy_binary_sensor_fixture(client, ecolink_door_sensor_state): + """Mock a legacy_binary_sensor node.""" + node = Node(client, ecolink_door_sensor_state) + client.driver.controller.nodes[node.node_id] = node + return node + + @pytest.fixture(name="hank_binary_switch") def hank_binary_switch_fixture(client, hank_binary_switch_state): """Mock a binary switch node.""" diff --git a/tests/components/zwave_js/test_binary_sensor.py b/tests/components/zwave_js/test_binary_sensor.py new file mode 100644 index 00000000000..e92071c48f9 --- /dev/null +++ b/tests/components/zwave_js/test_binary_sensor.py @@ -0,0 +1,86 @@ +"""Test the Z-Wave JS binary sensor platform.""" +from zwave_js_server.event import Event + +from homeassistant.components.binary_sensor import DEVICE_CLASS_MOTION +from homeassistant.const import DEVICE_CLASS_BATTERY, STATE_OFF, STATE_ON + +from .common import ( + DISABLED_LEGACY_BINARY_SENSOR, + ENABLED_LEGACY_BINARY_SENSOR, + LOW_BATTERY_BINARY_SENSOR, + NOTIFICATION_MOTION_BINARY_SENSOR, +) + + +async def test_low_battery_sensor(hass, multisensor_6, integration): + """Test boolean binary sensor of type low battery.""" + state = hass.states.get(LOW_BATTERY_BINARY_SENSOR) + + assert state + assert state.state == STATE_OFF + assert state.attributes["device_class"] == DEVICE_CLASS_BATTERY + + +async def test_enabled_legacy_sensor(hass, ecolink_door_sensor, integration): + """Test enabled legacy boolean binary sensor.""" + node = ecolink_door_sensor + # this node has Notification CC not (fully) implemented + # so legacy binary sensor should be enabled + + state = hass.states.get(ENABLED_LEGACY_BINARY_SENSOR) + assert state + assert state.state == STATE_OFF + assert state.attributes.get("device_class") is None + + # Test state updates from value updated event + event = Event( + type="value updated", + data={ + "source": "node", + "event": "value updated", + "nodeId": 53, + "args": { + "commandClassName": "Binary Sensor", + "commandClass": 48, + "endpoint": 0, + "property": "Any", + "newValue": True, + "prevValue": False, + "propertyName": "Any", + }, + }, + ) + node.receive_event(event) + + state = hass.states.get(ENABLED_LEGACY_BINARY_SENSOR) + assert state.state == STATE_ON + + +async def test_disabled_legacy_sensor(hass, multisensor_6, integration): + """Test disabled legacy boolean binary sensor.""" + # this node has Notification CC implemented so legacy binary sensor should be disabled + + registry = await hass.helpers.entity_registry.async_get_registry() + entity_id = DISABLED_LEGACY_BINARY_SENSOR + state = hass.states.get(entity_id) + assert state is None + entry = registry.async_get(entity_id) + assert entry + assert entry.disabled + assert entry.disabled_by == "integration" + + # Test enabling legacy entity + updated_entry = registry.async_update_entity( + entry.entity_id, **{"disabled_by": None} + ) + assert updated_entry != entry + assert updated_entry.disabled is False + + +async def test_notification_sensor(hass, multisensor_6, integration): + """Test binary sensor created from Notification CC.""" + state = hass.states.get(NOTIFICATION_MOTION_BINARY_SENSOR) + + assert state + assert state.state == STATE_ON + assert state.attributes["device_class"] == DEVICE_CLASS_MOTION diff --git a/tests/fixtures/zwave_js/ecolink_door_sensor_state.json b/tests/fixtures/zwave_js/ecolink_door_sensor_state.json new file mode 100644 index 00000000000..bd5f2c6b466 --- /dev/null +++ b/tests/fixtures/zwave_js/ecolink_door_sensor_state.json @@ -0,0 +1,334 @@ +{ + "nodeId": 53, + "index": 0, + "status": 1, + "ready": true, + "deviceClass": { + "basic": "Static Controller", + "generic": "Binary Sensor", + "specific": "Routing Binary Sensor", + "mandatorySupportedCCs": [ + "Basic", + "Binary Sensor" + ], + "mandatoryControlCCs": [ + + ] + }, + "isListening": false, + "isFrequentListening": false, + "isRouting": true, + "maxBaudRate": 40000, + "isSecure": false, + "version": 4, + "isBeaming": true, + "manufacturerId": 330, + "productId": 2, + "productType": 1, + "firmwareVersion": "2.0", + "deviceConfig": { + "manufacturerId": 330, + "manufacturer": "Ecolink", + "label": "DWZWAVE2", + "description": "Z-Wave Door/Window Sensor", + "devices": [ + { + "productType": "0x0001", + "productId": "0x0002" + } + ], + "firmwareVersion": { + "min": "0.0", + "max": "255.255" + }, + "associations": { + + }, + "paramInformation": { + "_map": { + + } + } + }, + "label": "DWZWAVE2", + "neighbors": [ + + ], + "interviewAttempts": 1, + "endpoints": [ + { + "nodeId": 2, + "index": 0 + } + ], + "values": [ + { + "commandClassName": "Basic", + "commandClass": 32, + "endpoint": 0, + "property": "currentValue", + "propertyName": "currentValue", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 99, + "label": "Current value" + } + }, + { + "commandClassName": "Basic", + "commandClass": 32, + "endpoint": 0, + "property": "targetValue", + "propertyName": "targetValue", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 0, + "max": 99, + "label": "Target value" + } + }, + { + "commandClassName": "Binary Sensor", + "commandClass": 48, + "endpoint": 0, + "property": "Any", + "propertyName": "Any", + "metadata": { + "type": "boolean", + "readable": true, + "writeable": false, + "label": "Any", + "ccSpecific": { + "sensorType": 255 + } + }, + "value": false + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 1, + "propertyName": "Sending Basic Sets to Association group 2", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 255, + "default": 0, + "format": 1, + "allowManualEntry": false, + "states": { + "0": "Off", + "255": "On" + }, + "label": "Sending Basic Sets to Association group 2", + "description": "Sending Basic Sets to Association group 2", + "isFromConfig": true + } + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 2, + "propertyName": "Sending sensor binary report", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 255, + "default": 0, + "format": 1, + "allowManualEntry": false, + "states": { + "0": "Off", + "255": "On" + }, + "label": "Sending sensor binary report", + "description": "Sending sensor binary report", + "isFromConfig": true + } + }, + { + "commandClassName": "Notification", + "commandClass": 113, + "endpoint": 0, + "property": "Home Security", + "propertyKey": "Cover status", + "propertyName": "Home Security", + "propertyKeyName": "Cover status", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": 3 + }, + { + "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": 330 + }, + { + "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": 2 + }, + { + "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": 61 + }, + { + "commandClassName": "Battery", + "commandClass": 128, + "endpoint": 0, + "property": "isLow", + "propertyName": "isLow", + "metadata": { + "type": "boolean", + "readable": true, + "writeable": false, + "label": "Low battery level" + }, + "value": false + }, + { + "commandClassName": "Wake Up", + "commandClass": 132, + "endpoint": 0, + "property": "wakeUpInterval", + "propertyName": "wakeUpInterval", + "metadata": { + "type": "number", + "readable": false, + "writeable": true, + "min": 3600, + "max": 604800, + "label": "Wake Up interval", + "steps": 200, + "default": 14400 + }, + "value": 14400 + }, + { + "commandClassName": "Wake Up", + "commandClass": 132, + "endpoint": 0, + "property": "controllerNodeId", + "propertyName": "controllerNodeId", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Node ID of the controller" + }, + "value": 1 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "libraryType", + "propertyName": "libraryType", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Library type" + }, + "value": 6 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "protocolVersion", + "propertyName": "protocolVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol version" + }, + "value": "3.40" + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "firmwareVersions", + "propertyName": "firmwareVersions", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip firmware versions" + }, + "value": [ + "2.0" + ] + } + ] + } + \ No newline at end of file