Merge branch 'dev' of https://github.com/balloob/home-assistant into findiphone
commit
396a65ab03
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
include README.md
|
||||
include README.rst
|
||||
include LICENSE
|
||||
graft homeassistant
|
||||
prune homeassistant/components/frontend/www_static/home-assistant-polymer
|
||||
|
|
38
README.md
38
README.md
|
@ -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.
|
|
@ -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/
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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'])])
|
||||
|
|
|
@ -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()
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()]
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. """
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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__)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
|
@ -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 = []
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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.',
|
||||
|
|
|
@ -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 = '*'
|
||||
|
|
|
@ -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?')
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ Type=simple
|
|||
User=%i
|
||||
WorkingDirectory=%h
|
||||
ExecStart=/usr/bin/hass --config %h/.homeassistant/
|
||||
SendSIGKILL=no
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -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)
|
|
@ -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,
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue