diff --git a/homeassistant/components/zwave_js/api.py b/homeassistant/components/zwave_js/api.py index 7d1c4622d50..d83b7261b5f 100644 --- a/homeassistant/components/zwave_js/api.py +++ b/homeassistant/components/zwave_js/api.py @@ -68,7 +68,11 @@ from .const import ( EVENT_DEVICE_ADDED_TO_REGISTRY, LOGGER, ) -from .helpers import async_enable_statistics, update_data_collection_preference +from .helpers import ( + async_enable_statistics, + async_get_node_from_device_id, + update_data_collection_preference, +) from .migrate import ( ZWaveMigrationData, async_get_migration_data, @@ -83,6 +87,7 @@ ID = "id" ENTRY_ID = "entry_id" ERR_NOT_LOADED = "not_loaded" NODE_ID = "node_id" +DEVICE_ID = "device_id" COMMAND_CLASS_ID = "command_class_id" TYPE = "type" PROPERTY = "property" @@ -254,21 +259,20 @@ def async_get_entry(orig_func: Callable) -> Callable: def async_get_node(orig_func: Callable) -> Callable: """Decorate async function to get node.""" - @async_get_entry @wraps(orig_func) async def async_get_node_func( - hass: HomeAssistant, - connection: ActiveConnection, - msg: dict, - entry: ConfigEntry, - client: Client, + hass: HomeAssistant, connection: ActiveConnection, msg: dict ) -> None: """Provide user specific data and store to function.""" - node_id = msg[NODE_ID] - node = client.driver.controller.nodes.get(node_id) + device_id = msg[DEVICE_ID] - if node is None: - connection.send_error(msg[ID], ERR_NOT_FOUND, f"Node {node_id} not found") + try: + node = async_get_node_from_device_id(hass, device_id) + except ValueError as err: + error_code = ERR_NOT_FOUND + if "loaded" in err.args[0]: + error_code = ERR_NOT_LOADED + connection.send_error(msg[ID], error_code, err.args[0]) return await orig_func(hass, connection, msg, node) @@ -299,13 +303,26 @@ def async_handle_failed_command(orig_func: Callable) -> Callable: return async_handle_failed_command_func +def node_status(node: Node) -> dict[str, Any]: + """Get node status.""" + return { + "node_id": node.node_id, + "is_routing": node.is_routing, + "status": node.status, + "is_secure": node.is_secure, + "ready": node.ready, + "zwave_plus_version": node.zwave_plus_version, + "highest_security_class": node.highest_security_class, + "is_controller_node": node.is_controller_node, + } + + @callback 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_node_status) websocket_api.async_register_command(hass, websocket_node_metadata) - websocket_api.async_register_command(hass, websocket_ping_node) websocket_api.async_register_command(hass, websocket_add_node) websocket_api.async_register_command(hass, websocket_grant_security_classes) websocket_api.async_register_command(hass, websocket_validate_dsk_and_enter_pin) @@ -395,7 +412,9 @@ async def websocket_network_status( "supports_timers": controller.supports_timers, "is_heal_network_active": controller.is_heal_network_active, "inclusion_state": controller.inclusion_state, - "nodes": list(client.driver.controller.nodes), + "nodes": [ + node_status(node) for node in client.driver.controller.nodes.values() + ], }, } connection.send_result( @@ -407,8 +426,7 @@ async def websocket_network_status( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/node_ready", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @@ -443,8 +461,7 @@ async def websocket_node_ready( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/node_status", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @@ -456,27 +473,13 @@ async def websocket_node_status( node: Node, ) -> None: """Get the status of a Z-Wave JS node.""" - data = { - "node_id": node.node_id, - "is_routing": node.is_routing, - "status": node.status, - "is_secure": node.is_secure, - "ready": node.ready, - "zwave_plus_version": node.zwave_plus_version, - "highest_security_class": node.highest_security_class, - "is_controller_node": node.is_controller_node, - } - connection.send_result( - msg[ID], - data, - ) + connection.send_result(msg[ID], node_status(node)) @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/node_metadata", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @@ -504,30 +507,6 @@ async def websocket_node_metadata( ) -@websocket_api.websocket_command( - { - vol.Required(TYPE): "zwave_js/ping_node", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, - } -) -@websocket_api.async_response -@async_handle_failed_command -@async_get_node -async def websocket_ping_node( - hass: HomeAssistant, - connection: ActiveConnection, - msg: dict, - node: Node, -) -> None: - """Ping a Z-Wave JS node.""" - result = await node.async_ping() - connection.send_result( - msg[ID], - result, - ) - - @websocket_api.require_admin @websocket_api.websocket_command( { @@ -1189,23 +1168,20 @@ async def websocket_replace_failed_node( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/remove_failed_node", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @async_handle_failed_command -@async_get_entry +@async_get_node async def websocket_remove_failed_node( hass: HomeAssistant, connection: ActiveConnection, msg: dict, - entry: ConfigEntry, - client: Client, + node: Node, ) -> None: """Remove a failed node from the Z-Wave network.""" - controller = client.driver.controller - node_id = msg[NODE_ID] + controller = node.client.driver.controller @callback def async_cleanup() -> None: @@ -1215,10 +1191,7 @@ async def websocket_remove_failed_node( @callback def node_removed(event: dict) -> None: - node = event["node"] - node_details = { - "node_id": node.node_id, - } + node_details = {"node_id": event["node"].node_id} connection.send_message( websocket_api.event_message( @@ -1229,7 +1202,7 @@ async def websocket_remove_failed_node( connection.subscriptions[msg["id"]] = async_cleanup msg[DATA_UNSUBSCRIBE] = unsubs = [controller.on("node removed", node_removed)] - result = await controller.async_remove_failed_node(node_id) + result = await controller.async_remove_failed_node(node.node_id) connection.send_result( msg[ID], result, @@ -1335,24 +1308,21 @@ async def websocket_stop_healing_network( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/heal_node", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @async_handle_failed_command -@async_get_entry +@async_get_node async def websocket_heal_node( hass: HomeAssistant, connection: ActiveConnection, msg: dict, - entry: ConfigEntry, - client: Client, + node: Node, ) -> None: """Heal a node on the Z-Wave network.""" - controller = client.driver.controller - node_id = msg[NODE_ID] - result = await controller.async_heal_node(node_id) + controller = node.client.driver.controller + result = await controller.async_heal_node(node.node_id) connection.send_result( msg[ID], result, @@ -1363,8 +1333,7 @@ async def websocket_heal_node( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/refresh_node_info", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, }, ) @websocket_api.async_response @@ -1414,8 +1383,7 @@ async def websocket_refresh_node_info( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/refresh_node_values", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, }, ) @websocket_api.async_response @@ -1436,8 +1404,7 @@ async def websocket_refresh_node_values( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/refresh_node_cc_values", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, vol.Required(COMMAND_CLASS_ID): int, }, ) @@ -1469,8 +1436,7 @@ async def websocket_refresh_node_cc_values( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/set_config_parameter", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, vol.Required(PROPERTY): int, vol.Optional(PROPERTY_KEY): int, vol.Required(VALUE): vol.Any(int, BITMASK_SCHEMA), @@ -1521,8 +1487,7 @@ async def websocket_set_config_parameter( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/get_config_parameters", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @@ -1762,8 +1727,7 @@ async def websocket_data_collection_status( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/abort_firmware_update", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @@ -1794,8 +1758,7 @@ def _get_firmware_update_progress_dict( @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/subscribe_firmware_update_status", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response @@ -2047,8 +2010,7 @@ def _get_node_statistics_dict(statistics: NodeStatistics) -> dict[str, int]: @websocket_api.websocket_command( { vol.Required(TYPE): "zwave_js/subscribe_node_statistics", - vol.Required(ENTRY_ID): str, - vol.Required(NODE_ID): int, + vol.Required(DEVICE_ID): str, } ) @websocket_api.async_response diff --git a/homeassistant/components/zwave_js/helpers.py b/homeassistant/components/zwave_js/helpers.py index c4eb0396287..68ff0c89b15 100644 --- a/homeassistant/components/zwave_js/helpers.py +++ b/homeassistant/components/zwave_js/helpers.py @@ -179,24 +179,22 @@ def async_get_node_from_device_id( # Use device config entry ID's to validate that this is a valid zwave_js device # and to get the client config_entry_ids = device_entry.config_entries - config_entry_id = next( + entry = next( ( - config_entry_id - for config_entry_id in config_entry_ids - if cast( - ConfigEntry, - hass.config_entries.async_get_entry(config_entry_id), - ).domain - == DOMAIN + entry + for entry in hass.config_entries.async_entries(DOMAIN) + if entry.entry_id in config_entry_ids ), None, ) - if config_entry_id is None or config_entry_id not in hass.data[DOMAIN]: + if entry and entry.state != ConfigEntryState.LOADED: + raise ValueError(f"Device {device_id} config entry is not loaded") + if entry is None or entry.entry_id not in hass.data[DOMAIN]: raise ValueError( f"Device {device_id} is not from an existing zwave_js config entry" ) - client = hass.data[DOMAIN][config_entry_id][DATA_CLIENT] + client = hass.data[DOMAIN][entry.entry_id][DATA_CLIENT] # Get node ID from device identifier, perform some validation, and then get the # node @@ -390,21 +388,6 @@ def copy_available_params( ) -@callback -def async_is_device_config_entry_not_loaded( - hass: HomeAssistant, device_id: str -) -> bool: - """Return whether device's config entries are not loaded.""" - dev_reg = dr.async_get(hass) - if (device := dev_reg.async_get(device_id)) is None: - raise ValueError(f"Device {device_id} not found") - return any( - (entry := hass.config_entries.async_get_entry(entry_id)) - and entry.state != ConfigEntryState.LOADED - for entry_id in device.config_entries - ) - - def get_value_state_schema( value: ZwaveValue, ) -> vol.Schema | None: diff --git a/tests/components/zwave_js/test_api.py b/tests/components/zwave_js/test_api.py index d8a36fc6509..60b83630add 100644 --- a/tests/components/zwave_js/test_api.py +++ b/tests/components/zwave_js/test_api.py @@ -35,6 +35,7 @@ from homeassistant.components.zwave_js.api import ( CLIENT_SIDE_AUTH, COMMAND_CLASS_ID, CONFIG, + DEVICE_ID, DSK, ENABLED, ENTRY_ID, @@ -70,9 +71,17 @@ from homeassistant.components.zwave_js.const import ( CONF_DATA_COLLECTION_OPTED_IN, DOMAIN, ) +from homeassistant.components.zwave_js.helpers import get_device_id from homeassistant.helpers import device_registry as dr +def get_device(hass, node): + """Get device ID for a node.""" + dev_reg = dr.async_get(hass) + device_id = get_device_id(node.client, node) + return dev_reg.async_get_device({device_id}) + + async def test_network_status(hass, integration, hass_ws_client): """Test the network status websocket command.""" entry = integration @@ -117,12 +126,16 @@ async def test_node_ready( node.data["ready"] = False client.driver.controller.nodes[node.node_id] = node + dev_reg = dr.async_get(hass) + device = dev_reg.async_get_or_create( + config_entry_id=entry.entry_id, identifiers={get_device_id(client, node)} + ) + await ws_client.send_json( { ID: 3, TYPE: "zwave_js/node_ready", - ENTRY_ID: entry.entry_id, - "node_id": node.node_id, + DEVICE_ID: device.id, } ) @@ -153,12 +166,12 @@ async def test_node_status(hass, multisensor_6, integration, hass_ws_client): ws_client = await hass_ws_client(hass) node = multisensor_6 + device = get_device(hass, node) await ws_client.send_json( { ID: 3, TYPE: "zwave_js/node_status", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -178,8 +191,7 @@ async def test_node_status(hass, multisensor_6, integration, hass_ws_client): { ID: 4, TYPE: "zwave_js/node_status", - ENTRY_ID: entry.entry_id, - NODE_ID: 99999, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -194,8 +206,7 @@ async def test_node_status(hass, multisensor_6, integration, hass_ws_client): { ID: 5, TYPE: "zwave_js/node_status", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -210,12 +221,12 @@ async def test_node_metadata(hass, wallmote_central_scene, integration, hass_ws_ ws_client = await hass_ws_client(hass) node = wallmote_central_scene + device = get_device(hass, node) await ws_client.send_json( { ID: 3, TYPE: "zwave_js/node_metadata", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -256,8 +267,7 @@ async def test_node_metadata(hass, wallmote_central_scene, integration, hass_ws_ { ID: 4, TYPE: "zwave_js/node_metadata", - ENTRY_ID: entry.entry_id, - NODE_ID: 99999, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -272,81 +282,7 @@ async def test_node_metadata(hass, wallmote_central_scene, integration, hass_ws_ { ID: 5, TYPE: "zwave_js/node_metadata", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, - } - ) - msg = await ws_client.receive_json() - - assert not msg["success"] - assert msg["error"]["code"] == ERR_NOT_LOADED - - -async def test_ping_node( - hass, wallmote_central_scene, integration, client, hass_ws_client -): - """Test the ping_node websocket command.""" - entry = integration - ws_client = await hass_ws_client(hass) - node = wallmote_central_scene - - client.async_send_command.return_value = {"responded": True} - - await ws_client.send_json( - { - ID: 3, - TYPE: "zwave_js/ping_node", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, - } - ) - - msg = await ws_client.receive_json() - assert msg["success"] - assert msg["result"] - - # Test getting non-existent node fails - await ws_client.send_json( - { - ID: 4, - TYPE: "zwave_js/ping_node", - ENTRY_ID: entry.entry_id, - NODE_ID: 99999, - } - ) - msg = await ws_client.receive_json() - assert not msg["success"] - assert msg["error"]["code"] == ERR_NOT_FOUND - - # Test FailedZWaveCommand is caught - with patch( - "zwave_js_server.model.node.Node.async_ping", - side_effect=FailedZWaveCommand("failed_command", 1, "error message"), - ): - await ws_client.send_json( - { - ID: 5, - TYPE: "zwave_js/ping_node", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, - } - ) - msg = await ws_client.receive_json() - - assert not msg["success"] - assert msg["error"]["code"] == "zwave_error" - assert msg["error"]["message"] == "Z-Wave error 1: error message" - - # Test sending command with not loaded entry fails - await hass.config_entries.async_unload(entry.entry_id) - await hass.async_block_till_done() - - await ws_client.send_json( - { - ID: 6, - TYPE: "zwave_js/ping_node", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -1812,19 +1748,38 @@ async def test_remove_failed_node( client, hass_ws_client, nortek_thermostat_removed_event, + nortek_thermostat_added_event, ): """Test the remove_failed_node websocket command.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, nortek_thermostat) client.async_send_command.return_value = {"success": True} + # Test FailedZWaveCommand is caught + with patch( + "zwave_js_server.model.controller.Controller.async_remove_failed_node", + side_effect=FailedZWaveCommand("failed_command", 1, "error message"), + ): + await ws_client.send_json( + { + ID: 1, + TYPE: "zwave_js/remove_failed_node", + DEVICE_ID: device.id, + } + ) + msg = await ws_client.receive_json() + + assert not msg["success"] + assert msg["error"]["code"] == "zwave_error" + assert msg["error"]["message"] == "Z-Wave error 1: error message" + await ws_client.send_json( { - ID: 3, + ID: 2, TYPE: "zwave_js/remove_failed_node", - ENTRY_ID: entry.entry_id, - NODE_ID: 67, + DEVICE_ID: device.id, } ) @@ -1846,29 +1801,15 @@ async def test_remove_failed_node( 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 - - # Test FailedZWaveCommand is caught - with patch( - "zwave_js_server.model.controller.Controller.async_remove_failed_node", - side_effect=FailedZWaveCommand("failed_command", 1, "error message"), - ): - await ws_client.send_json( - { - ID: 4, - TYPE: "zwave_js/remove_failed_node", - ENTRY_ID: entry.entry_id, - NODE_ID: 67, - } + assert ( + dev_reg.async_get_device( + identifiers={(DOMAIN, "3245146787-67")}, ) - msg = await ws_client.receive_json() + is None + ) - assert not msg["success"] - assert msg["error"]["code"] == "zwave_error" - assert msg["error"]["message"] == "Z-Wave error 1: error message" + # Re-add node so we can test config entry not loaded + client.driver.receive_event(nortek_thermostat_added_event) # Test sending command with not loaded entry fails await hass.config_entries.async_unload(entry.entry_id) @@ -1876,10 +1817,9 @@ async def test_remove_failed_node( await ws_client.send_json( { - ID: 5, + ID: 3, TYPE: "zwave_js/remove_failed_node", - ENTRY_ID: entry.entry_id, - NODE_ID: 67, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2091,6 +2031,7 @@ async def test_stop_healing_network( async def test_heal_node( hass, + multisensor_6, integration, client, hass_ws_client, @@ -2098,6 +2039,7 @@ async def test_heal_node( """Test the heal_node websocket command.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) client.async_send_command.return_value = {"success": True} @@ -2105,8 +2047,7 @@ async def test_heal_node( { ID: 3, TYPE: "zwave_js/heal_node", - ENTRY_ID: entry.entry_id, - NODE_ID: 67, + DEVICE_ID: device.id, } ) @@ -2123,8 +2064,7 @@ async def test_heal_node( { ID: 4, TYPE: "zwave_js/heal_node", - ENTRY_ID: entry.entry_id, - NODE_ID: 67, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2141,8 +2081,7 @@ async def test_heal_node( { ID: 5, TYPE: "zwave_js/heal_node", - ENTRY_ID: entry.entry_id, - NODE_ID: 67, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2158,13 +2097,14 @@ async def test_refresh_node_info( entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) + client.async_send_command_no_wait.return_value = None await ws_client.send_json( { ID: 1, TYPE: "zwave_js/refresh_node_info", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2232,8 +2172,7 @@ async def test_refresh_node_info( { ID: 2, TYPE: "zwave_js/refresh_node_info", - ENTRY_ID: entry.entry_id, - NODE_ID: 9999, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -2249,8 +2188,7 @@ async def test_refresh_node_info( { ID: 3, TYPE: "zwave_js/refresh_node_info", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2267,8 +2205,7 @@ async def test_refresh_node_info( { ID: 4, TYPE: "zwave_js/refresh_node_info", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2283,14 +2220,14 @@ async def test_refresh_node_values( """Test that the refresh_node_values WS API call works.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) client.async_send_command_no_wait.return_value = None await ws_client.send_json( { ID: 1, TYPE: "zwave_js/refresh_node_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2303,26 +2240,12 @@ async def test_refresh_node_values( client.async_send_command_no_wait.reset_mock() - # Test getting non-existent node fails + # Test getting non-existent device fails await ws_client.send_json( { ID: 2, TYPE: "zwave_js/refresh_node_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 99999, - } - ) - msg = await ws_client.receive_json() - assert not msg["success"] - assert msg["error"]["code"] == ERR_NOT_FOUND - - # Test getting non-existent entry fails - await ws_client.send_json( - { - ID: 3, - TYPE: "zwave_js/refresh_node_values", - ENTRY_ID: "fake_entry_id", - NODE_ID: 52, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -2338,8 +2261,7 @@ async def test_refresh_node_values( { ID: 4, TYPE: "zwave_js/refresh_node_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2356,8 +2278,7 @@ async def test_refresh_node_values( { ID: 5, TYPE: "zwave_js/refresh_node_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2367,19 +2288,19 @@ async def test_refresh_node_values( async def test_refresh_node_cc_values( - hass, client, multisensor_6, integration, hass_ws_client + hass, multisensor_6, client, integration, hass_ws_client ): """Test that the refresh_node_cc_values WS API call works.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) client.async_send_command_no_wait.return_value = None await ws_client.send_json( { ID: 1, TYPE: "zwave_js/refresh_node_cc_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, COMMAND_CLASS_ID: 112, } ) @@ -2399,8 +2320,7 @@ async def test_refresh_node_cc_values( { ID: 2, TYPE: "zwave_js/refresh_node_cc_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, COMMAND_CLASS_ID: 9999, } ) @@ -2408,13 +2328,12 @@ async def test_refresh_node_cc_values( assert not msg["success"] assert msg["error"]["code"] == ERR_NOT_FOUND - # Test getting non-existent node fails + # Test getting non-existent device fails await ws_client.send_json( { ID: 3, TYPE: "zwave_js/refresh_node_cc_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 9999, + DEVICE_ID: "fake_device", COMMAND_CLASS_ID: 112, } ) @@ -2431,8 +2350,7 @@ async def test_refresh_node_cc_values( { ID: 4, TYPE: "zwave_js/refresh_node_cc_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, COMMAND_CLASS_ID: 112, } ) @@ -2450,8 +2368,7 @@ async def test_refresh_node_cc_values( { ID: 5, TYPE: "zwave_js/refresh_node_cc_values", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, COMMAND_CLASS_ID: 112, } ) @@ -2462,11 +2379,12 @@ async def test_refresh_node_cc_values( async def test_set_config_parameter( - hass, client, hass_ws_client, multisensor_6, integration + hass, multisensor_6, client, hass_ws_client, integration ): """Test the set_config_parameter service.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) client.async_send_command_no_wait.return_value = None @@ -2474,8 +2392,7 @@ async def test_set_config_parameter( { ID: 1, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, @@ -2523,8 +2440,7 @@ async def test_set_config_parameter( { ID: 2, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: "0x1", @@ -2573,8 +2489,7 @@ async def test_set_config_parameter( { ID: 3, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, @@ -2593,8 +2508,7 @@ async def test_set_config_parameter( { ID: 4, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, @@ -2613,8 +2527,7 @@ async def test_set_config_parameter( { ID: 5, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, @@ -2633,8 +2546,7 @@ async def test_set_config_parameter( { ID: 6, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 9999, + DEVICE_ID: "fake_device", PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, @@ -2653,8 +2565,7 @@ async def test_set_config_parameter( { ID: 7, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, @@ -2674,8 +2585,7 @@ async def test_set_config_parameter( { ID: 8, TYPE: "zwave_js/set_config_parameter", - ENTRY_ID: entry.entry_id, - NODE_ID: 52, + DEVICE_ID: device.id, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, @@ -2693,14 +2603,14 @@ async def test_get_config_parameters(hass, multisensor_6, integration, hass_ws_c entry = integration ws_client = await hass_ws_client(hass) node = multisensor_6 + device = get_device(hass, node) # Test getting configuration parameter values await ws_client.send_json( { ID: 4, TYPE: "zwave_js/get_config_parameters", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -2722,8 +2632,7 @@ async def test_get_config_parameters(hass, multisensor_6, integration, hass_ws_c { ID: 5, TYPE: "zwave_js/get_config_parameters", - ENTRY_ID: entry.entry_id, - NODE_ID: 99999, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -2738,8 +2647,7 @@ async def test_get_config_parameters(hass, multisensor_6, integration, hass_ws_c { ID: 6, TYPE: "zwave_js/get_config_parameters", - ENTRY_ID: entry.entry_id, - NODE_ID: node.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -3276,14 +3184,14 @@ async def test_abort_firmware_update( """Test that the abort_firmware_update WS API call works.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) client.async_send_command_no_wait.return_value = {} await ws_client.send_json( { ID: 1, TYPE: "zwave_js/abort_firmware_update", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -3303,8 +3211,7 @@ async def test_abort_firmware_update( { ID: 2, TYPE: "zwave_js/abort_firmware_update", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -3321,8 +3228,7 @@ async def test_abort_firmware_update( { ID: 3, TYPE: "zwave_js/abort_firmware_update", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -3332,32 +3238,19 @@ async def test_abort_firmware_update( async def test_abort_firmware_update_failures( - hass, integration, multisensor_6, client, hass_ws_client + hass, multisensor_6, client, integration, hass_ws_client ): """Test failures for the abort_firmware_update websocket command.""" entry = integration ws_client = await hass_ws_client(hass) - # Test sending command with improper entry ID fails - await ws_client.send_json( - { - ID: 1, - TYPE: "zwave_js/abort_firmware_update", - ENTRY_ID: "fake_entry_id", - NODE_ID: multisensor_6.node_id, - } - ) - msg = await ws_client.receive_json() + device = get_device(hass, multisensor_6) - assert not msg["success"] - assert msg["error"]["code"] == ERR_NOT_FOUND - - # Test sending command with improper node ID fails + # Test sending command with improper device ID fails await ws_client.send_json( { ID: 2, TYPE: "zwave_js/abort_firmware_update", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id + 100, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -3373,8 +3266,7 @@ async def test_abort_firmware_update_failures( { ID: 3, TYPE: "zwave_js/abort_firmware_update", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -3384,11 +3276,11 @@ async def test_abort_firmware_update_failures( async def test_subscribe_firmware_update_status( - hass, integration, multisensor_6, client, hass_ws_client + hass, multisensor_6, integration, client, hass_ws_client ): """Test the subscribe_firmware_update_status websocket command.""" - entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) client.async_send_command_no_wait.return_value = {} @@ -3396,8 +3288,7 @@ async def test_subscribe_firmware_update_status( { ID: 1, TYPE: "zwave_js/subscribe_firmware_update_status", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) @@ -3445,11 +3336,11 @@ async def test_subscribe_firmware_update_status( async def test_subscribe_firmware_update_status_initial_value( - hass, integration, multisensor_6, client, hass_ws_client + hass, multisensor_6, client, integration, hass_ws_client ): """Test subscribe_firmware_update_status websocket command with in progress update.""" - entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) assert multisensor_6.firmware_update_progress is None @@ -3472,8 +3363,7 @@ async def test_subscribe_firmware_update_status_initial_value( { ID: 1, TYPE: "zwave_js/subscribe_firmware_update_status", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) @@ -3490,32 +3380,18 @@ async def test_subscribe_firmware_update_status_initial_value( async def test_subscribe_firmware_update_status_failures( - hass, integration, multisensor_6, client, hass_ws_client + hass, multisensor_6, client, integration, hass_ws_client ): """Test failures for the subscribe_firmware_update_status websocket command.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) # Test sending command with improper entry ID fails await ws_client.send_json( { ID: 1, TYPE: "zwave_js/subscribe_firmware_update_status", - ENTRY_ID: "fake_entry_id", - NODE_ID: multisensor_6.node_id, - } - ) - msg = await ws_client.receive_json() - - assert not msg["success"] - assert msg["error"]["code"] == ERR_NOT_FOUND - - # Test sending command with improper node ID fails - await ws_client.send_json( - { - ID: 2, - TYPE: "zwave_js/subscribe_firmware_update_status", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id + 100, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -3531,8 +3407,7 @@ async def test_subscribe_firmware_update_status_failures( { ID: 3, TYPE: "zwave_js/subscribe_firmware_update_status", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json() @@ -3783,13 +3658,13 @@ async def test_subscribe_node_statistics( """Test the subscribe_node_statistics command.""" entry = integration ws_client = await hass_ws_client(hass) + device = get_device(hass, multisensor_6) await ws_client.send_json( { ID: 1, TYPE: "zwave_js/subscribe_node_statistics", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) @@ -3843,8 +3718,7 @@ async def test_subscribe_node_statistics( { ID: 2, TYPE: "zwave_js/subscribe_node_statistics", - ENTRY_ID: "fake_entry_id", - NODE_ID: multisensor_6.node_id, + DEVICE_ID: "fake_device", } ) msg = await ws_client.receive_json() @@ -3852,17 +3726,6 @@ async def test_subscribe_node_statistics( assert not msg["success"] assert msg["error"]["code"] == ERR_NOT_FOUND - # Test sending command with improper node ID fails - await ws_client.send_json( - { - ID: 3, - TYPE: "zwave_js/subscribe_node_statistics", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id + 100, - } - ) - msg = await ws_client.receive_json() - # Test sending command with not loaded entry fails await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() @@ -3871,8 +3734,7 @@ async def test_subscribe_node_statistics( { ID: 4, TYPE: "zwave_js/subscribe_node_statistics", - ENTRY_ID: entry.entry_id, - NODE_ID: multisensor_6.node_id, + DEVICE_ID: device.id, } ) msg = await ws_client.receive_json()