diff --git a/homeassistant/components/zwave_js/__init__.py b/homeassistant/components/zwave_js/__init__.py index 25e886ea1bf..a4f2a99ecef 100644 --- a/homeassistant/components/zwave_js/__init__.py +++ b/homeassistant/components/zwave_js/__init__.py @@ -14,7 +14,13 @@ from homeassistant.helpers import device_registry from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.dispatcher import async_dispatcher_send -from .const import DATA_CLIENT, DATA_UNSUBSCRIBE, DOMAIN, PLATFORMS +from .const import ( + DATA_CLIENT, + DATA_UNSUBSCRIBE, + DOMAIN, + EVENT_DEVICE_ADDED_TO_REGISTRY, + PLATFORMS, +) from .discovery import async_discover_values from .websocket_api import async_register_api @@ -30,13 +36,14 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool: @callback def register_node_in_dev_reg( + hass: HomeAssistant, entry: ConfigEntry, dev_reg: device_registry.DeviceRegistry, client: ZwaveClient, node: ZwaveNode, ) -> None: """Register node in dev reg.""" - dev_reg.async_get_or_create( + device = dev_reg.async_get_or_create( config_entry_id=entry.entry_id, identifiers={(DOMAIN, f"{client.driver.controller.home_id}-{node.node_id}")}, sw_version=node.firmware_version, @@ -45,6 +52,8 @@ def register_node_in_dev_reg( manufacturer=node.device_config.manufacturer, ) + async_dispatcher_send(hass, EVENT_DEVICE_ADDED_TO_REGISTRY, device) + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Z-Wave JS from a config entry.""" @@ -75,7 +84,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: LOGGER.debug("Processing node %s", node) # register (or update) node in device registry - register_node_in_dev_reg(entry, dev_reg, client, node) + register_node_in_dev_reg(hass, entry, dev_reg, client, node) # run discovery on all node values and create/update entities for disc_info in async_discover_values(node): @@ -98,7 +107,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) # we do submit the node to device registry so user has # some visual feedback that something is (in the process of) being added - register_node_in_dev_reg(entry, dev_reg, client, node) + register_node_in_dev_reg(hass, entry, dev_reg, client, node) async def handle_ha_shutdown(event: Event) -> None: """Handle HA shutdown.""" diff --git a/homeassistant/components/zwave_js/const.py b/homeassistant/components/zwave_js/const.py index f9391dc1b05..561b5a414c8 100644 --- a/homeassistant/components/zwave_js/const.py +++ b/homeassistant/components/zwave_js/const.py @@ -7,3 +7,5 @@ PLATFORMS = ["binary_sensor", "climate", "light", "lock", "sensor", "switch"] DATA_CLIENT = "client" DATA_UNSUBSCRIBE = "unsubs" + +EVENT_DEVICE_ADDED_TO_REGISTRY = f"{DOMAIN}_device_added_to_registry" diff --git a/homeassistant/components/zwave_js/websocket_api.py b/homeassistant/components/zwave_js/websocket_api.py index 532b53695e1..6822aa6198f 100644 --- a/homeassistant/components/zwave_js/websocket_api.py +++ b/homeassistant/components/zwave_js/websocket_api.py @@ -3,12 +3,17 @@ import logging import voluptuous as vol +from zwave_js_server.client import Client as ZwaveClient +from zwave_js_server.model.node import Node as ZwaveNode from homeassistant.components import websocket_api from homeassistant.components.websocket_api.connection import ActiveConnection from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import device_registry +from homeassistant.helpers.device_registry import DeviceEntry +from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import DATA_CLIENT, DOMAIN +from .const import DATA_CLIENT, DOMAIN, EVENT_DEVICE_ADDED_TO_REGISTRY _LOGGER = logging.getLogger(__name__) @@ -21,6 +26,10 @@ TYPE = "type" def async_register_api(hass: HomeAssistant) -> None: """Register all of our api endpoints.""" websocket_api.async_register_command(hass, websocket_network_status) + websocket_api.async_register_command(hass, websocket_add_node) + websocket_api.async_register_command(hass, websocket_stop_inclusion) + websocket_api.async_register_command(hass, websocket_remove_node) + websocket_api.async_register_command(hass, websocket_stop_exclusion) @websocket_api.require_admin @@ -50,3 +59,191 @@ def websocket_network_status( msg[ID], data, ) + + +@websocket_api.require_admin # type: ignore +@websocket_api.async_response +@websocket_api.websocket_command( + { + vol.Required(TYPE): "zwave_js/add_node", + vol.Required(ENTRY_ID): str, + vol.Optional("secure", default=False): bool, + } +) +async def websocket_add_node( + hass: HomeAssistant, connection: ActiveConnection, msg: dict +) -> None: + """Add a node to the Z-Wave network.""" + entry_id = msg[ENTRY_ID] + client = hass.data[DOMAIN][entry_id][DATA_CLIENT] + controller = client.driver.controller + include_non_secure = not msg["secure"] + + @callback + def async_cleanup() -> None: + """Remove signal listeners.""" + for unsub in unsubs: + unsub() + + @callback + def forward_event(event: dict) -> None: + connection.send_message( + websocket_api.event_message(msg[ID], {"event": event["event"]}) + ) + + @callback + def node_added(event: dict) -> None: + node = event["node"] + node_details = { + "node_id": node.node_id, + "status": node.status, + "ready": node.ready, + } + connection.send_message( + websocket_api.event_message( + msg[ID], {"event": "node added", "node": node_details} + ) + ) + + @callback + def device_registered(device: DeviceEntry) -> None: + device_details = {"name": device.name, "id": device.id} + connection.send_message( + websocket_api.event_message( + msg[ID], {"event": "device registered", "device": device_details} + ) + ) + + connection.subscriptions[msg["id"]] = async_cleanup + unsubs = [ + controller.on("inclusion started", forward_event), + controller.on("inclusion failed", forward_event), + controller.on("inclusion stopped", forward_event), + controller.on("node added", node_added), + async_dispatcher_connect( + hass, EVENT_DEVICE_ADDED_TO_REGISTRY, device_registered + ), + ] + + result = await controller.async_begin_inclusion(include_non_secure) + connection.send_result( + msg[ID], + result, + ) + + +@websocket_api.require_admin # type: ignore +@websocket_api.async_response +@websocket_api.websocket_command( + { + vol.Required(TYPE): "zwave_js/stop_inclusion", + vol.Required(ENTRY_ID): str, + } +) +async def websocket_stop_inclusion( + hass: HomeAssistant, connection: ActiveConnection, msg: dict +) -> None: + """Cancel adding a node to the Z-Wave network.""" + entry_id = msg[ENTRY_ID] + client = hass.data[DOMAIN][entry_id][DATA_CLIENT] + controller = client.driver.controller + result = await controller.async_stop_inclusion() + connection.send_result( + msg[ID], + result, + ) + + +@websocket_api.require_admin # type: ignore +@websocket_api.async_response +@websocket_api.websocket_command( + { + vol.Required(TYPE): "zwave_js/stop_exclusion", + vol.Required(ENTRY_ID): str, + } +) +async def websocket_stop_exclusion( + hass: HomeAssistant, connection: ActiveConnection, msg: dict +) -> None: + """Cancel removing a node from the Z-Wave network.""" + entry_id = msg[ENTRY_ID] + client = hass.data[DOMAIN][entry_id][DATA_CLIENT] + controller = client.driver.controller + result = await controller.async_stop_exclusion() + connection.send_result( + msg[ID], + result, + ) + + +@websocket_api.require_admin # type:ignore +@websocket_api.async_response +@websocket_api.websocket_command( + { + vol.Required(TYPE): "zwave_js/remove_node", + vol.Required(ENTRY_ID): str, + } +) +async def websocket_remove_node( + hass: HomeAssistant, connection: ActiveConnection, msg: dict +) -> None: + """Remove a node from the Z-Wave network.""" + entry_id = msg[ENTRY_ID] + client = hass.data[DOMAIN][entry_id][DATA_CLIENT] + controller = client.driver.controller + + @callback + def async_cleanup() -> None: + """Remove signal listeners.""" + for unsub in unsubs: + unsub() + + @callback + def forward_event(event: dict) -> None: + connection.send_message( + websocket_api.event_message(msg[ID], {"event": event["event"]}) + ) + + @callback + def node_removed(event: dict) -> None: + node = event["node"] + node_details = { + "node_id": node.node_id, + } + + # Remove from device registry + hass.async_create_task(remove_from_device_registry(hass, client, node)) + + connection.send_message( + websocket_api.event_message( + msg[ID], {"event": "node removed", "node": node_details} + ) + ) + + connection.subscriptions[msg["id"]] = async_cleanup + unsubs = [ + controller.on("exclusion started", forward_event), + controller.on("exclusion failed", forward_event), + controller.on("exclusion stopped", forward_event), + controller.on("node removed", node_removed), + ] + + result = await controller.async_begin_exclusion() + connection.send_result( + msg[ID], + result, + ) + + +async def remove_from_device_registry( + hass: HomeAssistant, client: ZwaveClient, node: ZwaveNode +) -> None: + """Remove a node from the device registry.""" + registry = await device_registry.async_get_registry(hass) + device = registry.async_get_device( + {(DOMAIN, f"{client.driver.controller.home_id}-{node.node_id}")} + ) + if device is None: + return + + registry.async_remove_device(device.id) diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index 5c82d70152e..72c53e22bfc 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -3,6 +3,7 @@ import json from unittest.mock import DEFAULT, patch import pytest +from zwave_js_server.event import Event from zwave_js_server.model.driver import Driver from zwave_js_server.model.node import Node from zwave_js_server.version import VersionInfo @@ -75,6 +76,12 @@ def climate_radio_thermostat_ct100_plus_state_fixture(): ) +@pytest.fixture(name="nortek_thermostat_state", scope="session") +def nortek_thermostat_state_fixture(): + """Load the nortek thermostat node state fixture data.""" + return json.loads(load_fixture("zwave_js/nortek_thermostat_state.json")) + + @pytest.fixture(name="client") def mock_client_fixture(controller_state, version_state): """Mock a client.""" @@ -140,6 +147,32 @@ def climate_radio_thermostat_ct100_plus_fixture( return node +@pytest.fixture(name="nortek_thermostat") +def nortek_thermostat_fixture(client, nortek_thermostat_state): + """Mock a nortek thermostat node.""" + node = Node(client, nortek_thermostat_state) + client.driver.controller.nodes[node.node_id] = node + return node + + +@pytest.fixture(name="nortek_thermostat_added_event") +def nortek_thermostat_added_event_fixture(client): + """Mock a Nortek thermostat node added event.""" + event_data = json.loads(load_fixture("zwave_js/nortek_thermostat_added_event.json")) + event = Event("node added", event_data) + return event + + +@pytest.fixture(name="nortek_thermostat_removed_event") +def nortek_thermostat_removed_event_fixture(client): + """Mock a Nortek thermostat node removed event.""" + event_data = json.loads( + load_fixture("zwave_js/nortek_thermostat_removed_event.json") + ) + event = Event("node removed", event_data) + return event + + @pytest.fixture(name="integration") async def integration_fixture(hass, client): """Set up the zwave_js integration.""" diff --git a/tests/components/zwave_js/test_websocket_api.py b/tests/components/zwave_js/test_websocket_api.py index b5fb97feff1..1eaf4277332 100644 --- a/tests/components/zwave_js/test_websocket_api.py +++ b/tests/components/zwave_js/test_websocket_api.py @@ -1,6 +1,9 @@ """Test the Z-Wave JS Websocket API.""" +from zwave_js_server.event import Event +from homeassistant.components.zwave_js.const import DOMAIN from homeassistant.components.zwave_js.websocket_api import ENTRY_ID, ID, TYPE +from homeassistant.helpers.device_registry import async_get_registry async def test_websocket_api(hass, integration, hass_ws_client): @@ -16,3 +19,117 @@ async def test_websocket_api(hass, integration, hass_ws_client): assert result["client"]["ws_server_url"] == "ws://test:3000/zjs" assert result["client"]["server_version"] == "1.0.0" + + +async def test_add_node( + hass, integration, client, hass_ws_client, nortek_thermostat_added_event +): + """Test the add_node websocket command.""" + entry = integration + ws_client = await hass_ws_client(hass) + + client.async_send_command.return_value = {"success": True} + + await ws_client.send_json( + {ID: 3, TYPE: "zwave_js/add_node", ENTRY_ID: entry.entry_id} + ) + + msg = await ws_client.receive_json() + assert msg["success"] + + event = Event( + type="inclusion started", + data={ + "source": "controller", + "event": "inclusion started", + "secure": False, + }, + ) + client.driver.receive_event(event) + + msg = await ws_client.receive_json() + assert msg["event"]["event"] == "inclusion started" + + client.driver.receive_event(nortek_thermostat_added_event) + msg = await ws_client.receive_json() + assert msg["event"]["event"] == "node added" + + +async def test_cancel_inclusion_exclusion(hass, integration, client, hass_ws_client): + """Test cancelling the inclusion and exclusion process.""" + entry = integration + ws_client = await hass_ws_client(hass) + + client.async_send_command.return_value = {"success": True} + + await ws_client.send_json( + {ID: 4, TYPE: "zwave_js/stop_inclusion", ENTRY_ID: entry.entry_id} + ) + + msg = await ws_client.receive_json() + assert msg["success"] + + await ws_client.send_json( + {ID: 5, TYPE: "zwave_js/stop_exclusion", ENTRY_ID: entry.entry_id} + ) + + msg = await ws_client.receive_json() + assert msg["success"] + + +async def test_remove_node( + hass, + integration, + client, + hass_ws_client, + nortek_thermostat, + nortek_thermostat_removed_event, +): + """Test the remove_node websocket command.""" + entry = integration + ws_client = await hass_ws_client(hass) + + client.async_send_command.return_value = {"success": True} + + await ws_client.send_json( + {ID: 3, TYPE: "zwave_js/remove_node", ENTRY_ID: entry.entry_id} + ) + + msg = await ws_client.receive_json() + assert msg["success"] + + event = Event( + type="exclusion started", + data={ + "source": "controller", + "event": "exclusion started", + "secure": False, + }, + ) + client.driver.receive_event(event) + + msg = await ws_client.receive_json() + assert msg["event"]["event"] == "exclusion started" + + # Add mock node to controller + client.driver.controller.nodes[67] = nortek_thermostat + + dev_reg = await async_get_registry(hass) + + # Create device registry entry for mock node + device = dev_reg.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, "3245146787-67")}, + name="Node 67", + ) + + # Fire node removed event + client.driver.receive_event(nortek_thermostat_removed_event) + msg = await ws_client.receive_json() + assert msg["event"]["event"] == "node removed" + + # Verify device was removed from device registry + device = dev_reg.async_get_device( + identifiers={(DOMAIN, "3245146787-67")}, + ) + assert device is None diff --git a/tests/fixtures/zwave_js/nortek_thermostat_added_event.json b/tests/fixtures/zwave_js/nortek_thermostat_added_event.json new file mode 100644 index 00000000000..d778f77ce24 --- /dev/null +++ b/tests/fixtures/zwave_js/nortek_thermostat_added_event.json @@ -0,0 +1,260 @@ +{ + "source": "controller", + "event": "node added", + "node": { + "nodeId": 53, + "index": 0, + "status": 0, + "ready": false, + "deviceClass": { + "basic": "Static Controller", + "generic": "Thermostat", + "specific": "Thermostat General V2", + "mandatorySupportedCCs": [ + "Basic", + "Manufacturer Specific", + "Thermostat Mode", + "Thermostat Setpoint", + "Version" + ], + "mandatoryControlCCs": [] + }, + "neighbors": [], + "interviewAttempts": 1, + "endpoints": [ + { + "nodeId": 53, + "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": "Manufacturer Specific", + "commandClass": 114, + "endpoint": 0, + "property": "manufacturerId", + "propertyName": "manufacturerId", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 65535, + "label": "Manufacturer ID" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "commandClassName": "Thermostat Mode", + "commandClass": 64, + "endpoint": 0, + "property": "mode", + "propertyName": "mode", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 0, + "max": 31, + "label": "Thermostat mode" + } + }, + { + "commandClassName": "Thermostat Mode", + "commandClass": 64, + "endpoint": 0, + "property": "manufacturerData", + "propertyName": "manufacturerData", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + } + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "libraryType", + "propertyName": "libraryType", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Library type" + } + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "protocolVersion", + "propertyName": "protocolVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol version" + } + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "firmwareVersions", + "propertyName": "firmwareVersions", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip firmware versions" + } + }, + { + "commandClassName": "Thermostat Operating State", + "commandClass": 66, + "endpoint": 0, + "property": "state", + "propertyName": "state", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 255, + "label": "Operating state", + "states": { + "0": "Idle", + "1": "Heating", + "2": "Cooling", + "3": "Fan Only", + "4": "Pending Heat", + "5": "Pending Cool", + "6": "Vent/Economizer", + "7": "Aux Heating", + "8": "2nd Stage Heating", + "9": "2nd Stage Cooling", + "10": "2nd Stage Aux Heat", + "11": "3rd Stage Aux Heat" + } + } + }, + { + "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" + } + }, + { + "commandClassName": "Battery", + "commandClass": 128, + "endpoint": 0, + "property": "isLow", + "propertyName": "isLow", + "metadata": { + "type": "boolean", + "readable": true, + "writeable": false, + "label": "Low battery level" + } + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "sceneId", + "propertyName": "sceneId", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 1, + "max": 255, + "label": "Scene ID" + } + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "dimmingDuration", + "propertyName": "dimmingDuration", + "metadata": { + "type": "any", + "readable": true, + "writeable": true, + "label": "Dimming duration" + } + } + ] + } +} \ No newline at end of file diff --git a/tests/fixtures/zwave_js/nortek_thermostat_removed_event.json b/tests/fixtures/zwave_js/nortek_thermostat_removed_event.json new file mode 100644 index 00000000000..ed25a650543 --- /dev/null +++ b/tests/fixtures/zwave_js/nortek_thermostat_removed_event.json @@ -0,0 +1,283 @@ +{ + "source": "controller", + "event": "node removed", + "node": { + "nodeId": 67, + "index": 0, + "status": 4, + "ready": true, + "deviceClass": { + "basic": "Static Controller", + "generic": "Thermostat", + "specific": "Thermostat General V2", + "mandatorySupportedCCs": [ + "Basic", + "Manufacturer Specific", + "Thermostat Mode", + "Thermostat Setpoint", + "Version" + ], + "mandatoryControlCCs": [] + }, + "isListening": false, + "isFrequentListening": true, + "isRouting": true, + "maxBaudRate": 40000, + "isSecure": false, + "version": 4, + "isBeaming": true, + "deviceConfig": { + "manufacturerId": 335, + "manufacturer": "Nortek Security & Control LLC", + "label": "GoControl GC-TBZ48", + "description": "Z-Wave Plus Thermostat", + "devices": [ + { + "productType": "0x5442", + "productId": "0x5431" + }, + { + "productType": "0x5442", + "productId": "0x5436" + }, + { + "productType": "0x5442", + "productId": "0x5437" + } + ], + "firmwareVersion": { + "min": "0.0", + "max": "255.255" + }, + "paramInformation": { + "_map": {} + } + }, + "label": "GoControl GC-TBZ48", + "neighbors": [ + 1, + 32, + 39, + 52 + ], + "interviewAttempts": 1, + "endpoints": [ + { + "nodeId": 67, + "index": 0 + } + ], + "values": [ + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "commandClassName": "Thermostat Mode", + "commandClass": 64, + "endpoint": 0, + "property": "mode", + "propertyName": "mode", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 0, + "max": 31, + "label": "Thermostat mode" + } + }, + { + "commandClassName": "Thermostat Mode", + "commandClass": 64, + "endpoint": 0, + "property": "manufacturerData", + "propertyName": "manufacturerData", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + } + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "libraryType", + "propertyName": "libraryType", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Library type" + } + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "protocolVersion", + "propertyName": "protocolVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol version" + } + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "firmwareVersions", + "propertyName": "firmwareVersions", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip firmware versions" + } + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "hardwareVersion", + "propertyName": "hardwareVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip hardware version" + } + }, + { + "commandClassName": "Thermostat Operating State", + "commandClass": 66, + "endpoint": 0, + "property": "state", + "propertyName": "state", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 255, + "label": "Operating state", + "states": { + "0": "Idle", + "1": "Heating", + "2": "Cooling", + "3": "Fan Only", + "4": "Pending Heat", + "5": "Pending Cool", + "6": "Vent/Economizer", + "7": "Aux Heating", + "8": "2nd Stage Heating", + "9": "2nd Stage Cooling", + "10": "2nd Stage Aux Heat", + "11": "3rd Stage Aux Heat" + } + } + }, + { + "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" + } + }, + { + "commandClassName": "Battery", + "commandClass": 128, + "endpoint": 0, + "property": "isLow", + "propertyName": "isLow", + "metadata": { + "type": "boolean", + "readable": true, + "writeable": false, + "label": "Low battery level" + } + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "sceneId", + "propertyName": "sceneId", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 1, + "max": 255, + "label": "Scene ID" + } + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "dimmingDuration", + "propertyName": "dimmingDuration", + "metadata": { + "type": "any", + "readable": true, + "writeable": true, + "label": "Dimming duration" + } + } + ] + } +} \ No newline at end of file diff --git a/tests/fixtures/zwave_js/nortek_thermostat_state.json b/tests/fixtures/zwave_js/nortek_thermostat_state.json new file mode 100644 index 00000000000..62a08999cda --- /dev/null +++ b/tests/fixtures/zwave_js/nortek_thermostat_state.json @@ -0,0 +1,1284 @@ +{ + "nodeId": 67, + "index": 0, + "installerIcon": 4608, + "userIcon": 4608, + "status": 4, + "ready": true, + "deviceClass": { + "basic": "Static Controller", + "generic": "Thermostat", + "specific": "Thermostat General V2", + "mandatorySupportedCCs": [ + "Basic", + "Manufacturer Specific", + "Thermostat Mode", + "Thermostat Setpoint", + "Version" + ], + "mandatoryControlCCs": [] + }, + "isListening": false, + "isFrequentListening": true, + "isRouting": true, + "maxBaudRate": 40000, + "isSecure": false, + "version": 4, + "isBeaming": true, + "manufacturerId": 335, + "productId": 21559, + "productType": 21570, + "firmwareVersion": "1.0", + "zwavePlusVersion": 1, + "nodeType": 0, + "roleType": 7, + "deviceConfig": { + "manufacturerId": 335, + "manufacturer": "Nortek Security & Control LLC", + "label": "GoControl GC-TBZ48", + "description": "Z-Wave Plus Thermostat", + "devices": [ + { + "productType": "0x5442", + "productId": "0x5431" + }, + { + "productType": "0x5442", + "productId": "0x5436" + }, + { + "productType": "0x5442", + "productId": "0x5437" + } + ], + "firmwareVersion": { + "min": "0.0", + "max": "255.255" + }, + "paramInformation": { + "_map": {} + } + }, + "label": "GoControl GC-TBZ48", + "neighbors": [ + 1, + 32, + 39, + 52 + ], + "interviewAttempts": 1, + "endpoints": [ + { + "nodeId": 67, + "index": 0, + "installerIcon": 4608, + "userIcon": 4608 + } + ], + "values": [ + { + "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": 335 + }, + { + "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": 21570 + }, + { + "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": 21559 + }, + { + "commandClassName": "Thermostat Mode", + "commandClass": 64, + "endpoint": 0, + "property": "mode", + "propertyName": "mode", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 0, + "max": 31, + "label": "Thermostat mode", + "states": { + "0": "Off", + "1": "Heat", + "2": "Cool", + "3": "Auto", + "4": "Auxiliary" + } + }, + "value": 0 + }, + { + "commandClassName": "Thermostat Mode", + "commandClass": 64, + "endpoint": 0, + "property": "manufacturerData", + "propertyName": "manufacturerData", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + } + }, + { + "commandClassName": "Thermostat Setpoint", + "commandClass": 67, + "endpoint": 0, + "property": "setpoint", + "propertyKey": 1, + "propertyName": "setpoint", + "propertyKeyName": "Heating", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "unit": "°F", + "ccSpecific": { + "setpointType": 1 + } + }, + "value": 72 + }, + { + "commandClassName": "Thermostat Setpoint", + "commandClass": 67, + "endpoint": 0, + "property": "setpoint", + "propertyKey": 2, + "propertyName": "setpoint", + "propertyKeyName": "Cooling", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "unit": "°F", + "ccSpecific": { + "setpointType": 2 + } + }, + "value": 80 + }, + { + "commandClassName": "Thermostat Setpoint", + "commandClass": 67, + "endpoint": 0, + "property": "setpoint", + "propertyKey": 11, + "propertyName": "setpoint", + "propertyKeyName": "Energy Save Heating", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "unit": "°F", + "ccSpecific": { + "setpointType": 11 + } + }, + "value": 62 + }, + { + "commandClassName": "Thermostat Setpoint", + "commandClass": 67, + "endpoint": 0, + "property": "setpoint", + "propertyKey": 12, + "propertyName": "setpoint", + "propertyKeyName": "Energy Save Cooling", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "unit": "°F", + "ccSpecific": { + "setpointType": 12 + } + }, + "value": 80 + }, + { + "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": "4.5" + }, + { + "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.0" + ] + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "hardwareVersion", + "propertyName": "hardwareVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip hardware version" + } + }, + { + "commandClassName": "Thermostat Operating State", + "commandClass": 66, + "endpoint": 0, + "property": "state", + "propertyName": "state", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 255, + "label": "Operating state", + "states": { + "0": "Idle", + "1": "Heating", + "2": "Cooling", + "3": "Fan Only", + "4": "Pending Heat", + "5": "Pending Cool", + "6": "Vent/Economizer", + "7": "Aux Heating", + "8": "2nd Stage Heating", + "9": "2nd Stage Cooling", + "10": "2nd Stage Aux Heat", + "11": "3rd Stage Aux Heat" + } + }, + "value": 64 + }, + { + "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": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 1, + "propertyName": "System Type", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Standard", + "1": "Heat Pump" + }, + "label": "System Type", + "description": "System Type", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 2, + "propertyName": "Fan Type", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Gas", + "1": "Electric" + }, + "label": "Fan Type", + "description": "Fan Type", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 3, + "propertyName": "Change Over Type", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "w/Cool", + "1": "w/Heat" + }, + "label": "Change Over Type", + "description": "Change Over Type", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 4, + "propertyName": "2nd Stage Heat Enable", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Disabled", + "1": "Enabled" + }, + "label": "2nd Stage Heat Enable", + "description": "2nd Stage Heat Enable", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 5, + "propertyName": "Aux Heat Enable", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Disabled", + "1": "Enabled" + }, + "label": "Aux Heat Enable", + "description": "Aux Heat Enable", + "isFromConfig": true + }, + "value": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 6, + "propertyName": "2nd Stage Cool Enable", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Disabled", + "1": "Enabled" + }, + "label": "2nd Stage Cool Enable", + "description": "2nd Stage Cool Enable", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 7, + "propertyName": "Temperature Unit", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 1, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Celsius", + "1": "Fahrenheit" + }, + "label": "Temperature Unit", + "description": "Temperature Unit", + "isFromConfig": true + }, + "value": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 8, + "propertyName": "Minimum Off Time", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 5, + "max": 9, + "default": 5, + "format": 0, + "allowManualEntry": true, + "label": "Minimum Off Time", + "description": "Minimum Off Time", + "isFromConfig": true + }, + "value": 5 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 9, + "propertyName": "Minimum Run Time", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 3, + "max": 9, + "default": 3, + "format": 0, + "allowManualEntry": true, + "label": "Minimum Run Time", + "description": "Minimum Run Time", + "isFromConfig": true + }, + "value": 3 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 10, + "propertyName": "Setpoint H/C Delta", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 3, + "max": 15, + "default": 3, + "format": 0, + "allowManualEntry": true, + "label": "Setpoint H/C Delta", + "description": "Setpoint H/C Delta", + "isFromConfig": true + }, + "value": 3 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 11, + "propertyName": "H Delta Stage 1 ON", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 1, + "max": 6, + "default": 1, + "format": 0, + "allowManualEntry": true, + "label": "H Delta Stage 1 ON", + "description": "H Delta Stage 1 ON", + "isFromConfig": true + }, + "value": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 12, + "propertyName": "H Delta Stage 1 OFF", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 5, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "H Delta Stage 1 OFF", + "description": "H Delta Stage 1 OFF", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 13, + "propertyName": "H Delta Stage 2 ON", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 2, + "max": 7, + "default": 2, + "format": 0, + "allowManualEntry": true, + "label": "H Delta Stage 2 ON", + "description": "H Delta Stage 2 ON", + "isFromConfig": true + }, + "value": 2 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 14, + "propertyName": "H Delta Stage 2 OFF", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 6, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "H Delta Stage 2 OFF", + "description": "H Delta Stage 2 OFF", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 15, + "propertyName": "H Delta Aux ON", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 3, + "max": 8, + "default": 3, + "format": 0, + "allowManualEntry": true, + "label": "H Delta Aux ON", + "description": "H Delta Aux ON", + "isFromConfig": true + }, + "value": 3 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 16, + "propertyName": "H Delta Stage 3 OFF", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 7, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "H Delta Stage 3 OFF", + "description": "H Delta Stage 3 OFF", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 17, + "propertyName": "C Delta Stage 1 ON", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 1, + "max": 6, + "default": 1, + "format": 0, + "allowManualEntry": true, + "label": "C Delta Stage 1 ON", + "description": "C Delta Stage 1 ON", + "isFromConfig": true + }, + "value": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 18, + "propertyName": "C Delta Stage 1 OFF", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 5, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "C Delta Stage 1 OFF", + "description": "C Delta Stage 1 OFF", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 19, + "propertyName": "C Delta Stage 2 ON", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 2, + "max": 7, + "default": 2, + "format": 0, + "allowManualEntry": true, + "label": "C Delta Stage 2 ON", + "description": "C Delta Stage 2 ON", + "isFromConfig": true + }, + "value": 2 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 20, + "propertyName": "C Delta Stage 2 OFF", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 6, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "C Delta Stage 2 OFF", + "description": "C Delta Stage 2 OFF", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 23, + "propertyName": "Lifeline Association Group Report To Send", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 4, + "min": 0, + "max": 65535, + "default": 8319, + "format": 0, + "allowManualEntry": true, + "label": "Lifeline Association Group Report To Send", + "description": "Lifeline Association Group Report To Send", + "isFromConfig": true + }, + "value": 8287 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 24, + "propertyName": "Display Lock", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Unlocked", + "1": "Locked" + }, + "label": "Display Lock", + "description": "Display Lock", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 26, + "propertyName": "Backlight Timer", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 10, + "max": 30, + "default": 20, + "format": 0, + "allowManualEntry": true, + "label": "Backlight Timer", + "description": "Backlight Timer", + "isFromConfig": true + }, + "value": 20 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 33, + "propertyName": "Max Heat Setpoint", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 30, + "max": 109, + "default": 90, + "format": 0, + "allowManualEntry": true, + "label": "Max Heat Setpoint", + "description": "Max Heat Setpoint", + "isFromConfig": true + }, + "value": 90 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 34, + "propertyName": "Min Cool Setpoint", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 33, + "max": 112, + "default": 61, + "format": 0, + "allowManualEntry": true, + "label": "Min Cool Setpoint", + "description": "Min Cool Setpoint", + "isFromConfig": true + }, + "value": 60 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 38, + "propertyName": "Schedule Enable", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Disabled", + "1": "Enabled" + }, + "label": "Schedule Enable", + "description": "Schedule Enable", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 39, + "propertyName": "Run/Hold Mode", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "Hold", + "1": "Run" + }, + "label": "Run/Hold Mode", + "description": "Run/Hold Mode", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 40, + "propertyName": "Setback Mode", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 2, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "No Setback", + "2": "Unoccupied Mode" + }, + "label": "Setback Mode", + "description": "Setback Mode", + "isFromConfig": true + }, + "value": -1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 41, + "propertyName": "Un-Occupied HSP", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 30, + "max": 109, + "default": 62, + "format": 0, + "allowManualEntry": true, + "label": "Un-Occupied HSP", + "description": "Un-Occupied HSP", + "isFromConfig": true + }, + "value": 62 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 42, + "propertyName": "Un-Occupied CSP", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 33, + "max": 112, + "default": 80, + "format": 0, + "allowManualEntry": true, + "label": "Un-Occupied CSP", + "description": "Un-Occupied CSP", + "isFromConfig": true + }, + "value": 80 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 43, + "propertyName": "Remote Sensor 1 Node Number", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 252, + "default": 0, + "format": 1, + "allowManualEntry": true, + "label": "Remote Sensor 1 Node Number", + "description": "Remote Sensor 1 Node Number", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 46, + "propertyName": "Remote Sensor 1 Temperature", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 112, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Remote Sensor 1 Temperature", + "description": "Remote Sensor 1 Temperature", + "isFromConfig": true + }, + "value": 71 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 48, + "propertyName": "Internal Sensor Temp Offset", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": -7, + "max": 7, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Internal Sensor Temp Offset", + "description": "Internal Sensor Temp Offset", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 49, + "propertyName": "R1 Sensor Temp Offset", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": -7, + "max": 7, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "R1 Sensor Temp Offset", + "description": "R1 Sensor Temp Offset", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 54, + "propertyName": "Heat Timer", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 2, + "min": 0, + "max": 4000, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Heat Timer", + "description": "Heat Timer", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 55, + "propertyName": "Cool Timer", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 2, + "min": 0, + "max": 4000, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Cool Timer", + "description": "Cool Timer", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 61, + "propertyName": "Fan Purge Heat", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 90, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Fan Purge Heat", + "description": "Fan Purge Heat", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 62, + "propertyName": "Fan Purge Cool", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 90, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Fan Purge Cool", + "description": "Fan Purge Cool", + "isFromConfig": true + }, + "value": 0 + }, + { + "commandClassName": "Multilevel Sensor", + "commandClass": 49, + "endpoint": 0, + "property": "Air temperature", + "propertyName": "Air temperature", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "unit": "°F", + "label": "Air temperature", + "ccSpecific": { + "sensorType": 1, + "scale": 1 + } + }, + "value": 71 + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "sceneId", + "propertyName": "sceneId", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 1, + "max": 255, + "label": "Scene ID" + } + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "dimmingDuration", + "propertyName": "dimmingDuration", + "metadata": { + "type": "any", + "readable": true, + "writeable": true, + "label": "Dimming duration" + } + } + ] +} \ No newline at end of file