"""Support for IKEA Tradfri switches."""
import logging

from homeassistant.components.switch import SwitchDevice
from homeassistant.core import callback

from . import DOMAIN as TRADFRI_DOMAIN, KEY_API, KEY_GATEWAY
from .const import CONF_GATEWAY_ID

_LOGGER = logging.getLogger(__name__)

IKEA = 'IKEA of Sweden'
TRADFRI_SWITCH_MANAGER = 'Tradfri Switch Manager'


async def async_setup_entry(hass, config_entry, async_add_entities):
    """Load Tradfri switches based on a config entry."""
    gateway_id = config_entry.data[CONF_GATEWAY_ID]
    api = hass.data[KEY_API][config_entry.entry_id]
    gateway = hass.data[KEY_GATEWAY][config_entry.entry_id]

    devices_commands = await api(gateway.get_devices())
    devices = await api(devices_commands)
    switches = [dev for dev in devices if dev.has_socket_control]
    if switches:
        async_add_entities(
            TradfriSwitch(switch, api, gateway_id) for switch in switches)


class TradfriSwitch(SwitchDevice):
    """The platform class required by Home Assistant."""

    def __init__(self, switch, api, gateway_id):
        """Initialize a switch."""
        self._api = api
        self._unique_id = "{}-{}".format(gateway_id, switch.id)
        self._switch = None
        self._socket_control = None
        self._switch_data = None
        self._name = None
        self._available = True
        self._gateway_id = gateway_id

        self._refresh(switch)

    @property
    def unique_id(self):
        """Return unique ID for switch."""
        return self._unique_id

    @property
    def device_info(self):
        """Return the device info."""
        info = self._switch.device_info

        return {
            'identifiers': {
                (TRADFRI_DOMAIN, self._switch.id)
            },
            'name': self._name,
            'manufacturer': info.manufacturer,
            'model': info.model_number,
            'sw_version': info.firmware_version,
            'via_device': (TRADFRI_DOMAIN, self._gateway_id),
        }

    async def async_added_to_hass(self):
        """Start thread when added to hass."""
        self._async_start_observe()

    @property
    def available(self):
        """Return True if entity is available."""
        return self._available

    @property
    def should_poll(self):
        """No polling needed for tradfri switch."""
        return False

    @property
    def name(self):
        """Return the display name of this switch."""
        return self._name

    @property
    def is_on(self):
        """Return true if switch is on."""
        return self._switch_data.state

    async def async_turn_off(self, **kwargs):
        """Instruct the switch to turn off."""
        await self._api(self._socket_control.set_state(False))

    async def async_turn_on(self, **kwargs):
        """Instruct the switch to turn on."""
        await self._api(self._socket_control.set_state(True))

    @callback
    def _async_start_observe(self, exc=None):
        """Start observation of switch."""
        from pytradfri.error import PytradfriError
        if exc:
            self._available = False
            self.async_schedule_update_ha_state()
            _LOGGER.warning("Observation failed for %s", self._name,
                            exc_info=exc)

        try:
            cmd = self._switch.observe(callback=self._observe_update,
                                       err_callback=self._async_start_observe,
                                       duration=0)
            self.hass.async_create_task(self._api(cmd))
        except PytradfriError as err:
            _LOGGER.warning("Observation failed, trying again", exc_info=err)
            self._async_start_observe()

    def _refresh(self, switch):
        """Refresh the switch data."""
        self._switch = switch

        # Caching of switchControl and switch object
        self._available = switch.reachable
        self._socket_control = switch.socket_control
        self._switch_data = switch.socket_control.sockets[0]
        self._name = switch.name

    @callback
    def _observe_update(self, tradfri_device):
        """Receive new state data for this switch."""
        self._refresh(tradfri_device)
        self.async_schedule_update_ha_state()

"""Support for IKEA Tradfri switches."""
import logging

from homeassistant.components.switch import SwitchDevice
from homeassistant.core import callback

from . import DOMAIN as TRADFRI_DOMAIN, KEY_API, KEY_GATEWAY
from .const import CONF_GATEWAY_ID

