1 """Websocket API for Z-Wave JS."""
3 from __future__
import annotations
5 from collections.abc
import Callable, Coroutine
7 from functools
import partial, wraps
8 from typing
import Any, Concatenate, Literal, cast
10 from aiohttp
import web, web_exceptions, web_request
11 import voluptuous
as vol
12 from zwave_js_server.client
import Client
13 from zwave_js_server.const
import (
21 ProvisioningEntryStatus,
26 from zwave_js_server.exceptions
import (
27 BaseZwaveJSServerError,
33 from zwave_js_server.firmware
import controller_firmware_update_otw, update_firmware
34 from zwave_js_server.model.controller
import (
38 QRProvisioningInformation,
40 from zwave_js_server.model.controller.firmware
import (
41 ControllerFirmwareUpdateData,
42 ControllerFirmwareUpdateProgress,
43 ControllerFirmwareUpdateResult,
45 from zwave_js_server.model.driver
import Driver
46 from zwave_js_server.model.endpoint
import Endpoint
47 from zwave_js_server.model.log_config
import LogConfig
48 from zwave_js_server.model.log_message
import LogMessage
49 from zwave_js_server.model.node
import Node, NodeStatistics
50 from zwave_js_server.model.node.firmware
import (
51 NodeFirmwareUpdateData,
52 NodeFirmwareUpdateProgress,
53 NodeFirmwareUpdateResult,
55 from zwave_js_server.model.utils
import (
56 async_parse_qr_code_string,
57 async_try_parse_dsk_from_qr_code_string,
59 from zwave_js_server.model.value
import ConfigurationValueFormat
60 from zwave_js_server.util.node
import async_set_config_parameter
78 from .config_validation
import BITMASK_SCHEMA
85 CONF_DATA_COLLECTION_OPTED_IN,
89 EVENT_DEVICE_ADDED_TO_REGISTRY,
92 from .helpers
import (
93 async_enable_statistics,
94 async_get_node_from_device_id,
98 DATA_UNSUBSCRIBE =
"unsubs"
102 ENTRY_ID =
"entry_id"
103 ERR_NOT_LOADED =
"not_loaded"
105 DEVICE_ID =
"device_id"
106 COMMAND_CLASS_ID =
"command_class_id"
108 PROPERTY =
"property"
109 PROPERTY_KEY =
"property_key"
110 ENDPOINT =
"endpoint"
112 VALUE_SIZE =
"value_size"
113 VALUE_FORMAT =
"value_format"
118 LOG_TO_FILE =
"log_to_file"
119 FILENAME =
"filename"
121 FORCE_CONSOLE =
"force_console"
124 VALUE_ID =
"value_id"
129 OPTED_IN =
"opted_in"
132 SECURITY_CLASSES =
"securityClasses"
133 CLIENT_SIDE_AUTH =
"clientSideAuth"
136 INCLUSION_STRATEGY =
"inclusion_strategy"
138 INCLUSION_STRATEGY_NOT_SMART_START: dict[
141 InclusionStrategy.DEFAULT,
142 InclusionStrategy.SECURITY_S0,
143 InclusionStrategy.SECURITY_S2,
144 InclusionStrategy.INSECURE,
147 InclusionStrategy.DEFAULT.value: InclusionStrategy.DEFAULT,
148 InclusionStrategy.SECURITY_S0.value: InclusionStrategy.SECURITY_S0,
149 InclusionStrategy.SECURITY_S2.value: InclusionStrategy.SECURITY_S2,
150 InclusionStrategy.INSECURE.value: InclusionStrategy.INSECURE,
153 FORCE_SECURITY =
"force_security"
154 PLANNED_PROVISIONING_ENTRY =
"planned_provisioning_entry"
155 QR_PROVISIONING_INFORMATION =
"qr_provisioning_information"
156 QR_CODE_STRING =
"qr_code_string"
161 GENERIC_DEVICE_CLASS =
"genericDeviceClass"
162 SPECIFIC_DEVICE_CLASS =
"specificDeviceClass"
163 INSTALLER_ICON_TYPE =
"installerIconType"
164 MANUFACTURER_ID =
"manufacturerId"
165 PRODUCT_TYPE =
"productType"
166 PRODUCT_ID =
"productId"
167 APPLICATION_VERSION =
"applicationVersion"
168 MAX_INCLUSION_REQUEST_INTERVAL =
"maxInclusionRequestInterval"
170 SUPPORTED_PROTOCOLS =
"supportedProtocols"
171 ADDITIONAL_PROPERTIES =
"additional_properties"
173 REQUESTED_SECURITY_CLASSES =
"requestedSecurityClasses"
176 STRATEGY =
"strategy"
179 MINIMUM_QR_STRING_LENGTH = 52
183 PLANNED_PROVISIONING_ENTRY_SCHEMA = vol.All(
186 vol.Required(DSK): str,
187 vol.Required(SECURITY_CLASSES): vol.All(
189 [vol.Coerce(SecurityClass)],
191 vol.Optional(STATUS, default=ProvisioningEntryStatus.ACTIVE): vol.Coerce(
192 ProvisioningEntryStatus
194 vol.Optional(REQUESTED_SECURITY_CLASSES): vol.All(
195 cv.ensure_list, [vol.Coerce(SecurityClass)]
199 extra=vol.ALLOW_EXTRA,
201 ProvisioningEntry.from_dict,
204 QR_PROVISIONING_INFORMATION_SCHEMA = vol.All(
207 vol.Required(VERSION): vol.Coerce(QRCodeVersion),
208 vol.Required(SECURITY_CLASSES): vol.All(
210 [vol.Coerce(SecurityClass)],
212 vol.Required(DSK): str,
213 vol.Required(GENERIC_DEVICE_CLASS): int,
214 vol.Required(SPECIFIC_DEVICE_CLASS): int,
215 vol.Required(INSTALLER_ICON_TYPE): int,
216 vol.Required(MANUFACTURER_ID): int,
217 vol.Required(PRODUCT_TYPE): int,
218 vol.Required(PRODUCT_ID): int,
219 vol.Required(APPLICATION_VERSION): str,
220 vol.Optional(MAX_INCLUSION_REQUEST_INTERVAL): vol.Any(int,
None),
221 vol.Optional(UUID): vol.Any(str,
None),
222 vol.Optional(SUPPORTED_PROTOCOLS): vol.All(
224 [vol.Coerce(Protocols)],
226 vol.Optional(STATUS, default=ProvisioningEntryStatus.ACTIVE): vol.Coerce(
227 ProvisioningEntryStatus
229 vol.Optional(REQUESTED_SECURITY_CLASSES): vol.All(
230 cv.ensure_list, [vol.Coerce(SecurityClass)]
233 extra=vol.ALLOW_EXTRA,
235 QRProvisioningInformation.from_dict,
238 QR_CODE_STRING_SCHEMA = vol.All(str, vol.Length(min=MINIMUM_QR_STRING_LENGTH))
243 connection: ActiveConnection,
246 ) -> tuple[ConfigEntry, Client, Driver] | tuple[
None,
None,
None]:
247 """Get config entry and client from message data."""
248 entry = hass.config_entries.async_get_entry(entry_id)
250 connection.send_error(
251 msg[ID], ERR_NOT_FOUND, f
"Config entry {entry_id} not found"
253 return None,
None,
None
255 if entry.state
is not ConfigEntryState.LOADED:
256 connection.send_error(
257 msg[ID], ERR_NOT_LOADED, f
"Config entry {entry_id} not loaded"
259 return None,
None,
None
261 client: Client = entry.runtime_data[DATA_CLIENT]
263 if client.driver
is None:
264 connection.send_error(
267 f
"Config entry {msg[ENTRY_ID]} not loaded, driver not ready",
269 return None,
None,
None
271 return entry, client, client.driver
276 [HomeAssistant, ActiveConnection, dict[str, Any], ConfigEntry, Client, Driver],
277 Coroutine[Any, Any,
None],
280 [HomeAssistant, ActiveConnection, dict[str, Any]], Coroutine[Any, Any,
None]
282 """Decorate async function to get entry."""
285 async
def async_get_entry_func(
286 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
288 """Provide user specific data and store to function."""
290 hass, connection, msg, msg[ENTRY_ID]
293 if not entry
or not client
or not driver:
296 await orig_func(hass, connection, msg, entry, client, driver)
298 return async_get_entry_func
302 hass: HomeAssistant, connection: ActiveConnection, msg: dict, device_id: str
304 """Get node from message data."""
307 except ValueError
as err:
308 error_code = ERR_NOT_FOUND
309 if "loaded" in err.args[0]:
310 error_code = ERR_NOT_LOADED
311 connection.send_error(msg[ID], error_code, err.args[0])
318 [HomeAssistant, ActiveConnection, dict[str, Any], Node],
319 Coroutine[Any, Any,
None],
322 [HomeAssistant, ActiveConnection, dict[str, Any]], Coroutine[Any, Any,
None]
324 """Decorate async function to get node."""
327 async
def async_get_node_func(
328 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
330 """Provide user specific data and store to function."""
334 await orig_func(hass, connection, msg, node)
336 return async_get_node_func
339 def async_handle_failed_command[**_P](
341 Concatenate[HomeAssistant, ActiveConnection, dict[str, Any], _P],
342 Coroutine[Any, Any,
None],
345 Concatenate[HomeAssistant, ActiveConnection, dict[str, Any], _P],
346 Coroutine[Any, Any,
None],
348 """Decorate async function to handle FailedCommand and send relevant error."""
351 async
def async_handle_failed_command_func(
353 connection: ActiveConnection,
358 """Handle FailedCommand within function and send relevant error."""
360 await orig_func(hass, connection, msg, *args, **kwargs)
361 except FailedCommand
as err:
363 if unsubs := msg.get(DATA_UNSUBSCRIBE):
366 connection.send_error(msg[ID], err.error_code, err.args[0])
368 return async_handle_failed_command_func
372 """Get node status."""
374 "node_id": node.node_id,
375 "is_routing": node.is_routing,
376 "status": node.status,
377 "is_secure": node.is_secure,
379 "zwave_plus_version": node.zwave_plus_version,
380 "highest_security_class": node.highest_security_class,
381 "is_controller_node": node.is_controller_node,
382 "has_firmware_update_cc": any(
383 cc.id == CommandClass.FIRMWARE_UPDATE_MD.value
384 for cc
in node.command_classes
391 """Register all of our api endpoints."""
392 websocket_api.async_register_command(hass, websocket_network_status)
393 websocket_api.async_register_command(hass, websocket_subscribe_node_status)
394 websocket_api.async_register_command(hass, websocket_node_status)
395 websocket_api.async_register_command(hass, websocket_node_metadata)
396 websocket_api.async_register_command(hass, websocket_node_alerts)
397 websocket_api.async_register_command(hass, websocket_add_node)
398 websocket_api.async_register_command(hass, websocket_grant_security_classes)
399 websocket_api.async_register_command(hass, websocket_validate_dsk_and_enter_pin)
400 websocket_api.async_register_command(hass, websocket_provision_smart_start_node)
401 websocket_api.async_register_command(hass, websocket_unprovision_smart_start_node)
402 websocket_api.async_register_command(hass, websocket_get_provisioning_entries)
403 websocket_api.async_register_command(hass, websocket_parse_qr_code_string)
404 websocket_api.async_register_command(
405 hass, websocket_try_parse_dsk_from_qr_code_string
407 websocket_api.async_register_command(hass, websocket_supports_feature)
408 websocket_api.async_register_command(hass, websocket_stop_inclusion)
409 websocket_api.async_register_command(hass, websocket_stop_exclusion)
410 websocket_api.async_register_command(hass, websocket_remove_node)
411 websocket_api.async_register_command(hass, websocket_remove_failed_node)
412 websocket_api.async_register_command(hass, websocket_replace_failed_node)
413 websocket_api.async_register_command(hass, websocket_begin_rebuilding_routes)
414 websocket_api.async_register_command(
415 hass, websocket_subscribe_rebuild_routes_progress
417 websocket_api.async_register_command(hass, websocket_stop_rebuilding_routes)
418 websocket_api.async_register_command(hass, websocket_refresh_node_info)
419 websocket_api.async_register_command(hass, websocket_refresh_node_values)
420 websocket_api.async_register_command(hass, websocket_refresh_node_cc_values)
421 websocket_api.async_register_command(hass, websocket_rebuild_node_routes)
422 websocket_api.async_register_command(hass, websocket_set_config_parameter)
423 websocket_api.async_register_command(hass, websocket_get_config_parameters)
424 websocket_api.async_register_command(hass, websocket_get_raw_config_parameter)
425 websocket_api.async_register_command(hass, websocket_set_raw_config_parameter)
426 websocket_api.async_register_command(hass, websocket_subscribe_log_updates)
427 websocket_api.async_register_command(hass, websocket_update_log_config)
428 websocket_api.async_register_command(hass, websocket_get_log_config)
429 websocket_api.async_register_command(
430 hass, websocket_update_data_collection_preference
432 websocket_api.async_register_command(hass, websocket_data_collection_status)
433 websocket_api.async_register_command(hass, websocket_abort_firmware_update)
434 websocket_api.async_register_command(
435 hass, websocket_is_node_firmware_update_in_progress
437 websocket_api.async_register_command(
438 hass, websocket_subscribe_firmware_update_status
440 websocket_api.async_register_command(
441 hass, websocket_get_node_firmware_update_capabilities
443 websocket_api.async_register_command(
444 hass, websocket_is_any_ota_firmware_update_in_progress
446 websocket_api.async_register_command(hass, websocket_check_for_config_updates)
447 websocket_api.async_register_command(hass, websocket_install_config_update)
448 websocket_api.async_register_command(
449 hass, websocket_subscribe_controller_statistics
451 websocket_api.async_register_command(hass, websocket_subscribe_node_statistics)
452 websocket_api.async_register_command(hass, websocket_hard_reset_controller)
453 websocket_api.async_register_command(hass, websocket_node_capabilities)
454 websocket_api.async_register_command(hass, websocket_invoke_cc_api)
455 websocket_api.async_register_command(hass, websocket_get_integration_settings)
459 @websocket_api.require_admin
460 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/network_status",
461 vol.Exclusive(DEVICE_ID,
"id"): str,
462 vol.Exclusive(ENTRY_ID,
"id"): str,
465 @websocket_api.async_response
467 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
469 """Get the status of the Z-Wave JS network."""
471 _, client, driver = await
_async_get_entry(hass, connection, msg, msg[ENTRY_ID])
472 if not client
or not driver:
474 elif DEVICE_ID
in msg:
480 driver = client.driver
482 connection.send_error(
483 msg[ID], ERR_INVALID_FORMAT,
"Must specify either device_id or entry_id"
486 controller = driver.controller
487 controller.update(await controller.async_get_state())
488 client_version_info = client.version
489 assert client_version_info
492 "ws_server_url": client.ws_server_url,
493 "state":
"connected" if client.connected
else "disconnected",
494 "driver_version": client_version_info.driver_version,
495 "server_version": client_version_info.server_version,
496 "server_logging_enabled": client.server_logging_enabled,
499 "home_id": controller.home_id,
500 "sdk_version": controller.sdk_version,
501 "type": controller.controller_type,
502 "own_node_id": controller.own_node_id,
503 "is_primary": controller.is_primary,
504 "is_using_home_id_from_other_network": (
505 controller.is_using_home_id_from_other_network
507 "is_sis_present": controller.is_SIS_present,
508 "was_real_primary": controller.was_real_primary,
509 "is_suc": controller.is_suc,
510 "node_type": controller.node_type,
511 "firmware_version": controller.firmware_version,
512 "manufacturer_id": controller.manufacturer_id,
513 "product_id": controller.product_id,
514 "product_type": controller.product_type,
515 "supported_function_types": controller.supported_function_types,
516 "suc_node_id": controller.suc_node_id,
517 "supports_timers": controller.supports_timers,
518 "is_rebuilding_routes": controller.is_rebuilding_routes,
519 "inclusion_state": controller.inclusion_state,
520 "rf_region": controller.rf_region,
521 "status": controller.status,
522 "nodes": [
node_status(node)
for node
in driver.controller.nodes.values()],
525 connection.send_result(
531 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/subscribe_node_status",
532 vol.Required(DEVICE_ID): str,
535 @websocket_api.async_response
539 connection: ActiveConnection,
543 """Subscribe to node status update events of a Z-Wave JS node."""
546 def forward_event(event: dict) ->
None:
547 """Forward the event."""
548 connection.send_message(
549 websocket_api.event_message(
551 {
"event": event[
"event"],
"status": node.status,
"ready": node.ready},
557 """Remove signal listeners."""
561 connection.subscriptions[msg[
"id"]] = async_cleanup
562 msg[DATA_UNSUBSCRIBE] = unsubs = [
563 node.on(evt, forward_event)
564 for evt
in (
"alive",
"dead",
"sleep",
"wake up",
"ready")
567 connection.send_result(msg[ID])
570 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/node_status",
571 vol.Required(DEVICE_ID): str,
574 @websocket_api.async_response
578 connection: ActiveConnection,
582 """Get the status of a Z-Wave JS node."""
586 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/node_metadata",
587 vol.Required(DEVICE_ID): str,
590 @websocket_api.async_response
594 connection: ActiveConnection,
598 """Get the metadata of a Z-Wave JS node."""
600 "node_id": node.node_id,
601 "exclusion": node.device_config.metadata.exclusion,
602 "inclusion": node.device_config.metadata.inclusion,
603 "manual": node.device_config.metadata.manual,
604 "wakeup": node.device_config.metadata.wakeup,
605 "reset": node.device_config.metadata.reset,
606 "device_database_url": node.device_database_url,
608 connection.send_result(
614 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/node_alerts",
615 vol.Required(DEVICE_ID): str,
618 @websocket_api.async_response
622 connection: ActiveConnection,
626 """Get the alerts for a Z-Wave JS node."""
627 connection.send_result(
630 "comments": node.device_config.metadata.comments,
631 "is_embedded": node.device_config.is_embedded,
636 @websocket_api.require_admin
637 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/add_node",
638 vol.Required(ENTRY_ID): str,
639 vol.Optional(INCLUSION_STRATEGY, default=InclusionStrategy.DEFAULT): vol.All(
644 for strategy
in InclusionStrategy
645 if strategy != InclusionStrategy.SMART_START
649 vol.Optional(FORCE_SECURITY): bool,
651 PLANNED_PROVISIONING_ENTRY,
"options"
652 ): PLANNED_PROVISIONING_ENTRY_SCHEMA,
654 QR_PROVISIONING_INFORMATION,
"options"
655 ): QR_PROVISIONING_INFORMATION_SCHEMA,
656 vol.Exclusive(QR_CODE_STRING,
"options"): QR_CODE_STRING_SCHEMA,
657 vol.Exclusive(DSK,
"options"): str,
660 @websocket_api.async_response
661 @async_handle_failed_command
665 connection: ActiveConnection,
671 """Add a node to the Z-Wave network."""
672 controller = driver.controller
673 inclusion_strategy = InclusionStrategy(msg[INCLUSION_STRATEGY])
674 force_security = msg.get(FORCE_SECURITY)
676 msg.get(PLANNED_PROVISIONING_ENTRY)
677 or msg.get(QR_PROVISIONING_INFORMATION)
678 or msg.get(QR_CODE_STRING)
684 """Remove signal listeners."""
689 def forward_event(event: dict) ->
None:
690 connection.send_message(
691 websocket_api.event_message(msg[ID], {
"event": event[
"event"]})
695 def forward_dsk(event: dict) ->
None:
696 connection.send_message(
697 websocket_api.event_message(
698 msg[ID], {
"event": event[
"event"],
"dsk": event[
"dsk"]}
703 def forward_node_added(
704 node: Node, low_security: bool, low_security_reason: str |
None
707 node.on(
"interview started", forward_event),
708 node.on(
"interview completed", forward_event),
709 node.on(
"interview stage completed", forward_stage),
710 node.on(
"interview failed", forward_event),
712 unsubs.extend(interview_unsubs)
714 "node_id": node.node_id,
715 "status": node.status,
717 "low_security": low_security,
718 "low_security_reason": low_security_reason,
720 connection.send_message(
721 websocket_api.event_message(
722 msg[ID], {
"event":
"node added",
"node": node_details}
727 def forward_requested_grant(event: dict) ->
None:
728 connection.send_message(
729 websocket_api.event_message(
732 "event": event[
"event"],
733 "requested_grant": event[
"requested_grant"].to_dict(),
739 def forward_stage(event: dict) ->
None:
740 connection.send_message(
741 websocket_api.event_message(
742 msg[ID], {
"event": event[
"event"],
"stage": event[
"stageName"]}
747 def node_found(event: dict) ->
None:
750 "node_id": node[
"nodeId"],
752 connection.send_message(
753 websocket_api.event_message(
754 msg[ID], {
"event":
"node found",
"node": node_details}
759 def node_added(event: dict) ->
None:
762 event[
"result"].
get(
"lowSecurity",
False),
763 event[
"result"].
get(
"lowSecurityReason"),
767 def device_registered(device: dr.DeviceEntry) ->
None:
771 "manufacturer": device.manufacturer,
772 "model": device.model,
774 connection.send_message(
775 websocket_api.event_message(
776 msg[ID], {
"event":
"device registered",
"device": device_details}
780 connection.subscriptions[msg[
"id"]] = async_cleanup
781 unsubs: list[Callable[[],
None]] = [
782 controller.on(
"inclusion started", forward_event),
783 controller.on(
"inclusion failed", forward_event),
784 controller.on(
"inclusion stopped", forward_event),
785 controller.on(
"validate dsk and enter pin", forward_dsk),
786 controller.on(
"grant security classes", forward_requested_grant),
787 controller.on(
"node found", node_found),
788 controller.on(
"node added", node_added),
790 hass, EVENT_DEVICE_ADDED_TO_REGISTRY, device_registered
793 msg[DATA_UNSUBSCRIBE] = unsubs
795 if controller.inclusion_state == InclusionState.INCLUDING:
796 connection.send_result(
801 for node
in controller.nodes.values():
802 if node.status != NodeStatus.DEAD
and not node.ready:
810 result = await controller.async_begin_inclusion(
811 INCLUSION_STRATEGY_NOT_SMART_START[inclusion_strategy.value],
812 force_security=force_security,
813 provisioning=provisioning,
816 except ValueError
as err:
817 connection.send_error(
824 connection.send_result(
830 @websocket_api.require_admin
831 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/grant_security_classes",
832 vol.Required(ENTRY_ID): str,
833 vol.Required(SECURITY_CLASSES): vol.All(
835 [vol.Coerce(SecurityClass)],
837 vol.Optional(CLIENT_SIDE_AUTH, default=
False): bool,
840 @websocket_api.async_response
841 @async_handle_failed_command
845 connection: ActiveConnection,
851 """Choose SecurityClass grants as part of S2 inclusion process."""
852 inclusion_grant = InclusionGrant(
853 [SecurityClass(sec_cls)
for sec_cls
in msg[SECURITY_CLASSES]],
854 msg[CLIENT_SIDE_AUTH],
856 await driver.controller.async_grant_security_classes(inclusion_grant)
857 connection.send_result(msg[ID])
860 @websocket_api.require_admin
861 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/validate_dsk_and_enter_pin",
862 vol.Required(ENTRY_ID): str,
863 vol.Required(PIN): str,
866 @websocket_api.async_response
867 @async_handle_failed_command
871 connection: ActiveConnection,
877 """Validate DSK and enter PIN as part of S2 inclusion process."""
878 await driver.controller.async_validate_dsk_and_enter_pin(msg[PIN])
879 connection.send_result(msg[ID])
882 @websocket_api.require_admin
883 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/provision_smart_start_node",
884 vol.Required(ENTRY_ID): str,
886 PLANNED_PROVISIONING_ENTRY,
"options"
887 ): PLANNED_PROVISIONING_ENTRY_SCHEMA,
889 QR_PROVISIONING_INFORMATION,
"options"
890 ): QR_PROVISIONING_INFORMATION_SCHEMA,
891 vol.Exclusive(QR_CODE_STRING,
"options"): QR_CODE_STRING_SCHEMA,
894 @websocket_api.async_response
895 @async_handle_failed_command
899 connection: ActiveConnection,
905 """Pre-provision a smart start node."""
907 cv.has_at_least_one_key(
908 PLANNED_PROVISIONING_ENTRY, QR_PROVISIONING_INFORMATION, QR_CODE_STRING
910 except vol.Invalid
as err:
911 connection.send_error(
918 provisioning_info = (
919 msg.get(PLANNED_PROVISIONING_ENTRY)
920 or msg.get(QR_PROVISIONING_INFORMATION)
921 or msg[QR_CODE_STRING]
925 QR_PROVISIONING_INFORMATION
in msg
926 and provisioning_info.version == QRCodeVersion.S2
928 connection.send_error(
931 "QR code version S2 is not supported for this command",
934 await driver.controller.async_provision_smart_start_node(provisioning_info)
935 connection.send_result(msg[ID])
938 @websocket_api.require_admin
939 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/unprovision_smart_start_node",
940 vol.Required(ENTRY_ID): str,
941 vol.Exclusive(DSK,
"input"): str,
942 vol.Exclusive(NODE_ID,
"input"): int,
945 @websocket_api.async_response
946 @async_handle_failed_command
950 connection: ActiveConnection,
956 """Unprovision a smart start node."""
958 cv.has_at_least_one_key(DSK, NODE_ID)(msg)
959 except vol.Invalid
as err:
960 connection.send_error(
966 dsk_or_node_id = msg.get(DSK)
or msg[NODE_ID]
967 await driver.controller.async_unprovision_smart_start_node(dsk_or_node_id)
968 connection.send_result(msg[ID])
971 @websocket_api.require_admin
972 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/get_provisioning_entries",
973 vol.Required(ENTRY_ID): str,
976 @websocket_api.async_response
977 @async_handle_failed_command
981 connection: ActiveConnection,
987 """Get provisioning entries (entries that have been pre-provisioned)."""
988 provisioning_entries = await driver.controller.async_get_provisioning_entries()
989 connection.send_result(msg[ID], [entry.to_dict()
for entry
in provisioning_entries])
992 @websocket_api.require_admin
993 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/parse_qr_code_string",
994 vol.Required(ENTRY_ID): str,
995 vol.Required(QR_CODE_STRING): QR_CODE_STRING_SCHEMA,
998 @websocket_api.async_response
999 @async_handle_failed_command
1002 hass: HomeAssistant,
1003 connection: ActiveConnection,
1004 msg: dict[str, Any],
1009 """Parse a QR Code String and return QRProvisioningInformation dict."""
1010 qr_provisioning_information = await async_parse_qr_code_string(
1011 client, msg[QR_CODE_STRING]
1013 connection.send_result(msg[ID], qr_provisioning_information.to_dict())
1016 @websocket_api.require_admin
1017 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/try_parse_dsk_from_qr_code_string",
1018 vol.Required(ENTRY_ID): str,
1019 vol.Required(QR_CODE_STRING): str,
1022 @websocket_api.async_response
1023 @async_handle_failed_command
1026 hass: HomeAssistant,
1027 connection: ActiveConnection,
1028 msg: dict[str, Any],
1033 """Try to parse a DSK string from a QR code."""
1034 connection.send_result(
1036 await async_try_parse_dsk_from_qr_code_string(client, msg[QR_CODE_STRING]),
1040 @websocket_api.require_admin
1041 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/supports_feature",
1042 vol.Required(ENTRY_ID): str,
1043 vol.Required(FEATURE): vol.Coerce(ZwaveFeature),
1046 @websocket_api.async_response
1047 @async_handle_failed_command
1050 hass: HomeAssistant,
1051 connection: ActiveConnection,
1052 msg: dict[str, Any],
1057 """Check if controller supports a particular feature."""
1058 supported = await driver.controller.async_supports_feature(msg[FEATURE])
1059 connection.send_result(
1061 {
"supported": supported},
1065 @websocket_api.require_admin
1066 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/stop_inclusion",
1067 vol.Required(ENTRY_ID): str,
1070 @websocket_api.async_response
1071 @async_handle_failed_command
1074 hass: HomeAssistant,
1075 connection: ActiveConnection,
1076 msg: dict[str, Any],
1081 """Cancel adding a node to the Z-Wave network."""
1082 controller = driver.controller
1083 result = await controller.async_stop_inclusion()
1084 connection.send_result(
1090 @websocket_api.require_admin
1091 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/stop_exclusion",
1092 vol.Required(ENTRY_ID): str,
1095 @websocket_api.async_response
1096 @async_handle_failed_command
1099 hass: HomeAssistant,
1100 connection: ActiveConnection,
1101 msg: dict[str, Any],
1106 """Cancel removing a node from the Z-Wave network."""
1107 controller = driver.controller
1108 result = await controller.async_stop_exclusion()
1109 connection.send_result(
1115 @websocket_api.require_admin
1116 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/remove_node",
1117 vol.Required(ENTRY_ID): str,
1118 vol.Optional(STRATEGY): vol.Coerce(ExclusionStrategy),
1121 @websocket_api.async_response
1122 @async_handle_failed_command
1125 hass: HomeAssistant,
1126 connection: ActiveConnection,
1127 msg: dict[str, Any],
1132 """Remove a node from the Z-Wave network."""
1133 controller = driver.controller
1137 """Remove signal listeners."""
1138 for unsub
in unsubs:
1142 def forward_event(event: dict) ->
None:
1143 connection.send_message(
1144 websocket_api.event_message(msg[ID], {
"event": event[
"event"]})
1148 def node_removed(event: dict) ->
None:
1149 node = event[
"node"]
1151 "node_id": node.node_id,
1152 "reason": event[
"reason"],
1155 connection.send_message(
1156 websocket_api.event_message(
1157 msg[ID], {
"event":
"node removed",
"node": node_details}
1161 connection.subscriptions[msg[
"id"]] = async_cleanup
1162 msg[DATA_UNSUBSCRIBE] = unsubs = [
1163 controller.on(
"exclusion started", forward_event),
1164 controller.on(
"exclusion failed", forward_event),
1165 controller.on(
"exclusion stopped", forward_event),
1166 controller.on(
"node removed", node_removed),
1169 result = await controller.async_begin_exclusion(msg.get(STRATEGY))
1170 connection.send_result(
1176 @websocket_api.require_admin
1177 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/replace_failed_node",
1178 vol.Required(DEVICE_ID): str,
1179 vol.Optional(INCLUSION_STRATEGY, default=InclusionStrategy.DEFAULT): vol.All(
1184 for strategy
in InclusionStrategy
1185 if strategy != InclusionStrategy.SMART_START
1189 vol.Optional(FORCE_SECURITY): bool,
1191 PLANNED_PROVISIONING_ENTRY,
"options"
1192 ): PLANNED_PROVISIONING_ENTRY_SCHEMA,
1194 QR_PROVISIONING_INFORMATION,
"options"
1195 ): QR_PROVISIONING_INFORMATION_SCHEMA,
1196 vol.Exclusive(QR_CODE_STRING,
"options"): QR_CODE_STRING_SCHEMA,
1199 @websocket_api.async_response
1200 @async_handle_failed_command
1203 hass: HomeAssistant,
1204 connection: ActiveConnection,
1205 msg: dict[str, Any],
1208 """Replace a failed node with a new node."""
1209 assert node.client.driver
1210 controller = node.client.driver.controller
1211 inclusion_strategy = InclusionStrategy(msg[INCLUSION_STRATEGY])
1212 force_security = msg.get(FORCE_SECURITY)
1214 msg.get(PLANNED_PROVISIONING_ENTRY)
1215 or msg.get(QR_PROVISIONING_INFORMATION)
1216 or msg.get(QR_CODE_STRING)
1221 """Remove signal listeners."""
1222 for unsub
in unsubs:
1226 def forward_event(event: dict) ->
None:
1227 connection.send_message(
1228 websocket_api.event_message(msg[ID], {
"event": event[
"event"]})
1232 def forward_dsk(event: dict) ->
None:
1233 connection.send_message(
1234 websocket_api.event_message(
1235 msg[ID], {
"event": event[
"event"],
"dsk": event[
"dsk"]}
1240 def forward_requested_grant(event: dict) ->
None:
1241 connection.send_message(
1242 websocket_api.event_message(
1245 "event": event[
"event"],
1246 "requested_grant": event[
"requested_grant"].to_dict(),
1252 def forward_stage(event: dict) ->
None:
1253 connection.send_message(
1254 websocket_api.event_message(
1255 msg[ID], {
"event": event[
"event"],
"stage": event[
"stageName"]}
1260 def node_found(event: dict) ->
None:
1261 node = event[
"node"]
1263 "node_id": node[
"nodeId"],
1265 connection.send_message(
1266 websocket_api.event_message(
1267 msg[ID], {
"event":
"node found",
"node": node_details}
1272 def node_added(event: dict) ->
None:
1273 node = event[
"node"]
1274 interview_unsubs = [
1275 node.on(
"interview started", forward_event),
1276 node.on(
"interview completed", forward_event),
1277 node.on(
"interview stage completed", forward_stage),
1278 node.on(
"interview failed", forward_event),
1280 unsubs.extend(interview_unsubs)
1282 "node_id": node.node_id,
1283 "status": node.status,
1284 "ready": node.ready,
1286 connection.send_message(
1287 websocket_api.event_message(
1288 msg[ID], {
"event":
"node added",
"node": node_details}
1293 def node_removed(event: dict) ->
None:
1294 node = event[
"node"]
1296 "node_id": node.node_id,
1299 connection.send_message(
1300 websocket_api.event_message(
1301 msg[ID], {
"event":
"node removed",
"node": node_details}
1306 def device_registered(device: dr.DeviceEntry) ->
None:
1308 "name": device.name,
1310 "manufacturer": device.manufacturer,
1311 "model": device.model,
1313 connection.send_message(
1314 websocket_api.event_message(
1315 msg[ID], {
"event":
"device registered",
"device": device_details}
1319 connection.subscriptions[msg[
"id"]] = async_cleanup
1320 unsubs: list[Callable[[],
None]] = [
1321 controller.on(
"inclusion started", forward_event),
1322 controller.on(
"inclusion failed", forward_event),
1323 controller.on(
"inclusion stopped", forward_event),
1324 controller.on(
"validate dsk and enter pin", forward_dsk),
1325 controller.on(
"grant security classes", forward_requested_grant),
1326 controller.on(
"node removed", node_removed),
1327 controller.on(
"node found", node_found),
1328 controller.on(
"node added", node_added),
1330 hass, EVENT_DEVICE_ADDED_TO_REGISTRY, device_registered
1333 msg[DATA_UNSUBSCRIBE] = unsubs
1336 result = await controller.async_replace_failed_node(
1338 INCLUSION_STRATEGY_NOT_SMART_START[inclusion_strategy.value],
1339 force_security=force_security,
1340 provisioning=provisioning,
1342 except ValueError
as err:
1343 connection.send_error(
1350 connection.send_result(
1356 @websocket_api.require_admin
1357 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/remove_failed_node",
1358 vol.Required(DEVICE_ID): str,
1361 @websocket_api.async_response
1362 @async_handle_failed_command
1365 hass: HomeAssistant,
1366 connection: ActiveConnection,
1367 msg: dict[str, Any],
1370 """Remove a failed node from the Z-Wave network."""
1371 driver = node.client.driver
1372 assert driver
is not None
1373 controller = driver.controller
1377 """Remove signal listeners."""
1378 for unsub
in unsubs:
1382 def node_removed(event: dict) ->
None:
1383 node_details = {
"node_id": event[
"node"].node_id}
1385 connection.send_message(
1386 websocket_api.event_message(
1387 msg[ID], {
"event":
"node removed",
"node": node_details}
1391 connection.subscriptions[msg[
"id"]] = async_cleanup
1392 msg[DATA_UNSUBSCRIBE] = unsubs = [controller.on(
"node removed", node_removed)]
1394 await controller.async_remove_failed_node(node)
1395 connection.send_result(msg[ID])
1398 @websocket_api.require_admin
1399 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/begin_rebuilding_routes",
1400 vol.Required(ENTRY_ID): str,
1403 @websocket_api.async_response
1404 @async_handle_failed_command
1407 hass: HomeAssistant,
1408 connection: ActiveConnection,
1409 msg: dict[str, Any],
1414 """Begin rebuilding Z-Wave routes."""
1415 controller = driver.controller
1417 result = await controller.async_begin_rebuilding_routes()
1418 connection.send_result(
1424 @websocket_api.require_admin
1425 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/subscribe_rebuild_routes_progress",
1426 vol.Required(ENTRY_ID): str,
1429 @websocket_api.async_response
1432 hass: HomeAssistant,
1433 connection: ActiveConnection,
1434 msg: dict[str, Any],
1439 """Subscribe to rebuild Z-Wave routes status updates."""
1440 controller = driver.controller
1444 """Remove signal listeners."""
1445 for unsub
in unsubs:
1449 def forward_event(key: str, event: dict) ->
None:
1450 connection.send_message(
1451 websocket_api.event_message(
1452 msg[ID], {
"event": event[
"event"],
"rebuild_routes_status": event[key]}
1456 connection.subscriptions[msg[
"id"]] = async_cleanup
1457 msg[DATA_UNSUBSCRIBE] = unsubs = [
1458 controller.on(
"rebuild routes progress", partial(forward_event,
"progress")),
1459 controller.on(
"rebuild routes done", partial(forward_event,
"result")),
1462 if controller.rebuild_routes_progress:
1463 connection.send_result(
1466 node.node_id: status
1467 for node, status
in controller.rebuild_routes_progress.items()
1471 connection.send_result(msg[ID],
None)
1474 @websocket_api.require_admin
1475 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/stop_rebuilding_routes",
1476 vol.Required(ENTRY_ID): str,
1479 @websocket_api.async_response
1480 @async_handle_failed_command
1483 hass: HomeAssistant,
1484 connection: ActiveConnection,
1485 msg: dict[str, Any],
1490 """Stop rebuilding Z-Wave routes."""
1491 controller = driver.controller
1492 result = await controller.async_stop_rebuilding_routes()
1493 connection.send_result(
1499 @websocket_api.require_admin
1500 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/rebuild_node_routes",
1501 vol.Required(DEVICE_ID): str,
1504 @websocket_api.async_response
1505 @async_handle_failed_command
1508 hass: HomeAssistant,
1509 connection: ActiveConnection,
1510 msg: dict[str, Any],
1513 """Heal a node on the Z-Wave network."""
1514 driver = node.client.driver
1515 assert driver
is not None
1516 controller = driver.controller
1518 result = await controller.async_rebuild_node_routes(node)
1519 connection.send_result(
1525 @websocket_api.require_admin
1526 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/refresh_node_info",
1527 vol.Required(DEVICE_ID): str,
1530 @websocket_api.async_response
1531 @async_handle_failed_command
1534 hass: HomeAssistant,
1535 connection: ActiveConnection,
1536 msg: dict[str, Any],
1539 """Re-interview a node."""
1543 """Remove signal listeners."""
1544 for unsub
in unsubs:
1548 def forward_event(event: dict) ->
None:
1549 connection.send_message(
1550 websocket_api.event_message(msg[ID], {
"event": event[
"event"]})
1554 def forward_stage(event: dict) ->
None:
1555 connection.send_message(
1556 websocket_api.event_message(
1557 msg[ID], {
"event": event[
"event"],
"stage": event[
"stageName"]}
1561 connection.subscriptions[msg[
"id"]] = async_cleanup
1562 msg[DATA_UNSUBSCRIBE] = unsubs = [
1563 node.on(
"interview started", forward_event),
1564 node.on(
"interview completed", forward_event),
1565 node.on(
"interview stage completed", forward_stage),
1566 node.on(
"interview failed", forward_event),
1569 await node.async_refresh_info()
1570 connection.send_result(msg[ID])
1573 @websocket_api.require_admin
1574 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/refresh_node_values",
1575 vol.Required(DEVICE_ID): str,
1578 @websocket_api.async_response
1579 @async_handle_failed_command
1582 hass: HomeAssistant,
1583 connection: ActiveConnection,
1584 msg: dict[str, Any],
1587 """Refresh node values."""
1588 await node.async_refresh_values()
1589 connection.send_result(msg[ID])
1592 @websocket_api.require_admin
1593 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/refresh_node_cc_values",
1594 vol.Required(DEVICE_ID): str,
1595 vol.Required(COMMAND_CLASS_ID): int,
1598 @websocket_api.async_response
1599 @async_handle_failed_command
1602 hass: HomeAssistant,
1603 connection: ActiveConnection,
1604 msg: dict[str, Any],
1607 """Refresh node values for a particular CommandClass."""
1608 command_class_id = msg[COMMAND_CLASS_ID]
1611 command_class = CommandClass(command_class_id)
1613 connection.send_error(
1614 msg[ID], ERR_NOT_FOUND, f
"Command class {command_class_id} not found"
1618 await node.async_refresh_cc_values(command_class)
1619 connection.send_result(msg[ID])
1622 @websocket_api.require_admin
1623 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/set_config_parameter",
1624 vol.Required(DEVICE_ID): str,
1625 vol.Required(PROPERTY): int,
1626 vol.Optional(ENDPOINT, default=0): int,
1627 vol.Optional(PROPERTY_KEY): int,
1628 vol.Required(VALUE): vol.Any(int, BITMASK_SCHEMA),
1631 @websocket_api.async_response
1632 @async_handle_failed_command
1635 hass: HomeAssistant,
1636 connection: ActiveConnection,
1637 msg: dict[str, Any],
1640 """Set a config parameter value for a Z-Wave node."""
1641 property_ = msg[PROPERTY]
1642 endpoint = msg[ENDPOINT]
1643 property_key = msg.get(PROPERTY_KEY)
1647 zwave_value, cmd_status = await async_set_config_parameter(
1648 node, value, property_, property_key=property_key, endpoint=endpoint
1650 except (InvalidNewValue, NotFoundError, NotImplementedError, SetValueFailed)
as err:
1651 code = ERR_UNKNOWN_ERROR
1652 if isinstance(err, NotFoundError):
1653 code = ERR_NOT_FOUND
1654 elif isinstance(err, (InvalidNewValue, NotImplementedError)):
1655 code = ERR_NOT_SUPPORTED
1657 connection.send_error(
1664 connection.send_result(
1667 VALUE_ID: zwave_value.value_id,
1668 STATUS: cmd_status.status,
1673 @websocket_api.require_admin
1674 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/get_config_parameters",
1675 vol.Required(DEVICE_ID): str,
1678 @websocket_api.async_response
1681 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any], node: Node
1683 """Get a list of configuration parameters for a Z-Wave node."""
1684 values = node.get_configuration_values()
1685 result: dict[str, Any] = {}
1686 for value_id, zwave_value
in values.items():
1687 metadata = zwave_value.metadata
1688 result[value_id] = {
1689 "property": zwave_value.property_,
1690 "property_key": zwave_value.property_key,
1691 "endpoint": zwave_value.endpoint,
1692 "configuration_value_type": zwave_value.configuration_value_type.value,
1694 "description": metadata.description,
1695 "label": metadata.label,
1696 "type": metadata.type,
1697 "min": metadata.min,
1698 "max": metadata.max,
1699 "unit": metadata.unit,
1700 "writeable": metadata.writeable,
1701 "readable": metadata.readable,
1702 "default": metadata.default,
1704 "value": zwave_value.value,
1706 if zwave_value.metadata.states:
1707 result[value_id][
"metadata"][
"states"] = zwave_value.metadata.states
1709 connection.send_result(
1715 @websocket_api.require_admin
1716 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/set_raw_config_parameter",
1717 vol.Required(DEVICE_ID): str,
1718 vol.Required(PROPERTY): int,
1719 vol.Required(VALUE): int,
1720 vol.Required(VALUE_SIZE): vol.All(vol.Coerce(int), vol.Range(min=1, max=4)),
1721 vol.Required(VALUE_FORMAT): vol.Coerce(ConfigurationValueFormat),
1724 @websocket_api.async_response
1725 @async_handle_failed_command
1728 hass: HomeAssistant,
1729 connection: ActiveConnection,
1730 msg: dict[str, Any],
1733 """Set a custom config parameter value for a Z-Wave node."""
1734 result = await node.async_set_raw_config_parameter_value(
1737 value_size=msg[VALUE_SIZE],
1738 value_format=msg[VALUE_FORMAT],
1741 connection.send_result(
1744 STATUS: result.status,
1749 @websocket_api.require_admin
1750 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/get_raw_config_parameter",
1751 vol.Required(DEVICE_ID): str,
1752 vol.Required(PROPERTY): int,
1755 @websocket_api.async_response
1756 @async_handle_failed_command
1759 hass: HomeAssistant,
1760 connection: ActiveConnection,
1761 msg: dict[str, Any],
1764 """Get a custom config parameter value for a Z-Wave node."""
1765 value = await node.async_get_raw_config_parameter_value(
1769 connection.send_result(
1778 """Validate that filename is provided if log_to_file is True."""
1779 if obj.get(LOG_TO_FILE,
False)
and FILENAME
not in obj:
1780 raise vol.Invalid(
"`filename` must be provided if logging to file")
1784 @websocket_api.require_admin
1785 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/subscribe_log_updates",
1786 vol.Required(ENTRY_ID): str,
1789 @websocket_api.async_response
1790 @async_handle_failed_command
1793 hass: HomeAssistant,
1794 connection: ActiveConnection,
1795 msg: dict[str, Any],
1800 """Subscribe to log message events from the server."""
1804 """Remove signal listeners."""
1805 hass.async_create_task(client.async_stop_listening_logs())
1806 for unsub
in unsubs:
1810 def log_messages(event: dict) ->
None:
1811 log_msg: LogMessage = event[
"log_message"]
1812 connection.send_message(
1813 websocket_api.event_message(
1816 "type":
"log_message",
1818 "timestamp": log_msg.timestamp,
1819 "level": log_msg.level,
1820 "primary_tags": log_msg.primary_tags,
1821 "message": log_msg.formatted_message,
1828 def log_config_updates(event: dict) ->
None:
1829 log_config: LogConfig = event[
"log_config"]
1830 connection.send_message(
1831 websocket_api.event_message(
1834 "type":
"log_config",
1835 "log_config": dataclasses.asdict(log_config),
1840 msg[DATA_UNSUBSCRIBE] = unsubs = [
1841 driver.on(
"logging", log_messages),
1842 driver.on(
"log config updated", log_config_updates),
1844 connection.subscriptions[msg[
"id"]] = async_cleanup
1846 await client.async_start_listening_logs()
1847 connection.send_result(msg[ID])
1850 @websocket_api.require_admin
1851 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/update_log_config",
1852 vol.Required(ENTRY_ID): str,
1853 vol.Required(CONFIG): vol.All(
1856 vol.Optional(ENABLED): cv.boolean,
1857 vol.Optional(LEVEL): vol.All(
1860 vol.Coerce(LogLevel),
1862 vol.Optional(LOG_TO_FILE): cv.boolean,
1863 vol.Optional(FILENAME): str,
1864 vol.Optional(FORCE_CONSOLE): cv.boolean,
1867 cv.has_at_least_one_key(
1868 ENABLED, FILENAME, FORCE_CONSOLE, LEVEL, LOG_TO_FILE
1870 filename_is_present_if_logging_to_file,
1874 @websocket_api.async_response
1875 @async_handle_failed_command
1878 hass: HomeAssistant,
1879 connection: ActiveConnection,
1880 msg: dict[str, Any],
1885 """Update the driver log config."""
1886 await driver.async_update_log_config(LogConfig(**msg[CONFIG]))
1887 connection.send_result(
1892 @websocket_api.require_admin
1893 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/get_log_config",
1894 vol.Required(ENTRY_ID): str,
1897 @websocket_api.async_response
1900 hass: HomeAssistant,
1901 connection: ActiveConnection,
1902 msg: dict[str, Any],
1907 """Get log configuration for the Z-Wave JS driver."""
1908 assert client
and client.driver
1909 connection.send_result(
1911 dataclasses.asdict(driver.log_config),
1915 @websocket_api.require_admin
1916 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/update_data_collection_preference",
1917 vol.Required(ENTRY_ID): str,
1918 vol.Required(OPTED_IN): bool,
1921 @websocket_api.async_response
1922 @async_handle_failed_command
1925 hass: HomeAssistant,
1926 connection: ActiveConnection,
1927 msg: dict[str, Any],
1932 """Update preference for data collection and enable/disable collection."""
1933 opted_in = msg[OPTED_IN]
1934 if entry.data.get(CONF_DATA_COLLECTION_OPTED_IN) != opted_in:
1935 new_data = entry.data.copy()
1936 new_data[CONF_DATA_COLLECTION_OPTED_IN] = opted_in
1937 hass.config_entries.async_update_entry(entry, data=new_data)
1942 await driver.async_disable_statistics()
1944 connection.send_result(
1949 @websocket_api.require_admin
1950 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/data_collection_status",
1951 vol.Required(ENTRY_ID): str,
1954 @websocket_api.async_response
1955 @async_handle_failed_command
1958 hass: HomeAssistant,
1959 connection: ActiveConnection,
1960 msg: dict[str, Any],
1965 """Return data collection preference and status."""
1966 assert client
and client.driver
1968 OPTED_IN: entry.data.get(CONF_DATA_COLLECTION_OPTED_IN),
1969 ENABLED: await driver.async_is_statistics_enabled(),
1971 connection.send_result(msg[ID], result)
1974 @websocket_api.require_admin
1975 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/abort_firmware_update",
1976 vol.Required(DEVICE_ID): str,
1979 @websocket_api.async_response
1980 @async_handle_failed_command
1983 hass: HomeAssistant,
1984 connection: ActiveConnection,
1985 msg: dict[str, Any],
1988 """Abort a firmware update."""
1989 await node.async_abort_firmware_update()
1990 connection.send_result(msg[ID])
1993 @websocket_api.require_admin
1994 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/is_node_firmware_update_in_progress",
1995 vol.Required(DEVICE_ID): str,
1998 @websocket_api.async_response
1999 @async_handle_failed_command
2002 hass: HomeAssistant,
2003 connection: ActiveConnection,
2004 msg: dict[str, Any],
2007 """Get whether firmware update is in progress for given node."""
2008 connection.send_result(msg[ID], await node.async_is_firmware_update_in_progress())
2012 progress: NodeFirmwareUpdateProgress,
2013 ) -> dict[str, int | float]:
2014 """Get a dictionary of a node's firmware update progress."""
2016 "current_file": progress.current_file,
2017 "total_files": progress.total_files,
2018 "sent_fragments": progress.sent_fragments,
2019 "total_fragments": progress.total_fragments,
2020 "progress": progress.progress,
2025 progress: ControllerFirmwareUpdateProgress,
2026 ) -> dict[str, int | float]:
2027 """Get a dictionary of a controller's firmware update progress."""
2031 "sent_fragments": progress.sent_fragments,
2032 "total_fragments": progress.total_fragments,
2033 "progress": progress.progress,
2037 @websocket_api.require_admin
2038 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/subscribe_firmware_update_status",
2039 vol.Required(DEVICE_ID): str,
2042 @websocket_api.async_response
2045 hass: HomeAssistant,
2046 connection: ActiveConnection,
2047 msg: dict[str, Any],
2050 """Subscribe to the status of a firmware update."""
2051 assert node.client.driver
2052 controller = node.client.driver.controller
2056 """Remove signal listeners."""
2057 for unsub
in unsubs:
2061 def forward_node_progress(event: dict) ->
None:
2062 progress: NodeFirmwareUpdateProgress = event[
"firmware_update_progress"]
2063 connection.send_message(
2064 websocket_api.event_message(
2067 "event": event[
"event"],
2074 def forward_node_finished(event: dict) ->
None:
2075 finished: NodeFirmwareUpdateResult = event[
"firmware_update_finished"]
2076 connection.send_message(
2077 websocket_api.event_message(
2080 "event": event[
"event"],
2081 "status": finished.status,
2082 "success": finished.success,
2083 "wait_time": finished.wait_time,
2084 "reinterview": finished.reinterview,
2090 def forward_controller_progress(event: dict) ->
None:
2091 progress: ControllerFirmwareUpdateProgress = event[
"firmware_update_progress"]
2092 connection.send_message(
2093 websocket_api.event_message(
2096 "event": event[
"event"],
2103 def forward_controller_finished(event: dict) ->
None:
2104 finished: ControllerFirmwareUpdateResult = event[
"firmware_update_finished"]
2105 connection.send_message(
2106 websocket_api.event_message(
2109 "event": event[
"event"],
2110 "status": finished.status,
2111 "success": finished.success,
2116 if controller.own_node == node:
2117 msg[DATA_UNSUBSCRIBE] = unsubs = [
2118 controller.on(
"firmware update progress", forward_controller_progress),
2119 controller.on(
"firmware update finished", forward_controller_finished),
2122 msg[DATA_UNSUBSCRIBE] = unsubs = [
2123 node.on(
"firmware update progress", forward_node_progress),
2124 node.on(
"firmware update finished", forward_node_finished),
2126 connection.subscriptions[msg[
"id"]] = async_cleanup
2128 connection.send_result(msg[ID])
2129 if node.is_controller_node
and (
2130 controller_progress := controller.firmware_update_progress
2132 connection.send_message(
2133 websocket_api.event_message(
2136 "event":
"firmware update progress",
2143 elif controller.own_node != node
and (
2144 node_progress := node.firmware_update_progress
2146 connection.send_message(
2147 websocket_api.event_message(
2150 "event":
"firmware update progress",
2157 @websocket_api.require_admin
2158 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/get_node_firmware_update_capabilities",
2159 vol.Required(DEVICE_ID): str,
2162 @websocket_api.async_response
2163 @async_handle_failed_command
2166 hass: HomeAssistant,
2167 connection: ActiveConnection,
2168 msg: dict[str, Any],
2171 """Get a node's firmware update capabilities."""
2172 capabilities = await node.async_get_firmware_update_capabilities()
2173 connection.send_result(msg[ID], capabilities.to_dict())
2176 @websocket_api.require_admin
2177 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/is_any_ota_firmware_update_in_progress",
2178 vol.Required(ENTRY_ID): str,
2181 @websocket_api.async_response
2182 @async_handle_failed_command
2185 hass: HomeAssistant,
2186 connection: ActiveConnection,
2187 msg: dict[str, Any],
2192 """Get whether any firmware updates are in progress."""
2193 connection.send_result(
2194 msg[ID], await driver.controller.async_is_any_ota_firmware_update_in_progress()
2199 """View to upload firmware."""
2201 url =
r"/api/zwave_js/firmware/upload/{device_id}"
2202 name =
"api:zwave_js:firmware:upload"
2204 def __init__(self, dev_reg: dr.DeviceRegistry) ->
None:
2205 """Initialize view."""
2207 self._dev_reg = dev_reg
2210 async
def post(self, request: web.Request, device_id: str) -> web.Response:
2211 """Handle upload."""
2212 hass = request.app[KEY_HASS]
2216 except ValueError
as err:
2217 if "not loaded" in err.args[0]:
2218 raise web_exceptions.HTTPBadRequest
from err
2219 raise web_exceptions.HTTPNotFound
from err
2223 assert node.client.driver
2226 request._client_max_size = 1024 * 1024 * 10
2228 data = await request.post()
2230 if "file" not in data
or not isinstance(data[
"file"], web_request.FileField):
2231 raise web_exceptions.HTTPBadRequest
2233 uploaded_file: web_request.FileField = data[
"file"]
2236 if node.client.driver.controller.own_node == node:
2237 await controller_firmware_update_otw(
2238 node.client.ws_server_url,
2239 ControllerFirmwareUpdateData(
2240 uploaded_file.filename,
2241 await hass.async_add_executor_job(uploaded_file.file.read),
2244 additional_user_agent_components=USER_AGENT,
2247 firmware_target: int |
None =
None
2248 if "target" in data:
2249 firmware_target =
int(cast(str, data[
"target"]))
2250 await update_firmware(
2251 node.client.ws_server_url,
2254 NodeFirmwareUpdateData(
2255 uploaded_file.filename,
2256 await hass.async_add_executor_job(uploaded_file.file.read),
2257 firmware_target=firmware_target,
2261 additional_user_agent_components=USER_AGENT,
2263 except BaseZwaveJSServerError
as err:
2264 raise web_exceptions.HTTPBadRequest(reason=
str(err))
from err
2266 return self.json(
None)
2269 @websocket_api.require_admin
2270 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/check_for_config_updates",
2271 vol.Required(ENTRY_ID): str,
2274 @websocket_api.async_response
2275 @async_handle_failed_command
2278 hass: HomeAssistant,
2279 connection: ActiveConnection,
2280 msg: dict[str, Any],
2285 """Check for config updates."""
2286 config_update = await driver.async_check_for_config_updates()
2287 connection.send_result(
2290 "update_available": config_update.update_available,
2291 "new_version": config_update.new_version,
2296 @websocket_api.require_admin
2297 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/install_config_update",
2298 vol.Required(ENTRY_ID): str,
2301 @websocket_api.async_response
2302 @async_handle_failed_command
2305 hass: HomeAssistant,
2306 connection: ActiveConnection,
2307 msg: dict[str, Any],
2312 """Check for config updates."""
2313 success = await driver.async_install_config_update()
2314 connection.send_result(msg[ID], success)
2318 statistics: ControllerStatistics,
2319 ) -> dict[str, int]:
2320 """Get dictionary of controller statistics."""
2322 "messages_tx": statistics.messages_tx,
2323 "messages_rx": statistics.messages_rx,
2324 "messages_dropped_tx": statistics.messages_dropped_tx,
2325 "messages_dropped_rx": statistics.messages_dropped_rx,
2326 "nak": statistics.nak,
2327 "can": statistics.can,
2328 "timeout_ack": statistics.timeout_ack,
2329 "timout_response": statistics.timeout_response,
2330 "timeout_callback": statistics.timeout_callback,
2334 @websocket_api.require_admin
2335 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/subscribe_controller_statistics",
2336 vol.Required(ENTRY_ID): str,
2339 @websocket_api.async_response
2342 hass: HomeAssistant,
2343 connection: ActiveConnection,
2344 msg: dict[str, Any],
2349 """Subscribe to the statistics updates for a controller."""
2353 """Remove signal listeners."""
2354 for unsub
in unsubs:
2358 def forward_stats(event: dict) ->
None:
2359 statistics: ControllerStatistics = event[
"statistics_updated"]
2360 connection.send_message(
2361 websocket_api.event_message(
2364 "event": event[
"event"],
2365 "source":
"controller",
2371 controller = driver.controller
2373 msg[DATA_UNSUBSCRIBE] = unsubs = [
2374 controller.on(
"statistics updated", forward_stats)
2376 connection.subscriptions[msg[
"id"]] = async_cleanup
2378 connection.send_result(msg[ID])
2379 connection.send_message(
2380 websocket_api.event_message(
2383 "event":
"statistics updated",
2384 "source":
"controller",
2392 hass: HomeAssistant, statistics: NodeStatistics
2393 ) -> dict[str, Any]:
2394 """Get dictionary of node statistics."""
2395 dev_reg = dr.async_get(hass)
2397 def _convert_node_to_device_id(node: Node) -> str:
2398 """Convert a node to a device id."""
2399 driver = node.client.driver
2406 "commands_tx": statistics.commands_tx,
2407 "commands_rx": statistics.commands_rx,
2408 "commands_dropped_tx": statistics.commands_dropped_tx,
2409 "commands_dropped_rx": statistics.commands_dropped_rx,
2410 "timeout_response": statistics.timeout_response,
2411 "rtt": statistics.rtt,
2412 "rssi": statistics.rssi,
2413 "lwr": statistics.lwr.as_dict()
if statistics.lwr
else None,
2414 "nlwr": statistics.nlwr.as_dict()
if statistics.nlwr
else None,
2416 for key
in (
"lwr",
"nlwr"):
2419 for key_2
in (
"repeaters",
"route_failed_between"):
2420 if not data[key][key_2]:
2422 data[key][key_2] = [
2423 _convert_node_to_device_id(node)
for node
in data[key][key_2]
2429 @websocket_api.require_admin
2430 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/subscribe_node_statistics",
2431 vol.Required(DEVICE_ID): str,
2434 @websocket_api.async_response
2437 hass: HomeAssistant,
2438 connection: ActiveConnection,
2439 msg: dict[str, Any],
2442 """Subscribe to the statistics updates for a node."""
2446 """Remove signal listeners."""
2447 for unsub
in unsubs:
2451 def forward_stats(event: dict) ->
None:
2452 statistics: NodeStatistics = event[
"statistics_updated"]
2453 connection.send_message(
2454 websocket_api.event_message(
2457 "event": event[
"event"],
2459 "node_id": node.node_id,
2465 msg[DATA_UNSUBSCRIBE] = unsubs = [node.on(
"statistics updated", forward_stats)]
2466 connection.subscriptions[msg[
"id"]] = async_cleanup
2468 connection.send_result(msg[ID])
2469 connection.send_message(
2470 websocket_api.event_message(
2473 "event":
"statistics updated",
2475 "nodeId": node.node_id,
2482 @websocket_api.require_admin
2483 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/hard_reset_controller",
2484 vol.Required(ENTRY_ID): str,
2487 @websocket_api.async_response
2488 @async_handle_failed_command
2491 hass: HomeAssistant,
2492 connection: ActiveConnection,
2493 msg: dict[str, Any],
2498 """Hard reset controller."""
2502 """Remove signal listeners."""
2503 for unsub
in unsubs:
2508 def _handle_device_added(device: dr.DeviceEntry) ->
None:
2509 """Handle device is added."""
2510 if entry.entry_id
in device.config_entries:
2511 connection.send_result(msg[ID], device.id)
2514 msg[DATA_UNSUBSCRIBE] = unsubs = [
2516 hass, EVENT_DEVICE_ADDED_TO_REGISTRY, _handle_device_added
2519 await driver.async_hard_reset()
2522 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/node_capabilities",
2523 vol.Required(DEVICE_ID): str,
2526 @websocket_api.async_response
2527 @async_handle_failed_command
2530 hass: HomeAssistant,
2531 connection: ActiveConnection,
2532 msg: dict[str, Any],
2535 """Get node endpoints with their support command classes."""
2538 connection.send_result(
2542 command_class.to_dict() | {
"is_secure": command_class.is_secure}
2543 for command_class
in endpoint.command_classes
2545 for idx, endpoint
in node.endpoints.items()
2550 @websocket_api.require_admin
2551 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/invoke_cc_api",
2552 vol.Required(DEVICE_ID): str,
2553 vol.Required(ATTR_COMMAND_CLASS): vol.All(
2554 vol.Coerce(int), vol.Coerce(CommandClass)
2556 vol.Optional(ATTR_ENDPOINT): vol.Coerce(int),
2557 vol.Required(ATTR_METHOD_NAME): cv.string,
2558 vol.Required(ATTR_PARAMETERS): list,
2559 vol.Optional(ATTR_WAIT_FOR_RESULT): cv.boolean,
2562 @websocket_api.async_response
2563 @async_handle_failed_command
2566 hass: HomeAssistant,
2567 connection: ActiveConnection,
2568 msg: dict[str, Any],
2571 """Call invokeCCAPI on the node or provided endpoint."""
2572 command_class: CommandClass = msg[ATTR_COMMAND_CLASS]
2573 method_name: str = msg[ATTR_METHOD_NAME]
2574 parameters: list[Any] = msg[ATTR_PARAMETERS]
2576 node_or_endpoint: Node | Endpoint = node
2577 if (endpoint := msg.get(ATTR_ENDPOINT))
is not None:
2578 node_or_endpoint = node.endpoints[endpoint]
2581 result = await node_or_endpoint.async_invoke_cc_api(
2585 wait_for_result=msg.get(ATTR_WAIT_FOR_RESULT,
False),
2587 except BaseZwaveJSServerError
as err:
2588 connection.send_error(msg[ID], err.__class__.__name__,
str(err))
2590 connection.send_result(
2597 @websocket_api.require_admin
2598 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zwave_js/get_integration_settings",
2602 hass: HomeAssistant,
2603 connection: ActiveConnection,
2604 msg: dict[str, Any],
2606 """Get Z-Wave JS integration wide configuration."""
2607 connection.send_result(
2611 CONF_INSTALLER_MODE: hass.data[DOMAIN].
get(CONF_INSTALLER_MODE,
False),
2614
None __init__(self, _AOSmithCoordinatorT coordinator, str junction_id)
web.Response post(self, web.Request request, str config_key)
web.Response get(self, web.Request request, str config_key)
str get_device_id(ServerInfoMessage server_info, MatterEndpoint endpoint)
None websocket_provision_smart_start_node(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_unprovision_smart_start_node(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_node_metadata(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_add_node(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None async_register_api(HomeAssistant hass)
None websocket_remove_node(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_get_provisioning_entries(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_get_log_config(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
dict[str, int] _get_controller_statistics_dict(ControllerStatistics statistics)
None websocket_is_node_firmware_update_in_progress(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
dict[str, int|float] _get_node_firmware_update_progress_dict(NodeFirmwareUpdateProgress progress)
None websocket_grant_security_classes(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_subscribe_node_status(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_subscribe_firmware_update_status(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_get_integration_settings(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_subscribe_controller_statistics(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
dict[str, int|float] _get_controller_firmware_update_progress_dict(ControllerFirmwareUpdateProgress progress)
None websocket_remove_failed_node(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_node_alerts(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_subscribe_rebuild_routes_progress(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_replace_failed_node(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_install_config_update(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_update_data_collection_preference(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_network_status(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_try_parse_dsk_from_qr_code_string(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_set_config_parameter(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
Callable[[HomeAssistant, ActiveConnection, dict[str, Any]], Coroutine[Any, Any, None]] async_get_node(Callable[[HomeAssistant, ActiveConnection, dict[str, Any], Node], Coroutine[Any, Any, None],] orig_func)
Callable[[HomeAssistant, ActiveConnection, dict[str, Any]], Coroutine[Any, Any, None]] async_get_entry(Callable[[HomeAssistant, ActiveConnection, dict[str, Any], ConfigEntry, Client, Driver], Coroutine[Any, Any, None],] orig_func)
None websocket_update_log_config(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_check_for_config_updates(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_supports_feature(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_refresh_node_info(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_subscribe_node_statistics(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_node_capabilities(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_stop_inclusion(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_refresh_node_cc_values(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
dict filename_is_present_if_logging_to_file(dict obj)
None websocket_get_node_firmware_update_capabilities(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_rebuild_node_routes(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_abort_firmware_update(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_get_raw_config_parameter(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_data_collection_status(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_get_config_parameters(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
tuple[ConfigEntry, Client, Driver]|tuple[None, None, None] _async_get_entry(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, str entry_id)
None websocket_set_raw_config_parameter(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_stop_rebuilding_routes(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
Node|None _async_get_node(HomeAssistant hass, ActiveConnection connection, dict msg, str device_id)
None websocket_hard_reset_controller(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_node_status(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
dict[str, Any] node_status(Node node)
None websocket_invoke_cc_api(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_parse_qr_code_string(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_stop_exclusion(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_begin_rebuilding_routes(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_validate_dsk_and_enter_pin(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None websocket_refresh_node_values(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, Node node)
None websocket_is_any_ota_firmware_update_in_progress(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
dict[str, Any] _get_node_statistics_dict(HomeAssistant hass, NodeStatistics statistics)
None websocket_subscribe_log_updates(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg, ConfigEntry entry, Client client, Driver driver)
None async_enable_statistics(Driver driver)
ZwaveNode async_get_node_from_device_id(HomeAssistant hass, str device_id, dr.DeviceRegistry|None dev_reg=None)
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)
None async_cleanup(HomeAssistant hass, DeviceRegistry dev_reg, entity_registry.EntityRegistry ent_reg)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)