1 """Provide the device conditions for Z-Wave JS."""
3 from __future__
import annotations
5 from typing
import cast
7 import voluptuous
as vol
8 from zwave_js_server.const
import CommandClass
9 from zwave_js_server.model.value
import ConfigurationValue
18 from .config_validation
import VALUE_SCHEMA
27 from .device_automation_helpers
import (
31 async_bypass_dynamic_config_validation,
32 generate_config_parameter_subtype,
34 from .helpers
import (
35 async_get_node_from_device_id,
36 check_type_schema_map,
37 get_value_state_schema,
38 get_zwave_value_from_config,
39 remove_keys_with_empty_values,
42 CONF_STATUS =
"status"
44 NODE_STATUS_TYPE =
"node_status"
45 CONFIG_PARAMETER_TYPE =
"config_parameter"
47 CONDITION_TYPES = {NODE_STATUS_TYPE, CONFIG_PARAMETER_TYPE, VALUE_TYPE}
49 NODE_STATUS_CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend(
51 vol.Required(CONF_TYPE): NODE_STATUS_TYPE,
52 vol.Required(CONF_STATUS): vol.In(NODE_STATUSES),
56 CONFIG_PARAMETER_CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend(
58 vol.Required(CONF_TYPE): CONFIG_PARAMETER_TYPE,
59 vol.Required(CONF_VALUE_ID): cv.string,
60 vol.Required(CONF_SUBTYPE): cv.string,
61 vol.Optional(ATTR_VALUE): vol.Coerce(int),
65 VALUE_CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend(
67 vol.Required(CONF_TYPE): VALUE_TYPE,
68 vol.Required(ATTR_COMMAND_CLASS): vol.In([cc.value
for cc
in CommandClass]),
69 vol.Required(ATTR_PROPERTY): vol.Any(vol.Coerce(int), cv.string),
70 vol.Optional(ATTR_PROPERTY_KEY): vol.Any(vol.Coerce(int), cv.string),
71 vol.Optional(ATTR_ENDPOINT): vol.Coerce(int),
72 vol.Required(ATTR_VALUE): VALUE_SCHEMA,
77 NODE_STATUS_TYPE: NODE_STATUS_CONDITION_SCHEMA,
78 CONFIG_PARAMETER_TYPE: CONFIG_PARAMETER_CONDITION_SCHEMA,
79 VALUE_TYPE: VALUE_CONDITION_SCHEMA,
83 CONDITION_TYPE_SCHEMA = vol.Schema(
84 {vol.Required(CONF_TYPE): vol.In(TYPE_SCHEMA_MAP)}, extra=vol.ALLOW_EXTRA
87 CONDITION_SCHEMA = vol.All(
88 remove_keys_with_empty_values,
89 CONDITION_TYPE_SCHEMA,
95 hass: HomeAssistant, config: ConfigType
97 """Validate config."""
104 hass, config[CONF_DEVICE_ID]
106 except ValueError
as err:
108 f
"Device {config[CONF_DEVICE_ID]} not found"
111 if bypass_dynamic_config_validation:
114 if config[CONF_TYPE] == VALUE_TYPE:
118 except vol.Invalid
as err:
125 hass: HomeAssistant, device_id: str
126 ) -> list[dict[str, str]]:
127 """List device conditions for Z-Wave JS devices."""
128 conditions: list[dict] = []
130 CONF_CONDITION:
"device",
131 CONF_DEVICE_ID: device_id,
136 if node.client.driver
and node.client.driver.controller.own_node == node:
140 conditions.append({**base_condition, CONF_TYPE: VALUE_TYPE})
143 conditions.append({**base_condition, CONF_TYPE: NODE_STATUS_TYPE})
150 CONF_VALUE_ID: config_value.value_id,
151 CONF_TYPE: CONFIG_PARAMETER_TYPE,
154 for config_value
in node.get_configuration_values().values()
163 hass: HomeAssistant, config: ConfigType
164 ) -> condition.ConditionCheckerType:
165 """Create a function to test a device condition."""
166 condition_type = config[CONF_TYPE]
167 device_id = config[CONF_DEVICE_ID]
170 def test_node_status(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
171 """Test if node status is a certain state."""
173 return bool(node.status.name.lower() == config[CONF_STATUS])
175 if condition_type == NODE_STATUS_TYPE:
176 return test_node_status
179 def test_config_parameter(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
180 """Test if config parameter is a certain state."""
182 config_value = cast(ConfigurationValue, node.values[config[CONF_VALUE_ID]])
183 return bool(config_value.value == config[ATTR_VALUE])
185 if condition_type == CONFIG_PARAMETER_TYPE:
186 return test_config_parameter
189 def test_value(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
190 """Test if value is a certain state."""
193 return bool(value.value == config[ATTR_VALUE])
195 if condition_type == VALUE_TYPE:
202 hass: HomeAssistant, config: ConfigType
203 ) -> dict[str, vol.Schema]:
204 """List condition capabilities."""
205 device_id = config[CONF_DEVICE_ID]
209 if config[CONF_TYPE] == CONFIG_PARAMETER_TYPE:
210 value_id = config[CONF_VALUE_ID]
212 if value_schema
is None:
214 return {
"extra_fields": vol.Schema({vol.Required(ATTR_VALUE): value_schema})}
216 if config[CONF_TYPE] == VALUE_TYPE:
220 "extra_fields": vol.Schema(
222 vol.Required(ATTR_COMMAND_CLASS): vol.In(
224 CommandClass(cc.id).value: cc.name
226 node.command_classes, key=
lambda cc: cc.name
228 if cc.id != CommandClass.CONFIGURATION
231 vol.Required(ATTR_PROPERTY): cv.string,
232 vol.Optional(ATTR_PROPERTY_KEY): cv.string,
233 vol.Optional(ATTR_ENDPOINT): cv.string,
234 vol.Required(ATTR_VALUE): cv.string,
239 if config[CONF_TYPE] == NODE_STATUS_TYPE:
241 "extra_fields": vol.Schema(
242 {vol.Required(CONF_STATUS): vol.In(NODE_STATUSES)}
str generate_config_parameter_subtype(ConfigurationValue config_value)
bool async_bypass_dynamic_config_validation(HomeAssistant hass, str device_id)
ConfigType async_validate_condition_config(HomeAssistant hass, ConfigType config)
condition.ConditionCheckerType async_condition_from_config(HomeAssistant hass, ConfigType config)
dict[str, vol.Schema] async_get_condition_capabilities(HomeAssistant hass, ConfigType config)
list[dict[str, str]] async_get_conditions(HomeAssistant hass, str device_id)
Callable[[ConfigType], ConfigType] check_type_schema_map(dict[str, vol.Schema] schema_map)
VolSchemaType|vol.Coerce|vol.In|None get_value_state_schema(ZwaveValue value)
ZwaveValue get_zwave_value_from_config(ZwaveNode node, ConfigType config)
ZwaveNode async_get_node_from_device_id(HomeAssistant hass, str device_id, dr.DeviceRegistry|None dev_reg=None)