From 758c54d0f96a0544bc6518129bd86f8b637c36f7 Mon Sep 17 00:00:00 2001 From: Krisjanis Lejejs Date: Fri, 21 Jan 2022 22:43:04 +0200 Subject: [PATCH] Added many different Thermia heat pump sensors --- custom_components/thermia/config_flow.py | 2 +- custom_components/thermia/const.py | 5 + custom_components/thermia/manifest.json | 2 +- custom_components/thermia/sensor.py | 299 +++++++++++++++++- .../thermia/sensors/generic_sensor.py | 54 ++++ .../sensors/outdoor_temperature_sensor.py | 71 ----- 6 files changed, 349 insertions(+), 84 deletions(-) create mode 100644 custom_components/thermia/sensors/generic_sensor.py delete mode 100644 custom_components/thermia/sensors/outdoor_temperature_sensor.py diff --git a/custom_components/thermia/config_flow.py b/custom_components/thermia/config_flow.py index 81e1190..4c51ca3 100644 --- a/custom_components/thermia/config_flow.py +++ b/custom_components/thermia/config_flow.py @@ -61,7 +61,7 @@ async def async_step_user(self, user_input=None): try: await self._check_credentials(user_input) return self.async_create_entry( - title="Thermia", + title=f"Thermia ({user_input[CONF_USERNAME]})", data=user_input, ) except Exception: diff --git a/custom_components/thermia/const.py b/custom_components/thermia/const.py index 64f0680..010347b 100644 --- a/custom_components/thermia/const.py +++ b/custom_components/thermia/const.py @@ -8,3 +8,8 @@ API_TYPE = "api_type" API_TYPES = [API_TYPE_CLASSIC, API_TYPE_GENESIS] + +MDI_TIMER_COG_OUTLINE_ICON = "mdi:timer-cog-outline" +MDI_TEMPERATURE_ICON = "mdi:thermometer" + +DIAGNOSTIC_ENTITY_CATEGORY = "diagnostic" diff --git a/custom_components/thermia/manifest.json b/custom_components/thermia/manifest.json index 9c70040..8c31056 100644 --- a/custom_components/thermia/manifest.json +++ b/custom_components/thermia/manifest.json @@ -9,7 +9,7 @@ "@klejejs" ], "requirements": [ - "ThermiaOnlineAPI==2.7" + "ThermiaOnlineAPI==2.11" ], "version": "1.0", "iot_class": "cloud_polling", diff --git a/custom_components/thermia/sensor.py b/custom_components/thermia/sensor.py index 20b4add..dc08537 100644 --- a/custom_components/thermia/sensor.py +++ b/custom_components/thermia/sensor.py @@ -3,13 +3,19 @@ from __future__ import annotations from homeassistant.config_entries import ConfigEntry +from homeassistant.const import TEMP_CELSIUS, TIME_HOURS from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from .sensors.active_alarms_sensor import ThermiaActiveAlarmsSensor -from .sensors.outdoor_temperature_sensor import ThermiaOutdoorTemperatureSensor +from .sensors.generic_sensor import ThermiaGenericSensor -from .const import DOMAIN +from .const import ( + DIAGNOSTIC_ENTITY_CATEGORY, + DOMAIN, + MDI_TEMPERATURE_ICON, + MDI_TIMER_COG_OUTLINE_ICON, +) async def async_setup_entry( @@ -21,18 +27,289 @@ async def async_setup_entry( coordinator = hass.data[DOMAIN][config_entry.entry_id] - hass_thermia_outdoor_temperature_sensors = [ - ThermiaOutdoorTemperatureSensor(coordinator, idx) - for idx, heat_pump in enumerate(coordinator.data.heat_pumps) - if heat_pump.is_outdoor_temp_sensor_functioning - and heat_pump.outdoor_temperature - ] + hass_thermia_sensors = [] + + for idx, heat_pump in enumerate(coordinator.data.heat_pumps): + if ( + heat_pump.is_outdoor_temp_sensor_functioning + and heat_pump.outdoor_temperature is not None + ): + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Outdoor Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "outdoor_temperature", + TEMP_CELSIUS, + ) + ) + + if ( + heat_pump.has_indoor_temp_sensor + and heat_pump.indoor_temperature is not None + ): + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Indoor Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "indoor_temperature", + TEMP_CELSIUS, + ) + ) + + if ( + heat_pump.is_hot_water_active + and heat_pump.hot_water_temperature is not None + ): + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Hot Water Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "hot_water_temperature", + TEMP_CELSIUS, + ) + ) + + ########################################################################### + # Other temperature sensors + ########################################################################### + + if heat_pump.supply_line_temperature is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Supply Line Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "supply_line_temperature", + TEMP_CELSIUS, + ) + ) + + if heat_pump.desired_supply_line_temperature is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Desired Supply Line Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "desired_supply_line_temperature", + TEMP_CELSIUS, + ) + ) + + if heat_pump.return_line_temperature is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Return Line Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "return_line_temperature", + TEMP_CELSIUS, + ) + ) + + if heat_pump.brine_out_temperature is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Brine Out Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "brine_out_temperature", + TEMP_CELSIUS, + ) + ) + + if heat_pump.brine_in_temperature is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Brine In Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "brine_in_temperature", + TEMP_CELSIUS, + ) + ) + + if heat_pump.cooling_tank_temperature is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Cooling Tank Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "cooling_tank_temperature", + TEMP_CELSIUS, + ) + ) + + if heat_pump.cooling_supply_line_temperature is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Cooling Supply Line Temperature", + MDI_TEMPERATURE_ICON, + "sensor", + "temperature", + "measurement", + "cooling_supply_line_temperature", + TEMP_CELSIUS, + ) + ) + + ########################################################################### + # Operational status data + ########################################################################### + + if heat_pump.operational_status is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Operational Status", + "mdi:thermostat", + "sensor", + None, + "measurement", + "operational_status", + None, + ) + ) + + ########################################################################### + # Operational time data + ########################################################################### + + if heat_pump.compressor_operational_time is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Compressor Operational Time", + MDI_TIMER_COG_OUTLINE_ICON, + DIAGNOSTIC_ENTITY_CATEGORY, + None, + "total_increasing", + "compressor_operational_time", + TIME_HOURS, + ) + ) + + if heat_pump.hot_water_operational_time is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Hot Water Operational Time", + MDI_TIMER_COG_OUTLINE_ICON, + DIAGNOSTIC_ENTITY_CATEGORY, + None, + "total_increasing", + "hot_water_operational_time", + TIME_HOURS, + ) + ) + + if heat_pump.auxiliary_heater_1_operational_time is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Auxiliary Heater 1 Operational Time", + MDI_TIMER_COG_OUTLINE_ICON, + DIAGNOSTIC_ENTITY_CATEGORY, + None, + "total_increasing", + "auxiliary_heater_1_operational_time", + TIME_HOURS, + ) + ) + + if heat_pump.auxiliary_heater_2_operational_time is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Auxiliary Heater 2 Operational Time", + MDI_TIMER_COG_OUTLINE_ICON, + DIAGNOSTIC_ENTITY_CATEGORY, + None, + "total_increasing", + "auxiliary_heater_2_operational_time", + TIME_HOURS, + ) + ) + + if heat_pump.auxiliary_heater_3_operational_time is not None: + hass_thermia_sensors.append( + ThermiaGenericSensor( + coordinator, + idx, + "is_online", + "Auxiliary Heater 3 Operational Time", + MDI_TIMER_COG_OUTLINE_ICON, + DIAGNOSTIC_ENTITY_CATEGORY, + None, + "total_increasing", + "auxiliary_heater_3_operational_time", + TIME_HOURS, + ) + ) hass_thermia_active_alarms_sensors = [ ThermiaActiveAlarmsSensor(coordinator, idx) for idx, _ in enumerate(coordinator.data.heat_pumps) ] - async_add_entities( - [*hass_thermia_outdoor_temperature_sensors, *hass_thermia_active_alarms_sensors] - ) + async_add_entities([*hass_thermia_active_alarms_sensors, *hass_thermia_sensors]) diff --git a/custom_components/thermia/sensors/generic_sensor.py b/custom_components/thermia/sensors/generic_sensor.py new file mode 100644 index 0000000..ade0cff --- /dev/null +++ b/custom_components/thermia/sensors/generic_sensor.py @@ -0,0 +1,54 @@ +"""Thermia Generic Sensor integration.""" + +from __future__ import annotations + +from homeassistant.components.sensor import SensorEntity +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from ..const import DOMAIN + + +class ThermiaGenericSensor(CoordinatorEntity, SensorEntity): + """Representation of an Thermia generic sensor.""" + + def __init__( + self, + coordinator, + idx, + is_online_prop, + sensor_name, + mdi_icon, + entity_category, + device_class, + state_class, + value_prop, + unit_of_measurement, + ): + super().__init__(coordinator) + self.idx = idx + + self._attr_available = getattr( + self.coordinator.data.heat_pumps[self.idx], is_online_prop + ) + self._attr_name = ( + f"{self.coordinator.data.heat_pumps[self.idx].name} {sensor_name}" + ) + self._attr_unique_id = f"{self.coordinator.data.heat_pumps[self.idx].name}_{sensor_name.lower().replace(' ', '_')}" + self._attr_device_info = { + "identifiers": {(DOMAIN, self.coordinator.data.heat_pumps[self.idx].id)}, + "name": self.coordinator.data.heat_pumps[self.idx].name, + "manufacturer": "Thermia", + "model": self.coordinator.data.heat_pumps[self.idx].model, + } + self._attr_icon = mdi_icon + self._attr_entity_category = entity_category + self._attr_device_class = device_class + self._attr_state_class = state_class + self._attr_native_value = getattr( + self.coordinator.data.heat_pumps[self.idx], value_prop + ) + self._attr_unit_of_measurement = unit_of_measurement + + async def async_update(self): + """Update the sensor.""" + await self.coordinator.async_request_refresh() diff --git a/custom_components/thermia/sensors/outdoor_temperature_sensor.py b/custom_components/thermia/sensors/outdoor_temperature_sensor.py deleted file mode 100644 index 88e11c4..0000000 --- a/custom_components/thermia/sensors/outdoor_temperature_sensor.py +++ /dev/null @@ -1,71 +0,0 @@ -"""Thermia outdoor temperature sensor integration.""" - -from __future__ import annotations - -from homeassistant.components.sensor import SensorEntity -from homeassistant.const import TEMP_CELSIUS -from homeassistant.helpers.update_coordinator import CoordinatorEntity - -from ..const import DOMAIN - - -class ThermiaOutdoorTemperatureSensor(CoordinatorEntity, SensorEntity): - """Representation of an Thermia outdoor temperature sensor.""" - - def __init__(self, coordinator, idx): - super().__init__(coordinator) - self.idx = idx - - @property - def available(self): - """Return True if entity is available.""" - return self.coordinator.data.heat_pumps[self.idx].is_online - - @property - def name(self): - """Return the name of the sensor.""" - return f"{self.coordinator.data.heat_pumps[self.idx].name} Outdoor Temperature" - - @property - def unique_id(self): - """Return the unique ID of the sensor.""" - return f"{self.coordinator.data.heat_pumps[self.idx].name}_outdoor_temperature" - - @property - def icon(self): - """Return the icon of the sensor.""" - return "mdi:thermometer" - - @property - def device_info(self): - """Return device information.""" - return { - "identifiers": {(DOMAIN, self.coordinator.data.heat_pumps[self.idx].id)}, - "name": self.coordinator.data.heat_pumps[self.idx].name, - "manufacturer": "Thermia", - "model": self.coordinator.data.heat_pumps[self.idx].model, - } - - @property - def device_class(self): - """Return the device class.""" - return "temperature" - - @property - def state_class(self): - """Return the state class.""" - return "measurement" - - @property - def native_value(self): - """Return the temperature of the sensor.""" - return self.coordinator.data.heat_pumps[self.idx].outdoor_temperature - - @property - def native_unit_of_measurement(self): - """Return the unit of measurement of the sensor.""" - return TEMP_CELSIUS - - async def async_update(self): - """Update the sensor.""" - await self.coordinator.async_request_refresh()