Ensure doorbird events are re-registered when changing options (#46860)

- Fixed the update listener not being unsubscribed

- DRY up some of the code

- Fix sync code being called in async

- Reduce executor jumps
pull/47041/head
J. Nick Koston 2021-02-25 01:16:20 -06:00 committed by GitHub
parent a43f3c1a0c
commit 72263abfa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 22 deletions

View File

@ -34,6 +34,7 @@ from .const import (
DOOR_STATION_EVENT_ENTITY_IDS, DOOR_STATION_EVENT_ENTITY_IDS,
DOOR_STATION_INFO, DOOR_STATION_INFO,
PLATFORMS, PLATFORMS,
UNDO_UPDATE_LISTENER,
) )
from .util import get_doorstation_by_token from .util import get_doorstation_by_token
@ -128,8 +129,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
device = DoorBird(device_ip, username, password) device = DoorBird(device_ip, username, password)
try: try:
status = await hass.async_add_executor_job(device.ready) status, info = await hass.async_add_executor_job(_init_doorbird_device, device)
info = await hass.async_add_executor_job(device.info)
except urllib.error.HTTPError as err: except urllib.error.HTTPError as err:
if err.code == HTTP_UNAUTHORIZED: if err.code == HTTP_UNAUTHORIZED:
_LOGGER.error( _LOGGER.error(
@ -154,18 +154,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
custom_url = doorstation_config.get(CONF_CUSTOM_URL) custom_url = doorstation_config.get(CONF_CUSTOM_URL)
name = doorstation_config.get(CONF_NAME) name = doorstation_config.get(CONF_NAME)
events = doorstation_options.get(CONF_EVENTS, []) events = doorstation_options.get(CONF_EVENTS, [])
doorstation = ConfiguredDoorBird(device, name, events, custom_url, token) doorstation = ConfiguredDoorBird(device, name, custom_url, token)
doorstation.update_events(events)
# Subscribe to doorbell or motion events # Subscribe to doorbell or motion events
if not await _async_register_events(hass, doorstation): if not await _async_register_events(hass, doorstation):
raise ConfigEntryNotReady raise ConfigEntryNotReady
undo_listener = entry.add_update_listener(_update_listener)
hass.data[DOMAIN][config_entry_id] = { hass.data[DOMAIN][config_entry_id] = {
DOOR_STATION: doorstation, DOOR_STATION: doorstation,
DOOR_STATION_INFO: info, DOOR_STATION_INFO: info,
UNDO_UPDATE_LISTENER: undo_listener,
} }
entry.add_update_listener(_update_listener)
for component in PLATFORMS: for component in PLATFORMS:
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, component) hass.config_entries.async_forward_entry_setup(entry, component)
@ -174,9 +176,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
return True return True
def _init_doorbird_device(device):
return device.ready(), device.info()
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Unload a config entry.""" """Unload a config entry."""
hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENER]()
unload_ok = all( unload_ok = all(
await asyncio.gather( await asyncio.gather(
*[ *[
@ -195,7 +203,7 @@ async def _async_register_events(hass, doorstation):
try: try:
await hass.async_add_executor_job(doorstation.register_events, hass) await hass.async_add_executor_job(doorstation.register_events, hass)
except HTTPError: except HTTPError:
hass.components.persistent_notification.create( hass.components.persistent_notification.async_create(
"Doorbird configuration failed. Please verify that API " "Doorbird configuration failed. Please verify that API "
"Operator permission is enabled for the Doorbird user. " "Operator permission is enabled for the Doorbird user. "
"A restart will be required once permissions have been " "A restart will be required once permissions have been "
@ -212,8 +220,7 @@ async def _update_listener(hass: HomeAssistant, entry: ConfigEntry):
"""Handle options update.""" """Handle options update."""
config_entry_id = entry.entry_id config_entry_id = entry.entry_id
doorstation = hass.data[DOMAIN][config_entry_id][DOOR_STATION] doorstation = hass.data[DOMAIN][config_entry_id][DOOR_STATION]
doorstation.update_events(entry.options[CONF_EVENTS])
doorstation.events = entry.options[CONF_EVENTS]
# Subscribe to doorbell or motion events # Subscribe to doorbell or motion events
await _async_register_events(hass, doorstation) await _async_register_events(hass, doorstation)
@ -234,14 +241,19 @@ def _async_import_options_from_data_if_missing(hass: HomeAssistant, entry: Confi
class ConfiguredDoorBird: class ConfiguredDoorBird:
"""Attach additional information to pass along with configured device.""" """Attach additional information to pass along with configured device."""
def __init__(self, device, name, events, custom_url, token): def __init__(self, device, name, custom_url, token):
"""Initialize configured device.""" """Initialize configured device."""
self._name = name self._name = name
self._device = device self._device = device
self._custom_url = custom_url self._custom_url = custom_url
self.events = None
self.doorstation_events = None
self._token = token
def update_events(self, events):
"""Update the doorbird events."""
self.events = events self.events = events
self.doorstation_events = [self._get_event_name(event) for event in self.events] self.doorstation_events = [self._get_event_name(event) for event in self.events]
self._token = token
@property @property
def name(self): def name(self):
@ -305,16 +317,7 @@ class ConfiguredDoorBird:
def webhook_is_registered(self, url, favs=None) -> bool: def webhook_is_registered(self, url, favs=None) -> bool:
"""Return whether the given URL is registered as a device favorite.""" """Return whether the given URL is registered as a device favorite."""
favs = favs if favs else self.device.favorites() return self.get_webhook_id(url, favs) is not None
if "http" not in favs:
return False
for fav in favs["http"].values():
if fav["value"] == url:
return True
return False
def get_webhook_id(self, url, favs=None) -> str or None: def get_webhook_id(self, url, favs=None) -> str or None:
""" """

View File

@ -17,3 +17,5 @@ DOORBIRD_INFO_KEY_DEVICE_TYPE = "DEVICE-TYPE"
DOORBIRD_INFO_KEY_RELAYS = "RELAYS" DOORBIRD_INFO_KEY_RELAYS = "RELAYS"
DOORBIRD_INFO_KEY_PRIMARY_MAC_ADDR = "PRIMARY_MAC_ADDR" DOORBIRD_INFO_KEY_PRIMARY_MAC_ADDR = "PRIMARY_MAC_ADDR"
DOORBIRD_INFO_KEY_WIFI_MAC_ADDR = "WIFI_MAC_ADDR" DOORBIRD_INFO_KEY_WIFI_MAC_ADDR = "WIFI_MAC_ADDR"
UNDO_UPDATE_LISTENER = "undo_update_listener"

View File

@ -17,8 +17,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entities = [] entities = []
config_entry_id = config_entry.entry_id config_entry_id = config_entry.entry_id
doorstation = hass.data[DOMAIN][config_entry_id][DOOR_STATION] data = hass.data[DOMAIN][config_entry_id]
doorstation_info = hass.data[DOMAIN][config_entry_id][DOOR_STATION_INFO] doorstation = data[DOOR_STATION]
doorstation_info = data[DOOR_STATION_INFO]
relays = doorstation_info["RELAYS"] relays = doorstation_info["RELAYS"]
relays.append(IR_RELAY) relays.append(IR_RELAY)