Reduce bond fallback polling interval when BPUP is alive (#90871)

* Reduce bond fallback polling interval when BPUP is alive

If push updates are alive we should not check every
10 seconds.

* tweak

* tweak

* coverage

* coverage

* coverage
This commit is contained in:
J. Nick Koston 2023-04-08 17:12:42 -10:00 committed by GitHub
parent 8fe597b7c6
commit 59872f1914
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 12 deletions

View file

@ -17,9 +17,9 @@ from homeassistant.const import (
ATTR_SW_VERSION,
ATTR_VIA_DEVICE,
)
from homeassistant.core import callback
from homeassistant.core import CALLBACK_TYPE, callback
from homeassistant.helpers.entity import DeviceInfo, Entity
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.event import async_call_later
from .const import DOMAIN
from .utils import BondDevice, BondHub
@ -27,6 +27,7 @@ from .utils import BondDevice, BondHub
_LOGGER = logging.getLogger(__name__)
_FALLBACK_SCAN_INTERVAL = timedelta(seconds=10)
_BPUP_ALIVE_SCAN_INTERVAL = timedelta(seconds=60)
class BondEntity(Entity):
@ -65,6 +66,7 @@ class BondEntity(Entity):
self._attr_name = device.name
self._attr_assumed_state = self._hub.is_bridge and not self._device.trust_state
self._apply_state()
self._bpup_polling_fallback: CALLBACK_TYPE | None = None
@property
def device_info(self) -> DeviceInfo:
@ -100,12 +102,13 @@ class BondEntity(Entity):
return device_info
async def async_update(self) -> None:
"""Fetch assumed state of the cover from the hub using API."""
"""Perform a manual update from API."""
await self._async_update_from_api()
@callback
def _async_update_if_bpup_not_alive(self, now: datetime) -> None:
"""Fetch via the API if BPUP is not alive."""
self._async_schedule_bpup_alive_or_poll()
if (
self.hass.is_stopping
or self._bpup_subs.alive
@ -172,16 +175,22 @@ class BondEntity(Entity):
"""Subscribe to BPUP and start polling."""
await super().async_added_to_hass()
self._bpup_subs.subscribe(self._device_id, self._async_bpup_callback)
self.async_on_remove(
async_track_time_interval(
self.hass,
self._async_update_if_bpup_not_alive,
_FALLBACK_SCAN_INTERVAL,
name=f"Bond {self.entity_id} fallback polling",
)
self._async_schedule_bpup_alive_or_poll()
@callback
def _async_schedule_bpup_alive_or_poll(self) -> None:
"""Schedule the BPUP alive or poll."""
alive = self._bpup_subs.alive
self._bpup_polling_fallback = async_call_later(
self.hass,
_BPUP_ALIVE_SCAN_INTERVAL if alive else _FALLBACK_SCAN_INTERVAL,
self._async_update_if_bpup_not_alive,
)
async def async_will_remove_from_hass(self) -> None:
"""Unsubscribe from BPUP data on remove."""
await super().async_will_remove_from_hass()
self._bpup_subs.unsubscribe(self._device_id, self._async_bpup_callback)
if self._bpup_polling_fallback:
self._bpup_polling_fallback()
self._bpup_polling_fallback = None

View file

@ -127,7 +127,12 @@ def patch_bond_version(
return nullcontext()
if return_value is None:
return_value = {"bondid": "ZXXX12345"}
return_value = {
"bondid": "ZXXX12345",
"target": "test-model",
"fw_ver": "test-version",
"mcu_ver": "test-hw-version",
}
return patch(
"homeassistant.components.bond.Bond.version",

View file

@ -42,5 +42,12 @@ async def test_diagnostics(
"data": {"access_token": "**REDACTED**", "host": "some host"},
"title": "Mock Title",
},
"hub": {"version": {"bondid": "ZXXX12345"}},
"hub": {
"version": {
"bondid": "ZXXX12345",
"fw_ver": "test-version",
"mcu_ver": "test-hw-version",
"target": "test-model",
}
},
}

View file

@ -468,3 +468,63 @@ async def test_fan_available(hass: HomeAssistant) -> None:
await help_test_entity_available(
hass, FAN_DOMAIN, ceiling_fan("name-1"), "fan.name_1"
)
async def test_setup_smart_by_bond_fan(hass: HomeAssistant) -> None:
"""Test setting up a fan without a hub."""
config_entry = await setup_platform(
hass,
FAN_DOMAIN,
ceiling_fan("name-1"),
bond_device_id="test-device-id",
bond_version={
"bondid": "KXXX12345",
"target": "test-model",
"fw_ver": "test-version",
"mcu_ver": "test-hw-version",
},
)
assert hass.states.get("fan.name_1") is not None
registry = er.async_get(hass)
entry = registry.async_get("fan.name_1")
assert entry.device_id is not None
device_registry = dr.async_get(hass)
device = device_registry.async_get(entry.device_id)
assert device is not None
assert device.sw_version == "test-version"
assert device.manufacturer == "Olibra"
assert device.identifiers == {("bond", "KXXX12345", "test-device-id")}
assert device.hw_version == "test-hw-version"
await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done()
async def test_setup_hub_template_fan(hass: HomeAssistant) -> None:
"""Test setting up a fan on a hub created from a template."""
config_entry = await setup_platform(
hass,
FAN_DOMAIN,
{**ceiling_fan("name-1"), "template": "test-template"},
bond_device_id="test-device-id",
props={"branding_profile": "test-branding-profile"},
bond_version={
"bondid": "ZXXX12345",
"target": "test-model",
"fw_ver": "test-version",
"mcu_ver": "test-hw-version",
},
)
assert hass.states.get("fan.name_1") is not None
registry = er.async_get(hass)
entry = registry.async_get("fan.name_1")
assert entry.device_id is not None
device_registry = dr.async_get(hass)
device = device_registry.async_get(entry.device_id)
assert device is not None
assert device.sw_version is None
assert device.model == "test-branding-profile test-template"
assert device.manufacturer == "Olibra"
assert device.identifiers == {("bond", "ZXXX12345", "test-device-id")}
assert device.hw_version is None
await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done()