Fix ZHA device healthcheck pings (#32425)
This commit is contained in:
parent
cfa61a6b74
commit
896df9267a
2 changed files with 153 additions and 3 deletions
|
@ -87,7 +87,7 @@ class ZHADevice(LogMixin):
|
|||
self._available_signal = "{}_{}_{}".format(
|
||||
self.name, self.ieee, SIGNAL_AVAILABLE
|
||||
)
|
||||
self._checkins_missed_count = 2
|
||||
self._checkins_missed_count = 0
|
||||
self._unsub = async_dispatcher_connect(
|
||||
self.hass, self._available_signal, self.async_initialize
|
||||
)
|
||||
|
@ -284,8 +284,12 @@ class ZHADevice(LogMixin):
|
|||
)
|
||||
if not self._channels.pools:
|
||||
return
|
||||
pool = self._channels.pools[0]
|
||||
basic_ch = pool.all_channels[f"{pool.id}:0"]
|
||||
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
|
||||
|
|
146
tests/components/zha/test_device.py
Normal file
146
tests/components/zha/test_device.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
"""Test zha device switch."""
|
||||
from datetime import timedelta
|
||||
import time
|
||||
from unittest import mock
|
||||
|
||||
import asynctest
|
||||
import pytest
|
||||
import zigpy.zcl.clusters.general as general
|
||||
|
||||
import homeassistant.components.zha.core.device as zha_core_device
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .common import async_enable_traffic
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def zigpy_device(zigpy_device_mock):
|
||||
"""Device tracker zigpy device."""
|
||||
|
||||
def _dev(with_basic_channel: bool = True):
|
||||
in_clusters = [general.OnOff.cluster_id]
|
||||
if with_basic_channel:
|
||||
in_clusters.append(general.Basic.cluster_id)
|
||||
|
||||
endpoints = {
|
||||
3: {"in_clusters": in_clusters, "out_clusters": [], "device_type": 0}
|
||||
}
|
||||
return zigpy_device_mock(endpoints)
|
||||
|
||||
return _dev
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_with_basic_channel(zigpy_device):
|
||||
"""Return a zha device with a basic channel present."""
|
||||
return zigpy_device(with_basic_channel=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_without_basic_channel(zigpy_device):
|
||||
"""Return a zha device with a basic channel present."""
|
||||
return zigpy_device(with_basic_channel=False)
|
||||
|
||||
|
||||
def _send_time_changed(hass, seconds):
|
||||
"""Send a time changed event."""
|
||||
now = dt_util.utcnow() + timedelta(seconds)
|
||||
hass.bus.async_fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now})
|
||||
|
||||
|
||||
@asynctest.patch(
|
||||
"homeassistant.components.zha.core.channels.general.BasicChannel.async_initialize",
|
||||
new=mock.MagicMock(),
|
||||
)
|
||||
async def test_check_available_success(
|
||||
hass, device_with_basic_channel, zha_device_restored
|
||||
):
|
||||
"""Check device availability success on 1st try."""
|
||||
|
||||
# pylint: disable=protected-access
|
||||
zha_device = await zha_device_restored(device_with_basic_channel)
|
||||
await async_enable_traffic(hass, [zha_device])
|
||||
basic_ch = device_with_basic_channel.endpoints[3].basic
|
||||
|
||||
basic_ch.read_attributes.reset_mock()
|
||||
device_with_basic_channel.last_seen = None
|
||||
assert zha_device.available is True
|
||||
_send_time_changed(hass, 61)
|
||||
await hass.async_block_till_done()
|
||||
assert zha_device.available is False
|
||||
assert basic_ch.read_attributes.await_count == 0
|
||||
|
||||
device_with_basic_channel.last_seen = (
|
||||
time.time() - zha_core_device._KEEP_ALIVE_INTERVAL - 2
|
||||
)
|
||||
_seens = [time.time(), device_with_basic_channel.last_seen]
|
||||
|
||||
def _update_last_seen(*args, **kwargs):
|
||||
device_with_basic_channel.last_seen = _seens.pop()
|
||||
|
||||
basic_ch.read_attributes.side_effect = _update_last_seen
|
||||
|
||||
# successfully ping zigpy device, but zha_device is not yet available
|
||||
_send_time_changed(hass, 61)
|
||||
await hass.async_block_till_done()
|
||||
assert basic_ch.read_attributes.await_count == 1
|
||||
assert basic_ch.read_attributes.await_args[0][0] == ["manufacturer"]
|
||||
assert zha_device.available is False
|
||||
|
||||
# There was traffic from the device: pings, but not yet available
|
||||
_send_time_changed(hass, 61)
|
||||
await hass.async_block_till_done()
|
||||
assert basic_ch.read_attributes.await_count == 2
|
||||
assert basic_ch.read_attributes.await_args[0][0] == ["manufacturer"]
|
||||
assert zha_device.available is False
|
||||
|
||||
# There was traffic from the device: don't try to ping, marked as available
|
||||
_send_time_changed(hass, 61)
|
||||
await hass.async_block_till_done()
|
||||
assert basic_ch.read_attributes.await_count == 2
|
||||
assert basic_ch.read_attributes.await_args[0][0] == ["manufacturer"]
|
||||
assert zha_device.available is True
|
||||
|
||||
|
||||
@asynctest.patch(
|
||||
"homeassistant.components.zha.core.channels.general.BasicChannel.async_initialize",
|
||||
new=mock.MagicMock(),
|
||||
)
|
||||
async def test_check_available_unsuccessful(
|
||||
hass, device_with_basic_channel, zha_device_restored
|
||||
):
|
||||
"""Check device availability all tries fail."""
|
||||
|
||||
# pylint: disable=protected-access
|
||||
zha_device = await zha_device_restored(device_with_basic_channel)
|
||||
await async_enable_traffic(hass, [zha_device])
|
||||
basic_ch = device_with_basic_channel.endpoints[3].basic
|
||||
|
||||
assert zha_device.available is True
|
||||
assert basic_ch.read_attributes.await_count == 0
|
||||
|
||||
device_with_basic_channel.last_seen = (
|
||||
time.time() - zha_core_device._KEEP_ALIVE_INTERVAL - 2
|
||||
)
|
||||
|
||||
# unsuccessfuly ping zigpy device, but zha_device is still available
|
||||
_send_time_changed(hass, 61)
|
||||
await hass.async_block_till_done()
|
||||
assert basic_ch.read_attributes.await_count == 1
|
||||
assert basic_ch.read_attributes.await_args[0][0] == ["manufacturer"]
|
||||
assert zha_device.available is True
|
||||
|
||||
# still no traffic, but zha_device is still available
|
||||
_send_time_changed(hass, 61)
|
||||
await hass.async_block_till_done()
|
||||
assert basic_ch.read_attributes.await_count == 2
|
||||
assert basic_ch.read_attributes.await_args[0][0] == ["manufacturer"]
|
||||
assert zha_device.available is True
|
||||
|
||||
# not even trying to update, device is unavailble
|
||||
_send_time_changed(hass, 61)
|
||||
await hass.async_block_till_done()
|
||||
assert basic_ch.read_attributes.await_count == 2
|
||||
assert basic_ch.read_attributes.await_args[0][0] == ["manufacturer"]
|
||||
assert zha_device.available is False
|
Loading…
Add table
Reference in a new issue