From df475cb797696057898e73138e5b0dd0860fe8d2 Mon Sep 17 00:00:00 2001 From: Pascal Roeleven Date: Thu, 18 Apr 2019 12:43:34 +0200 Subject: [PATCH] Adds Orange Pi GPIO platform (#22541) * Adds Orange Pi GPIO platform * Add manifest.json * Remove cover platform * Apply requested changes * Remove switch platform * Update CODEOWNERS * Remove obsolete dependecies/requirements --- .coveragerc | 1 + CODEOWNERS | 1 + .../components/orangepi_gpio/__init__.py | 81 +++++++++++++++++++ .../components/orangepi_gpio/binary_sensor.py | 68 ++++++++++++++++ .../components/orangepi_gpio/const.py | 21 +++++ .../components/orangepi_gpio/manifest.json | 12 +++ requirements_all.txt | 3 + 7 files changed, 187 insertions(+) create mode 100644 homeassistant/components/orangepi_gpio/__init__.py create mode 100644 homeassistant/components/orangepi_gpio/binary_sensor.py create mode 100644 homeassistant/components/orangepi_gpio/const.py create mode 100644 homeassistant/components/orangepi_gpio/manifest.json diff --git a/.coveragerc b/.coveragerc index 86819ef51a39..cb0c50f72fe9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -418,6 +418,7 @@ omit = homeassistant/components/openweathermap/sensor.py homeassistant/components/openweathermap/weather.py homeassistant/components/opple/light.py + homeassistant/components/orangepi_gpio/* homeassistant/components/orvibo/switch.py homeassistant/components/osramlightify/light.py homeassistant/components/otp/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 68720c2821b4..aa4b5547d2c1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -161,6 +161,7 @@ homeassistant/components/ohmconnect/* @robbiet480 homeassistant/components/onboarding/* @home-assistant/core homeassistant/components/openuv/* @bachya homeassistant/components/openweathermap/* @fabaff +homeassistant/components/orangepi_gpio/* @pascallj homeassistant/components/owlet/* @oblogic7 homeassistant/components/panel_custom/* @home-assistant/core homeassistant/components/panel_iframe/* @home-assistant/core diff --git a/homeassistant/components/orangepi_gpio/__init__.py b/homeassistant/components/orangepi_gpio/__init__.py new file mode 100644 index 000000000000..072a05e0dd77 --- /dev/null +++ b/homeassistant/components/orangepi_gpio/__init__.py @@ -0,0 +1,81 @@ +"""Support for controlling GPIO pins of a Orange Pi.""" +import logging + +from homeassistant.const import ( + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) + +_LOGGER = logging.getLogger(__name__) + +CONF_PINMODE = 'pinmode' +DOMAIN = 'orangepi_gpio' +PINMODES = ['pc', 'zeroplus', 'zeroplus2', 'deo', 'neocore2'] + + +def setup(hass, config): + """Set up the Orange Pi GPIO component.""" + from OPi import GPIO + + def cleanup_gpio(event): + """Stuff to do before stopping.""" + 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) + return True + + +def setup_mode(mode): + """Set GPIO pin mode.""" + from OPi import GPIO + + if mode == 'pc': + import orangepi.pc + GPIO.setmode(orangepi.pc.BOARD) + elif mode == 'zeroplus': + import orangepi.zeroplus + GPIO.setmode(orangepi.zeroplus.BOARD) + elif mode == 'zeroplus2': + import orangepi.zeroplus + GPIO.setmode(orangepi.zeroplus2.BOARD) + elif mode == 'duo': + import nanopi.duo + GPIO.setmode(nanopi.duo.BOARD) + elif mode == 'neocore2': + import nanopi.neocore2 + GPIO.setmode(nanopi.neocore2.BOARD) + + +def setup_output(port): + """Set up a GPIO as output.""" + from OPi import GPIO + GPIO.setup(port, GPIO.OUT) + + +def setup_input(port): + """Set up a GPIO as input.""" + from OPi import GPIO + GPIO.setup(port, GPIO.IN) + + +def write_output(port, value): + """Write a value to a GPIO.""" + from OPi import GPIO + GPIO.output(port, value) + + +def read_input(port): + """Read a value from a GPIO.""" + from OPi import GPIO + return GPIO.input(port) + + +def edge_detect(port, event_callback): + """Add detection for RISING and FALLING events.""" + from OPi import GPIO + GPIO.add_event_detect( + port, + GPIO.BOTH, + callback=event_callback) diff --git a/homeassistant/components/orangepi_gpio/binary_sensor.py b/homeassistant/components/orangepi_gpio/binary_sensor.py new file mode 100644 index 000000000000..1c5a447b101f --- /dev/null +++ b/homeassistant/components/orangepi_gpio/binary_sensor.py @@ -0,0 +1,68 @@ +"""Support for binary sensor using Orange Pi GPIO.""" +import logging + +from homeassistant.components import orangepi_gpio +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, PLATFORM_SCHEMA) +from homeassistant.const import DEVICE_DEFAULT_NAME + +from . import CONF_PINMODE +from .const import CONF_INVERT_LOGIC, CONF_PORTS, PORT_SCHEMA + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(PORT_SCHEMA) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the Orange Pi GPIO devices.""" + pinmode = config[CONF_PINMODE] + orangepi_gpio.setup_mode(pinmode) + + invert_logic = config[CONF_INVERT_LOGIC] + + binary_sensors = [] + ports = config[CONF_PORTS] + for port_num, port_name in ports.items(): + binary_sensors.append(OPiGPIOBinarySensor( + port_name, port_num, invert_logic)) + add_entities(binary_sensors, True) + + +class OPiGPIOBinarySensor(BinarySensorDevice): + """Represent a binary sensor that uses Orange Pi GPIO.""" + + def __init__(self, name, port, invert_logic): + """Initialize the Orange Pi binary sensor.""" + self._name = name or DEVICE_DEFAULT_NAME + self._port = port + self._invert_logic = invert_logic + self._state = None + + orangepi_gpio.setup_input(self._port) + + def read_gpio(port): + """Read state from GPIO.""" + self._state = orangepi_gpio.read_input(self._port) + self.schedule_update_ha_state() + + orangepi_gpio.edge_detect(self._port, read_gpio) + + @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 GPIO state.""" + self._state = orangepi_gpio.read_input(self._port) diff --git a/homeassistant/components/orangepi_gpio/const.py b/homeassistant/components/orangepi_gpio/const.py new file mode 100644 index 000000000000..422660f1f64f --- /dev/null +++ b/homeassistant/components/orangepi_gpio/const.py @@ -0,0 +1,21 @@ +"""Constants for Orange Pi GPIO.""" +import voluptuous as vol + +from homeassistant.helpers import config_validation as cv + +from . import CONF_PINMODE, PINMODES + +CONF_INVERT_LOGIC = 'invert_logic' +CONF_PORTS = 'ports' + +DEFAULT_INVERT_LOGIC = False + +_SENSORS_SCHEMA = vol.Schema({ + cv.positive_int: cv.string, +}) + +PORT_SCHEMA = { + vol.Required(CONF_PORTS): _SENSORS_SCHEMA, + vol.Required(CONF_PINMODE): vol.In(PINMODES), + vol.Optional(CONF_INVERT_LOGIC, default=DEFAULT_INVERT_LOGIC): cv.boolean, +} diff --git a/homeassistant/components/orangepi_gpio/manifest.json b/homeassistant/components/orangepi_gpio/manifest.json new file mode 100644 index 000000000000..65fd0f7de508 --- /dev/null +++ b/homeassistant/components/orangepi_gpio/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "orangepi_gpio", + "name": "Orangepi GPIO", + "documentation": "https://www.home-assistant.io/components/orangepi_gpio", + "requirements": [ + "OPi.GPIO==0.3.6" + ], + "dependencies": [], + "codeowners": [ + "@pascallj" + ] +} diff --git a/requirements_all.txt b/requirements_all.txt index c4411eb17890..316a21da33a1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -38,6 +38,9 @@ HAP-python==2.5.0 # homeassistant.components.mastodon Mastodon.py==1.3.1 +# homeassistant.components.orangepi_gpio +OPi.GPIO==0.3.6 + # homeassistant.components.github PyGithub==1.43.5