Add zwave_js heal node and network WS API commands (#51047)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
pull/51112/head
Raman Gupta 2021-05-26 11:38:02 -04:00 committed by GitHub
parent 8edf7f0407
commit 6d9b67ddb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 326 additions and 6 deletions

View File

@ -2,7 +2,7 @@
from __future__ import annotations
import dataclasses
from functools import wraps
from functools import partial, wraps
import json
from typing import Callable
@ -142,18 +142,24 @@ def async_register_api(hass: HomeAssistant) -> None:
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_stop_inclusion)
websocket_api.async_register_command(hass, websocket_stop_exclusion)
websocket_api.async_register_command(hass, websocket_remove_node)
websocket_api.async_register_command(hass, websocket_remove_failed_node)
websocket_api.async_register_command(hass, websocket_replace_failed_node)
websocket_api.async_register_command(hass, websocket_stop_exclusion)
websocket_api.async_register_command(hass, websocket_begin_healing_network)
websocket_api.async_register_command(
hass, websocket_subscribe_heal_network_progress
)
websocket_api.async_register_command(hass, websocket_stop_healing_network)
websocket_api.async_register_command(hass, websocket_refresh_node_info)
websocket_api.async_register_command(hass, websocket_refresh_node_values)
websocket_api.async_register_command(hass, websocket_refresh_node_cc_values)
websocket_api.async_register_command(hass, websocket_heal_node)
websocket_api.async_register_command(hass, websocket_set_config_parameter)
websocket_api.async_register_command(hass, websocket_get_config_parameters)
websocket_api.async_register_command(hass, websocket_subscribe_logs)
websocket_api.async_register_command(hass, websocket_update_log_config)
websocket_api.async_register_command(hass, websocket_get_log_config)
websocket_api.async_register_command(hass, websocket_get_config_parameters)
websocket_api.async_register_command(hass, websocket_set_config_parameter)
websocket_api.async_register_command(
hass, websocket_update_data_collection_preference
)
@ -180,6 +186,7 @@ async def websocket_network_status(
client: Client,
) -> None:
"""Get the status of the Z-Wave JS network."""
controller = client.driver.controller
data = {
"client": {
"ws_server_url": client.ws_server_url,
@ -188,7 +195,24 @@ async def websocket_network_status(
"server_version": client.version.server_version,
},
"controller": {
"home_id": client.driver.controller.data["homeId"],
"home_id": controller.home_id,
"library_version": controller.library_version,
"type": controller.controller_type,
"own_node_id": controller.own_node_id,
"is_secondary": controller.is_secondary,
"is_using_home_id_from_other_network": controller.is_using_home_id_from_other_network,
"is_sis_present": controller.is_SIS_present,
"was_real_primary": controller.was_real_primary,
"is_static_update_controller": controller.is_static_update_controller,
"is_slave": controller.is_slave,
"serial_api_version": controller.serial_api_version,
"manufacturer_id": controller.manufacturer_id,
"product_id": controller.product_id,
"product_type": controller.product_type,
"supported_function_types": controller.supported_function_types,
"suc_node_id": controller.suc_node_id,
"supports_timers": controller.supports_timers,
"is_heal_network_active": controller.is_heal_network_active,
"nodes": list(client.driver.controller.nodes),
},
}
@ -643,6 +667,126 @@ async def websocket_remove_failed_node(
)
@websocket_api.require_admin
@websocket_api.websocket_command(
{
vol.Required(TYPE): "zwave_js/begin_healing_network",
vol.Required(ENTRY_ID): str,
}
)
@websocket_api.async_response
@async_get_entry
async def websocket_begin_healing_network(
hass: HomeAssistant,
connection: ActiveConnection,
msg: dict,
entry: ConfigEntry,
client: Client,
) -> None:
"""Begin healing the Z-Wave network."""
controller = client.driver.controller
result = await controller.async_begin_healing_network()
connection.send_result(
msg[ID],
result,
)
@websocket_api.require_admin
@websocket_api.websocket_command(
{
vol.Required(TYPE): "zwave_js/subscribe_heal_network_progress",
vol.Required(ENTRY_ID): str,
}
)
@websocket_api.async_response
@async_get_entry
async def websocket_subscribe_heal_network_progress(
hass: HomeAssistant,
connection: ActiveConnection,
msg: dict,
entry: ConfigEntry,
client: Client,
) -> None:
"""Subscribe to heal Z-Wave network status updates."""
controller = client.driver.controller
@callback
def async_cleanup() -> None:
"""Remove signal listeners."""
for unsub in unsubs:
unsub()
@callback
def forward_event(key: str, event: dict) -> None:
connection.send_message(
websocket_api.event_message(
msg[ID], {"event": event["event"], "heal_node_status": event[key]}
)
)
connection.subscriptions[msg["id"]] = async_cleanup
unsubs = [
controller.on("heal network progress", partial(forward_event, "progress")),
controller.on("heal network done", partial(forward_event, "result")),
]
connection.send_result(msg[ID])
@websocket_api.require_admin
@websocket_api.websocket_command(
{
vol.Required(TYPE): "zwave_js/stop_healing_network",
vol.Required(ENTRY_ID): str,
}
)
@websocket_api.async_response
@async_get_entry
async def websocket_stop_healing_network(
hass: HomeAssistant,
connection: ActiveConnection,
msg: dict,
entry: ConfigEntry,
client: Client,
) -> None:
"""Stop healing the Z-Wave network."""
controller = client.driver.controller
result = await controller.async_stop_healing_network()
connection.send_result(
msg[ID],
result,
)
@websocket_api.require_admin
@websocket_api.websocket_command(
{
vol.Required(TYPE): "zwave_js/heal_node",
vol.Required(ENTRY_ID): str,
vol.Required(NODE_ID): int,
}
)
@websocket_api.async_response
@async_get_entry
async def websocket_heal_node(
hass: HomeAssistant,
connection: ActiveConnection,
msg: dict,
entry: ConfigEntry,
client: Client,
) -> 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)
connection.send_result(
msg[ID],
result,
)
@websocket_api.require_admin
@websocket_api.websocket_command(
{

View File

@ -496,6 +496,7 @@ async def test_replace_failed_node(
msg = await ws_client.receive_json()
assert msg["success"]
assert msg["result"]
event = Event(
type="inclusion started",
@ -674,6 +675,180 @@ async def test_remove_failed_node(
assert msg["error"]["code"] == ERR_NOT_LOADED
async def test_begin_healing_network(
hass,
integration,
client,
hass_ws_client,
):
"""Test the begin_healing_network 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/begin_healing_network",
ENTRY_ID: entry.entry_id,
}
)
msg = await ws_client.receive_json()
assert msg["success"]
assert msg["result"]
# 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: 4,
TYPE: "zwave_js/begin_healing_network",
ENTRY_ID: entry.entry_id,
}
)
msg = await ws_client.receive_json()
assert not msg["success"]
assert msg["error"]["code"] == ERR_NOT_LOADED
async def test_subscribe_heal_network_progress(
hass, integration, client, hass_ws_client
):
"""Test the subscribe_heal_network_progress command."""
entry = integration
ws_client = await hass_ws_client(hass)
await ws_client.send_json(
{
ID: 3,
TYPE: "zwave_js/subscribe_heal_network_progress",
ENTRY_ID: entry.entry_id,
}
)
msg = await ws_client.receive_json()
assert msg["success"]
# Fire heal network progress
event = Event(
"heal network progress",
{
"source": "controller",
"event": "heal network progress",
"progress": {67: "pending"},
},
)
client.driver.controller.receive_event(event)
msg = await ws_client.receive_json()
assert msg["event"]["event"] == "heal network progress"
assert msg["event"]["heal_node_status"] == {"67": "pending"}
# 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: 4,
TYPE: "zwave_js/subscribe_heal_network_progress",
ENTRY_ID: entry.entry_id,
}
)
msg = await ws_client.receive_json()
assert not msg["success"]
assert msg["error"]["code"] == ERR_NOT_LOADED
async def test_stop_healing_network(
hass,
integration,
client,
hass_ws_client,
):
"""Test the stop_healing_network 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/stop_healing_network",
ENTRY_ID: entry.entry_id,
}
)
msg = await ws_client.receive_json()
assert msg["success"]
assert msg["result"]
# 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: 4,
TYPE: "zwave_js/stop_healing_network",
ENTRY_ID: entry.entry_id,
}
)
msg = await ws_client.receive_json()
assert not msg["success"]
assert msg["error"]["code"] == ERR_NOT_LOADED
async def test_heal_node(
hass,
integration,
client,
hass_ws_client,
):
"""Test the heal_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/heal_node",
ENTRY_ID: entry.entry_id,
NODE_ID: 67,
}
)
msg = await ws_client.receive_json()
assert msg["success"]
assert msg["result"]
# 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: 4,
TYPE: "zwave_js/heal_node",
ENTRY_ID: entry.entry_id,
NODE_ID: 67,
}
)
msg = await ws_client.receive_json()
assert not msg["success"]
assert msg["error"]["code"] == ERR_NOT_LOADED
async def test_refresh_node_info(
hass, client, multisensor_6, integration, hass_ws_client
):

View File

@ -91,7 +91,8 @@
239
],
"sucNodeId": 1,
"supportsTimers": false
"supportsTimers": false,
"isHealNetworkActive": false
},
"nodes": [
]