Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 139 additions & 4 deletions homeassistant/components/tado/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@
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__)

Expand All @@ -25,6 +36,23 @@
],
}

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
Expand All @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -125,3 +168,95 @@ def _async_update_device_data(self):
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
)
1 change: 1 addition & 0 deletions homeassistant/components/tado/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self, zone_name, home_id, zone_id):
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):
Expand Down
41 changes: 2 additions & 39 deletions homeassistant/components/tado/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,16 @@
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"],
}


Expand All @@ -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:
Expand All @@ -80,7 +71,6 @@ def __init__(self, tado, zone_name, zone_id, zone_variable):
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}"
Expand Down Expand Up @@ -172,12 +162,6 @@ def _async_update_zone_data(self):
"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 = {
Expand All @@ -188,26 +172,5 @@ def _async_update_zone_data(self):
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
56 changes: 55 additions & 1 deletion tests/components/tado/test_binary_sensor.py
Original file line number Diff line number Diff line change
@@ -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."""

Expand Down
Loading