# Buggy code
async def async_setup_entry(hass, config_entry):
    """Set up TPLink from a config entry."""
    from pyHS100 import SmartBulb, SmartPlug, SmartDeviceException

    devices = {}

    config_data = hass.data[DOMAIN].get(ATTR_CONFIG)

    # These will contain the initialized devices
    lights = hass.data[DOMAIN][CONF_LIGHT] = []
    switches = hass.data[DOMAIN][CONF_SWITCH] = []

    # If discovery is defined and not disabled, discover devices
    # If initialized from configure integrations, there's no config
    # so we default here to True
    if config_data is None or config_data[CONF_DISCOVERY]:
        devs = await _async_has_devices(hass)
        _LOGGER.info("Discovered %s TP-Link smart home device(s)", len(devs))
        devices.update(devs)

    def _device_for_type(host, type_):
        dev = None
        if type_ == CONF_LIGHT:
            dev = SmartBulb(host)
        elif type_ == CONF_SWITCH:
            dev = SmartPlug(host)

        return dev

    # When arriving from configure integrations, we have no config data.
    if config_data is not None:
        for type_ in [CONF_LIGHT, CONF_SWITCH]:
            for entry in config_data[type_]:
                try:
                    host = entry["host"]
                    dev = _device_for_type(host, type_)
                    devices[host] = dev
                    _LOGGER.debug("Succesfully added %s %s: %s", type_, host, dev)
                except SmartDeviceException as ex:
                    _LOGGER.error("Unable to initialize %s %s: %s", type_, host, ex)

    # This is necessary to avoid I/O blocking on is_dimmable
    def _fill_device_lists():
        for dev in devices.values():
            if isinstance(dev, SmartPlug):
                if dev.is_dimmable:  # Dimmers act as lights
                    lights.append(dev)
                else:
                    switches.append(dev)
            elif isinstance(dev, SmartBulb):
                lights.append(dev)
            else:
                _LOGGER.error("Unknown smart device type: %s", type(dev))

    # Avoid blocking on is_dimmable
    await hass.async_add_executor_job(_fill_device_lists)

    forward_setup = hass.config_entries.async_forward_entry_setup
    if lights:
        _LOGGER.debug("Got %s lights: %s", len(lights), lights)
        hass.async_create_task(forward_setup(config_entry, "light"))
    if switches:
        _LOGGER.debug("Got %s switches: %s", len(switches), switches)
        hass.async_create_task(forward_setup(config_entry, "switch"))

    return True


# Traceback (OSError)
2019-03-07 01:08:44 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry TP-Link Smart Home for tplink
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/pyHS100/smartdevice.py", line 116, in _query_helper
request=request,
File "/usr/local/lib/python3.7/site-packages/pyHS100/protocol.py", line 47, in query
sock = socket.create_connection((host, port), timeout)
File "/usr/local/lib/python3.7/socket.py", line 727, in create_connection
raise err
File "/usr/local/lib/python3.7/socket.py", line 716, in create_connection
sock.connect(sa)
OSError: [Errno 113] No route to host
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/app/homeassistant/config_entries.py", line 283, in async_setup
result = await component.async_setup_entry(hass, self)
File "/usr/src/app/homeassistant/components/tplink/__init__.py", line 120, in async_setup_entry
await hass.async_add_executor_job(_fill_device_lists)
File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/src/app/homeassistant/components/tplink/__init__.py", line 110, in _fill_device_lists
if dev.is_dimmable:  # Dimmers act as lights
File "/usr/local/lib/python3.7/site-packages/pyHS100/smartplug.py", line 131, in is_dimmable
return "brightness" in self.sys_info
File "/usr/local/lib/python3.7/site-packages/pyHS100/smartdevice.py", line 185, in sys_info
return defaultdict(lambda: None, self.get_sysinfo())
File "/usr/local/lib/python3.7/site-packages/pyHS100/smartdevice.py", line 195, in get_sysinfo
return self._query_helper("system", "get_sysinfo")
File "/usr/local/lib/python3.7/site-packages/pyHS100/smartdevice.py", line 119, in _query_helper
raise SmartDeviceException('Communication error') from ex
pyHS100.smartdevice.SmartDeviceException: Communication error

# Fixed code
async def async_setup_entry(hass, config_entry):
    """Set up TPLink from a config entry."""
    from pyHS100 import SmartBulb, SmartPlug, SmartDeviceException

    devices = {}

    config_data = hass.data[DOMAIN].get(ATTR_CONFIG)

    # These will contain the initialized devices
    lights = hass.data[DOMAIN][CONF_LIGHT] = []
    switches = hass.data[DOMAIN][CONF_SWITCH] = []

    # If discovery is defined and not disabled, discover devices
    # If initialized from configure integrations, there's no config
    # so we default here to True
    if config_data is None or config_data[CONF_DISCOVERY]:
        devs = await _async_has_devices(hass)
        _LOGGER.info("Discovered %s TP-Link smart home device(s)", len(devs))
        devices.update(devs)

    def _device_for_type(host, type_):
        dev = None
        if type_ == CONF_LIGHT:
            dev = SmartBulb(host)
        elif type_ == CONF_SWITCH:
            dev = SmartPlug(host)

        return dev

    # When arriving from configure integrations, we have no config data.
    if config_data is not None:
        for type_ in [CONF_LIGHT, CONF_SWITCH]:
            for entry in config_data[type_]:
                try:
                    host = entry["host"]
                    dev = _device_for_type(host, type_)
                    devices[host] = dev
                    _LOGGER.debug("Succesfully added %s %s: %s", type_, host, dev)
                except SmartDeviceException as ex:
                    _LOGGER.error("Unable to initialize %s %s: %s", type_, host, ex)

    # This is necessary to avoid I/O blocking on is_dimmable
    def _fill_device_lists():
        for dev in devices.values():
            if isinstance(dev, SmartPlug):
                try:
                    if dev.is_dimmable:  # Dimmers act as lights
                        lights.append(dev)
                    else:
                        switches.append(dev)
                except SmartDeviceException as ex:
                    _LOGGER.error("Unable to connect to device %s: %s", dev.host, ex)

            elif isinstance(dev, SmartBulb):
                lights.append(dev)
            else:
                _LOGGER.error("Unknown smart device type: %s", type(dev))

    # Avoid blocking on is_dimmable
    await hass.async_add_executor_job(_fill_device_lists)

    forward_setup = hass.config_entries.async_forward_entry_setup
    if lights:
        _LOGGER.debug("Got %s lights: %s", len(lights), lights)
        hass.async_create_task(forward_setup(config_entry, "light"))
    if switches:
        _LOGGER.debug("Got %s switches: %s", len(switches), switches)
        hass.async_create_task(forward_setup(config_entry, "switch"))

    return True