_LOGGER = logging.getLogger(__name__)

IKEA = 'IKEA of Sweden'
TRADFRI_SWITCH_MANAGER = 'Tradfri Switch Manager'


async def async_setup_entry(hass, config_entry, async_add_entities):
    """Load Tradfri switches based on a config entry."""
    gateway_id = config_entry.data[CONF_GATEWAY_ID]
    api = hass.data[KEY_API][config_entry.entry_id]
    gateway = hass.data[KEY_GATEWAY][config_entry.entry_id]

    devices_commands = await api(gateway.get_devices())
    devices = await api(devices_commands)
    switches = [dev for dev in devices if dev.has_socket_control]
    if switches:
        async_add_entities(
            TradfriSwitch(switch, api, gateway_id) for switch in switches)


class TradfriSwitch(SwitchDevice):
    """The platform class required by Home Assistant."""

    def __init__(self, switch, api, gateway_id):
        """Initialize a switch."""
        self._api = api
        self._unique_id = "{}-{}".format(gateway_id, switch.id)
        self._switch = None
        self._socket_control = None
        self._switch_data = None
        self._name = None
        self._available = True
        self._gateway_id = gateway_id

        self._refresh(switch)

    @property
    def unique_id(self):
        """Return unique ID for switch."""
        return self._unique_id

    @property
    def device_info(self):
        """Return the device info."""
        info = self._switch.device_info

        return {
            'identifiers': {
                (TRADFRI_DOMAIN, self._switch.id)
            },
            'name': self._name,
            'manufacturer': info.manufacturer,
            'model': info.model_number,
            'sw_version': info.firmware_version,
            'via_device': (TRADFRI_DOMAIN, self._gateway_id),
        }

    async def async_added_to_hass(self):
        """Start thread when added to hass."""
        self._async_start_observe()

    @property
    def available(self):
        """Return True if entity is available."""
        return self._available

    @property
    def should_poll(self):
        """No polling needed for tradfri switch."""
        return False

    @property
    def name(self):
        """Return the display name of this switch."""
        return self._name

    @property
    def is_on(self):
        """Return true if switch is on."""
        return self._switch_data.state

    async def async_turn_off(self, **kwargs):
        """Instruct the switch to turn off."""
        await self._api(self._socket_control.set_state(False))

    async def async_turn_on(self, **kwargs):
        """Instruct the switch to turn on."""
        await self._api(self._socket_control.set_state(True))

    @callback
    def _async_start_observe(self, exc=None):
        """Start observation of switch."""
        from pytradfri.error import PytradfriError
        if exc:
            self._available = False
            self.async_schedule_update_ha_state()
            _LOGGER.warning("Observation failed for %s", self._name,
                            exc_info=exc)

        try:
            cmd = self._switch.observe(callback=self._observe_update,
                                       err_callback=self._async_start_observe,
                                       duration=0)
            self.hass.async_create_task(self._api(cmd))
        except PytradfriError as err:
            _LOGGER.warning("Observation failed, trying again", exc_info=err)
            self._async_start_observe()

    def _refresh(self, switch):
        """Refresh the switch data."""
        self._switch = switch

        # Caching of switchControl and switch object
        self._available = switch.reachable
        self._socket_control = switch.socket_control
        self._switch_data = switch.socket_control.sockets[0]
        self._name = switch.name

    @callback
    def _observe_update(self, tradfri_device):
        """Receive new state data for this switch."""
        self._refresh(tradfri_device)
        self.async_schedule_update_ha_state()

Support for IKEA Tradfri switches. Load Tradfri switches based on a config entry. The platform class required by Home Assistant. Initialize a switch. Return unique ID for switch. Return the device info. Start thread when added to hass. Return True if entity is available. No polling needed for tradfri switch. Return the display name of this switch. Return true if switch is on. Instruct the switch to turn off. Instruct the switch to turn on. Start observation of switch. Refresh the switch data. # Caching of switchControl and switch object Receive new state data for this switch.