Merge branch 'dev' of https://github.com/balloob/home-assistant into alarmdotcom_bugfix

This commit is contained in:
Daren Lord 2016-01-15 22:16:01 -07:00
commit a194c4f1bd
22 changed files with 359 additions and 227 deletions

View File

@ -41,6 +41,9 @@ omit =
homeassistant/components/mysensors.py homeassistant/components/mysensors.py
homeassistant/components/*/mysensors.py homeassistant/components/*/mysensors.py
homeassistant/components/rpi_gpio.py
homeassistant/components/*/rpi_gpio.py
homeassistant/components/binary_sensor/arest.py homeassistant/components/binary_sensor/arest.py
homeassistant/components/binary_sensor/rest.py homeassistant/components/binary_sensor/rest.py
homeassistant/components/browser.py homeassistant/components/browser.py
@ -101,7 +104,6 @@ omit =
homeassistant/components/sensor/netatmo.py homeassistant/components/sensor/netatmo.py
homeassistant/components/sensor/openweathermap.py homeassistant/components/sensor/openweathermap.py
homeassistant/components/sensor/rest.py homeassistant/components/sensor/rest.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
@ -117,13 +119,13 @@ omit =
homeassistant/components/switch/mystrom.py homeassistant/components/switch/mystrom.py
homeassistant/components/switch/orvibo.py homeassistant/components/switch/orvibo.py
homeassistant/components/switch/rest.py homeassistant/components/switch/rest.py
homeassistant/components/switch/rpi_gpio.py
homeassistant/components/switch/transmission.py homeassistant/components/switch/transmission.py
homeassistant/components/switch/wemo.py homeassistant/components/switch/wemo.py
homeassistant/components/thermostat/heatmiser.py homeassistant/components/thermostat/heatmiser.py
homeassistant/components/thermostat/homematic.py homeassistant/components/thermostat/homematic.py
homeassistant/components/thermostat/honeywell.py homeassistant/components/thermostat/honeywell.py
homeassistant/components/thermostat/nest.py homeassistant/components/thermostat/nest.py
homeassistant/components/thermostat/proliphix.py
homeassistant/components/thermostat/radiotherm.py homeassistant/components/thermostat/radiotherm.py

View File

@ -1,9 +1,10 @@
""" """
homeassistant.components.alarm_control_panel.alarmdotcom homeassistant.components.alarm_control_panel.alarmdotcom
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Interfaces with Verisure alarm control panel. Interfaces with Verisure alarm control panel.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarmdotcom/ https://home-assistant.io/components/alarm_control_panel.alarmdotcom/
""" """
import logging import logging
@ -24,7 +25,7 @@ DEFAULT_NAME = 'Alarm.com'
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
""" Setup Alarm.com control panel """ """ Setup an Alarm.com control panel. """
username = config.get(CONF_USERNAME) username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD) password = config.get(CONF_PASSWORD)
@ -43,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-arguments, too-many-instance-attributes # pylint: disable=too-many-arguments, too-many-instance-attributes
# pylint: disable=abstract-method # pylint: disable=abstract-method
class AlarmDotCom(alarm.AlarmControlPanel): class AlarmDotCom(alarm.AlarmControlPanel):
""" Represents a Alarm.com status within HA """ """ Represents a Alarm.com status. """
def __init__(self, hass, name, code, username, password): def __init__(self, hass, name, code, username, password):
from pyalarmdotcom.pyalarmdotcom import Alarmdotcom from pyalarmdotcom.pyalarmdotcom import Alarmdotcom
@ -64,11 +65,12 @@ class AlarmDotCom(alarm.AlarmControlPanel):
@property @property
def code_format(self): def code_format(self):
""" One or more characters if code is defined """ """ One or more characters if code is defined. """
return None if self._code is None else '.+' return None if self._code is None else '.+'
@property @property
def state(self): def state(self):
""" Returns the state of the device. """
if self._alarm.state == 'Disarmed': if self._alarm.state == 'Disarmed':
return STATE_ALARM_DISARMED return STATE_ALARM_DISARMED
elif self._alarm.state == 'Armed Stay': elif self._alarm.state == 'Armed Stay':
@ -79,6 +81,7 @@ class AlarmDotCom(alarm.AlarmControlPanel):
return STATE_UNKNOWN return STATE_UNKNOWN
def alarm_disarm(self, code=None): def alarm_disarm(self, code=None):
""" Send disarm command. """
if not self._validate_code(code, 'arming home'): if not self._validate_code(code, 'arming home'):
return return
from pyalarmdotcom.pyalarmdotcom import Alarmdotcom from pyalarmdotcom.pyalarmdotcom import Alarmdotcom
@ -88,6 +91,7 @@ class AlarmDotCom(alarm.AlarmControlPanel):
self.update_ha_state() self.update_ha_state()
def alarm_arm_home(self, code=None): def alarm_arm_home(self, code=None):
""" Send arm home command. """
if not self._validate_code(code, 'arming home'): if not self._validate_code(code, 'arming home'):
return return
from pyalarmdotcom.pyalarmdotcom import Alarmdotcom from pyalarmdotcom.pyalarmdotcom import Alarmdotcom
@ -97,6 +101,7 @@ class AlarmDotCom(alarm.AlarmControlPanel):
self.update_ha_state() self.update_ha_state()
def alarm_arm_away(self, code=None): def alarm_arm_away(self, code=None):
""" Send arm away command. """
if not self._validate_code(code, 'arming home'): if not self._validate_code(code, 'arming home'):
return return
from pyalarmdotcom.pyalarmdotcom import Alarmdotcom from pyalarmdotcom.pyalarmdotcom import Alarmdotcom

View File

@ -0,0 +1,73 @@
"""
homeassistant.components.binary_sensor.rpi_gpio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a binary_sensor using RPi GPIO.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.rpi_gpio/
"""
import logging
import homeassistant.components.rpi_gpio as rpi_gpio
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.const import (DEVICE_DEFAULT_NAME)
DEFAULT_PULL_MODE = "UP"
DEFAULT_BOUNCETIME = 50
DEFAULT_INVERT_LOGIC = False
DEPENDENCIES = ['rpi_gpio']
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Raspberry PI GPIO devices. """
pull_mode = config.get('pull_mode', DEFAULT_PULL_MODE)
bouncetime = config.get('bouncetime', DEFAULT_BOUNCETIME)
invert_logic = config.get('invert_logic', DEFAULT_INVERT_LOGIC)
binary_sensors = []
ports = config.get('ports')
for port_num, port_name in ports.items():
binary_sensors.append(RPiGPIOBinarySensor(
port_name, port_num, pull_mode, bouncetime, invert_logic))
add_devices(binary_sensors)
# pylint: disable=too-many-arguments, too-many-instance-attributes
class RPiGPIOBinarySensor(BinarySensorDevice):
""" Represents a binary sensor that uses Raspberry Pi GPIO. """
def __init__(self, name, port, pull_mode, bouncetime, invert_logic):
# pylint: disable=no-member
self._name = name or DEVICE_DEFAULT_NAME
self._port = port
self._pull_mode = pull_mode
self._bouncetime = bouncetime
self._invert_logic = invert_logic
rpi_gpio.setup_input(self._port, self._pull_mode)
self._state = rpi_gpio.read_input(self._port)
def read_gpio(port):
""" Reads state from GPIO. """
self._state = rpi_gpio.read_input(self._port)
self.update_ha_state()
rpi_gpio.edge_detect(self._port, read_gpio, 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 is_on(self):
""" Returns the state of the entity. """
return self._state != self._invert_logic

View File

@ -49,10 +49,9 @@ def _handle_get_api_locative(hass, see, handler, path_match, data):
handler.write_text("Setting location to {}".format(location_name)) handler.write_text("Setting location to {}".format(location_name))
elif direction == 'exit': elif direction == 'exit':
current_state = hass.states.get( current_state = hass.states.get("{}.{}".format(DOMAIN, device))
"{}.{}".format(DOMAIN, device)).state
if current_state == location_name: if current_state is None or current_state.state == location_name:
see(dev_id=device, location_name=STATE_NOT_HOME) see(dev_id=device, location_name=STATE_NOT_HOME)
handler.write_text("Setting location to not home") handler.write_text("Setting location to not home")
else: else:

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """ """ DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "fe71771b9b24b0fb72a56e775c3e1112" VERSION = "1003c31441ec44b3db84b49980f736a7"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit 0b99a5933c35b88c3369e992426fff8bf450aa01 Subproject commit 2ecd6a818443780dc5d0d981996d165218b2b094

View File

@ -112,10 +112,10 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
_LOGGER.info("running http in development mode") _LOGGER.info("running http in development mode")
if ssl_certificate is not None: if ssl_certificate is not None:
wrap_kwargs = {'certfile': ssl_certificate} context = ssl.create_default_context(
if ssl_key is not None: purpose=ssl.Purpose.CLIENT_AUTH)
wrap_kwargs['keyfile'] = ssl_key context.load_cert_chain(ssl_certificate, keyfile=ssl_key)
self.socket = ssl.wrap_socket(self.socket, **wrap_kwargs) self.socket = context.wrap_socket(self.socket, server_side=True)
def start(self): def start(self):
""" Starts the HTTP server. """ """ Starts the HTTP server. """

View File

@ -15,7 +15,7 @@ from homeassistant.components.light import ATTR_BRIGHTNESS
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, STATE_ON from homeassistant.const import EVENT_HOMEASSISTANT_STOP, STATE_ON
REQUIREMENTS = ['pyvera==0.2.3'] REQUIREMENTS = ['pyvera==0.2.6']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -86,4 +86,4 @@ class VeraLight(VeraSwitch):
self.vera_device.switch_on() self.vera_device.switch_on()
self._state = STATE_ON self._state = STATE_ON
self.update_ha_state() self.update_ha_state(True)

View File

@ -12,7 +12,7 @@ from homeassistant.components.light import ATTR_BRIGHTNESS
from homeassistant.components.wink import WinkToggleDevice from homeassistant.components.wink import WinkToggleDevice
from homeassistant.const import CONF_ACCESS_TOKEN from homeassistant.const import CONF_ACCESS_TOKEN
REQUIREMENTS = ['python-wink==0.3.1'] REQUIREMENTS = ['python-wink==0.4.1']
def setup_platform(hass, config, add_devices_callback, discovery_info=None): def setup_platform(hass, config, add_devices_callback, discovery_info=None):

View File

@ -11,7 +11,7 @@ import logging
from homeassistant.components.lock import LockDevice from homeassistant.components.lock import LockDevice
from homeassistant.const import CONF_ACCESS_TOKEN from homeassistant.const import CONF_ACCESS_TOKEN
REQUIREMENTS = ['python-wink==0.3.1'] REQUIREMENTS = ['python-wink==0.4.1']
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):

View File

@ -0,0 +1,69 @@
"""
homeassistant.components.rpi_gpio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to control the GPIO pins of a Raspberry Pi.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/rpi_gpio/
"""
import logging
try:
import RPi.GPIO as GPIO
except ImportError:
GPIO = None
from homeassistant.const import (EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP)
REQUIREMENTS = ['RPi.GPIO==0.6.1']
DOMAIN = "rpi_gpio"
_LOGGER = logging.getLogger(__name__)
# pylint: disable=no-member
def setup(hass, config):
""" Sets up the Raspberry PI GPIO component. """
if GPIO is None:
_LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.')
return False
def cleanup_gpio(event):
""" Stuff to do before stop home assistant. """
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)
GPIO.setmode(GPIO.BCM)
return True
def setup_output(port):
""" Setup a GPIO as output. """
GPIO.setup(port, GPIO.OUT)
def setup_input(port, pull_mode):
""" Setup a GPIO as input. """
GPIO.setup(port, GPIO.IN,
GPIO.PUD_DOWN if pull_mode == 'DOWN' else GPIO.PUD_UP)
def write_output(port, value):
""" Write a value to a GPIO. """
GPIO.output(port, value)
def read_input(port):
""" Read a value from a GPIO. """
return GPIO.input(port)
def edge_detect(port, event_callback, bounce):
""" Adds detection for RISING and FALLING events. """
GPIO.add_event_detect(
port,
GPIO.BOTH,
callback=event_callback,
bouncetime=bounce)

View File

@ -1,97 +0,0 @@
"""
homeassistant.components.sensor.rpi_gpio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a binary state sensor using RPi GPIO.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.rpi_gpio/
"""
# pylint: disable=import-error
import logging
from homeassistant.helpers.entity import Entity
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. """
import RPi.GPIO as GPIO
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
import RPi.GPIO as GPIO
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

@ -15,7 +15,7 @@ from homeassistant.const import (
ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME, ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME,
TEMP_CELCIUS, TEMP_FAHRENHEIT, EVENT_HOMEASSISTANT_STOP) TEMP_CELCIUS, TEMP_FAHRENHEIT, EVENT_HOMEASSISTANT_STOP)
REQUIREMENTS = ['pyvera==0.2.3'] REQUIREMENTS = ['pyvera==0.2.6']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -45,7 +45,10 @@ def get_devices(hass, config):
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_subscription) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_subscription)
categories = ['Temperature Sensor', 'Light Sensor', 'Sensor'] categories = ['Temperature Sensor',
'Light Sensor',
'Humidity Sensor',
'Sensor']
devices = [] devices = []
try: try:
devices = vera_controller.get_devices(categories) devices = vera_controller.get_devices(categories)
@ -86,6 +89,7 @@ class VeraSensor(Entity):
self._temperature_units = None self._temperature_units = None
self.controller.register(vera_device, self._update_callback) self.controller.register(vera_device, self._update_callback)
self.update()
def _update_callback(self, _device): def _update_callback(self, _device):
""" Called by the vera device callback to update state. """ """ Called by the vera device callback to update state. """
@ -106,7 +110,12 @@ class VeraSensor(Entity):
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
""" Unit of measurement of this entity, if any. """ """ Unit of measurement of this entity, if any. """
return self._temperature_units if self.vera_device.category == "Temperature Sensor":
return self._temperature_units
elif self.vera_device.category == "Light Sensor":
return 'lux'
elif self.vera_device.category == "Humidity Sensor":
return '%'
@property @property
def state_attributes(self): def state_attributes(self):
@ -115,19 +124,19 @@ class VeraSensor(Entity):
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%' attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
if self.vera_device.is_armable: if self.vera_device.is_armable:
armed = self.vera_device.get_value('Armed') armed = self.vera_device.is_armed
attr[ATTR_ARMED] = 'True' if armed == '1' else 'False' attr[ATTR_ARMED] = 'True' if armed else 'False'
if self.vera_device.is_trippable: if self.vera_device.is_trippable:
last_tripped = self.vera_device.get_value('LastTrip') last_tripped = self.vera_device.last_trip
if last_tripped is not None: if last_tripped is not None:
utc_time = dt_util.utc_from_timestamp(int(last_tripped)) utc_time = dt_util.utc_from_timestamp(int(last_tripped))
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str( attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
utc_time) utc_time)
else: else:
attr[ATTR_LAST_TRIP_TIME] = None attr[ATTR_LAST_TRIP_TIME] = None
tripped = self.vera_device.get_value('Tripped') tripped = self.vera_device.is_tripped
attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False' attr[ATTR_TRIPPED] = 'True' if tripped else 'False'
attr['Vera Device Id'] = self.vera_device.vera_device_id attr['Vera Device Id'] = self.vera_device.vera_device_id
return attr return attr
@ -139,8 +148,9 @@ class VeraSensor(Entity):
def update(self): def update(self):
if self.vera_device.category == "Temperature Sensor": if self.vera_device.category == "Temperature Sensor":
current_temp = self.vera_device.get_value('CurrentTemperature') current_temp = self.vera_device.temperature
vera_temp_units = self.vera_device.veraController.temperature_units vera_temp_units = (
self.vera_device.vera_controller.temperature_units)
if vera_temp_units == 'F': if vera_temp_units == 'F':
self._temperature_units = TEMP_FAHRENHEIT self._temperature_units = TEMP_FAHRENHEIT
@ -156,9 +166,11 @@ class VeraSensor(Entity):
self.current_value = current_temp self.current_value = current_temp
elif self.vera_device.category == "Light Sensor": elif self.vera_device.category == "Light Sensor":
self.current_value = self.vera_device.get_value('CurrentLevel') self.current_value = self.vera_device.light
elif self.vera_device.category == "Humidity Sensor":
self.current_value = self.vera_device.humidity
elif self.vera_device.category == "Sensor": elif self.vera_device.category == "Sensor":
tripped = self.vera_device.get_value('Tripped') tripped = self.vera_device.is_tripped
self.current_value = 'Tripped' if tripped == '1' else 'Not Tripped' self.current_value = 'Tripped' if tripped else 'Not Tripped'
else: else:
self.current_value = 'Unknown' self.current_value = 'Unknown'

View File

@ -11,7 +11,7 @@ import logging
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.const import CONF_ACCESS_TOKEN, STATE_OPEN, STATE_CLOSED from homeassistant.const import CONF_ACCESS_TOKEN, STATE_OPEN, STATE_CLOSED
REQUIREMENTS = ['python-wink==0.3.1'] REQUIREMENTS = ['python-wink==0.4.1']
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):

View File

@ -1,69 +1,48 @@
""" """
homeassistant.components.switch.rpi_gpio homeassistant.components.switch.rpi_gpio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to control the GPIO pins of a Raspberry Pi. Allows to configure a switch using RPi GPIO.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/switch.rpi_gpio/ https://home-assistant.io/components/switch.rpi_gpio/
""" """
import logging import logging
try: import homeassistant.components.rpi_gpio as rpi_gpio
import RPi.GPIO as GPIO
except ImportError:
GPIO = None
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from homeassistant.const import (DEVICE_DEFAULT_NAME, from homeassistant.const import (DEVICE_DEFAULT_NAME)
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP)
DEFAULT_INVERT_LOGIC = False DEFAULT_INVERT_LOGIC = False
REQUIREMENTS = ['RPi.GPIO==0.5.11'] DEPENDENCIES = ['rpi_gpio']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument # pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Raspberry PI GPIO ports. """ """ Sets up the Raspberry PI GPIO devices. """
if GPIO is None:
_LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.') invert_logic = config.get('invert_logic', DEFAULT_INVERT_LOGIC)
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, name in ports.items():
switches.append(RPiGPIOSwitch(port_name, port_num, invert_logic)) switches.append(RPiGPIOSwitch(name, port, invert_logic))
add_devices(switches) add_devices(switches)
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 RPiGPIOSwitch(ToggleEntity): class RPiGPIOSwitch(ToggleEntity):
""" Represents a port that can be toggled using Raspberry Pi GPIO. """ """ Represents a switch that can be toggled using Raspberry Pi GPIO. """
def __init__(self, name, port, invert_logic):
def __init__(self, name, gpio, invert_logic):
self._name = name or DEVICE_DEFAULT_NAME self._name = name or DEVICE_DEFAULT_NAME
self._gpio = gpio self._port = port
self._active_state = not invert_logic self._invert_logic = invert_logic
self._state = not self._active_state self._state = False
# pylint: disable=no-member rpi_gpio.setup_output(self._port)
GPIO.setup(gpio, GPIO.OUT)
@property @property
def name(self): def name(self):
""" The name of the port. """ """ The name of the switch. """
return self._name return self._name
@property @property
@ -76,41 +55,14 @@ class RPiGPIOSwitch(ToggleEntity):
""" True if device is on. """ """ True if device is on. """
return self._state return self._state
def turn_on(self, **kwargs): def turn_on(self):
""" Turn the device on. """ """ Turn the device on. """
if self._switch(self._active_state): rpi_gpio.write_output(self._port, 0 if self._invert_logic else 1)
self._state = True self._state = True
self.update_ha_state() self.update_ha_state()
def turn_off(self, **kwargs): def turn_off(self):
""" Turn the device off. """ """ Turn the device off. """
if self._switch(not self._active_state): rpi_gpio.write_output(self._port, 1 if self._invert_logic else 0)
self._state = False self._state = False
self.update_ha_state() self.update_ha_state()
def _switch(self, new_state):
""" Change the output value to Raspberry Pi GPIO port. """
_LOGGER.info('Setting GPIO %s to %s', self._gpio, new_state)
# pylint: disable=bare-except
try:
# pylint: disable=no-member
GPIO.output(self._gpio, 1 if new_state else 0)
except:
_LOGGER.error('GPIO "%s" output failed', self._gpio)
return False
return True
# pylint: disable=no-self-use
@property
def device_state_attributes(self):
""" Returns device specific state attributes. """
return None
@property
def state_attributes(self):
""" Returns optional state attributes. """
data = {}
device_attr = self.device_state_attributes
if device_attr is not None:
data.update(device_attr)
return data

View File

@ -21,7 +21,7 @@ from homeassistant.const import (
STATE_ON, STATE_ON,
STATE_OFF) STATE_OFF)
REQUIREMENTS = ['pyvera==0.2.3'] REQUIREMENTS = ['pyvera==0.2.6']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -91,14 +91,10 @@ class VeraSwitch(SwitchDevice):
self._state = STATE_OFF self._state = STATE_OFF
self.controller.register(vera_device, self._update_callback) self.controller.register(vera_device, self._update_callback)
self.update()
def _update_callback(self, _device): def _update_callback(self, _device):
""" Called by the vera device callback to update state. """ self.update_ha_state(True)
if self.vera_device.is_switched_on():
self._state = STATE_ON
else:
self._state = STATE_OFF
self.update_ha_state()
@property @property
def name(self): def name(self):
@ -113,19 +109,19 @@ class VeraSwitch(SwitchDevice):
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%' attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
if self.vera_device.is_armable: if self.vera_device.is_armable:
armed = self.vera_device.get_value('Armed') armed = self.vera_device.is_armed
attr[ATTR_ARMED] = 'True' if armed == '1' else 'False' attr[ATTR_ARMED] = 'True' if armed else 'False'
if self.vera_device.is_trippable: if self.vera_device.is_trippable:
last_tripped = self.vera_device.get_value('LastTrip') last_tripped = self.vera_device.last_trip
if last_tripped is not None: if last_tripped is not None:
utc_time = dt_util.utc_from_timestamp(int(last_tripped)) utc_time = dt_util.utc_from_timestamp(int(last_tripped))
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str( attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
utc_time) utc_time)
else: else:
attr[ATTR_LAST_TRIP_TIME] = None attr[ATTR_LAST_TRIP_TIME] = None
tripped = self.vera_device.get_value('Tripped') tripped = self.vera_device.is_tripped
attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False' attr[ATTR_TRIPPED] = 'True' if tripped else 'False'
attr['Vera Device Id'] = self.vera_device.vera_device_id attr['Vera Device Id'] = self.vera_device.vera_device_id
@ -150,3 +146,10 @@ class VeraSwitch(SwitchDevice):
def is_on(self): def is_on(self):
""" True if device is on. """ """ True if device is on. """
return self._state == STATE_ON return self._state == STATE_ON
def update(self):
""" Called by the vera device callback to update state. """
if self.vera_device.is_switched_on():
self._state = STATE_ON
else:
self._state = STATE_OFF

View File

@ -11,7 +11,7 @@ import logging
from homeassistant.components.wink import WinkToggleDevice from homeassistant.components.wink import WinkToggleDevice
from homeassistant.const import CONF_ACCESS_TOKEN from homeassistant.const import CONF_ACCESS_TOKEN
REQUIREMENTS = ['python-wink==0.3.1'] REQUIREMENTS = ['python-wink==0.4.1']
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
@ -30,3 +30,5 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
pywink.set_bearer_token(token) pywink.set_bearer_token(token)
add_devices(WinkToggleDevice(switch) for switch in pywink.get_switches()) add_devices(WinkToggleDevice(switch) for switch in pywink.get_switches())
add_devices(WinkToggleDevice(switch) for switch in
pywink.get_powerstrip_outlets())

View File

@ -0,0 +1,90 @@
"""
homeassistant.components.thermostat.proliphix
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Proliphix NT10e Thermostat is an ethernet connected thermostat.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/thermostat.proliphix/
"""
from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL,
STATE_IDLE, STATE_HEAT)
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD,
CONF_HOST, TEMP_FAHRENHEIT)
REQUIREMENTS = ['proliphix==0.1.0']
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Proliphix thermostats. """
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
host = config.get(CONF_HOST)
import proliphix
pdp = proliphix.PDP(host, username, password)
add_devices([
ProliphixThermostat(pdp)
])
class ProliphixThermostat(ThermostatDevice):
""" Represents a Proliphix thermostat. """
def __init__(self, pdp):
self._pdp = pdp
# initial data
self._pdp.update()
self._name = self._pdp.name
@property
def should_poll(self):
""" Polling needed for thermostat.. """
return True
def update(self):
""" Update the data from the thermostat. """
self._pdp.update()
@property
def name(self):
""" Returns the name of the thermostat. """
return self._name
@property
def device_state_attributes(self):
""" Returns device specific state attributes. """
return {
"fan": self._pdp.fan_state
}
@property
def unit_of_measurement(self):
""" Returns the unit of measurement. """
return TEMP_FAHRENHEIT
@property
def current_temperature(self):
""" Returns the current temperature. """
return self._pdp.cur_temp
@property
def target_temperature(self):
""" Returns the temperature we try to reach. """
return self._pdp.setback_heat
@property
def operation(self):
""" Returns the current state of the thermostat. """
state = self._pdp.hvac_state
if state in (1, 2):
return STATE_IDLE
elif state == 3:
return STATE_HEAT
elif state == 6:
return STATE_COOL
def set_temperature(self, temperature):
""" Set new target temperature. """
self._pdp.setback_heat = temperature

View File

@ -16,7 +16,7 @@ from homeassistant.const import (
ATTR_SERVICE, ATTR_DISCOVERED, ATTR_FRIENDLY_NAME) ATTR_SERVICE, ATTR_DISCOVERED, ATTR_FRIENDLY_NAME)
DOMAIN = "wink" DOMAIN = "wink"
REQUIREMENTS = ['python-wink==0.3.1'] REQUIREMENTS = ['python-wink==0.4.1']
DISCOVER_LIGHTS = "wink.lights" DISCOVER_LIGHTS = "wink.lights"
DISCOVER_SWITCHES = "wink.switches" DISCOVER_SWITCHES = "wink.switches"
@ -37,9 +37,10 @@ def setup(hass, config):
# Load components for the devices in the Wink that we support # Load components for the devices in the Wink that we support
for component_name, func_exists, discovery_type in ( for component_name, func_exists, discovery_type in (
('light', pywink.get_bulbs, DISCOVER_LIGHTS), ('light', pywink.get_bulbs, DISCOVER_LIGHTS),
('switch', pywink.get_switches, DISCOVER_SWITCHES), ('switch', lambda: pywink.get_switches or
('sensor', lambda: pywink.get_sensors or pywink.get_eggtrays, pywink.get_powerstrip_outlets, DISCOVER_SWITCHES),
DISCOVER_SENSORS), ('sensor', lambda: pywink.get_sensors or
pywink.get_eggtrays, DISCOVER_SENSORS),
('lock', pywink.get_locks, DISCOVER_LOCKS)): ('lock', pywink.get_locks, DISCOVER_LOCKS)):
if func_exists(): if func_exists():

View File

@ -62,14 +62,14 @@ tellcore-py==1.1.2
# homeassistant.components.light.vera # homeassistant.components.light.vera
# homeassistant.components.sensor.vera # homeassistant.components.sensor.vera
# homeassistant.components.switch.vera # homeassistant.components.switch.vera
pyvera==0.2.3 pyvera==0.2.6
# homeassistant.components.wink # homeassistant.components.wink
# homeassistant.components.light.wink # homeassistant.components.light.wink
# homeassistant.components.lock.wink # homeassistant.components.lock.wink
# homeassistant.components.sensor.wink # homeassistant.components.sensor.wink
# homeassistant.components.switch.wink # homeassistant.components.switch.wink
python-wink==0.3.1 python-wink==0.4.1
# homeassistant.components.media_player.cast # homeassistant.components.media_player.cast
pychromecast==0.6.14 pychromecast==0.6.14
@ -122,6 +122,9 @@ dnspython3==1.12.0
# homeassistant.components.rfxtrx # homeassistant.components.rfxtrx
https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip#RFXtrx==0.2 https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip#RFXtrx==0.2
# homeassistant.components.rpi_gpio
# RPi.GPIO==0.6.1
# homeassistant.components.sensor.bitcoin # homeassistant.components.sensor.bitcoin
blockchain==1.1.2 blockchain==1.1.2
@ -146,10 +149,6 @@ https://github.com/HydrelioxGitHub/netatmo-api-python/archive/43ff238a0122b0939a
# homeassistant.components.sensor.openweathermap # homeassistant.components.sensor.openweathermap
pyowm==2.3.0 pyowm==2.3.0
# homeassistant.components.sensor.rpi_gpio
# homeassistant.components.switch.rpi_gpio
# RPi.GPIO==0.5.11
# homeassistant.components.sensor.sabnzbd # homeassistant.components.sensor.sabnzbd
https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1 https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1
@ -196,6 +195,9 @@ evohomeclient==0.2.4
# homeassistant.components.thermostat.nest # homeassistant.components.thermostat.nest
python-nest==2.6.0 python-nest==2.6.0
# homeassistant.components.thermostat.proliphix
proliphix==0.1.0
# homeassistant.components.thermostat.radiotherm # homeassistant.components.thermostat.radiotherm
radiotherm==1.2 radiotherm==1.2

View File

@ -203,3 +203,21 @@ class TestLocative(unittest.TestCase):
state = hass.states.get('{}.{}'.format('device_tracker', data['device'])) state = hass.states.get('{}.{}'.format('device_tracker', data['device']))
self.assertEqual(state.state, 'work') self.assertEqual(state.state, 'work')
def test_exit_first(self, update_config):
""" Test when an exit message is sent first on a new device """
data = {
'latitude': 40.7855,
'longitude': -111.7367,
'device': 'new_device',
'id': 'Home',
'trigger': 'exit'
}
# Exit Home
req = requests.get(_url(data))
self.assertEqual(200, req.status_code)
state = hass.states.get('{}.{}'.format('device_tracker', data['device']))
self.assertEqual(state.state, 'not_home')