1 """Support for ISY sensors."""
3 from __future__
import annotations
5 from typing
import Any, cast
7 from pyisy.constants
import (
10 COMMAND_FRIENDLY_NAME,
24 from pyisy.helpers
import EventListener, NodeProperty
25 from pyisy.nodes
import Node, NodeChangedEvent
47 from .entity
import ISYNodeEntity
48 from .helpers
import convert_isy_value_to_hass
49 from .models
import IsyData
52 AUX_DISABLED_BY_DEFAULT_MATCH = [
"GV",
"DO"]
53 AUX_DISABLED_BY_DEFAULT_EXACT = {
65 ISY_CONTROL_TO_DEVICE_CLASS = {
66 PROP_BATTERY_LEVEL: SensorDeviceClass.BATTERY,
67 PROP_HUMIDITY: SensorDeviceClass.HUMIDITY,
68 PROP_TEMPERATURE: SensorDeviceClass.TEMPERATURE,
69 "BARPRES": SensorDeviceClass.ATMOSPHERIC_PRESSURE,
70 "CC": SensorDeviceClass.CURRENT,
71 "CO2LVL": SensorDeviceClass.CO2,
72 "CPW": SensorDeviceClass.POWER,
73 "CV": SensorDeviceClass.VOLTAGE,
74 "DEWPT": SensorDeviceClass.TEMPERATURE,
75 "DISTANC": SensorDeviceClass.DISTANCE,
76 "ETO": SensorDeviceClass.PRECIPITATION_INTENSITY,
77 "FATM": SensorDeviceClass.WEIGHT,
78 "FREQ": SensorDeviceClass.FREQUENCY,
79 "MUSCLEM": SensorDeviceClass.WEIGHT,
80 "PF": SensorDeviceClass.POWER_FACTOR,
81 "PM10": SensorDeviceClass.PM10,
82 "PM25": SensorDeviceClass.PM25,
83 "PRECIP": SensorDeviceClass.PRECIPITATION,
84 "RAINRT": SensorDeviceClass.PRECIPITATION_INTENSITY,
85 "RFSS": SensorDeviceClass.SIGNAL_STRENGTH,
86 "SOILH": SensorDeviceClass.MOISTURE,
87 "SOILT": SensorDeviceClass.TEMPERATURE,
88 "SOLRAD": SensorDeviceClass.IRRADIANCE,
89 "SPEED": SensorDeviceClass.SPEED,
90 "TEMPEXH": SensorDeviceClass.TEMPERATURE,
91 "TEMPOUT": SensorDeviceClass.TEMPERATURE,
92 "TPW": SensorDeviceClass.ENERGY,
93 "WATERP": SensorDeviceClass.PRESSURE,
94 "WATERT": SensorDeviceClass.TEMPERATURE,
95 "WATERTB": SensorDeviceClass.TEMPERATURE,
96 "WATERTD": SensorDeviceClass.TEMPERATURE,
97 "WEIGHT": SensorDeviceClass.WEIGHT,
98 "WINDCH": SensorDeviceClass.TEMPERATURE,
100 ISY_CONTROL_TO_STATE_CLASS = {
101 control: SensorStateClass.MEASUREMENT
for control
in ISY_CONTROL_TO_DEVICE_CLASS
103 ISY_CONTROL_TO_ENTITY_CATEGORY = {
104 PROP_RAMP_RATE: EntityCategory.DIAGNOSTIC,
105 PROP_ON_LEVEL: EntityCategory.DIAGNOSTIC,
106 PROP_COMMS_ERROR: EntityCategory.DIAGNOSTIC,
111 hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
113 """Set up the ISY sensor platform."""
114 isy_data: IsyData = hass.data[DOMAIN][entry.entry_id]
115 entities: list[ISYSensorEntity] = []
116 devices: dict[str, DeviceInfo] = isy_data.devices
118 for node
in isy_data.nodes[Platform.SENSOR]:
119 _LOGGER.debug(
"Loading %s", node.name)
122 aux_sensors_list = isy_data.aux_properties[Platform.SENSOR]
123 for node, control
in aux_sensors_list:
124 _LOGGER.debug(
"Loading %s %s", node.name, COMMAND_FRIENDLY_NAME.get(control))
125 enabled_default = control
not in AUX_DISABLED_BY_DEFAULT_EXACT
and not any(
126 control.startswith(match)
for match
in AUX_DISABLED_BY_DEFAULT_MATCH
132 enabled_default=enabled_default,
133 unique_id=f
"{isy_data.uid_base(node)}_{control}",
134 device_info=devices.get(node.primary_node),
142 """Representation of an ISY sensor device."""
145 def target(self) -> Node | NodeProperty | None:
146 """Return target for the sensor."""
147 return self.
_node_node
151 """Return the target value."""
152 return self.
_node_node.status
156 """Get the raw unit of measurement for the ISY sensor device."""
157 if self.
targettarget
is None:
160 uom = self.
targettarget.uom
163 if isinstance(uom, list):
164 return UOM_FRIENDLY_NAME.get(uom[0], uom[0])
167 if isy_states := UOM_TO_STATES.get(uom):
170 if uom
in (UOM_ON_OFF, UOM_INDEX):
171 assert isinstance(uom, str)
174 return UOM_FRIENDLY_NAME.get(uom)
178 """Get the state of the ISY sensor device."""
179 if self.
targettarget
is None:
182 if (value := self.
target_valuetarget_value) == ISY_VALUE_UNKNOWN:
189 if isinstance(uom, dict):
190 return uom.get(value, value)
192 if uom
in (UOM_INDEX, UOM_ON_OFF):
193 return cast(str, self.
targettarget.formatted)
196 if uom == UOM_INDEX
and hasattr(self.
targettarget,
"formatted"):
197 return cast(str, self.
targettarget.formatted)
203 if uom
in (UnitOfTemperature.CELSIUS, UnitOfTemperature.FAHRENHEIT):
204 value = self.
hasshass.config.units.temperature(value, uom)
209 assert isinstance(value, (int, float))
214 """Get the Home Assistant unit of measurement for the device."""
217 if isinstance(raw_units, dict)
or raw_units
in (UOM_ON_OFF, UOM_INDEX):
220 UnitOfTemperature.FAHRENHEIT,
221 UnitOfTemperature.CELSIUS,
224 return self.
hasshass.config.units.temperature_unit
229 """Representation of an ISY aux sensor device."""
235 enabled_default: bool,
237 device_info: DeviceInfo |
None =
None,
239 """Initialize the ISY aux sensor."""
240 super().
__init__(node, device_info=device_info)
250 name = COMMAND_FRIENDLY_NAME.get(self.
_control_control, self.
_control_control)
254 def target(self) -> Node | NodeProperty | None:
255 """Return target for the sensor."""
256 if self.
_control_control
not in self.
_node_node.aux_properties:
259 return cast(NodeProperty, self.
_node_node.aux_properties[self.
_control_control])
263 """Return the target value."""
268 """Subscribe to the node control change events.
270 Overloads the default ISYNodeEntity updater to only update when
271 this control is changed on the device and prevent duplicate firing
272 of `isy994_control` events.
280 TAG_ADDRESS: self.
_node_node.address,
281 ATTR_ACTION: NC_NODE_ENABLED,
287 """Handle a control event from the ISY Node."""
292 """Return entity availability."""
293 return cast(bool, self.
_node_node.enabled)
None async_on_update(self, NodeProperty event)
None async_added_to_hass(self)
None __init__(self, Node node, str control, bool enabled_default, str unique_id, DeviceInfo|None device_info=None)
_attr_entity_registry_enabled_default
None async_on_update(self, NodeProperty|NodeChangedEvent event)
Node|NodeProperty|None target(self)
dict|str|None raw_unit_of_measurement(self)
Node|NodeProperty|None target(self)
float|int|str|None native_value(self)
str|None native_unit_of_measurement(self)
None async_write_ha_state(self)
float|int|None convert_isy_value_to_hass(float|None value, str|None uom, int|str precision, int|None fallback_precision=None)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)