Add Shelly config entry reload on device config change (#57356)

pull/57394/head
Shay Levy 2021-10-09 19:10:43 +03:00 committed by GitHub
parent 6a5895222e
commit 8de7966104
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 2 deletions

View File

@ -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(

View File

@ -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