1 """Support for Honeywell Lyric sensor platform."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
7 from datetime
import datetime, timedelta
9 from aiolyric
import Lyric
10 from aiolyric.objects.device
import LyricDevice
11 from aiolyric.objects.location
import LyricLocation
12 from aiolyric.objects.priority
import LyricAccessory, LyricRoom
17 SensorEntityDescription,
32 PRESET_PERMANENT_HOLD,
33 PRESET_TEMPORARY_HOLD,
36 from .entity
import LyricAccessoryEntity, LyricDeviceEntity
38 LYRIC_SETPOINT_STATUS_NAMES = {
39 PRESET_NO_HOLD:
"Following Schedule",
40 PRESET_PERMANENT_HOLD:
"Held Permanently",
41 PRESET_TEMPORARY_HOLD:
"Held Temporarily",
42 PRESET_VACATION_HOLD:
"Holiday",
46 @dataclass(frozen=True, kw_only=True)
48 """Class describing Honeywell Lyric sensor entities."""
50 value_fn: Callable[[LyricDevice], StateType | datetime]
51 suitable_fn: Callable[[LyricDevice], bool]
54 @dataclass(frozen=True, kw_only=True)
56 """Class describing Honeywell Lyric room sensor entities."""
58 value_fn: Callable[[LyricRoom, LyricAccessory], StateType | datetime]
59 suitable_fn: Callable[[LyricRoom, LyricAccessory], bool]
62 DEVICE_SENSORS: list[LyricSensorEntityDescription] = [
64 key=
"indoor_temperature",
65 translation_key=
"indoor_temperature",
66 device_class=SensorDeviceClass.TEMPERATURE,
67 state_class=SensorStateClass.MEASUREMENT,
68 value_fn=
lambda device: device.indoor_temperature,
69 suitable_fn=
lambda device: device.indoor_temperature,
72 key=
"indoor_humidity",
73 translation_key=
"indoor_humidity",
74 device_class=SensorDeviceClass.HUMIDITY,
75 state_class=SensorStateClass.MEASUREMENT,
76 native_unit_of_measurement=PERCENTAGE,
77 value_fn=
lambda device: device.indoor_humidity,
78 suitable_fn=
lambda device: device.indoor_humidity,
81 key=
"outdoor_temperature",
82 translation_key=
"outdoor_temperature",
83 device_class=SensorDeviceClass.TEMPERATURE,
84 state_class=SensorStateClass.MEASUREMENT,
85 value_fn=
lambda device: device.outdoor_temperature,
86 suitable_fn=
lambda device: device.outdoor_temperature,
89 key=
"outdoor_humidity",
90 translation_key=
"outdoor_humidity",
91 device_class=SensorDeviceClass.HUMIDITY,
92 state_class=SensorStateClass.MEASUREMENT,
93 native_unit_of_measurement=PERCENTAGE,
94 value_fn=
lambda device: device.displayed_outdoor_humidity,
95 suitable_fn=
lambda device: device.displayed_outdoor_humidity,
98 key=
"next_period_time",
99 translation_key=
"next_period_time",
100 device_class=SensorDeviceClass.TIMESTAMP,
102 device.changeable_values.next_period_time
104 suitable_fn=
lambda device: (
105 device.changeable_values
and device.changeable_values.next_period_time
109 key=
"setpoint_status",
110 translation_key=
"setpoint_status",
112 device.changeable_values.thermostat_setpoint_status,
113 device.changeable_values.next_period_time,
115 suitable_fn=
lambda device: (
116 device.changeable_values
117 and device.changeable_values.thermostat_setpoint_status
122 ACCESSORY_SENSORS: list[LyricSensorAccessoryEntityDescription] = [
124 key=
"room_temperature",
125 translation_key=
"room_temperature",
126 device_class=SensorDeviceClass.TEMPERATURE,
127 state_class=SensorStateClass.MEASUREMENT,
128 value_fn=
lambda _, accessory: accessory.temperature,
129 suitable_fn=
lambda _, accessory: accessory.type ==
"IndoorAirSensor",
133 translation_key=
"room_humidity",
134 device_class=SensorDeviceClass.HUMIDITY,
135 state_class=SensorStateClass.MEASUREMENT,
136 native_unit_of_measurement=PERCENTAGE,
137 value_fn=
lambda room, _: room.room_avg_humidity,
138 suitable_fn=
lambda _, accessory: accessory.type ==
"IndoorAirSensor",
144 """Get status of the setpoint."""
145 if status == PRESET_HOLD_UNTIL:
146 return f
"Held until {time}"
147 return LYRIC_SETPOINT_STATUS_NAMES.get(status)
151 """Get datetime from future time provided."""
152 time = dt_util.parse_time(time_str)
154 raise ValueError(f
"Unable to parse time {time_str}")
155 now = dt_util.utcnow()
156 if time <= now.time():
158 return dt_util.as_utc(datetime.combine(now.date(), time))
162 hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
164 """Set up the Honeywell Lyric sensor platform based on a config entry."""
165 coordinator: DataUpdateCoordinator[Lyric] = hass.data[DOMAIN][entry.entry_id]
174 for location
in coordinator.data.locations
175 for device
in location.devices
176 for device_sensor
in DEVICE_SENSORS
177 if device_sensor.suitable_fn(device)
182 coordinator, accessory_sensor, location, device, room, accessory
184 for location
in coordinator.data.locations
185 for device
in location.devices
186 for room
in coordinator.data.rooms_dict.get(device.mac_id, {}).values()
187 for accessory
in room.accessories
188 for accessory_sensor
in ACCESSORY_SENSORS
189 if accessory_sensor.suitable_fn(room, accessory)
194 """Define a Honeywell Lyric sensor."""
196 entity_description: LyricSensorEntityDescription
200 coordinator: DataUpdateCoordinator[Lyric],
201 description: LyricSensorEntityDescription,
202 location: LyricLocation,
210 f
"{device.mac_id}_{description.key}",
213 if description.device_class == SensorDeviceClass.TEMPERATURE:
214 if device.units ==
"Fahrenheit":
221 """Return the state."""
226 """Define a Honeywell Lyric sensor."""
228 entity_description: LyricSensorAccessoryEntityDescription
232 coordinator: DataUpdateCoordinator[Lyric],
233 description: LyricSensorAccessoryEntityDescription,
234 location: LyricLocation,
235 parentDevice: LyricDevice,
237 accessory: LyricAccessory,
246 f
"{parentDevice.mac_id}_room{room.id}_acc{accessory.id}_{description.key}",
249 if description.device_class == SensorDeviceClass.TEMPERATURE:
250 if parentDevice.units ==
"Fahrenheit":
257 """Return the state."""
LyricAccessory accessory(self)
_attr_native_unit_of_measurement
StateType|datetime native_value(self)
None __init__(self, DataUpdateCoordinator[Lyric] coordinator, LyricSensorAccessoryEntityDescription description, LyricLocation location, LyricDevice parentDevice, LyricRoom room, LyricAccessory accessory)
StateType|datetime native_value(self)
_attr_native_unit_of_measurement
None __init__(self, DataUpdateCoordinator[Lyric] coordinator, LyricSensorEntityDescription description, LyricLocation location, LyricDevice device)
str|None get_setpoint_status(str status, str time)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
datetime get_datetime_from_future_time(str time_str)