"""Support for mill wifi-enabled home heaters.""" from __future__ import annotations import mill from homeassistant.components.sensor import ( SensorDeviceClass, SensorEntity, SensorEntityDescription, SensorStateClass, ) from homeassistant.const import ( CONCENTRATION_PARTS_PER_BILLION, CONCENTRATION_PARTS_PER_MILLION, CONF_IP_ADDRESS, CONF_USERNAME, ENERGY_KILO_WATT_HOUR, PERCENTAGE, POWER_WATT, TEMP_CELSIUS, ) from homeassistant.core import callback from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import ( BATTERY, CLOUD, CONNECTION_TYPE, CONSUMPTION_TODAY, CONSUMPTION_YEAR, DOMAIN, ECO2, HUMIDITY, LOCAL, MANUFACTURER, TEMPERATURE, TVOC, ) HEATER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( SensorEntityDescription( key=CONSUMPTION_YEAR, device_class=SensorDeviceClass.ENERGY, native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, state_class=SensorStateClass.TOTAL_INCREASING, name="Year consumption", ), SensorEntityDescription( key=CONSUMPTION_TODAY, device_class=SensorDeviceClass.ENERGY, native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, state_class=SensorStateClass.TOTAL_INCREASING, name="Day consumption", ), ) SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( SensorEntityDescription( key=TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=TEMP_CELSIUS, name="Temperature", state_class=SensorStateClass.MEASUREMENT, ), SensorEntityDescription( key=HUMIDITY, device_class=SensorDeviceClass.HUMIDITY, native_unit_of_measurement=PERCENTAGE, name="Humidity", state_class=SensorStateClass.MEASUREMENT, ), SensorEntityDescription( key=BATTERY, device_class=SensorDeviceClass.BATTERY, native_unit_of_measurement=PERCENTAGE, name="Battery", state_class=SensorStateClass.MEASUREMENT, entity_category=EntityCategory.DIAGNOSTIC, ), SensorEntityDescription( key=ECO2, device_class=SensorDeviceClass.CO2, native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, name="Estimated CO2", ), SensorEntityDescription( key=TVOC, native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION, name="TVOC", state_class=SensorStateClass.MEASUREMENT, ), ) LOCAL_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( SensorEntityDescription( key="control_signal", native_unit_of_measurement=PERCENTAGE, name="Control signal", state_class=SensorStateClass.MEASUREMENT, ), SensorEntityDescription( key="current_power", device_class=SensorDeviceClass.POWER, native_unit_of_measurement=POWER_WATT, name="Current power", state_class=SensorStateClass.MEASUREMENT, ), SensorEntityDescription( key="raw_ambient_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=TEMP_CELSIUS, name="Uncalibrated temperature", state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, ), ) async def async_setup_entry(hass, entry, async_add_entities): """Set up the Mill sensor.""" if entry.data.get(CONNECTION_TYPE) == LOCAL: mill_data_coordinator = hass.data[DOMAIN][LOCAL][entry.data[CONF_IP_ADDRESS]] async_add_entities( LocalMillSensor( mill_data_coordinator, entity_description, ) for entity_description in LOCAL_SENSOR_TYPES ) return mill_data_coordinator = hass.data[DOMAIN][CLOUD][entry.data[CONF_USERNAME]] entities = [ MillSensor( mill_data_coordinator, entity_description, mill_device, ) for mill_device in mill_data_coordinator.data.values() for entity_description in ( HEATER_SENSOR_TYPES if isinstance(mill_device, mill.Heater) else SENSOR_TYPES ) ] async_add_entities(entities) class MillSensor(CoordinatorEntity, SensorEntity): """Representation of a Mill Sensor device.""" def __init__(self, coordinator, entity_description, mill_device): """Initialize the sensor.""" super().__init__(coordinator) self._id = mill_device.device_id self.entity_description = entity_description self._available = False self._attr_name = f"{mill_device.name} {entity_description.name}" self._attr_unique_id = f"{mill_device.device_id}_{entity_description.key}" self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, mill_device.device_id)}, name=self.name, manufacturer=MANUFACTURER, ) if isinstance(mill_device, mill.Heater): self._attr_device_info["model"] = f"Generation {mill_device.generation}" elif isinstance(mill_device, mill.Sensor): self._attr_device_info["model"] = "Mill Sense Air" self._update_attr(mill_device) @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" self._update_attr(self.coordinator.data[self._id]) self.async_write_ha_state() @property def available(self) -> bool: """Return True if entity is available.""" return super().available and self._available @callback def _update_attr(self, device): self._available = device.available self._attr_native_value = getattr(device, self.entity_description.key) class LocalMillSensor(CoordinatorEntity, SensorEntity): """Representation of a Mill Sensor device.""" def __init__(self, coordinator, entity_description): """Initialize the sensor.""" super().__init__(coordinator) self.entity_description = entity_description self._attr_name = ( f"{coordinator.mill_data_connection.name} {entity_description.name}" ) @property def native_value(self): """Return the native value of the sensor.""" return self.coordinator.data[self.entity_description.key]