Merge pull request #191 from fabaff/arduino

Arduino component
This commit is contained in:
Fabian Affolter 2015-06-27 13:14:29 +02:00
commit 7f0c334391
5 changed files with 320 additions and 0 deletions

View file

@ -7,6 +7,9 @@ omit =
homeassistant/external/*
# omit pieces of code that rely on external devices being present
homeassistant/components/arduino.py
homeassistant/components/*/arduino.py
homeassistant/components/wink.py
homeassistant/components/*/wink.py

View file

@ -0,0 +1,134 @@
"""
components.arduino
~~~~~~~~~~~~~~~~~~
Arduino component that connects to a directly attached Arduino board which
runs with the Firmata firmware.
Configuration:
To use the Arduino board you will need to add something like the following
to your config/configuration.yaml
arduino:
port: /dev/ttyACM0
Variables:
port
*Required
The port where is your board connected to your Home Assistant system.
If you are using an original Arduino the port will be named ttyACM*. The exact
number can be determined with 'ls /dev/ttyACM*' or check your 'dmesg'/
'journalctl -f' output. Keep in mind that Arduino clones are often using a
different name for the port (e.g. '/dev/ttyUSB*').
A word of caution: The Arduino is not storing states. This means that with
every initialization the pins are set to off/low.
"""
import logging
from PyMata.pymata import PyMata
import serial
from homeassistant.helpers import validate_config
from homeassistant.const import (EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP)
DOMAIN = "arduino"
DEPENDENCIES = []
BOARD = None
_LOGGER = logging.getLogger(__name__)
def setup(hass, config):
""" Setup the Arduino component. """
if not validate_config(config,
{DOMAIN: ['port']},
_LOGGER):
return False
# pylint: disable=global-statement
global BOARD
try:
BOARD = ArduinoBoard(config[DOMAIN]['port'])
except (serial.serialutil.SerialException, FileNotFoundError):
_LOGGER.exception("Your port is not accessible.")
return False
if BOARD.get_firmata()[1] <= 2:
_LOGGER.error("The StandardFirmata sketch should be 2.2 or newer.")
return False
def stop_arduino(event):
""" Stop the Arduino service. """
BOARD.disconnect()
def start_arduino(event):
""" Start the Arduino service. """
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_arduino)
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_arduino)
return True
class ArduinoBoard(object):
""" Represents an Arduino board. """
def __init__(self, port):
self._port = port
self._board = PyMata(self._port, verbose=False)
def set_mode(self, pin, direction, mode):
""" Sets the mode and the direction of a given pin. """
if mode == 'analog' and direction == 'in':
self._board.set_pin_mode(pin,
self._board.INPUT,
self._board.ANALOG)
elif mode == 'analog' and direction == 'out':
self._board.set_pin_mode(pin,
self._board.OUTPUT,
self._board.ANALOG)
elif mode == 'digital' and direction == 'in':
self._board.set_pin_mode(pin,
self._board.OUTPUT,
self._board.DIGITAL)
elif mode == 'digital' and direction == 'out':
self._board.set_pin_mode(pin,
self._board.OUTPUT,
self._board.DIGITAL)
elif mode == 'pwm':
self._board.set_pin_mode(pin,
self._board.OUTPUT,
self._board.PWM)
def get_analog_inputs(self):
""" Get the values from the pins. """
self._board.capability_query()
return self._board.get_analog_response_table()
def set_digital_out_high(self, pin):
""" Sets a given digital pin to high. """
self._board.digital_write(pin, 1)
def set_digital_out_low(self, pin):
""" Sets a given digital pin to low. """
self._board.digital_write(pin, 0)
def get_digital_in(self, pin):
""" Gets the value from a given digital pin. """
self._board.digital_read(pin)
def get_analog_in(self, pin):
""" Gets the value from a given analog pin. """
self._board.analog_read(pin)
def get_firmata(self):
""" Return the version of the Firmata firmware. """
return self._board.get_firmata_version()
def disconnect(self):
""" Disconnects the board and closes the serial connection. """
self._board.reset()
self._board.close()

View file

@ -0,0 +1,87 @@
"""
homeassistant.components.sensor.arduino
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for getting information from Arduino pins. Only analog pins are
supported.
Configuration:
sensor:
platform: arduino
pins:
7:
name: Door switch
type: analog
0:
name: Brightness
type: analog
Variables:
pins
*Required
An array specifying the digital pins to use on the Arduino board.
These are the variables for the pins array:
name
*Required
The name for the pin that will be used in the frontend.
type
*Required
The type of the pin: 'analog'.
"""
import logging
import homeassistant.components.arduino as arduino
from homeassistant.helpers.entity import Entity
from homeassistant.const import DEVICE_DEFAULT_NAME
DEPENDENCIES = ['arduino']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Arduino platform. """
# Verify that Arduino board is present
if arduino.BOARD is None:
_LOGGER.error('A connection has not been made to the Arduino board.')
return False
sensors = []
pins = config.get('pins')
for pinnum, pin in pins.items():
if pin.get('name'):
sensors.append(ArduinoSensor(pin.get('name'),
pinnum,
'analog'))
add_devices(sensors)
class ArduinoSensor(Entity):
""" Represents an Arduino Sensor. """
def __init__(self, name, pin, pin_type):
self._pin = pin
self._name = name or DEVICE_DEFAULT_NAME
self.pin_type = pin_type
self.direction = 'in'
self._value = None
arduino.BOARD.set_mode(self._pin, self.direction, self.pin_type)
@property
def state(self):
""" Returns the state of the sensor. """
return self._value
@property
def name(self):
""" Get the name of the sensor. """
return self._name
def update(self):
""" Get the latest value from the pin. """
self._value = arduino.BOARD.get_analog_inputs()[self._pin][1]

View file

@ -0,0 +1,93 @@
"""
homeassistant.components.switch.arduino
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for switching Arduino pins on and off. So fare only digital pins are
supported.
Configuration:
switch:
platform: arduino
pins:
11:
name: Fan Office
type: digital
12:
name: Light Desk
type: digital
Variables:
pins
*Required
An array specifying the digital pins to use on the Arduino board.
These are the variables for the pins array:
name
*Required
The name for the pin that will be used in the frontend.
type
*Required
The type of the pin: 'digital'.
"""
import logging
import homeassistant.components.arduino as arduino
from homeassistant.components.switch import SwitchDevice
from homeassistant.const import DEVICE_DEFAULT_NAME
DEPENDENCIES = ['arduino']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Arduino platform. """
# Verify that Arduino board is present
if arduino.BOARD is None:
_LOGGER.error('A connection has not been made to the Arduino board.')
return False
switches = []
pins = config.get('pins')
for pinnum, pin in pins.items():
if pin.get('name'):
switches.append(ArduinoSwitch(pin.get('name'),
pinnum,
pin.get('type')))
add_devices(switches)
class ArduinoSwitch(SwitchDevice):
""" Represents an Arduino Switch. """
def __init__(self, name, pin, pin_type):
self._pin = pin
self._name = name or DEVICE_DEFAULT_NAME
self.pin_type = pin_type
self.direction = 'out'
self._state = False
arduino.BOARD.set_mode(self._pin, self.direction, self.pin_type)
@property
def name(self):
""" Get the name of the pin. """
return self._name
@property
def is_on(self):
""" Returns True if pin is high/on. """
return self._state
def turn_on(self):
""" Turns the pin to high/on. """
self._state = True
arduino.BOARD.set_digital_out_high(self._pin)
def turn_off(self):
""" Turns the pin to low/off. """
self._state = False
arduino.BOARD.set_digital_out_low(self._pin)

View file

@ -73,3 +73,6 @@ jsonrpc-requests>=0.1
# Forecast.io Bindings (sensor.forecast)
python-forecastio>=1.3.3
# Firmata Bindings (*.arduino)
PyMata==2.07a