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.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers import aiohttp_client, device_registry, update_coordinator
|
from homeassistant.helpers import aiohttp_client, device_registry, update_coordinator
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.debounce import Debouncer
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
@ -39,6 +40,8 @@ from .const import (
|
||||||
DEFAULT_COAP_PORT,
|
DEFAULT_COAP_PORT,
|
||||||
DEVICE,
|
DEVICE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
DUAL_MODE_LIGHT_MODELS,
|
||||||
|
ENTRY_RELOAD_COOLDOWN,
|
||||||
EVENT_SHELLY_CLICK,
|
EVENT_SHELLY_CLICK,
|
||||||
INPUTS_EVENTS_DICT,
|
INPUTS_EVENTS_DICT,
|
||||||
POLLING_TIMEOUT_SEC,
|
POLLING_TIMEOUT_SEC,
|
||||||
|
@ -252,6 +255,18 @@ class BlockDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
||||||
self.entry = entry
|
self.entry = entry
|
||||||
self.device = device
|
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(
|
entry.async_on_unload(
|
||||||
self.async_add_listener(self._async_device_updates_handler)
|
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)
|
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
|
@callback
|
||||||
def _async_device_updates_handler(self) -> None:
|
def _async_device_updates_handler(self) -> None:
|
||||||
"""Handle device updates."""
|
"""Handle device updates."""
|
||||||
|
@ -280,8 +300,24 @@ class BlockDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Check for input events
|
# Check for input events and config change
|
||||||
|
cfg_changed = 0
|
||||||
for block in self.device.blocks:
|
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 (
|
if (
|
||||||
"inputEvent" not in block.sensor_ids
|
"inputEvent" not in block.sensor_ids
|
||||||
or "inputEventCnt" not in block.sensor_ids
|
or "inputEventCnt" not in block.sensor_ids
|
||||||
|
@ -318,6 +354,15 @@ class BlockDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
||||||
self.name,
|
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:
|
async def _async_update_data(self) -> None:
|
||||||
"""Fetch data."""
|
"""Fetch data."""
|
||||||
if sleep_period := self.entry.data.get("sleep_period"):
|
if sleep_period := self.entry.data.get("sleep_period"):
|
||||||
|
@ -496,6 +541,15 @@ class RpcDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
||||||
self.entry = entry
|
self.entry = entry
|
||||||
self.device = device
|
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(
|
entry.async_on_unload(
|
||||||
self.async_add_listener(self._async_device_updates_handler)
|
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)
|
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
|
@callback
|
||||||
def _async_device_updates_handler(self) -> None:
|
def _async_device_updates_handler(self) -> None:
|
||||||
"""Handle device updates."""
|
"""Handle device updates."""
|
||||||
|
@ -518,7 +577,18 @@ class RpcDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
||||||
self._last_event = self.device.event
|
self._last_event = self.device.event
|
||||||
|
|
||||||
for event in self.device.event["events"]:
|
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
|
continue
|
||||||
|
|
||||||
self.hass.bus.async_fire(
|
self.hass.bus.async_fire(
|
||||||
|
|
|
@ -35,6 +35,14 @@ MODELS_SUPPORTING_LIGHT_TRANSITION: Final = (
|
||||||
"SHVIN-1",
|
"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.
|
# Used in "_async_update_data" as timeout for polling data from devices.
|
||||||
POLLING_TIMEOUT_SEC: Final = 18
|
POLLING_TIMEOUT_SEC: Final = 18
|
||||||
|
|
||||||
|
@ -137,3 +145,6 @@ UPTIME_DEVIATION: Final = 5
|
||||||
|
|
||||||
# Max RPC switch/input key instances
|
# Max RPC switch/input key instances
|
||||||
MAX_RPC_KEY_INSTANCES = 4
|
MAX_RPC_KEY_INSTANCES = 4
|
||||||
|
|
||||||
|
# Time to wait before reloading entry upon device config change
|
||||||
|
ENTRY_RELOAD_COOLDOWN = 60
|
||||||
|
|
Loading…
Reference in New Issue