Add Shelly config entry reload on device config change (#57356)
parent
6a5895222e
commit
8de7966104
|
@ -24,6 +24,7 @@ from homeassistant.core import Event, HomeAssistant, callback
|
|||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import aiohttp_client, device_registry, update_coordinator
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import (
|
||||
|
@ -39,6 +40,8 @@ from .const import (
|
|||
DEFAULT_COAP_PORT,
|
||||
DEVICE,
|
||||
DOMAIN,
|
||||
DUAL_MODE_LIGHT_MODELS,
|
||||
ENTRY_RELOAD_COOLDOWN,
|
||||
EVENT_SHELLY_CLICK,
|
||||
INPUTS_EVENTS_DICT,
|
||||
POLLING_TIMEOUT_SEC,
|
||||
|
@ -252,6 +255,18 @@ class BlockDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
self.entry = entry
|
||||
self.device = device
|
||||
|
||||
self._debounced_reload = Debouncer(
|
||||
hass,
|
||||
_LOGGER,
|
||||
cooldown=ENTRY_RELOAD_COOLDOWN,
|
||||
immediate=False,
|
||||
function=self._async_reload_entry,
|
||||
)
|
||||
entry.async_on_unload(self._debounced_reload.async_cancel)
|
||||
self._last_cfg_changed: int | None = None
|
||||
self._last_mode: str | None = None
|
||||
self._last_effect: int | None = None
|
||||
|
||||
entry.async_on_unload(
|
||||
self.async_add_listener(self._async_device_updates_handler)
|
||||
)
|
||||
|
@ -261,6 +276,11 @@ class BlockDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self._handle_ha_stop)
|
||||
)
|
||||
|
||||
async def _async_reload_entry(self) -> None:
|
||||
"""Reload entry."""
|
||||
_LOGGER.debug("Reloading entry %s", self.name)
|
||||
await self.hass.config_entries.async_reload(self.entry.entry_id)
|
||||
|
||||
@callback
|
||||
def _async_device_updates_handler(self) -> None:
|
||||
"""Handle device updates."""
|
||||
|
@ -280,8 +300,24 @@ class BlockDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
|
||||
break
|
||||
|
||||
# Check for input events
|
||||
# Check for input events and config change
|
||||
cfg_changed = 0
|
||||
for block in self.device.blocks:
|
||||
if block.type == "device":
|
||||
cfg_changed = block.cfgChanged
|
||||
|
||||
# For dual mode bulbs ignore change if it is due to mode/effect change
|
||||
if self.model in DUAL_MODE_LIGHT_MODELS:
|
||||
if "mode" in block.sensor_ids and self.model != "SHRGBW2":
|
||||
if self._last_mode != block.mode:
|
||||
self._last_cfg_changed = None
|
||||
self._last_mode = block.mode
|
||||
|
||||
if "effect" in block.sensor_ids:
|
||||
if self._last_effect != block.effect:
|
||||
self._last_cfg_changed = None
|
||||
self._last_effect = block.effect
|
||||
|
||||
if (
|
||||
"inputEvent" not in block.sensor_ids
|
||||
or "inputEventCnt" not in block.sensor_ids
|
||||
|
@ -318,6 +354,15 @@ class BlockDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
self.name,
|
||||
)
|
||||
|
||||
if self._last_cfg_changed is not None and cfg_changed > self._last_cfg_changed:
|
||||
_LOGGER.info(
|
||||
"Config for %s changed, reloading entry in %s seconds",
|
||||
self.name,
|
||||
ENTRY_RELOAD_COOLDOWN,
|
||||
)
|
||||
self.hass.async_create_task(self._debounced_reload.async_call())
|
||||
self._last_cfg_changed = cfg_changed
|
||||
|
||||
async def _async_update_data(self) -> None:
|
||||
"""Fetch data."""
|
||||
if sleep_period := self.entry.data.get("sleep_period"):
|
||||
|
@ -496,6 +541,15 @@ class RpcDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
self.entry = entry
|
||||
self.device = device
|
||||
|
||||
self._debounced_reload = Debouncer(
|
||||
hass,
|
||||
_LOGGER,
|
||||
cooldown=ENTRY_RELOAD_COOLDOWN,
|
||||
immediate=False,
|
||||
function=self._async_reload_entry,
|
||||
)
|
||||
entry.async_on_unload(self._debounced_reload.async_cancel)
|
||||
|
||||
entry.async_on_unload(
|
||||
self.async_add_listener(self._async_device_updates_handler)
|
||||
)
|
||||
|
@ -505,6 +559,11 @@ class RpcDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self._handle_ha_stop)
|
||||
)
|
||||
|
||||
async def _async_reload_entry(self) -> None:
|
||||
"""Reload entry."""
|
||||
_LOGGER.debug("Reloading entry %s", self.name)
|
||||
await self.hass.config_entries.async_reload(self.entry.entry_id)
|
||||
|
||||
@callback
|
||||
def _async_device_updates_handler(self) -> None:
|
||||
"""Handle device updates."""
|
||||
|
@ -518,7 +577,18 @@ class RpcDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
self._last_event = self.device.event
|
||||
|
||||
for event in self.device.event["events"]:
|
||||
if event.get("event") not in RPC_INPUTS_EVENTS_TYPES:
|
||||
event_type = event.get("event")
|
||||
if event_type is None:
|
||||
continue
|
||||
|
||||
if event_type == "config_changed":
|
||||
_LOGGER.info(
|
||||
"Config for %s changed, reloading entry in %s seconds",
|
||||
self.name,
|
||||
ENTRY_RELOAD_COOLDOWN,
|
||||
)
|
||||
self.hass.async_create_task(self._debounced_reload.async_call())
|
||||
elif event_type not in RPC_INPUTS_EVENTS_TYPES:
|
||||
continue
|
||||
|
||||
self.hass.bus.async_fire(
|
||||
|
|
|
@ -35,6 +35,14 @@ MODELS_SUPPORTING_LIGHT_TRANSITION: Final = (
|
|||
"SHVIN-1",
|
||||
)
|
||||
|
||||
# Bulbs that support white & color modes
|
||||
DUAL_MODE_LIGHT_MODELS: Final = (
|
||||
"SHBDUO-1",
|
||||
"SHBLB-1",
|
||||
"SHCB-1",
|
||||
"SHRGBW2",
|
||||
)
|
||||
|
||||
# Used in "_async_update_data" as timeout for polling data from devices.
|
||||
POLLING_TIMEOUT_SEC: Final = 18
|
||||
|
||||
|
@ -137,3 +145,6 @@ UPTIME_DEVIATION: Final = 5
|
|||
|
||||
# Max RPC switch/input key instances
|
||||
MAX_RPC_KEY_INSTANCES = 4
|
||||
|
||||
# Time to wait before reloading entry upon device config change
|
||||
ENTRY_RELOAD_COOLDOWN = 60
|
||||
|
|
Loading…
Reference in New Issue