Просмотр исходного кода

Get HA to call async_refresh once for each device during startup

Since the persistent connection changes, devices are appearing
unavailable until startup completes, since we have to wait for startup
to complete before opening any persistent connection in order to avoid
being detected as delaying startup ourselves.

If we can make one poll to get initial data, then the devices can
activate, even if something is delaying startup.  The risk though is
that unresponsive devices can then be responsible for delaying startup
as the connection will be active until they timeout.  But since we
only do this once per device, it should be less of a problem than it
was when we were polling.
Jason Rumney 3 лет назад
Родитель
Сommit
7c971be759

+ 9 - 1
custom_components/tuya_local/device.py

@@ -141,10 +141,18 @@ class TuyaLocalDevice(object):
         _LOGGER.debug(f"Monitor loop for {self.name} stopped")
         self._refresh_task = None
 
-    def register_entity(self, entity):
+    async def async_register_entity(self, entity):
+        # If this is the first child entity to register, refresh the device
+        # state
+        should_poll = len(self._children) == 0
+
         self._children.append(entity)
         if not self._running and not self._startup_listener:
             self.start()
+        if self.has_returned_state:
+            await entity.async_schedule_update_ha_state()
+        elif should_poll:
+            await entity.async_schedule_update_ha_state(True)
 
     async def async_unregister_entity(self, entity):
         self._children.remove(entity)

+ 1 - 1
custom_components/tuya_local/helpers/mixin.py

@@ -85,7 +85,7 @@ class TuyaLocalEntity:
         await self._device.async_refresh()
 
     async def async_added_to_hass(self):
-        self._device.register_entity(self)
+        await self._device.async_register_entity(self)
 
     async def async_will_remove_from_hass(self):
         await self._device.async_unregister_entity(self)

+ 1 - 1
tests/test_config_flow.py

@@ -29,7 +29,7 @@ def auto_enable_custom_integrations(enable_custom_integrations):
 @pytest.fixture(autouse=True)
 def prevent_task_creation():
     with patch(
-        "custom_components.tuya_local.device.TuyaLocalDevice.register_entity",
+        "custom_components.tuya_local.device.TuyaLocalDevice.async_register_entity",
     ):
         yield
 

+ 16 - 11
tests/test_device.py

@@ -463,50 +463,55 @@ class TestDevice(IsolatedAsyncioTestCase):
         # Was the refresh task left empty?
         self.assertIsNone(self.subject._refresh_task)
 
-    def test_register_first_entity_ha_running(self):
+    async def test_register_first_entity_ha_running(self):
         # Set up preconditions
         self.subject._children = []
         self.subject._running = False
         self.subject._startup_listener = None
         self.subject.start = Mock()
+        entity = AsyncMock()
 
         # Call the function under test
-        self.subject.register_entity("Entity")
+        await self.subject.async_register_entity(entity)
 
         # Was the entity added to the list?
-        self.assertEqual(self.subject._children, ["Entity"])
+        self.assertEqual(self.subject._children, [entity])
 
         # Did we start the loop?
         self.subject.start.assert_called_once()
 
-    def test_register_subsequent_entity_ha_running(self):
+    async def test_register_subsequent_entity_ha_running(self):
         # Set up preconditions
-        self.subject._children = ["First"]
+        first = AsyncMock()
+        second = AsyncMock()
+        self.subject._children = [first]
         self.subject._running = True
         self.subject._startup_listener = None
         self.subject.start = Mock()
 
         # Call the function under test
-        self.subject.register_entity("Entity")
+        await self.subject.async_register_entity(second)
 
         # Was the entity added to the list?
-        self.assertCountEqual(self.subject._children, ["First", "Entity"])
+        self.assertCountEqual(self.subject._children, [first, second])
 
         # Did we avoid restarting the loop?
         self.subject.start.assert_not_called()
 
-    def test_register_subsequent_entity_ha_starting(self):
+    async def test_register_subsequent_entity_ha_starting(self):
         # Set up preconditions
-        self.subject._children = ["First"]
+        first = AsyncMock()
+        second = AsyncMock()
+        self.subject._children = [first]
         self.subject._running = False
         self.subject._startup_listener = Mock()
         self.subject.start = Mock()
 
         # Call the function under test
-        self.subject.register_entity("Entity")
+        await self.subject.async_register_entity(second)
 
         # Was the entity added to the list?
-        self.assertCountEqual(self.subject._children, ["First", "Entity"])
+        self.assertCountEqual(self.subject._children, [first, second])
         # Did we avoid restarting the loop?
         self.subject.start.assert_not_called()