From 5e52b11050c04d94b02286d260075dfd78d19d98 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Thu, 26 May 2022 19:21:50 -0400 Subject: [PATCH] Add additional data to zwave_js device statistics WS API (#72520) * Add additional data to zwave_js device statistics WS API * Rename variables * fix logic * correct typehint * Update homeassistant/components/zwave_js/api.py Co-authored-by: Martin Hjelmare * black Co-authored-by: Martin Hjelmare --- homeassistant/components/zwave_js/api.py | 36 +++++++++-- tests/components/zwave_js/test_api.py | 80 ++++++++++++++++++++---- 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/zwave_js/api.py b/homeassistant/components/zwave_js/api.py index c2e0398168669..e922571f4b160 100644 --- a/homeassistant/components/zwave_js/api.py +++ b/homeassistant/components/zwave_js/api.py @@ -71,6 +71,7 @@ from .helpers import ( async_enable_statistics, async_get_node_from_device_id, + get_device_id, update_data_collection_preference, ) @@ -2107,15 +2108,42 @@ def forward_stats(event: dict) -> None: ) -def _get_node_statistics_dict(statistics: NodeStatistics) -> dict[str, int]: +def _get_node_statistics_dict( + hass: HomeAssistant, statistics: NodeStatistics +) -> dict[str, Any]: """Get dictionary of node statistics.""" - return { + dev_reg = dr.async_get(hass) + + def _convert_node_to_device_id(node: Node) -> str: + """Convert a node to a device id.""" + driver = node.client.driver + assert driver + device = dev_reg.async_get_device({get_device_id(driver, node)}) + assert device + return device.id + + data: dict = { "commands_tx": statistics.commands_tx, "commands_rx": statistics.commands_rx, "commands_dropped_tx": statistics.commands_dropped_tx, "commands_dropped_rx": statistics.commands_dropped_rx, "timeout_response": statistics.timeout_response, + "rtt": statistics.rtt, + "rssi": statistics.rssi, + "lwr": statistics.lwr.as_dict() if statistics.lwr else None, + "nlwr": statistics.nlwr.as_dict() if statistics.nlwr else None, } + for key in ("lwr", "nlwr"): + if not data[key]: + continue + for key_2 in ("repeaters", "route_failed_between"): + if not data[key][key_2]: + continue + data[key][key_2] = [ + _convert_node_to_device_id(node) for node in data[key][key_2] + ] + + return data @websocket_api.require_admin @@ -2151,7 +2179,7 @@ def forward_stats(event: dict) -> None: "event": event["event"], "source": "node", "node_id": node.node_id, - **_get_node_statistics_dict(statistics), + **_get_node_statistics_dict(hass, statistics), }, ) ) @@ -2167,7 +2195,7 @@ def forward_stats(event: dict) -> None: "event": "statistics updated", "source": "node", "nodeId": node.node_id, - **_get_node_statistics_dict(node.statistics), + **_get_node_statistics_dict(hass, node.statistics), }, ) ) diff --git a/tests/components/zwave_js/test_api.py b/tests/components/zwave_js/test_api.py index e59a923ff4448..7f64ed6d87ddd 100644 --- a/tests/components/zwave_js/test_api.py +++ b/tests/components/zwave_js/test_api.py @@ -3768,18 +3768,26 @@ async def test_subscribe_controller_statistics( async def test_subscribe_node_statistics( - hass, multisensor_6, integration, client, hass_ws_client + hass, + multisensor_6, + wallmote_central_scene, + zen_31, + integration, + client, + hass_ws_client, ): """Test the subscribe_node_statistics command.""" entry = integration ws_client = await hass_ws_client(hass) - device = get_device(hass, multisensor_6) + multisensor_6_device = get_device(hass, multisensor_6) + zen_31_device = get_device(hass, zen_31) + wallmote_central_scene_device = get_device(hass, wallmote_central_scene) await ws_client.send_json( { ID: 1, TYPE: "zwave_js/subscribe_node_statistics", - DEVICE_ID: device.id, + DEVICE_ID: multisensor_6_device.id, } ) @@ -3797,6 +3805,10 @@ async def test_subscribe_node_statistics( "commands_dropped_tx": 0, "commands_dropped_rx": 0, "timeout_response": 0, + "rtt": None, + "rssi": None, + "lwr": None, + "nlwr": None, } # Fire statistics updated @@ -3808,10 +3820,32 @@ async def test_subscribe_node_statistics( "nodeId": multisensor_6.node_id, "statistics": { "commandsTX": 1, - "commandsRX": 1, - "commandsDroppedTX": 1, - "commandsDroppedRX": 1, - "timeoutResponse": 1, + "commandsRX": 2, + "commandsDroppedTX": 3, + "commandsDroppedRX": 4, + "timeoutResponse": 5, + "rtt": 6, + "rssi": 7, + "lwr": { + "protocolDataRate": 1, + "rssi": 1, + "repeaters": [wallmote_central_scene.node_id], + "repeaterRSSI": [1], + "routeFailedBetween": [ + zen_31.node_id, + multisensor_6.node_id, + ], + }, + "nlwr": { + "protocolDataRate": 2, + "rssi": 2, + "repeaters": [], + "repeaterRSSI": [127], + "routeFailedBetween": [ + multisensor_6.node_id, + zen_31.node_id, + ], + }, }, }, ) @@ -3822,10 +3856,32 @@ async def test_subscribe_node_statistics( "source": "node", "node_id": multisensor_6.node_id, "commands_tx": 1, - "commands_rx": 1, - "commands_dropped_tx": 1, - "commands_dropped_rx": 1, - "timeout_response": 1, + "commands_rx": 2, + "commands_dropped_tx": 3, + "commands_dropped_rx": 4, + "timeout_response": 5, + "rtt": 6, + "rssi": 7, + "lwr": { + "protocol_data_rate": 1, + "rssi": 1, + "repeaters": [wallmote_central_scene_device.id], + "repeater_rssi": [1], + "route_failed_between": [ + zen_31_device.id, + multisensor_6_device.id, + ], + }, + "nlwr": { + "protocol_data_rate": 2, + "rssi": 2, + "repeaters": [], + "repeater_rssi": [127], + "route_failed_between": [ + multisensor_6_device.id, + zen_31_device.id, + ], + }, } # Test sending command with improper entry ID fails @@ -3849,7 +3905,7 @@ async def test_subscribe_node_statistics( { ID: 4, TYPE: "zwave_js/subscribe_node_statistics", - DEVICE_ID: device.id, + DEVICE_ID: multisensor_6_device.id, } ) msg = await ws_client.receive_json()