From 0a9d82fe6f8def0deea2498f4189b6e275033281 Mon Sep 17 00:00:00 2001 From: sfam Date: Tue, 25 Aug 2015 23:23:51 +0100 Subject: [PATCH 1/9] Fix RPi_GPIO switch and add extra parameters --- homeassistant/components/switch/rpi_gpio.py | 23 ++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/switch/rpi_gpio.py b/homeassistant/components/switch/rpi_gpio.py index 127d02a121d..9c1caaea0b1 100644 --- a/homeassistant/components/switch/rpi_gpio.py +++ b/homeassistant/components/switch/rpi_gpio.py @@ -2,21 +2,28 @@ homeassistant.components.switch.rpi_gpio ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Allows to control the GPIO pins of a Raspberry Pi. +Note: To use RPi GPIO, Home Assistant must be run as root. Configuration: switch: platform: rpi_gpio + active_state: "HIGH" ports: 11: Fan Office 12: Light Desk Variables: +active_state +*Optional +Defines which GPIO state corresponds to a ACTIVE switch. Default is HIGH. + ports *Required An array specifying the GPIO ports to use and the name to use in the frontend. """ + import logging try: import RPi.GPIO as GPIO @@ -27,6 +34,8 @@ from homeassistant.const import (DEVICE_DEFAULT_NAME, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) +DEFAULT_ACTIVE_STATE = "HIGH" + REQUIREMENTS = ['RPi.GPIO>=0.5.11'] _LOGGER = logging.getLogger(__name__) @@ -38,10 +47,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.') return + GPIO.setmode(GPIO.BCM) + switches = [] + active_state = config.get('active_state', DEFAULT_ACTIVE_STATE) ports = config.get('ports') for port_num, port_name in ports.items(): - switches.append(RPiGPIOSwitch(port_name, port_num)) + switches.append(RPiGPIOSwitch(port_name, port_num, active_state)) add_devices(switches) def cleanup_gpio(event): @@ -59,10 +71,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class RPiGPIOSwitch(ToggleEntity): """ Represents a port that can be toggled using Raspberry Pi GPIO. """ - def __init__(self, name, gpio): + def __init__(self, name, gpio, active_state): self._name = name or DEVICE_DEFAULT_NAME - self._state = False + self._state = False if self._active_state == "HIGH" else True self._gpio = gpio + self._active_state = active_state # pylint: disable=no-member GPIO.setup(gpio, GPIO.OUT) @@ -83,13 +96,13 @@ class RPiGPIOSwitch(ToggleEntity): def turn_on(self, **kwargs): """ Turn the device on. """ - if self._switch(True): + if self._switch(True if self._active_state == "HIGH" else False): self._state = True self.update_ha_state() def turn_off(self, **kwargs): """ Turn the device off. """ - if self._switch(False): + if self._switch(False if self._active_state == "HIGH" else True): self._state = False self.update_ha_state() From ab5a5699223dd795e9bd01e27bae4df0e74169a9 Mon Sep 17 00:00:00 2001 From: sfam Date: Tue, 25 Aug 2015 23:24:36 +0100 Subject: [PATCH 2/9] Add RPi GPIO sensor --- homeassistant/components/sensor/rpi_gpio.py | 130 ++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 homeassistant/components/sensor/rpi_gpio.py diff --git a/homeassistant/components/sensor/rpi_gpio.py b/homeassistant/components/sensor/rpi_gpio.py new file mode 100644 index 00000000000..1f5cb072ca6 --- /dev/null +++ b/homeassistant/components/sensor/rpi_gpio.py @@ -0,0 +1,130 @@ +# -*- 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 + + 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) + + +class RPiGPIOSensor(Entity): + """ Sets up the Raspberry PI GPIO ports. """ + def __init__(self, port_name, port_num, pull_mode, + value_high, value_low, bouncetime): + self._name = port_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 """ + 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 From cfc2232c22f51c7aadfc258ba6a3adced62c668c Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 26 Aug 2015 00:02:52 +0100 Subject: [PATCH 3/9] fix pylint warnings --- homeassistant/components/switch/rpi_gpio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/rpi_gpio.py b/homeassistant/components/switch/rpi_gpio.py index 9c1caaea0b1..a1f9f61192b 100644 --- a/homeassistant/components/switch/rpi_gpio.py +++ b/homeassistant/components/switch/rpi_gpio.py @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if GPIO is None: _LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.') return - + # pylint: disable=no-member GPIO.setmode(GPIO.BCM) switches = [] @@ -73,9 +73,9 @@ class RPiGPIOSwitch(ToggleEntity): def __init__(self, name, gpio, active_state): self._name = name or DEVICE_DEFAULT_NAME - self._state = False if self._active_state == "HIGH" else True self._gpio = gpio self._active_state = active_state + self._state = False if self._active_state == "HIGH" else True # pylint: disable=no-member GPIO.setup(gpio, GPIO.OUT) From c194121da693ba2dbf39ce1af196a96bb8f3452f Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 26 Aug 2015 00:11:07 +0100 Subject: [PATCH 4/9] fix pylint warnings --- homeassistant/components/sensor/rpi_gpio.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/rpi_gpio.py b/homeassistant/components/sensor/rpi_gpio.py index 1f5cb072ca6..ee410be6ed4 100644 --- a/homeassistant/components/sensor/rpi_gpio.py +++ b/homeassistant/components/sensor/rpi_gpio.py @@ -63,7 +63,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if GPIO is None: _LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.') return - + # pylint: disable=no-member GPIO.setmode(GPIO.BCM) sensors = [] @@ -94,9 +94,10 @@ class RPiGPIOSensor(Entity): """ Sets up the Raspberry PI GPIO ports. """ def __init__(self, port_name, port_num, pull_mode, value_high, value_low, bouncetime): - self._name = port_name + # 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._pull = GPIO.PUD_DOWN if pull_mode == "DOWN" else GPIO.PUD_UP self._vhigh = value_high self._vlow = value_low self._bouncetime = bouncetime @@ -105,6 +106,7 @@ class RPiGPIOSensor(Entity): 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() From 930036272bbfbb1e29466e58e08e2395dd8434f7 Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 26 Aug 2015 00:15:57 +0100 Subject: [PATCH 5/9] fix pylint warnings --- homeassistant/components/sensor/rpi_gpio.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/sensor/rpi_gpio.py b/homeassistant/components/sensor/rpi_gpio.py index ee410be6ed4..c57cf31b397 100644 --- a/homeassistant/components/sensor/rpi_gpio.py +++ b/homeassistant/components/sensor/rpi_gpio.py @@ -90,6 +90,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): 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, From c8b88219b7d923e6d404efdff9047b24a94ac3bc Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 26 Aug 2015 11:03:06 +0100 Subject: [PATCH 6/9] rename config parameter to "invert_logic" --- homeassistant/components/switch/rpi_gpio.py | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/switch/rpi_gpio.py b/homeassistant/components/switch/rpi_gpio.py index a1f9f61192b..298168ed65a 100644 --- a/homeassistant/components/switch/rpi_gpio.py +++ b/homeassistant/components/switch/rpi_gpio.py @@ -8,16 +8,16 @@ Configuration: switch: platform: rpi_gpio - active_state: "HIGH" + invert_logic: false ports: 11: Fan Office 12: Light Desk Variables: -active_state +invert_logic *Optional -Defines which GPIO state corresponds to a ACTIVE switch. Default is HIGH. +If true, inverts the output logic to ACTIVE LOW. Default is false (ACTIVE HIGH). ports *Required @@ -34,7 +34,7 @@ from homeassistant.const import (DEVICE_DEFAULT_NAME, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) -DEFAULT_ACTIVE_STATE = "HIGH" +DEFAULT_INVERT_LOGIC = False REQUIREMENTS = ['RPi.GPIO>=0.5.11'] _LOGGER = logging.getLogger(__name__) @@ -50,10 +50,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): GPIO.setmode(GPIO.BCM) switches = [] - active_state = config.get('active_state', DEFAULT_ACTIVE_STATE) + invert_logic = config.get('invert_logic', DEFAULT_INVERT_LOGIC) ports = config.get('ports') for port_num, port_name in ports.items(): - switches.append(RPiGPIOSwitch(port_name, port_num, active_state)) + switches.append(RPiGPIOSwitch(port_name, port_num, invert_logic)) add_devices(switches) def cleanup_gpio(event): @@ -71,11 +71,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class RPiGPIOSwitch(ToggleEntity): """ Represents a port that can be toggled using Raspberry Pi GPIO. """ - def __init__(self, name, gpio, active_state): + def __init__(self, name, gpio, invert_logic): self._name = name or DEVICE_DEFAULT_NAME self._gpio = gpio - self._active_state = active_state - self._state = False if self._active_state == "HIGH" else True + self._active_state = !invert_logic + self._state = !self._active_state # pylint: disable=no-member GPIO.setup(gpio, GPIO.OUT) @@ -96,13 +96,13 @@ class RPiGPIOSwitch(ToggleEntity): def turn_on(self, **kwargs): """ Turn the device on. """ - if self._switch(True if self._active_state == "HIGH" else False): + if self._switch(self._active_state): self._state = True self.update_ha_state() def turn_off(self, **kwargs): """ Turn the device off. """ - if self._switch(False if self._active_state == "HIGH" else True): + if self._switch(!self._active_state): self._state = False self.update_ha_state() From 6b3b000822dd5306da590bed173ab4364c9a958e Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 26 Aug 2015 11:22:06 +0100 Subject: [PATCH 7/9] quick fix --- homeassistant/components/switch/rpi_gpio.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/switch/rpi_gpio.py b/homeassistant/components/switch/rpi_gpio.py index 298168ed65a..c21280a2fa8 100644 --- a/homeassistant/components/switch/rpi_gpio.py +++ b/homeassistant/components/switch/rpi_gpio.py @@ -74,8 +74,8 @@ class RPiGPIOSwitch(ToggleEntity): def __init__(self, name, gpio, invert_logic): self._name = name or DEVICE_DEFAULT_NAME self._gpio = gpio - self._active_state = !invert_logic - self._state = !self._active_state + self._active_state = not invert_logic + self._state = not self._active_state # pylint: disable=no-member GPIO.setup(gpio, GPIO.OUT) @@ -102,7 +102,7 @@ class RPiGPIOSwitch(ToggleEntity): def turn_off(self, **kwargs): """ Turn the device off. """ - if self._switch(!self._active_state): + if self._switch(not self._active_state): self._state = False self.update_ha_state() From 9811869111e7830f96fb7db08307e8a895193dc4 Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 26 Aug 2015 11:27:27 +0100 Subject: [PATCH 8/9] fix line too long --- homeassistant/components/switch/rpi_gpio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/switch/rpi_gpio.py b/homeassistant/components/switch/rpi_gpio.py index c21280a2fa8..bb9cf13e3ed 100644 --- a/homeassistant/components/switch/rpi_gpio.py +++ b/homeassistant/components/switch/rpi_gpio.py @@ -17,7 +17,7 @@ Variables: invert_logic *Optional -If true, inverts the output logic to ACTIVE LOW. Default is false (ACTIVE HIGH). +If true, inverts the output logic to ACTIVE LOW. Default is false (ACTIVE HIGH) ports *Required From 47998cff97399512546676f1957053fa8a435f9e Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 26 Aug 2015 15:45:39 +0100 Subject: [PATCH 9/9] Update .coveragerc --- .coveragerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.coveragerc b/.coveragerc index 7c0421c384a..65292aa9130 100644 --- a/.coveragerc +++ b/.coveragerc @@ -61,6 +61,7 @@ omit = homeassistant/components/sensor/mysensors.py homeassistant/components/sensor/openweathermap.py homeassistant/components/sensor/rfxtrx.py + homeassistant/components/sensor/rpi_gpio.py homeassistant/components/sensor/sabnzbd.py homeassistant/components/sensor/swiss_public_transport.py homeassistant/components/sensor/systemmonitor.py