Rescan static wemo (#49934)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
CantankerousBullMoose 2021-05-17 03:18:14 -07:00 committed by GitHub
parent 1c7242a37a
commit 9316f566c9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 28 deletions

View file

@ -1,5 +1,6 @@
"""Support for WeMo device discovery.""" """Support for WeMo device discovery."""
import asyncio from __future__ import annotations
import logging import logging
import pywemo import pywemo
@ -16,9 +17,14 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_call_later from homeassistant.helpers.event import async_call_later
from homeassistant.util.async_ import gather_with_concurrency
from .const import DOMAIN from .const import DOMAIN
# Max number of devices to initialize at once. This limit is in place to
# avoid tying up too many executor threads with WeMo device setup.
MAX_CONCURRENCY = 3
# Mapping from Wemo model_name to domain. # Mapping from Wemo model_name to domain.
WEMO_MODEL_DISPATCH = { WEMO_MODEL_DISPATCH = {
"Bridge": LIGHT_DOMAIN, "Bridge": LIGHT_DOMAIN,
@ -99,9 +105,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
# Keep track of WeMo device subscriptions for push updates # Keep track of WeMo device subscriptions for push updates
registry = hass.data[DOMAIN]["registry"] = pywemo.SubscriptionRegistry() registry = hass.data[DOMAIN]["registry"] = pywemo.SubscriptionRegistry()
await hass.async_add_executor_job(registry.start) await hass.async_add_executor_job(registry.start)
static_conf = config.get(CONF_STATIC, [])
wemo_dispatcher = WemoDispatcher(entry) wemo_dispatcher = WemoDispatcher(entry)
wemo_discovery = WemoDiscovery(hass, wemo_dispatcher) wemo_discovery = WemoDiscovery(hass, wemo_dispatcher, static_conf)
async def async_stop_wemo(event): async def async_stop_wemo(event):
"""Shutdown Wemo subscriptions and subscription thread on exit.""" """Shutdown Wemo subscriptions and subscription thread on exit."""
@ -113,17 +119,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_stop_wemo) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_stop_wemo)
) )
static_conf = config.get(CONF_STATIC, []) # Need to do this at least once in case statics are defined and discovery is disabled
if static_conf: await wemo_discovery.discover_statics()
_LOGGER.debug("Adding statically configured WeMo devices")
for device in await asyncio.gather(
*[
hass.async_add_executor_job(validate_static_config, host, port)
for host, port in static_conf
]
):
if device:
wemo_dispatcher.async_add_unique_device(hass, device)
if config.get(CONF_DISCOVERY, DEFAULT_DISCOVERY): if config.get(CONF_DISCOVERY, DEFAULT_DISCOVERY):
await wemo_discovery.async_discover_and_schedule() await wemo_discovery.async_discover_and_schedule()
@ -183,12 +180,18 @@ class WemoDiscovery:
ADDITIONAL_SECONDS_BETWEEN_SCANS = 10 ADDITIONAL_SECONDS_BETWEEN_SCANS = 10
MAX_SECONDS_BETWEEN_SCANS = 300 MAX_SECONDS_BETWEEN_SCANS = 300
def __init__(self, hass: HomeAssistant, wemo_dispatcher: WemoDispatcher) -> None: def __init__(
self,
hass: HomeAssistant,
wemo_dispatcher: WemoDispatcher,
static_config: list[tuple[[str, str | None]]],
) -> None:
"""Initialize the WemoDiscovery.""" """Initialize the WemoDiscovery."""
self._hass = hass self._hass = hass
self._wemo_dispatcher = wemo_dispatcher self._wemo_dispatcher = wemo_dispatcher
self._stop = None self._stop = None
self._scan_delay = 0 self._scan_delay = 0
self._static_config = static_config
async def async_discover_and_schedule(self, *_) -> None: async def async_discover_and_schedule(self, *_) -> None:
"""Periodically scan the network looking for WeMo devices.""" """Periodically scan the network looking for WeMo devices."""
@ -198,6 +201,8 @@ class WemoDiscovery:
pywemo.discover_devices pywemo.discover_devices
): ):
self._wemo_dispatcher.async_add_unique_device(self._hass, device) self._wemo_dispatcher.async_add_unique_device(self._hass, device)
await self.discover_statics()
finally: finally:
# Run discovery more frequently after hass has just started. # Run discovery more frequently after hass has just started.
self._scan_delay = min( self._scan_delay = min(
@ -217,6 +222,22 @@ class WemoDiscovery:
self._stop() self._stop()
self._stop = None self._stop = None
async def discover_statics(self):
"""Initialize or Re-Initialize connections to statically configured devices."""
if self._static_config:
_LOGGER.debug("Adding statically configured WeMo devices")
for device in await gather_with_concurrency(
MAX_CONCURRENCY,
*[
self._hass.async_add_executor_job(
validate_static_config, host, port
)
for host, port in self._static_config
],
):
if device:
self._wemo_dispatcher.async_add_unique_device(self._hass, device)
def validate_static_config(host, port): def validate_static_config(host, port):
"""Handle a static config.""" """Handle a static config."""

View file

@ -117,20 +117,26 @@ async def test_discovery(hass, pywemo_registry):
with patch( with patch(
"pywemo.discover_devices", return_value=pywemo_devices "pywemo.discover_devices", return_value=pywemo_devices
) as mock_discovery: ) as mock_discovery:
assert await async_setup_component( with patch(
hass, DOMAIN, {DOMAIN: {CONF_DISCOVERY: True}} "homeassistant.components.wemo.WemoDiscovery.discover_statics"
) ) as mock_discover_statics:
await pywemo_registry.semaphore.acquire() # Returns after platform setup. assert await async_setup_component(
mock_discovery.assert_called() hass, DOMAIN, {DOMAIN: {CONF_DISCOVERY: True}}
pywemo_devices.append(create_device(2)) )
await pywemo_registry.semaphore.acquire() # Returns after platform setup.
mock_discovery.assert_called()
mock_discover_statics.assert_called()
pywemo_devices.append(create_device(2))
# Test that discovery runs periodically and the async_dispatcher_send code works. # Test that discovery runs periodically and the async_dispatcher_send code works.
async_fire_time_changed( async_fire_time_changed(
hass, hass,
dt.utcnow() dt.utcnow()
+ timedelta(seconds=WemoDiscovery.ADDITIONAL_SECONDS_BETWEEN_SCANS + 1), + timedelta(seconds=WemoDiscovery.ADDITIONAL_SECONDS_BETWEEN_SCANS + 1),
) )
await hass.async_block_till_done() await hass.async_block_till_done()
# Test that discover_statics runs during discovery
assert mock_discover_statics.call_count == 3
# Verify that the expected number of devices were setup. # Verify that the expected number of devices were setup.
entity_reg = er.async_get(hass) entity_reg = er.async_get(hass)