Add proper S2 support for adding zwave_js nodes (#56516)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
db30c27455
commit
e76ddb4b27
3 changed files with 294 additions and 95 deletions
|
@ -10,7 +10,12 @@ from aiohttp import hdrs, web, web_exceptions, web_request
|
|||
import voluptuous as vol
|
||||
from zwave_js_server import dump
|
||||
from zwave_js_server.client import Client
|
||||
from zwave_js_server.const import CommandClass, InclusionStrategy, LogLevel
|
||||
from zwave_js_server.const import (
|
||||
CommandClass,
|
||||
InclusionStrategy,
|
||||
LogLevel,
|
||||
SecurityClass,
|
||||
)
|
||||
from zwave_js_server.exceptions import (
|
||||
BaseZwaveJSServerError,
|
||||
FailedCommand,
|
||||
|
@ -19,7 +24,7 @@ from zwave_js_server.exceptions import (
|
|||
SetValueFailed,
|
||||
)
|
||||
from zwave_js_server.firmware import begin_firmware_update
|
||||
from zwave_js_server.model.controller import ControllerStatistics
|
||||
from zwave_js_server.model.controller import ControllerStatistics, InclusionGrant
|
||||
from zwave_js_server.model.firmware import (
|
||||
FirmwareUpdateFinished,
|
||||
FirmwareUpdateProgress,
|
||||
|
@ -67,7 +72,8 @@ TYPE = "type"
|
|||
PROPERTY = "property"
|
||||
PROPERTY_KEY = "property_key"
|
||||
VALUE = "value"
|
||||
SECURE = "secure"
|
||||
INCLUSION_STRATEGY = "inclusion_strategy"
|
||||
PIN = "pin"
|
||||
|
||||
# constants for log config commands
|
||||
CONFIG = "config"
|
||||
|
@ -85,6 +91,10 @@ STATUS = "status"
|
|||
ENABLED = "enabled"
|
||||
OPTED_IN = "opted_in"
|
||||
|
||||
# constants for granting security classes
|
||||
SECURITY_CLASSES = "security_classes"
|
||||
CLIENT_SIDE_AUTH = "client_side_auth"
|
||||
|
||||
|
||||
def async_get_entry(orig_func: Callable) -> Callable:
|
||||
"""Decorate async function to get entry."""
|
||||
|
@ -171,6 +181,8 @@ def async_register_api(hass: HomeAssistant) -> None:
|
|||
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)
|
||||
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)
|
||||
|
@ -371,7 +383,9 @@ async def websocket_ping_node(
|
|||
{
|
||||
vol.Required(TYPE): "zwave_js/add_node",
|
||||
vol.Required(ENTRY_ID): str,
|
||||
vol.Optional(SECURE, default=False): bool,
|
||||
vol.Optional(INCLUSION_STRATEGY, default=InclusionStrategy.DEFAULT): vol.In(
|
||||
[strategy.value for strategy in InclusionStrategy]
|
||||
),
|
||||
}
|
||||
)
|
||||
@websocket_api.async_response
|
||||
|
@ -386,11 +400,7 @@ async def websocket_add_node(
|
|||
) -> None:
|
||||
"""Add a node to the Z-Wave network."""
|
||||
controller = client.driver.controller
|
||||
|
||||
if msg[SECURE]:
|
||||
inclusion_strategy = InclusionStrategy.SECURITY_S0
|
||||
else:
|
||||
inclusion_strategy = InclusionStrategy.INSECURE
|
||||
inclusion_strategy = InclusionStrategy(msg[INCLUSION_STRATEGY])
|
||||
|
||||
@callback
|
||||
def async_cleanup() -> None:
|
||||
|
@ -404,6 +414,26 @@ async def websocket_add_node(
|
|||
websocket_api.event_message(msg[ID], {"event": event["event"]})
|
||||
)
|
||||
|
||||
@callback
|
||||
def forward_dsk(event: dict) -> None:
|
||||
connection.send_message(
|
||||
websocket_api.event_message(
|
||||
msg[ID], {"event": event["event"], "dsk": event["dsk"]}
|
||||
)
|
||||
)
|
||||
|
||||
@callback
|
||||
def forward_requested_grant(event: dict) -> None:
|
||||
connection.send_message(
|
||||
websocket_api.event_message(
|
||||
msg[ID],
|
||||
{
|
||||
"event": event["event"],
|
||||
"requested_grant": event["requested_grant"].to_dict(),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@callback
|
||||
def forward_stage(event: dict) -> None:
|
||||
connection.send_message(
|
||||
|
@ -426,6 +456,7 @@ async def websocket_add_node(
|
|||
"node_id": node.node_id,
|
||||
"status": node.status,
|
||||
"ready": node.ready,
|
||||
"low_security": event["result"].get("lowSecurity", False),
|
||||
}
|
||||
connection.send_message(
|
||||
websocket_api.event_message(
|
||||
|
@ -452,6 +483,8 @@ async def websocket_add_node(
|
|||
controller.on("inclusion started", forward_event),
|
||||
controller.on("inclusion failed", forward_event),
|
||||
controller.on("inclusion stopped", forward_event),
|
||||
controller.on("validate dsk and enter pin", forward_dsk),
|
||||
controller.on("grant security classes", forward_requested_grant),
|
||||
controller.on("node added", node_added),
|
||||
async_dispatcher_connect(
|
||||
hass, EVENT_DEVICE_ADDED_TO_REGISTRY, device_registered
|
||||
|
@ -465,6 +498,59 @@ async def websocket_add_node(
|
|||
)
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required(TYPE): "zwave_js/grant_security_classes",
|
||||
vol.Required(ENTRY_ID): str,
|
||||
vol.Required(SECURITY_CLASSES): [
|
||||
vol.In([sec_cls.value for sec_cls in SecurityClass])
|
||||
],
|
||||
vol.Optional(CLIENT_SIDE_AUTH, default=False): bool,
|
||||
}
|
||||
)
|
||||
@websocket_api.async_response
|
||||
@async_handle_failed_command
|
||||
@async_get_entry
|
||||
async def websocket_grant_security_classes(
|
||||
hass: HomeAssistant,
|
||||
connection: ActiveConnection,
|
||||
msg: dict,
|
||||
entry: ConfigEntry,
|
||||
client: Client,
|
||||
) -> None:
|
||||
"""Add a node to the Z-Wave network."""
|
||||
inclusion_grant = InclusionGrant(
|
||||
[SecurityClass(sec_cls) for sec_cls in msg[SECURITY_CLASSES]],
|
||||
msg[CLIENT_SIDE_AUTH],
|
||||
)
|
||||
await client.driver.controller.async_grant_security_classes(inclusion_grant)
|
||||
connection.send_result(msg[ID])
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required(TYPE): "zwave_js/validate_dsk_and_enter_pin",
|
||||
vol.Required(ENTRY_ID): str,
|
||||
vol.Required(PIN): str,
|
||||
}
|
||||
)
|
||||
@websocket_api.async_response
|
||||
@async_handle_failed_command
|
||||
@async_get_entry
|
||||
async def websocket_validate_dsk_and_enter_pin(
|
||||
hass: HomeAssistant,
|
||||
connection: ActiveConnection,
|
||||
msg: dict,
|
||||
entry: ConfigEntry,
|
||||
client: Client,
|
||||
) -> None:
|
||||
"""Add a node to the Z-Wave network."""
|
||||
await client.driver.controller.async_validate_dsk_and_enter_pin(msg[PIN])
|
||||
connection.send_result(msg[ID])
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
|
@ -583,7 +669,9 @@ async def websocket_remove_node(
|
|||
vol.Required(TYPE): "zwave_js/replace_failed_node",
|
||||
vol.Required(ENTRY_ID): str,
|
||||
vol.Required(NODE_ID): int,
|
||||
vol.Optional(SECURE, default=False): bool,
|
||||
vol.Optional(INCLUSION_STRATEGY, default=InclusionStrategy.DEFAULT): vol.In(
|
||||
[strategy.value for strategy in InclusionStrategy]
|
||||
),
|
||||
}
|
||||
)
|
||||
@websocket_api.async_response
|
||||
|
@ -599,11 +687,7 @@ async def websocket_replace_failed_node(
|
|||
"""Replace a failed node with a new node."""
|
||||
controller = client.driver.controller
|
||||
node_id = msg[NODE_ID]
|
||||
|
||||
if msg[SECURE]:
|
||||
inclusion_strategy = InclusionStrategy.SECURITY_S0
|
||||
else:
|
||||
inclusion_strategy = InclusionStrategy.INSECURE
|
||||
inclusion_strategy = InclusionStrategy(msg[INCLUSION_STRATEGY])
|
||||
|
||||
@callback
|
||||
def async_cleanup() -> None:
|
||||
|
@ -617,6 +701,26 @@ async def websocket_replace_failed_node(
|
|||
websocket_api.event_message(msg[ID], {"event": event["event"]})
|
||||
)
|
||||
|
||||
@callback
|
||||
def forward_dsk(event: dict) -> None:
|
||||
connection.send_message(
|
||||
websocket_api.event_message(
|
||||
msg[ID], {"event": event["event"], "dsk": event["dsk"]}
|
||||
)
|
||||
)
|
||||
|
||||
@callback
|
||||
def forward_requested_grant(event: dict) -> None:
|
||||
connection.send_message(
|
||||
websocket_api.event_message(
|
||||
msg[ID],
|
||||
{
|
||||
"event": event["event"],
|
||||
"requested_grant": event["requested_grant"].to_dict(),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@callback
|
||||
def forward_stage(event: dict) -> None:
|
||||
connection.send_message(
|
||||
|
@ -678,6 +782,8 @@ async def websocket_replace_failed_node(
|
|||
controller.on("inclusion started", forward_event),
|
||||
controller.on("inclusion failed", forward_event),
|
||||
controller.on("inclusion stopped", forward_event),
|
||||
controller.on("validate dsk and enter pin", forward_dsk),
|
||||
controller.on("grant security classes", forward_requested_grant),
|
||||
controller.on("node removed", node_removed),
|
||||
controller.on("node added", node_added),
|
||||
async_dispatcher_connect(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue