Merge pull request #278 from sfam/dev

New RPi_GPIO sensor and switch improvements
This commit is contained in:
Paulus Schoutsen 2015-08-26 08:40:54 -07:00
commit e2cfe2a7d2
3 changed files with 152 additions and 5 deletions

View File

@ -62,6 +62,7 @@ omit =
homeassistant/components/sensor/mysensors.py homeassistant/components/sensor/mysensors.py
homeassistant/components/sensor/openweathermap.py homeassistant/components/sensor/openweathermap.py
homeassistant/components/sensor/rfxtrx.py homeassistant/components/sensor/rfxtrx.py
homeassistant/components/sensor/rpi_gpio.py
homeassistant/components/sensor/sabnzbd.py homeassistant/components/sensor/sabnzbd.py
homeassistant/components/sensor/swiss_public_transport.py homeassistant/components/sensor/swiss_public_transport.py
homeassistant/components/sensor/systemmonitor.py homeassistant/components/sensor/systemmonitor.py

View File

@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
"""
homeassistant.components.sensor.rpi_gpio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a binary state sensor using RPi GPIO.
Note: To use RPi GPIO, Home Assistant must be run as root.
sensor:
platform: rpi_gpio
pull_mode: "UP"
value_high: "Active"
value_low: "Inactive"
ports:
11: PIR Office
12: PIR Bedroom
Variables:
pull_mode
*Optional
The internal pull to use (UP or DOWN). Default is UP.
value_high
*Optional
The value of the sensor when the port is HIGH. Default is "HIGH".
value_low
*Optional
The value of the sensor when the port is LOW. Default is "LOW".
bouncetime
*Optional
The time in milliseconds for port debouncing. Default is 50ms.
ports
*Required
An array specifying the GPIO ports to use and the name to use in the frontend.
"""
import logging
from homeassistant.helpers.entity import Entity
try:
import RPi.GPIO as GPIO
except ImportError:
GPIO = None
from homeassistant.const import (DEVICE_DEFAULT_NAME,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP)
DEFAULT_PULL_MODE = "UP"
DEFAULT_VALUE_HIGH = "HIGH"
DEFAULT_VALUE_LOW = "LOW"
DEFAULT_BOUNCETIME = 50
REQUIREMENTS = ['RPi.GPIO>=0.5.11']
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Raspberry PI GPIO ports. """
if GPIO is None:
_LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.')
return
# pylint: disable=no-member
GPIO.setmode(GPIO.BCM)
sensors = []
pull_mode = config.get('pull_mode', DEFAULT_PULL_MODE)
value_high = config.get('value_high', DEFAULT_VALUE_HIGH)
value_low = config.get('value_low', DEFAULT_VALUE_LOW)
bouncetime = config.get('bouncetime', DEFAULT_BOUNCETIME)
ports = config.get('ports')
for port_num, port_name in ports.items():
sensors.append(RPiGPIOSensor(
port_name, port_num, pull_mode,
value_high, value_low, bouncetime))
add_devices(sensors)
def cleanup_gpio(event):
""" Stuff to do before stop home assistant. """
# pylint: disable=no-member
GPIO.cleanup()
def prepare_gpio(event):
""" Stuff to do when home assistant starts. """
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, cleanup_gpio)
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, prepare_gpio)
# pylint: disable=too-many-arguments, too-many-instance-attributes
class RPiGPIOSensor(Entity):
""" Sets up the Raspberry PI GPIO ports. """
def __init__(self, port_name, port_num, pull_mode,
value_high, value_low, bouncetime):
# pylint: disable=no-member
self._name = port_name or DEVICE_DEFAULT_NAME
self._port = port_num
self._pull = GPIO.PUD_DOWN if pull_mode == "DOWN" else GPIO.PUD_UP
self._vhigh = value_high
self._vlow = value_low
self._bouncetime = bouncetime
GPIO.setup(self._port, GPIO.IN, pull_up_down=self._pull)
self._state = self._vhigh if GPIO.input(self._port) else self._vlow
def edge_callback(channel):
""" port changed state """
# pylint: disable=no-member
self._state = self._vhigh if GPIO.input(channel) else self._vlow
self.update_ha_state()
GPIO.add_event_detect(
self._port,
GPIO.BOTH,
callback=edge_callback,
bouncetime=self._bouncetime)
@property
def should_poll(self):
""" No polling needed """
return False
@property
def name(self):
""" The name of the sensor """
return self._name
@property
def state(self):
""" Returns the state of the entity. """
return self._state

View File

@ -2,21 +2,28 @@
homeassistant.components.switch.rpi_gpio homeassistant.components.switch.rpi_gpio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to control the GPIO pins of a Raspberry Pi. Allows to control the GPIO pins of a Raspberry Pi.
Note: To use RPi GPIO, Home Assistant must be run as root.
Configuration: Configuration:
switch: switch:
platform: rpi_gpio platform: rpi_gpio
invert_logic: false
ports: ports:
11: Fan Office 11: Fan Office
12: Light Desk 12: Light Desk
Variables: Variables:
invert_logic
*Optional
If true, inverts the output logic to ACTIVE LOW. Default is false (ACTIVE HIGH)
ports ports
*Required *Required
An array specifying the GPIO ports to use and the name to use in the frontend. An array specifying the GPIO ports to use and the name to use in the frontend.
""" """
import logging import logging
try: try:
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
@ -27,6 +34,8 @@ from homeassistant.const import (DEVICE_DEFAULT_NAME,
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP) EVENT_HOMEASSISTANT_STOP)
DEFAULT_INVERT_LOGIC = False
REQUIREMENTS = ['RPi.GPIO>=0.5.11'] REQUIREMENTS = ['RPi.GPIO>=0.5.11']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -37,11 +46,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if GPIO is None: if GPIO is None:
_LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.') _LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.')
return return
# pylint: disable=no-member
GPIO.setmode(GPIO.BCM)
switches = [] switches = []
invert_logic = config.get('invert_logic', DEFAULT_INVERT_LOGIC)
ports = config.get('ports') ports = config.get('ports')
for port_num, port_name in ports.items(): for port_num, port_name in ports.items():
switches.append(RPiGPIOSwitch(port_name, port_num)) switches.append(RPiGPIOSwitch(port_name, port_num, invert_logic))
add_devices(switches) add_devices(switches)
def cleanup_gpio(event): def cleanup_gpio(event):
@ -59,10 +71,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class RPiGPIOSwitch(ToggleEntity): class RPiGPIOSwitch(ToggleEntity):
""" Represents a port that can be toggled using Raspberry Pi GPIO. """ """ Represents a port that can be toggled using Raspberry Pi GPIO. """
def __init__(self, name, gpio): def __init__(self, name, gpio, invert_logic):
self._name = name or DEVICE_DEFAULT_NAME self._name = name or DEVICE_DEFAULT_NAME
self._state = False
self._gpio = gpio self._gpio = gpio
self._active_state = not invert_logic
self._state = not self._active_state
# pylint: disable=no-member # pylint: disable=no-member
GPIO.setup(gpio, GPIO.OUT) GPIO.setup(gpio, GPIO.OUT)
@ -83,13 +96,13 @@ class RPiGPIOSwitch(ToggleEntity):
def turn_on(self, **kwargs): def turn_on(self, **kwargs):
""" Turn the device on. """ """ Turn the device on. """
if self._switch(True): if self._switch(self._active_state):
self._state = True self._state = True
self.update_ha_state() self.update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
""" Turn the device off. """ """ Turn the device off. """
if self._switch(False): if self._switch(not self._active_state):
self._state = False self._state = False
self.update_ha_state() self.update_ha_state()