text: """
  Support for switching devices via Pilight to on and off.
  
  For more details about this platform, please refer to the documentation at
  https://home-assistant.io/components/switch.pilight/
  """
  import asyncio
  import logging
  
  import voluptuous as vol
  
  import homeassistant.helpers.config_validation as cv
  import homeassistant.components.pilight as pilight
  from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
  from homeassistant.const import (CONF_NAME, CONF_ID, CONF_SWITCHES, CONF_STATE,
                                   CONF_PROTOCOL, STATE_ON)
  from homeassistant.helpers.restore_state import async_get_last_state
  
  _LOGGER = logging.getLogger(__name__)
  
  CONF_OFF_CODE = 'off_code'
  CONF_OFF_CODE_RECEIVE = 'off_code_receive'
  CONF_ON_CODE = 'on_code'
  CONF_ON_CODE_RECEIVE = 'on_code_receive'
  CONF_SYSTEMCODE = 'systemcode'
  CONF_UNIT = 'unit'
  CONF_UNITCODE = 'unitcode'
  CONF_ECHO = 'echo'
  
  DEPENDENCIES = ['pilight']
  
  COMMAND_SCHEMA = vol.Schema({
      vol.Optional(CONF_PROTOCOL): cv.string,
      vol.Optional('on'): cv.positive_int,
      vol.Optional('off'): cv.positive_int,
      vol.Optional(CONF_UNIT): cv.positive_int,
      vol.Optional(CONF_UNITCODE): cv.positive_int,
      vol.Optional(CONF_ID): vol.Any(cv.positive_int, cv.string),
      vol.Optional(CONF_STATE): cv.string,
      vol.Optional(CONF_SYSTEMCODE): cv.positive_int,
  }, extra=vol.ALLOW_EXTRA)
  
  RECEIVE_SCHEMA = COMMAND_SCHEMA.extend({
      vol.Optional(CONF_ECHO): cv.boolean
  })
  
  SWITCHES_SCHEMA = vol.Schema({
      vol.Required(CONF_ON_CODE): COMMAND_SCHEMA,
      vol.Required(CONF_OFF_CODE): COMMAND_SCHEMA,
      vol.Optional(CONF_NAME): cv.string,
      vol.Optional(CONF_OFF_CODE_RECEIVE, default=[]): vol.All(cv.ensure_list,
                                                               [COMMAND_SCHEMA]),
      vol.Optional(CONF_ON_CODE_RECEIVE, default=[]): vol.All(cv.ensure_list,
                                                              [COMMAND_SCHEMA])
  })
  
  PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
      vol.Required(CONF_SWITCHES):
          vol.Schema({cv.string: SWITCHES_SCHEMA}),
  })
  
  
  def setup_platform(hass, config, add_devices, discovery_info=None):
      """Set up the Pilight platform."""
      switches = config.get(CONF_SWITCHES)
      devices = []
  
      for dev_name, properties in switches.items():
          devices.append(
              PilightSwitch(
                  hass,
                  properties.get(CONF_NAME, dev_name),
                  properties.get(CONF_ON_CODE),
                  properties.get(CONF_OFF_CODE),
                  properties.get(CONF_ON_CODE_RECEIVE),
                  properties.get(CONF_OFF_CODE_RECEIVE)
              )
          )
  
      add_devices(devices)
  
  
  class _ReceiveHandle(object):
      def __init__(self, config, echo):
          """Initialize the handle."""
          self.config_items = config.items()
          self.echo = echo
  
      def match(self, code):
          """Test if the received code matches the configured values.
  
          The received values have to be a subset of the configured options.
          """
          return self.config_items <= code.items()
  
      def run(self, switch, turn_on):
          """Change the state of the switch."""
          switch.set_state(turn_on=turn_on, send_code=self.echo)
  
  
  class PilightSwitch(SwitchDevice):
      """Representation of a Pilight switch."""
  
      def __init__(self, hass, name, code_on, code_off, code_on_receive,
                   code_off_receive):
          """Initialize the switch."""
          self._hass = hass
          self._name = name
          self._state = False
          self._code_on = code_on
          self._code_off = code_off
  
          self._code_on_receive = []
          self._code_off_receive = []
  
          for code_list, conf in ((self._code_on_receive, code_on_receive),
                                  (self._code_off_receive, code_off_receive)):
              for code in conf:
                  echo = code.pop(CONF_ECHO, True)
                  code_list.append(_ReceiveHandle(code, echo))
  
          if any(self._code_on_receive) or any(self._code_off_receive):
              hass.bus.listen(pilight.EVENT, self._handle_code)
  
      @asyncio.coroutine
      def async_added_to_hass(self):
          """Call when entity about to be added to hass."""
          state = yield from async_get_last_state(self._hass, self.entity_id)
          if state:
              self._state = state.state == STATE_ON
  
      @property
      def name(self):
          """Get the name of the switch."""
          return self._name
  
      @property
      def should_poll(self):
          """No polling needed, state set when correct code is received."""
          return False
  
      @property
      def assumed_state(self):
          """Return True if unable to access real state of the entity."""
          return True
  
      @property
      def is_on(self):
          """Return true if switch is on."""
          return self._state
  
      def _handle_code(self, call):
          """Check if received code by the pilight-daemon.
  
          If the code matches the receive on/off codes of this switch the switch
          state is changed accordingly.
          """
          # - True if off_code/on_code is contained in received code dict, not
          #   all items have to match.
          # - Call turn on/off only once, even if more than one code is received
          if any(self._code_on_receive):
              for on_code in self._code_on_receive:
                  if on_code.match(call.data):
                      on_code.run(switch=self, turn_on=True)
                      break
  
          if any(self._code_off_receive):
              for off_code in self._code_off_receive:
                  if off_code.match(call.data):
                      off_code.run(switch=self, turn_on=False)
                      break
  
      def set_state(self, turn_on, send_code=True):
          """Set the state of the switch.
  
          This sets the state of the switch. If send_code is set to True, then
          it will call the pilight.send service to actually send the codes
          to the pilight daemon.
          """
          if send_code:
              if turn_on:
                  self._hass.services.call(pilight.DOMAIN, pilight.SERVICE_NAME,
                                           self._code_on, blocking=True)
              else:
                  self._hass.services.call(pilight.DOMAIN, pilight.SERVICE_NAME,
                                           self._code_off, blocking=True)
  
          self._state = turn_on
          self.schedule_update_ha_state()
  
      def turn_on(self, **kwargs):
          """Turn the switch on by calling pilight.send service with on code."""
          self.set_state(turn_on=True)
  
      def turn_off(self, **kwargs):
          """Turn the switch on by calling pilight.send service with off code."""
          self.set_state(turn_on=False)
  