1 """Representation of Venstar sensors."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
12 SensorEntityDescription,
17 CONCENTRATION_PARTS_PER_MILLION,
26 from .const
import DOMAIN
27 from .coordinator
import VenstarDataUpdateCoordinator
28 from .entity
import VenstarEntity
30 RUNTIME_HEAT1 =
"heat1"
31 RUNTIME_HEAT2 =
"heat2"
32 RUNTIME_COOL1 =
"cool1"
33 RUNTIME_COOL2 =
"cool2"
50 RUNTIME_ATTRIBUTES = {
51 RUNTIME_HEAT1:
"Heating Stage 1",
52 RUNTIME_HEAT2:
"Heating Stage 2",
53 RUNTIME_COOL1:
"Cooling Stage 1",
54 RUNTIME_COOL2:
"Cooling Stage 2",
55 RUNTIME_AUX1:
"Aux Stage 1",
56 RUNTIME_AUX2:
"Aux Stage 2",
57 RUNTIME_FC:
"Free Cooling",
58 RUNTIME_OV:
"Override",
61 SCHEDULE_PARTS: dict[int, str] = {
69 STAGES: dict[int, str] = {0:
"idle", 1:
"first_stage", 2:
"second_stage"}
72 @dataclass(frozen=True, kw_only=True)
74 """Base description of a Sensor entity."""
76 value_fn: Callable[[VenstarDataUpdateCoordinator, str], Any]
77 name_fn: Callable[[str], str] |
None
78 uom_fn: Callable[[VenstarDataUpdateCoordinator], str |
None]
83 config_entry: ConfigEntry,
84 async_add_entities: AddEntitiesCallback,
86 """Set up Venstar device sensors based on a config entry."""
87 coordinator: VenstarDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
88 entities: list[Entity] = []
90 if sensors := coordinator.client.get_sensor_list():
91 for sensor_name
in sensors:
94 VenstarSensor(coordinator, config_entry, description, sensor_name)
95 for description
in SENSOR_ENTITIES
96 if coordinator.client.get_sensor(sensor_name, description.key)
101 runtimes = coordinator.runtimes[-1]
102 for sensor_name
in runtimes:
103 if sensor_name
in RUNTIME_DEVICES:
106 coordinator, config_entry, RUNTIME_ENTITY, sensor_name
110 VenstarSensor(coordinator, config_entry, description, sensor_name)
111 for description
in CONSUMABLE_ENTITIES
112 if description.key == sensor_name
115 for description
in INFO_ENTITIES:
118 coordinator.client.get_info(description.key)
122 VenstarSensor(coordinator, config_entry, description, description.key)
130 """Return the correct unit for temperature."""
131 unit = UnitOfTemperature.CELSIUS
132 if coordinator.client.tempunits == coordinator.client.TEMPUNITS_F:
133 unit = UnitOfTemperature.FAHRENHEIT
138 """Base class for a Venstar sensor."""
140 entity_description: VenstarSensorEntityDescription
144 coordinator: VenstarDataUpdateCoordinator,
146 entity_description: VenstarSensorEntityDescription,
149 """Initialize the sensor."""
150 super().
__init__(coordinator, config)
153 if entity_description.name_fn:
154 self.
_attr_name_attr_name = entity_description.name_fn(sensor_name)
159 """Return the unique id."""
160 return f
"{self._config.entry_id}_{self.sensor_name.replace(' ', '_')}_{self.entity_description.key}"
164 """Return state of the sensor."""
169 """Return unit of measurement the value is expressed in."""
173 SENSOR_ENTITIES: tuple[VenstarSensorEntityDescription, ...] = (
176 device_class=SensorDeviceClass.HUMIDITY,
177 state_class=SensorStateClass.MEASUREMENT,
178 uom_fn=
lambda _: PERCENTAGE,
179 value_fn=
lambda coordinator, sensor_name: coordinator.client.get_sensor(
182 name_fn=
lambda sensor_name: f
"{sensor_name} Humidity",
186 device_class=SensorDeviceClass.TEMPERATURE,
187 state_class=SensorStateClass.MEASUREMENT,
188 uom_fn=temperature_unit,
189 value_fn=
lambda coordinator, sensor_name: round(
190 float(coordinator.client.get_sensor(sensor_name,
"temp")), 1
192 name_fn=
lambda sensor_name: f
"{sensor_name.replace(' Temp', '')} Temperature",
196 device_class=SensorDeviceClass.CO2,
197 state_class=SensorStateClass.MEASUREMENT,
198 uom_fn=
lambda _: CONCENTRATION_PARTS_PER_MILLION,
199 value_fn=
lambda coordinator, sensor_name: coordinator.client.get_sensor(
202 name_fn=
lambda sensor_name: f
"{sensor_name} CO2",
206 device_class=SensorDeviceClass.AQI,
207 state_class=SensorStateClass.MEASUREMENT,
208 uom_fn=
lambda _:
None,
209 value_fn=
lambda coordinator, sensor_name: coordinator.client.get_sensor(
212 name_fn=
lambda sensor_name: f
"{sensor_name} IAQ",
216 device_class=SensorDeviceClass.BATTERY,
217 state_class=SensorStateClass.MEASUREMENT,
218 uom_fn=
lambda _: PERCENTAGE,
219 value_fn=
lambda coordinator, sensor_name: coordinator.client.get_sensor(
220 sensor_name,
"battery"
222 name_fn=
lambda sensor_name: f
"{sensor_name} Battery",
228 state_class=SensorStateClass.MEASUREMENT,
229 uom_fn=
lambda _: UnitOfTime.MINUTES,
230 value_fn=
lambda coordinator, sensor_name: coordinator.runtimes[-1][sensor_name],
231 name_fn=
lambda sensor_name: f
"{RUNTIME_ATTRIBUTES[sensor_name]} Runtime",
234 CONSUMABLE_ENTITIES: tuple[VenstarSensorEntityDescription, ...] = (
237 state_class=SensorStateClass.MEASUREMENT,
238 uom_fn=
lambda _: UnitOfTime.HOURS,
239 value_fn=
lambda coordinator, sensor_name: (
240 coordinator.runtimes[-1][sensor_name] / 100
243 translation_key=
"filter_install_time",
247 state_class=SensorStateClass.MEASUREMENT,
248 uom_fn=
lambda _: UnitOfTime.DAYS,
249 value_fn=
lambda coordinator, sensor_name: coordinator.runtimes[-1][sensor_name],
251 translation_key=
"filter_usage",
255 INFO_ENTITIES: tuple[VenstarSensorEntityDescription, ...] = (
258 device_class=SensorDeviceClass.ENUM,
259 options=
list(SCHEDULE_PARTS.values()),
260 translation_key=
"schedule_part",
261 uom_fn=
lambda _:
None,
262 value_fn=
lambda coordinator, sensor_name: SCHEDULE_PARTS[
263 coordinator.client.get_info(sensor_name)
269 device_class=SensorDeviceClass.ENUM,
270 options=
list(STAGES.values()),
271 translation_key=
"active_stage",
272 uom_fn=
lambda _:
None,
273 value_fn=
lambda coordinator, sensor_name: STAGES[
274 coordinator.client.get_info(sensor_name)
str|None native_unit_of_measurement(self)
None __init__(self, VenstarDataUpdateCoordinator coordinator, ConfigEntry config, VenstarSensorEntityDescription entity_description, str sensor_name)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
str temperature_unit(VenstarDataUpdateCoordinator coordinator)