mirror of
https://github.com/home-assistant/core.git
synced 2026-02-15 07:36:16 +00:00
Disable mobile devices in tado (#160881)
Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
@@ -33,18 +33,12 @@ from .const import (
|
||||
DOMAIN,
|
||||
TADO_BRIDGE_MODELS,
|
||||
)
|
||||
from .coordinator import (
|
||||
TadoConfigEntry,
|
||||
TadoData,
|
||||
TadoDataUpdateCoordinator,
|
||||
TadoMobileDeviceUpdateCoordinator,
|
||||
)
|
||||
from .coordinator import TadoConfigEntry, TadoDataUpdateCoordinator
|
||||
from .services import async_setup_services
|
||||
|
||||
PLATFORMS = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.CLIMATE,
|
||||
Platform.DEVICE_TRACKER,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
Platform.WATER_HEATER,
|
||||
@@ -103,9 +97,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: TadoConfigEntry) -> bool
|
||||
coordinator = TadoDataUpdateCoordinator(hass, entry, tado)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
mobile_coordinator = TadoMobileDeviceUpdateCoordinator(hass, entry, tado)
|
||||
await mobile_coordinator.async_config_entry_first_refresh()
|
||||
|
||||
# Pre-register the bridge device to ensure it exists before other devices reference it
|
||||
device_registry = dr.async_get(hass)
|
||||
for device in coordinator.data["device"].values():
|
||||
@@ -121,7 +112,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TadoConfigEntry) -> bool
|
||||
configuration_url=f"https://app.tado.com/en/main/settings/rooms-and-devices/device/{device['serialNo']}",
|
||||
)
|
||||
|
||||
entry.runtime_data = TadoData(coordinator, mobile_coordinator)
|
||||
entry.runtime_data = coordinator
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
@@ -120,7 +120,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Tado sensor platform."""
|
||||
|
||||
tado = entry.runtime_data.coordinator
|
||||
tado = entry.runtime_data
|
||||
devices = tado.devices
|
||||
zones = tado.zones
|
||||
entities: list[BinarySensorEntity] = []
|
||||
|
||||
@@ -105,7 +105,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Tado climate platform."""
|
||||
|
||||
tado = entry.runtime_data.coordinator
|
||||
tado = entry.runtime_data
|
||||
entities = await _generate_entities(tado)
|
||||
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
@@ -30,17 +29,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=4)
|
||||
SCAN_INTERVAL = timedelta(minutes=5)
|
||||
SCAN_MOBILE_DEVICE_INTERVAL = timedelta(minutes=5)
|
||||
|
||||
type TadoConfigEntry = ConfigEntry[TadoData]
|
||||
|
||||
|
||||
@dataclass
|
||||
class TadoData:
|
||||
"""Class to hold Tado data."""
|
||||
|
||||
coordinator: TadoDataUpdateCoordinator
|
||||
mobile_coordinator: TadoMobileDeviceUpdateCoordinator
|
||||
type TadoConfigEntry = ConfigEntry[TadoDataUpdateCoordinator]
|
||||
|
||||
|
||||
class TadoDataUpdateCoordinator(DataUpdateCoordinator[dict[str, dict]]):
|
||||
@@ -372,57 +362,3 @@ class TadoDataUpdateCoordinator(DataUpdateCoordinator[dict[str, dict]]):
|
||||
)
|
||||
except RequestException as exc:
|
||||
raise HomeAssistantError(f"Error setting Tado child lock: {exc}") from exc
|
||||
|
||||
|
||||
class TadoMobileDeviceUpdateCoordinator(DataUpdateCoordinator[dict[str, dict]]):
|
||||
"""Class to manage the mobile devices from Tado via PyTado."""
|
||||
|
||||
config_entry: TadoConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: TadoConfigEntry,
|
||||
tado: Tado,
|
||||
) -> None:
|
||||
"""Initialize the Tado data update coordinator."""
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
config_entry=config_entry,
|
||||
name=DOMAIN,
|
||||
update_interval=SCAN_MOBILE_DEVICE_INTERVAL,
|
||||
)
|
||||
self._tado = tado
|
||||
self.data: dict[str, dict] = {}
|
||||
|
||||
async def _async_update_data(self) -> dict[str, dict]:
|
||||
"""Fetch the latest data from Tado."""
|
||||
|
||||
try:
|
||||
mobile_devices = await self.hass.async_add_executor_job(
|
||||
self._tado.get_mobile_devices
|
||||
)
|
||||
except RequestException as err:
|
||||
_LOGGER.error("Error updating Tado mobile devices: %s", err)
|
||||
raise UpdateFailed(f"Error updating Tado mobile devices: {err}") from err
|
||||
|
||||
mapped_mobile_devices: dict[str, dict] = {}
|
||||
for mobile_device in mobile_devices:
|
||||
mobile_device_id = mobile_device["id"]
|
||||
_LOGGER.debug("Updating mobile device %s", mobile_device_id)
|
||||
try:
|
||||
mapped_mobile_devices[mobile_device_id] = mobile_device
|
||||
_LOGGER.debug(
|
||||
"Mobile device %s updated, with data: %s",
|
||||
mobile_device_id,
|
||||
mobile_device,
|
||||
)
|
||||
except RequestException:
|
||||
_LOGGER.error(
|
||||
"Unable to connect to Tado while updating mobile device %s",
|
||||
mobile_device_id,
|
||||
)
|
||||
|
||||
self.data["mobile_device"] = mapped_mobile_devices
|
||||
return self.data
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
"""Support for Tado Smart device trackers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.components.device_tracker import (
|
||||
DOMAIN as DEVICE_TRACKER_DOMAIN,
|
||||
TrackerEntity,
|
||||
)
|
||||
from homeassistant.const import STATE_HOME, STATE_NOT_HOME
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
)
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import TadoConfigEntry, TadoMobileDeviceUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: TadoConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Tado device scannery entity."""
|
||||
_LOGGER.debug("Setting up Tado device scanner entity")
|
||||
tado = entry.runtime_data.mobile_coordinator
|
||||
tracked: set = set()
|
||||
|
||||
# Fix non-string unique_id for device trackers
|
||||
# Can be removed in 2025.1
|
||||
entity_registry = er.async_get(hass)
|
||||
for device_key in tado.data["mobile_device"]:
|
||||
if entity_id := entity_registry.async_get_entity_id(
|
||||
DEVICE_TRACKER_DOMAIN, DOMAIN, device_key
|
||||
):
|
||||
entity_registry.async_update_entity(
|
||||
entity_id, new_unique_id=str(device_key)
|
||||
)
|
||||
|
||||
@callback
|
||||
def update_devices() -> None:
|
||||
"""Update the values of the devices."""
|
||||
add_tracked_entities(hass, tado, async_add_entities, tracked)
|
||||
|
||||
update_devices()
|
||||
|
||||
|
||||
@callback
|
||||
def add_tracked_entities(
|
||||
hass: HomeAssistant,
|
||||
coordinator: TadoMobileDeviceUpdateCoordinator,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
tracked: set[str],
|
||||
) -> None:
|
||||
"""Add new tracker entities from Tado."""
|
||||
_LOGGER.debug("Fetching Tado devices from API for (newly) tracked entities")
|
||||
new_tracked = []
|
||||
for device_key, device in coordinator.data["mobile_device"].items():
|
||||
if device_key in tracked:
|
||||
continue
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding Tado device %s with deviceID %s", device["name"], device_key
|
||||
)
|
||||
new_tracked.append(
|
||||
TadoDeviceTrackerEntity(device_key, device["name"], coordinator)
|
||||
)
|
||||
tracked.add(device_key)
|
||||
|
||||
async_add_entities(new_tracked)
|
||||
|
||||
|
||||
class TadoDeviceTrackerEntity(CoordinatorEntity[DataUpdateCoordinator], TrackerEntity):
|
||||
"""A Tado Device Tracker entity."""
|
||||
|
||||
_attr_available = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_id: str,
|
||||
device_name: str,
|
||||
coordinator: TadoMobileDeviceUpdateCoordinator,
|
||||
) -> None:
|
||||
"""Initialize a Tado Device Tracker entity."""
|
||||
super().__init__(coordinator)
|
||||
self._attr_unique_id = str(device_id)
|
||||
self._device_id = device_id
|
||||
self._device_name = device_name
|
||||
self._active = False
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle updated data from the coordinator."""
|
||||
self.update_state()
|
||||
super()._handle_coordinator_update()
|
||||
|
||||
@callback
|
||||
def update_state(self) -> None:
|
||||
"""Update the Tado device."""
|
||||
_LOGGER.debug(
|
||||
"Updating Tado mobile device: %s (ID: %s)",
|
||||
self._device_name,
|
||||
self._device_id,
|
||||
)
|
||||
device = self.coordinator.data["mobile_device"][self._device_id]
|
||||
|
||||
self._attr_available = False
|
||||
_LOGGER.debug(
|
||||
"Tado device %s has geoTracking state %s",
|
||||
device["name"],
|
||||
device["settings"]["geoTrackingEnabled"],
|
||||
)
|
||||
|
||||
if device["settings"]["geoTrackingEnabled"] is False:
|
||||
return
|
||||
|
||||
self._attr_available = True
|
||||
self._active = False
|
||||
if device.get("location") is not None and device["location"]["atHome"]:
|
||||
_LOGGER.debug("Tado device %s is at home", device["name"])
|
||||
self._active = True
|
||||
else:
|
||||
_LOGGER.debug("Tado device %s is not at home", device["name"])
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the device."""
|
||||
return self._device_name
|
||||
|
||||
@property
|
||||
def location_name(self) -> str:
|
||||
"""Return the state of the device."""
|
||||
return STATE_HOME if self._active else STATE_NOT_HOME
|
||||
@@ -14,7 +14,4 @@ async def async_get_config_entry_diagnostics(
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a Tado config entry."""
|
||||
|
||||
return {
|
||||
"data": config_entry.runtime_data.coordinator.data,
|
||||
"mobile_devices": config_entry.runtime_data.mobile_coordinator.data,
|
||||
}
|
||||
return {"data": config_entry.runtime_data.data}
|
||||
|
||||
@@ -196,7 +196,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Tado sensor platform."""
|
||||
|
||||
tado = entry.runtime_data.coordinator
|
||||
tado = entry.runtime_data
|
||||
zones = tado.zones
|
||||
entities: list[SensorEntity] = []
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ async def _add_meter_reading(call: ServiceCall) -> None:
|
||||
call.hass, DOMAIN, call.data[CONF_CONFIG_ENTRY]
|
||||
)
|
||||
|
||||
coordinator = entry.runtime_data.coordinator
|
||||
coordinator = entry.runtime_data
|
||||
response: dict = await coordinator.set_meter_reading(call.data[CONF_READING])
|
||||
|
||||
if ATTR_MESSAGE in response:
|
||||
|
||||
@@ -20,14 +20,14 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Tado switch platform."""
|
||||
|
||||
tado = entry.runtime_data.coordinator
|
||||
tado = entry.runtime_data
|
||||
entities: list[TadoChildLockSwitchEntity] = []
|
||||
for zone in tado.zones:
|
||||
zoneChildLockSupported = (
|
||||
zone_child_lock_supported = (
|
||||
len(zone["devices"]) > 0 and "childLockEnabled" in zone["devices"][0]
|
||||
)
|
||||
|
||||
if not zoneChildLockSupported:
|
||||
if not zone_child_lock_supported:
|
||||
continue
|
||||
|
||||
entities.append(
|
||||
|
||||
@@ -66,8 +66,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Tado water heater platform."""
|
||||
|
||||
data = entry.runtime_data
|
||||
coordinator = data.coordinator
|
||||
coordinator = entry.runtime_data
|
||||
entities = await _generate_entities(coordinator)
|
||||
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
|
||||
@@ -238,8 +238,7 @@ async def init_integration(hass: HomeAssistant):
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# For a first refresh
|
||||
await entry.runtime_data.coordinator.async_refresh()
|
||||
await entry.runtime_data.mobile_coordinator.async_refresh()
|
||||
await entry.runtime_data.async_refresh()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
yield
|
||||
|
||||
@@ -111,33 +111,5 @@
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
'mobile_devices': dict({
|
||||
'mobile_device': dict({
|
||||
'123456': dict({
|
||||
'deviceMetadata': dict({
|
||||
'locale': 'nl',
|
||||
'model': 'Samsung',
|
||||
'osVersion': '14',
|
||||
'platform': 'Android',
|
||||
}),
|
||||
'id': 123456,
|
||||
'name': 'Home',
|
||||
'settings': dict({
|
||||
'geoTrackingEnabled': False,
|
||||
'onDemandLogRetrievalEnabled': False,
|
||||
'pushNotifications': dict({
|
||||
'awayModeReminder': True,
|
||||
'energyIqReminder': False,
|
||||
'energySavingsReportReminder': True,
|
||||
'homeModeReminder': True,
|
||||
'incidentDetection': True,
|
||||
'lowBatteryReminder': True,
|
||||
'openWindowReminder': True,
|
||||
}),
|
||||
'specialOffersEnabled': False,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
|
||||
Reference in New Issue
Block a user