diff --git a/homeassistant/components/tplink/common.py b/homeassistant/components/tplink/common.py index ad4c4ff63fa..a8ba48e3935 100644 --- a/homeassistant/components/tplink/common.py +++ b/homeassistant/components/tplink/common.py @@ -13,6 +13,8 @@ from pyHS100 import ( from homeassistant.helpers.typing import HomeAssistantType +from .const import DOMAIN as TPLINK_DOMAIN + _LOGGER = logging.getLogger(__name__) @@ -127,3 +129,31 @@ def get_static_devices(config_data) -> SmartDevices: "Failed to setup device %s due to %s; not retrying", host, sde ) return SmartDevices(lights, switches) + + +def add_available_devices(hass, device_type, device_class, async_add_entities): + """Get sysinfo for all devices.""" + + devices = hass.data[TPLINK_DOMAIN][device_type] + + if f"{device_type}_remaining" in hass.data[TPLINK_DOMAIN]: + devices = hass.data[TPLINK_DOMAIN][f"{device_type}_remaining"] + + entities_ready = [] + entities_unavailable = [] + for device in devices: + try: + device.get_sysinfo() + entities_ready.append(device_class(device)) + except SmartDeviceException as ex: + entities_unavailable.append(device) + _LOGGER.warning( + "Unable to communicate with device %s: %s", + device.host, + ex, + ) + + hass.data[TPLINK_DOMAIN][f"{device_type}_remaining"] = entities_unavailable + + if entities_ready: + async_add_entities(entities_ready, update_before_add=True) diff --git a/homeassistant/components/tplink/light.py b/homeassistant/components/tplink/light.py index 21dc382f486..e2acf3fcd90 100644 --- a/homeassistant/components/tplink/light.py +++ b/homeassistant/components/tplink/light.py @@ -16,7 +16,7 @@ from homeassistant.components.light import ( SUPPORT_COLOR_TEMP, LightEntity, ) -from homeassistant.exceptions import HomeAssistantError +from homeassistant.exceptions import HomeAssistantError, PlatformNotReady import homeassistant.helpers.device_registry as dr from homeassistant.helpers.typing import HomeAssistantType from homeassistant.util.color import ( @@ -26,6 +26,7 @@ from homeassistant.util.color import ( import homeassistant.util.dt as dt_util from . import CONF_LIGHT, DOMAIN as TPLINK_DOMAIN +from .common import add_available_devices PARALLEL_UPDATES = 0 SCAN_INTERVAL = timedelta(seconds=5) @@ -60,20 +61,12 @@ SLEEP_TIME = 2 async def async_setup_entry(hass: HomeAssistantType, config_entry, async_add_entities): """Set up lights.""" - devices = hass.data[TPLINK_DOMAIN][CONF_LIGHT] - entities = [] + await hass.async_add_executor_job( + add_available_devices, hass, CONF_LIGHT, TPLinkSmartBulb, async_add_entities + ) - await hass.async_add_executor_job(get_devices_sysinfo, devices) - for device in devices: - entities.append(TPLinkSmartBulb(device)) - - async_add_entities(entities, update_before_add=True) - - -def get_devices_sysinfo(devices): - """Get sysinfo for all devices.""" - for device in devices: - device.get_sysinfo() + if hass.data[TPLINK_DOMAIN][f"{CONF_LIGHT}_remaining"]: + raise PlatformNotReady def brightness_to_percentage(byt): diff --git a/homeassistant/components/tplink/switch.py b/homeassistant/components/tplink/switch.py index 236607f4cd7..b7e31e82e78 100644 --- a/homeassistant/components/tplink/switch.py +++ b/homeassistant/components/tplink/switch.py @@ -11,10 +11,12 @@ from homeassistant.components.switch import ( SwitchEntity, ) from homeassistant.const import ATTR_VOLTAGE +from homeassistant.exceptions import PlatformNotReady import homeassistant.helpers.device_registry as dr from homeassistant.helpers.typing import HomeAssistantType from . import CONF_SWITCH, DOMAIN as TPLINK_DOMAIN +from .common import add_available_devices PARALLEL_UPDATES = 0 @@ -29,20 +31,12 @@ SLEEP_TIME = 2 async def async_setup_entry(hass: HomeAssistantType, config_entry, async_add_entities): """Set up switches.""" - devices = hass.data[TPLINK_DOMAIN][CONF_SWITCH] - entities = [] + await hass.async_add_executor_job( + add_available_devices, hass, CONF_SWITCH, SmartPlugSwitch, async_add_entities + ) - await hass.async_add_executor_job(get_devices_sysinfo, devices) - for device in devices: - entities.append(SmartPlugSwitch(device)) - - async_add_entities(entities, update_before_add=True) - - -def get_devices_sysinfo(devices): - """Get sysinfo for all devices.""" - for device in devices: - device.get_sysinfo() + if hass.data[TPLINK_DOMAIN][f"{CONF_SWITCH}_remaining"]: + raise PlatformNotReady class SmartPlugSwitch(SwitchEntity): diff --git a/tests/components/tplink/test_light.py b/tests/components/tplink/test_light.py index 56de30b1951..4987f4f26cb 100644 --- a/tests/components/tplink/test_light.py +++ b/tests/components/tplink/test_light.py @@ -577,3 +577,33 @@ async def test_update_failure( in caplog.text ) assert "Device 123.123.123.123|light1 responded after " in caplog.text + + +async def test_async_setup_entry_unavailable( + hass: HomeAssistant, light_mock_data: LightMockData, caplog +): + """Test unavailable devices trigger a later retry.""" + caplog.clear() + caplog.set_level(logging.WARNING) + + with patch( + "homeassistant.components.tplink.common.SmartDevice.get_sysinfo", + side_effect=SmartDeviceException, + ): + await async_setup_component(hass, HA_DOMAIN, {}) + await hass.async_block_till_done() + + await async_setup_component( + hass, + tplink.DOMAIN, + { + tplink.DOMAIN: { + CONF_DISCOVERY: False, + CONF_LIGHT: [{CONF_HOST: "123.123.123.123"}], + } + }, + ) + + await hass.async_block_till_done() + assert "Unable to communicate with device 123.123.123.123" in caplog.text + assert len(hass.data[tplink.DOMAIN][f"{CONF_LIGHT}_remaining"]) == 1