From 524db33f13541c0fe12adece411f7f1d99aa404b Mon Sep 17 00:00:00 2001 From: Thibaut Date: Thu, 17 Dec 2020 16:46:22 +0100 Subject: [PATCH] Add Somfy battery sensor (#44311) Co-authored-by: Martin Hjelmare --- homeassistant/components/somfy/__init__.py | 2 +- homeassistant/components/somfy/climate.py | 42 ++-------------- homeassistant/components/somfy/sensor.py | 58 ++++++++++++++++++++++ 3 files changed, 63 insertions(+), 39 deletions(-) create mode 100644 homeassistant/components/somfy/sensor.py diff --git a/homeassistant/components/somfy/__init__.py b/homeassistant/components/somfy/__init__.py index a831b55606e..78429dd1fe0 100644 --- a/homeassistant/components/somfy/__init__.py +++ b/homeassistant/components/somfy/__init__.py @@ -47,7 +47,7 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -SOMFY_COMPONENTS = ["cover", "switch", "climate"] +SOMFY_COMPONENTS = ["climate", "cover", "sensor", "switch"] async def async_setup(hass, config): diff --git a/homeassistant/components/somfy/climate.py b/homeassistant/components/somfy/climate.py index 49b528645ea..c4abc12d240 100644 --- a/homeassistant/components/somfy/climate.py +++ b/homeassistant/components/somfy/climate.py @@ -1,7 +1,6 @@ """Support for Somfy Thermostat.""" -import logging -from typing import Any, Dict, List, Optional +from typing import List, Optional from pymfy.api.devices.category import Category from pymfy.api.devices.thermostat import ( @@ -14,9 +13,6 @@ from pymfy.api.devices.thermostat import ( from homeassistant.components.climate import ClimateEntity from homeassistant.components.climate.const import ( - CURRENT_HVAC_COOL, - CURRENT_HVAC_HEAT, - CURRENT_HVAC_IDLE, HVAC_MODE_AUTO, HVAC_MODE_COOL, HVAC_MODE_HEAT, @@ -26,13 +22,11 @@ from homeassistant.components.climate.const import ( SUPPORT_PRESET_MODE, SUPPORT_TARGET_TEMPERATURE, ) -from homeassistant.const import ATTR_BATTERY_LEVEL, ATTR_TEMPERATURE, TEMP_CELSIUS +from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from . import SomfyEntity from .const import API, COORDINATOR, DOMAIN -_LOGGER = logging.getLogger(__name__) - SUPPORTED_CATEGORIES = {Category.HVAC.value} PRESET_FROST_GUARD = "Frost Guard" @@ -88,11 +82,6 @@ class SomfyClimate(SomfyEntity, ClimateEntity): """Return the list of supported features.""" return SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE - @property - def device_state_attributes(self) -> Dict[str, Any]: - """Return the state attributes of the device.""" - return {ATTR_BATTERY_LEVEL: self._climate.get_battery()} - @property def temperature_unit(self): """Return the unit of measurement used by the platform.""" @@ -145,13 +134,11 @@ class SomfyClimate(SomfyEntity, ClimateEntity): HEAT and COOL mode are exclusive. End user has to enable a mode manually within the Somfy application. So only one mode can be displayed. Auto mode is a scheduler. """ - hvac_state = HVAC_MODES_MAPPING.get(self._climate.get_hvac_state()) + hvac_state = HVAC_MODES_MAPPING[self._climate.get_hvac_state()] return [HVAC_MODE_AUTO, hvac_state] def set_hvac_mode(self, hvac_mode: str) -> None: """Set new target hvac mode.""" - if hvac_mode == self.hvac_mode: - return if hvac_mode == HVAC_MODE_AUTO: self._climate.cancel_target() else: @@ -159,26 +146,6 @@ class SomfyClimate(SomfyEntity, ClimateEntity): TargetMode.MANUAL, self.target_temperature, DurationType.FURTHER_NOTICE ) - @property - def hvac_action(self) -> str: - """Return the current running hvac operation if supported.""" - if not self.current_temperature or not self.target_temperature: - return CURRENT_HVAC_IDLE - - if ( - self.hvac_mode == HVAC_MODE_HEAT - and self.current_temperature < self.target_temperature - ): - return CURRENT_HVAC_HEAT - - if ( - self.hvac_mode == HVAC_MODE_COOL - and self.current_temperature > self.target_temperature - ): - return CURRENT_HVAC_COOL - - return CURRENT_HVAC_IDLE - @property def preset_mode(self) -> Optional[str]: """Return the current preset mode.""" @@ -206,8 +173,7 @@ class SomfyClimate(SomfyEntity, ClimateEntity): elif preset_mode in [PRESET_MANUAL, PRESET_GEOFENCING]: temperature = self.target_temperature else: - _LOGGER.error("Preset mode not supported: %s", preset_mode) - return + raise ValueError(f"Preset mode not supported: {preset_mode}") self._climate.set_target( REVERSE_PRESET_MAPPING[preset_mode], temperature, DurationType.NEXT_MODE diff --git a/homeassistant/components/somfy/sensor.py b/homeassistant/components/somfy/sensor.py new file mode 100644 index 00000000000..3d7b1b8fc13 --- /dev/null +++ b/homeassistant/components/somfy/sensor.py @@ -0,0 +1,58 @@ +"""Support for Somfy Thermostat Battery.""" + +from pymfy.api.devices.category import Category +from pymfy.api.devices.thermostat import Thermostat + +from homeassistant.const import DEVICE_CLASS_BATTERY, PERCENTAGE + +from . import SomfyEntity +from .const import API, COORDINATOR, DOMAIN + +SUPPORTED_CATEGORIES = {Category.HVAC.value} + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up the Somfy climate platform.""" + + def get_thermostats(): + """Retrieve thermostats.""" + domain_data = hass.data[DOMAIN] + coordinator = domain_data[COORDINATOR] + api = domain_data[API] + + return [ + SomfyThermostatBatterySensor(coordinator, device_id, api) + for device_id, device in coordinator.data.items() + if SUPPORTED_CATEGORIES & set(device.categories) + ] + + async_add_entities(await hass.async_add_executor_job(get_thermostats)) + + +class SomfyThermostatBatterySensor(SomfyEntity): + """Representation of a Somfy thermostat battery.""" + + def __init__(self, coordinator, device_id, api): + """Initialize the Somfy device.""" + super().__init__(coordinator, device_id, api) + self._climate = None + self._create_device() + + def _create_device(self): + """Update the device with the latest data.""" + self._climate = Thermostat(self.device, self.api) + + @property + def state(self) -> int: + """Return the state of the sensor.""" + return self._climate.get_battery() + + @property + def device_class(self) -> str: + """Return the device class of the sensor.""" + return DEVICE_CLASS_BATTERY + + @property + def unit_of_measurement(self) -> str: + """Return the unit of measurement of the sensor.""" + return PERCENTAGE