1 """The Z-Wave JS integration."""
3 from __future__
import annotations
6 from collections
import defaultdict
7 from contextlib
import suppress
11 from awesomeversion
import AwesomeVersion
12 import voluptuous
as vol
13 from zwave_js_server.client
import Client
as ZwaveClient
14 from zwave_js_server.const
import CommandClass, RemoveNodeReason
15 from zwave_js_server.exceptions
import BaseZwaveJSServerError, InvalidServerVersion
16 from zwave_js_server.model.driver
import Driver
17 from zwave_js_server.model.node
import Node
as ZwaveNode
18 from zwave_js_server.model.notification
import (
19 EntryControlNotification,
20 MultilevelSwitchNotification,
21 NotificationNotification,
22 PowerLevelNotification,
24 from zwave_js_server.model.value
import Value, ValueNotification
34 EVENT_HOMEASSISTANT_STOP,
35 EVENT_LOGGING_CHANGED,
41 config_validation
as cv,
42 device_registry
as dr,
43 entity_registry
as er,
54 from .addon
import get_addon_manager
55 from .api
import async_register_api
57 ATTR_ACKNOWLEDGED_FRAMES,
59 ATTR_COMMAND_CLASS_NAME,
68 ATTR_EVENT_TYPE_LABEL,
75 ATTR_PROPERTY_KEY_NAME,
83 CONF_ADDON_LR_S2_ACCESS_CONTROL_KEY,
84 CONF_ADDON_LR_S2_AUTHENTICATED_KEY,
85 CONF_ADDON_NETWORK_KEY,
86 CONF_ADDON_S0_LEGACY_KEY,
87 CONF_ADDON_S2_ACCESS_CONTROL_KEY,
88 CONF_ADDON_S2_AUTHENTICATED_KEY,
89 CONF_ADDON_S2_UNAUTHENTICATED_KEY,
90 CONF_DATA_COLLECTION_OPTED_IN,
92 CONF_INTEGRATION_CREATED_ADDON,
93 CONF_LR_S2_ACCESS_CONTROL_KEY,
94 CONF_LR_S2_AUTHENTICATED_KEY,
97 CONF_S2_ACCESS_CONTROL_KEY,
98 CONF_S2_AUTHENTICATED_KEY,
99 CONF_S2_UNAUTHENTICATED_KEY,
104 EVENT_DEVICE_ADDED_TO_REGISTRY,
110 ZWAVE_JS_NOTIFICATION_EVENT,
111 ZWAVE_JS_VALUE_NOTIFICATION_EVENT,
112 ZWAVE_JS_VALUE_UPDATED_EVENT,
114 from .discovery
import (
116 async_discover_node_values,
117 async_discover_single_value,
119 from .helpers
import (
120 async_disable_server_logging_if_needed,
121 async_enable_server_logging_if_needed,
122 async_enable_statistics,
125 get_network_identifier_for_notification,
127 get_valueless_base_unique_id,
129 from .migrate
import async_migrate_discovered_value
130 from .services
import ZWaveServices
133 DATA_CLIENT_LISTEN_TASK =
"client_listen_task"
134 DATA_DRIVER_EVENTS =
"driver_events"
135 DATA_START_CLIENT_TASK =
"start_client_task"
137 CONFIG_SCHEMA = vol.Schema(
141 vol.Optional(CONF_INSTALLER_MODE, default=
False): cv.boolean,
145 extra=vol.ALLOW_EXTRA,
149 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
150 """Set up the Z-Wave JS component."""
151 hass.data[DOMAIN] = config.get(DOMAIN, {})
152 for entry
in hass.config_entries.async_entries(DOMAIN):
153 if not isinstance(entry.unique_id, str):
154 hass.config_entries.async_update_entry(
155 entry, unique_id=
str(entry.unique_id)
158 dev_reg = dr.async_get(hass)
159 ent_reg = er.async_get(hass)
161 services.async_register()
167 """Set up Z-Wave JS from a config entry."""
168 if use_addon := entry.data.get(CONF_USE_ADDON):
171 client = ZwaveClient(
172 entry.data[CONF_URL],
174 additional_user_agent_components=USER_AGENT,
179 async
with asyncio.timeout(CONNECT_TIMEOUT):
180 await client.connect()
181 except InvalidServerVersion
as err:
184 addon_manager.async_schedule_update_addon(catch_error=
True)
189 "invalid_server_version",
191 severity=IssueSeverity.ERROR,
192 translation_key=
"invalid_server_version",
195 except (TimeoutError, BaseZwaveJSServerError)
as err:
199 LOGGER.info(
"Connected to Zwave JS Server")
203 entry.runtime_data = {}
207 start_client_task = hass.async_create_task(
start_client(hass, entry, client))
208 entry.runtime_data[DATA_START_CLIENT_TASK] = start_client_task
214 hass: HomeAssistant, entry: ConfigEntry, client: ZwaveClient
216 """Start listening with the client."""
217 entry.runtime_data[DATA_CLIENT] = client
218 driver_events = entry.runtime_data[DATA_DRIVER_EVENTS] =
DriverEvents(hass, entry)
220 async
def handle_ha_shutdown(event: Event) ->
None:
221 """Handle HA shutdown."""
224 listen_task = asyncio.create_task(
227 entry.runtime_data[DATA_CLIENT_LISTEN_TASK] = listen_task
228 entry.async_on_unload(
229 hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, handle_ha_shutdown)
233 await driver_events.ready.wait()
234 except asyncio.CancelledError:
235 LOGGER.debug(
"Cancelling start client")
238 LOGGER.info(
"Connection to Zwave JS Server initialized")
242 hass, f
"{DOMAIN}_{client.driver.controller.home_id}_connected_to_server"
245 await driver_events.setup(client.driver)
249 """Represent driver events."""
253 def __init__(self, hass: HomeAssistant, entry: ConfigEntry) ->
None:
254 """Set up the driver events instance."""
258 self.platform_setup_tasks: dict[str, asyncio.Task] = {}
263 async
def setup(self, driver: Driver) ->
None:
264 """Set up devices using the ready driver."""
266 controller = driver.controller
270 if opted_in := self.
config_entryconfig_entry.data.get(CONF_DATA_COLLECTION_OPTED_IN):
272 elif opted_in
is False:
273 await driver.async_disable_statistics()
275 async
def handle_logging_changed(_: Event |
None =
None) ->
None:
276 """Handle logging changed event."""
277 if LIB_LOGGER.isEnabledFor(logging.DEBUG):
287 await handle_logging_changed()
290 self.
hasshass.bus.async_listen(EVENT_LOGGING_CHANGED, handle_logging_changed)
294 stored_devices = dr.async_entries_for_config_entry(
299 for node
in controller.nodes.values()
304 for device
in stored_devices:
305 if device
not in known_devices:
306 self.
dev_regdev_reg.async_remove_device(device.id)
309 if controller.own_node:
310 await self.
controller_eventscontroller_events.async_on_node_added(controller.own_node)
313 await asyncio.gather(
316 for node
in controller.nodes.values()
317 if node != controller.own_node
325 lambda event: self.
hasshass.async_create_task(
334 controller.on(
"node removed", self.
controller_eventscontroller_events.async_on_node_removed)
339 controller.on(
"identify", self.
controller_eventscontroller_events.async_on_identify)
343 """Set up platform if needed."""
344 if platform
not in self.platform_setup_tasks:
345 self.platform_setup_tasks[platform] = self.
hasshass.async_create_task(
346 self.
hasshass.config_entries.async_forward_entry_setups(
350 await self.platform_setup_tasks[platform]
354 """Represent controller events.
356 Handle the following events:
361 def __init__(self, hass: HomeAssistant, driver_events: DriverEvents) ->
None:
362 """Set up the controller events instance."""
365 self.discovered_value_ids: dict[str, set[str]] = defaultdict(set)
368 self.registered_unique_ids: dict[str, dict[Platform, set[str]]] = defaultdict(
369 lambda: defaultdict(set)
375 """Remove device from registry."""
377 self.
dev_regdev_reg.async_remove_device(device.id)
378 self.registered_unique_ids.pop(device.id,
None)
379 self.discovered_value_ids.pop(device.id,
None)
382 """Handle node added event."""
394 f
"{DOMAIN}_{base_unique_id}_remove_entity_on_interview_started",
399 if node.is_controller_node:
403 f
"{DOMAIN}_{self.config_entry.entry_id}_add_controller_status_sensor",
409 f
"{DOMAIN}_{self.config_entry.entry_id}_add_node_status_sensor",
417 f
"{DOMAIN}_{self.config_entry.entry_id}_add_ping_button_entity",
424 f
"{DOMAIN}_{self.config_entry.entry_id}_add_statistics_sensors",
428 LOGGER.debug(
"Node added: %s", node.node_id)
434 lambda event: self.
hasshass.async_create_task(
435 self.
node_eventsnode_events.async_on_node_ready(event[
"node"]),
444 await self.
node_eventsnode_events.async_on_node_ready(node)
453 """Handle node removed event."""
454 node: ZwaveNode = event[
"node"]
455 reason: RemoveNodeReason = event[
"reason"]
458 device = self.
dev_regdev_reg.async_get_device(identifiers={dev_id})
461 if reason
in (RemoveNodeReason.REPLACED, RemoveNodeReason.PROXY_REPLACED):
462 self.discovered_value_ids.pop(device.id,
None)
468 f
"{get_valueless_base_unique_id(self.driver_events.driver, node)}_"
475 if reason == RemoveNodeReason.RESET:
476 device_name = device.name_by_user
or device.name
or f
"Node {node.node_id}"
481 f
"`{device_name}` has been factory reset "
482 "and removed from the Z-Wave network"
486 if identifier[-1] ==
",":
487 identifier = identifier[:-1]
488 notification_msg = f
"{notification_msg} {identifier}."
490 notification_msg = f
"{notification_msg}."
494 "Device Was Factory Reset!",
495 f
"{DOMAIN}.node_reset_and_removed.{dev_id[1]}",
502 """Handle identify event."""
504 node: ZwaveNode = event[
"node"]
506 device = self.
dev_regdev_reg.async_get_device(identifiers={dev_id})
508 device_name = device.name_by_user
or device.name
or f
"Node {node.node_id}"
517 f
"`{device_name}` has just requested the controller for your Z-Wave "
518 f
"network {identifier} to identify itself. No action is needed from "
519 "you other than to note the source of the request, and you can safely "
520 "dismiss this notification when ready."
522 "New Z-Wave Identify Controller Request",
523 f
"{DOMAIN}.identify_controller.{dev_id[1]}",
528 """Register node in dev reg."""
532 node_id_device = self.
dev_regdev_reg.async_get_device(identifiers={device_id})
534 controller = driver.controller
536 if controller.own_node
and controller.own_node != node:
551 and len(node_id_device.identifiers) == 2
552 and device_id_ext
not in node_id_device.identifiers
554 new_identifiers = node_id_device.identifiers.copy()
555 new_identifiers.remove(device_id)
557 node_id_device.id, new_identifiers=new_identifiers
563 hardware_device := self.
dev_regdev_reg.async_get_device(
564 identifiers={device_id_ext}
566 )
and len(hardware_device.identifiers) == 1:
567 new_identifiers = hardware_device.identifiers.copy()
568 new_identifiers.add(device_id)
570 hardware_device.id, new_identifiers=new_identifiers
572 ids = {device_id, device_id_ext}
576 device = self.
dev_regdev_reg.async_get_or_create(
579 sw_version=node.firmware_version,
580 name=node.name
or node.device_config.description
or f
"Node {node.node_id}",
581 model=node.device_config.label,
582 manufacturer=node.device_config.manufacturer,
583 suggested_area=node.location
if node.location
else UNDEFINED,
584 via_device=via_device_id,
593 """Represent node events.
595 Handle the following events:
605 self, hass: HomeAssistant, controller_events: ControllerEvents
607 """Set up the node events instance."""
610 self.
dev_regdev_reg = controller_events.dev_reg
615 """Handle node ready event."""
616 LOGGER.debug(
"Processing node %s", node)
621 self.
controller_eventscontroller_events.discovered_value_ids.pop(device.id,
None)
623 value_updates_disc_info: dict[str, ZwaveDiscoveryInfo] = {}
626 await asyncio.gather(
629 device, disc_info, value_updates_disc_info
631 for disc_info
in async_discover_node_values(
638 for event
in (
"value added", EVENT_VALUE_UPDATED,
"metadata updated"):
642 lambda event: self.
hasshass.async_create_task(
644 value_updates_disc_info, event[
"value"]
653 "value notification",
655 event[
"value_notification"]
667 if not node.is_controller_node
and any(
668 cc.id == CommandClass.FIRMWARE_UPDATE_MD.value
669 for cc
in node.command_classes
671 await self.
controller_eventscontroller_events.driver_events.async_setup_platform(
676 f
"{DOMAIN}_{self.config_entry.entry_id}_add_firmware_update_entity",
683 if not node.is_controller_node
and await node.async_has_device_config_changed():
684 device_name = device.name_by_user
or device.name
or "Unnamed device"
688 f
"device_config_file_changed.{device.id}",
689 data={
"device_id": device.id,
"device_name": device_name},
692 translation_key=
"device_config_file_changed",
693 translation_placeholders={
"device_name": device_name},
694 severity=IssueSeverity.WARNING,
699 device: dr.DeviceEntry,
700 disc_info: ZwaveDiscoveryInfo,
701 value_updates_disc_info: dict[str, ZwaveDiscoveryInfo],
703 """Handle discovery info and all dependent tasks."""
710 self.
controller_eventscontroller_events.registered_unique_ids[device.id][disc_info.platform],
716 platform = disc_info.platform
717 await self.
controller_eventscontroller_events.driver_events.async_setup_platform(platform)
719 LOGGER.debug(
"Discovered entity: %s", disc_info)
722 f
"{DOMAIN}_{self.config_entry.entry_id}_add_{platform}",
727 if not disc_info.assumed_state:
729 value_updates_disc_info[disc_info.primary_value.value_id] = disc_info
732 if len(value_updates_disc_info) != 1:
739 value_updates_disc_info, event[
"value"]
745 self, value_updates_disc_info: dict[str, ZwaveDiscoveryInfo], value: Value
747 """Fire value updated event."""
756 or not (device := self.
dev_regdev_reg.async_get_device(identifiers={device_id}))
757 or value.value_id
in self.
controller_eventscontroller_events.discovered_value_ids[device.id]
761 LOGGER.debug(
"Processing node %s added value %s", value.node, value)
762 await asyncio.gather(
765 device, disc_info, value_updates_disc_info
767 for disc_info
in async_discover_single_value(
775 """Relay stateless value notification events from Z-Wave nodes to hass."""
777 device = self.
dev_regdev_reg.async_get_device(
782 raw_value = value = notification.value
783 if notification.metadata.states:
784 value = notification.metadata.states.get(
str(value), value)
785 self.
hasshass.bus.async_fire(
786 ZWAVE_JS_VALUE_NOTIFICATION_EVENT,
789 ATTR_NODE_ID: notification.node.node_id,
790 ATTR_HOME_ID: driver.controller.home_id,
791 ATTR_ENDPOINT: notification.endpoint,
792 ATTR_DEVICE_ID: device.id,
793 ATTR_COMMAND_CLASS: notification.command_class,
794 ATTR_COMMAND_CLASS_NAME: notification.command_class_name,
795 ATTR_LABEL: notification.metadata.label,
796 ATTR_PROPERTY: notification.property_,
797 ATTR_PROPERTY_NAME: notification.property_name,
798 ATTR_PROPERTY_KEY: notification.property_key,
799 ATTR_PROPERTY_KEY_NAME: notification.property_key_name,
801 ATTR_VALUE_RAW: raw_value,
807 """Relay stateless notification events from Z-Wave nodes to hass."""
808 if "notification" not in event:
809 LOGGER.info(
"Unknown notification: %s", event)
814 EntryControlNotification
815 | NotificationNotification
816 | PowerLevelNotification
817 | MultilevelSwitchNotification
818 ) = event[
"notification"]
819 device = self.
dev_regdev_reg.async_get_device(
826 ATTR_NODE_ID: notification.node.node_id,
827 ATTR_HOME_ID: driver.controller.home_id,
828 ATTR_ENDPOINT: notification.endpoint_idx,
829 ATTR_DEVICE_ID: device.id,
830 ATTR_COMMAND_CLASS: notification.command_class,
833 if isinstance(notification, EntryControlNotification):
836 ATTR_COMMAND_CLASS_NAME:
"Entry Control",
837 ATTR_EVENT_TYPE: notification.event_type,
838 ATTR_EVENT_TYPE_LABEL: notification.event_type_label,
839 ATTR_DATA_TYPE: notification.data_type,
840 ATTR_DATA_TYPE_LABEL: notification.data_type_label,
841 ATTR_EVENT_DATA: notification.event_data,
844 elif isinstance(notification, NotificationNotification):
847 ATTR_COMMAND_CLASS_NAME:
"Notification",
848 ATTR_LABEL: notification.label,
849 ATTR_TYPE: notification.type_,
850 ATTR_EVENT: notification.event,
851 ATTR_EVENT_LABEL: notification.event_label,
852 ATTR_PARAMETERS: notification.parameters,
855 elif isinstance(notification, PowerLevelNotification):
858 ATTR_COMMAND_CLASS_NAME:
"Powerlevel",
859 ATTR_TEST_NODE_ID: notification.test_node_id,
860 ATTR_STATUS: notification.status,
861 ATTR_ACKNOWLEDGED_FRAMES: notification.acknowledged_frames,
864 elif isinstance(notification, MultilevelSwitchNotification):
867 ATTR_COMMAND_CLASS_NAME:
"Multilevel Switch",
868 ATTR_EVENT_TYPE: notification.event_type,
869 ATTR_EVENT_TYPE_LABEL: notification.event_type_label,
870 ATTR_DIRECTION: notification.direction,
874 raise TypeError(f
"Unhandled notification type: {notification}")
876 self.
hasshass.bus.async_fire(ZWAVE_JS_NOTIFICATION_EVENT, event_data)
880 self, value_updates_disc_info: dict[str, ZwaveDiscoveryInfo], value: Value
882 """Fire value updated event."""
885 if value.value_id
not in value_updates_disc_info:
889 disc_info = value_updates_disc_info[value.value_id]
891 device = self.
dev_regdev_reg.async_get_device(
897 unique_id =
get_unique_id(driver, disc_info.primary_value.value_id)
898 entity_id = self.
ent_regent_reg.async_get_entity_id(
899 disc_info.platform, DOMAIN, unique_id
902 raw_value = value_ = value.value
903 if value.metadata.states:
904 value_ = value.metadata.states.get(
str(value_), value_)
906 self.
hasshass.bus.async_fire(
907 ZWAVE_JS_VALUE_UPDATED_EVENT,
909 ATTR_NODE_ID: value.node.node_id,
910 ATTR_HOME_ID: driver.controller.home_id,
911 ATTR_DEVICE_ID: device.id,
912 ATTR_ENTITY_ID: entity_id,
913 ATTR_COMMAND_CLASS: value.command_class,
914 ATTR_COMMAND_CLASS_NAME: value.command_class_name,
915 ATTR_ENDPOINT: value.endpoint,
916 ATTR_PROPERTY: value.property_,
917 ATTR_PROPERTY_NAME: value.property_name,
918 ATTR_PROPERTY_KEY: value.property_key,
919 ATTR_PROPERTY_KEY_NAME: value.property_key_name,
921 ATTR_VALUE_RAW: raw_value,
930 driver_ready: asyncio.Event,
932 """Listen with the client."""
935 await client.listen(driver_ready)
936 except asyncio.CancelledError:
937 should_reload =
False
938 except BaseZwaveJSServerError
as err:
939 LOGGER.error(
"Failed to listen: %s", err)
940 except Exception
as err:
942 LOGGER.exception(
"Unexpected exception: %s", err)
948 LOGGER.info(
"Disconnected from server. Reloading integration")
949 hass.async_create_task(hass.config_entries.async_reload(entry.entry_id))
953 """Disconnect client."""
954 client: ZwaveClient = entry.runtime_data[DATA_CLIENT]
955 listen_task: asyncio.Task = entry.runtime_data[DATA_CLIENT_LISTEN_TASK]
956 start_client_task: asyncio.Task = entry.runtime_data[DATA_START_CLIENT_TASK]
957 driver_events: DriverEvents = entry.runtime_data[DATA_DRIVER_EVENTS]
959 start_client_task.cancel()
960 platform_setup_tasks = driver_events.platform_setup_tasks.values()
961 for task
in platform_setup_tasks:
964 tasks = (listen_task, start_client_task, *platform_setup_tasks)
965 await asyncio.gather(*tasks, return_exceptions=
True)
967 with suppress(asyncio.CancelledError):
971 await client.disconnect()
972 LOGGER.info(
"Disconnected from Zwave JS Server")
976 """Unload a config entry."""
977 client: ZwaveClient = entry.runtime_data[DATA_CLIENT]
978 driver_events: DriverEvents = entry.runtime_data[DATA_DRIVER_EVENTS]
981 for platform, task
in driver_events.platform_setup_tasks.items()
984 unload_ok = await hass.config_entries.async_unload_platforms(entry, platforms)
986 if client.connected
and client.driver:
988 if DATA_CLIENT_LISTEN_TASK
in entry.runtime_data:
991 if entry.data.get(CONF_USE_ADDON)
and entry.disabled_by:
993 LOGGER.debug(
"Stopping Z-Wave JS add-on")
995 await addon_manager.async_stop_addon()
996 except AddonError
as err:
997 LOGGER.error(
"Failed to stop the Z-Wave JS add-on: %s", err)
1004 """Remove a config entry."""
1005 if not entry.data.get(CONF_INTEGRATION_CREATED_ADDON):
1010 await addon_manager.async_stop_addon()
1011 except AddonError
as err:
1015 await addon_manager.async_create_backup()
1016 except AddonError
as err:
1020 await addon_manager.async_uninstall_addon()
1021 except AddonError
as err:
1026 hass: HomeAssistant, config_entry: ConfigEntry, device_entry: dr.DeviceEntry
1028 """Remove a config entry from a device."""
1029 client: ZwaveClient = config_entry.runtime_data[DATA_CLIENT]
1033 if (driver := client.driver)
is None:
1034 LOGGER.error(
"Driver for %s is not ready", config_entry.title)
1042 for node
in driver.controller.nodes.values()
1049 controller_events: ControllerEvents = config_entry.runtime_data[
1052 controller_events.registered_unique_ids.pop(device_entry.id,
None)
1053 controller_events.discovered_value_ids.pop(device_entry.id,
None)
1058 """Ensure that Z-Wave JS add-on is installed and running."""
1061 addon_info = await addon_manager.async_get_addon_info()
1062 except AddonError
as err:
1065 usb_path: str = entry.data[CONF_USB_PATH]
1067 s0_legacy_key: str = entry.data.get(CONF_S0_LEGACY_KEY,
"")
1068 if not s0_legacy_key:
1069 s0_legacy_key = entry.data.get(CONF_NETWORK_KEY,
"")
1070 s2_access_control_key: str = entry.data.get(CONF_S2_ACCESS_CONTROL_KEY,
"")
1071 s2_authenticated_key: str = entry.data.get(CONF_S2_AUTHENTICATED_KEY,
"")
1072 s2_unauthenticated_key: str = entry.data.get(CONF_S2_UNAUTHENTICATED_KEY,
"")
1073 lr_s2_access_control_key: str = entry.data.get(CONF_LR_S2_ACCESS_CONTROL_KEY,
"")
1074 lr_s2_authenticated_key: str = entry.data.get(CONF_LR_S2_AUTHENTICATED_KEY,
"")
1075 addon_state = addon_info.state
1077 CONF_ADDON_DEVICE: usb_path,
1078 CONF_ADDON_S0_LEGACY_KEY: s0_legacy_key,
1079 CONF_ADDON_S2_ACCESS_CONTROL_KEY: s2_access_control_key,
1080 CONF_ADDON_S2_AUTHENTICATED_KEY: s2_authenticated_key,
1081 CONF_ADDON_S2_UNAUTHENTICATED_KEY: s2_unauthenticated_key,
1083 if addon_info.version
and AwesomeVersion(addon_info.version) >= LR_ADDON_VERSION:
1084 addon_config[CONF_ADDON_LR_S2_ACCESS_CONTROL_KEY] = lr_s2_access_control_key
1085 addon_config[CONF_ADDON_LR_S2_AUTHENTICATED_KEY] = lr_s2_authenticated_key
1087 if addon_state == AddonState.NOT_INSTALLED:
1088 addon_manager.async_schedule_install_setup_addon(
1092 raise ConfigEntryNotReady
1094 if addon_state == AddonState.NOT_RUNNING:
1095 addon_manager.async_schedule_setup_addon(
1099 raise ConfigEntryNotReady
1101 addon_options = addon_info.options
1102 addon_device = addon_options[CONF_ADDON_DEVICE]
1104 addon_s0_legacy_key = addon_options.get(CONF_ADDON_S0_LEGACY_KEY,
"")
1105 if not addon_s0_legacy_key:
1106 addon_s0_legacy_key = addon_options.get(CONF_ADDON_NETWORK_KEY,
"")
1107 addon_s2_access_control_key = addon_options.get(
1108 CONF_ADDON_S2_ACCESS_CONTROL_KEY,
""
1110 addon_s2_authenticated_key = addon_options.get(CONF_ADDON_S2_AUTHENTICATED_KEY,
"")
1111 addon_s2_unauthenticated_key = addon_options.get(
1112 CONF_ADDON_S2_UNAUTHENTICATED_KEY,
""
1115 if usb_path != addon_device:
1116 updates[CONF_USB_PATH] = addon_device
1117 if s0_legacy_key != addon_s0_legacy_key:
1118 updates[CONF_S0_LEGACY_KEY] = addon_s0_legacy_key
1119 if s2_access_control_key != addon_s2_access_control_key:
1120 updates[CONF_S2_ACCESS_CONTROL_KEY] = addon_s2_access_control_key
1121 if s2_authenticated_key != addon_s2_authenticated_key:
1122 updates[CONF_S2_AUTHENTICATED_KEY] = addon_s2_authenticated_key
1123 if s2_unauthenticated_key != addon_s2_unauthenticated_key:
1124 updates[CONF_S2_UNAUTHENTICATED_KEY] = addon_s2_unauthenticated_key
1126 if addon_info.version
and AwesomeVersion(addon_info.version) >= AwesomeVersion(
1129 addon_lr_s2_access_control_key = addon_options.get(
1130 CONF_ADDON_LR_S2_ACCESS_CONTROL_KEY,
""
1132 addon_lr_s2_authenticated_key = addon_options.get(
1133 CONF_ADDON_LR_S2_AUTHENTICATED_KEY,
""
1135 if lr_s2_access_control_key != addon_lr_s2_access_control_key:
1136 updates[CONF_LR_S2_ACCESS_CONTROL_KEY] = addon_lr_s2_access_control_key
1137 if lr_s2_authenticated_key != addon_lr_s2_authenticated_key:
1138 updates[CONF_LR_S2_AUTHENTICATED_KEY] = addon_lr_s2_authenticated_key
1141 hass.config_entries.async_update_entry(entry, data={**entry.data, **updates})
1146 """Ensure that Z-Wave JS add-on is updated and running."""
1148 if addon_manager.task_in_progress():
1149 raise ConfigEntryNotReady
1150 return addon_manager
None __init__(self, HomeAssistant hass, DriverEvents driver_events)
None async_on_node_removed(self, dict event)
None remove_device(self, dr.DeviceEntry device)
dr.DeviceEntry register_node_in_dev_reg(self, ZwaveNode node)
None async_on_identify(self, dict event)
None async_on_node_added(self, ZwaveNode node)
None __init__(self, HomeAssistant hass, ConfigEntry entry)
None setup(self, Driver driver)
None async_setup_platform(self, Platform platform)
None async_handle_discovery_info(self, dr.DeviceEntry device, ZwaveDiscoveryInfo disc_info, dict[str, ZwaveDiscoveryInfo] value_updates_disc_info)
None async_on_value_added(self, dict[str, ZwaveDiscoveryInfo] value_updates_disc_info, Value value)
None __init__(self, HomeAssistant hass, ControllerEvents controller_events)
None async_on_node_ready(self, ZwaveNode node)
None async_on_notification(self, dict[str, Any] event)
None async_on_value_updated_fire_event(self, dict[str, ZwaveDiscoveryInfo] value_updates_disc_info, Value value)
None async_on_value_notification(self, ValueNotification notification)
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
None async_update_device(HomeAssistant hass, ConfigEntry entry, str adapter, AdapterDetails details)
AddonManager get_addon_manager(HomeAssistant hass)
None async_register_api(HomeAssistant hass)
None async_create_issue(HomeAssistant hass, str entry_id)
None async_delete_issue(HomeAssistant hass, str entry_id)
None async_create(HomeAssistant hass, str message, str|None title=None, str|None notification_id=None)
DeviceTuple get_device_id(rfxtrxmod.RFXtrxDevice device, int|None data_bits=None)
str get_unique_id(dict[str, Any] data)
tuple[str, str]|None get_device_id_ext(Driver driver, ZwaveNode node)
str get_valueless_base_unique_id(Driver driver, ZwaveNode node)
None async_enable_statistics(Driver driver)
None async_enable_server_logging_if_needed(HomeAssistant hass, ConfigEntry entry, Driver driver)
str get_network_identifier_for_notification(HomeAssistant hass, ConfigEntry config_entry, Controller controller)
None async_disable_server_logging_if_needed(HomeAssistant hass, ConfigEntry entry, Driver driver)
None async_migrate_discovered_value(HomeAssistant hass, er.EntityRegistry ent_reg, set[str] registered_unique_ids, dr.DeviceEntry device, Driver driver, ZwaveDiscoveryInfo disc_info)
None async_ensure_addon_running(HomeAssistant hass, ConfigEntry entry)
None client_listen(HomeAssistant hass, ConfigEntry entry, ZwaveClient client, asyncio.Event driver_ready)
bool async_remove_config_entry_device(HomeAssistant hass, ConfigEntry config_entry, dr.DeviceEntry device_entry)
None async_remove_entry(HomeAssistant hass, ConfigEntry entry)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
None start_client(HomeAssistant hass, ConfigEntry entry, ZwaveClient client)
bool async_setup(HomeAssistant hass, ConfigType config)
AddonManager _get_addon_manager(HomeAssistant hass)
None disconnect_client(HomeAssistant hass, ConfigEntry entry)
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_dispatcher_send(HomeAssistant hass, str signal, *Any args)