Refactor ZHA device keep alive checker (#32561)
* Refactor zha core device _check_available(). Make it async, so we don't run it in a sync worker. * Use random keep alive interval for zha device pings. * Update tests.
This commit is contained in:
parent
732457745f
commit
7e781946fa
2 changed files with 68 additions and 37 deletions
|
@ -3,6 +3,7 @@ import asyncio
|
|||
from datetime import timedelta
|
||||
from enum import Enum
|
||||
import logging
|
||||
import random
|
||||
import time
|
||||
|
||||
from zigpy import types
|
||||
|
@ -61,7 +62,7 @@ from .helpers import LogMixin
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_KEEP_ALIVE_INTERVAL = 7200
|
||||
_UPDATE_ALIVE_INTERVAL = timedelta(seconds=60)
|
||||
_UPDATE_ALIVE_INTERVAL = (60, 90)
|
||||
_CHECKIN_GRACE_PERIODS = 2
|
||||
|
||||
|
||||
|
@ -98,8 +99,9 @@ class ZHADevice(LogMixin):
|
|||
self._zigpy_device.__class__.__module__,
|
||||
self._zigpy_device.__class__.__name__,
|
||||
)
|
||||
keep_alive_interval = random.randint(*_UPDATE_ALIVE_INTERVAL)
|
||||
self._available_check = async_track_time_interval(
|
||||
self.hass, self._check_available, _UPDATE_ALIVE_INTERVAL
|
||||
self.hass, self._check_available, timedelta(seconds=keep_alive_interval)
|
||||
)
|
||||
self._ha_device_id = None
|
||||
self.status = DeviceStatus.CREATED
|
||||
|
@ -271,37 +273,40 @@ class ZHADevice(LogMixin):
|
|||
zha_dev.channels = channels.Channels.new(zha_dev)
|
||||
return zha_dev
|
||||
|
||||
def _check_available(self, *_):
|
||||
async def _check_available(self, *_):
|
||||
if self.last_seen is None:
|
||||
self.update_available(False)
|
||||
else:
|
||||
difference = time.time() - self.last_seen
|
||||
if difference > _KEEP_ALIVE_INTERVAL:
|
||||
if self._checkins_missed_count < _CHECKIN_GRACE_PERIODS:
|
||||
self._checkins_missed_count += 1
|
||||
if self.manufacturer != "LUMI":
|
||||
self.debug(
|
||||
"Attempting to checkin with device - missed checkins: %s",
|
||||
self._checkins_missed_count,
|
||||
)
|
||||
if not self._channels.pools:
|
||||
return
|
||||
try:
|
||||
pool = self._channels.pools[0]
|
||||
basic_ch = pool.all_channels[f"{pool.id}:0x0000"]
|
||||
except KeyError:
|
||||
self.debug("%s %s does not have a mandatory basic cluster")
|
||||
return
|
||||
self.hass.async_create_task(
|
||||
basic_ch.get_attribute_value(
|
||||
ATTR_MANUFACTURER, from_cache=False
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.update_available(False)
|
||||
else:
|
||||
self.update_available(True)
|
||||
self._checkins_missed_count = 0
|
||||
return
|
||||
|
||||
difference = time.time() - self.last_seen
|
||||
if difference < _KEEP_ALIVE_INTERVAL:
|
||||
self.update_available(True)
|
||||
self._checkins_missed_count = 0
|
||||
return
|
||||
|
||||
if (
|
||||
self._checkins_missed_count >= _CHECKIN_GRACE_PERIODS
|
||||
or self.manufacturer == "LUMI"
|
||||
or not self._channels.pools
|
||||
):
|
||||
self.update_available(False)
|
||||
return
|
||||
|
||||
self._checkins_missed_count += 1
|
||||
self.debug(
|
||||
"Attempting to checkin with device - missed checkins: %s",
|
||||
self._checkins_missed_count,
|
||||
)
|
||||
try:
|
||||
pool = self._channels.pools[0]
|
||||
basic_ch = pool.all_channels[f"{pool.id}:0x0000"]
|
||||
except KeyError:
|
||||
self.debug("does not have a mandatory basic cluster")
|
||||
self.update_available(False)
|
||||
return
|
||||
res = await basic_ch.get_attribute_value(ATTR_MANUFACTURER, from_cache=False)
|
||||
if res is not None:
|
||||
self._checkins_missed_count = 0
|
||||
|
||||
def update_available(self, available):
|
||||
"""Set sensor availability."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue