From 15e3af72d171ff0e7757307a576490d73cefac3c Mon Sep 17 00:00:00 2001 From: Erwin Douna Date: Wed, 10 Jan 2024 12:09:10 +0100 Subject: [PATCH] Fix Tado unique mobile device dispatcher (#107631) * Add unique home ID device dispatch * Adding fixture for new setup * Minor refactor work * Add check for unlinked to different homes * If the interface returns an error * Proper error handling * Feedback fixes * Comments for error in client * Typo * Update homeassistant/components/tado/__init__.py Co-authored-by: Martin Hjelmare * Update homeassistant/components/tado/__init__.py Co-authored-by: Martin Hjelmare * Update devices fix standard * Dispatch out of loop * Update dispatcher * Clean up --------- Co-authored-by: Martin Hjelmare --- homeassistant/components/tado/__init__.py | 43 ++++++++++++++++--- homeassistant/components/tado/const.py | 2 +- .../components/tado/device_tracker.py | 12 +++--- .../tado/fixtures/mobile_devices.json | 26 +++++++++++ tests/components/tado/util.py | 5 +++ 5 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 tests/components/tado/fixtures/mobile_devices.json diff --git a/homeassistant/components/tado/__init__.py b/homeassistant/components/tado/__init__.py index 7f166ccf01a..871d6c2e6b1 100644 --- a/homeassistant/components/tado/__init__.py +++ b/homeassistant/components/tado/__init__.py @@ -186,12 +186,13 @@ class TadoConnector: def get_mobile_devices(self): """Return the Tado mobile devices.""" - return self.tado.getMobileDevices() + return self.tado.get_mobile_devices() @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Update the registered zones.""" self.update_devices() + self.update_mobile_devices() self.update_zones() self.update_home() @@ -203,17 +204,31 @@ class TadoConnector: _LOGGER.error("Unable to connect to Tado while updating mobile devices") return + if not mobile_devices: + _LOGGER.debug("No linked mobile devices found for home ID %s", self.home_id) + return + + # Errors are planned to be converted to exceptions + # in PyTado library, so this can be removed + if "errors" in mobile_devices and mobile_devices["errors"]: + _LOGGER.error( + "Error for home ID %s while updating mobile devices: %s", + self.home_id, + mobile_devices["errors"], + ) + return + for mobile_device in mobile_devices: self.data["mobile_device"][mobile_device["id"]] = mobile_device + _LOGGER.debug( + "Dispatching update to %s mobile device: %s", + self.home_id, + mobile_device, + ) - _LOGGER.debug( - "Dispatching update to %s mobile devices: %s", - self.home_id, - mobile_devices, - ) dispatcher_send( self.hass, - SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED, + SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED.format(self.home_id), ) def update_devices(self): @@ -224,6 +239,20 @@ class TadoConnector: _LOGGER.error("Unable to connect to Tado while updating devices") return + if not devices: + _LOGGER.debug("No linked devices found for home ID %s", self.home_id) + return + + # Errors are planned to be converted to exceptions + # in PyTado library, so this can be removed + if "errors" in devices and devices["errors"]: + _LOGGER.error( + "Error for home ID %s while updating devices: %s", + self.home_id, + devices["errors"], + ) + return + for device in devices: device_short_serial_no = device["shortSerialNo"] _LOGGER.debug("Updating device %s", device_short_serial_no) diff --git a/homeassistant/components/tado/const.py b/homeassistant/components/tado/const.py index c14906c3a89..ee24af29b9d 100644 --- a/homeassistant/components/tado/const.py +++ b/homeassistant/components/tado/const.py @@ -179,7 +179,7 @@ TADO_TO_HA_SWING_MODE_MAP = { DOMAIN = "tado" SIGNAL_TADO_UPDATE_RECEIVED = "tado_update_received_{}_{}_{}" -SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED = "tado_mobile_device_update_received" +SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED = "tado_mobile_device_update_received_{}" UNIQUE_ID = "unique_id" DEFAULT_NAME = "Tado" diff --git a/homeassistant/components/tado/device_tracker.py b/homeassistant/components/tado/device_tracker.py index e9d85abd2da..eb57aeaec79 100644 --- a/homeassistant/components/tado/device_tracker.py +++ b/homeassistant/components/tado/device_tracker.py @@ -2,7 +2,6 @@ from __future__ import annotations import logging -from typing import Any import voluptuous as vol @@ -22,6 +21,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.typing import ConfigType +from . import TadoConnector from .const import CONF_HOME_ID, DATA, DOMAIN, SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED _LOGGER = logging.getLogger(__name__) @@ -90,7 +90,7 @@ async def async_setup_entry( entry.async_on_unload( async_dispatcher_connect( hass, - SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED, + SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED.format(tado.home_id), update_devices, ) ) @@ -99,12 +99,12 @@ async def async_setup_entry( @callback def add_tracked_entities( hass: HomeAssistant, - tado: Any, + tado: TadoConnector, async_add_entities: AddEntitiesCallback, tracked: set[str], ) -> None: """Add new tracker entities from Tado.""" - _LOGGER.debug("Fetching Tado devices from API") + _LOGGER.debug("Fetching Tado devices from API for (newly) tracked entities") new_tracked = [] for device_key, device in tado.data["mobile_device"].items(): if device_key in tracked: @@ -129,7 +129,7 @@ class TadoDeviceTrackerEntity(TrackerEntity): self, device_id: str, device_name: str, - tado: Any, + tado: TadoConnector, ) -> None: """Initialize a Tado Device Tracker entity.""" super().__init__() @@ -181,7 +181,7 @@ class TadoDeviceTrackerEntity(TrackerEntity): self.async_on_remove( async_dispatcher_connect( self.hass, - SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED, + SIGNAL_TADO_MOBILE_DEVICE_UPDATE_RECEIVED.format(self._tado.home_id), self.on_demand_update, ) ) diff --git a/tests/components/tado/fixtures/mobile_devices.json b/tests/components/tado/fixtures/mobile_devices.json new file mode 100644 index 00000000000..80700a1e426 --- /dev/null +++ b/tests/components/tado/fixtures/mobile_devices.json @@ -0,0 +1,26 @@ +[ + { + "name": "Home", + "id": 123456, + "settings": { + "geoTrackingEnabled": false, + "specialOffersEnabled": false, + "onDemandLogRetrievalEnabled": false, + "pushNotifications": { + "lowBatteryReminder": true, + "awayModeReminder": true, + "homeModeReminder": true, + "openWindowReminder": true, + "energySavingsReportReminder": true, + "incidentDetection": true, + "energyIqReminder": false + } + }, + "deviceMetadata": { + "platform": "Android", + "osVersion": "14", + "model": "Samsung", + "locale": "nl" + } + } +] diff --git a/tests/components/tado/util.py b/tests/components/tado/util.py index 21e0e255ed1..dd7c108c984 100644 --- a/tests/components/tado/util.py +++ b/tests/components/tado/util.py @@ -17,6 +17,7 @@ async def async_init_integration( token_fixture = "tado/token.json" devices_fixture = "tado/devices.json" + mobile_devices_fixture = "tado/mobile_devices.json" me_fixture = "tado/me.json" weather_fixture = "tado/weather.json" home_state_fixture = "tado/home_state.json" @@ -70,6 +71,10 @@ async def async_init_integration( "https://my.tado.com/api/v2/homes/1/devices", text=load_fixture(devices_fixture), ) + m.get( + "https://my.tado.com/api/v2/homes/1/mobileDevices", + text=load_fixture(mobile_devices_fixture), + ) m.get( "https://my.tado.com/api/v2/devices/WR1/", text=load_fixture(device_wr1_fixture),