"""Support for Tado sensors for each zone.""" import logging from homeassistant.components.binary_sensor import ( BinarySensorDeviceClass, BinarySensorEntity, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback 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__) DEVICE_SENSORS = { TYPE_BATTERY: [ "battery state", "connection state", ], TYPE_POWER: [ "connection state", ], } 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: AddEntitiesCallback ) -> None: """Set up the Tado sensor platform.""" tado = hass.data[DOMAIN][entry.entry_id][DATA] devices = tado.devices zones = tado.zones entities = [] # Create device sensors for device in devices: if "batteryState" in device: device_type = TYPE_BATTERY else: device_type = TYPE_POWER entities.extend( [ 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 TadoDeviceBinarySensor(TadoDeviceEntity, BinarySensorEntity): """Representation of a tado Sensor.""" def __init__(self, tado, device_info, device_variable): """Initialize of the Tado Sensor.""" self._tado = tado super().__init__(device_info) self.device_variable = device_variable self._unique_id = f"{device_variable} {self.device_id} {tado.home_id}" self._state = 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, "device", self.device_id ), self._async_update_callback, ) ) self._async_update_device_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.device_name} {self.device_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.device_variable == "battery state": return BinarySensorDeviceClass.BATTERY if self.device_variable == "connection state": return BinarySensorDeviceClass.CONNECTIVITY return None @callback def _async_update_callback(self): """Update and write state.""" self._async_update_device_data() self.async_write_ha_state() @callback def _async_update_device_data(self): """Handle update callbacks.""" try: self._device_info = self._tado.data["device"][self.device_id] except KeyError: return if self.device_variable == "battery state": self._state = self._device_info["batteryState"] == "LOW" elif self.device_variable == "connection state": 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._state_attributes = 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 BinarySensorDeviceClass.POWER if self.zone_variable == "link": return BinarySensorDeviceClass.CONNECTIVITY if self.zone_variable == "open window": return BinarySensorDeviceClass.WINDOW if self.zone_variable == "overlay": return BinarySensorDeviceClass.POWER if self.zone_variable == "power": return BinarySensorDeviceClass.POWER return None @property def extra_state_attributes(self): """Return the state attributes.""" return self._state_attributes @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 == "ON" elif self.zone_variable == "link": self._state = self._tado_zone_data.link == "ONLINE" elif self.zone_variable == "overlay": self._state = self._tado_zone_data.overlay_active if self._tado_zone_data.overlay_active: self._state_attributes = { "termination": self._tado_zone_data.overlay_termination_type } 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