1 """Offer Z-Wave JS value updated listening automation trigger."""
3 from __future__
import annotations
5 from collections.abc
import Callable
8 import voluptuous
as vol
9 from zwave_js_server.const
import CommandClass
10 from zwave_js_server.model.driver
import Driver
11 from zwave_js_server.model.value
import Value, get_value_id_str
20 from ..config_validation
import VALUE_SCHEMA
23 ATTR_COMMAND_CLASS_NAME,
25 ATTR_CURRENT_VALUE_RAW,
29 ATTR_PREVIOUS_VALUE_RAW,
32 ATTR_PROPERTY_KEY_NAME,
37 from ..helpers
import async_get_nodes_from_targets, get_device_id
38 from .trigger_helpers
import async_bypass_dynamic_config_validation
41 PLATFORM_TYPE = f
"{DOMAIN}.{__name__.rsplit('.', maxsplit=1)[-1]}"
46 TRIGGER_SCHEMA = vol.All(
47 cv.TRIGGER_BASE_SCHEMA.extend(
49 vol.Required(CONF_PLATFORM): PLATFORM_TYPE,
50 vol.Optional(ATTR_DEVICE_ID): vol.All(cv.ensure_list, [cv.string]),
51 vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
52 vol.Required(ATTR_COMMAND_CLASS): vol.In(
53 {cc.value: cc.name
for cc
in CommandClass}
55 vol.Required(ATTR_PROPERTY): vol.Any(vol.Coerce(int), cv.string),
56 vol.Optional(ATTR_ENDPOINT): vol.Coerce(int),
57 vol.Optional(ATTR_PROPERTY_KEY): vol.Any(vol.Coerce(int), cv.string),
58 vol.Optional(ATTR_FROM, default=MATCH_ALL): vol.Any(
59 VALUE_SCHEMA, [VALUE_SCHEMA]
61 vol.Optional(ATTR_TO, default=MATCH_ALL): vol.Any(
62 VALUE_SCHEMA, [VALUE_SCHEMA]
66 cv.has_at_least_one_key(ATTR_ENTITY_ID, ATTR_DEVICE_ID),
71 hass: HomeAssistant, config: ConfigType
73 """Validate config."""
81 f
"No nodes found for given {ATTR_DEVICE_ID}s or {ATTR_ENTITY_ID}s."
89 action: TriggerActionType,
90 trigger_info: TriggerInfo,
92 platform_type: str = PLATFORM_TYPE,
94 """Listen for state changes based on configuration."""
95 dev_reg = dr.async_get(hass)
98 f
"No nodes found for given {ATTR_DEVICE_ID}s or {ATTR_ENTITY_ID}s."
101 from_value = config[ATTR_FROM]
102 to_value = config[ATTR_TO]
103 command_class = config[ATTR_COMMAND_CLASS]
104 property_ = config[ATTR_PROPERTY]
105 endpoint = config.get(ATTR_ENDPOINT)
106 property_key = config.get(ATTR_PROPERTY_KEY)
107 unsubs: list[Callable] = []
110 trigger_data = trigger_info[
"trigger_data"]
113 def async_on_value_updated(
114 value: Value, device: dr.DeviceEntry, event: dict
116 """Handle value update."""
117 event_value: Value = event[
"value"]
118 if event_value != value:
122 prev_value_raw = event[
"args"][
"prevValue"]
123 prev_value = value.metadata.states.get(
str(prev_value_raw), prev_value_raw)
125 curr_value_raw = event[
"args"][
"newValue"]
126 curr_value = value.metadata.states.get(
str(curr_value_raw), curr_value_raw)
128 for value_to_eval, raw_value_to_eval, match
in (
129 (prev_value, prev_value_raw, from_value),
130 (curr_value, curr_value_raw, to_value),
132 if match
not in (MATCH_ALL, value_to_eval, raw_value_to_eval)
and not (
133 isinstance(match, list)
134 and (value_to_eval
in match
or raw_value_to_eval
in match)
138 device_name = device.name_by_user
or device.name
142 CONF_PLATFORM: platform_type,
143 ATTR_DEVICE_ID: device.id,
144 ATTR_NODE_ID: value.node.node_id,
145 ATTR_COMMAND_CLASS: value.command_class,
146 ATTR_COMMAND_CLASS_NAME: value.command_class_name,
147 ATTR_PROPERTY: value.property_,
148 ATTR_PROPERTY_NAME: value.property_name,
149 ATTR_ENDPOINT: endpoint,
150 ATTR_PROPERTY_KEY: value.property_key,
151 ATTR_PROPERTY_KEY_NAME: value.property_key_name,
152 ATTR_PREVIOUS_VALUE: prev_value,
153 ATTR_PREVIOUS_VALUE_RAW: prev_value_raw,
154 ATTR_CURRENT_VALUE: curr_value,
155 ATTR_CURRENT_VALUE_RAW: curr_value_raw,
156 "description": f
"Z-Wave value {value.value_id} updated on {device_name}",
159 hass.async_run_hass_job(job, {
"trigger": payload})
163 """Remove state listeners async."""
168 def _create_zwave_listeners() -> None:
169 """Create Z-Wave JS listeners."""
173 drivers: set[Driver] = set()
175 driver = node.client.driver
176 assert driver
is not None
179 device = dev_reg.async_get_device(identifiers={device_identifier})
181 value_id = get_value_id_str(
182 node, command_class, property_, endpoint, property_key
184 value = node.values[value_id]
189 functools.partial(async_on_value_updated, value, device),
196 f
"{DOMAIN}_{driver.controller.home_id}_connected_to_server",
197 _create_zwave_listeners,
199 for driver
in drivers
202 _create_zwave_listeners()
str get_device_id(ServerInfoMessage server_info, MatterEndpoint endpoint)
bool async_bypass_dynamic_config_validation(HomeAssistant hass, str device_id)
set[ZwaveNode] async_get_nodes_from_targets(HomeAssistant hass, dict[str, Any] val, er.EntityRegistry|None ent_reg=None, dr.DeviceRegistry|None dev_reg=None, logging.Logger logger=LOGGER)
CALLBACK_TYPE async_attach_trigger(HomeAssistant hass, ConfigType config, TriggerActionType action, TriggerInfo trigger_info, *str platform_type=PLATFORM_TYPE)
ConfigType async_validate_trigger_config(HomeAssistant hass, ConfigType config)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
None async_remove(HomeAssistant hass, str intent_type)