text: """
  Support for RFXtrx binary sensors.
  
  Lighting4 devices (sensors based on PT2262 encoder) are supported and
  tested. Other types may need some work.
  
  """
  
  import logging
  
  import voluptuous as vol
  
  from homeassistant.const import (
      CONF_DEVICE_CLASS, CONF_COMMAND_ON, CONF_COMMAND_OFF, CONF_NAME)
  from homeassistant.components import rfxtrx
  from homeassistant.helpers import event as evt
  from homeassistant.helpers import config_validation as cv
  from homeassistant.components.binary_sensor import (
      BinarySensorDevice, PLATFORM_SCHEMA)
  from homeassistant.components.rfxtrx import (
      ATTR_NAME, ATTR_DATA_BITS, ATTR_OFF_DELAY, ATTR_FIRE_EVENT,
      CONF_AUTOMATIC_ADD, CONF_FIRE_EVENT,
      CONF_DATA_BITS, CONF_DEVICES)
  from homeassistant.util import slugify
  from homeassistant.util import dt as dt_util
  
  
  DEPENDENCIES = ["rfxtrx"]
  
  _LOGGER = logging.getLogger(__name__)
  
  PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
      vol.Optional(CONF_DEVICES, default={}): {
          cv.string: vol.Schema({
              vol.Optional(CONF_NAME): cv.string,
              vol.Optional(CONF_DEVICE_CLASS): cv.string,
              vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
              vol.Optional(CONF_DATA_BITS): cv.positive_int,
              vol.Optional(CONF_COMMAND_ON): cv.byte,
              vol.Optional(CONF_COMMAND_OFF): cv.byte
          })
      },
      vol.Optional(CONF_AUTOMATIC_ADD, default=False):  cv.boolean,
  }, extra=vol.ALLOW_EXTRA)
  
  
  def setup_platform(hass, config, add_devices_callback, discovery_info=None):
      """Setup the Binary Sensor platform to rfxtrx."""
      import RFXtrx as rfxtrxmod
      sensors = []
  
      for packet_id, entity in config['devices'].items():
          event = rfxtrx.get_rfx_object(packet_id)
          device_id = slugify(event.device.id_string.lower())
  
          if device_id in rfxtrx.RFX_DEVICES:
              continue
  
          if entity[CONF_DATA_BITS] is not None:
              _LOGGER.debug("Masked device id: %s",
                            rfxtrx.get_pt2262_deviceid(device_id,
                                                       entity[ATTR_DATA_BITS]))
  
          _LOGGER.debug("Add %s rfxtrx.binary_sensor (class %s)",
                        entity[ATTR_NAME], entity[CONF_DEVICE_CLASS])
  
          device = RfxtrxBinarySensor(event, entity[ATTR_NAME],
                                      entity[CONF_DEVICE_CLASS],
                                      entity[ATTR_FIRE_EVENT],
                                      entity[ATTR_OFF_DELAY],
                                      entity[ATTR_DATA_BITS],
                                      entity[CONF_COMMAND_ON],
                                      entity[CONF_COMMAND_OFF])
          device.hass = hass
          sensors.append(device)
          rfxtrx.RFX_DEVICES[device_id] = device
  
      add_devices_callback(sensors)
  
      # pylint: disable=too-many-branches
      def binary_sensor_update(event):
          """Callback for control updates from the RFXtrx gateway."""
          if not isinstance(event, rfxtrxmod.ControlEvent):
              return
  
          device_id = slugify(event.device.id_string.lower())
  
          if device_id in rfxtrx.RFX_DEVICES:
              sensor = rfxtrx.RFX_DEVICES[device_id]
          else:
              sensor = rfxtrx.get_pt2262_device(device_id)
  
          if sensor is None:
              # Add the entity if not exists and automatic_add is True
              if not config[CONF_AUTOMATIC_ADD]:
                  return
  
              if event.device.packettype == 0x13:
                  poss_dev = rfxtrx.find_possible_pt2262_device(device_id)
                  if poss_dev is not None:
                      poss_id = slugify(poss_dev.event.device.id_string.lower())
                      _LOGGER.debug("Found possible matching deviceid %s.",
                                    poss_id)
  
              pkt_id = "".join("{0:02x}".format(x) for x in event.data)
              sensor = RfxtrxBinarySensor(event, pkt_id)
              sensor.hass = hass
              rfxtrx.RFX_DEVICES[device_id] = sensor
              add_devices_callback([sensor])
              _LOGGER.info("Added binary sensor %s "
                           "(Device_id: %s Class: %s Sub: %s)",
                           pkt_id,
                           slugify(event.device.id_string.lower()),
                           event.device.__class__.__name__,
                           event.device.subtype)
  
          elif not isinstance(sensor, RfxtrxBinarySensor):
              return
          else:
              _LOGGER.debug("Binary sensor update "
                            "(Device_id: %s Class: %s Sub: %s)",
                            slugify(event.device.id_string.lower()),
                            event.device.__class__.__name__,
                            event.device.subtype)
  
          if sensor.is_lighting4:
              if sensor.data_bits is not None:
                  cmd = rfxtrx.get_pt2262_cmd(device_id, sensor.data_bits)
                  sensor.apply_cmd(int(cmd, 16))
              else:
                  sensor.update_state(True)
          else:
              rfxtrx.apply_received_command(event)
  
          if (sensor.is_on and sensor.off_delay is not None and
                  sensor.delay_listener is None):
  
              def off_delay_listener(now):
                  """Switch device off after a delay."""
                  sensor.delay_listener = None
                  sensor.update_state(False)
  
              sensor.delay_listener = evt.track_point_in_time(
                  hass, off_delay_listener, dt_util.utcnow() + sensor.off_delay
              )
  
      # Subscribe to main rfxtrx events
      if binary_sensor_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS:
          rfxtrx.RECEIVED_EVT_SUBSCRIBERS.append(binary_sensor_update)
  
  
  # pylint: disable=too-many-instance-attributes,too-many-arguments
  class RfxtrxBinarySensor(BinarySensorDevice):
      """An Rfxtrx binary sensor."""
  
      def __init__(self, event, name, device_class=None,
                   should_fire=False, off_delay=None, data_bits=None,
                   cmd_on=None, cmd_off=None):
          """Initialize the sensor."""
          self.event = event
          self._name = name
          self._should_fire_event = should_fire
          self._device_class = device_class
          self._off_delay = off_delay
          self._state = False
          self.is_lighting4 = (event.device.packettype == 0x13)
          self.delay_listener = None
          self._data_bits = data_bits
          self._cmd_on = cmd_on
          self._cmd_off = cmd_off
  
          if data_bits is not None:
              self._masked_id = rfxtrx.get_pt2262_deviceid(
                  event.device.id_string.lower(),
                  data_bits)
          else:
              self._masked_id = None
  
      @property
      def name(self):
          """Return the device name."""
          return self._name
  
      @property
      def masked_id(self):
          """Return the masked device id (isolated address bits)."""
          return self._masked_id
  
      @property
      def data_bits(self):
          """Return the number of data bits."""
          return self._data_bits
  
      @property
      def cmd_on(self):
          """Return the value of the 'On' command."""
          return self._cmd_on
  
      @property
      def cmd_off(self):
          """Return the value of the 'Off' command."""
          return self._cmd_off
  
      @property
      def should_poll(self):
          """No polling needed."""
          return False
  
      @property
      def should_fire_event(self):
          """Return is the device must fire event."""
          return self._should_fire_event
  
      @property
      def device_class(self):
          """Return the sensor class."""
          return self._device_class
  
      @property
      def off_delay(self):
          """Return the off_delay attribute value."""
          return self._off_delay
  
      @property
      def is_on(self):
          """Return true if the sensor state is True."""
          return self._state
  
      def apply_cmd(self, cmd):
          """Apply a command for updating the state."""
          if cmd == self.cmd_on:
              self.update_state(True)
          elif cmd == self.cmd_off:
              self.update_state(False)
  
      def update_state(self, state):
          """Update the state of the device."""
          self._state = state
          self.schedule_update_ha_state()
  