mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Merge branch 'dev' of https://github.com/balloob/home-assistant into findiphone
This commit is contained in:
commit
396a65ab03
@ -50,6 +50,7 @@ omit =
|
|||||||
homeassistant/components/downloader.py
|
homeassistant/components/downloader.py
|
||||||
homeassistant/components/keyboard.py
|
homeassistant/components/keyboard.py
|
||||||
homeassistant/components/light/hue.py
|
homeassistant/components/light/hue.py
|
||||||
|
homeassistant/components/light/mqtt.py
|
||||||
homeassistant/components/light/limitlessled.py
|
homeassistant/components/light/limitlessled.py
|
||||||
homeassistant/components/light/blinksticklight.py
|
homeassistant/components/light/blinksticklight.py
|
||||||
homeassistant/components/light/hyperion.py
|
homeassistant/components/light/hyperion.py
|
||||||
@ -83,6 +84,7 @@ omit =
|
|||||||
homeassistant/components/sensor/glances.py
|
homeassistant/components/sensor/glances.py
|
||||||
homeassistant/components/sensor/mysensors.py
|
homeassistant/components/sensor/mysensors.py
|
||||||
homeassistant/components/sensor/openweathermap.py
|
homeassistant/components/sensor/openweathermap.py
|
||||||
|
homeassistant/components/switch/orvibo.py
|
||||||
homeassistant/components/sensor/rest.py
|
homeassistant/components/sensor/rest.py
|
||||||
homeassistant/components/sensor/rpi_gpio.py
|
homeassistant/components/sensor/rpi_gpio.py
|
||||||
homeassistant/components/sensor/sabnzbd.py
|
homeassistant/components/sensor/sabnzbd.py
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
include README.md
|
include README.rst
|
||||||
include LICENSE
|
include LICENSE
|
||||||
graft homeassistant
|
graft homeassistant
|
||||||
prune homeassistant/components/frontend/www_static/home-assistant-polymer
|
prune homeassistant/components/frontend/www_static/home-assistant-polymer
|
||||||
|
38
README.md
38
README.md
@ -1,38 +0,0 @@
|
|||||||
# Home Assistant [](https://travis-ci.org/balloob/home-assistant) [](https://coveralls.io/r/balloob/home-assistant?branch=master) [](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.
|
|
||||||
|
|
||||||
[][demo]
|
|
||||||
|
|
||||||
Examples of devices it can interface it:
|
|
||||||
|
|
||||||
* Monitoring connected devices to a wireless router: [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), [DD-WRT](http://www.dd-wrt.com/site/index), [TPLink](http://www.tp-link.us/), [ASUSWRT](http://event.asus.com/2013/nw/ASUSWRT/) and any SNMP capable Linksys WAP/WRT
|
|
||||||
* [Philips Hue](http://meethue.com) lights, [WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) switches, [Edimax](http://www.edimax.com/) switches, [Efergy](https://efergy.com) energy monitoring, and [Tellstick](http://www.telldus.se/products/tellstick) devices and sensors
|
|
||||||
* [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast), [Music Player Daemon](http://www.musicpd.org/), [Logitech Squeezebox](https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29), [Plex](https://plex.tv/), [Kodi (XBMC)](http://kodi.tv/), iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api)), and Amazon Fire TV (by way of [python-firetv](https://github.com/happyleavesaoc/python-firetv))
|
|
||||||
* Support for [ISY994](https://www.universal-devices.com/residential/isy994i-series/) (Insteon and X10 devices), [Z-Wave](http://www.z-wave.com/), [Nest Thermostats](https://nest.com/), [RFXtrx](http://www.rfxcom.com/), [Arduino](https://www.arduino.cc/), [Raspberry Pi](https://www.raspberrypi.org/), and [Modbus](http://www.modbus.org/)
|
|
||||||
* Interaction with [IFTTT](https://ifttt.com/)
|
|
||||||
* Integrate data from the [Bitcoin](https://bitcoin.org) network, meteorological data from [OpenWeatherMap](http://openweathermap.org/) and [Forecast.io](https://forecast.io/), [Transmission](http://www.transmissionbt.com/), or [SABnzbd](http://sabnzbd.org).
|
|
||||||
* [See full list of supported devices](https://home-assistant.io/components/)
|
|
||||||
|
|
||||||
Built home automation on top of your devices:
|
|
||||||
|
|
||||||
* Keep a precise history of every change to the state of your house
|
|
||||||
* Turn on the lights when people get home after sun set
|
|
||||||
* Turn on lights slowly during sun set to compensate for less light
|
|
||||||
* Turn off all lights and devices when everybody leaves the house
|
|
||||||
* Offers a [REST API](https://home-assistant.io/developers/api.html) and can interface with MQTT for easy integration with other projects like [OwnTracks](http://owntracks.org/)
|
|
||||||
* Allow sending notifications using [Instapush](https://instapush.im), [Notify My Android (NMA)](http://www.notifymyandroid.com/), [PushBullet](https://www.pushbullet.com/), [PushOver](https://pushover.net/), [Slack](https://slack.com/), [Telegram](https://telegram.org/), and [Jabber (XMPP)](http://xmpp.org)
|
|
||||||
|
|
||||||
The system is built modular so support for other devices or actions can be implemented easily. See also the [section on architecture](https://home-assistant.io/developers/architecture.html) and the [section on creating your own components](https://home-assistant.io/developers/creating_components.html).
|
|
||||||
|
|
||||||
If you run into issues while using Home Assistant or during development of a component, check the [Home Assistant help section](https://home-assistant.io/help/) how to reach us.
|
|
98
README.rst
Normal file
98
README.rst
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
Home Assistant |Build Status| |Coverage Status| |Join the chat at https://gitter.im/balloob/home-assistant|
|
||||||
|
===========================================================================================================
|
||||||
|
|
||||||
|
Home Assistant is a home automation platform running on Python 3. The
|
||||||
|
goal of Home Assistant is to be able to track and control all devices at
|
||||||
|
home and offer a platform for automating control.
|
||||||
|
|
||||||
|
To get started:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
python3 -m pip install homeassistant
|
||||||
|
hass --open-ui
|
||||||
|
|
||||||
|
Check out `the website <https://home-assistant.io>`__ for `a
|
||||||
|
demo <https://home-assistant.io/demo/>`__, installation instructions,
|
||||||
|
tutorials and documentation.
|
||||||
|
|
||||||
|
|screenshot-states|
|
||||||
|
|
||||||
|
Examples of devices it can interface it:
|
||||||
|
|
||||||
|
- Monitoring connected devices to a wireless router:
|
||||||
|
`OpenWrt <https://openwrt.org/>`__,
|
||||||
|
`Tomato <http://www.polarcloud.com/tomato>`__,
|
||||||
|
`Netgear <http://netgear.com>`__,
|
||||||
|
`DD-WRT <http://www.dd-wrt.com/site/index>`__,
|
||||||
|
`TPLink <http://www.tp-link.us/>`__,
|
||||||
|
`ASUSWRT <http://event.asus.com/2013/nw/ASUSWRT/>`__ and any SNMP
|
||||||
|
capable Linksys WAP/WRT
|
||||||
|
- `Philips Hue <http://meethue.com>`__ lights,
|
||||||
|
`WeMo <http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/>`__
|
||||||
|
switches, `Edimax <http://www.edimax.com/>`__ switches,
|
||||||
|
`Efergy <https://efergy.com>`__ energy monitoring, and
|
||||||
|
`Tellstick <http://www.telldus.se/products/tellstick>`__ devices and
|
||||||
|
sensors
|
||||||
|
- `Google
|
||||||
|
Chromecasts <http://www.google.com/intl/en/chrome/devices/chromecast>`__,
|
||||||
|
`Music Player Daemon <http://www.musicpd.org/>`__, `Logitech
|
||||||
|
Squeezebox <https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29>`__,
|
||||||
|
`Plex <https://plex.tv/>`__, `Kodi (XBMC) <http://kodi.tv/>`__,
|
||||||
|
iTunes (by way of
|
||||||
|
`itunes-api <https://github.com/maddox/itunes-api>`__), and Amazon
|
||||||
|
Fire TV (by way of
|
||||||
|
`python-firetv <https://github.com/happyleavesaoc/python-firetv>`__)
|
||||||
|
- Support for
|
||||||
|
`ISY994 <https://www.universal-devices.com/residential/isy994i-series/>`__
|
||||||
|
(Insteon and X10 devices), `Z-Wave <http://www.z-wave.com/>`__, `Nest
|
||||||
|
Thermostats <https://nest.com/>`__,
|
||||||
|
`RFXtrx <http://www.rfxcom.com/>`__,
|
||||||
|
`Arduino <https://www.arduino.cc/>`__, `Raspberry
|
||||||
|
Pi <https://www.raspberrypi.org/>`__, and
|
||||||
|
`Modbus <http://www.modbus.org/>`__
|
||||||
|
- Interaction with `IFTTT <https://ifttt.com/>`__
|
||||||
|
- Integrate data from the `Bitcoin <https://bitcoin.org>`__ network,
|
||||||
|
meteorological data from
|
||||||
|
`OpenWeatherMap <http://openweathermap.org/>`__ and
|
||||||
|
`Forecast.io <https://forecast.io/>`__,
|
||||||
|
`Transmission <http://www.transmissionbt.com/>`__, or
|
||||||
|
`SABnzbd <http://sabnzbd.org>`__.
|
||||||
|
- `See full list of supported
|
||||||
|
devices <https://home-assistant.io/components/>`__
|
||||||
|
|
||||||
|
Built home automation on top of your devices:
|
||||||
|
|
||||||
|
- Keep a precise history of every change to the state of your house
|
||||||
|
- Turn on the lights when people get home after sun set
|
||||||
|
- Turn on lights slowly during sun set to compensate for less light
|
||||||
|
- Turn off all lights and devices when everybody leaves the house
|
||||||
|
- Offers a `REST API <https://home-assistant.io/developers/api/>`__
|
||||||
|
and can interface with MQTT for easy integration with other projects
|
||||||
|
like `OwnTracks <http://owntracks.org/>`__
|
||||||
|
- Allow sending notifications using
|
||||||
|
`Instapush <https://instapush.im>`__, `Notify My Android
|
||||||
|
(NMA) <http://www.notifymyandroid.com/>`__,
|
||||||
|
`PushBullet <https://www.pushbullet.com/>`__,
|
||||||
|
`PushOver <https://pushover.net/>`__, `Slack <https://slack.com/>`__,
|
||||||
|
`Telegram <https://telegram.org/>`__, and `Jabber
|
||||||
|
(XMPP) <http://xmpp.org>`__
|
||||||
|
|
||||||
|
The system is built modular so support for other devices or actions can
|
||||||
|
be implemented easily. See also the `section on
|
||||||
|
architecture <https://home-assistant.io/developers/architecture.html>`__
|
||||||
|
and the `section on creating your own
|
||||||
|
components <https://home-assistant.io/developers/creating_components.html>`__.
|
||||||
|
|
||||||
|
If you run into issues while using Home Assistant or during development
|
||||||
|
of a component, check the `Home Assistant help
|
||||||
|
section <https://home-assistant.io/help/>`__ how to reach us.
|
||||||
|
|
||||||
|
.. |Build Status| image:: https://travis-ci.org/balloob/home-assistant.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/balloob/home-assistant
|
||||||
|
.. |Coverage Status| image:: https://img.shields.io/coveralls/balloob/home-assistant.svg
|
||||||
|
:target: https://coveralls.io/r/balloob/home-assistant?branch=master
|
||||||
|
.. |Join the chat at https://gitter.im/balloob/home-assistant| image:: https://badges.gitter.im/Join%20Chat.svg
|
||||||
|
:target: https://gitter.im/balloob/home-assistant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||||
|
.. |screenshot-states| image:: https://raw.github.com/balloob/home-assistant/master/docs/screenshots.png
|
||||||
|
:target: https://home-assistant.io/demo/
|
@ -9,11 +9,12 @@ After bootstrapping you can add your own components or
|
|||||||
start by calling homeassistant.start_home_assistant(bus)
|
start by calling homeassistant.start_home_assistant(bus)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
from collections import defaultdict
|
||||||
import sys
|
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
from collections import defaultdict
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
import homeassistant.core as core
|
import homeassistant.core as core
|
||||||
import homeassistant.util.dt as date_util
|
import homeassistant.util.dt as date_util
|
||||||
@ -25,7 +26,7 @@ import homeassistant.components as core_components
|
|||||||
import homeassistant.components.group as group
|
import homeassistant.components.group as group
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.const import (
|
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,
|
CONF_TEMPERATURE_UNIT, CONF_NAME, CONF_TIME_ZONE, CONF_CUSTOMIZE,
|
||||||
TEMP_CELCIUS, TEMP_FAHRENHEIT)
|
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
|
hass.config.config_dir = config_dir
|
||||||
mount_local_lib_path(config_dir)
|
mount_local_lib_path(config_dir)
|
||||||
|
|
||||||
|
process_ha_config_upgrade(hass)
|
||||||
process_ha_core_config(hass, config.get(core.DOMAIN, {}))
|
process_ha_core_config(hass, config.get(core.DOMAIN, {}))
|
||||||
|
|
||||||
if enable_log:
|
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)
|
'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):
|
def process_ha_core_config(hass, config):
|
||||||
""" Processes the [homeassistant] section from the config. """
|
""" Processes the [homeassistant] section from the config. """
|
||||||
hac = hass.config
|
hac = hass.config
|
||||||
|
50
homeassistant/components/binary_sensor/__init__.py
Normal file
50
homeassistant/components/binary_sensor/__init__.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.binary_sensor
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Component to interface with binary sensors (sensors which only know two states)
|
||||||
|
that can be monitored.
|
||||||
|
|
||||||
|
For more details about this component, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/binary_sensor/
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.const import (STATE_ON, STATE_OFF)
|
||||||
|
|
||||||
|
DOMAIN = 'binary_sensor'
|
||||||
|
DEPENDENCIES = []
|
||||||
|
SCAN_INTERVAL = 30
|
||||||
|
|
||||||
|
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||||
|
|
||||||
|
|
||||||
|
def setup(hass, config):
|
||||||
|
""" Track states and offer events for binary sensors. """
|
||||||
|
component = EntityComponent(
|
||||||
|
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)
|
||||||
|
|
||||||
|
component.setup(config)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=no-self-use
|
||||||
|
class BinarySensorDevice(Entity):
|
||||||
|
""" Represents a binary sensor. """
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
""" True if the binary sensor is on. """
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
""" Returns the state of the binary sensor. """
|
||||||
|
return STATE_ON if self.is_on else STATE_OFF
|
||||||
|
|
||||||
|
@property
|
||||||
|
def friendly_state(self):
|
||||||
|
""" Returns the friendly state of the binary sensor. """
|
||||||
|
return None
|
43
homeassistant/components/binary_sensor/demo.py
Normal file
43
homeassistant/components/binary_sensor/demo.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.binary_sensor.demo
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Demo platform that has two fake binary sensors.
|
||||||
|
"""
|
||||||
|
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
""" Sets up the Demo binary sensors. """
|
||||||
|
add_devices([
|
||||||
|
DemoBinarySensor('Window Bathroom', True, None),
|
||||||
|
DemoBinarySensor('Floor Basement', False, None),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class DemoBinarySensor(BinarySensorDevice):
|
||||||
|
""" A Demo binary sensor. """
|
||||||
|
|
||||||
|
def __init__(self, name, state, icon=None):
|
||||||
|
self._name = name
|
||||||
|
self._state = state
|
||||||
|
self._icon = icon
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
""" No polling needed for a demo binary sensor. """
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" Returns the name of the binary sensor. """
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
""" Returns the icon to use for device if any. """
|
||||||
|
return self._icon
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
""" True if the binary sensor is on. """
|
||||||
|
return self._state
|
@ -58,7 +58,7 @@ MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n'
|
|||||||
|
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
""" Track states and offer events for sensors. """
|
""" Track states and offer events for cameras. """
|
||||||
|
|
||||||
component = EntityComponent(
|
component = EntityComponent(
|
||||||
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
|
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
|
||||||
@ -87,7 +87,10 @@ def setup(hass, config):
|
|||||||
|
|
||||||
if camera:
|
if camera:
|
||||||
response = camera.camera_image()
|
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:
|
else:
|
||||||
handler.send_response(HTTP_NOT_FOUND)
|
handler.send_response(HTTP_NOT_FOUND)
|
||||||
|
|
||||||
@ -98,7 +101,8 @@ def setup(hass, config):
|
|||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def _proxy_camera_mjpeg_stream(handler, path_match, data):
|
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
|
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
|
into an MJPEG stream. This means that HA can return a live video
|
||||||
stream even with only a still image URL available.
|
stream even with only a still image URL available.
|
||||||
@ -129,7 +133,8 @@ def setup(hass, config):
|
|||||||
while True:
|
while True:
|
||||||
|
|
||||||
img_bytes = camera.camera_image()
|
img_bytes = camera.camera_image()
|
||||||
|
if img_bytes is None:
|
||||||
|
continue
|
||||||
headers_str = '\r\n'.join((
|
headers_str = '\r\n'.join((
|
||||||
'Content-length: {}'.format(len(img_bytes)),
|
'Content-length: {}'.format(len(img_bytes)),
|
||||||
'Content-type: image/jpeg',
|
'Content-type: image/jpeg',
|
||||||
@ -159,7 +164,7 @@ def setup(hass, config):
|
|||||||
|
|
||||||
|
|
||||||
class Camera(Entity):
|
class Camera(Entity):
|
||||||
""" The base class for camera components """
|
""" The base class for camera components. """
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.is_streaming = False
|
self.is_streaming = False
|
||||||
@ -167,23 +172,23 @@ class Camera(Entity):
|
|||||||
@property
|
@property
|
||||||
# pylint: disable=no-self-use
|
# pylint: disable=no-self-use
|
||||||
def is_recording(self):
|
def is_recording(self):
|
||||||
""" Returns true if the device is recording """
|
""" Returns true if the device is recording. """
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
# pylint: disable=no-self-use
|
# pylint: disable=no-self-use
|
||||||
def brand(self):
|
def brand(self):
|
||||||
""" Should return a string of the camera brand """
|
""" Should return a string of the camera brand. """
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
# pylint: disable=no-self-use
|
# pylint: disable=no-self-use
|
||||||
def model(self):
|
def model(self):
|
||||||
""" Returns string of camera model """
|
""" Returns string of camera model. """
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def camera_image(self):
|
def camera_image(self):
|
||||||
""" Return bytes of camera image """
|
""" Return bytes of camera image. """
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
37
homeassistant/components/camera/demo.py
Normal file
37
homeassistant/components/camera/demo.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.camera.demo
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Demo platform that has a fake camera.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from random import randint
|
||||||
|
from homeassistant.components.camera import Camera
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
""" Sets up the Demo camera. """
|
||||||
|
add_devices([
|
||||||
|
DemoCamera('Demo camera')
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class DemoCamera(Camera):
|
||||||
|
""" A Demo camera. """
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
super().__init__()
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def camera_image(self):
|
||||||
|
""" Return a faked still image response. """
|
||||||
|
|
||||||
|
image_path = os.path.join(os.path.dirname(__file__),
|
||||||
|
'demo_{}.png'.format(randint(1, 5)))
|
||||||
|
with open(image_path, 'rb') as file:
|
||||||
|
output = file.read()
|
||||||
|
return output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" Return the name of this device. """
|
||||||
|
return self._name
|
BIN
homeassistant/components/camera/demo_1.png
Normal file
BIN
homeassistant/components/camera/demo_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
BIN
homeassistant/components/camera/demo_2.png
Normal file
BIN
homeassistant/components/camera/demo_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
BIN
homeassistant/components/camera/demo_3.png
Normal file
BIN
homeassistant/components/camera/demo_3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
BIN
homeassistant/components/camera/demo_4.png
Normal file
BIN
homeassistant/components/camera/demo_4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
BIN
homeassistant/components/camera/demo_5.png
Normal file
BIN
homeassistant/components/camera/demo_5.png
Normal file
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']
|
self._still_image_url = device_info['still_image_url']
|
||||||
|
|
||||||
def camera_image(self):
|
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:
|
if self._username and self._password:
|
||||||
response = requests.get(
|
try:
|
||||||
self._still_image_url,
|
response = requests.get(
|
||||||
auth=HTTPBasicAuth(self._username, self._password))
|
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:
|
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
|
return response.content
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone']
|
|||||||
|
|
||||||
COMPONENTS_WITH_DEMO_PLATFORM = [
|
COMPONENTS_WITH_DEMO_PLATFORM = [
|
||||||
'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor',
|
'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor',
|
||||||
'thermostat']
|
'thermostat', 'camera', 'binary_sensor']
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
|
@ -134,13 +134,16 @@ class AsusWrtDeviceScanner(object):
|
|||||||
for lease in leases_result:
|
for lease in leases_result:
|
||||||
match = _LEASES_REGEX.search(lease.decode('utf-8'))
|
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
|
# For leases where the client doesn't set a hostname, ensure
|
||||||
# it is blank and not '*', which breaks the entity_id down
|
# it is blank and not '*', which breaks the entity_id down
|
||||||
# the line
|
# the line
|
||||||
if match:
|
host = match.group('host')
|
||||||
host = match.group('host')
|
if host == '*':
|
||||||
if host == '*':
|
host = ''
|
||||||
host = ''
|
|
||||||
|
|
||||||
devices[match.group('ip')] = {
|
devices[match.group('ip')] = {
|
||||||
'host': host,
|
'host': host,
|
||||||
@ -151,6 +154,9 @@ class AsusWrtDeviceScanner(object):
|
|||||||
|
|
||||||
for neighbor in neighbors:
|
for neighbor in neighbors:
|
||||||
match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8'))
|
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')
|
devices[match.group('ip')]['status'] = match.group('status')
|
||||||
return devices
|
return devices
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
""" DO NOT MODIFY. Auto-generated by build_frontend script """
|
""" 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
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -22,6 +20,8 @@ DEPENDENCIES = []
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Add device specified by serial number. """
|
""" Add device specified by serial number. """
|
||||||
|
from blinkstick import blinkstick
|
||||||
|
|
||||||
stick = blinkstick.find_by_serial(config['serial'])
|
stick = blinkstick.find_by_serial(config['serial'])
|
||||||
|
|
||||||
add_devices_callback([BlinkStickLight(stick, config['name'])])
|
add_devices_callback([BlinkStickLight(stick, config['name'])])
|
||||||
|
184
homeassistant/components/light/mqtt.py
Normal file
184
homeassistant/components/light/mqtt.py
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.light.mqtt
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Allows to configure a MQTT light.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/light.mqtt/
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import homeassistant.util.color as color_util
|
||||||
|
import homeassistant.components.mqtt as mqtt
|
||||||
|
from homeassistant.components.light import (Light,
|
||||||
|
ATTR_BRIGHTNESS, ATTR_RGB_COLOR)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DEFAULT_NAME = "MQTT Light"
|
||||||
|
DEFAULT_QOS = 0
|
||||||
|
DEFAULT_PAYLOAD_ON = "on"
|
||||||
|
DEFAULT_PAYLOAD_OFF = "off"
|
||||||
|
DEFAULT_RGB_PATTERN = "%d,%d,%d"
|
||||||
|
DEFAULT_OPTIMISTIC = False
|
||||||
|
|
||||||
|
DEPENDENCIES = ['mqtt']
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
|
""" Add MQTT Light. """
|
||||||
|
|
||||||
|
if config.get('command_topic') is None:
|
||||||
|
_LOGGER.error("Missing required variable: command_topic")
|
||||||
|
return False
|
||||||
|
|
||||||
|
add_devices_callback([MqttLight(
|
||||||
|
hass,
|
||||||
|
config.get('name', DEFAULT_NAME),
|
||||||
|
{"state_topic": config.get('state_topic'),
|
||||||
|
"command_topic": config.get('command_topic'),
|
||||||
|
"brightness_state_topic": config.get('brightness_state_topic'),
|
||||||
|
"brightness_command_topic":
|
||||||
|
config.get('brightness_command_topic'),
|
||||||
|
"rgb_state_topic": config.get('rgb_state_topic'),
|
||||||
|
"rgb_command_topic": config.get('rgb_command_topic')},
|
||||||
|
config.get('rgb', None),
|
||||||
|
config.get('qos', DEFAULT_QOS),
|
||||||
|
{"on": config.get('payload_on', DEFAULT_PAYLOAD_ON),
|
||||||
|
"off": config.get('payload_off', DEFAULT_PAYLOAD_OFF)},
|
||||||
|
config.get('brightness'),
|
||||||
|
config.get('optimistic', DEFAULT_OPTIMISTIC))])
|
||||||
|
|
||||||
|
# pylint: disable=too-many-instance-attributes
|
||||||
|
|
||||||
|
|
||||||
|
class MqttLight(Light):
|
||||||
|
""" Provides a MQTT light. """
|
||||||
|
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
|
def __init__(self, hass, name,
|
||||||
|
topic,
|
||||||
|
rgb, qos,
|
||||||
|
payload,
|
||||||
|
brightness, optimistic):
|
||||||
|
|
||||||
|
self._hass = hass
|
||||||
|
self._name = name
|
||||||
|
self._topic = topic
|
||||||
|
self._rgb = rgb
|
||||||
|
self._qos = qos
|
||||||
|
self._payload = payload
|
||||||
|
self._brightness = brightness
|
||||||
|
self._optimistic = optimistic
|
||||||
|
self._state = False
|
||||||
|
self._xy = None
|
||||||
|
|
||||||
|
def message_received(topic, payload, qos):
|
||||||
|
""" A new MQTT message has been received. """
|
||||||
|
if payload == self._payload["on"]:
|
||||||
|
self._state = True
|
||||||
|
elif payload == self._payload["off"]:
|
||||||
|
self._state = False
|
||||||
|
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
|
if self._topic["state_topic"] is None:
|
||||||
|
# force optimistic mode
|
||||||
|
self._optimistic = True
|
||||||
|
else:
|
||||||
|
# Subscribe the state_topic
|
||||||
|
mqtt.subscribe(self._hass, self._topic["state_topic"],
|
||||||
|
message_received, self._qos)
|
||||||
|
|
||||||
|
def brightness_received(topic, payload, qos):
|
||||||
|
""" A new MQTT message for the brightness has been received. """
|
||||||
|
self._brightness = int(payload)
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
|
def rgb_received(topic, payload, qos):
|
||||||
|
""" A new MQTT message has been received. """
|
||||||
|
self._rgb = [int(val) for val in payload.split(',')]
|
||||||
|
self._xy = color_util.color_RGB_to_xy(int(self._rgb[0]),
|
||||||
|
int(self._rgb[1]),
|
||||||
|
int(self._rgb[2]))
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
|
if self._topic["brightness_state_topic"] is not None:
|
||||||
|
mqtt.subscribe(self._hass, self._topic["brightness_state_topic"],
|
||||||
|
brightness_received, self._qos)
|
||||||
|
self._brightness = 255
|
||||||
|
else:
|
||||||
|
self._brightness = None
|
||||||
|
|
||||||
|
if self._topic["rgb_state_topic"] is not None:
|
||||||
|
mqtt.subscribe(self._hass, self._topic["rgb_state_topic"],
|
||||||
|
rgb_received, self._qos)
|
||||||
|
self._xy = [0, 0]
|
||||||
|
else:
|
||||||
|
self._xy = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def brightness(self):
|
||||||
|
""" Brightness of this light between 0..255. """
|
||||||
|
return self._brightness
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rgb_color(self):
|
||||||
|
""" RGB color value. """
|
||||||
|
return self._rgb
|
||||||
|
|
||||||
|
@property
|
||||||
|
def color_xy(self):
|
||||||
|
""" RGB color value. """
|
||||||
|
return self._xy
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
""" No polling needed for a MQTT light. """
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" Returns the name of the device if any. """
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
""" True if device is on. """
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
""" Turn the device on. """
|
||||||
|
|
||||||
|
if ATTR_RGB_COLOR in kwargs and \
|
||||||
|
self._topic["rgb_command_topic"] is not None:
|
||||||
|
self._rgb = kwargs[ATTR_RGB_COLOR]
|
||||||
|
rgb = DEFAULT_RGB_PATTERN % tuple(self._rgb)
|
||||||
|
mqtt.publish(self._hass, self._topic["rgb_command_topic"],
|
||||||
|
rgb, self._qos)
|
||||||
|
|
||||||
|
if ATTR_BRIGHTNESS in kwargs and \
|
||||||
|
self._topic["brightness_command_topic"] is not None:
|
||||||
|
self._brightness = kwargs[ATTR_BRIGHTNESS]
|
||||||
|
mqtt.publish(self._hass, self._topic["brightness_command_topic"],
|
||||||
|
self._brightness, self._qos)
|
||||||
|
|
||||||
|
mqtt.publish(self._hass, self._topic["command_topic"],
|
||||||
|
self._payload["on"], self._qos)
|
||||||
|
|
||||||
|
if self._optimistic:
|
||||||
|
# optimistically assume that switch has changed state
|
||||||
|
self._state = True
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
""" Turn the device off. """
|
||||||
|
mqtt.publish(self._hass, self._topic["command_topic"],
|
||||||
|
self._payload["off"], self._qos)
|
||||||
|
|
||||||
|
if self._optimistic:
|
||||||
|
# optimistically assume that switch has changed state
|
||||||
|
self._state = False
|
||||||
|
self.update_ha_state()
|
@ -8,7 +8,6 @@ https://home-assistant.io/components/light.rfxtrx/
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import homeassistant.components.rfxtrx as rfxtrx
|
import homeassistant.components.rfxtrx as rfxtrx
|
||||||
import RFXtrx as rfxtrxmod
|
|
||||||
|
|
||||||
from homeassistant.components.light import Light
|
from homeassistant.components.light import Light
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
@ -20,6 +19,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Setup the RFXtrx platform. """
|
""" Setup the RFXtrx platform. """
|
||||||
|
import RFXtrx as rfxtrxmod
|
||||||
|
|
||||||
lights = []
|
lights = []
|
||||||
devices = config.get('devices', None)
|
devices = config.get('devices', None)
|
||||||
if devices:
|
if devices:
|
||||||
|
@ -6,13 +6,9 @@ Support for Tellstick lights.
|
|||||||
For more details about this platform, please refer to the documentation at
|
For more details about this platform, please refer to the documentation at
|
||||||
https://home-assistant.io/components/light.tellstick/
|
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.components.light import Light, ATTR_BRIGHTNESS
|
||||||
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP,
|
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP,
|
||||||
ATTR_FRIENDLY_NAME)
|
ATTR_FRIENDLY_NAME)
|
||||||
import tellcore.constants as tellcore_constants
|
|
||||||
from tellcore.library import DirectCallbackDispatcher
|
|
||||||
REQUIREMENTS = ['tellcore-py==1.1.2']
|
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):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Find and return Tellstick lights. """
|
""" Find and return Tellstick lights. """
|
||||||
|
|
||||||
try:
|
import tellcore.telldus as telldus
|
||||||
import tellcore.telldus as telldus
|
from tellcore.library import DirectCallbackDispatcher
|
||||||
except ImportError:
|
import tellcore.constants as tellcore_constants
|
||||||
logging.getLogger(__name__).exception(
|
|
||||||
"Failed to import tellcore")
|
|
||||||
return []
|
|
||||||
|
|
||||||
core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher())
|
core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher())
|
||||||
|
|
||||||
@ -58,17 +51,20 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
|||||||
|
|
||||||
class TellstickLight(Light):
|
class TellstickLight(Light):
|
||||||
""" Represents a Tellstick 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):
|
def __init__(self, tellstick_device):
|
||||||
|
import tellcore.constants as tellcore_constants
|
||||||
|
|
||||||
self.tellstick_device = tellstick_device
|
self.tellstick_device = tellstick_device
|
||||||
self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name}
|
self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name}
|
||||||
self._brightness = 0
|
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
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
""" Returns the name of the switch if any. """
|
""" Returns the name of the switch if any. """
|
||||||
@ -104,6 +100,8 @@ class TellstickLight(Light):
|
|||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
""" Update state of the light. """
|
""" Update state of the light. """
|
||||||
|
import tellcore.constants as tellcore_constants
|
||||||
|
|
||||||
last_command = self.tellstick_device.last_sent_command(
|
last_command = self.tellstick_device.last_sent_command(
|
||||||
self.last_sent_command_mask)
|
self.last_sent_command_mask)
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
homeassistant.components.light.zwave
|
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
|
# pylint: disable=import-error
|
||||||
from openzwave.network import ZWaveNetwork
|
|
||||||
from pydispatch import dispatcher
|
|
||||||
|
|
||||||
import homeassistant.components.zwave as zwave
|
import homeassistant.components.zwave as zwave
|
||||||
|
|
||||||
from homeassistant.const import STATE_ON, STATE_OFF
|
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):
|
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:
|
if discovery_info is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -34,8 +34,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
|
|
||||||
|
|
||||||
def brightness_state(value):
|
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:
|
if value.data > 0:
|
||||||
return (value.data / 99) * 255, STATE_ON
|
return (value.data / 99) * 255, STATE_ON
|
||||||
else:
|
else:
|
||||||
@ -43,9 +45,12 @@ def brightness_state(value):
|
|||||||
|
|
||||||
|
|
||||||
class ZwaveDimmer(Light):
|
class ZwaveDimmer(Light):
|
||||||
""" Provides a zwave dimmer. """
|
""" Provides a Z-Wave dimmer. """
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
|
from openzwave.network import ZWaveNetwork
|
||||||
|
from pydispatch import dispatcher
|
||||||
|
|
||||||
self._value = value
|
self._value = value
|
||||||
self._node = value.node
|
self._node = value.node
|
||||||
|
|
||||||
|
@ -1,30 +1,10 @@
|
|||||||
"""
|
"""
|
||||||
homeassistant.components.logger
|
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
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/logger/
|
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
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
@ -48,7 +28,7 @@ LOGGER_LOGS = 'logs'
|
|||||||
|
|
||||||
|
|
||||||
class HomeAssistantLogFilter(logging.Filter):
|
class HomeAssistantLogFilter(logging.Filter):
|
||||||
"""A Home Assistant log filter"""
|
""" A log filter. """
|
||||||
# pylint: disable=no-init,too-few-public-methods
|
# pylint: disable=no-init,too-few-public-methods
|
||||||
|
|
||||||
def __init__(self, logfilter):
|
def __init__(self, logfilter):
|
||||||
@ -58,7 +38,7 @@ class HomeAssistantLogFilter(logging.Filter):
|
|||||||
|
|
||||||
def filter(self, record):
|
def filter(self, record):
|
||||||
|
|
||||||
# Log with filterd severity
|
# Log with filtered severity
|
||||||
if LOGGER_LOGS in self.logfilter:
|
if LOGGER_LOGS in self.logfilter:
|
||||||
for filtername in self.logfilter[LOGGER_LOGS]:
|
for filtername in self.logfilter[LOGGER_LOGS]:
|
||||||
logseverity = self.logfilter[LOGGER_LOGS][filtername]
|
logseverity = self.logfilter[LOGGER_LOGS][filtername]
|
||||||
@ -82,7 +62,7 @@ def setup(hass, config=None):
|
|||||||
config.get(DOMAIN)[LOGGER_DEFAULT].upper()
|
config.get(DOMAIN)[LOGGER_DEFAULT].upper()
|
||||||
]
|
]
|
||||||
|
|
||||||
# Compute logseverity for components
|
# Compute log severity for components
|
||||||
if LOGGER_LOGS in config.get(DOMAIN):
|
if LOGGER_LOGS in config.get(DOMAIN):
|
||||||
for key, value in config.get(DOMAIN)[LOGGER_LOGS].items():
|
for key, value in config.get(DOMAIN)[LOGGER_LOGS].items():
|
||||||
config.get(DOMAIN)[LOGGER_LOGS][key] = LOGSEVERITY[value.upper()]
|
config.get(DOMAIN)[LOGGER_LOGS][key] = LOGSEVERITY[value.upper()]
|
||||||
|
@ -173,7 +173,7 @@ class SqueezeBoxDevice(MediaPlayerDevice):
|
|||||||
def volume_level(self):
|
def volume_level(self):
|
||||||
""" Volume level of the media player (0..1). """
|
""" Volume level of the media player (0..1). """
|
||||||
if 'mixer volume' in self._status:
|
if 'mixer volume' in self._status:
|
||||||
return int(self._status['mixer volume']) / 100.0
|
return int(float(self._status['mixer volume'])) / 100.0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_volume_muted(self):
|
def is_volume_muted(self):
|
||||||
|
@ -10,8 +10,8 @@ from functools import partial
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import homeassistant.bootstrap as bootstrap
|
||||||
from homeassistant.config import load_yaml_config_file
|
from homeassistant.config import load_yaml_config_file
|
||||||
from homeassistant.loader import get_component
|
|
||||||
from homeassistant.helpers import config_per_platform
|
from homeassistant.helpers import config_per_platform
|
||||||
|
|
||||||
from homeassistant.const import CONF_NAME
|
from homeassistant.const import CONF_NAME
|
||||||
@ -23,6 +23,9 @@ DEPENDENCIES = []
|
|||||||
ATTR_TITLE = "title"
|
ATTR_TITLE = "title"
|
||||||
ATTR_TITLE_DEFAULT = "Home Assistant"
|
ATTR_TITLE_DEFAULT = "Home Assistant"
|
||||||
|
|
||||||
|
# Target of the notification (user, device, etc)
|
||||||
|
ATTR_TARGET = 'target'
|
||||||
|
|
||||||
# Text to notify user of
|
# Text to notify user of
|
||||||
ATTR_MESSAGE = "message"
|
ATTR_MESSAGE = "message"
|
||||||
|
|
||||||
@ -45,8 +48,8 @@ def setup(hass, config):
|
|||||||
|
|
||||||
for platform, p_config in config_per_platform(config, DOMAIN, _LOGGER):
|
for platform, p_config in config_per_platform(config, DOMAIN, _LOGGER):
|
||||||
# get platform
|
# get platform
|
||||||
notify_implementation = get_component(
|
notify_implementation = bootstrap.prepare_setup_platform(
|
||||||
'notify.{}'.format(platform))
|
hass, config, DOMAIN, platform)
|
||||||
|
|
||||||
if notify_implementation is None:
|
if notify_implementation is None:
|
||||||
_LOGGER.error("Unknown notification service specified.")
|
_LOGGER.error("Unknown notification service specified.")
|
||||||
@ -69,8 +72,9 @@ def setup(hass, config):
|
|||||||
return
|
return
|
||||||
|
|
||||||
title = call.data.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
|
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
|
# register service
|
||||||
service_call_handler = partial(notify_message, notify_service)
|
service_call_handler = partial(notify_message, notify_service)
|
||||||
|
@ -8,15 +8,18 @@ https://home-assistant.io/components/notify.pushbullet/
|
|||||||
"""
|
"""
|
||||||
import logging
|
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
|
from homeassistant.const import CONF_API_KEY
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_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):
|
def get_service(hass, config):
|
||||||
""" Get the PushBullet notification service. """
|
""" Get the PushBullet notification service. """
|
||||||
|
from pushbullet import PushBullet
|
||||||
from pushbullet import InvalidKeyError
|
from pushbullet import InvalidKeyError
|
||||||
|
|
||||||
if CONF_API_KEY not in config:
|
if CONF_API_KEY not in config:
|
||||||
@ -24,27 +27,99 @@ def get_service(hass, config):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return PushBulletNotificationService(config[CONF_API_KEY])
|
pushbullet = PushBullet(config[CONF_API_KEY])
|
||||||
|
|
||||||
except InvalidKeyError:
|
except InvalidKeyError:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Wrong API key supplied. "
|
"Wrong API key supplied. "
|
||||||
"Get it at https://www.pushbullet.com/account")
|
"Get it at https://www.pushbullet.com/account")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
return PushBulletNotificationService(pushbullet)
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
class PushBulletNotificationService(BaseNotificationService):
|
class PushBulletNotificationService(BaseNotificationService):
|
||||||
""" Implements notification service for Pushbullet. """
|
""" Implements notification service for Pushbullet. """
|
||||||
|
|
||||||
def __init__(self, api_key):
|
def __init__(self, pb):
|
||||||
from pushbullet import Pushbullet
|
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):
|
pbtargets stores all targets available from this pushbullet instance
|
||||||
""" Send a message to a user. """
|
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)
|
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:
|
title:
|
||||||
description: Optional title for your notification.
|
description: Optional title for your notification.
|
||||||
example: 'Your Garage Door Friend'
|
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"
|
CONF_DELAY = "delay"
|
||||||
|
|
||||||
ATTR_LAST_ACTION = 'last_action'
|
ATTR_LAST_ACTION = 'last_action'
|
||||||
|
ATTR_CAN_CANCEL = 'can_cancel'
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -113,6 +114,8 @@ class Script(ToggleEntity):
|
|||||||
self._cur = -1
|
self._cur = -1
|
||||||
self._last_action = None
|
self._last_action = None
|
||||||
self._listener = None
|
self._listener = None
|
||||||
|
self._can_cancel = not any(CONF_DELAY in action for action
|
||||||
|
in self.sequence)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
@ -126,7 +129,9 @@ class Script(ToggleEntity):
|
|||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
""" Returns the state attributes. """
|
""" Returns the state attributes. """
|
||||||
attrs = {}
|
attrs = {
|
||||||
|
ATTR_CAN_CANCEL: self._can_cancel
|
||||||
|
}
|
||||||
|
|
||||||
if self._last_action:
|
if self._last_action:
|
||||||
attrs[ATTR_LAST_ACTION] = 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.util import Throttle
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.const import STATE_UNKNOWN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEFAULT_NAME = 'Glances Sensor'
|
|
||||||
_RESOURCE = '/api/2/all'
|
_RESOURCE = '/api/2/all'
|
||||||
|
CONF_HOST = 'host'
|
||||||
|
CONF_PORT = '61208'
|
||||||
|
CONF_RESOURCES = 'resources'
|
||||||
SENSOR_TYPES = {
|
SENSOR_TYPES = {
|
||||||
'disk_use_percent': ['Disk Use', '%'],
|
'disk_use_percent': ['Disk Use', '%'],
|
||||||
'disk_use': ['Disk Use', 'GiB'],
|
'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):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
""" Setup the Glances sensor. """
|
""" Setup the Glances sensor. """
|
||||||
|
|
||||||
if not config.get('host'):
|
host = config.get(CONF_HOST)
|
||||||
_LOGGER.error('"host:" is missing your configuration')
|
port = config.get('port', CONF_PORT)
|
||||||
return False
|
|
||||||
|
|
||||||
host = config.get('host')
|
|
||||||
port = config.get('port', 61208)
|
|
||||||
url = 'http://{}:{}{}'.format(host, port, _RESOURCE)
|
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:
|
try:
|
||||||
response = requests.get(url, timeout=10)
|
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)
|
_LOGGER.error('Response status is "%s"', response.status_code)
|
||||||
return False
|
return False
|
||||||
except requests.exceptions.MissingSchema:
|
except requests.exceptions.MissingSchema:
|
||||||
_LOGGER.error('Missing resource or schema in configuration. '
|
_LOGGER.error("Missing resource or schema in configuration. "
|
||||||
'Please heck our details in the configuration file.')
|
"Please check the details in the configuration file.")
|
||||||
return False
|
return False
|
||||||
except requests.exceptions.ConnectionError:
|
except requests.exceptions.ConnectionError:
|
||||||
_LOGGER.error('No route to resource/endpoint. '
|
_LOGGER.error("No route to resource/endpoint: '%s'. "
|
||||||
'Please check the details in the configuration file.')
|
"Please check the details in the configuration file.",
|
||||||
|
url)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
rest = GlancesData(url)
|
rest = GlancesData(url)
|
||||||
|
|
||||||
dev = []
|
dev = []
|
||||||
for resource in config['resources']:
|
for resource in var_conf:
|
||||||
if resource not in SENSOR_TYPES:
|
if resource not in SENSOR_TYPES:
|
||||||
_LOGGER.error('Sensor type: "%s" does not exist', resource)
|
_LOGGER.error('Sensor type: "%s" does not exist', resource)
|
||||||
else:
|
else:
|
||||||
@ -78,13 +84,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
|
|
||||||
|
|
||||||
class GlancesSensor(Entity):
|
class GlancesSensor(Entity):
|
||||||
""" Implements a REST sensor. """
|
""" Implements a Glances sensor. """
|
||||||
|
|
||||||
def __init__(self, rest, sensor_type):
|
def __init__(self, rest, sensor_type):
|
||||||
self.rest = rest
|
self.rest = rest
|
||||||
self._name = SENSOR_TYPES[sensor_type][0]
|
self._name = SENSOR_TYPES[sensor_type][0]
|
||||||
self.type = sensor_type
|
self.type = sensor_type
|
||||||
self._state = None
|
self._state = STATE_UNKNOWN
|
||||||
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
|
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
@ -98,46 +104,49 @@ class GlancesSensor(Entity):
|
|||||||
""" Unit the value is expressed in. """
|
""" Unit the value is expressed in. """
|
||||||
return self._unit_of_measurement
|
return self._unit_of_measurement
|
||||||
|
|
||||||
|
# pylint: disable=too-many-branches, too-many-return-statements
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
""" Returns the state of the device. """
|
""" Returns the state of the resources. """
|
||||||
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()
|
|
||||||
value = self.rest.data
|
value = self.rest.data
|
||||||
|
|
||||||
if value is not None:
|
if value is not None:
|
||||||
if self.type == 'disk_use_percent':
|
if self.type == 'disk_use_percent':
|
||||||
self._state = value['fs'][0]['percent']
|
return value['fs'][0]['percent']
|
||||||
elif self.type == 'disk_use':
|
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':
|
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':
|
elif self.type == 'memory_use_percent':
|
||||||
self._state = value['mem']['percent']
|
return value['mem']['percent']
|
||||||
elif self.type == 'memory_use':
|
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':
|
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':
|
elif self.type == 'swap_use_percent':
|
||||||
self._state = value['memswap']['percent']
|
return value['memswap']['percent']
|
||||||
elif self.type == 'swap_use':
|
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':
|
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':
|
elif self.type == 'processor_load':
|
||||||
self._state = value['load']['min15']
|
return value['load']['min15']
|
||||||
elif self.type == 'process_running':
|
elif self.type == 'process_running':
|
||||||
self._state = value['processcount']['running']
|
return value['processcount']['running']
|
||||||
elif self.type == 'process_total':
|
elif self.type == 'process_total':
|
||||||
self._state = value['processcount']['total']
|
return value['processcount']['total']
|
||||||
elif self.type == 'process_thread':
|
elif self.type == 'process_thread':
|
||||||
self._state = value['processcount']['thread']
|
return value['processcount']['thread']
|
||||||
elif self.type == 'process_sleeping':
|
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
|
# pylint: disable=too-few-public-methods
|
||||||
@ -145,15 +154,16 @@ class GlancesData(object):
|
|||||||
""" Class for handling the data retrieval. """
|
""" Class for handling the data retrieval. """
|
||||||
|
|
||||||
def __init__(self, resource):
|
def __init__(self, resource):
|
||||||
self.resource = resource
|
self._resource = resource
|
||||||
self.data = dict()
|
self.data = dict()
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
def update(self):
|
def update(self):
|
||||||
""" Gets the latest data from REST service. """
|
""" Gets the latest data from the Glances REST API. """
|
||||||
try:
|
try:
|
||||||
response = requests.get(self.resource, timeout=10)
|
response = requests.get(self._resource, timeout=10)
|
||||||
self.data = response.json()
|
self.data = response.json()
|
||||||
except requests.exceptions.ConnectionError:
|
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
|
self.data = None
|
||||||
|
@ -11,7 +11,6 @@ from collections import OrderedDict
|
|||||||
|
|
||||||
from homeassistant.const import (TEMP_CELCIUS)
|
from homeassistant.const import (TEMP_CELCIUS)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from RFXtrx import SensorEvent
|
|
||||||
import homeassistant.components.rfxtrx as rfxtrx
|
import homeassistant.components.rfxtrx as rfxtrx
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
@ -28,6 +27,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Setup the RFXtrx platform. """
|
""" Setup the RFXtrx platform. """
|
||||||
|
from RFXtrx import SensorEvent
|
||||||
|
|
||||||
def sensor_update(event):
|
def sensor_update(event):
|
||||||
""" Callback for sensor updates from the RFXtrx gateway. """
|
""" Callback for sensor updates from the RFXtrx gateway. """
|
||||||
|
@ -9,9 +9,6 @@ https://home-assistant.io/components/sensor.tellstick/
|
|||||||
import logging
|
import logging
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
import tellcore.telldus as telldus
|
|
||||||
import tellcore.constants as tellcore_constants
|
|
||||||
|
|
||||||
from homeassistant.const import TEMP_CELCIUS
|
from homeassistant.const import TEMP_CELCIUS
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
import homeassistant.util as util
|
import homeassistant.util as util
|
||||||
@ -24,6 +21,9 @@ REQUIREMENTS = ['tellcore-py==1.1.2']
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
""" Sets up Tellstick sensors. """
|
""" Sets up Tellstick sensors. """
|
||||||
|
import tellcore.telldus as telldus
|
||||||
|
import tellcore.constants as tellcore_constants
|
||||||
|
|
||||||
sensor_value_descriptions = {
|
sensor_value_descriptions = {
|
||||||
tellcore_constants.TELLSTICK_TEMPERATURE:
|
tellcore_constants.TELLSTICK_TEMPERATURE:
|
||||||
DatatypeDescription(
|
DatatypeDescription(
|
||||||
|
@ -11,10 +11,6 @@ from datetime import timedelta
|
|||||||
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
||||||
|
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
# pylint: disable=no-name-in-module, import-error
|
|
||||||
import transmissionrpc
|
|
||||||
|
|
||||||
from transmissionrpc.error import TransmissionError
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -33,6 +29,9 @@ _THROTTLED_REFRESH = None
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
""" Sets up the Transmission sensors. """
|
""" Sets up the Transmission sensors. """
|
||||||
|
import transmissionrpc
|
||||||
|
from transmissionrpc.error import TransmissionError
|
||||||
|
|
||||||
host = config.get(CONF_HOST)
|
host = config.get(CONF_HOST)
|
||||||
username = config.get(CONF_USERNAME, None)
|
username = config.get(CONF_USERNAME, None)
|
||||||
password = config.get(CONF_PASSWORD, None)
|
password = config.get(CONF_PASSWORD, None)
|
||||||
@ -97,6 +96,8 @@ class TransmissionSensor(Entity):
|
|||||||
|
|
||||||
def refresh_transmission_data(self):
|
def refresh_transmission_data(self):
|
||||||
""" Calls the throttled Transmission refresh method. """
|
""" Calls the throttled Transmission refresh method. """
|
||||||
|
from transmissionrpc.error import TransmissionError
|
||||||
|
|
||||||
if _THROTTLED_REFRESH is not None:
|
if _THROTTLED_REFRESH is not None:
|
||||||
try:
|
try:
|
||||||
_THROTTLED_REFRESH()
|
_THROTTLED_REFRESH()
|
||||||
|
@ -15,9 +15,9 @@ from homeassistant.const import (
|
|||||||
ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME,
|
ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME,
|
||||||
TEMP_CELCIUS, TEMP_FAHRENHEIT)
|
TEMP_CELCIUS, TEMP_FAHRENHEIT)
|
||||||
|
|
||||||
REQUIREMENTS = ['https://github.com/balloob/home-assistant-vera-api/archive/'
|
REQUIREMENTS = ['https://github.com/pavoni/home-assistant-vera-api/archive/'
|
||||||
'a8f823066ead6c7da6fb5e7abaf16fef62e63364.zip'
|
'efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip'
|
||||||
'#python-vera==0.1']
|
'#python-vera==0.1.1']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ at https://home-assistant.io/components/zwave/
|
|||||||
"""
|
"""
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
from homeassistant.helpers.event import track_point_in_time
|
from homeassistant.helpers.event import track_point_in_time
|
||||||
from openzwave.network import ZWaveNetwork
|
|
||||||
from pydispatch import dispatcher
|
|
||||||
import datetime
|
import datetime
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
import homeassistant.components.zwave as zwave
|
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:
|
elif value.command_class == zwave.COMMAND_CLASS_SENSOR_MULTILEVEL:
|
||||||
add_devices([ZWaveMultilevelSensor(value)])
|
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):
|
class ZWaveSensor(Entity):
|
||||||
""" Represents a Z-Wave sensor. """
|
""" Represents a Z-Wave sensor. """
|
||||||
|
|
||||||
def __init__(self, sensor_value):
|
def __init__(self, sensor_value):
|
||||||
|
from openzwave.network import ZWaveNetwork
|
||||||
|
from pydispatch import dispatcher
|
||||||
|
|
||||||
self._value = sensor_value
|
self._value = sensor_value
|
||||||
self._node = sensor_value.node
|
self._node = sensor_value.node
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@ from homeassistant.helpers.entity import ToggleEntity
|
|||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
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'
|
DOMAIN = 'switch'
|
||||||
DEPENDENCIES = []
|
DEPENDENCIES = []
|
||||||
@ -38,7 +39,8 @@ DISCOVERY_PLATFORMS = {
|
|||||||
discovery.SERVICE_WEMO: 'wemo',
|
discovery.SERVICE_WEMO: 'wemo',
|
||||||
wink.DISCOVER_SWITCHES: 'wink',
|
wink.DISCOVER_SWITCHES: 'wink',
|
||||||
isy994.DISCOVER_SWITCHES: 'isy994',
|
isy994.DISCOVER_SWITCHES: 'isy994',
|
||||||
verisure.DISCOVER_SWITCHES: 'verisure'
|
verisure.DISCOVER_SWITCHES: 'verisure',
|
||||||
|
zwave.DISCOVER_SWITCHES: 'zwave',
|
||||||
}
|
}
|
||||||
|
|
||||||
PROP_TO_ATTR = {
|
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
|
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
try:
|
|
||||||
import hikvision.api
|
|
||||||
from hikvision.error import HikvisionError, MissingParamError
|
|
||||||
except ImportError:
|
|
||||||
hikvision.api = None
|
|
||||||
|
|
||||||
_LOGGING = logging.getLogger(__name__)
|
_LOGGING = logging.getLogger(__name__)
|
||||||
REQUIREMENTS = ['hikvision==0.4']
|
REQUIREMENTS = ['hikvision==0.4']
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
@ -25,6 +19,8 @@ REQUIREMENTS = ['hikvision==0.4']
|
|||||||
|
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Setup Hikvision camera. """
|
""" Setup Hikvision camera. """
|
||||||
|
import hikvision.api
|
||||||
|
from hikvision.error import HikvisionError, MissingParamError
|
||||||
|
|
||||||
host = config.get(CONF_HOST, None)
|
host = config.get(CONF_HOST, None)
|
||||||
port = config.get('port', "80")
|
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")
|
username = config.get(CONF_USERNAME, "admin")
|
||||||
password = config.get(CONF_PASSWORD, "12345")
|
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:
|
try:
|
||||||
hikvision_cam = hikvision.api.CreateDevice(
|
hikvision_cam = hikvision.api.CreateDevice(
|
||||||
host, port=port, username=username,
|
host, port=port, username=username,
|
||||||
|
78
homeassistant/components/switch/orvibo.py
Normal file
78
homeassistant/components/switch/orvibo.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.switch.orvibo
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Support for Orvibo S20 Wifi Smart Switches.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/switch.orvibo/
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.components.switch import SwitchDevice
|
||||||
|
|
||||||
|
DEFAULT_NAME = "Orvibo S20 Switch"
|
||||||
|
REQUIREMENTS = ['orvibo==1.0.0']
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
|
""" Find and return S20 switches. """
|
||||||
|
from orvibo.s20 import S20, S20Exception
|
||||||
|
|
||||||
|
if config.get('host') is None:
|
||||||
|
_LOGGER.error("Missing required variable: host")
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
s20 = S20(config.get('host'))
|
||||||
|
add_devices_callback([S20Switch(config.get('name', DEFAULT_NAME),
|
||||||
|
s20)])
|
||||||
|
except S20Exception:
|
||||||
|
_LOGGER.exception("S20 couldn't be initialized")
|
||||||
|
|
||||||
|
|
||||||
|
class S20Switch(SwitchDevice):
|
||||||
|
""" Represents an S20 switch. """
|
||||||
|
def __init__(self, name, s20):
|
||||||
|
from orvibo.s20 import S20Exception
|
||||||
|
|
||||||
|
self._name = name
|
||||||
|
self._s20 = s20
|
||||||
|
self._state = False
|
||||||
|
self._exc = S20Exception
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
""" Poll. """
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" The name of the switch. """
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
""" True if device is on. """
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
""" Update device state. """
|
||||||
|
try:
|
||||||
|
self._state = self._s20.on
|
||||||
|
except self._exc:
|
||||||
|
_LOGGER.exception("Error while fetching S20 state")
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
""" Turn the device on. """
|
||||||
|
try:
|
||||||
|
self._s20.on = True
|
||||||
|
except self._exc:
|
||||||
|
_LOGGER.exception("Error while turning on S20")
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
""" Turn the device off. """
|
||||||
|
try:
|
||||||
|
self._s20.on = False
|
||||||
|
except self._exc:
|
||||||
|
_LOGGER.exception("Error while turning off S20")
|
@ -8,7 +8,6 @@ https://home-assistant.io/components/switch.rfxtrx/
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import homeassistant.components.rfxtrx as rfxtrx
|
import homeassistant.components.rfxtrx as rfxtrx
|
||||||
from RFXtrx import LightingDevice
|
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchDevice
|
from homeassistant.components.switch import SwitchDevice
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
@ -20,6 +19,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Setup the RFXtrx platform. """
|
""" Setup the RFXtrx platform. """
|
||||||
|
from RFXtrx import LightingDevice
|
||||||
|
|
||||||
# Add switch from config file
|
# Add switch from config file
|
||||||
switchs = []
|
switchs = []
|
||||||
|
@ -11,8 +11,6 @@ import logging
|
|||||||
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP,
|
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP,
|
||||||
ATTR_FRIENDLY_NAME)
|
ATTR_FRIENDLY_NAME)
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
import tellcore.constants as tellcore_constants
|
|
||||||
from tellcore.library import DirectCallbackDispatcher
|
|
||||||
|
|
||||||
SIGNAL_REPETITIONS = 1
|
SIGNAL_REPETITIONS = 1
|
||||||
REQUIREMENTS = ['tellcore-py==1.1.2']
|
REQUIREMENTS = ['tellcore-py==1.1.2']
|
||||||
@ -22,11 +20,9 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Find and return Tellstick switches. """
|
""" Find and return Tellstick switches. """
|
||||||
try:
|
import tellcore.telldus as telldus
|
||||||
import tellcore.telldus as telldus
|
import tellcore.constants as tellcore_constants
|
||||||
except ImportError:
|
from tellcore.library import DirectCallbackDispatcher
|
||||||
_LOGGER.exception("Failed to import tellcore")
|
|
||||||
return
|
|
||||||
|
|
||||||
core = telldus.TelldusCore(callback_dispatcher=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):
|
class TellstickSwitchDevice(ToggleEntity):
|
||||||
""" Represents a Tellstick switch. """
|
""" Represents a Tellstick switch. """
|
||||||
last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
|
|
||||||
tellcore_constants.TELLSTICK_TURNOFF)
|
|
||||||
|
|
||||||
def __init__(self, tellstick_device, signal_repetitions):
|
def __init__(self, tellstick_device, signal_repetitions):
|
||||||
|
import tellcore.constants as tellcore_constants
|
||||||
|
|
||||||
self.tellstick_device = tellstick_device
|
self.tellstick_device = tellstick_device
|
||||||
self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name}
|
self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name}
|
||||||
self.signal_repetitions = signal_repetitions
|
self.signal_repetitions = signal_repetitions
|
||||||
|
|
||||||
|
self.last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
|
||||||
|
tellcore_constants.TELLSTICK_TURNOFF)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
""" Tells Home Assistant not to poll this entity. """
|
""" Tells Home Assistant not to poll this entity. """
|
||||||
@ -88,6 +87,8 @@ class TellstickSwitchDevice(ToggleEntity):
|
|||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
""" True if switch is on. """
|
""" True if switch is on. """
|
||||||
|
import tellcore.constants as tellcore_constants
|
||||||
|
|
||||||
last_command = self.tellstick_device.last_sent_command(
|
last_command = self.tellstick_device.last_sent_command(
|
||||||
self.last_sent_command_mask)
|
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.const import STATE_ON, STATE_OFF
|
||||||
|
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
# pylint: disable=no-name-in-module, import-error
|
|
||||||
import transmissionrpc
|
|
||||||
from transmissionrpc.error import TransmissionError
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
_LOGGING = logging.getLogger(__name__)
|
_LOGGING = logging.getLogger(__name__)
|
||||||
@ -22,6 +19,9 @@ REQUIREMENTS = ['transmissionrpc==0.11']
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Sets up the transmission sensor. """
|
""" Sets up the transmission sensor. """
|
||||||
|
import transmissionrpc
|
||||||
|
from transmissionrpc.error import TransmissionError
|
||||||
|
|
||||||
host = config.get(CONF_HOST)
|
host = config.get(CONF_HOST)
|
||||||
username = config.get(CONF_USERNAME, None)
|
username = config.get(CONF_USERNAME, None)
|
||||||
password = config.get(CONF_PASSWORD, None)
|
password = config.get(CONF_PASSWORD, None)
|
||||||
|
76
homeassistant/components/switch/zwave.py
Normal file
76
homeassistant/components/switch/zwave.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.switch.zwave
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Zwave platform that handles simple binary switches.
|
||||||
|
"""
|
||||||
|
# pylint: disable=import-error
|
||||||
|
|
||||||
|
import homeassistant.components.zwave as zwave
|
||||||
|
|
||||||
|
from homeassistant.components.switch import SwitchDevice
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
""" Find and return demo switches. """
|
||||||
|
if discovery_info is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
node = zwave.NETWORK.nodes[discovery_info[zwave.ATTR_NODE_ID]]
|
||||||
|
value = node.values[discovery_info[zwave.ATTR_VALUE_ID]]
|
||||||
|
|
||||||
|
if value.command_class != zwave.COMMAND_CLASS_SWITCH_BINARY:
|
||||||
|
return
|
||||||
|
if value.type != zwave.TYPE_BOOL:
|
||||||
|
return
|
||||||
|
if value.genre != zwave.GENRE_USER:
|
||||||
|
return
|
||||||
|
|
||||||
|
value.set_change_verified(False)
|
||||||
|
add_devices([ZwaveSwitch(value)])
|
||||||
|
|
||||||
|
|
||||||
|
class ZwaveSwitch(SwitchDevice):
|
||||||
|
""" Provides a zwave switch. """
|
||||||
|
def __init__(self, value):
|
||||||
|
from openzwave.network import ZWaveNetwork
|
||||||
|
from pydispatch import dispatcher
|
||||||
|
|
||||||
|
self._value = value
|
||||||
|
self._node = value.node
|
||||||
|
|
||||||
|
self._state = value.data
|
||||||
|
dispatcher.connect(
|
||||||
|
self._value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED)
|
||||||
|
|
||||||
|
def _value_changed(self, value):
|
||||||
|
""" Called when a value has changed on the network. """
|
||||||
|
if self._value.value_id == value.value_id:
|
||||||
|
self._state = value.data
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
""" No polling needed for a demo switch. """
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" Returns the name of the device if any. """
|
||||||
|
name = self._node.name or "{}".format(self._node.product_name)
|
||||||
|
|
||||||
|
return "{}".format(name or self._value.label)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
""" True if device is on. """
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
""" Turn the device on. """
|
||||||
|
self._node.set_switch(self._value.value_id, True)
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
""" Turn the device off. """
|
||||||
|
self._node.set_switch(self._value.value_id, False)
|
57
homeassistant/components/updater.py
Normal file
57
homeassistant/components/updater.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.updater
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Component that checks for available updates.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
at https://home-assistant.io/components/updater/
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from homeassistant.const import __version__ as CURRENT_VERSION
|
||||||
|
from homeassistant.const import ATTR_FRIENDLY_NAME
|
||||||
|
from homeassistant.helpers import event
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
PYPI_URL = 'https://pypi.python.org/pypi/homeassistant/json'
|
||||||
|
DEPENDENCIES = []
|
||||||
|
DOMAIN = 'updater'
|
||||||
|
ENTITY_ID = 'updater.updater'
|
||||||
|
|
||||||
|
|
||||||
|
def setup(hass, config):
|
||||||
|
""" Setup the updater component. """
|
||||||
|
|
||||||
|
def check_newest_version(_=None):
|
||||||
|
""" Check if a new version is available and report if one is. """
|
||||||
|
newest = get_newest_version()
|
||||||
|
|
||||||
|
if newest != CURRENT_VERSION and newest is not None:
|
||||||
|
hass.states.set(
|
||||||
|
ENTITY_ID, newest, {ATTR_FRIENDLY_NAME: 'Update Available'})
|
||||||
|
|
||||||
|
event.track_time_change(hass, check_newest_version,
|
||||||
|
hour=[0, 12], minute=0, second=0)
|
||||||
|
|
||||||
|
check_newest_version()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_newest_version():
|
||||||
|
""" Get the newest Home Assistant version from PyPI. """
|
||||||
|
try:
|
||||||
|
req = requests.get(PYPI_URL)
|
||||||
|
|
||||||
|
return req.json()['info']['version']
|
||||||
|
except requests.RequestException:
|
||||||
|
_LOGGER.exception('Could not contact PyPI to check for updates')
|
||||||
|
return
|
||||||
|
except ValueError:
|
||||||
|
_LOGGER.exception('Received invalid response from PyPI')
|
||||||
|
return
|
||||||
|
except KeyError:
|
||||||
|
_LOGGER.exception('Response from PyPI did not include version')
|
||||||
|
return
|
@ -6,6 +6,9 @@ Connects Home Assistant to a Z-Wave network.
|
|||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/zwave/
|
https://home-assistant.io/components/zwave/
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
from homeassistant import bootstrap
|
from homeassistant import bootstrap
|
||||||
@ -20,13 +23,20 @@ REQUIREMENTS = ['pydispatcher==2.0.5']
|
|||||||
CONF_USB_STICK_PATH = "usb_path"
|
CONF_USB_STICK_PATH = "usb_path"
|
||||||
DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick"
|
DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick"
|
||||||
CONF_DEBUG = "debug"
|
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_SENSORS = "zwave.sensors"
|
||||||
|
DISCOVER_SWITCHES = "zwave.switch"
|
||||||
DISCOVER_LIGHTS = "zwave.light"
|
DISCOVER_LIGHTS = "zwave.light"
|
||||||
|
|
||||||
COMMAND_CLASS_SWITCH_MULTILEVEL = 38
|
COMMAND_CLASS_SWITCH_MULTILEVEL = 38
|
||||||
|
|
||||||
|
COMMAND_CLASS_SWITCH_BINARY = 37
|
||||||
COMMAND_CLASS_SENSOR_BINARY = 48
|
COMMAND_CLASS_SENSOR_BINARY = 48
|
||||||
COMMAND_CLASS_SENSOR_MULTILEVEL = 49
|
COMMAND_CLASS_SENSOR_MULTILEVEL = 49
|
||||||
|
COMMAND_CLASS_METER = 50
|
||||||
COMMAND_CLASS_BATTERY = 128
|
COMMAND_CLASS_BATTERY = 128
|
||||||
|
|
||||||
GENRE_WHATEVER = None
|
GENRE_WHATEVER = None
|
||||||
@ -35,20 +45,28 @@ GENRE_USER = "User"
|
|||||||
TYPE_WHATEVER = None
|
TYPE_WHATEVER = None
|
||||||
TYPE_BYTE = "Byte"
|
TYPE_BYTE = "Byte"
|
||||||
TYPE_BOOL = "Bool"
|
TYPE_BOOL = "Bool"
|
||||||
|
TYPE_DECIMAL = "Decimal"
|
||||||
|
|
||||||
# list of tuple (DOMAIN, discovered service, supported command
|
# list of tuple (DOMAIN, discovered service, supported command
|
||||||
# classes, value type)
|
# classes, value type)
|
||||||
DISCOVERY_COMPONENTS = [
|
DISCOVERY_COMPONENTS = [
|
||||||
('sensor',
|
('sensor',
|
||||||
DISCOVER_SENSORS,
|
DISCOVER_SENSORS,
|
||||||
[COMMAND_CLASS_SENSOR_BINARY, COMMAND_CLASS_SENSOR_MULTILEVEL],
|
[COMMAND_CLASS_SENSOR_BINARY,
|
||||||
|
COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||||
|
COMMAND_CLASS_METER],
|
||||||
TYPE_WHATEVER,
|
TYPE_WHATEVER,
|
||||||
GENRE_WHATEVER),
|
GENRE_USER),
|
||||||
('light',
|
('light',
|
||||||
DISCOVER_LIGHTS,
|
DISCOVER_LIGHTS,
|
||||||
[COMMAND_CLASS_SWITCH_MULTILEVEL],
|
[COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||||
TYPE_BYTE,
|
TYPE_BYTE,
|
||||||
GENRE_USER),
|
GENRE_USER),
|
||||||
|
('switch',
|
||||||
|
DISCOVER_SWITCHES,
|
||||||
|
[COMMAND_CLASS_SWITCH_BINARY],
|
||||||
|
TYPE_BOOL,
|
||||||
|
GENRE_USER),
|
||||||
]
|
]
|
||||||
|
|
||||||
ATTR_NODE_ID = "node_id"
|
ATTR_NODE_ID = "node_id"
|
||||||
@ -107,7 +125,9 @@ def setup(hass, config):
|
|||||||
# Setup options
|
# Setup options
|
||||||
options = ZWaveOption(
|
options = ZWaveOption(
|
||||||
config[DOMAIN].get(CONF_USB_STICK_PATH, DEFAULT_CONF_USB_STICK_PATH),
|
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.set_console_output(use_debug)
|
||||||
options.lock()
|
options.lock()
|
||||||
@ -165,6 +185,10 @@ def setup(hass, config):
|
|||||||
""" Called when Home Assistant starts up. """
|
""" Called when Home Assistant starts up. """
|
||||||
NETWORK.start()
|
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_STOP, stop_zwave)
|
||||||
|
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)
|
||||||
|
@ -32,6 +32,7 @@ DEFAULT_CONFIG = (
|
|||||||
DEFAULT_COMPONENTS = {
|
DEFAULT_COMPONENTS = {
|
||||||
'introduction': 'Show links to resources in log and frontend',
|
'introduction': 'Show links to resources in log and frontend',
|
||||||
'frontend': 'Enables the frontend',
|
'frontend': 'Enables the frontend',
|
||||||
|
'updater': 'Checks for available updates',
|
||||||
'discovery': 'Discover some devices automatically',
|
'discovery': 'Discover some devices automatically',
|
||||||
'conversation': 'Allows you to issue voice commands from the frontend',
|
'conversation': 'Allows you to issue voice commands from the frontend',
|
||||||
'history': 'Enables support for tracking state changes over time.',
|
'history': 'Enables support for tracking state changes over time.',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
""" Constants used by Home Assistant components. """
|
""" 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.
|
# Can be used to specify a catch all when registering state or event listeners.
|
||||||
MATCH_ALL = '*'
|
MATCH_ALL = '*'
|
||||||
|
@ -84,7 +84,7 @@ class HomeAssistant(object):
|
|||||||
|
|
||||||
if os.name != "nt":
|
if os.name != "nt":
|
||||||
try:
|
try:
|
||||||
signal.signal(signal.SIGQUIT, stop_homeassistant)
|
signal.signal(signal.SIGTERM, stop_homeassistant)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
'Could not bind to SIGQUIT. Are you running in a thread?')
|
'Could not bind to SIGQUIT. Are you running in a thread?')
|
||||||
|
@ -29,6 +29,7 @@ def install_package(package, upgrade=True, target=None):
|
|||||||
try:
|
try:
|
||||||
return 0 == subprocess.call(args)
|
return 0 == subprocess.call(args)
|
||||||
except subprocess.SubprocessError:
|
except subprocess.SubprocessError:
|
||||||
|
_LOGGER.exception('Unable to install pacakge %s', package)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,158 +1,166 @@
|
|||||||
# Required for Home Assistant core
|
# Home Assistant core
|
||||||
requests>=2,<3
|
requests>=2,<3
|
||||||
pyyaml>=3.11,<4
|
pyyaml>=3.11,<4
|
||||||
pytz>=2015.4
|
pytz>=2015.4
|
||||||
pip>=7.0.0
|
pip>=7.0.0
|
||||||
vincenty==0.1.3
|
vincenty==0.1.3
|
||||||
|
|
||||||
# Optional, needed for specific components
|
# homeassistant.components.arduino
|
||||||
|
|
||||||
# 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)
|
|
||||||
PyMata==2.07a
|
PyMata==2.07a
|
||||||
|
|
||||||
# Rfxtrx (rfxtrx)
|
# homeassistant.components.device_tracker.netgear
|
||||||
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)
|
|
||||||
pynetgear==0.3
|
pynetgear==0.3
|
||||||
|
|
||||||
# Netdisco (discovery)
|
# homeassistant.components.device_tracker.nmap_tracker
|
||||||
netdisco==0.5.1
|
python-nmap==0.4.3
|
||||||
|
|
||||||
# Wemo (switch.wemo)
|
# homeassistant.components.device_tracker.snmp
|
||||||
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)
|
|
||||||
pysnmp==4.2.5
|
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
|
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
|
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
|
py-cpuinfo==0.1.6
|
||||||
|
|
||||||
# Radio Thermostat (thermostat.radiotherm)
|
# homeassistant.components.sensor.dht
|
||||||
radiotherm==1.2
|
# 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
|
evohomeclient==0.2.3
|
||||||
|
|
||||||
# Pushetta (notify.pushetta)
|
# homeassistant.components.thermostat.nest
|
||||||
pushetta==1.0.15
|
python-nest==2.6.0
|
||||||
|
|
||||||
|
# homeassistant.components.thermostat.radiotherm
|
||||||
|
radiotherm==1.2
|
||||||
|
|
||||||
|
# homeassistant.components.verisure
|
||||||
|
https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60f7f35854390d59be.zip#python-verisure==0.2.6
|
||||||
|
|
||||||
|
# homeassistant.components.zwave
|
||||||
|
pydispatcher==2.0.5
|
||||||
|
|
||||||
|
90
script/gen_requirements_all.py
Executable file
90
script/gen_requirements_all.py
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Generate an updated requirements_all.txt
|
||||||
|
"""
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
import re
|
||||||
|
|
||||||
|
COMMENT_REQUIREMENTS = [
|
||||||
|
'RPi.GPIO',
|
||||||
|
'Adafruit_Python_DHT'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def explore_module(package, explore_children):
|
||||||
|
module = importlib.import_module(package)
|
||||||
|
|
||||||
|
found = []
|
||||||
|
|
||||||
|
if not hasattr(module, '__path__'):
|
||||||
|
return found
|
||||||
|
|
||||||
|
for _, name, ispkg in pkgutil.iter_modules(module.__path__, package + '.'):
|
||||||
|
found.append(name)
|
||||||
|
|
||||||
|
if explore_children:
|
||||||
|
found.extend(explore_module(name, False))
|
||||||
|
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
def core_requirements():
|
||||||
|
with open('setup.py') as inp:
|
||||||
|
reqs_raw = re.search(
|
||||||
|
r'REQUIRES = \[(.*?)\]', inp.read(), re.S).group(1)
|
||||||
|
|
||||||
|
return re.findall(r"'(.*?)'", reqs_raw)
|
||||||
|
|
||||||
|
|
||||||
|
def comment_requirement(req):
|
||||||
|
""" Some requirements don't install on all systems. """
|
||||||
|
return any(ign in req for ign in COMMENT_REQUIREMENTS)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not os.path.isfile('requirements_all.txt'):
|
||||||
|
print('Run this from HA root dir')
|
||||||
|
return
|
||||||
|
|
||||||
|
reqs = OrderedDict()
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
for package in sorted(explore_module('homeassistant.components', True)):
|
||||||
|
try:
|
||||||
|
module = importlib.import_module(package)
|
||||||
|
except ImportError:
|
||||||
|
errors.append(package)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not getattr(module, 'REQUIREMENTS', None):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for req in module.REQUIREMENTS:
|
||||||
|
reqs.setdefault(req, []).append(package)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print("Found errors")
|
||||||
|
print('\n'.join(errors))
|
||||||
|
return
|
||||||
|
|
||||||
|
print('# Home Assistant core')
|
||||||
|
print('\n'.join(core_requirements()))
|
||||||
|
print()
|
||||||
|
|
||||||
|
for pkg, requirements in reqs.items():
|
||||||
|
for req in sorted(requirements,
|
||||||
|
key=lambda name: (len(name.split('.')), name)):
|
||||||
|
print('#', req)
|
||||||
|
|
||||||
|
if comment_requirement(pkg):
|
||||||
|
print('#', pkg)
|
||||||
|
else:
|
||||||
|
print(pkg)
|
||||||
|
print()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -53,7 +53,7 @@ stop() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
echo 'Stopping service…' >&2
|
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;
|
while ps -p $(cat "$PID_FILE") > /dev/null 2>&1; do sleep 1;done;
|
||||||
echo 'Service stopped' >&2
|
echo 'Service stopped' >&2
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ Type=simple
|
|||||||
User=%i
|
User=%i
|
||||||
WorkingDirectory=%h
|
WorkingDirectory=%h
|
||||||
ExecStart=/usr/bin/hass --config %h/.homeassistant/
|
ExecStart=/usr/bin/hass --config %h/.homeassistant/
|
||||||
|
SendSIGKILL=no
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
0
tests/components/light/__init__.py
Normal file
0
tests/components/light/__init__.py
Normal file
153
tests/components/light/test_mqtt.py
Normal file
153
tests/components/light/test_mqtt.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
"""
|
||||||
|
tests.components.light.test_mqtt
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests mqtt light.
|
||||||
|
|
||||||
|
config for RGB Version with brightness:
|
||||||
|
|
||||||
|
light:
|
||||||
|
platform: mqtt
|
||||||
|
name: "Office Light RGB"
|
||||||
|
state_topic: "office/rgb1/light/status"
|
||||||
|
command_topic: "office/rgb1/light/switch"
|
||||||
|
brightness_state_topic: "office/rgb1/brightness/status"
|
||||||
|
brightness_command_topic: "office/rgb1/brightness/set"
|
||||||
|
rgb_state_topic: "office/rgb1/rgb/status"
|
||||||
|
rgb_command_topic: "office/rgb1/rgb/set"
|
||||||
|
qos: 0
|
||||||
|
payload_on: "on"
|
||||||
|
payload_off: "off"
|
||||||
|
|
||||||
|
config without RGB:
|
||||||
|
|
||||||
|
light:
|
||||||
|
platform: mqtt
|
||||||
|
name: "Office Light"
|
||||||
|
state_topic: "office/rgb1/light/status"
|
||||||
|
command_topic: "office/rgb1/light/switch"
|
||||||
|
brightness_state_topic: "office/rgb1/brightness/status"
|
||||||
|
brightness_command_topic: "office/rgb1/brightness/set"
|
||||||
|
qos: 0
|
||||||
|
payload_on: "on"
|
||||||
|
payload_off: "off"
|
||||||
|
|
||||||
|
config without RGB and brightness:
|
||||||
|
|
||||||
|
light:
|
||||||
|
platform: mqtt
|
||||||
|
name: "Office Light"
|
||||||
|
state_topic: "office/rgb1/light/status"
|
||||||
|
command_topic: "office/rgb1/light/switch"
|
||||||
|
qos: 0
|
||||||
|
payload_on: "on"
|
||||||
|
payload_off: "off"
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
import homeassistant.util.color as color_util
|
||||||
|
|
||||||
|
from homeassistant.const import STATE_ON, STATE_OFF
|
||||||
|
import homeassistant.core as ha
|
||||||
|
import homeassistant.components.light as light
|
||||||
|
from tests.common import mock_mqtt_component, fire_mqtt_message
|
||||||
|
|
||||||
|
|
||||||
|
class TestLightMQTT(unittest.TestCase):
|
||||||
|
""" Test the MQTT light. """
|
||||||
|
|
||||||
|
def setUp(self): # pylint: disable=invalid-name
|
||||||
|
self.hass = ha.HomeAssistant()
|
||||||
|
self.mock_publish = mock_mqtt_component(self.hass)
|
||||||
|
|
||||||
|
def tearDown(self): # pylint: disable=invalid-name
|
||||||
|
""" Stop down stuff we started. """
|
||||||
|
self.hass.stop()
|
||||||
|
|
||||||
|
def test_controlling_state_via_topic(self):
|
||||||
|
self.assertTrue(light.setup(self.hass, {
|
||||||
|
'light': {
|
||||||
|
'platform': 'mqtt',
|
||||||
|
'name': 'test',
|
||||||
|
'state_topic': 'test_light_rgb/status',
|
||||||
|
'command_topic': 'test_light_rgb/set',
|
||||||
|
'brightness_state_topic': 'test_light_rgb/brightness/status',
|
||||||
|
'brightness_command_topic': 'test_light_rgb/brightness/set',
|
||||||
|
'rgb_state_topic': 'test_light_rgb/rgb/status',
|
||||||
|
'rgb_command_topic': 'test_light_rgb/rgb/set',
|
||||||
|
'qos': 0,
|
||||||
|
'payload_on': 'on',
|
||||||
|
'payload_off': 'off'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
state = self.hass.states.get('light.test')
|
||||||
|
self.assertEqual(STATE_OFF, state.state)
|
||||||
|
|
||||||
|
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'on')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
state = self.hass.states.get('light.test')
|
||||||
|
self.assertEqual(STATE_ON, state.state)
|
||||||
|
|
||||||
|
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'off')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
state = self.hass.states.get('light.test')
|
||||||
|
self.assertEqual(STATE_OFF, state.state)
|
||||||
|
|
||||||
|
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'on')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
fire_mqtt_message(self.hass, 'test_light_rgb/brightness/status', '100')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
light_state = self.hass.states.get('light.test')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
self.assertEqual(100,
|
||||||
|
light_state.attributes['brightness'])
|
||||||
|
|
||||||
|
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'on')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
fire_mqtt_message(self.hass, 'test_light_rgb/rgb/status',
|
||||||
|
'125,125,125')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
light_state = self.hass.states.get('light.test')
|
||||||
|
self.assertEqual([125, 125, 125],
|
||||||
|
light_state.attributes.get('rgb_color'))
|
||||||
|
|
||||||
|
def test_sending_mqtt_commands_and_optimistic(self):
|
||||||
|
self.assertTrue(light.setup(self.hass, {
|
||||||
|
'light': {
|
||||||
|
'platform': 'mqtt',
|
||||||
|
'name': 'test',
|
||||||
|
'command_topic': 'test_light_rgb/set',
|
||||||
|
'brightness_state_topic': 'test_light_rgb/brightness/status',
|
||||||
|
'brightness_command_topic': 'test_light_rgb/brightness/set',
|
||||||
|
'rgb_state_topic': 'test_light_rgb/rgb/status',
|
||||||
|
'rgb_command_topic': 'test_light_rgb/rgb/set',
|
||||||
|
'qos': 2,
|
||||||
|
'payload_on': 'on',
|
||||||
|
'payload_off': 'off'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
state = self.hass.states.get('light.test')
|
||||||
|
self.assertEqual(STATE_OFF, state.state)
|
||||||
|
|
||||||
|
light.turn_on(self.hass, 'light.test')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
self.assertEqual(('test_light_rgb/set', 'on', 2),
|
||||||
|
self.mock_publish.mock_calls[-1][1])
|
||||||
|
state = self.hass.states.get('light.test')
|
||||||
|
self.assertEqual(STATE_ON, state.state)
|
||||||
|
|
||||||
|
light.turn_off(self.hass, 'light.test')
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
self.assertEqual(('test_light_rgb/set', 'off', 2),
|
||||||
|
self.mock_publish.mock_calls[-1][1])
|
||||||
|
state = self.hass.states.get('light.test')
|
||||||
|
self.assertEqual(STATE_OFF, state.state)
|
@ -88,6 +88,8 @@ class TestScript(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(1, len(calls))
|
self.assertEqual(1, len(calls))
|
||||||
self.assertEqual('world', calls[0].data.get('hello'))
|
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):
|
def test_calling_service_old(self):
|
||||||
calls = []
|
calls = []
|
||||||
@ -172,6 +174,9 @@ class TestScript(unittest.TestCase):
|
|||||||
self.hass.pool.block_till_done()
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
self.assertTrue(script.is_on(self.hass, ENTITY_ID))
|
self.assertTrue(script.is_on(self.hass, ENTITY_ID))
|
||||||
|
self.assertEqual(
|
||||||
|
False,
|
||||||
|
self.hass.states.get(ENTITY_ID).attributes.get('can_cancel'))
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
event,
|
event,
|
||||||
|
@ -5,11 +5,13 @@ tests.test_bootstrap
|
|||||||
Tests bootstrap.
|
Tests bootstrap.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-public-methods,protected-access
|
# pylint: disable=too-many-public-methods,protected-access
|
||||||
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
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
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from tests.common import mock_detect_location_info
|
from tests.common import mock_detect_location_info
|
||||||
@ -39,3 +41,45 @@ class TestBootstrap(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(sorted(components),
|
self.assertEqual(sorted(components),
|
||||||
sorted(hass.config.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…
x
Reference in New Issue
Block a user