diff --git a/homeassistant/components/zwave_js/api.py b/homeassistant/components/zwave_js/api.py index a55ae47b935fa4..6cd0ea4fe44b66 100644 --- a/homeassistant/components/zwave_js/api.py +++ b/homeassistant/components/zwave_js/api.py @@ -10,7 +10,7 @@ import voluptuous as vol from zwave_js_server import dump from zwave_js_server.client import Client -from zwave_js_server.const import CommandClass, LogLevel +from zwave_js_server.const import CommandClass, InclusionStrategy, LogLevel from zwave_js_server.exceptions import ( BaseZwaveJSServerError, FailedCommand, @@ -386,7 +386,11 @@ async def websocket_add_node( ) -> None: """Add a node to the Z-Wave network.""" controller = client.driver.controller - include_non_secure = not msg[SECURE] + + if msg[SECURE]: + inclusion_strategy = InclusionStrategy.SECURITY_S0 + else: + inclusion_strategy = InclusionStrategy.INSECURE @callback def async_cleanup() -> None: @@ -454,7 +458,7 @@ def device_registered(device: DeviceEntry) -> None: ), ] - result = await controller.async_begin_inclusion(include_non_secure) + result = await controller.async_begin_inclusion(inclusion_strategy) connection.send_result( msg[ID], result, @@ -594,9 +598,13 @@ async def websocket_replace_failed_node( ) -> None: """Replace a failed node with a new node.""" controller = client.driver.controller - include_non_secure = not msg[SECURE] node_id = msg[NODE_ID] + if msg[SECURE]: + inclusion_strategy = InclusionStrategy.SECURITY_S0 + else: + inclusion_strategy = InclusionStrategy.INSECURE + @callback def async_cleanup() -> None: """Remove signal listeners.""" @@ -677,7 +685,7 @@ def device_registered(device: DeviceEntry) -> None: ), ] - result = await controller.async_replace_failed_node(node_id, include_non_secure) + result = await controller.async_replace_failed_node(node_id, inclusion_strategy) connection.send_result( msg[ID], result, diff --git a/homeassistant/components/zwave_js/manifest.json b/homeassistant/components/zwave_js/manifest.json index b24bc957303d82..6f713ed2ef23e5 100644 --- a/homeassistant/components/zwave_js/manifest.json +++ b/homeassistant/components/zwave_js/manifest.json @@ -3,7 +3,7 @@ "name": "Z-Wave JS", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zwave_js", - "requirements": ["zwave-js-server-python==0.28.0"], + "requirements": ["zwave-js-server-python==0.29.0"], "codeowners": ["@home-assistant/z-wave"], "dependencies": ["http", "websocket_api"], "iot_class": "local_push" diff --git a/requirements_all.txt b/requirements_all.txt index a1b9869e1261c5..76891354250dd2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2482,4 +2482,4 @@ zigpy==0.36.1 zm-py==0.5.2 # homeassistant.components.zwave_js -zwave-js-server-python==0.28.0 +zwave-js-server-python==0.29.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index cacc3ed3f26667..50dbf55d42fa58 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1390,4 +1390,4 @@ zigpy-znp==0.5.3 zigpy==0.36.1 # homeassistant.components.zwave_js -zwave-js-server-python==0.28.0 +zwave-js-server-python==0.29.0 diff --git a/tests/components/zwave_js/test_api.py b/tests/components/zwave_js/test_api.py index 75fca7f11ff2d2..ee05724a9cb3f3 100644 --- a/tests/components/zwave_js/test_api.py +++ b/tests/components/zwave_js/test_api.py @@ -3,7 +3,7 @@ from unittest.mock import patch import pytest -from zwave_js_server.const import LogLevel +from zwave_js_server.const import InclusionStrategy, LogLevel from zwave_js_server.event import Event from zwave_js_server.exceptions import ( FailedCommand, @@ -29,6 +29,7 @@ OPTED_IN, PROPERTY, PROPERTY_KEY, + SECURE, TYPE, VALUE, ) @@ -318,6 +319,31 @@ async def test_ping_node( assert msg["error"]["code"] == ERR_NOT_LOADED +async def test_add_node_secure( + hass, nortek_thermostat_added_event, integration, client, hass_ws_client +): + """Test the add_node websocket command with secure flag.""" + entry = integration + ws_client = await hass_ws_client(hass) + + client.async_send_command.return_value = {"success": True} + + await ws_client.send_json( + {ID: 1, TYPE: "zwave_js/add_node", ENTRY_ID: entry.entry_id, SECURE: True} + ) + + msg = await ws_client.receive_json() + assert msg["success"] + + assert len(client.async_send_command.call_args_list) == 1 + assert client.async_send_command.call_args[0][0] == { + "command": "controller.begin_inclusion", + "options": {"inclusionStrategy": InclusionStrategy.SECURITY_S0}, + } + + client.async_send_command.reset_mock() + + async def test_add_node( hass, nortek_thermostat_added_event, integration, client, hass_ws_client ): @@ -334,6 +360,12 @@ async def test_add_node( msg = await ws_client.receive_json() assert msg["success"] + assert len(client.async_send_command.call_args_list) == 1 + assert client.async_send_command.call_args[0][0] == { + "command": "controller.begin_inclusion", + "options": {"inclusionStrategy": InclusionStrategy.INSECURE}, + } + event = Event( type="inclusion started", data={ @@ -599,6 +631,52 @@ async def test_remove_node( assert msg["error"]["code"] == ERR_NOT_LOADED +async def test_replace_failed_node_secure( + hass, + nortek_thermostat, + integration, + client, + hass_ws_client, +): + """Test the replace_failed_node websocket command with secure flag.""" + entry = integration + ws_client = await hass_ws_client(hass) + + dev_reg = dr.async_get(hass) + + # Create device registry entry for mock node + dev_reg.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, "3245146787-67")}, + name="Node 67", + ) + + client.async_send_command.return_value = {"success": True} + + await ws_client.send_json( + { + ID: 1, + TYPE: "zwave_js/replace_failed_node", + ENTRY_ID: entry.entry_id, + NODE_ID: 67, + SECURE: True, + } + ) + + msg = await ws_client.receive_json() + assert msg["success"] + assert msg["result"] + + assert len(client.async_send_command.call_args_list) == 1 + assert client.async_send_command.call_args[0][0] == { + "command": "controller.replace_failed_node", + "nodeId": nortek_thermostat.node_id, + "options": {"inclusionStrategy": InclusionStrategy.SECURITY_S0}, + } + + client.async_send_command.reset_mock() + + async def test_replace_failed_node( hass, nortek_thermostat, @@ -638,6 +716,15 @@ async def test_replace_failed_node( assert msg["success"] assert msg["result"] + assert len(client.async_send_command.call_args_list) == 1 + assert client.async_send_command.call_args[0][0] == { + "command": "controller.replace_failed_node", + "nodeId": nortek_thermostat.node_id, + "options": {"inclusionStrategy": InclusionStrategy.INSECURE}, + } + + client.async_send_command.reset_mock() + event = Event( type="inclusion started", data={ diff --git a/tests/components/zwave_js/test_device_condition.py b/tests/components/zwave_js/test_device_condition.py index 0256981a72633a..dd5507d4c0a1d7 100644 --- a/tests/components/zwave_js/test_device_condition.py +++ b/tests/components/zwave_js/test_device_condition.py @@ -437,7 +437,7 @@ async def test_get_condition_capabilities_value( (98, "DOOR_LOCK"), (122, "FIRMWARE_UPDATE_MD"), (114, "MANUFACTURER_SPECIFIC"), - (113, "ALARM"), + (113, "NOTIFICATION"), (152, "SECURITY"), (99, "USER_CODE"), (134, "VERSION"),