Add tado zone binary sensors (#44576)
These should be binary sensors. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
This commit is contained in:
parent
40cbe597be
commit
067f2d0098
5 changed files with 197 additions and 86 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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."""
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue