diff --git a/.coveragerc b/.coveragerc index bbc40156cb5..f54cc6fbafe 100644 --- a/.coveragerc +++ b/.coveragerc @@ -91,6 +91,9 @@ omit = homeassistant/components/rpi_gpio.py homeassistant/components/*/rpi_gpio.py + homeassistant/components/rpi_pfio.py + homeassistant/components/*/rpi_pfio.py + homeassistant/components/scsgate.py homeassistant/components/*/scsgate.py diff --git a/homeassistant/components/binary_sensor/rpi_pfio.py b/homeassistant/components/binary_sensor/rpi_pfio.py new file mode 100644 index 00000000000..92d02067dfc --- /dev/null +++ b/homeassistant/components/binary_sensor/rpi_pfio.py @@ -0,0 +1,93 @@ +""" +Support for binary sensor using the PiFace Digital I/O module on a RPi. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.rpi_pfio/ +""" +import logging + +import voluptuous as vol + +import homeassistant.components.rpi_pfio as rpi_pfio +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, PLATFORM_SCHEMA) +from homeassistant.const import DEVICE_DEFAULT_NAME +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +ATTR_NAME = 'name' +ATTR_INVERT_LOGIC = 'invert_logic' +ATTR_SETTLE_TIME = 'settle_time' +CONF_PORTS = 'ports' + +DEFAULT_INVERT_LOGIC = False +DEFAULT_SETTLE_TIME = 20 + +DEPENDENCIES = ['rpi_pfio'] + +PORT_SCHEMA = vol.Schema({ + vol.Optional(ATTR_NAME, default=None): cv.string, + vol.Optional(ATTR_SETTLE_TIME, default=DEFAULT_SETTLE_TIME): + cv.positive_int, + vol.Optional(ATTR_INVERT_LOGIC, default=DEFAULT_INVERT_LOGIC): cv.boolean +}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_PORTS, default={}): vol.Schema({ + cv.positive_int: PORT_SCHEMA + }) +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the PiFace Digital Input devices.""" + binary_sensors = [] + ports = config.get('ports') + for port, port_entity in ports.items(): + name = port_entity[ATTR_NAME] + settle_time = port_entity[ATTR_SETTLE_TIME] / 1000 + invert_logic = port_entity[ATTR_INVERT_LOGIC] + + binary_sensors.append(RPiPFIOBinarySensor( + hass, port, name, settle_time, invert_logic)) + add_devices(binary_sensors, True) + + rpi_pfio.activate_listener(hass) + + +class RPiPFIOBinarySensor(BinarySensorDevice): + """Represent a binary sensor that a PiFace Digital Input.""" + + def __init__(self, hass, port, name, settle_time, invert_logic): + """Initialize the RPi binary sensor.""" + self._port = port + self._name = name or DEVICE_DEFAULT_NAME + self._invert_logic = invert_logic + self._state = None + + def read_pfio(port): + """Read state from PFIO.""" + self._state = rpi_pfio.read_input(self._port) + self.schedule_update_ha_state() + + rpi_pfio.edge_detect(hass, self._port, read_pfio, settle_time) + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def is_on(self): + """Return the state of the entity.""" + return self._state != self._invert_logic + + def update(self): + """Update the PFIO state.""" + self._state = rpi_pfio.read_input(self._port) diff --git a/homeassistant/components/rpi_pfio.py b/homeassistant/components/rpi_pfio.py new file mode 100644 index 00000000000..bf8fdccfab0 --- /dev/null +++ b/homeassistant/components/rpi_pfio.py @@ -0,0 +1,63 @@ +""" +Support for controlling the PiFace Digital I/O module on a RPi. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/rpi_pfio/ +""" +import logging + +from homeassistant.const import ( + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) + +REQUIREMENTS = ['pifacecommon==4.1.2', 'pifacedigitalio==3.0.5'] + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = 'rpi_pfio' + +DATA_PFIO_LISTENER = 'pfio_listener' + + +def setup(hass, config): + """Set up the Raspberry PI PFIO component.""" + import pifacedigitalio as PFIO + + pifacedigital = PFIO.PiFaceDigital() + hass.data[DATA_PFIO_LISTENER] = PFIO.InputEventListener(chip=pifacedigital) + + def cleanup_pfio(event): + """Stuff to do before stopping.""" + PFIO.deinit() + + def prepare_pfio(event): + """Stuff to do when home assistant starts.""" + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, cleanup_pfio) + + hass.bus.listen_once(EVENT_HOMEASSISTANT_START, prepare_pfio) + PFIO.init() + + return True + + +def write_output(port, value): + """Write a value to a PFIO.""" + import pifacedigitalio as PFIO + PFIO.digital_write(port, value) + + +def read_input(port): + """Read a value from a PFIO.""" + import pifacedigitalio as PFIO + return PFIO.digital_read(port) + + +def edge_detect(hass, port, event_callback, settle): + """Add detection for RISING and FALLING events.""" + import pifacedigitalio as PFIO + hass.data[DATA_PFIO_LISTENER].register( + port, PFIO.IODIR_BOTH, event_callback, settle_time=settle) + + +def activate_listener(hass): + """Activate the registered listener events.""" + hass.data[DATA_PFIO_LISTENER].activate() diff --git a/homeassistant/components/switch/rpi_pfio.py b/homeassistant/components/switch/rpi_pfio.py new file mode 100644 index 00000000000..6e50725b564 --- /dev/null +++ b/homeassistant/components/switch/rpi_pfio.py @@ -0,0 +1,87 @@ +""" +Allows to configure a switch using the PiFace Digital I/O module on a RPi. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.rpi_pfio/ +""" +import logging + +import voluptuous as vol + +from homeassistant.components.switch import PLATFORM_SCHEMA +import homeassistant.components.rpi_pfio as rpi_pfio +from homeassistant.const import DEVICE_DEFAULT_NAME +from homeassistant.helpers.entity import ToggleEntity +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['rpi_pfio'] + +ATTR_INVERT_LOGIC = 'invert_logic' +ATTR_NAME = 'name' +CONF_PORTS = 'ports' + +DEFAULT_INVERT_LOGIC = False + +PORT_SCHEMA = vol.Schema({ + vol.Optional(ATTR_NAME, default=None): cv.string, + vol.Optional(ATTR_INVERT_LOGIC, default=DEFAULT_INVERT_LOGIC): cv.boolean +}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_PORTS, default={}): vol.Schema({ + cv.positive_int: PORT_SCHEMA + }) +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the PiFace Digital Output devices.""" + switches = [] + ports = config.get(CONF_PORTS) + for port, port_entity in ports.items(): + name = port_entity[ATTR_NAME] + invert_logic = port_entity[ATTR_INVERT_LOGIC] + + switches.append(RPiPFIOSwitch(port, name, invert_logic)) + add_devices(switches) + + +class RPiPFIOSwitch(ToggleEntity): + """Representation of a PiFace Digital Output.""" + + def __init__(self, port, name, invert_logic): + """Initialize the pin.""" + self._port = port + self._name = name or DEVICE_DEFAULT_NAME + self._invert_logic = invert_logic + self._state = False + rpi_pfio.write_output(self._port, 1 if self._invert_logic else 0) + + @property + def name(self): + """Return the name of the switch.""" + return self._name + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def is_on(self): + """Return true if device is on.""" + return self._state + + def turn_on(self): + """Turn the device on.""" + rpi_pfio.write_output(self._port, 0 if self._invert_logic else 1) + self._state = True + self.schedule_update_ha_state() + + def turn_off(self): + """Turn the device off.""" + rpi_pfio.write_output(self._port, 1 if self._invert_logic else 0) + self._state = False + self.schedule_update_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index 27ae45c9ddf..84cd1a50ce8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -429,6 +429,12 @@ pexpect==4.0.1 # homeassistant.components.light.hue phue==0.9 +# homeassistant.components.rpi_pfio +pifacecommon==4.1.2 + +# homeassistant.components.rpi_pfio +pifacedigitalio==3.0.5 + # homeassistant.components.light.piglow piglow==1.2.4