From 0608afd9e9f3097b3742c24fad5c462b7feed9e3 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 10:10:51 +0200 Subject: [PATCH 01/39] Initial diff for sensor against ##33691 --- .../components/plugwise/__init__.py.patch | 27 ++ homeassistant/components/plugwise/sensor.py | 431 ++++++++++++++++++ 2 files changed, 458 insertions(+) create mode 100644 homeassistant/components/plugwise/__init__.py.patch create mode 100644 homeassistant/components/plugwise/sensor.py diff --git a/homeassistant/components/plugwise/__init__.py.patch b/homeassistant/components/plugwise/__init__.py.patch new file mode 100644 index 00000000000000..14c9072d92c9ff --- /dev/null +++ b/homeassistant/components/plugwise/__init__.py.patch @@ -0,0 +1,27 @@ +--- __init__.py.orig 2020-05-28 10:03:10.000000000 +0200 ++++ __init__.py.sensor 2020-05-28 10:08:09.000000000 +0200 +@@ -22,7 +22,8 @@ + + _LOGGER = logging.getLogger(__name__) + +-ALL_PLATFORMS = ["climate"] ++SENSOR_PLATFORMS = ["sensor"] ++ALL_PLATFORMS = ["climate", "sensor"] + + + async def async_setup(hass: HomeAssistant, config: dict): +@@ -100,7 +101,13 @@ + sw_version=api.smile_version[0], + ) + +- for component in ALL_PLATFORMS: ++ platforms = ALL_PLATFORMS ++ ++ single_master_thermostat = api.single_master_thermostat() ++ if single_master_thermostat is None: ++ platforms = SENSOR_PLATFORMS ++ ++ for component in platforms: + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(entry, component) + ) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py new file mode 100644 index 00000000000000..e93cd7a14c74d6 --- /dev/null +++ b/homeassistant/components/plugwise/sensor.py @@ -0,0 +1,431 @@ +"""Plugwise Sensor component for Home Assistant.""" + +import logging +from typing import Dict + +from homeassistant.const import ( + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_ILLUMINANCE, + DEVICE_CLASS_POWER, + DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_TEMPERATURE, + PRESSURE_BAR, + TEMP_CELSIUS, +) +from homeassistant.helpers.entity import Entity + +from . import SmileGateway +from .const import ( + COOL_ICON, + DEVICE_CLASS_GAS, + DEVICE_CLASS_VALVE, + DEVICE_STATE, + DOMAIN, + FLAME_ICON, + IDLE_ICON, +) + +_LOGGER = logging.getLogger(__name__) + +ATTR_TEMPERATURE = [ + "Temperature", + TEMP_CELSIUS, + DEVICE_CLASS_TEMPERATURE, + "mdi:thermometer", +] +ATTR_BATTERY_LEVEL = ["Charge", "%", DEVICE_CLASS_BATTERY, "mdi:battery-high"] +ATTR_ILLUMINANCE = [ + "Illuminance", + "lm", + DEVICE_CLASS_ILLUMINANCE, + "mdi:lightbulb-on-outline", +] +ATTR_PRESSURE = ["Pressure", PRESSURE_BAR, DEVICE_CLASS_PRESSURE, "mdi:water"] +SENSOR_MAP = { + "setpoint": ATTR_TEMPERATURE, + "temperature": ATTR_TEMPERATURE, + "intended_boiler_temperature": ATTR_TEMPERATURE, + "battery": ATTR_BATTERY_LEVEL, + "water_pressure": ATTR_PRESSURE, + "temperature_difference": ATTR_TEMPERATURE, + "electricity_consumed": [ + "Current Consumed Power", + "W", + DEVICE_CLASS_POWER, + "mdi:flash", + ], + "electricity_produced": [ + "Current Produced Power", + "W", + DEVICE_CLASS_POWER, + "mdi:flash", + ], + "electricity_consumed_interval": [ + "Consumed Power Interval", + "Wh", + DEVICE_CLASS_POWER, + "mdi:flash", + ], + "electricity_produced_interval": [ + "Produced Power Interval", + "Wh", + DEVICE_CLASS_POWER, + "mdi:flash", + ], + "outdoor_temperature": ATTR_TEMPERATURE, + "illuminance": ATTR_ILLUMINANCE, + "water_temperature": ATTR_TEMPERATURE, + "return_temperature": ATTR_TEMPERATURE, + "electricity_consumed_off_peak_point": [ + "Current Consumed Power (off peak)", + "W", + DEVICE_CLASS_POWER, + "mdi:flash", + ], + "electricity_consumed_peak_point": [ + "Current Consumed Power", + "W", + DEVICE_CLASS_POWER, + "mdi:flash", + ], + "electricity_consumed_off_peak_cumulative": [ + "Cumulative Consumed Power (off peak)", + "kWh", + DEVICE_CLASS_POWER, + "mdi:gauge", + ], + "electricity_consumed_peak_cumulative": [ + "Cumulative Consumed Power", + "kWh", + DEVICE_CLASS_POWER, + "mdi:gauge", + ], + "electricity_produced_off_peak_point": [ + "Current Consumed Power (off peak)", + "W", + DEVICE_CLASS_POWER, + "mdi:white-balance-sunny", + ], + "electricity_produced_peak_point": [ + "Current Consumed Power", + "W", + DEVICE_CLASS_POWER, + "mdi:white-balance-sunny", + ], + "electricity_produced_off_peak_cumulative": [ + "Cumulative Consumed Power (off peak)", + "kWh", + DEVICE_CLASS_POWER, + "mdi:gauge", + ], + "electricity_produced_peak_cumulative": [ + "Cumulative Consumed Power", + "kWh", + DEVICE_CLASS_POWER, + "mdi:gauge", + ], + "gas_consumed_interval": [ + "Current Consumed Gas", + "m3", + DEVICE_CLASS_GAS, + "mdi:gas-cylinder", + ], + "gas_consumed_cumulative": [ + "Cumulative Consumed Gas", + "m3", + DEVICE_CLASS_GAS, + "mdi:gauge", + ], + "net_electricity_point": [ + "Current net Power", + "W", + DEVICE_CLASS_POWER, + "mdi:solar-power", + ], + "net_electricity_cumulative": [ + "Cumulative net Power", + "kWh", + DEVICE_CLASS_POWER, + "mdi:gauge", + ], + "valve_position": ["Valve Position", "%", DEVICE_CLASS_VALVE, "mdi:valve"], + "modulation_level": ["Heater Modulation Level", "%", "modulation", "mdi:percent"], +} + +INDICATE_ACTIVE_LOCAL_DEVICE = [ + "boiler_state", + "cooling_state", + "flame_state", +] + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up the Smile sensors from a config entry.""" + api = hass.data[DOMAIN][config_entry.entry_id]["api"] + coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"] + + entities = [] + all_entities = api.get_all_devices() + single_thermostat = api.single_master_thermostat() + for dev_id, device in all_entities.items(): + data = api.get_device_data(dev_id) + for sensor, sensor_type in SENSOR_MAP.items(): + if sensor in data: + if data[sensor] is not None: + if "power" in device["types"]: + model = None + + if "plug" in device["types"]: + model = "Metered Switch" + + entities.append( + PwPowerSensor( + api, + coordinator, + device["name"], + dev_id, + sensor, + sensor_type, + model, + ) + ) + else: + entities.append( + PwThermostatSensor( + api, + coordinator, + device["name"], + dev_id, + sensor, + sensor_type, + ) + ) + _LOGGER.info("Added sensor.%s", device["name"]) + + if single_thermostat is not None and not single_thermostat: + idx = 1 + for state in INDICATE_ACTIVE_LOCAL_DEVICE: + if state in data: + if idx == 1: + entities.append( + PwThermostatSensor( + api, + coordinator, + device["name"], + dev_id, + DEVICE_STATE, + None, + ) + ) + _LOGGER.info( + "Added sensor.%s_state", "{}".format(device["name"]) + ) + idx += 1 + + async_add_entities(entities, True) + + +class PwThermostatSensor(SmileGateway, Entity): + """Thermostat (or generic) sensor entities.""" + + def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): + """Set up the Plugwise API.""" + super().__init__(api, coordinator) + + self._api = api + self._dev_id = dev_id + self._sensor_type = sensor_type + self._name = name + self._sensor = sensor + self._state = None + self._model = None + self._unit_of_measurement = None + if self._sensor_type is not None: + self._model = self._sensor_type[0] + self._unit_of_measurement = self._sensor_type[1] + self._dev_class = self._sensor_type[2] + self._icon = self._sensor_type[3] + else: + self._dev_class = "auxiliary" + + self._boiler_state = False + self._heating_state = False + self._cooling_state = False + + if self._dev_id == self._api.heater_id: + self._name = "Auxiliary" + sensorname = sensor.replace("_", " ").title() + self._sensorname = f"{self._name} {sensorname}" + + if self._dev_id == self._api.gateway_id: + self._name = f"Smile {self._name}" + + self._unique_id = f"{dev_id}-{sensor}" + + @property + def device_class(self): + """Device class of this entity.""" + return self._dev_class + + @property + def name(self): + """Return the name of the thermostat, if any.""" + return self._sensorname + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def device_info(self) -> Dict[str, any]: + """Return the device information.""" + + device_information = { + "identifiers": {(DOMAIN, self._dev_id)}, + "name": self._name, + "manufacturer": "Plugwise", + } + + if self._model is not None: + device_information["model"] = self._model + + if self._dev_id != self._api.gateway_id: + device_information["via_device"] = (DOMAIN, self._api.gateway_id) + + return device_information + + @property + def unit_of_measurement(self): + """Return the unit of measurement.""" + return self._unit_of_measurement + + @property + def icon(self): + """Icon for the sensor.""" + if self._sensor_type is None: + if self._boiler_state or self._heating_state: + return FLAME_ICON + if self._cooling_state: + return COOL_ICON + return IDLE_ICON + return self._icon + + def _process_data(self): + """Update the entity.""" + data = self._api.get_device_data(self._dev_id) + + if not data: + _LOGGER.error("Received no data for device %s.", self._name) + else: + if self._sensor in data: + if data[self._sensor] is not None: + measurement = data[self._sensor] + if self._sensor == "battery" or self._sensor == "valve_position": + measurement = measurement * 100 + if self._unit_of_measurement == "%": + measurement = int(measurement) + self._state = measurement + + if "boiler_state" in data: + if data["boiler_state"] is not None: + self._boiler_state = data["boiler_state"] + if "heating_state" in data: + if data["heating_state"] is not None: + self._heating_state = data["heating_state"] + if "cooling_state" in data: + if data["cooling_state"] is not None: + self._cooling_state = data["cooling_state"] + if self._sensor == DEVICE_STATE: + if self._boiler_state or self._heating_state: + self._state = "heating" + elif self._cooling_state: + self._state = "cooling" + else: + self._state = "idle" + + self.async_write_ha_state() + + +class PwPowerSensor(SmileGateway, Entity): + """Power sensor entities.""" + + def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): + """Set up the Plugwise API.""" + super().__init__(api, coordinator) + + self._api = api + self._model = model + self._name = name + self._dev_id = dev_id + self._device = sensor_type[0] + self._unit_of_measurement = sensor_type[1] + self._dev_class = sensor_type[2] + self._icon = sensor_type[3] + self._sensor = sensor + self._state = None + + sensorname = sensor.replace("_", " ").title() + self._sensorname = f"{name} {sensorname}" + + if self._dev_id == self._api.gateway_id: + self._name = f"Smile {self._name}" + + self._unique_id = f"{dev_id}-{sensor}" + + @property + def name(self): + """Return the name of the sensor.""" + return self._sensorname + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return self._icon + + @property + def device_class(self): + """Device class of this entity.""" + return self._dev_class + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def device_info(self) -> Dict[str, any]: + """Return the device information.""" + + device_information = { + "identifiers": {(DOMAIN, self._dev_id)}, + "name": self._name, + "manufacturer": "Plugwise", + "model": self._device, + } + + if self._dev_id != self._api.gateway_id: + device_information["via_device"] = (DOMAIN, self._api.gateway_id) + + return device_information + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + return self._unit_of_measurement + + def _process_data(self): + """Update the entity.""" + data = self._api.get_device_data(self._dev_id) + + if not data: + _LOGGER.error("Received no data for device %s.", self._name) + else: + if self._sensor in data: + if data[self._sensor] is not None: + measurement = data[self._sensor] + if self._unit_of_measurement == "kWh": + measurement = int(measurement / 1000) + self._state = measurement + + self.async_write_ha_state() From 0afaa46d36b7f03630367c780c384c5c69b3cd5b Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 10:19:49 +0200 Subject: [PATCH 02/39] Additional device->entity renaming --- homeassistant/components/plugwise/sensor.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index e93cd7a14c74d6..ed5916d941a25d 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -167,22 +167,22 @@ async def async_setup_entry(hass, config_entry, async_add_entities): entities = [] all_entities = api.get_all_devices() single_thermostat = api.single_master_thermostat() - for dev_id, device in all_entities.items(): + for dev_id, entity in all_entities.items(): data = api.get_device_data(dev_id) for sensor, sensor_type in SENSOR_MAP.items(): if sensor in data: if data[sensor] is not None: - if "power" in device["types"]: + if "power" in entity["types"]: model = None - if "plug" in device["types"]: + if "plug" in entity["types"]: model = "Metered Switch" entities.append( PwPowerSensor( api, coordinator, - device["name"], + entity["name"], dev_id, sensor, sensor_type, @@ -194,13 +194,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities): PwThermostatSensor( api, coordinator, - device["name"], + entity["name"], dev_id, sensor, sensor_type, ) ) - _LOGGER.info("Added sensor.%s", device["name"]) + _LOGGER.info("Added sensor.%s", entity["name"]) if single_thermostat is not None and not single_thermostat: idx = 1 @@ -211,14 +211,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities): PwThermostatSensor( api, coordinator, - device["name"], + entity["name"], dev_id, DEVICE_STATE, None, ) ) _LOGGER.info( - "Added sensor.%s_state", "{}".format(device["name"]) + "Added sensor.%s_state", "{}".format(entity["name"]) ) idx += 1 From 393d7aab8f938073f8b2ba3d164c31da23d0a04a Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 12:48:22 +0200 Subject: [PATCH 03/39] Improve code --- homeassistant/components/plugwise/sensor.py | 28 +++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index ed5916d941a25d..c8f02ea097b9d4 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -202,25 +202,21 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ) _LOGGER.info("Added sensor.%s", entity["name"]) - if single_thermostat is not None and not single_thermostat: - idx = 1 + if single_thermostat is False: for state in INDICATE_ACTIVE_LOCAL_DEVICE: if state in data: - if idx == 1: - entities.append( - PwThermostatSensor( - api, - coordinator, - entity["name"], - dev_id, - DEVICE_STATE, - None, - ) - ) - _LOGGER.info( - "Added sensor.%s_state", "{}".format(entity["name"]) + entities.append( + PwThermostatSensor( + api, + coordinator, + entity["name"], + dev_id, + DEVICE_STATE, + None, ) - idx += 1 + ) + _LOGGER.info("Added sensor.%s_state", "{}".format(entity["name"])) + break async_add_entities(entities, True) From 3c5dd8c0bab5d57c99e97a524e2427f5f58a33c1 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 13:00:37 +0200 Subject: [PATCH 04/39] Remove redundant heating state --- homeassistant/components/plugwise/sensor.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index c8f02ea097b9d4..ee283e443bff2e 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -153,7 +153,6 @@ } INDICATE_ACTIVE_LOCAL_DEVICE = [ - "boiler_state", "cooling_state", "flame_state", ] @@ -244,7 +243,6 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): else: self._dev_class = "auxiliary" - self._boiler_state = False self._heating_state = False self._cooling_state = False @@ -300,7 +298,7 @@ def unit_of_measurement(self): def icon(self): """Icon for the sensor.""" if self._sensor_type is None: - if self._boiler_state or self._heating_state: + if self._heating_state: return FLAME_ICON if self._cooling_state: return COOL_ICON @@ -323,9 +321,6 @@ def _process_data(self): measurement = int(measurement) self._state = measurement - if "boiler_state" in data: - if data["boiler_state"] is not None: - self._boiler_state = data["boiler_state"] if "heating_state" in data: if data["heating_state"] is not None: self._heating_state = data["heating_state"] @@ -333,7 +328,7 @@ def _process_data(self): if data["cooling_state"] is not None: self._cooling_state = data["cooling_state"] if self._sensor == DEVICE_STATE: - if self._boiler_state or self._heating_state: + if self._heating_state: self._state = "heating" elif self._cooling_state: self._state = "cooling" From 1c2e9c7dab5f3ba5679c8af4e2368cb4a84c70a0 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 23:19:40 +0200 Subject: [PATCH 05/39] Remove patch as PR is merged --- .../components/plugwise/__init__.py.patch | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 homeassistant/components/plugwise/__init__.py.patch diff --git a/homeassistant/components/plugwise/__init__.py.patch b/homeassistant/components/plugwise/__init__.py.patch deleted file mode 100644 index 14c9072d92c9ff..00000000000000 --- a/homeassistant/components/plugwise/__init__.py.patch +++ /dev/null @@ -1,27 +0,0 @@ ---- __init__.py.orig 2020-05-28 10:03:10.000000000 +0200 -+++ __init__.py.sensor 2020-05-28 10:08:09.000000000 +0200 -@@ -22,7 +22,8 @@ - - _LOGGER = logging.getLogger(__name__) - --ALL_PLATFORMS = ["climate"] -+SENSOR_PLATFORMS = ["sensor"] -+ALL_PLATFORMS = ["climate", "sensor"] - - - async def async_setup(hass: HomeAssistant, config: dict): -@@ -100,7 +101,13 @@ - sw_version=api.smile_version[0], - ) - -- for component in ALL_PLATFORMS: -+ platforms = ALL_PLATFORMS -+ -+ single_master_thermostat = api.single_master_thermostat() -+ if single_master_thermostat is None: -+ platforms = SENSOR_PLATFORMS -+ -+ for component in platforms: - hass.async_create_task( - hass.config_entries.async_forward_entry_setup(entry, component) - ) From b0cd8beaab2b383feb117234c2a01a05780a484a Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 23:20:52 +0200 Subject: [PATCH 06/39] Remove Class-able defs - improve detection --- homeassistant/components/plugwise/climate.py | 50 +++++--------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index 209fdcdd24243e..2d31da5c4af86d 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -1,7 +1,6 @@ """Plugwise Climate component for Home Assistant.""" import logging -from typing import Dict from Plugwise_Smile.Smile import Smile @@ -80,6 +79,7 @@ def __init__( super().__init__(api, coordinator) self._api = api + self._gateway_id = self._api.gateway_id self._name = name self._dev_id = dev_id self._loc_id = loc_id @@ -92,9 +92,9 @@ def __init__( self._preset_mode = None self._presets = None self._presets_list = None - self._boiler_state = None self._heating_state = None self._cooling_state = None + self._compressor_state = None self._dhw_state = None self._hvac_mode = None self._schema_names = None @@ -105,49 +105,23 @@ def __init__( self._schedule_temp = None self._hvac_mode = None self._single_thermostat = self._api.single_master_thermostat() + self._icon = THERMOSTAT_ICON self._unique_id = f"{dev_id}-climate" @property def hvac_action(self): """Return the current action.""" if self._single_thermostat: - if self._heating_state or self._boiler_state: + if self._heating_state: return CURRENT_HVAC_HEAT if self._cooling_state: return CURRENT_HVAC_COOL return CURRENT_HVAC_IDLE - if self._heating_state is not None or self._boiler_state is not None: + if self._heating_state is not None: if self._setpoint > self._temperature: return CURRENT_HVAC_HEAT return CURRENT_HVAC_IDLE - @property - def name(self): - """Return the name of the thermostat, if any.""" - return self._name - - @property - def device_info(self) -> Dict[str, any]: - """Return the device information.""" - - device_information = { - "identifiers": {(DOMAIN, self._dev_id)}, - "name": self._name, - "manufacturer": "Plugwise", - "model": self._model.replace("_", " ").title(), - } - - if self._dev_id != self._api.gateway_id: - device_information["via_device"] = (DOMAIN, self._api.gateway_id) - del device_information["via_device"] - - return device_information - - @property - def icon(self): - """Return the icon to use in the frontend.""" - return THERMOSTAT_ICON - @property def supported_features(self): """Return the list of supported features.""" @@ -172,8 +146,8 @@ def preset_modes(self): @property def hvac_modes(self): """Return the available hvac modes list.""" - if self._heating_state is not None or self._boiler_state is not None: - if self._cooling_state is not None: + if self._heating_state is not None: + if self._compressor_state is not None: return HVAC_MODES_HEAT_COOL return HVAC_MODES_HEAT_ONLY @@ -286,21 +260,21 @@ def _process_data(self): if "active_preset" in climate_data: self._preset_mode = climate_data["active_preset"] - if "boiler_state" in heater_central_data: - if heater_central_data["boiler_state"] is not None: - self._boiler_state = heater_central_data["boiler_state"] if "heating_state" in heater_central_data: if heater_central_data["heating_state"] is not None: self._heating_state = heater_central_data["heating_state"] if "cooling_state" in heater_central_data: if heater_central_data["cooling_state"] is not None: self._cooling_state = heater_central_data["cooling_state"] + if "compressor_state" in heater_central_data: + if heater_central_data["compressor_state"] is not None: + self._compressor_state = heater_central_data["compressor_state"] if self._schema_status: self._hvac_mode = HVAC_MODE_AUTO - elif self._heating_state is not None or self._boiler_state is not None: + elif self._heating_state is not None: self._hvac_mode = HVAC_MODE_HEAT - if self._cooling_state is not None: + if self._compressor_state is not None: self._hvac_mode = HVAC_MODE_HEAT_COOL self.async_write_ha_state() From d1eda7ba756539b18070c7dde77d7a123facb342 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 23:21:47 +0200 Subject: [PATCH 07/39] Apply patch, improve class, add new class --- homeassistant/components/plugwise/__init__.py | 86 ++++++++++++++++++- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index c6509091e1cec9..ea821ba1c741d3 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -3,6 +3,7 @@ import asyncio from datetime import timedelta import logging +from typing import Dict from Plugwise_Smile.Smile import Smile import async_timeout @@ -16,13 +17,14 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import DOMAIN +from .const import DOMAIN, THERMOSTAT_ICON CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA) _LOGGER = logging.getLogger(__name__) -ALL_PLATFORMS = ["climate"] +SENSOR_PLATFORMS = ["sensor"] +ALL_PLATFORMS = ["climate", "sensor"] async def async_setup(hass: HomeAssistant, config: dict): @@ -100,7 +102,13 @@ async def async_update_data(): sw_version=api.smile_version[0], ) - for component in ALL_PLATFORMS: + platforms = ALL_PLATFORMS + + single_master_thermostat = api.single_master_thermostat() + if single_master_thermostat is None: + platforms = SENSOR_PLATFORMS + + for component in platforms: hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, component) ) @@ -128,10 +136,15 @@ class SmileGateway(Entity): """Represent Smile Gateway.""" def __init__(self, api, coordinator): - """Initialise the sensor.""" + """Initialise the gateway.""" self._api = api self._coordinator = coordinator self._unique_id = None + self._name = None + self._icon = None + self._dev_id = None + self._model = None + self._gateway_id = None @property def unique_id(self): @@ -148,6 +161,38 @@ def available(self): """Return True if entity is available.""" return self._coordinator.last_update_success + @property + def name(self): + """Return the name of the entity, if any.""" + if not self._name: + pass + return self._name + + @property + def icon(self): + """Return the icon to use in the frontend.""" + if not self._icon: + return THERMOSTAT_ICON + return self._icon + + @property + def device_info(self) -> Dict[str, any]: + """Return the device information.""" + + device_information = { + "identifiers": {(DOMAIN, self._dev_id)}, + "name": self._name, + "manufacturer": "Plugwise", + } + + if self._model is not None: + device_information["model"] = self._model.replace("_", " ").title() + + if self._dev_id != self._gateway_id: + device_information["via_device"] = (DOMAIN, self._gateway_id) + + return device_information + async def async_added_to_hass(self): """Subscribe to updates.""" self.async_on_remove(self._coordinator.async_add_listener(self._process_data)) @@ -159,3 +204,36 @@ def _process_data(self): async def async_update(self): """Update the entity.""" await self._coordinator.async_request_refresh() + + +class SmileSensor(SmileGateway): + """Represent Smile Sensors.""" + + def __init__(self, api, coordinator): + """Initialise the sensor.""" + super().__init__(api, coordinator) + + self._dev_class = None + self._state = None + self._unit_of_measurement = None + + @property + def device_class(self): + """Device class of this entity.""" + if not self._dev_class: + pass + return self._dev_class + + @property + def state(self): + """Device class of this entity.""" + if not self._state: + pass + return self._state + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + if not self._unit_of_measurement: + pass + return self._unit_of_measurement From e324f61749137ff3f543bcdbb603986ccc22e497 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 28 May 2020 23:22:21 +0200 Subject: [PATCH 08/39] Make sensor use new class --- homeassistant/components/plugwise/const.py | 1 + homeassistant/components/plugwise/sensor.py | 246 +++++++------------- 2 files changed, 86 insertions(+), 161 deletions(-) diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 2f804ef09a323b..42f5fdd9e18956 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -11,6 +11,7 @@ DEFAULT_SCAN_INTERVAL = {"thermostat": 60, "power": 10} DEVICE_CLASS_GAS = "gas" +DEVICE_CLASS_VALVE = "valve" # Configuration directives CONF_MIN_TEMP = "min_temp" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index ee283e443bff2e..67f4ad29ae4360 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -1,7 +1,6 @@ """Plugwise Sensor component for Home Assistant.""" import logging -from typing import Dict from homeassistant.const import ( DEVICE_CLASS_BATTERY, @@ -14,7 +13,7 @@ ) from homeassistant.helpers.entity import Entity -from . import SmileGateway +from . import SmileSensor from .const import ( COOL_ICON, DEVICE_CLASS_GAS, @@ -170,36 +169,38 @@ async def async_setup_entry(hass, config_entry, async_add_entities): data = api.get_device_data(dev_id) for sensor, sensor_type in SENSOR_MAP.items(): if sensor in data: - if data[sensor] is not None: - if "power" in entity["types"]: - model = None - - if "plug" in entity["types"]: - model = "Metered Switch" - - entities.append( - PwPowerSensor( - api, - coordinator, - entity["name"], - dev_id, - sensor, - sensor_type, - model, - ) + if data[sensor] is None: + continue + + if "power" in entity["types"]: + model = None + + if "plug" in entity["types"]: + model = "Metered Switch" + + entities.append( + PwPowerSensor( + api, + coordinator, + entity["name"], + dev_id, + sensor, + sensor_type, + model, ) - else: - entities.append( - PwThermostatSensor( - api, - coordinator, - entity["name"], - dev_id, - sensor, - sensor_type, - ) + ) + else: + entities.append( + PwThermostatSensor( + api, + coordinator, + entity["name"], + dev_id, + sensor, + sensor_type, ) - _LOGGER.info("Added sensor.%s", entity["name"]) + ) + _LOGGER.info("Added sensor.%s", entity["name"]) if single_thermostat is False: for state in INDICATE_ACTIVE_LOCAL_DEVICE: @@ -220,7 +221,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_entities(entities, True) -class PwThermostatSensor(SmileGateway, Entity): +class PwThermostatSensor(SmileSensor, Entity): """Thermostat (or generic) sensor entities.""" def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): @@ -228,9 +229,10 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): super().__init__(api, coordinator) self._api = api + self._gateway_id = self._api.gateway_id self._dev_id = dev_id self._sensor_type = sensor_type - self._name = name + self._entity_name = name self._sensor = sensor self._state = None self._model = None @@ -247,98 +249,58 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): self._cooling_state = False if self._dev_id == self._api.heater_id: - self._name = "Auxiliary" + self._entity_name = "Auxiliary" sensorname = sensor.replace("_", " ").title() - self._sensorname = f"{self._name} {sensorname}" + self._name = f"{self._entity_name} {sensorname}" if self._dev_id == self._api.gateway_id: - self._name = f"Smile {self._name}" + self._entity_name = f"Smile {self._entity_name}" self._unique_id = f"{dev_id}-{sensor}" - @property - def device_class(self): - """Device class of this entity.""" - return self._dev_class - - @property - def name(self): - """Return the name of the thermostat, if any.""" - return self._sensorname - - @property - def state(self): - """Return the state of the sensor.""" - return self._state - - @property - def device_info(self) -> Dict[str, any]: - """Return the device information.""" - - device_information = { - "identifiers": {(DOMAIN, self._dev_id)}, - "name": self._name, - "manufacturer": "Plugwise", - } - - if self._model is not None: - device_information["model"] = self._model - - if self._dev_id != self._api.gateway_id: - device_information["via_device"] = (DOMAIN, self._api.gateway_id) - - return device_information - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return self._unit_of_measurement - - @property - def icon(self): - """Icon for the sensor.""" - if self._sensor_type is None: - if self._heating_state: - return FLAME_ICON - if self._cooling_state: - return COOL_ICON - return IDLE_ICON - return self._icon - def _process_data(self): """Update the entity.""" data = self._api.get_device_data(self._dev_id) if not data: - _LOGGER.error("Received no data for device %s.", self._name) - else: - if self._sensor in data: - if data[self._sensor] is not None: - measurement = data[self._sensor] - if self._sensor == "battery" or self._sensor == "valve_position": - measurement = measurement * 100 - if self._unit_of_measurement == "%": - measurement = int(measurement) - self._state = measurement - - if "heating_state" in data: - if data["heating_state"] is not None: - self._heating_state = data["heating_state"] - if "cooling_state" in data: - if data["cooling_state"] is not None: - self._cooling_state = data["cooling_state"] - if self._sensor == DEVICE_STATE: - if self._heating_state: - self._state = "heating" - elif self._cooling_state: - self._state = "cooling" - else: - self._state = "idle" + _LOGGER.error("Received no data for device %s.", self._entity_name) + self.async_write_ha_state() + return + + if self._sensor in data: + if data[self._sensor] is not None: + measurement = data[self._sensor] + if self._sensor == "battery" or self._sensor == "valve_position": + measurement = measurement * 100 + if self._unit_of_measurement == "%": + measurement = int(measurement) + self._state = measurement + + if "heating_state" in data: + if data["heating_state"] is not None: + self._heating_state = data["heating_state"] + if "cooling_state" in data: + if data["cooling_state"] is not None: + self._cooling_state = data["cooling_state"] + if self._sensor == DEVICE_STATE: + if self._heating_state: + self._state = "heating" + elif self._cooling_state: + self._state = "cooling" + else: + self._state = "idle" + + if self._sensor_type is None: + self._icon = IDLE_ICON + if self._heating_state: + self._icon = FLAME_ICON + if self._cooling_state: + self._icon = COOL_ICON self.async_write_ha_state() -class PwPowerSensor(SmileGateway, Entity): +class PwPowerSensor(SmileSensor, Entity): """Power sensor entities.""" def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): @@ -346,8 +308,9 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): super().__init__(api, coordinator) self._api = api + self._gateway_id = self._api.gateway_id self._model = model - self._name = name + self._entity_name = name self._dev_id = dev_id self._device = sensor_type[0] self._unit_of_measurement = sensor_type[1] @@ -357,66 +320,27 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): self._state = None sensorname = sensor.replace("_", " ").title() - self._sensorname = f"{name} {sensorname}" + self._name = f"{name} {sensorname}" if self._dev_id == self._api.gateway_id: - self._name = f"Smile {self._name}" + self._entity_name = f"Smile {self._entity_name}" self._unique_id = f"{dev_id}-{sensor}" - @property - def name(self): - """Return the name of the sensor.""" - return self._sensorname - - @property - def icon(self): - """Icon to use in the frontend, if any.""" - return self._icon - - @property - def device_class(self): - """Device class of this entity.""" - return self._dev_class - - @property - def state(self): - """Return the state of the sensor.""" - return self._state - - @property - def device_info(self) -> Dict[str, any]: - """Return the device information.""" - - device_information = { - "identifiers": {(DOMAIN, self._dev_id)}, - "name": self._name, - "manufacturer": "Plugwise", - "model": self._device, - } - - if self._dev_id != self._api.gateway_id: - device_information["via_device"] = (DOMAIN, self._api.gateway_id) - - return device_information - - @property - def unit_of_measurement(self): - """Return the unit of measurement of this entity, if any.""" - return self._unit_of_measurement - def _process_data(self): """Update the entity.""" data = self._api.get_device_data(self._dev_id) if not data: - _LOGGER.error("Received no data for device %s.", self._name) - else: - if self._sensor in data: - if data[self._sensor] is not None: - measurement = data[self._sensor] - if self._unit_of_measurement == "kWh": - measurement = int(measurement / 1000) - self._state = measurement + _LOGGER.error("Received no data for device %s.", self._entity_name) + self.async_write_ha_state() + return + + if self._sensor in data: + if data[self._sensor] is not None: + measurement = data[self._sensor] + if self._unit_of_measurement == "kWh": + measurement = int(measurement / 1000) + self._state = measurement self.async_write_ha_state() From bb0aa73a57d076737578bc99c2c7e299507db973 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Fri, 29 May 2020 12:32:10 +0200 Subject: [PATCH 09/39] Fixes from additional review on parent --- homeassistant/components/plugwise/climate.py | 19 ++++++++----------- .../components/plugwise/config_flow.py | 2 +- .../components/plugwise/manifest.json | 1 - homeassistant/components/plugwise/sensor.py | 4 ++-- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index 2d31da5c4af86d..0b5b5142ddcdaa 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -46,9 +46,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): "zone_thermostat", "thermostatic_radiator_valve", ] - all_entities = api.get_all_devices() + all_devices = api.get_all_devices() - for dev_id, device in all_entities.items(): + for dev_id, device in all_devices.items(): if device["class"] not in thermostat_classes: continue @@ -260,15 +260,12 @@ def _process_data(self): if "active_preset" in climate_data: self._preset_mode = climate_data["active_preset"] - if "heating_state" in heater_central_data: - if heater_central_data["heating_state"] is not None: - self._heating_state = heater_central_data["heating_state"] - if "cooling_state" in heater_central_data: - if heater_central_data["cooling_state"] is not None: - self._cooling_state = heater_central_data["cooling_state"] - if "compressor_state" in heater_central_data: - if heater_central_data["compressor_state"] is not None: - self._compressor_state = heater_central_data["compressor_state"] + if heater_central_data.get("heating_state") is not None: + self._heating_state = heater_central_data["heating_state"] + if heater_central_data.get("cooling_state") is not None: + self._cooling_state = heater_central_data["cooling_state"] + if heater_central_data.get("compressor_state") is not None: + self._compressor_state = heater_central_data["compressor_state"] if self._schema_status: self._hvac_mode = HVAC_MODE_AUTO diff --git a/homeassistant/components/plugwise/config_flow.py b/homeassistant/components/plugwise/config_flow.py index 7182665a506355..8f82a10757655b 100644 --- a/homeassistant/components/plugwise/config_flow.py +++ b/homeassistant/components/plugwise/config_flow.py @@ -47,7 +47,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def async_step_user(self, user_input=None): """Handle the initial step.""" errors = {} - api = None + if user_input is not None: try: diff --git a/homeassistant/components/plugwise/manifest.json b/homeassistant/components/plugwise/manifest.json index 2a0d5a1e0fcd4d..baecf48568291b 100644 --- a/homeassistant/components/plugwise/manifest.json +++ b/homeassistant/components/plugwise/manifest.json @@ -3,7 +3,6 @@ "name": "Plugwise", "documentation": "https://www.home-assistant.io/integrations/plugwise", "requirements": ["Plugwise_Smile==0.2.10"], - "dependencies": [], "codeowners": ["@CoMPaTech", "@bouwew"], "config_flow": true } diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 67f4ad29ae4360..4c05c33a5a2d75 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -163,9 +163,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"] entities = [] - all_entities = api.get_all_devices() + all_devices = api.get_all_devices() single_thermostat = api.single_master_thermostat() - for dev_id, entity in all_entities.items(): + for dev_id, entity in all_devices.items(): data = api.get_device_data(dev_id) for sensor, sensor_type in SENSOR_MAP.items(): if sensor in data: From 0fe9c2a6655f8018ab1fb09499fc94ce61f5973d Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 09:59:37 +0200 Subject: [PATCH 10/39] Update homeassistant/components/plugwise/__init__.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index ea821ba1c741d3..49b26110554bd9 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -165,7 +165,7 @@ def available(self): def name(self): """Return the name of the entity, if any.""" if not self._name: - pass + return None return self._name @property From b189a53cd10c65e320effba95031203e48dbb3f5 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 09:59:54 +0200 Subject: [PATCH 11/39] Update homeassistant/components/plugwise/__init__.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index 49b26110554bd9..cf77e60e300704 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -221,7 +221,7 @@ def __init__(self, api, coordinator): def device_class(self): """Device class of this entity.""" if not self._dev_class: - pass + return None return self._dev_class @property From 8c33e8a40a132723ec2f5dd0f5fd3c1368f67997 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:00:04 +0200 Subject: [PATCH 12/39] Update homeassistant/components/plugwise/__init__.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index cf77e60e300704..c0d4c5acb59b83 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -228,7 +228,7 @@ def device_class(self): def state(self): """Device class of this entity.""" if not self._state: - pass + return None return self._state @property From 3e22c195ac7a92dfe0aba31005b28fa44e0f07d9 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:00:15 +0200 Subject: [PATCH 13/39] Update homeassistant/components/plugwise/__init__.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index c0d4c5acb59b83..244a56fda1b355 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -235,5 +235,5 @@ def state(self): def unit_of_measurement(self): """Return the unit of measurement of this entity, if any.""" if not self._unit_of_measurement: - pass + return None return self._unit_of_measurement From d72afd0f8a3dbda84f60e839427a3fa7d9e5d809 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:03:34 +0200 Subject: [PATCH 14/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 4c05c33a5a2d75..654d47be4abf67 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -143,7 +143,7 @@ ], "net_electricity_cumulative": [ "Cumulative net Power", - "kWh", + ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, "mdi:gauge", ], From 9a90b757174f3e649ed53d0cf4ef30e6862e5dc2 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:03:43 +0200 Subject: [PATCH 15/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 654d47be4abf67..0d67a6960f0d3c 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -107,7 +107,7 @@ ], "electricity_produced_peak_point": [ "Current Consumed Power", - "W", + POWER_WATT, DEVICE_CLASS_POWER, "mdi:white-balance-sunny", ], From de0abf0de97826a720076068e76d080b75e6da1a Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:03:51 +0200 Subject: [PATCH 16/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 0d67a6960f0d3c..82067542621823 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -113,7 +113,7 @@ ], "electricity_produced_off_peak_cumulative": [ "Cumulative Consumed Power (off peak)", - "kWh", + ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, "mdi:gauge", ], From 98a2ced5a06c4027b5569f637c5ea2fd97678394 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:04:00 +0200 Subject: [PATCH 17/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 82067542621823..76acd09bb72191 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -101,7 +101,7 @@ ], "electricity_produced_off_peak_point": [ "Current Consumed Power (off peak)", - "W", + "POWER_WATT, DEVICE_CLASS_POWER, "mdi:white-balance-sunny", ], From 4d30d752d3574c320fea6945722d29709d43b4b7 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:04:08 +0200 Subject: [PATCH 18/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 76acd09bb72191..a7886f5e4a9e99 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -61,7 +61,7 @@ ], "electricity_consumed_interval": [ "Consumed Power Interval", - "Wh", + ENERGY_WATT_HOUR, DEVICE_CLASS_POWER, "mdi:flash", ], From 088611b2820c2aad7c25c8774433b1cf78511165 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:04:21 +0200 Subject: [PATCH 19/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index a7886f5e4a9e99..ffd02983b4ec71 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -119,7 +119,7 @@ ], "electricity_produced_peak_cumulative": [ "Cumulative Consumed Power", - "kWh", + ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, "mdi:gauge", ], From f626761b5fe15ae32b88a7ce8ba7d833d089f4bc Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 10:04:35 +0200 Subject: [PATCH 20/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index ffd02983b4ec71..43e9f2f65b9960 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -137,7 +137,7 @@ ], "net_electricity_point": [ "Current net Power", - "W", + POWER_WATT, DEVICE_CLASS_POWER, "mdi:solar-power", ], From 971e4b05d9a48aebd9e52ec1c8c40b6e2e9fd1ce Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 10:10:35 +0200 Subject: [PATCH 21/39] Added consts --- homeassistant/components/plugwise/sensor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 43e9f2f65b9960..515fea2bb32e65 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -8,6 +8,9 @@ DEVICE_CLASS_POWER, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, + ENERGY_KILO_WATT_HOUR, + ENERGY_WATT_HOUR, + POWER_WATT, PRESSURE_BAR, TEMP_CELSIUS, ) @@ -101,7 +104,7 @@ ], "electricity_produced_off_peak_point": [ "Current Consumed Power (off peak)", - "POWER_WATT, + POWER_WATT, DEVICE_CLASS_POWER, "mdi:white-balance-sunny", ], From 0f76337d1df75593675e58cff446e78ffef9b422 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 10:24:05 +0200 Subject: [PATCH 22/39] Replace other consts as well --- homeassistant/components/plugwise/sensor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 515fea2bb32e65..8c48edab4cf2c1 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -92,13 +92,13 @@ ], "electricity_consumed_off_peak_cumulative": [ "Cumulative Consumed Power (off peak)", - "kWh", + ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, "mdi:gauge", ], "electricity_consumed_peak_cumulative": [ "Cumulative Consumed Power", - "kWh", + ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, "mdi:gauge", ], @@ -342,7 +342,7 @@ def _process_data(self): if self._sensor in data: if data[self._sensor] is not None: measurement = data[self._sensor] - if self._unit_of_measurement == "kWh": + if self._unit_of_measurement == ENERGY_KILO_WATT_HOUR: measurement = int(measurement / 1000) self._state = measurement From 4a4080f1f93439821bd3da444130027781440d99 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 10:34:04 +0200 Subject: [PATCH 23/39] Replace one more set of const --- homeassistant/components/plugwise/sensor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 8c48edab4cf2c1..0bbc3189a160b3 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -13,6 +13,7 @@ POWER_WATT, PRESSURE_BAR, TEMP_CELSIUS, + VOLUME_CUBIC_METERS, ) from homeassistant.helpers.entity import Entity @@ -128,13 +129,13 @@ ], "gas_consumed_interval": [ "Current Consumed Gas", - "m3", + VOLUME_CUBIC_METERS, DEVICE_CLASS_GAS, "mdi:gas-cylinder", ], "gas_consumed_cumulative": [ "Cumulative Consumed Gas", - "m3", + VOLUME_CUBIC_METERS, DEVICE_CLASS_GAS, "mdi:gauge", ], From 377062d73f843287f08d7341799062bab9813409 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 11:23:45 +0200 Subject: [PATCH 24/39] Fix initial processing as discussed --- homeassistant/components/plugwise/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index 244a56fda1b355..876ea5df3918e5 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -195,6 +195,7 @@ def device_info(self) -> Dict[str, any]: async def async_added_to_hass(self): """Subscribe to updates.""" + self._process_data() self.async_on_remove(self._coordinator.async_add_listener(self._process_data)) def _process_data(self): From 57529ecf2d98bd2a2da310cb1bd54e05ddd7f4bf Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 13:35:52 +0200 Subject: [PATCH 25/39] Improve consts move Sensor childclass --- homeassistant/components/plugwise/__init__.py | 33 ------- homeassistant/components/plugwise/const.py | 6 +- homeassistant/components/plugwise/sensor.py | 97 +++++++++++++++---- 3 files changed, 84 insertions(+), 52 deletions(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index 876ea5df3918e5..a1927b6cf97ad9 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -205,36 +205,3 @@ def _process_data(self): async def async_update(self): """Update the entity.""" await self._coordinator.async_request_refresh() - - -class SmileSensor(SmileGateway): - """Represent Smile Sensors.""" - - def __init__(self, api, coordinator): - """Initialise the sensor.""" - super().__init__(api, coordinator) - - self._dev_class = None - self._state = None - self._unit_of_measurement = None - - @property - def device_class(self): - """Device class of this entity.""" - if not self._dev_class: - return None - return self._dev_class - - @property - def state(self): - """Device class of this entity.""" - if not self._state: - return None - return self._state - - @property - def unit_of_measurement(self): - """Return the unit of measurement of this entity, if any.""" - if not self._unit_of_measurement: - return None - return self._unit_of_measurement diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 42f5fdd9e18956..1477fadca720c3 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -23,7 +23,10 @@ CONF_GAS = "gas" ATTR_ILLUMINANCE = "illuminance" +UNIT_LUMEN = "lm" + CURRENT_HVAC_DHW = "hot_water" + DEVICE_STATE = "device_state" SCHEDULE_ON = "true" @@ -40,4 +43,5 @@ POWER_ICON = "mdi:flash" POWER_FAILURE_ICON = "mdi:flash-off" SWELL_SAG_ICON = "mdi:pulse" -VALVE_ICON = "mdi:valve" +VALVE_OPEN_ICON = "mdi:valve-open" +VALVE_CLOSED_ICON = "mdi:valve-closed" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 0bbc3189a160b3..dfa7e57b65ed7f 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -13,11 +13,12 @@ POWER_WATT, PRESSURE_BAR, TEMP_CELSIUS, + UNIT_PERCENTAGE, VOLUME_CUBIC_METERS, ) from homeassistant.helpers.entity import Entity -from . import SmileSensor +from . import SmileGateway from .const import ( COOL_ICON, DEVICE_CLASS_GAS, @@ -26,6 +27,7 @@ DOMAIN, FLAME_ICON, IDLE_ICON, + UNIT_LUMEN, ) _LOGGER = logging.getLogger(__name__) @@ -36,30 +38,40 @@ DEVICE_CLASS_TEMPERATURE, "mdi:thermometer", ] -ATTR_BATTERY_LEVEL = ["Charge", "%", DEVICE_CLASS_BATTERY, "mdi:battery-high"] +ATTR_BATTERY_LEVEL = [ + "Charge", + UNIT_PERCENTAGE, + DEVICE_CLASS_BATTERY, + "mdi:battery-high", +] ATTR_ILLUMINANCE = [ "Illuminance", - "lm", + UNIT_LUMEN, DEVICE_CLASS_ILLUMINANCE, "mdi:lightbulb-on-outline", ] ATTR_PRESSURE = ["Pressure", PRESSURE_BAR, DEVICE_CLASS_PRESSURE, "mdi:water"] -SENSOR_MAP = { + +TEMP_SENSOR_MAP = { "setpoint": ATTR_TEMPERATURE, "temperature": ATTR_TEMPERATURE, "intended_boiler_temperature": ATTR_TEMPERATURE, - "battery": ATTR_BATTERY_LEVEL, - "water_pressure": ATTR_PRESSURE, "temperature_difference": ATTR_TEMPERATURE, + "outdoor_temperature": ATTR_TEMPERATURE, + "water_temperature": ATTR_TEMPERATURE, + "return_temperature": ATTR_TEMPERATURE, +} + +ENERGY_SENSOR_MAP = { "electricity_consumed": [ "Current Consumed Power", - "W", + POWER_WATT, DEVICE_CLASS_POWER, "mdi:flash", ], "electricity_produced": [ "Current Produced Power", - "W", + POWER_WATT, DEVICE_CLASS_POWER, "mdi:flash", ], @@ -71,23 +83,19 @@ ], "electricity_produced_interval": [ "Produced Power Interval", - "Wh", + ENERGY_WATT_HOUR, DEVICE_CLASS_POWER, "mdi:flash", ], - "outdoor_temperature": ATTR_TEMPERATURE, - "illuminance": ATTR_ILLUMINANCE, - "water_temperature": ATTR_TEMPERATURE, - "return_temperature": ATTR_TEMPERATURE, "electricity_consumed_off_peak_point": [ "Current Consumed Power (off peak)", - "W", + POWER_WATT, DEVICE_CLASS_POWER, "mdi:flash", ], "electricity_consumed_peak_point": [ "Current Consumed Power", - "W", + POWER_WATT, DEVICE_CLASS_POWER, "mdi:flash", ], @@ -151,8 +159,24 @@ DEVICE_CLASS_POWER, "mdi:gauge", ], - "valve_position": ["Valve Position", "%", DEVICE_CLASS_VALVE, "mdi:valve"], - "modulation_level": ["Heater Modulation Level", "%", "modulation", "mdi:percent"], +} + +MISC_SENSOR_MAP = { + "battery": ATTR_BATTERY_LEVEL, + "illuminance": ATTR_ILLUMINANCE, + "modulation_level": [ + "Heater Modulation Level", + UNIT_PERCENTAGE, + "modulation", + "mdi:percent", + ], + "valve_position": [ + "Valve Position", + UNIT_PERCENTAGE, + DEVICE_CLASS_VALVE, + "mdi:valve", + ], + "water_pressure": ATTR_PRESSURE, } INDICATE_ACTIVE_LOCAL_DEVICE = [ @@ -171,7 +195,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): single_thermostat = api.single_master_thermostat() for dev_id, entity in all_devices.items(): data = api.get_device_data(dev_id) - for sensor, sensor_type in SENSOR_MAP.items(): + for sensor, sensor_type in { + **TEMP_SENSOR_MAP, + **ENERGY_SENSOR_MAP, + **MISC_SENSOR_MAP, + }.items(): if sensor in data: if data[sensor] is None: continue @@ -225,6 +253,39 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_entities(entities, True) +class SmileSensor(SmileGateway): + """Represent Smile Sensors.""" + + def __init__(self, api, coordinator): + """Initialise the sensor.""" + super().__init__(api, coordinator) + + self._dev_class = None + self._state = None + self._unit_of_measurement = None + + @property + def device_class(self): + """Device class of this entity.""" + if not self._dev_class: + return None + return self._dev_class + + @property + def state(self): + """Device class of this entity.""" + if not self._state: + return None + return self._state + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + if not self._unit_of_measurement: + return None + return self._unit_of_measurement + + class PwThermostatSensor(SmileSensor, Entity): """Thermostat (or generic) sensor entities.""" From f9c6cfa74f9735ece526d39da6bee40fc437aeac Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 16:10:44 +0200 Subject: [PATCH 26/39] Remove introduced dev_classes --- homeassistant/components/plugwise/const.py | 3 -- homeassistant/components/plugwise/sensor.py | 31 ++++++--------------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 1477fadca720c3..0a0a3a0f117bd6 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -10,9 +10,6 @@ DEFAULT_MAX_TEMP = 30 DEFAULT_SCAN_INTERVAL = {"thermostat": 60, "power": 10} -DEVICE_CLASS_GAS = "gas" -DEVICE_CLASS_VALVE = "valve" - # Configuration directives CONF_MIN_TEMP = "min_temp" CONF_MAX_TEMP = "max_temp" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index dfa7e57b65ed7f..05c1b2f5bb4693 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -19,16 +19,7 @@ from homeassistant.helpers.entity import Entity from . import SmileGateway -from .const import ( - COOL_ICON, - DEVICE_CLASS_GAS, - DEVICE_CLASS_VALVE, - DEVICE_STATE, - DOMAIN, - FLAME_ICON, - IDLE_ICON, - UNIT_LUMEN, -) +from .const import COOL_ICON, DEVICE_STATE, DOMAIN, FLAME_ICON, IDLE_ICON, UNIT_LUMEN _LOGGER = logging.getLogger(__name__) @@ -138,13 +129,13 @@ "gas_consumed_interval": [ "Current Consumed Gas", VOLUME_CUBIC_METERS, - DEVICE_CLASS_GAS, + None, "mdi:gas-cylinder", ], "gas_consumed_cumulative": [ "Cumulative Consumed Gas", VOLUME_CUBIC_METERS, - DEVICE_CLASS_GAS, + None, "mdi:gauge", ], "net_electricity_point": [ @@ -170,12 +161,7 @@ "modulation", "mdi:percent", ], - "valve_position": [ - "Valve Position", - UNIT_PERCENTAGE, - DEVICE_CLASS_VALVE, - "mdi:valve", - ], + "valve_position": ["Valve Position", UNIT_PERCENTAGE, None, "mdi:valve"], "water_pressure": ATTR_PRESSURE, } @@ -302,19 +288,18 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): self._state = None self._model = None self._unit_of_measurement = None + self._heating_state = False + self._cooling_state = False + if self._sensor_type is not None: self._model = self._sensor_type[0] self._unit_of_measurement = self._sensor_type[1] self._dev_class = self._sensor_type[2] self._icon = self._sensor_type[3] - else: - self._dev_class = "auxiliary" - - self._heating_state = False - self._cooling_state = False if self._dev_id == self._api.heater_id: self._entity_name = "Auxiliary" + sensorname = sensor.replace("_", " ").title() self._name = f"{self._entity_name} {sensorname}" From 4158c94f5a67ad823727a1b4632a6c7364f69ca6 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 17:18:02 +0200 Subject: [PATCH 27/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 05c1b2f5bb4693..2500f530d66d28 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -322,7 +322,7 @@ def _process_data(self): measurement = data[self._sensor] if self._sensor == "battery" or self._sensor == "valve_position": measurement = measurement * 100 - if self._unit_of_measurement == "%": + if self._unit_of_measurement == UNIT_PERCENTAGE: measurement = int(measurement) self._state = measurement From 3ff982180cf78a87d39283d67c85f6a86ddd1731 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 30 May 2020 17:32:37 +0200 Subject: [PATCH 28/39] Update homeassistant/components/plugwise/sensor.py Co-authored-by: J. Nick Koston --- homeassistant/components/plugwise/sensor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 2500f530d66d28..08a0fffd90d43d 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -292,10 +292,10 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): self._cooling_state = False if self._sensor_type is not None: - self._model = self._sensor_type[0] - self._unit_of_measurement = self._sensor_type[1] - self._dev_class = self._sensor_type[2] - self._icon = self._sensor_type[3] + self._model = self._sensor_type[SENSOR_MAP_MODEL] + self._unit_of_measurement = self._sensor_type[SENSOR_MAP_UOM] + self._dev_class = self._sensor_type[SENSOR_MAP_DEVICE_CLASS] + self._icon = self._sensor_type[SENSOR_MAP_ICON] if self._dev_id == self._api.heater_id: self._entity_name = "Auxiliary" From ded76aef2c6b54d570a40eef5ad424d4e8624212 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 17:38:14 +0200 Subject: [PATCH 29/39] Add consts for typemapping as suggested --- homeassistant/components/plugwise/const.py | 6 ++++++ homeassistant/components/plugwise/sensor.py | 24 ++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 0a0a3a0f117bd6..fee82230e2fbab 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -1,6 +1,12 @@ """Constant for Plugwise component.""" DOMAIN = "plugwise" +# Sensor mapping +SENSOR_MAP_MODEL = 0 +SENSOR_MAP_UOM = 1 +SENSOR_MAP_DEVICE_CLASS = 2 +SENSOR_MAP_ICON = 3 + # Default directives DEFAULT_NAME = "Smile" DEFAULT_USERNAME = "smile" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 08a0fffd90d43d..768bc6dd27fccc 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -19,7 +19,18 @@ from homeassistant.helpers.entity import Entity from . import SmileGateway -from .const import COOL_ICON, DEVICE_STATE, DOMAIN, FLAME_ICON, IDLE_ICON, UNIT_LUMEN +from .const import ( + COOL_ICON, + DEVICE_STATE, + DOMAIN, + FLAME_ICON, + IDLE_ICON, + SENSOR_MAP_DEVICE_CLASS, + SENSOR_MAP_ICON, + SENSOR_MAP_MODEL, + SENSOR_MAP_UOM, + UNIT_LUMEN, +) _LOGGER = logging.getLogger(__name__) @@ -285,6 +296,7 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): self._sensor_type = sensor_type self._entity_name = name self._sensor = sensor + self._state = None self._model = None self._unit_of_measurement = None @@ -362,13 +374,15 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): self._model = model self._entity_name = name self._dev_id = dev_id - self._device = sensor_type[0] - self._unit_of_measurement = sensor_type[1] - self._dev_class = sensor_type[2] - self._icon = sensor_type[3] self._sensor = sensor + self._state = None + self._model = sensor_type[SENSOR_MAP_MODEL] + self._unit_of_measurement = sensor_type[SENSOR_MAP_UOM] + self._dev_class = sensor_type[SENSOR_MAP_DEVICE_CLASS] + self._icon = sensor_type[SENSOR_MAP_ICON] + sensorname = sensor.replace("_", " ").title() self._name = f"{name} {sensorname}" From e5c657049c7544cc7b7bdfa92e65dbec33060cd2 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 22:37:32 +0200 Subject: [PATCH 30/39] Excluded from coverage --- .coveragerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.coveragerc b/.coveragerc index 5003e179b801c5..23b00aed6ded49 100644 --- a/.coveragerc +++ b/.coveragerc @@ -606,6 +606,7 @@ omit = homeassistant/components/plex/sensor.py homeassistant/components/plugwise/__init__.py homeassistant/components/plugwise/climate.py + homeassistant/components/plugwise/sensor.py homeassistant/components/plum_lightpad/* homeassistant/components/pocketcasts/sensor.py homeassistant/components/point/* From 55f587240456d7f12ec46ace556a7c20baa68222 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 30 May 2020 23:19:33 +0200 Subject: [PATCH 31/39] Add @bouwew rework on separate auxiliary class --- homeassistant/components/plugwise/sensor.py | 133 +++++++++++--------- 1 file changed, 76 insertions(+), 57 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 768bc6dd27fccc..7cfa0cc3106c1c 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -235,16 +235,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities): for state in INDICATE_ACTIVE_LOCAL_DEVICE: if state in data: entities.append( - PwThermostatSensor( - api, - coordinator, - entity["name"], - dev_id, - DEVICE_STATE, - None, + PwAuxDeviceSensor( + api, coordinator, entity["name"], dev_id, DEVICE_STATE, ) ) - _LOGGER.info("Added sensor.%s_state", "{}".format(entity["name"])) + _LOGGER.info( + "Added auxiliary sensor.%s_state", "{}".format(entity["name"]) + ) break async_add_entities(entities, True) @@ -284,7 +281,7 @@ def unit_of_measurement(self): class PwThermostatSensor(SmileSensor, Entity): - """Thermostat (or generic) sensor entities.""" + """Thermostat and climate sensor entities.""" def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): """Set up the Plugwise API.""" @@ -297,17 +294,10 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): self._entity_name = name self._sensor = sensor - self._state = None - self._model = None - self._unit_of_measurement = None - self._heating_state = False - self._cooling_state = False - - if self._sensor_type is not None: - self._model = self._sensor_type[SENSOR_MAP_MODEL] - self._unit_of_measurement = self._sensor_type[SENSOR_MAP_UOM] - self._dev_class = self._sensor_type[SENSOR_MAP_DEVICE_CLASS] - self._icon = self._sensor_type[SENSOR_MAP_ICON] + self._model = self._sensor_type[SENSOR_MAP_MODEL] + self._unit_of_measurement = self._sensor_type[SENSOR_MAP_UOM] + self._dev_class = self._sensor_type[SENSOR_MAP_DEVICE_CLASS] + self._icon = self._sensor_type[SENSOR_MAP_ICON] if self._dev_id == self._api.heater_id: self._entity_name = "Auxiliary" @@ -329,35 +319,67 @@ def _process_data(self): self.async_write_ha_state() return - if self._sensor in data: - if data[self._sensor] is not None: - measurement = data[self._sensor] - if self._sensor == "battery" or self._sensor == "valve_position": - measurement = measurement * 100 - if self._unit_of_measurement == UNIT_PERCENTAGE: - measurement = int(measurement) - self._state = measurement - - if "heating_state" in data: - if data["heating_state"] is not None: - self._heating_state = data["heating_state"] - if "cooling_state" in data: - if data["cooling_state"] is not None: - self._cooling_state = data["cooling_state"] - if self._sensor == DEVICE_STATE: - if self._heating_state: - self._state = "heating" - elif self._cooling_state: - self._state = "cooling" - else: - self._state = "idle" - - if self._sensor_type is None: - self._icon = IDLE_ICON - if self._heating_state: - self._icon = FLAME_ICON - if self._cooling_state: - self._icon = COOL_ICON + if data.get(self._sensor) is not None: + measurement = data[self._sensor] + if self._sensor == "battery" or self._sensor == "valve_position": + measurement = measurement * 100 + if self._unit_of_measurement == UNIT_PERCENTAGE: + measurement = int(measurement) + self._state = measurement + + self.async_write_ha_state() + + +class PwAuxDeviceSensor(SmileSensor, Entity): + """Auxiliary sensor entities for the heating/cooling device.""" + + def __init__(self, api, coordinator, name, dev_id, sensor): + """Set up the Plugwise API.""" + super().__init__(api, coordinator) + + self._api = api + self._gateway_id = self._api.gateway_id + self._dev_id = dev_id + self._entity_name = name + self._sensor = sensor + + self._model = None + self._heating_state = False + self._cooling_state = False + + if self._dev_id == self._api.heater_id: + self._entity_name = "Auxiliary" + + sensorname = sensor.replace("_", " ").title() + self._name = f"{self._entity_name} {sensorname}" + + self._unique_id = f"{dev_id}-{sensor}" + + def _process_data(self): + """Update the entity.""" + data = self._api.get_device_data(self._dev_id) + + if not data: + _LOGGER.error("Received no data for device %s.", self._entity_name) + self.async_write_ha_state() + return + + if data.get("heating_state") is not None: + self._heating_state = data["heating_state"] + if data.get("cooling_state") is not None: + self._cooling_state = data["cooling_state"] + + self._state = "idle" + if self._heating_state: + self._state = "heating" + if self._cooling_state: + self._state = "cooling" + + self._icon = IDLE_ICON + if self._heating_state: + self._icon = FLAME_ICON + if self._cooling_state: + self._icon = COOL_ICON self.async_write_ha_state() @@ -376,8 +398,6 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): self._dev_id = dev_id self._sensor = sensor - self._state = None - self._model = sensor_type[SENSOR_MAP_MODEL] self._unit_of_measurement = sensor_type[SENSOR_MAP_UOM] self._dev_class = sensor_type[SENSOR_MAP_DEVICE_CLASS] @@ -400,11 +420,10 @@ def _process_data(self): self.async_write_ha_state() return - if self._sensor in data: - if data[self._sensor] is not None: - measurement = data[self._sensor] - if self._unit_of_measurement == ENERGY_KILO_WATT_HOUR: - measurement = int(measurement / 1000) - self._state = measurement + if data.get(self._sensor) is not None: + measurement = data[self._sensor] + if self._unit_of_measurement == ENERGY_KILO_WATT_HOUR: + measurement = int(measurement / 1000) + self._state = measurement self.async_write_ha_state() From 5de9ab9dd24e88c8c8c40c339c9fd3acb7f5007e Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sun, 31 May 2020 10:29:22 +0200 Subject: [PATCH 32/39] Improve entity naming in code and fix device/entity names --- homeassistant/components/plugwise/__init__.py | 3 ++- homeassistant/components/plugwise/climate.py | 11 +++++---- homeassistant/components/plugwise/sensor.py | 24 ++++++++++++------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index a1927b6cf97ad9..c6d9bd92dc62ea 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -141,6 +141,7 @@ def __init__(self, api, coordinator): self._coordinator = coordinator self._unique_id = None self._name = None + self._entity_name = None self._icon = None self._dev_id = None self._model = None @@ -181,7 +182,7 @@ def device_info(self) -> Dict[str, any]: device_information = { "identifiers": {(DOMAIN, self._dev_id)}, - "name": self._name, + "name": self._entity_name, "manufacturer": "Plugwise", } diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index 0b5b5142ddcdaa..cb041e8a450520 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -48,18 +48,18 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ] all_devices = api.get_all_devices() - for dev_id, device in all_devices.items(): + for dev_id, device_properties in all_devices.items(): - if device["class"] not in thermostat_classes: + if device_properties["class"] not in thermostat_classes: continue thermostat = PwThermostat( api, coordinator, - device["name"], + device_properties["name"], dev_id, - device["location"], - device["class"], + device_properties["location"], + device_properties["class"], DEFAULT_MIN_TEMP, DEFAULT_MAX_TEMP, ) @@ -104,6 +104,7 @@ def __init__( self._water_pressure = None self._schedule_temp = None self._hvac_mode = None + self._entity_name = self._name self._single_thermostat = self._api.single_master_thermostat() self._icon = THERMOSTAT_ICON self._unique_id = f"{dev_id}-climate" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 7cfa0cc3106c1c..36799030a27e8d 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -190,7 +190,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): entities = [] all_devices = api.get_all_devices() single_thermostat = api.single_master_thermostat() - for dev_id, entity in all_devices.items(): + for dev_id, device_properties in all_devices.items(): data = api.get_device_data(dev_id) for sensor, sensor_type in { **TEMP_SENSOR_MAP, @@ -201,17 +201,17 @@ async def async_setup_entry(hass, config_entry, async_add_entities): if data[sensor] is None: continue - if "power" in entity["types"]: + if "power" in device_properties["types"]: model = None - if "plug" in entity["types"]: + if "plug" in device_properties["types"]: model = "Metered Switch" entities.append( PwPowerSensor( api, coordinator, - entity["name"], + device_properties["name"], dev_id, sensor, sensor_type, @@ -223,24 +223,29 @@ async def async_setup_entry(hass, config_entry, async_add_entities): PwThermostatSensor( api, coordinator, - entity["name"], + device_properties["name"], dev_id, sensor, sensor_type, ) ) - _LOGGER.info("Added sensor.%s", entity["name"]) + _LOGGER.info("Added sensor %s", device_properties["name"]) if single_thermostat is False: for state in INDICATE_ACTIVE_LOCAL_DEVICE: if state in data: entities.append( PwAuxDeviceSensor( - api, coordinator, entity["name"], dev_id, DEVICE_STATE, + api, + coordinator, + device_properties["name"], + dev_id, + DEVICE_STATE, ) ) _LOGGER.info( - "Added auxiliary sensor.%s_state", "{}".format(entity["name"]) + "Added auxiliary sensor %s", + "{}".format(device_properties["name"]), ) break @@ -353,6 +358,9 @@ def __init__(self, api, coordinator, name, dev_id, sensor): sensorname = sensor.replace("_", " ").title() self._name = f"{self._entity_name} {sensorname}" + if self._dev_id == self._api.gateway_id: + self._entity_name = f"Smile {self._entity_name}" + self._unique_id = f"{dev_id}-{sensor}" def _process_data(self): From 3ec7c9db197f72c2e9d202b0717e966afe23252d Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sun, 31 May 2020 10:34:32 +0200 Subject: [PATCH 33/39] Suggested logging change --- homeassistant/components/plugwise/sensor.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 36799030a27e8d..011235fbcf186d 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -243,10 +243,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): DEVICE_STATE, ) ) - _LOGGER.info( - "Added auxiliary sensor %s", - "{}".format(device_properties["name"]), - ) + _LOGGER.info("Added auxiliary sensor %s", device_properties["name"]) break async_add_entities(entities, True) From 5d457f0c053047ae9d76d5063add5c8d4340b013 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sun, 31 May 2020 13:03:42 +0200 Subject: [PATCH 34/39] Remove logging, add callback --- homeassistant/components/plugwise/__init__.py | 11 +++++++---- homeassistant/components/plugwise/climate.py | 4 +++- homeassistant/components/plugwise/sensor.py | 12 +++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index c6d9bd92dc62ea..24c68f185c94b3 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -10,7 +10,7 @@ import voluptuous as vol from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import device_registry as dr from homeassistant.helpers.aiohttp_client import async_get_clientsession @@ -196,10 +196,13 @@ def device_info(self) -> Dict[str, any]: async def async_added_to_hass(self): """Subscribe to updates.""" - self._process_data() - self.async_on_remove(self._coordinator.async_add_listener(self._process_data)) + self._async_process_data() + self.async_on_remove( + self._coordinator.async_add_listener(self._async_process_data) + ) - def _process_data(self): + @callback + def _async_process_data(self): """Interpret and process API data.""" raise NotImplementedError diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index cb041e8a450520..bd7246f8aa233f 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -16,6 +16,7 @@ SUPPORT_TARGET_TEMPERATURE, ) from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS +from homeassistant.core import callback from . import SmileGateway from .const import ( @@ -233,7 +234,8 @@ async def async_set_preset_mode(self, preset_mode): except Smile.PlugwiseError: _LOGGER.error("Error while communicating to device") - def _process_data(self): + @callback + def _async_process_data(self): """Update the data for this climate device.""" climate_data = self._api.get_device_data(self._dev_id) heater_central_data = self._api.get_device_data(self._api.heater_id) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 011235fbcf186d..71d2775e2a63a6 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -16,6 +16,7 @@ UNIT_PERCENTAGE, VOLUME_CUBIC_METERS, ) +from homeassistant.core import callback from homeassistant.helpers.entity import Entity from . import SmileGateway @@ -229,7 +230,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): sensor_type, ) ) - _LOGGER.info("Added sensor %s", device_properties["name"]) if single_thermostat is False: for state in INDICATE_ACTIVE_LOCAL_DEVICE: @@ -243,7 +243,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): DEVICE_STATE, ) ) - _LOGGER.info("Added auxiliary sensor %s", device_properties["name"]) break async_add_entities(entities, True) @@ -312,7 +311,8 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): self._unique_id = f"{dev_id}-{sensor}" - def _process_data(self): + @callback + def _async_process_data(self): """Update the entity.""" data = self._api.get_device_data(self._dev_id) @@ -360,7 +360,8 @@ def __init__(self, api, coordinator, name, dev_id, sensor): self._unique_id = f"{dev_id}-{sensor}" - def _process_data(self): + @callback + def _async_process_data(self): """Update the entity.""" data = self._api.get_device_data(self._dev_id) @@ -416,7 +417,8 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): self._unique_id = f"{dev_id}-{sensor}" - def _process_data(self): + @callback + def _async_process_data(self): """Update the entity.""" data = self._api.get_device_data(self._dev_id) From 2545da0af24622342960feb3f5763d4dc2710105 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sun, 31 May 2020 15:42:47 +0200 Subject: [PATCH 35/39] Removing icons for known device classes, effectively just drop icons --- homeassistant/components/plugwise/__init__.py | 10 +-- homeassistant/components/plugwise/climate.py | 10 +-- homeassistant/components/plugwise/const.py | 15 ---- homeassistant/components/plugwise/sensor.py | 72 +++---------------- 4 files changed, 10 insertions(+), 97 deletions(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index 24c68f185c94b3..43d34214a09a3e 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -17,7 +17,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import DOMAIN, THERMOSTAT_ICON +from .const import DOMAIN CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA) @@ -142,7 +142,6 @@ def __init__(self, api, coordinator): self._unique_id = None self._name = None self._entity_name = None - self._icon = None self._dev_id = None self._model = None self._gateway_id = None @@ -169,13 +168,6 @@ def name(self): return None return self._name - @property - def icon(self): - """Return the icon to use in the frontend.""" - if not self._icon: - return THERMOSTAT_ICON - return self._icon - @property def device_info(self) -> Dict[str, any]: """Return the device information.""" diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index bd7246f8aa233f..9acc9471333369 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -19,14 +19,7 @@ from homeassistant.core import callback from . import SmileGateway -from .const import ( - DEFAULT_MAX_TEMP, - DEFAULT_MIN_TEMP, - DOMAIN, - SCHEDULE_OFF, - SCHEDULE_ON, - THERMOSTAT_ICON, -) +from .const import DEFAULT_MAX_TEMP, DEFAULT_MIN_TEMP, DOMAIN, SCHEDULE_OFF, SCHEDULE_ON HVAC_MODES_HEAT_ONLY = [HVAC_MODE_HEAT, HVAC_MODE_AUTO] HVAC_MODES_HEAT_COOL = [HVAC_MODE_HEAT_COOL, HVAC_MODE_AUTO] @@ -107,7 +100,6 @@ def __init__( self._hvac_mode = None self._entity_name = self._name self._single_thermostat = self._api.single_master_thermostat() - self._icon = THERMOSTAT_ICON self._unique_id = f"{dev_id}-climate" @property diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index fee82230e2fbab..8c68d1748d9b00 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -5,7 +5,6 @@ SENSOR_MAP_MODEL = 0 SENSOR_MAP_UOM = 1 SENSOR_MAP_DEVICE_CLASS = 2 -SENSOR_MAP_ICON = 3 # Default directives DEFAULT_NAME = "Smile" @@ -34,17 +33,3 @@ SCHEDULE_ON = "true" SCHEDULE_OFF = "false" - -# Icons -SWITCH_ICON = "mdi:electric-switch" -THERMOSTAT_ICON = "mdi:thermometer" -WATER_ICON = "mdi:water-pump" -FLAME_ICON = "mdi:fire" -COOL_ICON = "mdi:snowflake" -IDLE_ICON = "mdi:circle-off-outline" -GAS_ICON = "mdi:fire" -POWER_ICON = "mdi:flash" -POWER_FAILURE_ICON = "mdi:flash-off" -SWELL_SAG_ICON = "mdi:pulse" -VALVE_OPEN_ICON = "mdi:valve-open" -VALVE_CLOSED_ICON = "mdi:valve-closed" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 71d2775e2a63a6..2cd792adbc0e7e 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -21,13 +21,9 @@ from . import SmileGateway from .const import ( - COOL_ICON, DEVICE_STATE, DOMAIN, - FLAME_ICON, - IDLE_ICON, SENSOR_MAP_DEVICE_CLASS, - SENSOR_MAP_ICON, SENSOR_MAP_MODEL, SENSOR_MAP_UOM, UNIT_LUMEN, @@ -39,21 +35,18 @@ "Temperature", TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE, - "mdi:thermometer", ] ATTR_BATTERY_LEVEL = [ "Charge", UNIT_PERCENTAGE, DEVICE_CLASS_BATTERY, - "mdi:battery-high", ] ATTR_ILLUMINANCE = [ "Illuminance", UNIT_LUMEN, DEVICE_CLASS_ILLUMINANCE, - "mdi:lightbulb-on-outline", ] -ATTR_PRESSURE = ["Pressure", PRESSURE_BAR, DEVICE_CLASS_PRESSURE, "mdi:water"] +ATTR_PRESSURE = ["Pressure", PRESSURE_BAR, DEVICE_CLASS_PRESSURE] TEMP_SENSOR_MAP = { "setpoint": ATTR_TEMPERATURE, @@ -66,114 +59,73 @@ } ENERGY_SENSOR_MAP = { - "electricity_consumed": [ - "Current Consumed Power", - POWER_WATT, - DEVICE_CLASS_POWER, - "mdi:flash", - ], - "electricity_produced": [ - "Current Produced Power", - POWER_WATT, - DEVICE_CLASS_POWER, - "mdi:flash", - ], + "electricity_consumed": ["Current Consumed Power", POWER_WATT, DEVICE_CLASS_POWER], + "electricity_produced": ["Current Produced Power", POWER_WATT, DEVICE_CLASS_POWER], "electricity_consumed_interval": [ "Consumed Power Interval", ENERGY_WATT_HOUR, DEVICE_CLASS_POWER, - "mdi:flash", ], "electricity_produced_interval": [ "Produced Power Interval", ENERGY_WATT_HOUR, DEVICE_CLASS_POWER, - "mdi:flash", ], "electricity_consumed_off_peak_point": [ "Current Consumed Power (off peak)", POWER_WATT, DEVICE_CLASS_POWER, - "mdi:flash", ], "electricity_consumed_peak_point": [ "Current Consumed Power", POWER_WATT, DEVICE_CLASS_POWER, - "mdi:flash", ], "electricity_consumed_off_peak_cumulative": [ "Cumulative Consumed Power (off peak)", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, - "mdi:gauge", ], "electricity_consumed_peak_cumulative": [ "Cumulative Consumed Power", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, - "mdi:gauge", ], "electricity_produced_off_peak_point": [ "Current Consumed Power (off peak)", POWER_WATT, DEVICE_CLASS_POWER, - "mdi:white-balance-sunny", ], "electricity_produced_peak_point": [ "Current Consumed Power", POWER_WATT, DEVICE_CLASS_POWER, - "mdi:white-balance-sunny", ], "electricity_produced_off_peak_cumulative": [ "Cumulative Consumed Power (off peak)", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, - "mdi:gauge", ], "electricity_produced_peak_cumulative": [ "Cumulative Consumed Power", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, - "mdi:gauge", - ], - "gas_consumed_interval": [ - "Current Consumed Gas", - VOLUME_CUBIC_METERS, - None, - "mdi:gas-cylinder", - ], - "gas_consumed_cumulative": [ - "Cumulative Consumed Gas", - VOLUME_CUBIC_METERS, - None, - "mdi:gauge", - ], - "net_electricity_point": [ - "Current net Power", - POWER_WATT, - DEVICE_CLASS_POWER, - "mdi:solar-power", ], + "gas_consumed_interval": ["Current Consumed Gas", VOLUME_CUBIC_METERS, None], + "gas_consumed_cumulative": ["Cumulative Consumed Gas", VOLUME_CUBIC_METERS, None], + "net_electricity_point": ["Current net Power", POWER_WATT, DEVICE_CLASS_POWER], "net_electricity_cumulative": [ "Cumulative net Power", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, - "mdi:gauge", ], } MISC_SENSOR_MAP = { "battery": ATTR_BATTERY_LEVEL, "illuminance": ATTR_ILLUMINANCE, - "modulation_level": [ - "Heater Modulation Level", - UNIT_PERCENTAGE, - "modulation", - "mdi:percent", - ], - "valve_position": ["Valve Position", UNIT_PERCENTAGE, None, "mdi:valve"], + "modulation_level": ["Heater Modulation Level", UNIT_PERCENTAGE, "modulation"], + "valve_position": ["Valve Position", UNIT_PERCENTAGE, None], "water_pressure": ATTR_PRESSURE, } @@ -298,7 +250,6 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): self._model = self._sensor_type[SENSOR_MAP_MODEL] self._unit_of_measurement = self._sensor_type[SENSOR_MAP_UOM] self._dev_class = self._sensor_type[SENSOR_MAP_DEVICE_CLASS] - self._icon = self._sensor_type[SENSOR_MAP_ICON] if self._dev_id == self._api.heater_id: self._entity_name = "Auxiliary" @@ -381,12 +332,6 @@ def _async_process_data(self): if self._cooling_state: self._state = "cooling" - self._icon = IDLE_ICON - if self._heating_state: - self._icon = FLAME_ICON - if self._cooling_state: - self._icon = COOL_ICON - self.async_write_ha_state() @@ -407,7 +352,6 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): self._model = sensor_type[SENSOR_MAP_MODEL] self._unit_of_measurement = sensor_type[SENSOR_MAP_UOM] self._dev_class = sensor_type[SENSOR_MAP_DEVICE_CLASS] - self._icon = sensor_type[SENSOR_MAP_ICON] sensorname = sensor.replace("_", " ").title() self._name = f"{name} {sensorname}" From f7dc2eb08e7fa9abe471b6b58c1e89512b065e44 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sun, 31 May 2020 23:40:14 +0200 Subject: [PATCH 36/39] Move unique_id and collateral - cleanup unuseds --- homeassistant/components/plugwise/__init__.py | 15 ++-- homeassistant/components/plugwise/climate.py | 6 +- homeassistant/components/plugwise/sensor.py | 71 +++++-------------- 3 files changed, 27 insertions(+), 65 deletions(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index 43d34214a09a3e..610acfc3e23cfc 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -135,16 +135,17 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): class SmileGateway(Entity): """Represent Smile Gateway.""" - def __init__(self, api, coordinator): + def __init__(self, api, coordinator, name, dev_id): """Initialise the gateway.""" self._api = api self._coordinator = coordinator + self._name = name + self._dev_id = dev_id + self._unique_id = None - self._name = None - self._entity_name = None - self._dev_id = None self._model = None - self._gateway_id = None + + self._entity_name = self._name @property def unique_id(self): @@ -181,8 +182,8 @@ def device_info(self) -> Dict[str, any]: if self._model is not None: device_information["model"] = self._model.replace("_", " ").title() - if self._dev_id != self._gateway_id: - device_information["via_device"] = (DOMAIN, self._gateway_id) + if self._dev_id != self._api.gateway_id: + device_information["via_device"] = (DOMAIN, self._api.gateway_id) return device_information diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index 9acc9471333369..42d4aa462b63de 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -70,12 +70,9 @@ def __init__( self, api, coordinator, name, dev_id, loc_id, model, min_temp, max_temp ): """Set up the Plugwise API.""" - super().__init__(api, coordinator) + super().__init__(api, coordinator, name, dev_id) self._api = api - self._gateway_id = self._api.gateway_id - self._name = name - self._dev_id = dev_id self._loc_id = loc_id self._model = model self._min_temp = min_temp @@ -98,7 +95,6 @@ def __init__( self._water_pressure = None self._schedule_temp = None self._hvac_mode = None - self._entity_name = self._name self._single_thermostat = self._api.single_master_thermostat() self._unique_id = f"{dev_id}-climate" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 2cd792adbc0e7e..45537d1a579589 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -203,33 +203,40 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class SmileSensor(SmileGateway): """Represent Smile Sensors.""" - def __init__(self, api, coordinator): + def __init__(self, api, coordinator, name, dev_id, sensor): """Initialise the sensor.""" - super().__init__(api, coordinator) + super().__init__(api, coordinator, name, dev_id) + + self._sensor = sensor self._dev_class = None self._state = None self._unit_of_measurement = None + if dev_id == self._api.heater_id: + self._entity_name = "Auxiliary" + + sensorname = sensor.replace("_", " ").title() + self._name = f"{self._entity_name} {sensorname}" + + if dev_id == self._api.gateway_id: + self._entity_name = f"Smile {self._entity_name}" + + self._unique_id = f"{dev_id}-{sensor}" + @property def device_class(self): """Device class of this entity.""" - if not self._dev_class: - return None return self._dev_class @property def state(self): """Device class of this entity.""" - if not self._state: - return None return self._state @property def unit_of_measurement(self): """Return the unit of measurement of this entity, if any.""" - if not self._unit_of_measurement: - return None return self._unit_of_measurement @@ -238,30 +245,15 @@ class PwThermostatSensor(SmileSensor, Entity): def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): """Set up the Plugwise API.""" - super().__init__(api, coordinator) + super().__init__(api, coordinator, name, dev_id, sensor) self._api = api - self._gateway_id = self._api.gateway_id - self._dev_id = dev_id self._sensor_type = sensor_type - self._entity_name = name - self._sensor = sensor self._model = self._sensor_type[SENSOR_MAP_MODEL] self._unit_of_measurement = self._sensor_type[SENSOR_MAP_UOM] self._dev_class = self._sensor_type[SENSOR_MAP_DEVICE_CLASS] - if self._dev_id == self._api.heater_id: - self._entity_name = "Auxiliary" - - sensorname = sensor.replace("_", " ").title() - self._name = f"{self._entity_name} {sensorname}" - - if self._dev_id == self._api.gateway_id: - self._entity_name = f"Smile {self._entity_name}" - - self._unique_id = f"{dev_id}-{sensor}" - @callback def _async_process_data(self): """Update the entity.""" @@ -288,29 +280,14 @@ class PwAuxDeviceSensor(SmileSensor, Entity): def __init__(self, api, coordinator, name, dev_id, sensor): """Set up the Plugwise API.""" - super().__init__(api, coordinator) + super().__init__(api, coordinator, name, dev_id, sensor) self._api = api - self._gateway_id = self._api.gateway_id - self._dev_id = dev_id - self._entity_name = name - self._sensor = sensor self._model = None self._heating_state = False self._cooling_state = False - if self._dev_id == self._api.heater_id: - self._entity_name = "Auxiliary" - - sensorname = sensor.replace("_", " ").title() - self._name = f"{self._entity_name} {sensorname}" - - if self._dev_id == self._api.gateway_id: - self._entity_name = f"Smile {self._entity_name}" - - self._unique_id = f"{dev_id}-{sensor}" - @callback def _async_process_data(self): """Update the entity.""" @@ -340,27 +317,15 @@ class PwPowerSensor(SmileSensor, Entity): def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): """Set up the Plugwise API.""" - super().__init__(api, coordinator) + super().__init__(api, coordinator, name, dev_id, sensor) self._api = api - self._gateway_id = self._api.gateway_id self._model = model - self._entity_name = name - self._dev_id = dev_id - self._sensor = sensor self._model = sensor_type[SENSOR_MAP_MODEL] self._unit_of_measurement = sensor_type[SENSOR_MAP_UOM] self._dev_class = sensor_type[SENSOR_MAP_DEVICE_CLASS] - sensorname = sensor.replace("_", " ").title() - self._name = f"{name} {sensorname}" - - if self._dev_id == self._api.gateway_id: - self._entity_name = f"Smile {self._entity_name}" - - self._unique_id = f"{dev_id}-{sensor}" - @callback def _async_process_data(self): """Update the entity.""" From c1f9018eb8ba0220d0d574090732dbcddc9747ac Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 1 Jun 2020 08:38:18 +0200 Subject: [PATCH 37/39] Further cleaning --- homeassistant/components/plugwise/sensor.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 45537d1a579589..00a0f3a3ba69ae 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -247,12 +247,9 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id, sensor) - self._api = api - self._sensor_type = sensor_type - - self._model = self._sensor_type[SENSOR_MAP_MODEL] - self._unit_of_measurement = self._sensor_type[SENSOR_MAP_UOM] - self._dev_class = self._sensor_type[SENSOR_MAP_DEVICE_CLASS] + self._model = sensor_type[SENSOR_MAP_MODEL] + self._unit_of_measurement = sensor_type[SENSOR_MAP_UOM] + self._dev_class = sensor_type[SENSOR_MAP_DEVICE_CLASS] @callback def _async_process_data(self): @@ -282,9 +279,6 @@ def __init__(self, api, coordinator, name, dev_id, sensor): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id, sensor) - self._api = api - - self._model = None self._heating_state = False self._cooling_state = False @@ -319,13 +313,16 @@ def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type, model): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id, sensor) - self._api = api self._model = model + if model is None: + self._model = sensor_type[SENSOR_MAP_MODEL] - self._model = sensor_type[SENSOR_MAP_MODEL] self._unit_of_measurement = sensor_type[SENSOR_MAP_UOM] self._dev_class = sensor_type[SENSOR_MAP_DEVICE_CLASS] + if dev_id == self._api.gateway_id: + self._model = "P1 DSMR" + @callback def _async_process_data(self): """Update the entity.""" From 64e5e895283b1f0521d8b705076fcc9a3e07a802 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 1 Jun 2020 10:18:42 +0200 Subject: [PATCH 38/39] Revert sensoric icons for non-device class (i.e. auxiliary) --- homeassistant/components/plugwise/const.py | 4 ++++ homeassistant/components/plugwise/sensor.py | 14 +++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 8c68d1748d9b00..b57532b9192ed0 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -33,3 +33,7 @@ SCHEDULE_ON = "true" SCHEDULE_OFF = "false" + +COOL_ICON = "mdi:snowflake" +FLAME_ICON = "mdi:fire" +IDLE_ICON = "mdi:circle-off-outline" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 00a0f3a3ba69ae..2aa5eba9b743d8 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -21,8 +21,11 @@ from . import SmileGateway from .const import ( + COOL_ICON, DEVICE_STATE, DOMAIN, + FLAME_ICON, + IDLE_ICON, SENSOR_MAP_DEVICE_CLASS, SENSOR_MAP_MODEL, SENSOR_MAP_UOM, @@ -279,8 +282,14 @@ def __init__(self, api, coordinator, name, dev_id, sensor): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id, sensor) - self._heating_state = False self._cooling_state = False + self._heating_state = False + self._icon = None + + @property + def icon(self): + """Return the icon to use in the frontend.""" + return self._icon @callback def _async_process_data(self): @@ -298,10 +307,13 @@ def _async_process_data(self): self._cooling_state = data["cooling_state"] self._state = "idle" + self._icon = IDLE_ICON if self._heating_state: self._state = "heating" + self._icon = FLAME_ICON if self._cooling_state: self._state = "cooling" + self._icon = COOL_ICON self.async_write_ha_state() From 76d9d9c358751889f9e69073e8450bb1372823ed Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 1 Jun 2020 12:08:54 +0200 Subject: [PATCH 39/39] Rogue illegal device class (well spotted @bouwew) --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 2aa5eba9b743d8..eabb5c6655f64a 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -127,7 +127,7 @@ MISC_SENSOR_MAP = { "battery": ATTR_BATTERY_LEVEL, "illuminance": ATTR_ILLUMINANCE, - "modulation_level": ["Heater Modulation Level", UNIT_PERCENTAGE, "modulation"], + "modulation_level": ["Heater Modulation Level", UNIT_PERCENTAGE, None], "valve_position": ["Valve Position", UNIT_PERCENTAGE, None], "water_pressure": ATTR_PRESSURE, }