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

pull/616/head
Daren Lord 2015-11-21 15:26:44 -07:00
commit 396a65ab03
60 changed files with 1414 additions and 383 deletions

View File

@ -50,6 +50,7 @@ omit =
homeassistant/components/downloader.py
homeassistant/components/keyboard.py
homeassistant/components/light/hue.py
homeassistant/components/light/mqtt.py
homeassistant/components/light/limitlessled.py
homeassistant/components/light/blinksticklight.py
homeassistant/components/light/hyperion.py
@ -83,6 +84,7 @@ omit =
homeassistant/components/sensor/glances.py
homeassistant/components/sensor/mysensors.py
homeassistant/components/sensor/openweathermap.py
homeassistant/components/switch/orvibo.py
homeassistant/components/sensor/rest.py
homeassistant/components/sensor/rpi_gpio.py
homeassistant/components/sensor/sabnzbd.py

View File

@ -1,4 +1,4 @@
include README.md
include README.rst
include LICENSE
graft homeassistant
prune homeassistant/components/frontend/www_static/home-assistant-polymer

View File

@ -1,38 +0,0 @@
# Home Assistant [![Build Status](https://travis-ci.org/balloob/home-assistant.svg?branch=master)](https://travis-ci.org/balloob/home-assistant) [![Coverage Status](https://img.shields.io/coveralls/balloob/home-assistant.svg)](https://coveralls.io/r/balloob/home-assistant?branch=master) [![Join the chat at https://gitter.im/balloob/home-assistant](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/balloob/home-assistant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[demo]: https://home-assistant.io/demo/
Home Assistant is a home automation platform running on Python 3. The goal of Home Assistant is to be able to track and control all devices at home and offer a platform for automating control.
To get started:
```bash
python3 -m pip install homeassistant
hass --open-ui
```
Check out [the website](https://home-assistant.io) for [a demo][demo], installation instructions, tutorials and documentation.
[![screenshot-states](https://raw.github.com/balloob/home-assistant/master/docs/screenshots.png)][demo]
Examples of devices it can interface it:
* Monitoring connected devices to a wireless router: [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), [DD-WRT](http://www.dd-wrt.com/site/index), [TPLink](http://www.tp-link.us/), [ASUSWRT](http://event.asus.com/2013/nw/ASUSWRT/) and any SNMP capable Linksys WAP/WRT
* [Philips Hue](http://meethue.com) lights, [WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) switches, [Edimax](http://www.edimax.com/) switches, [Efergy](https://efergy.com) energy monitoring, and [Tellstick](http://www.telldus.se/products/tellstick) devices and sensors
* [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast), [Music Player Daemon](http://www.musicpd.org/), [Logitech Squeezebox](https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29), [Plex](https://plex.tv/), [Kodi (XBMC)](http://kodi.tv/), iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api)), and Amazon Fire TV (by way of [python-firetv](https://github.com/happyleavesaoc/python-firetv))
* Support for [ISY994](https://www.universal-devices.com/residential/isy994i-series/) (Insteon and X10 devices), [Z-Wave](http://www.z-wave.com/), [Nest Thermostats](https://nest.com/), [RFXtrx](http://www.rfxcom.com/), [Arduino](https://www.arduino.cc/), [Raspberry Pi](https://www.raspberrypi.org/), and [Modbus](http://www.modbus.org/)
* Interaction with [IFTTT](https://ifttt.com/)
* Integrate data from the [Bitcoin](https://bitcoin.org) network, meteorological data from [OpenWeatherMap](http://openweathermap.org/) and [Forecast.io](https://forecast.io/), [Transmission](http://www.transmissionbt.com/), or [SABnzbd](http://sabnzbd.org).
* [See full list of supported devices](https://home-assistant.io/components/)
Built home automation on top of your devices:
* Keep a precise history of every change to the state of your house
* Turn on the lights when people get home after sun set
* Turn on lights slowly during sun set to compensate for less light
* Turn off all lights and devices when everybody leaves the house
* Offers a [REST API](https://home-assistant.io/developers/api.html) and can interface with MQTT for easy integration with other projects like [OwnTracks](http://owntracks.org/)
* Allow sending notifications using [Instapush](https://instapush.im), [Notify My Android (NMA)](http://www.notifymyandroid.com/), [PushBullet](https://www.pushbullet.com/), [PushOver](https://pushover.net/), [Slack](https://slack.com/), [Telegram](https://telegram.org/), and [Jabber (XMPP)](http://xmpp.org)
The system is built modular so support for other devices or actions can be implemented easily. See also the [section on architecture](https://home-assistant.io/developers/architecture.html) and the [section on creating your own components](https://home-assistant.io/developers/creating_components.html).
If you run into issues while using Home Assistant or during development of a component, check the [Home Assistant help section](https://home-assistant.io/help/) how to reach us.

98
README.rst Normal file
View File

@ -0,0 +1,98 @@
Home Assistant |Build Status| |Coverage Status| |Join the chat at https://gitter.im/balloob/home-assistant|
===========================================================================================================
Home Assistant is a home automation platform running on Python 3. The
goal of Home Assistant is to be able to track and control all devices at
home and offer a platform for automating control.
To get started:
.. code:: bash
python3 -m pip install homeassistant
hass --open-ui
Check out `the website <https://home-assistant.io>`__ for `a
demo <https://home-assistant.io/demo/>`__, installation instructions,
tutorials and documentation.
|screenshot-states|
Examples of devices it can interface it:
- Monitoring connected devices to a wireless router:
`OpenWrt <https://openwrt.org/>`__,
`Tomato <http://www.polarcloud.com/tomato>`__,
`Netgear <http://netgear.com>`__,
`DD-WRT <http://www.dd-wrt.com/site/index>`__,
`TPLink <http://www.tp-link.us/>`__,
`ASUSWRT <http://event.asus.com/2013/nw/ASUSWRT/>`__ and any SNMP
capable Linksys WAP/WRT
- `Philips Hue <http://meethue.com>`__ lights,
`WeMo <http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/>`__
switches, `Edimax <http://www.edimax.com/>`__ switches,
`Efergy <https://efergy.com>`__ energy monitoring, and
`Tellstick <http://www.telldus.se/products/tellstick>`__ devices and
sensors
- `Google
Chromecasts <http://www.google.com/intl/en/chrome/devices/chromecast>`__,
`Music Player Daemon <http://www.musicpd.org/>`__, `Logitech
Squeezebox <https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29>`__,
`Plex <https://plex.tv/>`__, `Kodi (XBMC) <http://kodi.tv/>`__,
iTunes (by way of
`itunes-api <https://github.com/maddox/itunes-api>`__), and Amazon
Fire TV (by way of
`python-firetv <https://github.com/happyleavesaoc/python-firetv>`__)
- Support for
`ISY994 <https://www.universal-devices.com/residential/isy994i-series/>`__
(Insteon and X10 devices), `Z-Wave <http://www.z-wave.com/>`__, `Nest
Thermostats <https://nest.com/>`__,
`RFXtrx <http://www.rfxcom.com/>`__,
`Arduino <https://www.arduino.cc/>`__, `Raspberry
Pi <https://www.raspberrypi.org/>`__, and
`Modbus <http://www.modbus.org/>`__
- Interaction with `IFTTT <https://ifttt.com/>`__
- Integrate data from the `Bitcoin <https://bitcoin.org>`__ network,
meteorological data from
`OpenWeatherMap <http://openweathermap.org/>`__ and
`Forecast.io <https://forecast.io/>`__,
`Transmission <http://www.transmissionbt.com/>`__, or
`SABnzbd <http://sabnzbd.org>`__.
- `See full list of supported
devices <https://home-assistant.io/components/>`__
Built home automation on top of your devices:
- Keep a precise history of every change to the state of your house
- Turn on the lights when people get home after sun set
- Turn on lights slowly during sun set to compensate for less light
- Turn off all lights and devices when everybody leaves the house
- Offers a `REST API <https://home-assistant.io/developers/api/>`__
and can interface with MQTT for easy integration with other projects
like `OwnTracks <http://owntracks.org/>`__
- Allow sending notifications using
`Instapush <https://instapush.im>`__, `Notify My Android
(NMA) <http://www.notifymyandroid.com/>`__,
`PushBullet <https://www.pushbullet.com/>`__,
`PushOver <https://pushover.net/>`__, `Slack <https://slack.com/>`__,
`Telegram <https://telegram.org/>`__, and `Jabber
(XMPP) <http://xmpp.org>`__
The system is built modular so support for other devices or actions can
be implemented easily. See also the `section on
architecture <https://home-assistant.io/developers/architecture.html>`__
and the `section on creating your own
components <https://home-assistant.io/developers/creating_components.html>`__.
If you run into issues while using Home Assistant or during development
of a component, check the `Home Assistant help
section <https://home-assistant.io/help/>`__ how to reach us.
.. |Build Status| image:: https://travis-ci.org/balloob/home-assistant.svg?branch=master
:target: https://travis-ci.org/balloob/home-assistant
.. |Coverage Status| image:: https://img.shields.io/coveralls/balloob/home-assistant.svg
:target: https://coveralls.io/r/balloob/home-assistant?branch=master
.. |Join the chat at https://gitter.im/balloob/home-assistant| image:: https://badges.gitter.im/Join%20Chat.svg
:target: https://gitter.im/balloob/home-assistant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
.. |screenshot-states| image:: https://raw.github.com/balloob/home-assistant/master/docs/screenshots.png
:target: https://home-assistant.io/demo/

View File

@ -9,11 +9,12 @@ After bootstrapping you can add your own components or
start by calling homeassistant.start_home_assistant(bus)
"""
import os
import sys
from collections import defaultdict
import logging
import logging.handlers
from collections import defaultdict
import os
import shutil
import sys
import homeassistant.core as core
import homeassistant.util.dt as date_util
@ -25,7 +26,7 @@ import homeassistant.components as core_components
import homeassistant.components.group as group
from homeassistant.helpers.entity import Entity
from homeassistant.const import (
EVENT_COMPONENT_LOADED, CONF_LATITUDE, CONF_LONGITUDE,
__version__, EVENT_COMPONENT_LOADED, CONF_LATITUDE, CONF_LONGITUDE,
CONF_TEMPERATURE_UNIT, CONF_NAME, CONF_TIME_ZONE, CONF_CUSTOMIZE,
TEMP_CELCIUS, TEMP_FAHRENHEIT)
@ -168,6 +169,7 @@ def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
hass.config.config_dir = config_dir
mount_local_lib_path(config_dir)
process_ha_config_upgrade(hass)
process_ha_core_config(hass, config.get(core.DOMAIN, {}))
if enable_log:
@ -281,6 +283,31 @@ def enable_logging(hass, verbose=False, daemon=False, log_rotate_days=None):
'Unable to setup error log %s (access denied)', err_log_path)
def process_ha_config_upgrade(hass):
""" Upgrade config if necessary. """
version_path = hass.config.path('.HA_VERSION')
try:
with open(version_path, 'rt') as inp:
conf_version = inp.readline().strip()
except FileNotFoundError:
# Last version to not have this file
conf_version = '0.7.7'
if conf_version == __version__:
return
_LOGGER.info('Upgrading config directory from %s to %s', conf_version,
__version__)
lib_path = hass.config.path('lib')
if os.path.isdir(lib_path):
shutil.rmtree(lib_path)
with open(version_path, 'wt') as outp:
outp.write(__version__)
def process_ha_core_config(hass, config):
""" Processes the [homeassistant] section from the config. """
hac = hass.config

View File

@ -0,0 +1,50 @@
"""
homeassistant.components.binary_sensor
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with binary sensors (sensors which only know two states)
that can be monitored.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/binary_sensor/
"""
import logging
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity import Entity
from homeassistant.const import (STATE_ON, STATE_OFF)
DOMAIN = 'binary_sensor'
DEPENDENCIES = []
SCAN_INTERVAL = 30
ENTITY_ID_FORMAT = DOMAIN + '.{}'
def setup(hass, config):
""" Track states and offer events for binary sensors. """
component = EntityComponent(
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)
component.setup(config)
return True
# pylint: disable=no-self-use
class BinarySensorDevice(Entity):
""" Represents a binary sensor. """
@property
def is_on(self):
""" True if the binary sensor is on. """
return None
@property
def state(self):
""" Returns the state of the binary sensor. """
return STATE_ON if self.is_on else STATE_OFF
@property
def friendly_state(self):
""" Returns the friendly state of the binary sensor. """
return None

View File

@ -0,0 +1,43 @@
"""
homeassistant.components.binary_sensor.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform that has two fake binary sensors.
"""
from homeassistant.components.binary_sensor import BinarySensorDevice
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Demo binary sensors. """
add_devices([
DemoBinarySensor('Window Bathroom', True, None),
DemoBinarySensor('Floor Basement', False, None),
])
class DemoBinarySensor(BinarySensorDevice):
""" A Demo binary sensor. """
def __init__(self, name, state, icon=None):
self._name = name
self._state = state
self._icon = icon
@property
def should_poll(self):
""" No polling needed for a demo binary sensor. """
return False
@property
def name(self):
""" Returns the name of the binary sensor. """
return self._name
@property
def icon(self):
""" Returns the icon to use for device if any. """
return self._icon
@property
def is_on(self):
""" True if the binary sensor is on. """
return self._state

View File

@ -58,7 +58,7 @@ MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n'
# pylint: disable=too-many-branches
def setup(hass, config):
""" Track states and offer events for sensors. """
""" Track states and offer events for cameras. """
component = EntityComponent(
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
@ -87,7 +87,10 @@ def setup(hass, config):
if camera:
response = camera.camera_image()
handler.wfile.write(response)
if response is not None:
handler.wfile.write(response)
else:
handler.send_response(HTTP_NOT_FOUND)
else:
handler.send_response(HTTP_NOT_FOUND)
@ -98,7 +101,8 @@ def setup(hass, config):
# pylint: disable=unused-argument
def _proxy_camera_mjpeg_stream(handler, path_match, data):
""" Proxies the camera image as an mjpeg stream via the HA server.
"""
Proxies the camera image as an mjpeg stream via the HA server.
This function takes still images from the IP camera and turns them
into an MJPEG stream. This means that HA can return a live video
stream even with only a still image URL available.
@ -129,7 +133,8 @@ def setup(hass, config):
while True:
img_bytes = camera.camera_image()
if img_bytes is None:
continue
headers_str = '\r\n'.join((
'Content-length: {}'.format(len(img_bytes)),
'Content-type: image/jpeg',
@ -159,7 +164,7 @@ def setup(hass, config):
class Camera(Entity):
""" The base class for camera components """
""" The base class for camera components. """
def __init__(self):
self.is_streaming = False
@ -167,23 +172,23 @@ class Camera(Entity):
@property
# pylint: disable=no-self-use
def is_recording(self):
""" Returns true if the device is recording """
""" Returns true if the device is recording. """
return False
@property
# pylint: disable=no-self-use
def brand(self):
""" Should return a string of the camera brand """
""" Should return a string of the camera brand. """
return None
@property
# pylint: disable=no-self-use
def model(self):
""" Returns string of camera model """
""" Returns string of camera model. """
return None
def camera_image(self):
""" Return bytes of camera image """
""" Return bytes of camera image. """
raise NotImplementedError()
@property

View File

@ -0,0 +1,37 @@
"""
homeassistant.components.camera.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform that has a fake camera.
"""
import os
from random import randint
from homeassistant.components.camera import Camera
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Demo camera. """
add_devices([
DemoCamera('Demo camera')
])
class DemoCamera(Camera):
""" A Demo camera. """
def __init__(self, name):
super().__init__()
self._name = name
def camera_image(self):
""" Return a faked still image response. """
image_path = os.path.join(os.path.dirname(__file__),
'demo_{}.png'.format(randint(1, 5)))
with open(image_path, 'rb') as file:
output = file.read()
return output
@property
def name(self):
""" Return the name of this device. """
return self._name

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -40,13 +40,21 @@ class GenericCamera(Camera):
self._still_image_url = device_info['still_image_url']
def camera_image(self):
""" Return a still image reponse from the camera. """
""" Return a still image response from the camera. """
if self._username and self._password:
response = requests.get(
self._still_image_url,
auth=HTTPBasicAuth(self._username, self._password))
try:
response = requests.get(
self._still_image_url,
auth=HTTPBasicAuth(self._username, self._password))
except requests.exceptions.RequestException as error:
_LOGGER.error('Error getting camera image: %s', error)
return None
else:
response = requests.get(self._still_image_url)
try:
response = requests.get(self._still_image_url)
except requests.exceptions.RequestException as error:
_LOGGER.error('Error getting camera image: %s', error)
return None
return response.content

View File

@ -18,7 +18,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone']
COMPONENTS_WITH_DEMO_PLATFORM = [
'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor',
'thermostat']
'thermostat', 'camera', 'binary_sensor']
def setup(hass, config):

View File

@ -134,13 +134,16 @@ class AsusWrtDeviceScanner(object):
for lease in leases_result:
match = _LEASES_REGEX.search(lease.decode('utf-8'))
if not match:
_LOGGER.warning("Could not parse lease row: %s", lease)
continue
# For leases where the client doesn't set a hostname, ensure
# it is blank and not '*', which breaks the entity_id down
# the line
if match:
host = match.group('host')
if host == '*':
host = ''
host = match.group('host')
if host == '*':
host = ''
devices[match.group('ip')] = {
'host': host,
@ -151,6 +154,9 @@ class AsusWrtDeviceScanner(object):
for neighbor in neighbors:
match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8'))
if match and match.group('ip') in devices:
if not match:
_LOGGER.warning("Could not parse neighbor row: %s", neighbor)
continue
if match.group('ip') in devices:
devices[match.group('ip')]['status'] = match.group('status')
return devices

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "75532015507fd544f46081ec0eeb5004"
VERSION = "dff74f773ea8b0356b0bd8130ed6f0cf"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit 8e33f925e171fd279adf0338f5440c1d7160311d
Subproject commit 39e09d85b74afb332ad2872b5aa556c9c9d113c3

File diff suppressed because one or more lines are too long

View File

@ -8,9 +8,7 @@ https://home-assistant.io/components/light.blinksticklight/
"""
import logging
from blinkstick import blinkstick
from homeassistant.components.light import (Light, ATTR_RGB_COLOR)
from homeassistant.components.light import Light, ATTR_RGB_COLOR
_LOGGER = logging.getLogger(__name__)
@ -22,6 +20,8 @@ DEPENDENCIES = []
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Add device specified by serial number. """
from blinkstick import blinkstick
stick = blinkstick.find_by_serial(config['serial'])
add_devices_callback([BlinkStickLight(stick, config['name'])])

View File

@ -0,0 +1,184 @@
"""
homeassistant.components.light.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a MQTT light.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.mqtt/
"""
import logging
import homeassistant.util.color as color_util
import homeassistant.components.mqtt as mqtt
from homeassistant.components.light import (Light,
ATTR_BRIGHTNESS, ATTR_RGB_COLOR)
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "MQTT Light"
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_ON = "on"
DEFAULT_PAYLOAD_OFF = "off"
DEFAULT_RGB_PATTERN = "%d,%d,%d"
DEFAULT_OPTIMISTIC = False
DEPENDENCIES = ['mqtt']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Add MQTT Light. """
if config.get('command_topic') is None:
_LOGGER.error("Missing required variable: command_topic")
return False
add_devices_callback([MqttLight(
hass,
config.get('name', DEFAULT_NAME),
{"state_topic": config.get('state_topic'),
"command_topic": config.get('command_topic'),
"brightness_state_topic": config.get('brightness_state_topic'),
"brightness_command_topic":
config.get('brightness_command_topic'),
"rgb_state_topic": config.get('rgb_state_topic'),
"rgb_command_topic": config.get('rgb_command_topic')},
config.get('rgb', None),
config.get('qos', DEFAULT_QOS),
{"on": config.get('payload_on', DEFAULT_PAYLOAD_ON),
"off": config.get('payload_off', DEFAULT_PAYLOAD_OFF)},
config.get('brightness'),
config.get('optimistic', DEFAULT_OPTIMISTIC))])
# pylint: disable=too-many-instance-attributes
class MqttLight(Light):
""" Provides a MQTT light. """
# pylint: disable=too-many-arguments
def __init__(self, hass, name,
topic,
rgb, qos,
payload,
brightness, optimistic):
self._hass = hass
self._name = name
self._topic = topic
self._rgb = rgb
self._qos = qos
self._payload = payload
self._brightness = brightness
self._optimistic = optimistic
self._state = False
self._xy = None
def message_received(topic, payload, qos):
""" A new MQTT message has been received. """
if payload == self._payload["on"]:
self._state = True
elif payload == self._payload["off"]:
self._state = False
self.update_ha_state()
if self._topic["state_topic"] is None:
# force optimistic mode
self._optimistic = True
else:
# Subscribe the state_topic
mqtt.subscribe(self._hass, self._topic["state_topic"],
message_received, self._qos)
def brightness_received(topic, payload, qos):
""" A new MQTT message for the brightness has been received. """
self._brightness = int(payload)
self.update_ha_state()
def rgb_received(topic, payload, qos):
""" A new MQTT message has been received. """
self._rgb = [int(val) for val in payload.split(',')]
self._xy = color_util.color_RGB_to_xy(int(self._rgb[0]),
int(self._rgb[1]),
int(self._rgb[2]))
self.update_ha_state()
if self._topic["brightness_state_topic"] is not None:
mqtt.subscribe(self._hass, self._topic["brightness_state_topic"],
brightness_received, self._qos)
self._brightness = 255
else:
self._brightness = None
if self._topic["rgb_state_topic"] is not None:
mqtt.subscribe(self._hass, self._topic["rgb_state_topic"],
rgb_received, self._qos)
self._xy = [0, 0]
else:
self._xy = None
@property
def brightness(self):
""" Brightness of this light between 0..255. """
return self._brightness
@property
def rgb_color(self):
""" RGB color value. """
return self._rgb
@property
def color_xy(self):
""" RGB color value. """
return self._xy
@property
def should_poll(self):
""" No polling needed for a MQTT light. """
return False
@property
def name(self):
""" Returns the name of the device if any. """
return self._name
@property
def is_on(self):
""" True if device is on. """
return self._state
def turn_on(self, **kwargs):
""" Turn the device on. """
if ATTR_RGB_COLOR in kwargs and \
self._topic["rgb_command_topic"] is not None:
self._rgb = kwargs[ATTR_RGB_COLOR]
rgb = DEFAULT_RGB_PATTERN % tuple(self._rgb)
mqtt.publish(self._hass, self._topic["rgb_command_topic"],
rgb, self._qos)
if ATTR_BRIGHTNESS in kwargs and \
self._topic["brightness_command_topic"] is not None:
self._brightness = kwargs[ATTR_BRIGHTNESS]
mqtt.publish(self._hass, self._topic["brightness_command_topic"],
self._brightness, self._qos)
mqtt.publish(self._hass, self._topic["command_topic"],
self._payload["on"], self._qos)
if self._optimistic:
# optimistically assume that switch has changed state
self._state = True
self.update_ha_state()
def turn_off(self, **kwargs):
""" Turn the device off. """
mqtt.publish(self._hass, self._topic["command_topic"],
self._payload["off"], self._qos)
if self._optimistic:
# optimistically assume that switch has changed state
self._state = False
self.update_ha_state()

View File

@ -8,7 +8,6 @@ https://home-assistant.io/components/light.rfxtrx/
"""
import logging
import homeassistant.components.rfxtrx as rfxtrx
import RFXtrx as rfxtrxmod
from homeassistant.components.light import Light
from homeassistant.util import slugify
@ -20,6 +19,8 @@ _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Setup the RFXtrx platform. """
import RFXtrx as rfxtrxmod
lights = []
devices = config.get('devices', None)
if devices:

View File

@ -6,13 +6,9 @@ Support for Tellstick lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.tellstick/
"""
import logging
# pylint: disable=no-name-in-module, import-error
from homeassistant.components.light import Light, ATTR_BRIGHTNESS
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP,
ATTR_FRIENDLY_NAME)
import tellcore.constants as tellcore_constants
from tellcore.library import DirectCallbackDispatcher
REQUIREMENTS = ['tellcore-py==1.1.2']
@ -20,12 +16,9 @@ REQUIREMENTS = ['tellcore-py==1.1.2']
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return Tellstick lights. """
try:
import tellcore.telldus as telldus
except ImportError:
logging.getLogger(__name__).exception(
"Failed to import tellcore")
return []
import tellcore.telldus as telldus
from tellcore.library import DirectCallbackDispatcher
import tellcore.constants as tellcore_constants
core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher())
@ -58,17 +51,20 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
class TellstickLight(Light):
""" Represents a Tellstick light. """
last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
tellcore_constants.TELLSTICK_TURNOFF |
tellcore_constants.TELLSTICK_DIM |
tellcore_constants.TELLSTICK_UP |
tellcore_constants.TELLSTICK_DOWN)
def __init__(self, tellstick_device):
import tellcore.constants as tellcore_constants
self.tellstick_device = tellstick_device
self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name}
self._brightness = 0
self.last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
tellcore_constants.TELLSTICK_TURNOFF |
tellcore_constants.TELLSTICK_DIM |
tellcore_constants.TELLSTICK_UP |
tellcore_constants.TELLSTICK_DOWN)
@property
def name(self):
""" Returns the name of the switch if any. """
@ -104,6 +100,8 @@ class TellstickLight(Light):
def update(self):
""" Update state of the light. """
import tellcore.constants as tellcore_constants
last_command = self.tellstick_device.last_sent_command(
self.last_sent_command_mask)

View File

@ -1,12 +1,12 @@
"""
homeassistant.components.light.zwave
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Z-Wave lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.zwave/
"""
# pylint: disable=import-error
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
import homeassistant.components.zwave as zwave
from homeassistant.const import STATE_ON, STATE_OFF
@ -15,7 +15,7 @@ from threading import Timer
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Find and add zwave lights. """
""" Find and add Z-Wave lights. """
if discovery_info is None:
return
@ -34,8 +34,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
def brightness_state(value):
""" Returns the brightness and state according to the current
data of given value. """
"""
Returns the brightness and state according to the current data of given
value.
"""
if value.data > 0:
return (value.data / 99) * 255, STATE_ON
else:
@ -43,9 +45,12 @@ def brightness_state(value):
class ZwaveDimmer(Light):
""" Provides a zwave dimmer. """
""" Provides a Z-Wave dimmer. """
# pylint: disable=too-many-arguments
def __init__(self, value):
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
self._value = value
self._node = value.node

View File

@ -1,30 +1,10 @@
"""
homeassistant.components.logger
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component that will help guide the user taking its first steps.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component that will help set the level of logging for components.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/logger/
Sample configuration
# By default log all messages and ignore log event lowest than critical
# for custom omponents
logger:
default: info
logs:
homeassistant.components.device_tracker: critical
homeassistant.components.camera: critical
# By default ignore all messages lowest than critical and log event
# for custom components
logger:
default: critical
logs:
homeassistant.components: info
homeassistant.components.rfxtrx: debug
homeassistant.components.device_tracker: critical
homeassistant.components.camera: critical
"""
import logging
from collections import OrderedDict
@ -48,7 +28,7 @@ LOGGER_LOGS = 'logs'
class HomeAssistantLogFilter(logging.Filter):
"""A Home Assistant log filter"""
""" A log filter. """
# pylint: disable=no-init,too-few-public-methods
def __init__(self, logfilter):
@ -58,7 +38,7 @@ class HomeAssistantLogFilter(logging.Filter):
def filter(self, record):
# Log with filterd severity
# Log with filtered severity
if LOGGER_LOGS in self.logfilter:
for filtername in self.logfilter[LOGGER_LOGS]:
logseverity = self.logfilter[LOGGER_LOGS][filtername]
@ -82,7 +62,7 @@ def setup(hass, config=None):
config.get(DOMAIN)[LOGGER_DEFAULT].upper()
]
# Compute logseverity for components
# Compute log severity for components
if LOGGER_LOGS in config.get(DOMAIN):
for key, value in config.get(DOMAIN)[LOGGER_LOGS].items():
config.get(DOMAIN)[LOGGER_LOGS][key] = LOGSEVERITY[value.upper()]

View File

@ -173,7 +173,7 @@ class SqueezeBoxDevice(MediaPlayerDevice):
def volume_level(self):
""" Volume level of the media player (0..1). """
if 'mixer volume' in self._status:
return int(self._status['mixer volume']) / 100.0
return int(float(self._status['mixer volume'])) / 100.0
@property
def is_volume_muted(self):

View File

@ -10,8 +10,8 @@ from functools import partial
import logging
import os
import homeassistant.bootstrap as bootstrap
from homeassistant.config import load_yaml_config_file
from homeassistant.loader import get_component
from homeassistant.helpers import config_per_platform
from homeassistant.const import CONF_NAME
@ -23,6 +23,9 @@ DEPENDENCIES = []
ATTR_TITLE = "title"
ATTR_TITLE_DEFAULT = "Home Assistant"
# Target of the notification (user, device, etc)
ATTR_TARGET = 'target'
# Text to notify user of
ATTR_MESSAGE = "message"
@ -45,8 +48,8 @@ def setup(hass, config):
for platform, p_config in config_per_platform(config, DOMAIN, _LOGGER):
# get platform
notify_implementation = get_component(
'notify.{}'.format(platform))
notify_implementation = bootstrap.prepare_setup_platform(
hass, config, DOMAIN, platform)
if notify_implementation is None:
_LOGGER.error("Unknown notification service specified.")
@ -69,8 +72,9 @@ def setup(hass, config):
return
title = call.data.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
target = call.data.get(ATTR_TARGET)
notify_service.send_message(message, title=title)
notify_service.send_message(message, title=title, target=target)
# register service
service_call_handler = partial(notify_message, notify_service)

View File

@ -8,15 +8,18 @@ https://home-assistant.io/components/notify.pushbullet/
"""
import logging
from homeassistant.components.notify import ATTR_TITLE, BaseNotificationService
from homeassistant.components.notify import (
ATTR_TITLE, ATTR_TARGET, BaseNotificationService)
from homeassistant.const import CONF_API_KEY
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pushbullet.py==0.8.1']
REQUIREMENTS = ['pushbullet.py==0.9.0']
# pylint: disable=unused-argument
def get_service(hass, config):
""" Get the PushBullet notification service. """
from pushbullet import PushBullet
from pushbullet import InvalidKeyError
if CONF_API_KEY not in config:
@ -24,27 +27,99 @@ def get_service(hass, config):
return None
try:
return PushBulletNotificationService(config[CONF_API_KEY])
pushbullet = PushBullet(config[CONF_API_KEY])
except InvalidKeyError:
_LOGGER.error(
"Wrong API key supplied. "
"Get it at https://www.pushbullet.com/account")
return None
return PushBulletNotificationService(pushbullet)
# pylint: disable=too-few-public-methods
class PushBulletNotificationService(BaseNotificationService):
""" Implements notification service for Pushbullet. """
def __init__(self, api_key):
from pushbullet import Pushbullet
def __init__(self, pb):
self.pushbullet = pb
self.pbtargets = {}
self.refresh()
self.pushbullet = Pushbullet(api_key)
def refresh(self):
'''
Refresh devices, contacts, etc
def send_message(self, message="", **kwargs):
""" Send a message to a user. """
pbtargets stores all targets available from this pushbullet instance
into a dict. These are PB objects!. It sacrifices a bit of memory
for faster processing at send_message
As of sept 2015, contacts were replaced by chats. This is not
implemented in the module yet
'''
self.pushbullet.refresh()
self.pbtargets = {
'device': {
tgt.nickname.lower(): tgt for tgt in self.pushbullet.devices},
'channel': {
tgt.channel_tag.lower(): tgt for
tgt in self.pushbullet.channels},
}
def send_message(self, message=None, **kwargs):
"""
Send a message to a specified target.
If no target specified, a 'normal' push will be sent to all devices
linked to the PB account.
Email is special, these are assumed to always exist. We use a special
call which doesn't require a push object
"""
targets = kwargs.get(ATTR_TARGET)
title = kwargs.get(ATTR_TITLE)
refreshed = False
self.pushbullet.push_note(title, message)
if not targets:
# Backward compatebility, notify all devices in own account
self.pushbullet.push_note(title, message)
_LOGGER.info('Sent notification to self')
return
# Make list if not so
if not isinstance(targets, list):
targets = [targets]
# Main loop, Process all targets specified
for target in targets:
try:
ttype, tname = target.split('/', 1)
except ValueError:
_LOGGER.error('Invalid target syntax: %s', target)
continue
# Target is email, send directly, don't use a target object
# This also seems works to send to all devices in own account
if ttype == 'email':
self.pushbullet.push_note(title, message, email=tname)
_LOGGER.info('Sent notification to self')
continue
# Refresh if name not found. While awaiting periodic refresh
# solution in component, poor mans refresh ;)
if ttype not in self.pbtargets:
_LOGGER.error('Invalid target syntax: %s', target)
continue
if tname.lower() not in self.pbtargets[ttype] and not refreshed:
self.refresh()
refreshed = True
# Attempt push_note on a dict value. Keys are types & target
# name. Dict pbtargets has all *actual* targets.
try:
self.pbtargets[ttype][tname.lower()].push_note(title, message)
except KeyError:
_LOGGER.error('No such target: %s/%s', ttype, tname)
continue
except self.pushbullet.errors.PushError:
_LOGGER.error('Notify failed to: %s/%s', ttype, tname)
continue
_LOGGER.info('Sent notification to %s/%s', ttype, tname)

View File

@ -9,3 +9,7 @@ notify:
title:
description: Optional title for your notification.
example: 'Your Garage Door Friend'
target:
description: Target of the notification. Optional depending on the platform
example: platform specific

View File

@ -37,6 +37,7 @@ CONF_EVENT_DATA = "event_data"
CONF_DELAY = "delay"
ATTR_LAST_ACTION = 'last_action'
ATTR_CAN_CANCEL = 'can_cancel'
_LOGGER = logging.getLogger(__name__)
@ -113,6 +114,8 @@ class Script(ToggleEntity):
self._cur = -1
self._last_action = None
self._listener = None
self._can_cancel = not any(CONF_DELAY in action for action
in self.sequence)
@property
def should_poll(self):
@ -126,7 +129,9 @@ class Script(ToggleEntity):
@property
def state_attributes(self):
""" Returns the state attributes. """
attrs = {}
attrs = {
ATTR_CAN_CANCEL: self._can_cancel
}
if self._last_action:
attrs[ATTR_LAST_ACTION] = self._last_action

View File

@ -12,11 +12,14 @@ from datetime import timedelta
from homeassistant.util import Throttle
from homeassistant.helpers.entity import Entity
from homeassistant.const import STATE_UNKNOWN
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Glances Sensor'
_RESOURCE = '/api/2/all'
CONF_HOST = 'host'
CONF_PORT = '61208'
CONF_RESOURCES = 'resources'
SENSOR_TYPES = {
'disk_use_percent': ['Disk Use', '%'],
'disk_use': ['Disk Use', 'GiB'],
@ -43,13 +46,15 @@ MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Setup the Glances sensor. """
if not config.get('host'):
_LOGGER.error('"host:" is missing your configuration')
return False
host = config.get('host')
port = config.get('port', 61208)
host = config.get(CONF_HOST)
port = config.get('port', CONF_PORT)
url = 'http://{}:{}{}'.format(host, port, _RESOURCE)
var_conf = config.get(CONF_RESOURCES)
if None in (host, var_conf):
_LOGGER.error('Not all required config keys present: %s',
', '.join((CONF_HOST, CONF_RESOURCES)))
return False
try:
response = requests.get(url, timeout=10)
@ -57,18 +62,19 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.error('Response status is "%s"', response.status_code)
return False
except requests.exceptions.MissingSchema:
_LOGGER.error('Missing resource or schema in configuration. '
'Please heck our details in the configuration file.')
_LOGGER.error("Missing resource or schema in configuration. "
"Please check the details in the configuration file.")
return False
except requests.exceptions.ConnectionError:
_LOGGER.error('No route to resource/endpoint. '
'Please check the details in the configuration file.')
_LOGGER.error("No route to resource/endpoint: '%s'. "
"Please check the details in the configuration file.",
url)
return False
rest = GlancesData(url)
dev = []
for resource in config['resources']:
for resource in var_conf:
if resource not in SENSOR_TYPES:
_LOGGER.error('Sensor type: "%s" does not exist', resource)
else:
@ -78,13 +84,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class GlancesSensor(Entity):
""" Implements a REST sensor. """
""" Implements a Glances sensor. """
def __init__(self, rest, sensor_type):
self.rest = rest
self._name = SENSOR_TYPES[sensor_type][0]
self.type = sensor_type
self._state = None
self._state = STATE_UNKNOWN
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
self.update()
@ -98,46 +104,49 @@ class GlancesSensor(Entity):
""" Unit the value is expressed in. """
return self._unit_of_measurement
# pylint: disable=too-many-branches, too-many-return-statements
@property
def state(self):
""" Returns the state of the device. """
return self._state
# pylint: disable=too-many-branches
def update(self):
""" Gets the latest data from REST API and updates the state. """
self.rest.update()
""" Returns the state of the resources. """
value = self.rest.data
if value is not None:
if self.type == 'disk_use_percent':
self._state = value['fs'][0]['percent']
return value['fs'][0]['percent']
elif self.type == 'disk_use':
self._state = round(value['fs'][0]['used'] / 1024**3, 1)
return round(value['fs'][0]['used'] / 1024**3, 1)
elif self.type == 'disk_free':
self._state = round(value['fs'][0]['free'] / 1024**3, 1)
try:
return round(value['fs'][0]['free'] / 1024**3, 1)
except KeyError:
return round((value['fs'][0]['size'] -
value['fs'][0]['used']) / 1024**3, 1)
elif self.type == 'memory_use_percent':
self._state = value['mem']['percent']
return value['mem']['percent']
elif self.type == 'memory_use':
self._state = round(value['mem']['used'] / 1024**2, 1)
return round(value['mem']['used'] / 1024**2, 1)
elif self.type == 'memory_free':
self._state = round(value['mem']['free'] / 1024**2, 1)
return round(value['mem']['free'] / 1024**2, 1)
elif self.type == 'swap_use_percent':
self._state = value['memswap']['percent']
return value['memswap']['percent']
elif self.type == 'swap_use':
self._state = round(value['memswap']['used'] / 1024**3, 1)
return round(value['memswap']['used'] / 1024**3, 1)
elif self.type == 'swap_free':
self._state = round(value['memswap']['free'] / 1024**3, 1)
return round(value['memswap']['free'] / 1024**3, 1)
elif self.type == 'processor_load':
self._state = value['load']['min15']
return value['load']['min15']
elif self.type == 'process_running':
self._state = value['processcount']['running']
return value['processcount']['running']
elif self.type == 'process_total':
self._state = value['processcount']['total']
return value['processcount']['total']
elif self.type == 'process_thread':
self._state = value['processcount']['thread']
return value['processcount']['thread']
elif self.type == 'process_sleeping':
self._state = value['processcount']['sleeping']
return value['processcount']['sleeping']
def update(self):
""" Gets the latest data from REST API. """
self.rest.update()
# pylint: disable=too-few-public-methods
@ -145,15 +154,16 @@ class GlancesData(object):
""" Class for handling the data retrieval. """
def __init__(self, resource):
self.resource = resource
self._resource = resource
self.data = dict()
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
""" Gets the latest data from REST service. """
""" Gets the latest data from the Glances REST API. """
try:
response = requests.get(self.resource, timeout=10)
response = requests.get(self._resource, timeout=10)
self.data = response.json()
except requests.exceptions.ConnectionError:
_LOGGER.error("No route to host/endpoint.")
_LOGGER.error("No route to host/endpoint '%s'. Is device offline?",
self._resource)
self.data = None

View File

@ -11,7 +11,6 @@ from collections import OrderedDict
from homeassistant.const import (TEMP_CELCIUS)
from homeassistant.helpers.entity import Entity
from RFXtrx import SensorEvent
import homeassistant.components.rfxtrx as rfxtrx
from homeassistant.util import slugify
@ -28,6 +27,7 @@ _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Setup the RFXtrx platform. """
from RFXtrx import SensorEvent
def sensor_update(event):
""" Callback for sensor updates from the RFXtrx gateway. """

View File

@ -9,9 +9,6 @@ https://home-assistant.io/components/sensor.tellstick/
import logging
from collections import namedtuple
import tellcore.telldus as telldus
import tellcore.constants as tellcore_constants
from homeassistant.const import TEMP_CELCIUS
from homeassistant.helpers.entity import Entity
import homeassistant.util as util
@ -24,6 +21,9 @@ REQUIREMENTS = ['tellcore-py==1.1.2']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up Tellstick sensors. """
import tellcore.telldus as telldus
import tellcore.constants as tellcore_constants
sensor_value_descriptions = {
tellcore_constants.TELLSTICK_TEMPERATURE:
DatatypeDescription(

View File

@ -11,10 +11,6 @@ from datetime import timedelta
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
from homeassistant.helpers.entity import Entity
# pylint: disable=no-name-in-module, import-error
import transmissionrpc
from transmissionrpc.error import TransmissionError
import logging
@ -33,6 +29,9 @@ _THROTTLED_REFRESH = None
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Transmission sensors. """
import transmissionrpc
from transmissionrpc.error import TransmissionError
host = config.get(CONF_HOST)
username = config.get(CONF_USERNAME, None)
password = config.get(CONF_PASSWORD, None)
@ -97,6 +96,8 @@ class TransmissionSensor(Entity):
def refresh_transmission_data(self):
""" Calls the throttled Transmission refresh method. """
from transmissionrpc.error import TransmissionError
if _THROTTLED_REFRESH is not None:
try:
_THROTTLED_REFRESH()

View File

@ -15,9 +15,9 @@ from homeassistant.const import (
ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME,
TEMP_CELCIUS, TEMP_FAHRENHEIT)
REQUIREMENTS = ['https://github.com/balloob/home-assistant-vera-api/archive/'
'a8f823066ead6c7da6fb5e7abaf16fef62e63364.zip'
'#python-vera==0.1']
REQUIREMENTS = ['https://github.com/pavoni/home-assistant-vera-api/archive/'
'efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip'
'#python-vera==0.1.1']
_LOGGER = logging.getLogger(__name__)

View File

@ -8,8 +8,6 @@ at https://home-assistant.io/components/zwave/
"""
# pylint: disable=import-error
from homeassistant.helpers.event import track_point_in_time
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
import datetime
import homeassistant.util.dt as dt_util
import homeassistant.components.zwave as zwave
@ -70,11 +68,18 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
elif value.command_class == zwave.COMMAND_CLASS_SENSOR_MULTILEVEL:
add_devices([ZWaveMultilevelSensor(value)])
elif (value.command_class == zwave.COMMAND_CLASS_METER and
value.type == zwave.TYPE_DECIMAL):
add_devices([ZWaveMultilevelSensor(value)])
class ZWaveSensor(Entity):
""" Represents a Z-Wave sensor. """
def __init__(self, sensor_value):
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
self._value = sensor_value
self._node = sensor_value.node

View File

@ -16,7 +16,8 @@ from homeassistant.helpers.entity import ToggleEntity
from homeassistant.const import (
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
from homeassistant.components import group, discovery, wink, isy994, verisure
from homeassistant.components import (
group, discovery, wink, isy994, verisure, zwave)
DOMAIN = 'switch'
DEPENDENCIES = []
@ -38,7 +39,8 @@ DISCOVERY_PLATFORMS = {
discovery.SERVICE_WEMO: 'wemo',
wink.DISCOVER_SWITCHES: 'wink',
isy994.DISCOVER_SWITCHES: 'isy994',
verisure.DISCOVER_SWITCHES: 'verisure'
verisure.DISCOVER_SWITCHES: 'verisure',
zwave.DISCOVER_SWITCHES: 'zwave',
}
PROP_TO_ATTR = {

View File

@ -11,12 +11,6 @@ from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
import logging
try:
import hikvision.api
from hikvision.error import HikvisionError, MissingParamError
except ImportError:
hikvision.api = None
_LOGGING = logging.getLogger(__name__)
REQUIREMENTS = ['hikvision==0.4']
# pylint: disable=too-many-arguments
@ -25,6 +19,8 @@ REQUIREMENTS = ['hikvision==0.4']
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Setup Hikvision camera. """
import hikvision.api
from hikvision.error import HikvisionError, MissingParamError
host = config.get(CONF_HOST, None)
port = config.get('port', "80")
@ -32,13 +28,6 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
username = config.get(CONF_USERNAME, "admin")
password = config.get(CONF_PASSWORD, "12345")
if hikvision.api is None:
_LOGGING.error((
"Failed to import hikvision. Did you maybe not install the "
"'hikvision' dependency?"))
return False
try:
hikvision_cam = hikvision.api.CreateDevice(
host, port=port, username=username,

View File

@ -0,0 +1,78 @@
"""
homeassistant.components.switch.orvibo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Orvibo S20 Wifi Smart Switches.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/switch.orvibo/
"""
import logging
from homeassistant.components.switch import SwitchDevice
DEFAULT_NAME = "Orvibo S20 Switch"
REQUIREMENTS = ['orvibo==1.0.0']
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return S20 switches. """
from orvibo.s20 import S20, S20Exception
if config.get('host') is None:
_LOGGER.error("Missing required variable: host")
return
try:
s20 = S20(config.get('host'))
add_devices_callback([S20Switch(config.get('name', DEFAULT_NAME),
s20)])
except S20Exception:
_LOGGER.exception("S20 couldn't be initialized")
class S20Switch(SwitchDevice):
""" Represents an S20 switch. """
def __init__(self, name, s20):
from orvibo.s20 import S20Exception
self._name = name
self._s20 = s20
self._state = False
self._exc = S20Exception
@property
def should_poll(self):
""" Poll. """
return True
@property
def name(self):
""" The name of the switch. """
return self._name
@property
def is_on(self):
""" True if device is on. """
return self._state
def update(self):
""" Update device state. """
try:
self._state = self._s20.on
except self._exc:
_LOGGER.exception("Error while fetching S20 state")
def turn_on(self, **kwargs):
""" Turn the device on. """
try:
self._s20.on = True
except self._exc:
_LOGGER.exception("Error while turning on S20")
def turn_off(self, **kwargs):
""" Turn the device off. """
try:
self._s20.on = False
except self._exc:
_LOGGER.exception("Error while turning off S20")

View File

@ -8,7 +8,6 @@ https://home-assistant.io/components/switch.rfxtrx/
"""
import logging
import homeassistant.components.rfxtrx as rfxtrx
from RFXtrx import LightingDevice
from homeassistant.components.switch import SwitchDevice
from homeassistant.util import slugify
@ -20,6 +19,7 @@ _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Setup the RFXtrx platform. """
from RFXtrx import LightingDevice
# Add switch from config file
switchs = []

View File

@ -11,8 +11,6 @@ import logging
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP,
ATTR_FRIENDLY_NAME)
from homeassistant.helpers.entity import ToggleEntity
import tellcore.constants as tellcore_constants
from tellcore.library import DirectCallbackDispatcher
SIGNAL_REPETITIONS = 1
REQUIREMENTS = ['tellcore-py==1.1.2']
@ -22,11 +20,9 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return Tellstick switches. """
try:
import tellcore.telldus as telldus
except ImportError:
_LOGGER.exception("Failed to import tellcore")
return
import tellcore.telldus as telldus
import tellcore.constants as tellcore_constants
from tellcore.library import DirectCallbackDispatcher
core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher())
@ -62,14 +58,17 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
class TellstickSwitchDevice(ToggleEntity):
""" Represents a Tellstick switch. """
last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
tellcore_constants.TELLSTICK_TURNOFF)
def __init__(self, tellstick_device, signal_repetitions):
import tellcore.constants as tellcore_constants
self.tellstick_device = tellstick_device
self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name}
self.signal_repetitions = signal_repetitions
self.last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
tellcore_constants.TELLSTICK_TURNOFF)
@property
def should_poll(self):
""" Tells Home Assistant not to poll this entity. """
@ -88,6 +87,8 @@ class TellstickSwitchDevice(ToggleEntity):
@property
def is_on(self):
""" True if switch is on. """
import tellcore.constants as tellcore_constants
last_command = self.tellstick_device.last_sent_command(
self.last_sent_command_mask)

View File

@ -10,9 +10,6 @@ from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.helpers.entity import ToggleEntity
# pylint: disable=no-name-in-module, import-error
import transmissionrpc
from transmissionrpc.error import TransmissionError
import logging
_LOGGING = logging.getLogger(__name__)
@ -22,6 +19,9 @@ REQUIREMENTS = ['transmissionrpc==0.11']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Sets up the transmission sensor. """
import transmissionrpc
from transmissionrpc.error import TransmissionError
host = config.get(CONF_HOST)
username = config.get(CONF_USERNAME, None)
password = config.get(CONF_PASSWORD, None)

View File

@ -0,0 +1,76 @@
"""
homeassistant.components.switch.zwave
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Zwave platform that handles simple binary switches.
"""
# pylint: disable=import-error
import homeassistant.components.zwave as zwave
from homeassistant.components.switch import SwitchDevice
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Find and return demo switches. """
if discovery_info is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.ATTR_VALUE_ID]]
if value.command_class != zwave.COMMAND_CLASS_SWITCH_BINARY:
return
if value.type != zwave.TYPE_BOOL:
return
if value.genre != zwave.GENRE_USER:
return
value.set_change_verified(False)
add_devices([ZwaveSwitch(value)])
class ZwaveSwitch(SwitchDevice):
""" Provides a zwave switch. """
def __init__(self, value):
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
self._value = value
self._node = value.node
self._state = value.data
dispatcher.connect(
self._value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED)
def _value_changed(self, value):
""" Called when a value has changed on the network. """
if self._value.value_id == value.value_id:
self._state = value.data
self.update_ha_state()
@property
def should_poll(self):
""" No polling needed for a demo switch. """
return False
@property
def name(self):
""" Returns the name of the device if any. """
name = self._node.name or "{}".format(self._node.product_name)
return "{}".format(name or self._value.label)
@property
def is_on(self):
""" True if device is on. """
return self._state
def turn_on(self, **kwargs):
""" Turn the device on. """
self._node.set_switch(self._value.value_id, True)
def turn_off(self, **kwargs):
""" Turn the device off. """
self._node.set_switch(self._value.value_id, False)

View File

@ -0,0 +1,57 @@
"""
homeassistant.components.updater
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component that checks for available updates.
For more details about this platform, please refer to the documentation at
at https://home-assistant.io/components/updater/
"""
import logging
import requests
from homeassistant.const import __version__ as CURRENT_VERSION
from homeassistant.const import ATTR_FRIENDLY_NAME
from homeassistant.helpers import event
_LOGGER = logging.getLogger(__name__)
PYPI_URL = 'https://pypi.python.org/pypi/homeassistant/json'
DEPENDENCIES = []
DOMAIN = 'updater'
ENTITY_ID = 'updater.updater'
def setup(hass, config):
""" Setup the updater component. """
def check_newest_version(_=None):
""" Check if a new version is available and report if one is. """
newest = get_newest_version()
if newest != CURRENT_VERSION and newest is not None:
hass.states.set(
ENTITY_ID, newest, {ATTR_FRIENDLY_NAME: 'Update Available'})
event.track_time_change(hass, check_newest_version,
hour=[0, 12], minute=0, second=0)
check_newest_version()
return True
def get_newest_version():
""" Get the newest Home Assistant version from PyPI. """
try:
req = requests.get(PYPI_URL)
return req.json()['info']['version']
except requests.RequestException:
_LOGGER.exception('Could not contact PyPI to check for updates')
return
except ValueError:
_LOGGER.exception('Received invalid response from PyPI')
return
except KeyError:
_LOGGER.exception('Response from PyPI did not include version')
return

View File

@ -6,6 +6,9 @@ Connects Home Assistant to a Z-Wave network.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zwave/
"""
import sys
import os.path
from pprint import pprint
from homeassistant import bootstrap
@ -20,13 +23,20 @@ REQUIREMENTS = ['pydispatcher==2.0.5']
CONF_USB_STICK_PATH = "usb_path"
DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick"
CONF_DEBUG = "debug"
CONF_POLLING_INTERVAL = "polling_interval"
DEFAULT_ZWAVE_CONFIG_PATH = os.path.join(sys.prefix, 'share',
'python-openzwave', 'config')
DISCOVER_SENSORS = "zwave.sensors"
DISCOVER_SWITCHES = "zwave.switch"
DISCOVER_LIGHTS = "zwave.light"
COMMAND_CLASS_SWITCH_MULTILEVEL = 38
COMMAND_CLASS_SWITCH_BINARY = 37
COMMAND_CLASS_SENSOR_BINARY = 48
COMMAND_CLASS_SENSOR_MULTILEVEL = 49
COMMAND_CLASS_METER = 50
COMMAND_CLASS_BATTERY = 128
GENRE_WHATEVER = None
@ -35,20 +45,28 @@ GENRE_USER = "User"
TYPE_WHATEVER = None
TYPE_BYTE = "Byte"
TYPE_BOOL = "Bool"
TYPE_DECIMAL = "Decimal"
# list of tuple (DOMAIN, discovered service, supported command
# classes, value type)
DISCOVERY_COMPONENTS = [
('sensor',
DISCOVER_SENSORS,
[COMMAND_CLASS_SENSOR_BINARY, COMMAND_CLASS_SENSOR_MULTILEVEL],
[COMMAND_CLASS_SENSOR_BINARY,
COMMAND_CLASS_SENSOR_MULTILEVEL,
COMMAND_CLASS_METER],
TYPE_WHATEVER,
GENRE_WHATEVER),
GENRE_USER),
('light',
DISCOVER_LIGHTS,
[COMMAND_CLASS_SWITCH_MULTILEVEL],
TYPE_BYTE,
GENRE_USER),
('switch',
DISCOVER_SWITCHES,
[COMMAND_CLASS_SWITCH_BINARY],
TYPE_BOOL,
GENRE_USER),
]
ATTR_NODE_ID = "node_id"
@ -107,7 +125,9 @@ def setup(hass, config):
# Setup options
options = ZWaveOption(
config[DOMAIN].get(CONF_USB_STICK_PATH, DEFAULT_CONF_USB_STICK_PATH),
user_path=hass.config.config_dir)
user_path=hass.config.config_dir,
config_path=config[DOMAIN].get('config_path',
DEFAULT_ZWAVE_CONFIG_PATH),)
options.set_console_output(use_debug)
options.lock()
@ -165,6 +185,10 @@ def setup(hass, config):
""" Called when Home Assistant starts up. """
NETWORK.start()
polling_interval = config[DOMAIN].get(CONF_POLLING_INTERVAL, None)
if polling_interval is not None:
NETWORK.setPollInterval(polling_interval)
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave)
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)

View File

@ -32,6 +32,7 @@ DEFAULT_CONFIG = (
DEFAULT_COMPONENTS = {
'introduction': 'Show links to resources in log and frontend',
'frontend': 'Enables the frontend',
'updater': 'Checks for available updates',
'discovery': 'Discover some devices automatically',
'conversation': 'Allows you to issue voice commands from the frontend',
'history': 'Enables support for tracking state changes over time.',

View File

@ -1,7 +1,7 @@
# coding: utf-8
""" Constants used by Home Assistant components. """
__version__ = "0.8.0.dev0"
__version__ = "0.9.0.dev0"
# Can be used to specify a catch all when registering state or event listeners.
MATCH_ALL = '*'

View File

@ -84,7 +84,7 @@ class HomeAssistant(object):
if os.name != "nt":
try:
signal.signal(signal.SIGQUIT, stop_homeassistant)
signal.signal(signal.SIGTERM, stop_homeassistant)
except ValueError:
_LOGGER.warning(
'Could not bind to SIGQUIT. Are you running in a thread?')

View File

@ -29,6 +29,7 @@ def install_package(package, upgrade=True, target=None):
try:
return 0 == subprocess.call(args)
except subprocess.SubprocessError:
_LOGGER.exception('Unable to install pacakge %s', package)
return False

View File

@ -1,158 +1,166 @@
# Required for Home Assistant core
# Home Assistant core
requests>=2,<3
pyyaml>=3.11,<4
pytz>=2015.4
pip>=7.0.0
vincenty==0.1.3
# Optional, needed for specific components
# Sun (sun)
astral==0.8.1
# Philips Hue (lights.hue)
phue==0.8
# Limitlessled/Easybulb/Milight (lights.limitlessled)
ledcontroller==1.1.0
# Chromecast (media_player.cast)
pychromecast==0.6.12
# Keyboard (keyboard)
pyuserinput==0.1.9
# Tellstick (*.tellstick)
tellcore-py==1.1.2
# Nmap (device_tracker.nmap)
python-nmap==0.4.3
# PushBullet (notify.pushbullet)
pushbullet.py==0.8.1
# Nest Thermostat (thermostat.nest)
python-nest==2.6.0
# Z-Wave (*.zwave)
pydispatcher==2.0.5
# ISY994 (isy994)
PyISY==1.0.5
# PSutil (sensor.systemmonitor)
psutil==3.2.2
# Pushover (notify.pushover)
python-pushover==0.2
# Transmission Torrent Client (*.transmission)
transmissionrpc==0.11
# OpenWeatherMap (sensor.openweathermap)
pyowm==2.2.1
# XMPP (notify.xmpp)
sleekxmpp==1.3.1
dnspython3==1.12.0
# Blockchain (sensor.bitcoin)
blockchain==1.1.2
# Music Player Daemon (media_player.mpd)
python-mpd2==0.5.4
# Hikvision (switch.hikvisioncam)
hikvision==0.4
# Console log coloring
colorlog==2.6.0
# JSON-RPC interface (media_player.kodi)
jsonrpc-requests==0.1
# Forecast.io (sensor.forecast)
python-forecastio==1.3.3
# Firmata (*.arduino)
# homeassistant.components.arduino
PyMata==2.07a
# Rfxtrx (rfxtrx)
https://github.com/Danielhiversen/pyRFXtrx/archive/ec7a1aaddf8270db6e5da1c13d58c1547effd7cf.zip#RFXtrx==0.15
# Mysensors (sensor.mysensors)
https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3
# Netgear (device_tracker.netgear)
# homeassistant.components.device_tracker.netgear
pynetgear==0.3
# Netdisco (discovery)
netdisco==0.5.1
# homeassistant.components.device_tracker.nmap_tracker
python-nmap==0.4.3
# Wemo (switch.wemo)
pywemo==0.3.2
# Wink (*.wink)
https://github.com/balloob/python-wink/archive/9eb39eaba0717922815e673ad1114c685839d890.zip#python-wink==0.1.1
# Slack notifier (notify.slack)
slacker==0.6.8
# Temper sensors (sensor.temper)
https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3
# PyEdimax (switch.edimax)
https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip#pyedimax==0.1
# RPI-GPIO platform (*.rpi_gpio)
# Uncomment for Raspberry Pi
# RPi.GPIO==0.5.11
# Adafruit temperature/humidity sensor (sensor.dht)
# Uncomment on a Raspberry Pi / Beaglebone
# http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0
# PAHO MQTT (mqtt)
paho-mqtt==1.1
# PyModbus (modbus)
https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0
# Verisure (verisure)
https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60f7f35854390d59be.zip#python-verisure==0.2.6
# IFTTT Maker Channel (ifttt)
pyfttt==0.3
# SABnzbd (sensor.sabnzbd)
https://github.com/balloob/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1
# Vera (*.vera)
https://github.com/pavoni/home-assistant-vera-api/archive/efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip#python-vera==0.1.1
# Sonos (media_player.sonos)
SoCo==0.11.1
# PlexAPI (media_player.plex)
plexapi==1.1.0
# SNMP (device_tracker.snmp)
# homeassistant.components.device_tracker.snmp
pysnmp==4.2.5
# Blinkstick (light.blinksticklight)
# homeassistant.components.discovery
netdisco==0.5.1
# homeassistant.components.ifttt
pyfttt==0.3
# homeassistant.components.isy994
PyISY==1.0.5
# homeassistant.components.keyboard
pyuserinput==0.1.9
# homeassistant.components.light.blinksticklight
blinkstick==1.1.7
# Telegram (notify.telegram)
# homeassistant.components.light.hue
phue==0.8
# homeassistant.components.light.limitlessled
ledcontroller==1.1.0
# homeassistant.components.light.tellstick
# homeassistant.components.sensor.tellstick
# homeassistant.components.switch.tellstick
tellcore-py==1.1.2
# homeassistant.components.light.vera
# homeassistant.components.sensor.vera
# homeassistant.components.switch.vera
https://github.com/pavoni/home-assistant-vera-api/archive/efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip#python-vera==0.1.1
# homeassistant.components.wink
# homeassistant.components.light.wink
# homeassistant.components.sensor.wink
# homeassistant.components.switch.wink
https://github.com/balloob/python-wink/archive/9eb39eaba0717922815e673ad1114c685839d890.zip#python-wink==0.1.1
# homeassistant.components.media_player.cast
pychromecast==0.6.12
# homeassistant.components.media_player.kodi
jsonrpc-requests==0.1
# homeassistant.components.media_player.mpd
python-mpd2==0.5.4
# homeassistant.components.media_player.plex
plexapi==1.1.0
# homeassistant.components.media_player.sonos
SoCo==0.11.1
# homeassistant.components.modbus
https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0
# homeassistant.components.mqtt
paho-mqtt==1.1
# homeassistant.components.notify.pushbullet
pushbullet.py==0.9.0
# homeassistant.components.notify.pushetta
pushetta==1.0.15
# homeassistant.components.notify.pushover
python-pushover==0.2
# homeassistant.components.notify.slack
slacker==0.6.8
# homeassistant.components.notify.telegram
python-telegram-bot==2.8.7
# CPUinfo (sensor.cpuinfo)
# homeassistant.components.notify.xmpp
sleekxmpp==1.3.1
# homeassistant.components.notify.xmpp
dnspython3==1.12.0
# homeassistant.components.rfxtrx
https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip#RFXtrx==0.2
# homeassistant.components.sensor.bitcoin
blockchain==1.1.2
# homeassistant.components.sensor.cpuspeed
py-cpuinfo==0.1.6
# Radio Thermostat (thermostat.radiotherm)
radiotherm==1.2
# homeassistant.components.sensor.dht
# http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0
# Honeywell Evo Home Client (thermostat.honeywell)
# homeassistant.components.sensor.forecast
python-forecastio==1.3.3
# homeassistant.components.sensor.mysensors
https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3
# homeassistant.components.sensor.openweathermap
pyowm==2.2.1
# homeassistant.components.sensor.rpi_gpio
# homeassistant.components.switch.rpi_gpio
# RPi.GPIO==0.5.11
# homeassistant.components.sensor.sabnzbd
https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1
# homeassistant.components.sensor.systemmonitor
psutil==3.2.2
# homeassistant.components.sensor.temper
https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3
# homeassistant.components.sensor.transmission
# homeassistant.components.switch.transmission
transmissionrpc==0.11
# homeassistant.components.sun
astral==0.8.1
# homeassistant.components.switch.edimax
https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip#pyedimax==0.1
# homeassistant.components.switch.hikvisioncam
hikvision==0.4
# homeassistant.components.switch.orvibo
orvibo==1.0.0
# homeassistant.components.switch.wemo
pywemo==0.3.2
# homeassistant.components.thermostat.honeywell
evohomeclient==0.2.3
# Pushetta (notify.pushetta)
pushetta==1.0.15
# homeassistant.components.thermostat.nest
python-nest==2.6.0
# homeassistant.components.thermostat.radiotherm
radiotherm==1.2
# homeassistant.components.verisure
https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60f7f35854390d59be.zip#python-verisure==0.2.6
# homeassistant.components.zwave
pydispatcher==2.0.5

90
script/gen_requirements_all.py Executable file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env python3
"""
Generate an updated requirements_all.txt
"""
from collections import OrderedDict
import importlib
import os
import pkgutil
import re
COMMENT_REQUIREMENTS = [
'RPi.GPIO',
'Adafruit_Python_DHT'
]
def explore_module(package, explore_children):
module = importlib.import_module(package)
found = []
if not hasattr(module, '__path__'):
return found
for _, name, ispkg in pkgutil.iter_modules(module.__path__, package + '.'):
found.append(name)
if explore_children:
found.extend(explore_module(name, False))
return found
def core_requirements():
with open('setup.py') as inp:
reqs_raw = re.search(
r'REQUIRES = \[(.*?)\]', inp.read(), re.S).group(1)
return re.findall(r"'(.*?)'", reqs_raw)
def comment_requirement(req):
""" Some requirements don't install on all systems. """
return any(ign in req for ign in COMMENT_REQUIREMENTS)
def main():
if not os.path.isfile('requirements_all.txt'):
print('Run this from HA root dir')
return
reqs = OrderedDict()
errors = []
for package in sorted(explore_module('homeassistant.components', True)):
try:
module = importlib.import_module(package)
except ImportError:
errors.append(package)
continue
if not getattr(module, 'REQUIREMENTS', None):
continue
for req in module.REQUIREMENTS:
reqs.setdefault(req, []).append(package)
if errors:
print("Found errors")
print('\n'.join(errors))
return
print('# Home Assistant core')
print('\n'.join(core_requirements()))
print()
for pkg, requirements in reqs.items():
for req in sorted(requirements,
key=lambda name: (len(name.split('.')), name)):
print('#', req)
if comment_requirement(pkg):
print('#', pkg)
else:
print(pkg)
print()
if __name__ == '__main__':
main()

View File

@ -53,7 +53,7 @@ stop() {
return 1
fi
echo 'Stopping service…' >&2
kill -3 $(cat "$PID_FILE")
kill $(cat "$PID_FILE")
while ps -p $(cat "$PID_FILE") > /dev/null 2>&1; do sleep 1;done;
echo 'Service stopped' >&2
}

View File

@ -9,6 +9,7 @@ Type=simple
User=%i
WorkingDirectory=%h
ExecStart=/usr/bin/hass --config %h/.homeassistant/
SendSIGKILL=no
[Install]
WantedBy=multi-user.target

View File

View File

@ -0,0 +1,153 @@
"""
tests.components.light.test_mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tests mqtt light.
config for RGB Version with brightness:
light:
platform: mqtt
name: "Office Light RGB"
state_topic: "office/rgb1/light/status"
command_topic: "office/rgb1/light/switch"
brightness_state_topic: "office/rgb1/brightness/status"
brightness_command_topic: "office/rgb1/brightness/set"
rgb_state_topic: "office/rgb1/rgb/status"
rgb_command_topic: "office/rgb1/rgb/set"
qos: 0
payload_on: "on"
payload_off: "off"
config without RGB:
light:
platform: mqtt
name: "Office Light"
state_topic: "office/rgb1/light/status"
command_topic: "office/rgb1/light/switch"
brightness_state_topic: "office/rgb1/brightness/status"
brightness_command_topic: "office/rgb1/brightness/set"
qos: 0
payload_on: "on"
payload_off: "off"
config without RGB and brightness:
light:
platform: mqtt
name: "Office Light"
state_topic: "office/rgb1/light/status"
command_topic: "office/rgb1/light/switch"
qos: 0
payload_on: "on"
payload_off: "off"
"""
import unittest
import homeassistant.util.color as color_util
from homeassistant.const import STATE_ON, STATE_OFF
import homeassistant.core as ha
import homeassistant.components.light as light
from tests.common import mock_mqtt_component, fire_mqtt_message
class TestLightMQTT(unittest.TestCase):
""" Test the MQTT light. """
def setUp(self): # pylint: disable=invalid-name
self.hass = ha.HomeAssistant()
self.mock_publish = mock_mqtt_component(self.hass)
def tearDown(self): # pylint: disable=invalid-name
""" Stop down stuff we started. """
self.hass.stop()
def test_controlling_state_via_topic(self):
self.assertTrue(light.setup(self.hass, {
'light': {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test_light_rgb/status',
'command_topic': 'test_light_rgb/set',
'brightness_state_topic': 'test_light_rgb/brightness/status',
'brightness_command_topic': 'test_light_rgb/brightness/set',
'rgb_state_topic': 'test_light_rgb/rgb/status',
'rgb_command_topic': 'test_light_rgb/rgb/set',
'qos': 0,
'payload_on': 'on',
'payload_off': 'off'
}
}))
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'on')
self.hass.pool.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'off')
self.hass.pool.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'on')
self.hass.pool.block_till_done()
fire_mqtt_message(self.hass, 'test_light_rgb/brightness/status', '100')
self.hass.pool.block_till_done()
light_state = self.hass.states.get('light.test')
self.hass.pool.block_till_done()
self.assertEqual(100,
light_state.attributes['brightness'])
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'on')
self.hass.pool.block_till_done()
fire_mqtt_message(self.hass, 'test_light_rgb/rgb/status',
'125,125,125')
self.hass.pool.block_till_done()
light_state = self.hass.states.get('light.test')
self.assertEqual([125, 125, 125],
light_state.attributes.get('rgb_color'))
def test_sending_mqtt_commands_and_optimistic(self):
self.assertTrue(light.setup(self.hass, {
'light': {
'platform': 'mqtt',
'name': 'test',
'command_topic': 'test_light_rgb/set',
'brightness_state_topic': 'test_light_rgb/brightness/status',
'brightness_command_topic': 'test_light_rgb/brightness/set',
'rgb_state_topic': 'test_light_rgb/rgb/status',
'rgb_command_topic': 'test_light_rgb/rgb/set',
'qos': 2,
'payload_on': 'on',
'payload_off': 'off'
}
}))
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
light.turn_on(self.hass, 'light.test')
self.hass.pool.block_till_done()
self.assertEqual(('test_light_rgb/set', 'on', 2),
self.mock_publish.mock_calls[-1][1])
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
light.turn_off(self.hass, 'light.test')
self.hass.pool.block_till_done()
self.assertEqual(('test_light_rgb/set', 'off', 2),
self.mock_publish.mock_calls[-1][1])
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)

View File

@ -88,6 +88,8 @@ class TestScript(unittest.TestCase):
self.assertEqual(1, len(calls))
self.assertEqual('world', calls[0].data.get('hello'))
self.assertEqual(
True, self.hass.states.get(ENTITY_ID).attributes.get('can_cancel'))
def test_calling_service_old(self):
calls = []
@ -172,6 +174,9 @@ class TestScript(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertTrue(script.is_on(self.hass, ENTITY_ID))
self.assertEqual(
False,
self.hass.states.get(ENTITY_ID).attributes.get('can_cancel'))
self.assertEqual(
event,

View File

@ -5,11 +5,13 @@ tests.test_bootstrap
Tests bootstrap.
"""
# pylint: disable=too-many-public-methods,protected-access
import os
import tempfile
import unittest
from unittest import mock
from homeassistant import bootstrap
from homeassistant import core, bootstrap
from homeassistant.const import __version__
import homeassistant.util.dt as dt_util
from tests.common import mock_detect_location_info
@ -39,3 +41,45 @@ class TestBootstrap(unittest.TestCase):
self.assertEqual(sorted(components),
sorted(hass.config.components))
def test_remove_lib_on_upgrade(self):
with tempfile.TemporaryDirectory() as config_dir:
version_path = os.path.join(config_dir, '.HA_VERSION')
lib_dir = os.path.join(config_dir, 'lib')
check_file = os.path.join(lib_dir, 'check')
with open(version_path, 'wt') as outp:
outp.write('0.7.0')
os.mkdir(lib_dir)
with open(check_file, 'w'):
pass
hass = core.HomeAssistant()
hass.config.config_dir = config_dir
self.assertTrue(os.path.isfile(check_file))
bootstrap.process_ha_config_upgrade(hass)
self.assertFalse(os.path.isfile(check_file))
def test_not_remove_lib_if_not_upgrade(self):
with tempfile.TemporaryDirectory() as config_dir:
version_path = os.path.join(config_dir, '.HA_VERSION')
lib_dir = os.path.join(config_dir, 'lib')
check_file = os.path.join(lib_dir, 'check')
with open(version_path, 'wt') as outp:
outp.write(__version__)
os.mkdir(lib_dir)
with open(check_file, 'w'):
pass
hass = core.HomeAssistant()
hass.config.config_dir = config_dir
bootstrap.process_ha_config_upgrade(hass)
self.assertTrue(os.path.isfile(check_file))