Discover tplink devices periodically (#57221)

- These devices sometimes do not respond on the first try
  or may be subject to transient broadcast failures, or
  overloads. We now try discovery periodically once the
  integration has been loaded.

- We used to try this 4x at startup, but that solution
  seemed to aggressive as we want to be sure we pickup
  the devices after startup as well since the network
  will likely be more calm after startup.
This commit is contained in:
J. Nick Koston 2021-10-07 05:52:24 -10:00 committed by GitHub
parent a238cce37c
commit a2dcc0308b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 6 deletions

View file

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from datetime import timedelta
from typing import Any from typing import Any
from kasa import SmartDevice, SmartDeviceException from kasa import SmartDevice, SmartDeviceException
@ -11,9 +12,15 @@ import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import network from homeassistant.components import network
from homeassistant.config_entries import ConfigEntry, ConfigEntryNotReady from homeassistant.config_entries import ConfigEntry, ConfigEntryNotReady
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME from homeassistant.const import (
CONF_HOST,
CONF_MAC,
CONF_NAME,
EVENT_HOMEASSISTANT_STARTED,
)
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, device_registry as dr from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from .const import ( from .const import (
@ -32,6 +39,8 @@ from .migration import (
async_migrate_yaml_entries, async_migrate_yaml_entries,
) )
DISCOVERY_INTERVAL = timedelta(minutes=15)
TPLINK_HOST_SCHEMA = vol.Schema({vol.Required(CONF_HOST): cv.string}) TPLINK_HOST_SCHEMA = vol.Schema({vol.Required(CONF_HOST): cv.string})
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
@ -118,6 +127,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
if discovered_devices: if discovered_devices:
async_trigger_discovery(hass, discovered_devices) async_trigger_discovery(hass, discovered_devices)
async def _async_discovery(*_: Any) -> None:
if discovered := await async_discover_devices(hass):
async_trigger_discovery(hass, discovered)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _async_discovery)
async_track_time_interval(hass, _async_discovery, DISCOVERY_INTERVAL)
return True return True

View file

@ -1,27 +1,41 @@
"""Tests for the TP-Link component.""" """Tests for the TP-Link component."""
from __future__ import annotations from __future__ import annotations
from unittest.mock import patch from datetime import timedelta
from unittest.mock import MagicMock, patch
from homeassistant.components import tplink from homeassistant.components import tplink
from homeassistant.components.tplink.const import DOMAIN from homeassistant.components.tplink.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_HOST from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STARTED
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util
from . import IP_ADDRESS, MAC_ADDRESS, _patch_discovery, _patch_single_discovery from . import IP_ADDRESS, MAC_ADDRESS, _patch_discovery, _patch_single_discovery
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, async_fire_time_changed
async def test_configuring_tplink_causes_discovery(hass): async def test_configuring_tplink_causes_discovery(hass):
"""Test that specifying empty config does discovery.""" """Test that specifying empty config does discovery."""
with patch("homeassistant.components.tplink.Discover.discover") as discover: with patch("homeassistant.components.tplink.Discover.discover") as discover:
discover.return_value = {"host": 1234} discover.return_value = {MagicMock(): MagicMock()}
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
call_count = len(discover.mock_calls)
assert discover.mock_calls
assert discover.mock_calls hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert len(discover.mock_calls) == call_count * 2
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15))
await hass.async_block_till_done()
assert len(discover.mock_calls) == call_count * 3
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=30))
await hass.async_block_till_done()
assert len(discover.mock_calls) == call_count * 4
async def test_config_entry_reload(hass): async def test_config_entry_reload(hass):