mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 08:47:10 +00:00
Add gui config option consider device unavailable (#51218)
* Add gui config option consider device unavailable * Update tests
This commit is contained in:
parent
d1f0ec8db8
commit
ceadb0cba0
@ -137,10 +137,23 @@ CONF_RADIO_TYPE = "radio_type"
|
||||
CONF_USB_PATH = "usb_path"
|
||||
CONF_ZIGPY = "zigpy_config"
|
||||
|
||||
CONF_CONSIDER_UNAVAILABLE_MAINS = "consider_unavailable_mains"
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS = 60 * 60 * 2 # 2 hours
|
||||
CONF_CONSIDER_UNAVAILABLE_BATTERY = "consider_unavailable_battery"
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY = 60 * 60 * 6 # 6 hours
|
||||
|
||||
CONF_ZHA_OPTIONS_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_DEFAULT_LIGHT_TRANSITION): cv.positive_int,
|
||||
vol.Required(CONF_ENABLE_IDENTIFY_ON_JOIN, default=True): cv.boolean,
|
||||
vol.Optional(
|
||||
CONF_CONSIDER_UNAVAILABLE_MAINS,
|
||||
default=CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS,
|
||||
): cv.positive_int,
|
||||
vol.Optional(
|
||||
CONF_CONSIDER_UNAVAILABLE_BATTERY,
|
||||
default=CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY,
|
||||
): cv.positive_int,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -55,6 +55,10 @@ from .const import (
|
||||
CLUSTER_COMMANDS_SERVER,
|
||||
CLUSTER_TYPE_IN,
|
||||
CLUSTER_TYPE_OUT,
|
||||
CONF_CONSIDER_UNAVAILABLE_BATTERY,
|
||||
CONF_CONSIDER_UNAVAILABLE_MAINS,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS,
|
||||
CONF_ENABLE_IDENTIFY_ON_JOIN,
|
||||
EFFECT_DEFAULT_VARIANT,
|
||||
EFFECT_OKAY,
|
||||
@ -70,8 +74,6 @@ from .const import (
|
||||
from .helpers import LogMixin, async_get_zha_config_value
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CONSIDER_UNAVAILABLE_MAINS = 60 * 60 * 2 # 2 hours
|
||||
CONSIDER_UNAVAILABLE_BATTERY = 60 * 60 * 6 # 6 hours
|
||||
_UPDATE_ALIVE_INTERVAL = (60, 90)
|
||||
_CHECKIN_GRACE_PERIODS = 2
|
||||
|
||||
@ -107,9 +109,20 @@ class ZHADevice(LogMixin):
|
||||
)
|
||||
|
||||
if self.is_mains_powered:
|
||||
self._consider_unavailable_time = CONSIDER_UNAVAILABLE_MAINS
|
||||
self.consider_unavailable_time = async_get_zha_config_value(
|
||||
self._zha_gateway.config_entry,
|
||||
ZHA_OPTIONS,
|
||||
CONF_CONSIDER_UNAVAILABLE_MAINS,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS,
|
||||
)
|
||||
else:
|
||||
self._consider_unavailable_time = CONSIDER_UNAVAILABLE_BATTERY
|
||||
self.consider_unavailable_time = async_get_zha_config_value(
|
||||
self._zha_gateway.config_entry,
|
||||
ZHA_OPTIONS,
|
||||
CONF_CONSIDER_UNAVAILABLE_BATTERY,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY,
|
||||
)
|
||||
|
||||
keep_alive_interval = random.randint(*_UPDATE_ALIVE_INTERVAL)
|
||||
self.unsubs.append(
|
||||
async_track_time_interval(
|
||||
@ -320,7 +333,7 @@ class ZHADevice(LogMixin):
|
||||
return
|
||||
|
||||
difference = time.time() - self.last_seen
|
||||
if difference < self._consider_unavailable_time:
|
||||
if difference < self.consider_unavailable_time:
|
||||
self.update_available(True)
|
||||
self._checkins_missed_count = 0
|
||||
return
|
||||
|
@ -77,12 +77,7 @@ from .const import (
|
||||
ZHA_GW_MSG_RAW_INIT,
|
||||
RadioType,
|
||||
)
|
||||
from .device import (
|
||||
CONSIDER_UNAVAILABLE_BATTERY,
|
||||
CONSIDER_UNAVAILABLE_MAINS,
|
||||
DeviceStatus,
|
||||
ZHADevice,
|
||||
)
|
||||
from .device import DeviceStatus, ZHADevice
|
||||
from .group import GroupMember, ZHAGroup
|
||||
from .registries import GROUP_ENTITY_DOMAINS
|
||||
from .store import async_get_registry
|
||||
@ -185,17 +180,15 @@ class ZHAGateway:
|
||||
delta_msg = "not known"
|
||||
if zha_dev_entry and zha_dev_entry.last_seen is not None:
|
||||
delta = round(time.time() - zha_dev_entry.last_seen)
|
||||
if zha_device.is_mains_powered:
|
||||
zha_device.available = delta < CONSIDER_UNAVAILABLE_MAINS
|
||||
else:
|
||||
zha_device.available = delta < CONSIDER_UNAVAILABLE_BATTERY
|
||||
zha_device.available = delta < zha_device.consider_unavailable_time
|
||||
delta_msg = f"{str(timedelta(seconds=delta))} ago"
|
||||
_LOGGER.debug(
|
||||
"[%s](%s) restored as '%s', last seen: %s",
|
||||
"[%s](%s) restored as '%s', last seen: %s, consider_unavailable_time: %s seconds",
|
||||
zha_device.nwk,
|
||||
zha_device.name,
|
||||
"available" if zha_device.available else "unavailable",
|
||||
delta_msg,
|
||||
zha_device.consider_unavailable_time,
|
||||
)
|
||||
# update the last seen time for devices every 10 minutes to avoid thrashing
|
||||
# writes and shutdown issues where storage isn't updated
|
||||
|
@ -33,7 +33,9 @@
|
||||
"zha_options": {
|
||||
"title": "Global Options",
|
||||
"enable_identify_on_join": "Enable identify effect when devices join the network",
|
||||
"default_light_transition": "Default light transition time (seconds)"
|
||||
"default_light_transition": "Default light transition time (seconds)",
|
||||
"consider_unavailable_mains": "Consider mains powered devices unavailable after (seconds)",
|
||||
"consider_unavailable_battery": "Consider battery powered devices unavailable after (seconds)"
|
||||
},
|
||||
"zha_alarm_options": {
|
||||
"title": "Alarm Control Panel Options",
|
||||
|
@ -43,6 +43,8 @@
|
||||
"zha_options": {
|
||||
"default_light_transition": "Default light transition time (seconds)",
|
||||
"enable_identify_on_join": "Enable identify effect when devices join the network",
|
||||
"consider_unavailable_mains": "Consider mains powered devices unavailable after (seconds)",
|
||||
"consider_unavailable_battery": "Consider battery powered devices unavailable after (seconds)",
|
||||
"title": "Global Options"
|
||||
}
|
||||
},
|
||||
|
@ -8,7 +8,10 @@ import pytest
|
||||
import zigpy.profiles.zha
|
||||
import zigpy.zcl.clusters.general as general
|
||||
|
||||
import homeassistant.components.zha.core.device as zha_core_device
|
||||
from homeassistant.components.zha.core.const import (
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS,
|
||||
)
|
||||
from homeassistant.const import STATE_OFF, STATE_UNAVAILABLE
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
import homeassistant.util.dt as dt_util
|
||||
@ -117,13 +120,13 @@ async def test_check_available_success(
|
||||
basic_ch.read_attributes.reset_mock()
|
||||
device_with_basic_channel.last_seen = None
|
||||
assert zha_device.available is True
|
||||
_send_time_changed(hass, zha_core_device.CONSIDER_UNAVAILABLE_MAINS + 2)
|
||||
_send_time_changed(hass, zha_device.consider_unavailable_time + 2)
|
||||
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.CONSIDER_UNAVAILABLE_MAINS - 2
|
||||
time.time() - zha_device.consider_unavailable_time - 2
|
||||
)
|
||||
_seens = [time.time(), device_with_basic_channel.last_seen]
|
||||
|
||||
@ -172,7 +175,7 @@ async def test_check_available_unsuccessful(
|
||||
assert basic_ch.read_attributes.await_count == 0
|
||||
|
||||
device_with_basic_channel.last_seen = (
|
||||
time.time() - zha_core_device.CONSIDER_UNAVAILABLE_MAINS - 2
|
||||
time.time() - zha_device.consider_unavailable_time - 2
|
||||
)
|
||||
|
||||
# unsuccessfuly ping zigpy device, but zha_device is still available
|
||||
@ -213,7 +216,7 @@ async def test_check_available_no_basic_channel(
|
||||
assert zha_device.available is True
|
||||
|
||||
device_without_basic_channel.last_seen = (
|
||||
time.time() - zha_core_device.CONSIDER_UNAVAILABLE_BATTERY - 2
|
||||
time.time() - zha_device.consider_unavailable_time - 2
|
||||
)
|
||||
|
||||
assert "does not have a mandatory basic cluster" not in caplog.text
|
||||
@ -246,38 +249,38 @@ async def test_ota_sw_version(hass, ota_zha_device):
|
||||
("zigpy_device", 0, True),
|
||||
(
|
||||
"zigpy_device",
|
||||
zha_core_device.CONSIDER_UNAVAILABLE_MAINS + 2,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS + 2,
|
||||
True,
|
||||
),
|
||||
(
|
||||
"zigpy_device",
|
||||
zha_core_device.CONSIDER_UNAVAILABLE_BATTERY - 2,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY - 2,
|
||||
True,
|
||||
),
|
||||
(
|
||||
"zigpy_device",
|
||||
zha_core_device.CONSIDER_UNAVAILABLE_BATTERY + 2,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY + 2,
|
||||
False,
|
||||
),
|
||||
("zigpy_device_mains", 0, True),
|
||||
(
|
||||
"zigpy_device_mains",
|
||||
zha_core_device.CONSIDER_UNAVAILABLE_MAINS - 2,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS - 2,
|
||||
True,
|
||||
),
|
||||
(
|
||||
"zigpy_device_mains",
|
||||
zha_core_device.CONSIDER_UNAVAILABLE_MAINS + 2,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS + 2,
|
||||
False,
|
||||
),
|
||||
(
|
||||
"zigpy_device_mains",
|
||||
zha_core_device.CONSIDER_UNAVAILABLE_BATTERY - 2,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY - 2,
|
||||
False,
|
||||
),
|
||||
(
|
||||
"zigpy_device_mains",
|
||||
zha_core_device.CONSIDER_UNAVAILABLE_BATTERY + 2,
|
||||
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY + 2,
|
||||
False,
|
||||
),
|
||||
),
|
||||
|
@ -7,7 +7,6 @@ import zigpy.profiles.zha
|
||||
import zigpy.zcl.clusters.general as general
|
||||
|
||||
import homeassistant.components.automation as automation
|
||||
import homeassistant.components.zha.core.device as zha_core_device
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
@ -252,9 +251,7 @@ async def test_device_offline_fires(
|
||||
await hass.async_block_till_done()
|
||||
assert zha_device.available is True
|
||||
|
||||
zigpy_device.last_seen = (
|
||||
time.time() - zha_core_device.CONSIDER_UNAVAILABLE_BATTERY - 2
|
||||
)
|
||||
zigpy_device.last_seen = time.time() - zha_device.consider_unavailable_time - 2
|
||||
|
||||
# there are 3 checkins to perform before marking the device unavailable
|
||||
future = dt_util.utcnow() + timedelta(seconds=90)
|
||||
@ -266,7 +263,7 @@ async def test_device_offline_fires(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
future = dt_util.utcnow() + timedelta(
|
||||
seconds=zha_core_device.CONSIDER_UNAVAILABLE_BATTERY + 100
|
||||
seconds=zha_device.consider_unavailable_time + 100
|
||||
)
|
||||
async_fire_time_changed(hass, future)
|
||||
await hass.async_block_till_done()
|
||||
|
Loading…
x
Reference in New Issue
Block a user