From 6860acd28fdc0cc20a1a175e83d143476c7262c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hjelseth=20H=C3=B8yer?= Date: Tue, 26 Oct 2021 21:15:33 +0200 Subject: [PATCH] Add Mill Sense Air sensors (#57776) Co-authored-by: J. Nick Koston --- homeassistant/components/mill/__init__.py | 2 +- homeassistant/components/mill/climate.py | 11 +- homeassistant/components/mill/const.py | 9 +- homeassistant/components/mill/manifest.json | 2 +- homeassistant/components/mill/sensor.py | 136 ++++++++++++++++---- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 7 files changed, 128 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/mill/__init__.py b/homeassistant/components/mill/__init__.py index 73cb65daf05..73480563c29 100644 --- a/homeassistant/components/mill/__init__.py +++ b/homeassistant/components/mill/__init__.py @@ -33,7 +33,7 @@ class MillDataUpdateCoordinator(DataUpdateCoordinator): hass, _LOGGER, name=DOMAIN, - update_method=mill_data_connection.fetch_heater_data, + update_method=mill_data_connection.fetch_heater_and_sensor_data, update_interval=timedelta(seconds=30), ) diff --git a/homeassistant/components/mill/climate.py b/homeassistant/components/mill/climate.py index e464065a8d9..0361322222b 100644 --- a/homeassistant/components/mill/climate.py +++ b/homeassistant/components/mill/climate.py @@ -1,4 +1,5 @@ """Support for mill wifi-enabled home heaters.""" +import mill import voluptuous as vol from homeassistant.components.climate import ClimateEntity @@ -46,10 +47,12 @@ async def async_setup_entry(hass, entry, async_add_entities): mill_data_coordinator = hass.data[DOMAIN] - dev = [] - for heater in mill_data_coordinator.data.values(): - dev.append(MillHeater(mill_data_coordinator, heater)) - async_add_entities(dev) + entities = [ + MillHeater(mill_data_coordinator, mill_device) + for mill_device in mill_data_coordinator.data.values() + if isinstance(mill_device, mill.Heater) + ] + async_add_entities(entities) async def set_room_temp(service): """Set room temp.""" diff --git a/homeassistant/components/mill/const.py b/homeassistant/components/mill/const.py index 61171420e44..25a57117a65 100644 --- a/homeassistant/components/mill/const.py +++ b/homeassistant/components/mill/const.py @@ -4,10 +4,15 @@ ATTR_AWAY_TEMP = "away_temp" ATTR_COMFORT_TEMP = "comfort_temp" ATTR_ROOM_NAME = "room_name" ATTR_SLEEP_TEMP = "sleep_temp" -CONSUMPTION_TODAY = "consumption_today" -CONSUMPTION_YEAR = "consumption_year" +BATTERY = "battery" +CONSUMPTION_TODAY = "day_consumption" +CONSUMPTION_YEAR = "year_consumption" DOMAIN = "mill" +ECO2 = "eco2" +HUMIDITY = "humidity" MANUFACTURER = "Mill" MAX_TEMP = 35 MIN_TEMP = 5 SERVICE_SET_ROOM_TEMP = "set_room_temperature" +TEMPERATURE = "current_temp" +TVOC = "tvoc" diff --git a/homeassistant/components/mill/manifest.json b/homeassistant/components/mill/manifest.json index 55aeec305fb..342b54d2483 100644 --- a/homeassistant/components/mill/manifest.json +++ b/homeassistant/components/mill/manifest.json @@ -2,7 +2,7 @@ "domain": "mill", "name": "Mill", "documentation": "https://www.home-assistant.io/integrations/mill", - "requirements": ["millheater==0.6.2"], + "requirements": ["millheater==0.7.3"], "codeowners": ["@danielhiversen"], "config_flow": true, "iot_class": "cloud_polling" diff --git a/homeassistant/components/mill/sensor.py b/homeassistant/components/mill/sensor.py index 7d3ac40f608..d11a3e43cf2 100644 --- a/homeassistant/components/mill/sensor.py +++ b/homeassistant/components/mill/sensor.py @@ -1,16 +1,96 @@ """Support for mill wifi-enabled home heaters.""" +from __future__ import annotations + +import mill from homeassistant.components.sensor import ( + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_CO2, DEVICE_CLASS_ENERGY, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING, SensorEntity, + SensorEntityDescription, +) +from homeassistant.const import ( + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_PARTS_PER_MILLION, + ENERGY_KILO_WATT_HOUR, + ENTITY_CATEGORY_DIAGNOSTIC, + PERCENTAGE, + TEMP_CELSIUS, ) -from homeassistant.const import ENERGY_KILO_WATT_HOUR from homeassistant.core import callback from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import CONSUMPTION_TODAY, CONSUMPTION_YEAR, DOMAIN, MANUFACTURER +from .const import ( + BATTERY, + CONSUMPTION_TODAY, + CONSUMPTION_YEAR, + DOMAIN, + ECO2, + HUMIDITY, + MANUFACTURER, + TEMPERATURE, + TVOC, +) + +HEATER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( + SensorEntityDescription( + key=CONSUMPTION_YEAR, + device_class=DEVICE_CLASS_ENERGY, + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + state_class=STATE_CLASS_TOTAL_INCREASING, + name="Year consumption", + ), + SensorEntityDescription( + key=CONSUMPTION_TODAY, + device_class=DEVICE_CLASS_ENERGY, + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + state_class=STATE_CLASS_TOTAL_INCREASING, + name="Day consumption", + ), +) + +SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( + SensorEntityDescription( + key=TEMPERATURE, + device_class=DEVICE_CLASS_TEMPERATURE, + native_unit_of_measurement=TEMP_CELSIUS, + name="Temperature", + state_class=STATE_CLASS_MEASUREMENT, + ), + SensorEntityDescription( + key=HUMIDITY, + device_class=DEVICE_CLASS_HUMIDITY, + native_unit_of_measurement=PERCENTAGE, + name="Humidity", + state_class=STATE_CLASS_MEASUREMENT, + ), + SensorEntityDescription( + key=BATTERY, + device_class=DEVICE_CLASS_BATTERY, + native_unit_of_measurement=PERCENTAGE, + name="Battery", + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + SensorEntityDescription( + key=ECO2, + device_class=DEVICE_CLASS_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=STATE_CLASS_MEASUREMENT, + ), +) async def async_setup_entry(hass, entry, async_add_entities): @@ -19,36 +99,44 @@ async def async_setup_entry(hass, entry, async_add_entities): mill_data_coordinator = hass.data[DOMAIN] entities = [ - MillHeaterEnergySensor(mill_data_coordinator, sensor_type, heater) - for sensor_type in (CONSUMPTION_TODAY, CONSUMPTION_YEAR) - for heater in mill_data_coordinator.data.values() + 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 MillHeaterEnergySensor(CoordinatorEntity, SensorEntity): +class MillSensor(CoordinatorEntity, SensorEntity): """Representation of a Mill Sensor device.""" - _attr_device_class = DEVICE_CLASS_ENERGY - _attr_native_unit_of_measurement = ENERGY_KILO_WATT_HOUR - _attr_state_class = STATE_CLASS_TOTAL_INCREASING - - def __init__(self, coordinator, sensor_type, heater): + def __init__(self, coordinator, entity_description, mill_device): """Initialize the sensor.""" super().__init__(coordinator) - self._id = heater.device_id - self._sensor_type = sensor_type + self._id = mill_device.device_id + self.entity_description = entity_description - self._attr_name = f"{heater.name} {sensor_type.replace('_', ' ')}" - self._attr_unique_id = f"{heater.device_id}_{sensor_type}" + 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, heater.device_id)}, - manufacturer=MANUFACTURER, - model=f"generation {1 if heater.is_gen1 else 2}", + identifiers={(DOMAIN, mill_device.device_id)}, name=self.name, + manufacturer=MANUFACTURER, ) - self._update_attr(heater) + 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: @@ -57,10 +145,6 @@ class MillHeaterEnergySensor(CoordinatorEntity, SensorEntity): self.async_write_ha_state() @callback - def _update_attr(self, heater): - self._attr_available = heater.available - - if self._sensor_type == CONSUMPTION_TODAY: - self._attr_native_value = heater.day_consumption - elif self._sensor_type == CONSUMPTION_YEAR: - self._attr_native_value = heater.year_consumption + def _update_attr(self, device): + self._attr_available = device.available + self._attr_native_value = getattr(device, self.entity_description.key) diff --git a/requirements_all.txt b/requirements_all.txt index e1881b2ad7e..24f23a95911 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1005,7 +1005,7 @@ micloud==0.4 miflora==0.7.0 # homeassistant.components.mill -millheater==0.6.2 +millheater==0.7.3 # homeassistant.components.minio minio==4.0.9 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 088a140ffe3..dae5074e1a6 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -600,7 +600,7 @@ mficlient==0.3.0 micloud==0.4 # homeassistant.components.mill -millheater==0.6.2 +millheater==0.7.3 # homeassistant.components.minio minio==4.0.9