From 3c8c5a814b2058cb8554c6c725e37892cb72612c Mon Sep 17 00:00:00 2001
From: "J. Nick Koston" <nick@koston.org>
Date: Tue, 27 Oct 2020 19:57:22 -0500
Subject: [PATCH] Fix somfy device recreation on update (#42462)

* Fix somfy device recreation on update

If all devices are assumed state, only update every hour
to ensure the token is refreshed

* pylint
---
 homeassistant/components/somfy/__init__.py | 21 ++++++++++++++++++++-
 homeassistant/components/somfy/cover.py    |  6 +++---
 homeassistant/components/somfy/switch.py   |  5 ++---
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/homeassistant/components/somfy/__init__.py b/homeassistant/components/somfy/__init__.py
index dd6e3340b17..99b0a2ee564 100644
--- a/homeassistant/components/somfy/__init__.py
+++ b/homeassistant/components/somfy/__init__.py
@@ -1,4 +1,5 @@
 """Support for Somfy hubs."""
+from abc import abstractmethod
 import asyncio
 from datetime import timedelta
 import logging
@@ -9,6 +10,7 @@ import voluptuous as vol
 from homeassistant.components.somfy import config_flow
 from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
+from homeassistant.core import callback
 from homeassistant.helpers import (
     config_entry_oauth2_flow,
     config_validation as cv,
@@ -27,7 +29,7 @@ from .const import API, CONF_OPTIMISTIC, COORDINATOR, DOMAIN
 _LOGGER = logging.getLogger(__name__)
 
 SCAN_INTERVAL = timedelta(minutes=1)
-
+SCAN_INTERVAL_ALL_ASSUMED_STATE = timedelta(minutes=60)
 
 SOMFY_AUTH_CALLBACK_PATH = "/auth/somfy/callback"
 SOMFY_AUTH_START = "/auth/somfy"
@@ -103,6 +105,13 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
 
     await coordinator.async_refresh()
 
+    if all(not bool(device.states) for device in coordinator.data.values()):
+        _LOGGER.debug(
+            "All devices have assumed state. Update interval has been reduced to: %s",
+            SCAN_INTERVAL_ALL_ASSUMED_STATE,
+        )
+        coordinator.update_interval = SCAN_INTERVAL_ALL_ASSUMED_STATE
+
     device_registry = await dr.async_get_registry(hass)
 
     hubs = [
@@ -188,3 +197,13 @@ class SomfyEntity(CoordinatorEntity, Entity):
     def assumed_state(self):
         """Return if the device has an assumed state."""
         return not bool(self.device.states)
+
+    @callback
+    def _handle_coordinator_update(self):
+        """Process an update from the coordinator."""
+        self._create_device()
+        super()._handle_coordinator_update()
+
+    @abstractmethod
+    def _create_device(self):
+        """Update the device with the latest data."""
diff --git a/homeassistant/components/somfy/cover.py b/homeassistant/components/somfy/cover.py
index 7d025e66bdd..605d58a941b 100644
--- a/homeassistant/components/somfy/cover.py
+++ b/homeassistant/components/somfy/cover.py
@@ -49,16 +49,16 @@ class SomfyCover(SomfyEntity, RestoreEntity, CoverEntity):
     def __init__(self, coordinator, device_id, api, optimistic):
         """Initialize the Somfy device."""
         super().__init__(coordinator, device_id, api)
-        self.cover = Blind(self.device, self.api)
         self.categories = set(self.device.categories)
         self.optimistic = optimistic
         self._closed = None
         self._is_opening = None
         self._is_closing = None
+        self.cover = None
+        self._create_device()
 
-    async def async_update(self):
+    def _create_device(self):
         """Update the device with the latest data."""
-        await super().async_update()
         self.cover = Blind(self.device, self.api)
 
     async def async_close_cover(self, **kwargs):
diff --git a/homeassistant/components/somfy/switch.py b/homeassistant/components/somfy/switch.py
index 2a81775cc22..d614776778e 100644
--- a/homeassistant/components/somfy/switch.py
+++ b/homeassistant/components/somfy/switch.py
@@ -32,11 +32,10 @@ class SomfyCameraShutter(SomfyEntity, SwitchEntity):
     def __init__(self, coordinator, device_id, api):
         """Initialize the Somfy device."""
         super().__init__(coordinator, device_id, api)
-        self.shutter = CameraProtect(self.device, self.api)
+        self._create_device()
 
-    async def async_update(self):
+    def _create_device(self):
         """Update the device with the latest data."""
-        await super().async_update()
         self.shutter = CameraProtect(self.device, self.api)
 
     def turn_on(self, **kwargs) -> None: