From 067f2d0098d13134284e442d75ae5f1015ae044c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 2 Jan 2021 13:35:59 +0100 Subject: [PATCH] Add tado zone binary sensors (#44576) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These should be binary sensors. Signed-off-by: Álvaro Fernández Rojas --- .../components/tado/binary_sensor.py | 143 +++++++++++++++++- homeassistant/components/tado/entity.py | 1 + homeassistant/components/tado/sensor.py | 41 +---- tests/components/tado/test_binary_sensor.py | 56 ++++++- tests/components/tado/test_sensor.py | 42 ----- 5 files changed, 197 insertions(+), 86 deletions(-) diff --git a/homeassistant/components/tado/binary_sensor.py b/homeassistant/components/tado/binary_sensor.py index 279633b07b1..bf958cceb5d 100644 --- a/homeassistant/components/tado/binary_sensor.py +++ b/homeassistant/components/tado/binary_sensor.py @@ -4,14 +4,25 @@ import logging from homeassistant.components.binary_sensor import ( DEVICE_CLASS_BATTERY, DEVICE_CLASS_CONNECTIVITY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_WINDOW, BinarySensorEntity, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import DATA, DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED, TYPE_BATTERY, TYPE_POWER -from .entity import TadoDeviceEntity +from .const import ( + DATA, + DOMAIN, + SIGNAL_TADO_UPDATE_RECEIVED, + TYPE_AIR_CONDITIONING, + TYPE_BATTERY, + TYPE_HEATING, + TYPE_HOT_WATER, + TYPE_POWER, +) +from .entity import TadoDeviceEntity, TadoZoneEntity _LOGGER = logging.getLogger(__name__) @@ -25,6 +36,23 @@ DEVICE_SENSORS = { ], } +ZONE_SENSORS = { + TYPE_HEATING: [ + "power", + "link", + "overlay", + "early start", + "open window", + ], + TYPE_AIR_CONDITIONING: [ + "power", + "link", + "overlay", + "open window", + ], + TYPE_HOT_WATER: ["power", "link", "overlay"], +} + async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities @@ -33,6 +61,7 @@ async def async_setup_entry( tado = hass.data[DOMAIN][entry.entry_id][DATA] devices = tado.devices + zones = tado.zones entities = [] # Create device sensors @@ -44,16 +73,30 @@ async def async_setup_entry( entities.extend( [ - TadoDeviceSensor(tado, device, variable) + TadoDeviceBinarySensor(tado, device, variable) for variable in DEVICE_SENSORS[device_type] ] ) + # Create zone sensors + for zone in zones: + zone_type = zone["type"] + if zone_type not in ZONE_SENSORS: + _LOGGER.warning("Unknown zone type skipped: %s", zone_type) + continue + + entities.extend( + [ + TadoZoneBinarySensor(tado, zone["name"], zone["id"], variable) + for variable in ZONE_SENSORS[zone_type] + ] + ) + if entities: async_add_entities(entities, True) -class TadoDeviceSensor(TadoDeviceEntity, BinarySensorEntity): +class TadoDeviceBinarySensor(TadoDeviceEntity, BinarySensorEntity): """Representation of a tado Sensor.""" def __init__(self, tado, device_info, device_variable): @@ -125,3 +168,95 @@ class TadoDeviceSensor(TadoDeviceEntity, BinarySensorEntity): self._state = self._device_info.get("connectionState", {}).get( "value", False ) + + +class TadoZoneBinarySensor(TadoZoneEntity, BinarySensorEntity): + """Representation of a tado Sensor.""" + + def __init__(self, tado, zone_name, zone_id, zone_variable): + """Initialize of the Tado Sensor.""" + self._tado = tado + super().__init__(zone_name, tado.home_id, zone_id) + + self.zone_variable = zone_variable + + self._unique_id = f"{zone_variable} {zone_id} {tado.home_id}" + + self._state = None + self._tado_zone_data = None + + async def async_added_to_hass(self): + """Register for sensor updates.""" + + self.async_on_remove( + async_dispatcher_connect( + self.hass, + SIGNAL_TADO_UPDATE_RECEIVED.format( + self._tado.home_id, "zone", self.zone_id + ), + self._async_update_callback, + ) + ) + self._async_update_zone_data() + + @property + def unique_id(self): + """Return the unique id.""" + return self._unique_id + + @property + def name(self): + """Return the name of the sensor.""" + return f"{self.zone_name} {self.zone_variable}" + + @property + def is_on(self): + """Return true if sensor is on.""" + return self._state + + @property + def device_class(self): + """Return the class of this sensor.""" + if self.zone_variable == "early start": + return DEVICE_CLASS_POWER + if self.zone_variable == "link": + return DEVICE_CLASS_CONNECTIVITY + if self.zone_variable == "open window": + return DEVICE_CLASS_WINDOW + if self.zone_variable == "overlay": + return DEVICE_CLASS_POWER + if self.zone_variable == "power": + return DEVICE_CLASS_POWER + return None + + @callback + def _async_update_callback(self): + """Update and write state.""" + self._async_update_zone_data() + self.async_write_ha_state() + + @callback + def _async_update_zone_data(self): + """Handle update callbacks.""" + try: + self._tado_zone_data = self._tado.data["zone"][self.zone_id] + except KeyError: + return + + if self.zone_variable == "power": + self._state = self._tado_zone_data.power + + elif self.zone_variable == "link": + self._state = self._tado_zone_data.link + + elif self.zone_variable == "overlay": + self._state = self._tado_zone_data.overlay_active + + elif self.zone_variable == "early start": + self._state = self._tado_zone_data.preparation + + elif self.zone_variable == "open window": + self._state = bool( + self._tado_zone_data.open_window + or self._tado_zone_data.open_window_detected + ) diff --git a/homeassistant/components/tado/entity.py b/homeassistant/components/tado/entity.py index 03900fdeeb5..bd0c605b0eb 100644 --- a/homeassistant/components/tado/entity.py +++ b/homeassistant/components/tado/entity.py @@ -40,6 +40,7 @@ class TadoZoneEntity(Entity): super().__init__() self._device_zone_id = f"{home_id}_{zone_id}" self.zone_name = zone_name + self.zone_id = zone_id @property def device_info(self): diff --git a/homeassistant/components/tado/sensor.py b/homeassistant/components/tado/sensor.py index 4e8f69b17c8..f9a924b52c6 100644 --- a/homeassistant/components/tado/sensor.py +++ b/homeassistant/components/tado/sensor.py @@ -23,25 +23,16 @@ ZONE_SENSORS = { TYPE_HEATING: [ "temperature", "humidity", - "power", - "link", "heating", "tado mode", - "overlay", - "early start", - "open window", ], TYPE_AIR_CONDITIONING: [ "temperature", "humidity", - "power", - "link", "ac", "tado mode", - "overlay", - "open window", ], - TYPE_HOT_WATER: ["power", "link", "tado mode", "overlay"], + TYPE_HOT_WATER: ["tado mode"], } @@ -51,10 +42,10 @@ async def async_setup_entry( """Set up the Tado sensor platform.""" tado = hass.data[DOMAIN][entry.entry_id][DATA] - # Create zone sensors zones = tado.zones entities = [] + # Create zone sensors for zone in zones: zone_type = zone["type"] if zone_type not in ZONE_SENSORS: @@ -80,7 +71,6 @@ class TadoZoneSensor(TadoZoneEntity, Entity): self._tado = tado super().__init__(zone_name, tado.home_id, zone_id) - self.zone_id = zone_id self.zone_variable = zone_variable self._unique_id = f"{zone_variable} {zone_id} {tado.home_id}" @@ -172,12 +162,6 @@ class TadoZoneSensor(TadoZoneEntity, Entity): "time": self._tado_zone_data.current_humidity_timestamp } - elif self.zone_variable == "power": - self._state = self._tado_zone_data.power - - elif self.zone_variable == "link": - self._state = self._tado_zone_data.link - elif self.zone_variable == "heating": self._state = self._tado_zone_data.heating_power_percentage self._state_attributes = { @@ -188,26 +172,5 @@ class TadoZoneSensor(TadoZoneEntity, Entity): self._state = self._tado_zone_data.ac_power self._state_attributes = {"time": self._tado_zone_data.ac_power_timestamp} - elif self.zone_variable == "tado bridge status": - self._state = self._tado_zone_data.connection - elif self.zone_variable == "tado mode": self._state = self._tado_zone_data.tado_mode - - elif self.zone_variable == "overlay": - self._state = self._tado_zone_data.overlay_active - self._state_attributes = ( - {"termination": self._tado_zone_data.overlay_termination_type} - if self._tado_zone_data.overlay_active - else {} - ) - - elif self.zone_variable == "early start": - self._state = self._tado_zone_data.preparation - - elif self.zone_variable == "open window": - self._state = bool( - self._tado_zone_data.open_window - or self._tado_zone_data.open_window_detected - ) - self._state_attributes = self._tado_zone_data.open_window_attr diff --git a/tests/components/tado/test_binary_sensor.py b/tests/components/tado/test_binary_sensor.py index 39dd068f5a6..c811314e4f9 100644 --- a/tests/components/tado/test_binary_sensor.py +++ b/tests/components/tado/test_binary_sensor.py @@ -1,10 +1,64 @@ """The sensor tests for the tado platform.""" -from homeassistant.const import STATE_ON +from homeassistant.const import STATE_OFF, STATE_ON from .util import async_init_integration +async def test_air_con_create_binary_sensors(hass): + """Test creation of aircon sensors.""" + + await async_init_integration(hass) + + state = hass.states.get("binary_sensor.air_conditioning_power") + assert state.state == STATE_ON + + state = hass.states.get("binary_sensor.air_conditioning_link") + assert state.state == STATE_ON + + state = hass.states.get("binary_sensor.air_conditioning_overlay") + assert state.state == STATE_ON + + state = hass.states.get("binary_sensor.air_conditioning_open_window") + assert state.state == STATE_OFF + + +async def test_heater_create_binary_sensors(hass): + """Test creation of heater sensors.""" + + await async_init_integration(hass) + + state = hass.states.get("binary_sensor.baseboard_heater_power") + assert state.state == STATE_ON + + state = hass.states.get("binary_sensor.baseboard_heater_link") + assert state.state == STATE_ON + + state = hass.states.get("binary_sensor.baseboard_heater_early_start") + assert state.state == STATE_OFF + + state = hass.states.get("binary_sensor.baseboard_heater_overlay") + assert state.state == STATE_ON + + state = hass.states.get("binary_sensor.baseboard_heater_open_window") + assert state.state == STATE_OFF + + +async def test_water_heater_create_binary_sensors(hass): + """Test creation of water heater sensors.""" + + await async_init_integration(hass) + + state = hass.states.get("binary_sensor.water_heater_link") + assert state.state == STATE_ON + + state = hass.states.get("binary_sensor.water_heater_overlay") + assert state.state == STATE_OFF + + state = hass.states.get("binary_sensor.water_heater_power") + assert state.state == STATE_ON + + async def test_home_create_binary_sensors(hass): """Test creation of home binary sensors.""" diff --git a/tests/components/tado/test_sensor.py b/tests/components/tado/test_sensor.py index 646e7741530..2fac88bc22e 100644 --- a/tests/components/tado/test_sensor.py +++ b/tests/components/tado/test_sensor.py @@ -8,15 +8,6 @@ async def test_air_con_create_sensors(hass): await async_init_integration(hass) - state = hass.states.get("sensor.air_conditioning_power") - assert state.state == "ON" - - state = hass.states.get("sensor.air_conditioning_link") - assert state.state == "ONLINE" - - state = hass.states.get("sensor.air_conditioning_link") - assert state.state == "ONLINE" - state = hass.states.get("sensor.air_conditioning_tado_mode") assert state.state == "HOME" @@ -26,48 +17,24 @@ async def test_air_con_create_sensors(hass): state = hass.states.get("sensor.air_conditioning_ac") assert state.state == "ON" - state = hass.states.get("sensor.air_conditioning_overlay") - assert state.state == "True" - state = hass.states.get("sensor.air_conditioning_humidity") assert state.state == "60.9" - state = hass.states.get("sensor.air_conditioning_open_window") - assert state.state == "False" - async def test_heater_create_sensors(hass): """Test creation of heater sensors.""" await async_init_integration(hass) - state = hass.states.get("sensor.baseboard_heater_power") - assert state.state == "ON" - - state = hass.states.get("sensor.baseboard_heater_link") - assert state.state == "ONLINE" - - state = hass.states.get("sensor.baseboard_heater_link") - assert state.state == "ONLINE" - state = hass.states.get("sensor.baseboard_heater_tado_mode") assert state.state == "HOME" state = hass.states.get("sensor.baseboard_heater_temperature") assert state.state == "20.65" - state = hass.states.get("sensor.baseboard_heater_early_start") - assert state.state == "False" - - state = hass.states.get("sensor.baseboard_heater_overlay") - assert state.state == "True" - state = hass.states.get("sensor.baseboard_heater_humidity") assert state.state == "45.2" - state = hass.states.get("sensor.baseboard_heater_open_window") - assert state.state == "False" - async def test_water_heater_create_sensors(hass): """Test creation of water heater sensors.""" @@ -76,12 +43,3 @@ async def test_water_heater_create_sensors(hass): state = hass.states.get("sensor.water_heater_tado_mode") assert state.state == "HOME" - - state = hass.states.get("sensor.water_heater_link") - assert state.state == "ONLINE" - - state = hass.states.get("sensor.water_heater_overlay") - assert state.state == "False" - - state = hass.states.get("sensor.water_heater_power") - assert state.state == "ON"