From 5cf4483df519846f9b13b3a1bb984c1593bdc69e Mon Sep 17 00:00:00 2001 From: Shay Levy Date: Fri, 28 Oct 2022 19:48:27 +0300 Subject: [PATCH] Fix Shelly Plus H&T sleep period on external power state change (#81121) --- .../components/shelly/coordinator.py | 30 ++++++++++++++++++- homeassistant/components/shelly/utils.py | 5 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/shelly/coordinator.py b/homeassistant/components/shelly/coordinator.py index 014355116c1..23f905b0fd9 100644 --- a/homeassistant/components/shelly/coordinator.py +++ b/homeassistant/components/shelly/coordinator.py @@ -41,7 +41,12 @@ from .const import ( SLEEP_PERIOD_MULTIPLIER, UPDATE_PERIOD_MULTIPLIER, ) -from .utils import device_update_info, get_block_device_name, get_rpc_device_name +from .utils import ( + device_update_info, + get_block_device_name, + get_rpc_device_name, + get_rpc_device_wakeup_period, +) @dataclass @@ -355,6 +360,24 @@ class ShellyRpcCoordinator(DataUpdateCoordinator): LOGGER.debug("Reloading entry %s", self.name) await self.hass.config_entries.async_reload(self.entry.entry_id) + def update_sleep_period(self) -> bool: + """Check device sleep period & update if changed.""" + if ( + not self.device.initialized + or not (wakeup_period := get_rpc_device_wakeup_period(self.device.status)) + or wakeup_period == self.entry.data.get(CONF_SLEEP_PERIOD) + ): + return False + + data = {**self.entry.data} + data[CONF_SLEEP_PERIOD] = wakeup_period + self.hass.config_entries.async_update_entry(self.entry, data=data) + + update_interval = SLEEP_PERIOD_MULTIPLIER * wakeup_period + self.update_interval = timedelta(seconds=update_interval) + + return True + @callback def _async_device_updates_handler(self) -> None: """Handle device updates.""" @@ -365,6 +388,8 @@ class ShellyRpcCoordinator(DataUpdateCoordinator): ): return + self.update_sleep_period() + self._last_event = self.device.event for event in self.device.event["events"]: @@ -393,6 +418,9 @@ class ShellyRpcCoordinator(DataUpdateCoordinator): async def _async_update_data(self) -> None: """Fetch data.""" + if self.update_sleep_period(): + return + if sleep_period := self.entry.data.get(CONF_SLEEP_PERIOD): # Sleeping device, no point polling it, just mark it unavailable raise UpdateFailed( diff --git a/homeassistant/components/shelly/utils.py b/homeassistant/components/shelly/utils.py index 79f5a5848f0..c3b6d24752f 100644 --- a/homeassistant/components/shelly/utils.py +++ b/homeassistant/components/shelly/utils.py @@ -272,6 +272,11 @@ def get_rpc_device_sleep_period(config: dict[str, Any]) -> int: return cast(int, config["sys"].get("sleep", {}).get("wakeup_period", 0)) +def get_rpc_device_wakeup_period(status: dict[str, Any]) -> int: + """Return the device wakeup period in seconds or 0 for non sleeping devices.""" + return cast(int, status["sys"].get("wakeup_period", 0)) + + def get_info_auth(info: dict[str, Any]) -> bool: """Return true if device has authorization enabled.""" return cast(bool, info.get("auth") or info.get("auth_en"))