1 """Helper functions for mysensors package."""
3 from __future__
import annotations
5 from collections
import defaultdict
6 from collections.abc
import Callable
7 from enum
import IntEnum
9 from typing
import cast
11 from mysensors
import BaseAsyncGateway, Message
12 from mysensors.sensor
import ChildSensor
13 import voluptuous
as vol
27 MYSENSORS_DISCOVERED_NODES,
29 MYSENSORS_NODE_DISCOVERY,
38 _LOGGER = logging.getLogger(__name__)
40 tuple[str, str], Callable[[BaseAsyncGateway, ChildSensor, ValueType], vol.Schema]
45 def on_unload(hass: HomeAssistant, gateway_id: GatewayId, fnct: Callable) ->
None:
46 """Register a callback to be called when entry is unloaded.
48 This function is used by platforms to cleanup after themselves.
50 key = MYSENSORS_ON_UNLOAD.format(gateway_id)
51 if key
not in hass.data[DOMAIN]:
52 hass.data[DOMAIN][key] = []
53 hass.data[DOMAIN][key].append(fnct)
58 hass: HomeAssistant, gateway_id: GatewayId, platform: str, new_devices: list[DevId]
60 """Discover a MySensors platform."""
61 _LOGGER.debug(
"Discovering platform %s with devIds: %s", platform, new_devices)
64 MYSENSORS_DISCOVERY.format(gateway_id, platform),
66 ATTR_DEVICES: new_devices,
68 ATTR_GATEWAY_ID: gateway_id,
75 hass: HomeAssistant, gateway_id: GatewayId, node_id: int
77 """Discover a MySensors node."""
78 discovered_nodes = hass.data[DOMAIN].setdefault(
79 MYSENSORS_DISCOVERED_NODES.format(gateway_id), set()
82 if node_id
not in discovered_nodes:
83 discovered_nodes.add(node_id)
86 MYSENSORS_NODE_DISCOVERY,
88 ATTR_GATEWAY_ID: gateway_id,
89 ATTR_NODE_ID: node_id,
95 gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
97 """Return a default validation schema for value types."""
98 schema = {value_type_name: cv.string}
102 @SCHEMAS.register(("light", "V_DIMMER"))
104 gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
106 """Return a validation schema for V_DIMMER."""
107 schema = {
"V_DIMMER": cv.string,
"V_LIGHT": cv.string}
111 @SCHEMAS.register(("light", "V_PERCENTAGE"))
113 gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
115 """Return a validation schema for V_PERCENTAGE."""
116 schema = {
"V_PERCENTAGE": cv.string,
"V_STATUS": cv.string}
120 @SCHEMAS.register(("light", "V_RGB"))
122 gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
124 """Return a validation schema for V_RGB."""
125 schema = {
"V_RGB": cv.string,
"V_STATUS": cv.string}
129 @SCHEMAS.register(("light", "V_RGBW"))
131 gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
133 """Return a validation schema for V_RGBW."""
134 schema = {
"V_RGBW": cv.string,
"V_STATUS": cv.string}
138 @SCHEMAS.register(("switch", "V_IR_SEND"))
140 gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
142 """Return a validation schema for V_IR_SEND."""
143 schema = {
"V_IR_SEND": cv.string,
"V_LIGHT": cv.string}
148 gateway: BaseAsyncGateway,
150 value_type_name: ValueType,
153 """Return a child schema."""
154 set_req = gateway.const.SetReq
155 child_schema = cast(vol.Schema, child.get_schema(gateway.protocol_version))
156 return child_schema.extend(
159 set_req[name].value, msg=
invalid_msg(gateway, child, name)
160 ): child_schema.schema.get(set_req[name].value, valid)
161 for name, valid
in schema.items()
163 extra=vol.ALLOW_EXTRA,
168 gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
170 """Return a message for an invalid child during schema validation."""
171 presentation = gateway.const.Presentation
172 set_req = gateway.const.SetReq
173 return f
"{presentation(child.type).name} requires value_type {set_req[value_type_name].name}"
177 gateway_id: GatewayId, msg: Message
178 ) -> dict[Platform, list[DevId]]:
179 """Validate a set message."""
182 child = msg.gateway.sensors[msg.node_id].children[msg.child_id]
183 return validate_child(gateway_id, msg.gateway, msg.node_id, child, msg.sub_type)
187 """Validate a node."""
188 if gateway.sensors[node_id].sketch_name
is None:
189 _LOGGER.debug(
"Node %s is missing sketch name", node_id)
195 gateway_id: GatewayId,
196 gateway: BaseAsyncGateway,
199 value_type: int |
None =
None,
200 ) -> defaultdict[Platform, list[DevId]]:
201 """Validate a child. Returns a dict mapping hass platform names to list of DevId."""
202 validated: defaultdict[Platform, list[DevId]] = defaultdict(list)
203 presentation: type[IntEnum] = gateway.const.Presentation
204 set_req: type[IntEnum] = gateway.const.SetReq
205 child_type_name: SensorType |
None = next(
206 (member.name
for member
in presentation
if member.value == child.type),
None
208 if not child_type_name:
209 _LOGGER.warning(
"Child type %s is not supported", child.type)
212 value_types: set[int] = {value_type}
if value_type
else {*child.values}
213 value_type_names: set[ValueType] = {
214 member.name
for member
in set_req
if member.value
in value_types
216 platforms: list[Platform] = TYPE_TO_PLATFORMS.get(child_type_name, [])
218 _LOGGER.warning(
"Child type %s is not supported", child.type)
221 for platform
in platforms:
222 platform_v_names: set[ValueType] = FLAT_PLATFORM_TYPES[
223 platform, child_type_name
225 v_names: set[ValueType] = platform_v_names & value_type_names
227 child_value_names: set[ValueType] = {
228 member.name
for member
in set_req
if member.value
in child.values
230 v_names = platform_v_names & child_value_names
232 for v_name
in v_names:
233 child_schema_gen = SCHEMAS.get((platform, v_name), default_schema)
234 child_schema = child_schema_gen(gateway, child, v_name)
236 child_schema(child.values)
237 except vol.Invalid
as exc:
239 "Invalid %s on node %s, %s platform: %s",
250 set_req[v_name].value,
252 validated[platform].append(dev_id)
None on_unload(HomeAssistant hass, GatewayId gateway_id, Callable fnct)
vol.Schema light_rgb_schema(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name)
vol.Schema get_child_schema(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name, dict schema)
vol.Schema light_dimmer_schema(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name)
vol.Schema light_rgbw_schema(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name)
vol.Schema switch_ir_send_schema(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name)
bool validate_node(BaseAsyncGateway gateway, int node_id)
vol.Schema light_percentage_schema(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name)
str invalid_msg(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name)
None discover_mysensors_platform(HomeAssistant hass, GatewayId gateway_id, str platform, list[DevId] new_devices)
vol.Schema default_schema(BaseAsyncGateway gateway, ChildSensor child, ValueType value_type_name)
None discover_mysensors_node(HomeAssistant hass, GatewayId gateway_id, int node_id)
defaultdict[Platform, list[DevId]] validate_child(GatewayId gateway_id, BaseAsyncGateway gateway, int node_id, ChildSensor child, int|None value_type=None)
dict[Platform, list[DevId]] validate_set_msg(GatewayId gateway_id, Message msg)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)