1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-21 10:27:52 +00:00
Files
Joshua Monta 70e84526cc Uhoo integration (#158887)
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-01-27 21:08:41 +01:00

198 lines
6.3 KiB
Python

"""Custom uhoo sensors setup."""
from collections.abc import Callable
from dataclasses import dataclass
from uhooapi import Device
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
PERCENTAGE,
UnitOfPressure,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
API_CO,
API_CO2,
API_HUMIDITY,
API_MOLD,
API_NO2,
API_OZONE,
API_PM25,
API_PRESSURE,
API_TEMP,
API_TVOC,
API_VIRUS,
DOMAIN,
MANUFACTURER,
MODEL,
)
from .coordinator import UhooConfigEntry, UhooDataUpdateCoordinator
PARALLEL_UPDATES = 1
@dataclass(frozen=True, kw_only=True)
class UhooSensorEntityDescription(SensorEntityDescription):
"""Extended SensorEntityDescription with a type-safe value function."""
value_fn: Callable[[Device], float | None]
SENSOR_TYPES: tuple[UhooSensorEntityDescription, ...] = (
UhooSensorEntityDescription(
key=API_CO,
device_class=SensorDeviceClass.CO,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.co,
),
UhooSensorEntityDescription(
key=API_CO2,
device_class=SensorDeviceClass.CO2,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.co2,
),
UhooSensorEntityDescription(
key=API_PM25,
device_class=SensorDeviceClass.PM25,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.pm25,
),
UhooSensorEntityDescription(
key=API_HUMIDITY,
device_class=SensorDeviceClass.HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.humidity,
),
UhooSensorEntityDescription(
key=API_TEMP,
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS, # Base unit
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.temperature,
),
UhooSensorEntityDescription(
key=API_PRESSURE,
device_class=SensorDeviceClass.PRESSURE,
native_unit_of_measurement=UnitOfPressure.HPA,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.air_pressure,
),
UhooSensorEntityDescription(
key=API_TVOC,
translation_key="volatile_organic_compounds",
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.tvoc,
),
UhooSensorEntityDescription(
key=API_NO2,
translation_key="nitrogen_dioxide",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.no2,
),
UhooSensorEntityDescription(
key=API_OZONE,
translation_key="ozone",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.ozone,
),
UhooSensorEntityDescription(
key=API_VIRUS,
translation_key=API_VIRUS,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.virus_index,
),
UhooSensorEntityDescription(
key=API_MOLD,
translation_key=API_MOLD,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data.mold_index,
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: UhooConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Setup sensor platform."""
coordinator = config_entry.runtime_data
async_add_entities(
UhooSensorEntity(description, serial_number, coordinator)
for serial_number in coordinator.data
for description in SENSOR_TYPES
)
class UhooSensorEntity(CoordinatorEntity[UhooDataUpdateCoordinator], SensorEntity):
"""Uhoo Sensor Object with init and methods."""
entity_description: UhooSensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
description: UhooSensorEntityDescription,
serial_number: str,
coordinator: UhooDataUpdateCoordinator,
) -> None:
"""Initialize Uhoo Sensor."""
super().__init__(coordinator)
self.entity_description = description
self._serial_number = serial_number
self._attr_unique_id = f"{serial_number}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, serial_number)},
name=self.device.device_name,
model=MODEL,
manufacturer=MANUFACTURER,
serial_number=serial_number,
)
@property
def device(self) -> Device:
"""Return the device object for this sensor's serial number."""
return self.coordinator.data[self._serial_number]
@property
def available(self) -> bool:
"""Return if entity is available."""
return super().available and self._serial_number in self.coordinator.data
@property
def native_value(self) -> StateType:
"""State of the sensor."""
return self.entity_description.value_fn(self.device)
@property
def native_unit_of_measurement(self) -> str | None:
"""Return unit of measurement."""
if self.entity_description.key == API_TEMP:
if self.device.user_settings["temp"] == "f":
return UnitOfTemperature.FAHRENHEIT
return UnitOfTemperature.CELSIUS
return super().native_unit_of_measurement