From a14bde8187016bceba77abf100821e36bc733da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hjelseth=20H=C3=B8yer?= Date: Tue, 20 Jul 2021 20:18:09 +0200 Subject: [PATCH] Melcloud use NamedTuple (#53234) Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> --- homeassistant/components/melcloud/sensor.py | 188 ++++++++++---------- 1 file changed, 98 insertions(+), 90 deletions(-) diff --git a/homeassistant/components/melcloud/sensor.py b/homeassistant/components/melcloud/sensor.py index c1b7e5e8cbd..b0f1d73f238 100644 --- a/homeassistant/components/melcloud/sensor.py +++ b/homeassistant/components/melcloud/sensor.py @@ -1,4 +1,8 @@ """Support for MelCloud device sensors.""" +from __future__ import annotations + +from typing import Any, Callable, NamedTuple + from pymelcloud import DEVICE_TYPE_ATA, DEVICE_TYPE_ATW from pymelcloud.atw_device import Zone @@ -8,83 +12,85 @@ from homeassistant.components.sensor import ( STATE_CLASS_MEASUREMENT, SensorEntity, ) -from homeassistant.const import ( - ATTR_DEVICE_CLASS, - ATTR_ICON, - ENERGY_KILO_WATT_HOUR, - TEMP_CELSIUS, -) +from homeassistant.const import ENERGY_KILO_WATT_HOUR, TEMP_CELSIUS from homeassistant.util import dt as dt_util from . import MelCloudDevice from .const import DOMAIN -ATTR_MEASUREMENT_NAME = "measurement_name" -ATTR_UNIT = "unit" -ATTR_VALUE_FN = "value_fn" -ATTR_ENABLED_FN = "enabled" -ATA_SENSORS = { - "room_temperature": { - ATTR_MEASUREMENT_NAME: "Room Temperature", - ATTR_ICON: "mdi:thermometer", - ATTR_UNIT: TEMP_CELSIUS, - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_VALUE_FN: lambda x: x.device.room_temperature, - ATTR_ENABLED_FN: lambda x: True, - }, - "energy": { - ATTR_MEASUREMENT_NAME: "Energy", - ATTR_ICON: "mdi:factory", - ATTR_UNIT: ENERGY_KILO_WATT_HOUR, - ATTR_DEVICE_CLASS: DEVICE_CLASS_ENERGY, - ATTR_VALUE_FN: lambda x: x.device.total_energy_consumed, - ATTR_ENABLED_FN: lambda x: x.device.has_energy_consumed_meter, - }, +class SensorMetadata(NamedTuple): + """Metadata for an individual sensor.""" + + measurement_name: str + icon: str + unit: str + device_class: str + value_fn: Callable[[Any], float] + enabled: Callable[[Any], bool] + + +ATA_SENSORS: dict[str, SensorMetadata] = { + "room_temperature": SensorMetadata( + "Room Temperature", + icon="mdi:thermometer", + unit=TEMP_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + value_fn=lambda x: x.device.room_temperature, + enabled=lambda x: True, + ), + "energy": SensorMetadata( + "Energy", + icon="mdi:factory", + unit=ENERGY_KILO_WATT_HOUR, + device_class=DEVICE_CLASS_ENERGY, + value_fn=lambda x: x.device.total_energy_consumed, + enabled=lambda x: x.device.has_energy_consumed_meter, + ), } -ATW_SENSORS = { - "outside_temperature": { - ATTR_MEASUREMENT_NAME: "Outside Temperature", - ATTR_ICON: "mdi:thermometer", - ATTR_UNIT: TEMP_CELSIUS, - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_VALUE_FN: lambda x: x.device.outside_temperature, - ATTR_ENABLED_FN: lambda x: True, - }, - "tank_temperature": { - ATTR_MEASUREMENT_NAME: "Tank Temperature", - ATTR_ICON: "mdi:thermometer", - ATTR_UNIT: TEMP_CELSIUS, - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_VALUE_FN: lambda x: x.device.tank_temperature, - ATTR_ENABLED_FN: lambda x: True, - }, +ATW_SENSORS: dict[str, SensorMetadata] = { + "outside_temperature": SensorMetadata( + "Outside Temperature", + icon="mdi:thermometer", + unit=TEMP_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + value_fn=lambda x: x.device.outside_temperature, + enabled=lambda x: True, + ), + "tank_temperature": SensorMetadata( + "Tank Temperature", + icon="mdi:thermometer", + unit=TEMP_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + value_fn=lambda x: x.device.tank_temperature, + enabled=lambda x: True, + ), } -ATW_ZONE_SENSORS = { - "room_temperature": { - ATTR_MEASUREMENT_NAME: "Room Temperature", - ATTR_ICON: "mdi:thermometer", - ATTR_UNIT: TEMP_CELSIUS, - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_VALUE_FN: lambda zone: zone.room_temperature, - ATTR_ENABLED_FN: lambda x: True, - }, - "flow_temperature": { - ATTR_MEASUREMENT_NAME: "Flow Temperature", - ATTR_ICON: "mdi:thermometer", - ATTR_UNIT: TEMP_CELSIUS, - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_VALUE_FN: lambda zone: zone.flow_temperature, - ATTR_ENABLED_FN: lambda x: True, - }, - "return_temperature": { - ATTR_MEASUREMENT_NAME: "Flow Return Temperature", - ATTR_ICON: "mdi:thermometer", - ATTR_UNIT: TEMP_CELSIUS, - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_VALUE_FN: lambda zone: zone.return_temperature, - ATTR_ENABLED_FN: lambda x: True, - }, +ATW_ZONE_SENSORS: dict[str, SensorMetadata] = { + "room_temperature": SensorMetadata( + "Room Temperature", + icon="mdi:thermometer", + unit=TEMP_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + value_fn=lambda zone: zone.room_temperature, + enabled=lambda x: True, + ), + "flow_temperature": SensorMetadata( + "Flow Temperature", + icon="mdi:thermometer", + unit=TEMP_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + value_fn=lambda zone: zone.flow_temperature, + enabled=lambda x: True, + ), + "return_temperature": SensorMetadata( + "Flow Return Temperature", + icon="mdi:thermometer", + unit=TEMP_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + value_fn=lambda zone: zone.return_temperature, + enabled=lambda x: True, + ), } @@ -93,23 +99,23 @@ async def async_setup_entry(hass, entry, async_add_entities): mel_devices = hass.data[DOMAIN].get(entry.entry_id) async_add_entities( [ - MelDeviceSensor(mel_device, measurement, definition) - for measurement, definition in ATA_SENSORS.items() + MelDeviceSensor(mel_device, measurement, metadata) + for measurement, metadata in ATA_SENSORS.items() for mel_device in mel_devices[DEVICE_TYPE_ATA] - if definition[ATTR_ENABLED_FN](mel_device) + if metadata.enabled(mel_device) ] + [ - MelDeviceSensor(mel_device, measurement, definition) - for measurement, definition in ATW_SENSORS.items() + MelDeviceSensor(mel_device, measurement, metadata) + for measurement, metadata in ATW_SENSORS.items() for mel_device in mel_devices[DEVICE_TYPE_ATW] - if definition[ATTR_ENABLED_FN](mel_device) + if metadata.enabled(mel_device) ] + [ - AtwZoneSensor(mel_device, zone, measurement, definition) + AtwZoneSensor(mel_device, zone, measurement, metadata) for mel_device in mel_devices[DEVICE_TYPE_ATW] for zone in mel_device.device.zones - for measurement, definition, in ATW_ZONE_SENSORS.items() - if definition[ATTR_ENABLED_FN](zone) + for measurement, metadata, in ATW_ZONE_SENSORS.items() + if metadata.enabled(zone) ], True, ) @@ -118,25 +124,25 @@ async def async_setup_entry(hass, entry, async_add_entities): class MelDeviceSensor(SensorEntity): """Representation of a Sensor.""" - def __init__(self, api: MelCloudDevice, measurement, definition): + def __init__(self, api: MelCloudDevice, measurement, metadata: SensorMetadata): """Initialize the sensor.""" self._api = api - self._def = definition + self._metadata = metadata - self._attr_device_class = definition[ATTR_DEVICE_CLASS] - self._attr_icon = definition[ATTR_ICON] - self._attr_name = f"{api.name} {definition[ATTR_MEASUREMENT_NAME]}" + self._attr_device_class = metadata.device_class + self._attr_icon = metadata.icon + self._attr_name = f"{api.name} {metadata.measurement_name}" self._attr_unique_id = f"{api.device.serial}-{api.device.mac}-{measurement}" - self._attr_unit_of_measurement = definition[ATTR_UNIT] + self._attr_unit_of_measurement = metadata.unit self._attr_state_class = STATE_CLASS_MEASUREMENT - if self.device_class == DEVICE_CLASS_ENERGY: + if metadata.device_class == DEVICE_CLASS_ENERGY: self._attr_last_reset = dt_util.utc_from_timestamp(0) @property def state(self): """Return the state of the sensor.""" - return self._def[ATTR_VALUE_FN](self._api) + return self._metadata.value_fn(self._api) async def async_update(self): """Retrieve latest state.""" @@ -151,17 +157,19 @@ class MelDeviceSensor(SensorEntity): class AtwZoneSensor(MelDeviceSensor): """Air-to-Air device sensor.""" - def __init__(self, api: MelCloudDevice, zone: Zone, measurement, definition): + def __init__( + self, api: MelCloudDevice, zone: Zone, measurement, metadata: SensorMetadata + ): """Initialize the sensor.""" if zone.zone_index == 1: full_measurement = measurement else: full_measurement = f"{measurement}-zone-{zone.zone_index}" - super().__init__(api, full_measurement, definition) + super().__init__(api, full_measurement, metadata) self._zone = zone - self._attr_name = f"{api.name} {zone.name} {definition[ATTR_MEASUREMENT_NAME]}" + self._attr_name = f"{api.name} {zone.name} {metadata.measurement_name}" @property def state(self): """Return zone based state.""" - return self._def[ATTR_VALUE_FN](self._zone) + return self._metadata.value_fn(self._zone)