Merge pull request #554 from balloob/dev

0.7.6-rc1
This commit is contained in:
Paulus Schoutsen 2015-10-26 21:31:41 -07:00
commit 27c6c27db6
152 changed files with 4863 additions and 4938 deletions

View File

@ -37,6 +37,7 @@ omit =
homeassistant/components/device_tracker/asuswrt.py
homeassistant/components/device_tracker/ddwrt.py
homeassistant/components/device_tracker/luci.py
homeassistant/components/device_tracker/ubus.py
homeassistant/components/device_tracker/netgear.py
homeassistant/components/device_tracker/nmap_tracker.py
homeassistant/components/device_tracker/thomson.py
@ -49,8 +50,10 @@ omit =
homeassistant/components/light/hue.py
homeassistant/components/light/limitlessled.py
homeassistant/components/light/blinksticklight.py
homeassistant/components/light/hyperion.py
homeassistant/components/media_player/cast.py
homeassistant/components/media_player/denon.py
homeassistant/components/media_player/firetv.py
homeassistant/components/media_player/itunes.py
homeassistant/components/media_player/kodi.py
homeassistant/components/media_player/mpd.py
@ -70,6 +73,7 @@ omit =
homeassistant/components/sensor/arest.py
homeassistant/components/sensor/bitcoin.py
homeassistant/components/sensor/command_sensor.py
homeassistant/components/sensor/cpuspeed.py
homeassistant/components/sensor/dht.py
homeassistant/components/sensor/efergy.py
homeassistant/components/sensor/forecast.py
@ -89,10 +93,12 @@ omit =
homeassistant/components/switch/command_switch.py
homeassistant/components/switch/edimax.py
homeassistant/components/switch/hikvisioncam.py
homeassistant/components/switch/rest.py
homeassistant/components/switch/rpi_gpio.py
homeassistant/components/switch/transmission.py
homeassistant/components/switch/wemo.py
homeassistant/components/thermostat/nest.py
homeassistant/components/thermostat/radiotherm.py
[report]

View File

@ -20,8 +20,8 @@ After you finish adding support for your device:
- Update the supported devices in the `README.md` file.
- Add any new dependencies to `requirements_all.txt`. There is no ordering right now, so just add it to the end.
- Update the `.coveragerc` file.
- Provide some documentation for [home-assistant.io](https://home-assistant.io/). The documentation is handled in a separate [git repository](https://github.com/balloob/home-assistant.io).
- Make sure all your code passes Pylint and flake8 (PEP8 and some more) validation. To generate reports, run `pylint homeassistant > pylint.txt` and `flake8 homeassistant --exclude bower_components,external > flake8.txt`.
- Provide some documentation for [home-assistant.io](https://home-assistant.io/). The documentation is handled in a separate [git repository](https://github.com/balloob/home-assistant.io). It's OK to add a docstring with configuration details to the file header.
- Make sure all your code passes ``pylint`` and ``flake8`` (PEP8 and some more) validation. To check your repository, run `./script/lint`.
- Create a Pull Request against the [**dev**](https://github.com/balloob/home-assistant/tree/dev) branch of Home Assistant.
- Check for comments and suggestions on your Pull Request and keep an eye on the [Travis output](https://travis-ci.org/balloob/home-assistant/).

View File

@ -10,11 +10,10 @@ RUN apt-get update && \
apt-get install -y --no-install-recommends nmap net-tools && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Open Z-Wave disabled because broken
#RUN apt-get update && \
# apt-get install -y cython3 libudev-dev && \
# apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
# pip3 install cython && \
# scripts/build_python_openzwave
RUN apt-get update && \
apt-get install -y cython3 libudev-dev && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
pip3 install "cython<0.23" && \
script/build_python_openzwave
CMD [ "python", "-m", "homeassistant", "--config", "/config" ]

View File

@ -19,7 +19,7 @@ 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, RFXtrx sensors, 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/), and iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api))
* [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).

View File

@ -8,7 +8,7 @@ import os
from homeassistant.components import verisure
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY)
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity import Entity
@ -29,6 +29,7 @@ SERVICE_TO_METHOD = {
SERVICE_ALARM_DISARM: 'alarm_disarm',
SERVICE_ALARM_ARM_HOME: 'alarm_arm_home',
SERVICE_ALARM_ARM_AWAY: 'alarm_arm_away',
SERVICE_ALARM_TRIGGER: 'alarm_trigger'
}
ATTR_CODE = 'code'
@ -53,9 +54,9 @@ def setup(hass, config):
target_alarms = component.extract_from_service(service)
if ATTR_CODE not in service.data:
return
code = service.data[ATTR_CODE]
code = None
else:
code = service.data[ATTR_CODE]
method = SERVICE_TO_METHOD[service.service]
@ -72,36 +73,50 @@ def setup(hass, config):
return True
def alarm_disarm(hass, code, entity_id=None):
def alarm_disarm(hass, code=None, entity_id=None):
""" Send the alarm the command for disarm. """
data = {ATTR_CODE: code}
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_DISARM, data)
def alarm_arm_home(hass, code, entity_id=None):
def alarm_arm_home(hass, code=None, entity_id=None):
""" Send the alarm the command for arm home. """
data = {ATTR_CODE: code}
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_HOME, data)
def alarm_arm_away(hass, code, entity_id=None):
def alarm_arm_away(hass, code=None, entity_id=None):
""" Send the alarm the command for arm away. """
data = {ATTR_CODE: code}
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data)
def alarm_trigger(hass, code=None, entity_id=None):
""" Send the alarm the command for trigger. """
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data)
# pylint: disable=no-self-use
class AlarmControlPanel(Entity):
""" ABC for alarm control devices. """
@ -123,6 +138,10 @@ class AlarmControlPanel(Entity):
""" Send arm away command. """
raise NotImplementedError()
def alarm_trigger(self, code=None):
""" Send alarm trigger command. """
raise NotImplementedError()
@property
def state_attributes(self):
""" Return the state attributes. """

View File

@ -0,0 +1,149 @@
"""
homeassistant.components.alarm_control_panel.manual
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for manual alarms.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.manual.html
"""
import logging
import datetime
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.helpers.event import track_point_in_time
import homeassistant.util.dt as dt_util
from homeassistant.const import (
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED)
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = []
DEFAULT_ALARM_NAME = 'HA Alarm'
DEFAULT_PENDING_TIME = 60
DEFAULT_TRIGGER_TIME = 120
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the manual alarm platform. """
add_devices([ManualAlarm(
hass,
config.get('name', DEFAULT_ALARM_NAME),
config.get('code'),
config.get('pending_time', DEFAULT_PENDING_TIME),
config.get('trigger_time', DEFAULT_TRIGGER_TIME),
)])
# pylint: disable=too-many-arguments, too-many-instance-attributes
# pylint: disable=abstract-method
class ManualAlarm(alarm.AlarmControlPanel):
"""
Represents an alarm status.
When armed, will be pending for 'pending_time', after that armed.
When triggered, will be pending for 'trigger_time'. After that will be
triggered for 'trigger_time', after that we return to disarmed.
"""
def __init__(self, hass, name, code, pending_time, trigger_time):
self._state = STATE_ALARM_DISARMED
self._hass = hass
self._name = name
self._code = str(code) if code else None
self._pending_time = datetime.timedelta(seconds=pending_time)
self._trigger_time = datetime.timedelta(seconds=trigger_time)
self._state_ts = None
@property
def should_poll(self):
""" No polling needed. """
return False
@property
def name(self):
""" Returns the name of the device. """
return self._name
@property
def state(self):
""" Returns the state of the device. """
if self._state in (STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY) and \
self._pending_time and self._state_ts + self._pending_time > \
dt_util.utcnow():
return STATE_ALARM_PENDING
if self._state == STATE_ALARM_TRIGGERED and self._trigger_time:
if self._state_ts + self._pending_time > dt_util.utcnow():
return STATE_ALARM_PENDING
elif (self._state_ts + self._pending_time +
self._trigger_time) < dt_util.utcnow():
return STATE_ALARM_DISARMED
return self._state
@property
def code_format(self):
""" One or more characters. """
return None if self._code is None else '.+'
def alarm_disarm(self, code=None):
""" Send disarm command. """
if not self._validate_code(code, STATE_ALARM_DISARMED):
return
self._state = STATE_ALARM_DISARMED
self._state_ts = dt_util.utcnow()
self.update_ha_state()
def alarm_arm_home(self, code=None):
""" Send arm home command. """
if not self._validate_code(code, STATE_ALARM_ARMED_HOME):
return
self._state = STATE_ALARM_ARMED_HOME
self._state_ts = dt_util.utcnow()
self.update_ha_state()
if self._pending_time:
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time)
def alarm_arm_away(self, code=None):
""" Send arm away command. """
if not self._validate_code(code, STATE_ALARM_ARMED_AWAY):
return
self._state = STATE_ALARM_ARMED_AWAY
self._state_ts = dt_util.utcnow()
self.update_ha_state()
if self._pending_time:
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time)
def alarm_trigger(self, code=None):
""" Send alarm trigger command. No code needed. """
self._state = STATE_ALARM_TRIGGERED
self._state_ts = dt_util.utcnow()
self.update_ha_state()
if self._trigger_time:
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time)
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time + self._trigger_time)
def _validate_code(self, code, state):
""" Validate given code. """
check = self._code is None or code == self._code
if not check:
_LOGGER.warning('Invalid code given for %s', state)
return check

View File

@ -1,68 +1,18 @@
"""
homeassistant.components.alarm_control_panel.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This platform enables the possibility to control a MQTT alarm.
In this platform, 'state_topic' and 'command_topic' are required.
The alarm will only change state after receiving the a new state
from 'state_topic'. If these messages are published with RETAIN flag,
the MQTT alarm will receive an instant state update after subscription
and will start with correct state. Otherwise, the initial state will
be 'unknown'.
Configuration:
alarm_control_panel:
platform: mqtt
name: "MQTT Alarm"
state_topic: "home/alarm"
command_topic: "home/alarm/set"
qos: 0
payload_disarm: "DISARM"
payload_arm_home: "ARM_HOME"
payload_arm_away: "ARM_AWAY"
code: "mySecretCode"
Variables:
name
*Optional
The name of the alarm. Default is 'MQTT Alarm'.
state_topic
*Required
The MQTT topic subscribed to receive state updates.
command_topic
*Required
The MQTT topic to publish commands to change the alarm state.
qos
*Optional
The maximum QoS level of the state topic. Default is 0.
This QoS will also be used to publishing messages.
payload_disarm
*Optional
The payload do disarm alarm. Default is "DISARM".
payload_arm_home
*Optional
The payload to set armed-home mode. Default is "ARM_HOME".
payload_arm_away
*Optional
The payload to set armed-away mode. Default is "ARM_AWAY".
code
*Optional
If defined, specifies a code to enable or disable the alarm in the frontend.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.mqtt.html
"""
import logging
import homeassistant.components.mqtt as mqtt
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.const import (STATE_UNKNOWN)
from homeassistant.const import (
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN)
_LOGGER = logging.getLogger(__name__)
@ -99,6 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-arguments, too-many-instance-attributes
# pylint: disable=abstract-method
class MqttAlarm(alarm.AlarmControlPanel):
""" represents a MQTT alarm status within home assistant. """
@ -113,10 +64,15 @@ class MqttAlarm(alarm.AlarmControlPanel):
self._payload_disarm = payload_disarm
self._payload_arm_home = payload_arm_home
self._payload_arm_away = payload_arm_away
self._code = code
self._code = str(code) if code else None
def message_received(topic, payload, qos):
""" A new MQTT message has been received. """
if payload not in (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_AWAY, STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED):
_LOGGER.warning('Received unexpected payload: %s', payload)
return
self._state = payload
self.update_ha_state()
@ -144,24 +100,28 @@ class MqttAlarm(alarm.AlarmControlPanel):
def alarm_disarm(self, code=None):
""" Send disarm command. """
if code == str(self._code) or self.code_format is None:
mqtt.publish(self.hass, self._command_topic,
self._payload_disarm, self._qos)
else:
_LOGGER.warning("Wrong code entered while disarming!")
if not self._validate_code(code, 'disarming'):
return
mqtt.publish(self.hass, self._command_topic,
self._payload_disarm, self._qos)
def alarm_arm_home(self, code=None):
""" Send arm home command. """
if code == str(self._code) or self.code_format is None:
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_home, self._qos)
else:
_LOGGER.warning("Wrong code entered while arming home!")
if not self._validate_code(code, 'arming home'):
return
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_home, self._qos)
def alarm_arm_away(self, code=None):
""" Send arm away command. """
if code == str(self._code) or self.code_format is None:
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_away, self._qos)
else:
_LOGGER.warning("Wrong code entered while arming away!")
if not self._validate_code(code, 'arming away'):
return
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_away, self._qos)
def _validate_code(self, code, state):
""" Validate given code. """
check = self._code is None or code == self._code
if not check:
_LOGGER.warning('Wrong code entered for %s', state)
return check

View File

@ -33,6 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
add_devices(alarms)
# pylint: disable=abstract-method
class VerisureAlarm(alarm.AlarmControlPanel):
""" Represents a Verisure alarm status. """

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.api
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides a Rest API for Home Assistant.
For more details about the RESTful API, please refer to the documentation at
https://home-assistant.io/developers/api.html
"""
import re
import logging

View File

@ -4,26 +4,8 @@ components.arduino
Arduino component that connects to a directly attached Arduino board which
runs with the Firmata firmware.
Configuration:
To use the Arduino board you will need to add something like the following
to your configuration.yaml file.
arduino:
port: /dev/ttyACM0
Variables:
port
*Required
The port where is your board connected to your Home Assistant system.
If you are using an original Arduino the port will be named ttyACM*. The exact
number can be determined with 'ls /dev/ttyACM*' or check your 'dmesg'/
'journalctl -f' output. Keep in mind that Arduino clones are often using a
different name for the port (e.g. '/dev/ttyUSB*').
A word of caution: The Arduino is not storing states. This means that with
every initialization the pins are set to off/low.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/arduino.html
"""
import logging

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.automation.event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers event listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#event-trigger
"""
import logging

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.automation.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers MQTT listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#mqtt-trigger
"""
import logging

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.automation.numeric_state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers numeric state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#numeric-state-trigger
"""
import logging

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.automation.state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#state-trigger
"""
import logging
@ -28,6 +30,11 @@ def trigger(hass, config, action):
from_state = config.get(CONF_FROM, MATCH_ALL)
to_state = config.get(CONF_TO) or config.get(CONF_STATE) or MATCH_ALL
if isinstance(from_state, bool) or isinstance(to_state, bool):
logging.getLogger(__name__).error(
'Config error. Surround to/from values with quotes.')
return False
def state_automation_listener(entity, from_s, to_s):
""" Listens for state changes and calls action. """
action()

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.automation.sun
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers sun based automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#sun-trigger
"""
import logging
from datetime import timedelta

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.automation.time
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers time listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#time-trigger
"""
import logging

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.automation.zone
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers zone automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#zone-trigger
"""
import logging

View File

@ -3,42 +3,6 @@ homeassistant.components.camera.foscam
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This component provides basic support for Foscam IP cameras.
As part of the basic support the following features will be provided:
-MJPEG video streaming
To use this component, add the following to your configuration.yaml file.
camera:
platform: foscam
name: Door Camera
ip: 192.168.0.123
port: 88
username: YOUR_USERNAME
password: YOUR_PASSWORD
Variables:
ip
*Required
The IP address of your Foscam device.
username
*Required
The username of a visitor or operator of your camera. Oddly admin accounts
don't seem to have access to take snapshots.
password
*Required
The password for accessing your camera.
name
*Optional
This parameter allows you to override the name of your camera in homeassistant.
port
*Optional
The port that the camera is running on. The default is 88.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.foscam.html
"""

View File

@ -3,43 +3,8 @@ homeassistant.components.camera.generic
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for IP Cameras.
This component provides basic support for IP cameras. For the basic support to
work you camera must support accessing a JPEG snapshot via a URL and you will
need to specify the "still_image_url" parameter which should be the location of
the JPEG image.
As part of the basic support the following features will be provided:
- MJPEG video streaming
- Saving a snapshot
- Recording(JPEG frame capture)
To use this component, add the following to your configuration.yaml file.
camera:
platform: generic
name: Door Camera
username: YOUR_USERNAME
password: YOUR_PASSWORD
still_image_url: http://YOUR_CAMERA_IP_AND_PORT/image.jpg
Variables:
still_image_url
*Required
The URL your camera serves the image on, eg. http://192.168.1.21:2112/
name
*Optional
This parameter allows you to override the name of your camera in Home
Assistant.
username
*Optional
The username for accessing your camera.
password
*Optional
The password for accessing your camera.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.generic.html
"""
import logging
from requests.auth import HTTPBasicAuth

View File

@ -1,9 +1,10 @@
"""
homeassistant.components.conversation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to have conversations with Home Assistant.
This is more a proof of concept.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/conversation.html
"""
import logging
import re

View File

@ -63,6 +63,14 @@ def setup(hass, config):
'still_image_url': 'http://home-assistant.io/demo/webcam.jpg',
}})
# Setup alarm_control_panel
bootstrap.setup_component(
hass, 'alarm_control_panel',
{'alarm_control_panel': {
'platform': 'manual',
'name': 'Test Alarm',
}})
# Setup scripts
bootstrap.setup_component(
hass, 'script',

View File

@ -4,41 +4,8 @@ homeassistant.components.device_tracker.actiontec
Device tracker platform that supports scanning an Actiontec MI424WR
(Verizon FIOS) router for device presence.
This device tracker needs telnet to be enabled on the router.
Configuration:
To use the Actiontec tracker you will need to add something like the
following to your configuration.yaml file. If you experience disconnects
you can modify the home_interval variable.
device_tracker:
platform: actiontec
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
# optional:
home_interval: 10
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
home_interval
*Optional
If the home_interval is set then the component will not let a device
be AWAY if it has been HOME in the last home_interval minutes. This is
in addition to the 3 minute wait built into the device_tracker component.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.actiontec.html
"""
import logging
from datetime import timedelta
@ -56,7 +23,7 @@ from homeassistant.components.device_tracker import DOMAIN
# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
# interval in minutes to exclude devices from a scan while they are home
# Interval in minutes to exclude devices from a scan while they are home
CONF_HOME_INTERVAL = "home_interval"
_LOGGER = logging.getLogger(__name__)

View File

@ -4,33 +4,8 @@ homeassistant.components.device_tracker.aruba
Device tracker platform that supports scanning a Aruba Access Point for device
presence.
This device tracker needs telnet to be enabled on the router.
Configuration:
To use the Aruba tracker you will need to add something like the following
to your configuration.yaml file. You also need to enable Telnet in the
configuration page of your router.
device_tracker:
platform: aruba
host: YOUR_ACCESS_POINT_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.aruba.html
"""
import logging
from datetime import timedelta

View File

@ -161,9 +161,10 @@ class AsusWrtDeviceScanner(object):
# For leases where the client doesn't set a hostname, ensure
# it is blank and not '*', which breaks the entity_id down
# the line
host = match.group('host')
if host == '*':
host = ''
if match:
host = match.group('host')
if host == '*':
host = ''
devices[match.group('ip')] = {
'host': host,
@ -174,6 +175,6 @@ class AsusWrtDeviceScanner(object):
for neighbor in neighbors:
match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8'))
if match.group('ip') in devices:
if match and match.group('ip') in devices:
devices[match.group('ip')]['status'] = match.group('status')
return devices

View File

@ -4,30 +4,8 @@ homeassistant.components.device_tracker.ddwrt
Device tracker platform that supports scanning a DD-WRT router for device
presence.
Configuration:
To use the DD-WRT tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: ddwrt
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ddwrt.html
"""
import logging
from datetime import timedelta

View File

@ -0,0 +1,71 @@
"""
homeassistant.components.device_tracker.geofancy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Geofancy platform for the device tracker.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.geofancy.html
"""
from homeassistant.const import (
HTTP_UNPROCESSABLE_ENTITY, HTTP_INTERNAL_SERVER_ERROR)
DEPENDENCIES = ['http']
_SEE = 0
URL_API_GEOFANCY_ENDPOINT = "/api/geofancy"
def setup_scanner(hass, config, see):
""" Set up an endpoint for the Geofancy app. """
# Use a global variable to keep setup_scanner compact when using a callback
global _SEE
_SEE = see
# POST would be semantically better, but that currently does not work
# since Geofancy sends the data as key1=value1&key2=value2
# in the request body, while Home Assistant expects json there.
hass.http.register_path(
'GET', URL_API_GEOFANCY_ENDPOINT, _handle_get_api_geofancy)
return True
def _handle_get_api_geofancy(handler, path_match, data):
""" Geofancy message received. """
if not isinstance(data, dict):
handler.write_json_message(
"Error while parsing Geofancy message.",
HTTP_INTERNAL_SERVER_ERROR)
return
if 'latitude' not in data or 'longitude' not in data:
handler.write_json_message(
"Location not specified.",
HTTP_UNPROCESSABLE_ENTITY)
return
if 'device' not in data or 'id' not in data:
handler.write_json_message(
"Device id or location id not specified.",
HTTP_UNPROCESSABLE_ENTITY)
return
try:
gps_coords = (float(data['latitude']), float(data['longitude']))
except ValueError:
# If invalid latitude / longitude format
handler.write_json_message(
"Invalid latitude / longitude format.",
HTTP_UNPROCESSABLE_ENTITY)
return
# entity id's in Home Assistant must be alphanumerical
device_uuid = data['device']
device_entity_id = device_uuid.replace('-', '')
_SEE(dev_id=device_entity_id, gps=gps_coords, location_name=data['id'])
handler.write_json_message("Geofancy message processed")

View File

@ -4,33 +4,8 @@ homeassistant.components.device_tracker.luci
Device tracker platform that supports scanning a OpenWRT router for device
presence.
It's required that the luci RPC package is installed on the OpenWRT router:
# opkg install luci-mod-rpc
Configuration:
To use the Luci tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: luci
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.luci.html
"""
import logging
import json

View File

@ -1,15 +1,10 @@
"""
homeassistant.components.device_tracker.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MQTT platform for the device tracker.
device_tracker:
platform: mqtt
qos: 1
devices:
paulus_oneplus: /location/paulus
annetherese_n4: /location/annetherese
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.mqtt.html
"""
import logging
from homeassistant import util

View File

@ -4,30 +4,8 @@ homeassistant.components.device_tracker.netgear
Device tracker platform that supports scanning a Netgear router for device
presence.
Configuration:
To use the Netgear tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: netgear
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.netgear.html
"""
import logging
from datetime import timedelta

View File

@ -3,26 +3,8 @@ homeassistant.components.device_tracker.nmap
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a network with nmap.
Configuration:
To use the nmap tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: nmap_tracker
hosts: 192.168.1.1/24
Variables:
hosts
*Required
The IP addresses to scan in the network-prefix notation (192.168.1.1/24) or
the range notation (192.168.1.1-255).
home_interval
*Optional
Number of minutes it will not scan devices that it found in previous results.
This is to save battery.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.nmap_scanner.html
"""
import logging
from datetime import timedelta

View File

@ -1,11 +1,10 @@
"""
homeassistant.components.device_tracker.owntracks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OwnTracks platform for the device tracker.
device_tracker:
platform: owntracks
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.owntracks.html
"""
import json
import logging

View File

@ -4,32 +4,8 @@ homeassistant.components.device_tracker.thomson
Device tracker platform that supports scanning a THOMSON router for device
presence.
This device tracker needs telnet to be enabled on the router.
Configuration:
To use the THOMSON tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: thomson
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.thomson.html
"""
import logging
from datetime import timedelta

View File

@ -4,36 +4,8 @@ homeassistant.components.device_tracker.tomato
Device tracker platform that supports scanning a Tomato router for device
presence.
Configuration:
To use the Tomato tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: tomato
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
http_id: ABCDEFG
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
http_id
*Required
The value can be obtained by logging in to the Tomato admin interface and
search for http_id in the page source code.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tomato.html
"""
import logging
import json

View File

@ -4,30 +4,8 @@ homeassistant.components.device_tracker.tplink
Device tracker platform that supports scanning a TP-Link router for device
presence.
Configuration:
To use the TP-Link tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: tplink
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tplink.html
"""
import base64
import logging
@ -54,10 +32,13 @@ def get_scanner(hass, config):
_LOGGER):
return None
scanner = Tplink2DeviceScanner(config[DOMAIN])
scanner = Tplink3DeviceScanner(config[DOMAIN])
if not scanner.success_init:
scanner = TplinkDeviceScanner(config[DOMAIN])
scanner = Tplink2DeviceScanner(config[DOMAIN])
if not scanner.success_init:
scanner = TplinkDeviceScanner(config[DOMAIN])
return scanner if scanner.success_init else None
@ -156,7 +137,7 @@ class Tplink2DeviceScanner(TplinkDeviceScanner):
with self.lock:
_LOGGER.info("Loading wireless clients...")
url = 'http://{}/data/map_access_wireless_client_grid.json'\
url = 'http://{}/data/map_access_wireless_client_grid.json' \
.format(self.host)
referer = 'http://{}'.format(self.host)
@ -166,7 +147,7 @@ class Tplink2DeviceScanner(TplinkDeviceScanner):
b64_encoded_username_password = base64.b64encode(
username_password.encode('ascii')
).decode('ascii')
cookie = 'Authorization=Basic {}'\
cookie = 'Authorization=Basic {}' \
.format(b64_encoded_username_password)
response = requests.post(url, headers={'referer': referer,
@ -183,7 +164,119 @@ class Tplink2DeviceScanner(TplinkDeviceScanner):
self.last_results = {
device['mac_addr'].replace('-', ':'): device['name']
for device in result
}
}
return True
return False
class Tplink3DeviceScanner(TplinkDeviceScanner):
"""
This class queries the Archer C9 router running version 150811 or higher
of TP-Link firmware for connected devices.
"""
def __init__(self, config):
self.stok = ''
self.sysauth = ''
super(Tplink3DeviceScanner, self).__init__(config)
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
self._update_info()
return self.last_results.keys()
# pylint: disable=no-self-use
def get_device_name(self, device):
"""
The TP-Link firmware doesn't save the name of the wireless device.
We are forced to use the MAC address as name here.
"""
return self.last_results.get(device)
def _get_auth_tokens(self):
"""
Retrieves auth tokens from the router.
"""
_LOGGER.info("Retrieving auth tokens...")
url = 'http://{}/cgi-bin/luci/;stok=/login?form=login' \
.format(self.host)
referer = 'http://{}/webpages/login.html'.format(self.host)
# if possible implement rsa encryption of password here
response = requests.post(url,
params={'operation': 'login',
'username': self.username,
'password': self.password},
headers={'referer': referer})
try:
self.stok = response.json().get('data').get('stok')
_LOGGER.info(self.stok)
regex_result = re.search('sysauth=(.*);',
response.headers['set-cookie'])
self.sysauth = regex_result.group(1)
_LOGGER.info(self.sysauth)
return True
except ValueError:
_LOGGER.error("Couldn't fetch auth tokens!")
return False
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the TP-Link router is up to date.
Returns boolean if scanning successful.
"""
with self.lock:
if (self.stok == '') or (self.sysauth == ''):
self._get_auth_tokens()
_LOGGER.info("Loading wireless clients...")
url = 'http://{}/cgi-bin/luci/;stok={}/admin/wireless?form=statistics' \
.format(self.host, self.stok)
referer = 'http://{}/webpages/index.html'.format(self.host)
response = requests.post(url,
params={'operation': 'load'},
headers={'referer': referer},
cookies={'sysauth': self.sysauth})
try:
json_response = response.json()
if json_response.get('success'):
result = response.json().get('data')
else:
if json_response.get('errorcode') == 'timeout':
_LOGGER.info("Token timed out. "
"Relogging on next scan.")
self.stok = ''
self.sysauth = ''
return False
else:
_LOGGER.error("An unknown error happened "
"while fetching data.")
return False
except ValueError:
_LOGGER.error("Router didn't respond with JSON. "
"Check if credentials are correct.")
return False
if result:
self.last_results = {
device['mac'].replace('-', ':'): device['mac']
for device in result
}
return True
return False

View File

@ -0,0 +1,173 @@
"""
homeassistant.components.device_tracker.ubus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a OpenWRT router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ubus.html
"""
import logging
import json
from datetime import timedelta
import re
import threading
import requests
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
from homeassistant.components.device_tracker import DOMAIN
# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)
def get_scanner(hass, config):
""" Validates config and returns a Luci scanner. """
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
return None
scanner = UbusDeviceScanner(config[DOMAIN])
return scanner if scanner.success_init else None
# pylint: disable=too-many-instance-attributes
class UbusDeviceScanner(object):
"""
This class queries a wireless router running OpenWrt firmware
for connected devices. Adapted from Tomato scanner.
Configure your routers' ubus ACL based on following instructions:
http://wiki.openwrt.org/doc/techref/ubus
Read only access will be fine.
To use this class you have to install rpcd-mod-file package
in your OpenWrt router:
opkg install rpcd-mod-file
"""
def __init__(self, config):
host = config[CONF_HOST]
username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
self.parse_api_pattern = re.compile(r"(?P<param>\w*) = (?P<value>.*);")
self.lock = threading.Lock()
self.last_results = {}
self.url = 'http://{}/ubus'.format(host)
self.session_id = _get_session_id(self.url, username, password)
self.hostapd = []
self.leasefile = None
self.mac2name = None
self.success_init = self.session_id is not None
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
self._update_info()
return self.last_results
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
with self.lock:
if self.leasefile is None:
result = _req_json_rpc(self.url, self.session_id,
'call', 'uci', 'get',
config="dhcp", type="dnsmasq")
if result:
values = result["values"].values()
self.leasefile = next(iter(values))["leasefile"]
else:
return
if self.mac2name is None:
result = _req_json_rpc(self.url, self.session_id,
'call', 'file', 'read',
path=self.leasefile)
if result:
self.mac2name = dict()
for line in result["data"].splitlines():
hosts = line.split(" ")
self.mac2name[hosts[1].upper()] = hosts[3]
else:
# Error, handled in the _req_json_rpc
return
return self.mac2name.get(device.upper(), None)
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the Luci router is up to date.
Returns boolean if scanning successful.
"""
if not self.success_init:
return False
with self.lock:
_LOGGER.info("Checking ARP")
if not self.hostapd:
hostapd = _req_json_rpc(self.url, self.session_id,
'list', 'hostapd.*', '')
self.hostapd.extend(hostapd.keys())
self.last_results = []
results = 0
for hostapd in self.hostapd:
result = _req_json_rpc(self.url, self.session_id,
'call', hostapd, 'get_clients')
if result:
results = results + 1
self.last_results.extend(result['clients'].keys())
return bool(results)
def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params):
""" Perform one JSON RPC operation. """
data = json.dumps({"jsonrpc": "2.0",
"id": 1,
"method": rpcmethod,
"params": [session_id,
subsystem,
method,
params]})
try:
res = requests.post(url, data=data, timeout=5)
except requests.exceptions.Timeout:
return
if res.status_code == 200:
response = res.json()
if rpcmethod == "call":
return response["result"][1]
else:
return response["result"]
def _get_session_id(url, username, password):
""" Get authentication token for the given host+username+password. """
res = _req_json_rpc(url, "00000000000000000000000000000000", 'call',
'session', 'login', username=username,
password=password)
return res["ubus_rpc_session"]

View File

@ -19,7 +19,7 @@ from homeassistant.const import (
DOMAIN = "discovery"
DEPENDENCIES = []
REQUIREMENTS = ['netdisco==0.4.2']
REQUIREMENTS = ['netdisco==0.5.1']
SCAN_INTERVAL = 300 # seconds
@ -28,6 +28,7 @@ SERVICE_HUE = 'philips_hue'
SERVICE_CAST = 'google_cast'
SERVICE_NETGEAR = 'netgear_router'
SERVICE_SONOS = 'sonos'
SERVICE_PLEX = 'plex_mediaserver'
SERVICE_HANDLERS = {
SERVICE_WEMO: "switch",
@ -35,6 +36,7 @@ SERVICE_HANDLERS = {
SERVICE_HUE: "light",
SERVICE_NETGEAR: 'device_tracker',
SERVICE_SONOS: 'media_player',
SERVICE_PLEX: 'media_player',
}
@ -88,6 +90,7 @@ def setup(hass, config):
ATTR_DISCOVERED: info
})
# pylint: disable=unused-argument
def start_discovery(event):
""" Start discovering. """
netdisco = DiscoveryService(SCAN_INTERVAL)

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.downloader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to download files.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/downloader.html
"""
import os
import logging
@ -42,6 +44,10 @@ def setup(hass, config):
download_path = config[DOMAIN][CONF_DOWNLOAD_DIR]
# If path is relative, we assume relative to HASS config dir
if not os.path.isabs(download_path):
download_path = hass.config.path(download_path)
if not os.path.isdir(download_path):
logger.error(

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "c4722afa376379bc4457d54bb9a38cee"
VERSION = "beb922c55bb26ea576581b453f6d7c04"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit 6989009b2d59e39fd39b3025ff5899877f618bd3
Subproject commit 24623ff26ab8cbf7b39f0a25c26d9d991063b61a

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,11 @@
"""
homeassistant.components.group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to group devices that can be turned on or off.
"""
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/group.html
"""
import homeassistant.core as ha
from homeassistant.helpers import generate_entity_id
from homeassistant.helpers.event import track_state_change

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.history
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provide pre-made queries on top of the recorder component.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/history.html
"""
import re
from datetime import timedelta

View File

@ -1,76 +1,11 @@
"""
homeassistant.components.httpinterface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
homeassistant.components.http
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module provides an API and a HTTP interface for debug purposes.
By default it will run on port 8123.
All API calls have to be accompanied by an 'api_password' parameter and will
return JSON. If successful calls will return status code 200 or 201.
Other status codes that can occur are:
- 400 (Bad Request)
- 401 (Unauthorized)
- 404 (Not Found)
- 405 (Method not allowed)
The api supports the following actions:
/api - GET
Returns message if API is up and running.
Example result:
{
"message": "API running."
}
/api/states - GET
Returns a list of entities for which a state is available
Example result:
[
{ .. state object .. },
{ .. state object .. }
]
/api/states/<entity_id> - GET
Returns the current state from an entity
Example result:
{
"attributes": {
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
"entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
/api/states/<entity_id> - POST
Updates the current state of an entity. Returns status code 201 if successful
with location header of updated resource and as body the new state.
parameter: new_state - string
optional parameter: attributes - JSON encoded object
Example result:
{
"attributes": {
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
"entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
/api/events/<event_type> - POST
Fires an event with event_type
optional parameter: event_data - JSON encoded object
Example result:
{
"message": "Event download_file fired."
}
For more details about the RESTful API, please refer to the documentation at
https://home-assistant.io/developers/api.html
"""
import json
import threading
import logging

View File

@ -1,23 +1,10 @@
"""
homeassistant.components.ifttt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This component enable you to trigger Maker IFTTT recipes.
Check https://ifttt.com/maker for details.
Configuration:
To use Maker IFTTT you will need to add something like the following to your
config/configuration.yaml.
ifttt:
key: xxxxx-x-xxxxxxxxxxxxx
Variables:
key
*Required
Your api key
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/ifttt.html
"""
import logging
import requests

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.introduction
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component that will help guide the user taking its first steps.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/introduction.html
"""
import logging

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.keyboard
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to emulate keyboard presses on host machine.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/keyboard.html
"""
import logging

View File

@ -2,6 +2,8 @@
homeassistant.components.light.hue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Hue lights.
https://home-assistant.io/components/light.hue.html
"""
import logging
import socket

View File

@ -0,0 +1,125 @@
"""
homeassistant.components.light.hyperion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Hyperion remotes.
https://home-assistant.io/components/light.hyperion.html
"""
import logging
import socket
import json
from homeassistant.const import CONF_HOST
from homeassistant.components.light import (Light, ATTR_RGB_COLOR)
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = []
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Sets up a Hyperion server remote """
host = config.get(CONF_HOST, None)
port = config.get("port", 19444)
device = Hyperion(host, port)
if device.setup():
add_devices_callback([device])
return True
else:
return False
class Hyperion(Light):
""" Represents a Hyperion remote """
def __init__(self, host, port):
self._host = host
self._port = port
self._name = host
self._is_available = True
self._rgb_color = [255, 255, 255]
@property
def name(self):
""" Return the hostname of the server. """
return self._name
@property
def rgb_color(self):
""" Last RGB color value set. """
return self._rgb_color
@property
def is_on(self):
""" True if the device is online. """
return self._is_available
def turn_on(self, **kwargs):
""" Turn the lights on. """
if self._is_available:
if ATTR_RGB_COLOR in kwargs:
self._rgb_color = kwargs[ATTR_RGB_COLOR]
self.json_request({"command": "color", "priority": 128,
"color": self._rgb_color})
def turn_off(self, **kwargs):
""" Disconnect the remote. """
self.json_request({"command": "clearall"})
def update(self):
""" Ping the remote. """
# just see if the remote port is open
self._is_available = self.json_request()
def setup(self):
""" Get the hostname of the remote. """
response = self.json_request({"command": "serverinfo"})
if response:
self._name = response["info"]["hostname"]
return True
return False
def json_request(self, request=None, wait_for_response=False):
""" Communicate with the json server. """
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
try:
sock.connect((self._host, self._port))
except OSError:
sock.close()
return False
if not request:
# no communication needed, simple presence detection returns True
sock.close()
return True
sock.send(bytearray(json.dumps(request) + "\n", "utf-8"))
try:
buf = sock.recv(4096)
except socket.timeout:
# something is wrong, assume it's offline
sock.close()
return False
# read until a newline or timeout
buffering = True
while buffering:
if "\n" in str(buf, "utf-8"):
response = str(buf, "utf-8").split("\n")[0]
buffering = False
else:
try:
more = sock.recv(4096)
except socket.timeout:
more = None
if not more:
buffering = False
response = str(buf, "utf-8")
else:
buf += more
sock.close()
return json.loads(response)

View File

@ -12,22 +12,7 @@ Support for LimitlessLED bulbs, also known as...
- dekolight
- iLight
Configuration:
To use limitlessled you will need to add the following to your
configuration.yaml file.
light:
platform: limitlessled
bridges:
- host: 192.168.1.10
group_1_name: Living Room
group_2_name: Bedroom
group_3_name: Office
group_3_type: white
group_4_name: Kitchen
- host: 192.168.1.11
group_2_name: Basement
https://home-assistant.io/components/light.limitlessled.html
"""
import logging

View File

@ -2,6 +2,9 @@
homeassistant.components.light.tellstick
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Tellstick lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.tellstick.html
"""
import logging
# pylint: disable=no-name-in-module, import-error

View File

@ -1,52 +1,10 @@
"""
homeassistant.components.light.vera
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Vera lights. This component is useful if you wish for switches
connected to your Vera controller to appear as lights in Home Assistant.
All switches will be added as a light unless you exclude them in the config.
Configuration:
To use the Vera lights you will need to add something like the following to
your configuration.yaml file.
light:
platform: vera
vera_controller_url: http://YOUR_VERA_IP:3480/
device_data:
12:
name: My awesome switch
exclude: true
13:
name: Another switch
Variables:
vera_controller_url
*Required
This is the base URL of your vera controller including the port number if not
running on 80. Example: http://192.168.1.21:3480/
device_data
*Optional
This contains an array additional device info for your Vera devices. It is not
required and if not specified all lights configured in your Vera controller
will be added with default values. You should use the id of your vera device
as the key for the device within device_data.
These are the variables for the device_data array:
name
*Optional
This parameter allows you to override the name of your Vera device in the HA
interface, if not specified the value configured for the device in your Vera
will be used.
exclude
*Optional
This parameter allows you to exclude the specified device from Home Assistant,
it should be set to "true" if you want this device excluded.
Support for Vera lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.vera.html
"""
import logging
from requests.exceptions import RequestException

View File

@ -2,6 +2,9 @@
homeassistant.components.light.wink
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Wink lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.wink.html
"""
import logging

View File

@ -1,8 +1,10 @@
"""
homeassistant.components.logbook
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parses events and generates a human log.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/logbook.html
"""
from datetime import timedelta
from itertools import groupby

View File

@ -28,6 +28,7 @@ ENTITY_ID_FORMAT = DOMAIN + '.{}'
DISCOVERY_PLATFORMS = {
discovery.SERVICE_CAST: 'cast',
discovery.SERVICE_SONOS: 'sonos',
discovery.SERVICE_PLEX: 'plex',
}
SERVICE_YOUTUBE_VIDEO = 'play_youtube_video'

View File

@ -3,22 +3,8 @@ homeassistant.components.media_player.chromecast
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to interact with Cast devices on the network.
WARNING: This platform is currently not working due to a changed Cast API.
Configuration:
To use the chromecast integration you will need to add something like the
following to your configuration.yaml file.
media_player:
platform: chromecast
host: 192.168.1.9
Variables:
host
*Optional
Use only if you don't want to scan for devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.cast.html
"""
import logging

View File

@ -2,42 +2,9 @@
homeassistant.components.media_player.denon
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to Denon Network Receivers.
Developed for a Denon DRA-N5, see
http://www.denon.co.uk/chg/product/compactsystems/networkmusicsystems/ceolpiccolo
A few notes:
- As long as this module is active and connected, the receiver does
not seem to accept additional telnet connections.
- Be careful with the volume. 50% or even 100% are very loud.
- To be able to wake up the receiver, activate the "remote" setting
in the receiver's settings.
- Play and pause are supported, toggling is not possible.
- Seeking cannot be implemented as the UI sends absolute positions.
Only seeking via simulated button presses is possible.
Configuration:
To use your Denon you will need to add something like the following to
your config/configuration.yaml:
media_player:
platform: denon
name: Music station
host: 192.168.0.123
Variables:
host
*Required
The ip of the player. Example: 192.168.0.123
name
*Optional
The name of the device.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.denon.html
"""
import telnetlib
import logging
@ -67,13 +34,15 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
CONF_HOST)
return False
add_devices([
DenonDevice(
config.get('name', 'Music station'),
config.get('host'))
])
return True
denon = DenonDevice(
config.get("name", "Music station"),
config.get("host")
)
if denon.update():
add_devices([denon])
return True
else:
return False
class DenonDevice(MediaPlayerDevice):
@ -84,28 +53,41 @@ class DenonDevice(MediaPlayerDevice):
def __init__(self, name, host):
self._name = name
self._host = host
self._telnet = telnetlib.Telnet(self._host)
self._pwstate = "PWSTANDBY"
self._volume = 0
self._muted = False
self._mediasource = ""
def query(self, message):
""" Send request and await response from server """
@classmethod
def telnet_request(cls, telnet, command):
""" Executes `command` and returns the response. """
telnet.write(command.encode("ASCII") + b"\r")
return telnet.read_until(b"\r", timeout=0.2).decode("ASCII").strip()
def telnet_command(self, command):
""" Establishes a telnet connection and sends `command`. """
telnet = telnetlib.Telnet(self._host)
telnet.write(command.encode("ASCII") + b"\r")
telnet.read_very_eager() # skip response
telnet.close()
def update(self):
try:
# unspecified command, should be ignored
self._telnet.write("?".encode('UTF-8') + b'\r')
except (EOFError, BrokenPipeError, ConnectionResetError):
self._telnet.open(self._host)
telnet = telnetlib.Telnet(self._host)
except ConnectionRefusedError:
return False
self._telnet.read_very_eager() # skip what is not requested
self._pwstate = self.telnet_request(telnet, "PW?")
# PW? sends also SISTATUS, which is not interesting
telnet.read_until(b"\r", timeout=0.2)
self._telnet.write(message.encode('ASCII') + b'\r')
# timeout 200ms, defined by protocol
resp = self._telnet.read_until(b'\r', timeout=0.2)\
.decode('UTF-8').strip()
volume_str = self.telnet_request(telnet, "MV?")[len("MV"):]
self._volume = int(volume_str) / 60
self._muted = (self.telnet_request(telnet, "MU?") == "MUON")
self._mediasource = self.telnet_request(telnet, "SI?")[len("SI"):]
if message == "PW?":
# workaround; PW? sends also SISTATUS
self._telnet.read_until(b'\r', timeout=0.2)
return resp
telnet.close()
return True
@property
def name(self):
@ -115,10 +97,9 @@ class DenonDevice(MediaPlayerDevice):
@property
def state(self):
""" Returns the state of the device. """
pwstate = self.query('PW?')
if pwstate == "PWSTANDBY":
if self._pwstate == "PWSTANDBY":
return STATE_OFF
if pwstate == "PWON":
if self._pwstate == "PWON":
return STATE_ON
return STATE_UNKNOWN
@ -126,17 +107,17 @@ class DenonDevice(MediaPlayerDevice):
@property
def volume_level(self):
""" Volume level of the media player (0..1). """
return int(self.query('MV?')[len('MV'):]) / 60
return self._volume
@property
def is_volume_muted(self):
""" Boolean if volume is currently muted. """
return self.query('MU?') == "MUON"
return self._muted
@property
def media_title(self):
""" Current media source. """
return self.query('SI?')[len('SI'):]
return self._mediasource
@property
def supported_media_commands(self):
@ -145,24 +126,24 @@ class DenonDevice(MediaPlayerDevice):
def turn_off(self):
""" turn_off media player. """
self.query('PWSTANDBY')
self.telnet_command("PWSTANDBY")
def volume_up(self):
""" volume_up media player. """
self.query('MVUP')
self.telnet_command("MVUP")
def volume_down(self):
""" volume_down media player. """
self.query('MVDOWN')
self.telnet_command("MVDOWN")
def set_volume_level(self, volume):
""" set volume level, range 0..1. """
# 60dB max
self.query('MV' + str(round(volume * 60)).zfill(2))
self.telnet_command("MV" + str(round(volume * 60)).zfill(2))
def mute_volume(self, mute):
""" mute (true) or unmute (false) media player. """
self.query('MU' + ('ON' if mute else 'OFF'))
self.telnet_command("MU" + ("ON" if mute else "OFF"))
def media_play_pause(self):
""" media_play_pause media player. """
@ -170,22 +151,22 @@ class DenonDevice(MediaPlayerDevice):
def media_play(self):
""" media_play media player. """
self.query('NS9A')
self.telnet_command("NS9A")
def media_pause(self):
""" media_pause media player. """
self.query('NS9B')
self.telnet_command("NS9B")
def media_next_track(self):
""" Send next track command. """
self.query('NS9D')
self.telnet_command("NS9D")
def media_previous_track(self):
self.query('NS9E')
self.telnet_command("NS9E")
def media_seek(self, position):
raise NotImplementedError()
def turn_on(self):
""" turn the media player on. """
self.query('PWON')
self.telnet_command("PWON")

View File

@ -0,0 +1,190 @@
"""
homeassistant.components.media_player.firetv
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to interact with FireTV devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.firetv.html
"""
import logging
import requests
from homeassistant.const import (
STATE_PLAYING, STATE_PAUSED, STATE_IDLE, STATE_OFF,
STATE_UNKNOWN, STATE_STANDBY)
from homeassistant.components.media_player import (
MediaPlayerDevice,
SUPPORT_PAUSE, SUPPORT_VOLUME_SET,
SUPPORT_TURN_ON, SUPPORT_TURN_OFF,
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK)
SUPPORT_FIRETV = SUPPORT_PAUSE | \
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \
SUPPORT_NEXT_TRACK | SUPPORT_VOLUME_SET
DOMAIN = 'firetv'
DEVICE_LIST_URL = 'http://{0}/devices/list'
DEVICE_STATE_URL = 'http://{0}/devices/state/{1}'
DEVICE_ACTION_URL = 'http://{0}/devices/action/{1}/{2}'
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the FireTV platform. """
host = config.get('host', 'localhost:5556')
device_id = config.get('device', 'default')
try:
response = requests.get(DEVICE_LIST_URL.format(host)).json()
if device_id in response['devices'].keys():
add_devices([
FireTVDevice(
host,
device_id,
config.get('name', 'Amazon Fire TV')
)
])
_LOGGER.info(
'Device %s accessible and ready for control', device_id)
else:
_LOGGER.warn(
'Device %s is not registered with firetv-server', device_id)
except requests.exceptions.RequestException:
_LOGGER.error('Could not connect to firetv-server at %s', host)
class FireTV(object):
""" firetv-server client.
Should a native Python 3 ADB module become available, python-firetv can
support Python 3, it can be added as a dependency, and this class can be
dispensed of.
For now, it acts as a client to the firetv-server HTTP server (which must
be running via Python 2).
"""
def __init__(self, host, device_id):
self.host = host
self.device_id = device_id
@property
def state(self):
""" Get the device state. An exception means UNKNOWN state. """
try:
response = requests.get(
DEVICE_STATE_URL.format(
self.host,
self.device_id
)
).json()
return response.get('state', STATE_UNKNOWN)
except requests.exceptions.RequestException:
_LOGGER.error(
'Could not retrieve device state for %s', self.device_id)
return STATE_UNKNOWN
def action(self, action_id):
""" Perform an action on the device. """
try:
requests.get(
DEVICE_ACTION_URL.format(
self.host,
self.device_id,
action_id
)
)
except requests.exceptions.RequestException:
_LOGGER.error(
'Action request for %s was not accepted for device %s',
action_id, self.device_id)
class FireTVDevice(MediaPlayerDevice):
""" Represents an Amazon Fire TV device on the network. """
def __init__(self, host, device, name):
self._firetv = FireTV(host, device)
self._name = name
self._state = STATE_UNKNOWN
@property
def name(self):
""" Get the device name. """
return self._name
@property
def should_poll(self):
""" Device should be polled. """
return True
@property
def supported_media_commands(self):
""" Flags of media commands that are supported. """
return SUPPORT_FIRETV
@property
def state(self):
""" State of the player. """
return self._state
def update(self):
""" Update device state. """
self._state = {
'idle': STATE_IDLE,
'off': STATE_OFF,
'play': STATE_PLAYING,
'pause': STATE_PAUSED,
'standby': STATE_STANDBY,
'disconnected': STATE_UNKNOWN,
}.get(self._firetv.state, STATE_UNKNOWN)
def turn_on(self):
""" Turns on the device. """
self._firetv.action('turn_on')
def turn_off(self):
""" Turns off the device. """
self._firetv.action('turn_off')
def media_play(self):
""" Send play command. """
self._firetv.action('media_play')
def media_pause(self):
""" Send pause command. """
self._firetv.action('media_pause')
def media_play_pause(self):
""" Send play/pause command. """
self._firetv.action('media_play_pause')
def volume_up(self):
""" Send volume up command. """
self._firetv.action('volume_up')
def volume_down(self):
""" Send volume down command. """
self._firetv.action('volume_down')
def media_previous_track(self):
""" Send previous track command (results in rewind). """
self._firetv.action('media_previous')
def media_next_track(self):
""" Send next track command (results in fast-forward). """
self._firetv.action('media_next')
def media_seek(self, position):
raise NotImplementedError()
def mute_volume(self, mute):
raise NotImplementedError()
def play_youtube(self, media_id):
raise NotImplementedError()
def set_volume_level(self, volume):
raise NotImplementedError()

View File

@ -1,36 +1,10 @@
"""
homeassistant.components.media_player.itunes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to iTunes-API (https://github.com/maddox/itunes-api)
The iTunes media player will allow you to control your iTunes instance. You
can play/pause/next/previous/mute, adjust volume, etc.
In addition to controlling iTunes, your available AirPlay endpoints will be
added as media players as well. You can then individually address them append
turn them on, turn them off, or adjust their volume.
Configuration:
To use iTunes you will need to add something like the following to
your configuration.yaml file.
media_player:
platform: itunes
name: iTunes
host: http://192.168.1.16
port: 8181
Variables:
name
*Optional
The name of the device.
url
*Required
URL of your running version of iTunes-API. Example: http://192.168.1.50:8181
Provides an interface to iTunes API.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.itunes.html
"""
import logging
@ -157,11 +131,9 @@ class Itunes(object):
path = '/airplay_devices/' + device_id + '/volume'
return self._request('PUT', path, {'level': level})
# pylint: disable=unused-argument
# pylint: disable=abstract-method
# pylint: disable=unused-argument, abstract-method
# pylint: disable=too-many-instance-attributes
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the itunes platform. """
@ -179,7 +151,6 @@ class ItunesDevice(MediaPlayerDevice):
""" Represents a iTunes-API instance. """
# pylint: disable=too-many-public-methods
def __init__(self, name, host, port, add_devices):
self._name = name
self._host = host

View File

@ -3,35 +3,8 @@ homeassistant.components.media_player.kodi
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to the XBMC/Kodi JSON-RPC API
Configuration:
To use the Kodi you will need to add something like the following to
your configuration.yaml file.
media_player:
platform: kodi
name: Kodi
url: http://192.168.0.123/jsonrpc
user: kodi
password: my_secure_password
Variables:
name
*Optional
The name of the device.
url
*Required
The URL of the XBMC/Kodi JSON-RPC API. Example: http://192.168.0.123/jsonrpc
user
*Optional
The XBMC/Kodi HTTP username.
password
*Optional
The XBMC/Kodi HTTP password.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.kodi.html
"""
import urllib
import logging

View File

@ -3,35 +3,8 @@ homeassistant.components.media_player.mpd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to interact with a Music Player Daemon.
Configuration:
To use MPD you will need to add something like the following to your
configuration.yaml file.
media_player:
platform: mpd
server: 127.0.0.1
port: 6600
location: bedroom
password: superSecretPassword123
Variables:
server
*Required
IP address of the Music Player Daemon. Example: 192.168.1.32
port
*Optional
Port of the Music Player Daemon, defaults to 6600. Example: 6600
location
*Optional
Location of your Music Player Daemon.
password
*Optional
Password for your Music Player Daemon.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.mpd.html
"""
import logging
import socket

View File

@ -6,38 +6,114 @@ Provides an interface to the Plex API.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.plex.html
"""
import os
import json
import logging
from datetime import timedelta
from urllib.parse import urlparse
from homeassistant.loader import get_component
import homeassistant.util as util
from homeassistant.components.media_player import (
MediaPlayerDevice, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK,
SUPPORT_NEXT_TRACK, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO)
from homeassistant.const import (
STATE_IDLE, STATE_PLAYING, STATE_PAUSED, STATE_OFF, STATE_UNKNOWN)
import homeassistant.util as util
DEVICE_DEFAULT_NAME, STATE_IDLE, STATE_PLAYING,
STATE_PAUSED, STATE_OFF, STATE_UNKNOWN)
REQUIREMENTS = ['https://github.com/adrienbrault/python-plexapi/archive/'
'df2d0847e801d6d5cda920326d693cf75f304f1a.zip'
'#python-plexapi==1.0.2']
REQUIREMENTS = ['plexapi==1.1.0']
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1)
PLEX_CONFIG_FILE = 'plex.conf'
# Map ip to request id for configuring
_CONFIGURING = {}
_LOGGER = logging.getLogger(__name__)
SUPPORT_PLEX = SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK
# pylint: disable=abstract-method, unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the plex platform. """
from plexapi.myplex import MyPlexUser
from plexapi.exceptions import BadRequest
def config_from_file(filename, config=None):
''' Small configuration file management function'''
if config:
# We're writing configuration
try:
with open(filename, 'w') as fdesc:
fdesc.write(json.dumps(config))
except IOError as error:
_LOGGER.error('Saving config file failed: %s', error)
return False
return True
else:
# We're reading config
if os.path.isfile(filename):
try:
with open(filename, 'r') as fdesc:
return json.loads(fdesc.read())
except IOError as error:
_LOGGER.error('Reading config file failed: %s', error)
# This won't work yet
return False
else:
return {}
# pylint: disable=abstract-method, unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Sets up the plex platform. """
config = config_from_file(hass.config.path(PLEX_CONFIG_FILE))
if len(config):
# Setup a configured PlexServer
host, token = config.popitem()
token = token['token']
# Via discovery
elif discovery_info is not None:
# Parse discovery data
host = urlparse(discovery_info[1]).netloc
_LOGGER.info('Discovered PLEX server: %s', host)
if host in _CONFIGURING:
return
token = None
else:
return
setup_plexserver(host, token, hass, add_devices_callback)
# pylint: disable=too-many-branches
def setup_plexserver(host, token, hass, add_devices_callback):
''' Setup a plexserver based on host parameter'''
import plexapi.server
import plexapi.exceptions
try:
plexserver = plexapi.server.PlexServer('http://%s' % host, token)
except (plexapi.exceptions.BadRequest,
plexapi.exceptions.Unauthorized,
plexapi.exceptions.NotFound) as error:
_LOGGER.info(error)
# No token or wrong token
request_configuration(host, hass, add_devices_callback)
return
# If we came here and configuring this host, mark as done
if host in _CONFIGURING:
request_id = _CONFIGURING.pop(host)
configurator = get_component('configurator')
configurator.request_done(request_id)
_LOGGER.info('Discovery configuration done!')
# Save config
if not config_from_file(
hass.config.path(PLEX_CONFIG_FILE),
{host: {'token': token}}):
_LOGGER.error('failed to save config file')
_LOGGER.info('Connected to: htts://%s', host)
name = config.get('name', '')
user = config.get('user', '')
password = config.get('password', '')
plexuser = MyPlexUser.signin(user, password)
plexserver = plexuser.getResource(name).connect()
plex_clients = {}
plex_sessions = {}
@ -45,34 +121,34 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
def update_devices():
""" Updates the devices objects. """
try:
devices = plexuser.devices()
except BadRequest:
devices = plexserver.clients()
except plexapi.exceptions.BadRequest:
_LOGGER.exception("Error listing plex devices")
return
new_plex_clients = []
for device in devices:
if (all(x not in ['client', 'player'] for x in device.provides)
or 'PlexAPI' == device.product):
# For now, let's allow all deviceClass types
if device.deviceClass in ['badClient']:
continue
if device.clientIdentifier not in plex_clients:
if device.machineIdentifier not in plex_clients:
new_client = PlexClient(device, plex_sessions, update_devices,
update_sessions)
plex_clients[device.clientIdentifier] = new_client
plex_clients[device.machineIdentifier] = new_client
new_plex_clients.append(new_client)
else:
plex_clients[device.clientIdentifier].set_device(device)
plex_clients[device.machineIdentifier].set_device(device)
if new_plex_clients:
add_devices(new_plex_clients)
add_devices_callback(new_plex_clients)
@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
def update_sessions():
""" Updates the sessions objects. """
try:
sessions = plexserver.sessions()
except BadRequest:
except plexapi.exceptions.BadRequest:
_LOGGER.exception("Error listing plex sessions")
return
@ -84,10 +160,34 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
update_sessions()
def request_configuration(host, hass, add_devices_callback):
""" Request configuration steps from the user. """
configurator = get_component('configurator')
# We got an error if this method is called while we are configuring
if host in _CONFIGURING:
configurator.notify_errors(
_CONFIGURING[host], "Failed to register, please try again.")
return
def plex_configuration_callback(data):
""" Actions to do when our configuration callback is called. """
setup_plexserver(host, data.get('token'), hass, add_devices_callback)
_CONFIGURING[host] = configurator.request_config(
hass, "Plex Media Server", plex_configuration_callback,
description=('Enter the X-Plex-Token'),
description_image="/static/images/config_plex_mediaserver.png",
submit_caption="Confirm",
fields=[{'id': 'token', 'name': 'X-Plex-Token', 'type': ''}]
)
class PlexClient(MediaPlayerDevice):
""" Represents a Plex device. """
# pylint: disable=too-many-public-methods
# pylint: disable=too-many-public-methods, attribute-defined-outside-init
def __init__(self, device, plex_sessions, update_devices, update_sessions):
self.plex_sessions = plex_sessions
self.update_devices = update_devices
@ -99,17 +199,23 @@ class PlexClient(MediaPlayerDevice):
self.device = device
@property
def session(self):
""" Returns the session, if any. """
if self.device.clientIdentifier not in self.plex_sessions:
return None
return self.plex_sessions[self.device.clientIdentifier]
def unique_id(self):
""" Returns the id of this plex client """
return "{}.{}".format(
self.__class__, self.device.machineIdentifier or self.device.name)
@property
def name(self):
""" Returns the name of the device. """
return self.device.name or self.device.product or self.device.device
return self.device.name or DEVICE_DEFAULT_NAME
@property
def session(self):
""" Returns the session, if any. """
if self.device.machineIdentifier not in self.plex_sessions:
return None
return self.plex_sessions[self.device.machineIdentifier]
@property
def state(self):
@ -120,7 +226,8 @@ class PlexClient(MediaPlayerDevice):
return STATE_PLAYING
elif state == 'paused':
return STATE_PAUSED
elif self.device.isReachable:
# This is nasty. Need to find a way to determine alive
elif self.device:
return STATE_IDLE
else:
return STATE_OFF
@ -196,16 +303,16 @@ class PlexClient(MediaPlayerDevice):
def media_play(self):
""" media_play media player. """
self.device.play({'type': 'video'})
self.device.play()
def media_pause(self):
""" media_pause media player. """
self.device.pause({'type': 'video'})
self.device.pause()
def media_next_track(self):
""" Send next track command. """
self.device.skipNext({'type': 'video'})
self.device.skipNext()
def media_previous_track(self):
""" Send previous track command. """
self.device.skipPrevious({'type': 'video'})
self.device.skipPrevious()

View File

@ -1,17 +1,11 @@
"""
homeassistant.components.media_player.sonos
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to Sonos players (via SoCo)
Configuration:
To use SoCo, add something like this to your configuration:
media_player:
platform: sonos
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.sonos.html
"""
import logging
import datetime
@ -56,8 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
return True
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-public-methods
# pylint: disable=too-many-instance-attributes, too-many-public-methods
# pylint: disable=abstract-method
class SonosDevice(MediaPlayerDevice):
""" Represents a Sonos device. """
@ -74,7 +67,7 @@ class SonosDevice(MediaPlayerDevice):
return True
def update_sonos(self, now):
""" Updates state, called by track_utc_time_change """
""" Updates state, called by track_utc_time_change. """
self.update_ha_state(True)
@property
@ -162,31 +155,31 @@ class SonosDevice(MediaPlayerDevice):
return SUPPORT_SONOS
def turn_off(self):
""" turn_off media player. """
""" Turn off media player. """
self._player.pause()
def volume_up(self):
""" volume_up media player. """
""" Volume up media player. """
self._player.volume += 1
def volume_down(self):
""" volume_down media player. """
""" Volume down media player. """
self._player.volume -= 1
def set_volume_level(self, volume):
""" set volume level, range 0..1. """
""" Set volume level, range 0..1. """
self._player.volume = str(int(volume * 100))
def mute_volume(self, mute):
""" mute (true) or unmute (false) media player. """
""" Mute (true) or unmute (false) media player. """
self._player.mute = mute
def media_play(self):
""" media_play media player. """
""" Send paly command. """
self._player.play()
def media_pause(self):
""" media_pause media player. """
""" Send pause command. """
self._player.pause()
def media_next_track(self):
@ -202,5 +195,5 @@ class SonosDevice(MediaPlayerDevice):
self._player.seek(str(datetime.timedelta(seconds=int(position))))
def turn_on(self):
""" turn the media player on. """
""" Turn the media player on. """
self._player.play()

View File

@ -1,39 +1,11 @@
"""
homeassistant.components.media_player.squeezebox
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to the Logitech SqueezeBox API
Configuration:
To use SqueezeBox add something something like the following to your
configuration.yaml file.
media_player:
platform: squeezebox
host: 192.168.1.21
port: 9090
username: user
password: password
Variables:
host
*Required
The host name or address of the Logitech Media Server.
port
*Optional
Telnet port to Logitech Media Server, default 9090.
usermame
*Optional
Username, if password protection is enabled.
password
*Optional
Password, if password protection is enabled.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.squeezebox.html
"""
import logging
import telnetlib
import urllib.parse
@ -291,7 +263,7 @@ class SqueezeBoxDevice(MediaPlayerDevice):
def media_pause(self):
""" media_pause media player. """
self._lms.query(self._id, 'pause', '0')
self._lms.query(self._id, 'pause', '1')
self.update_ha_state()
def media_next_track(self):

View File

@ -3,27 +3,8 @@ homeassistant.components.modbus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Modbus component, using pymodbus (python3 branch).
Configuration:
To use the Modbus component you will need to add something like the following
to your configuration.yaml file.
#Modbus TCP
modbus:
type: tcp
host: 127.0.0.1
port: 2020
#Modbus RTU
modbus:
type: serial
method: rtu
port: /dev/ttyUSB0
baudrate: 9600
stopbits: 1
bytesize: 8
parity: N
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/modbus.html
"""
import logging

View File

@ -1,52 +1,10 @@
"""
homeassistant.components.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MQTT component, using paho-mqtt. This component needs a MQTT broker like
Mosquitto or Mosca. The Eclipse Foundation is running a public MQTT server
at iot.eclipse.org. If you prefer to use that one, keep in mind to adjust
the topic/client ID and that your messages are public.
MQTT component, using paho-mqtt.
Configuration:
To use MQTT you will need to add something like the following to your
config/configuration.yaml.
mqtt:
broker: 127.0.0.1
Or, if you want more options:
mqtt:
broker: 127.0.0.1
port: 1883
client_id: home-assistant-1
keepalive: 60
username: your_username
password: your_secret_password
certificate: /home/paulus/dev/addtrustexternalcaroot.crt
Variables:
broker
*Required
This is the IP address of your MQTT broker, e.g. 192.168.1.32.
port
*Optional
The network port to connect to. Default is 1883.
client_id
*Optional
Client ID that Home Assistant will use. Has to be unique on the server.
Default is a random generated one.
keepalive
*Optional
The keep alive in seconds for this client. Default is 60.
certificate
*Optional
Certificate to use for encrypting the connection to the broker.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/mqtt.html
"""
import logging
import os

View File

@ -3,26 +3,8 @@ homeassistant.components.notify.file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
File notification service.
Configuration:
To use the File notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: file
filename: FILENAME
timestamp: 1 or 0
Variables:
filename
*Required
Name of the file to use. The file will be created if it doesn't exist and saved
in your config/ folder.
timestamp
*Required
Add a timestamp to the entry, valid entries are 1 or 0.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.file.html
"""
import logging
import os

View File

@ -3,52 +3,8 @@ homeassistant.components.notify.instapush
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instapush notification service.
Configuration:
To use the Instapush notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: instapush
api_key: YOUR_APP_KEY
app_secret: YOUR_APP_SECRET
event: YOUR_EVENT
tracker: YOUR_TRACKER
Variables:
api_key
*Required
To retrieve this value log into your account at https://instapush.im and go
to 'APPS', choose an app, and check 'Basic Info'.
app_secret
*Required
To get this value log into your account at https://instapush.im and go to
'APPS'. The 'Application ID' can be found under 'Basic Info'.
event
*Required
To retrieve a valid event log into your account at https://instapush.im and go
to 'APPS'. If you have no events to use with Home Assistant, create one event
for your app.
tracker
*Required
To retrieve the tracker value log into your account at https://instapush.im and
go to 'APPS', choose the app, and check the event entries.
Example usage of Instapush if you have an event 'notification' and a tracker
'home-assistant'.
curl -X POST \
-H "x-instapush-appid: YOUR_APP_KEY" \
-H "x-instapush-appsecret: YOUR_APP_SECRET" \
-H "Content-Type: application/json" \
-d '{"event":"notification","trackers":{"home-assistant":"Switch 1"}}' \
https://api.instapush.im/v1/post
Details for the API : https://instapush.im/developer/rest
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.instapush.html
"""
import logging
import json

View File

@ -3,23 +3,8 @@ homeassistant.components.notify.nma
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NMA (Notify My Android) notification service.
Configuration:
To use the NMA notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: nma
api_key: YOUR_API_KEY
Variables:
api_key
*Required
Enter the API key for NMA. Go to https://www.notifymyandroid.com and create a
new API key to use with Home Assistant.
Details for the API : https://www.notifymyandroid.com/api.jsp
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.nma.html
"""
import logging
import xml.etree.ElementTree as ET

View File

@ -3,21 +3,8 @@ homeassistant.components.notify.pushbullet
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PushBullet platform for notify component.
Configuration:
To use the PushBullet notifier you will need to add something like the
following to your configuration.yaml file.
notify:
platform: pushbullet
api_key: YOUR_API_KEY
Variables:
api_key
*Required
Enter the API key for PushBullet. Go to https://www.pushbullet.com/ to retrieve
your API key.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.pushbullet.html
"""
import logging

View File

@ -3,35 +3,8 @@ homeassistant.components.notify.pushover
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pushover platform for notify component.
Configuration:
To use the Pushover notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: pushover
api_key: ABCDEFGHJKLMNOPQRSTUVXYZ
user_key: ABCDEFGHJKLMNOPQRSTUVXYZ
Variables:
api_key
*Required
This parameter is optional but should be configured, in order to get an API
key you should go to https://pushover.net and register a new application.
This is a quote from the pushover website regarding free/open source apps:
"If you are creating a client-side library, application, or open source project
that will be redistributed and installed by end-users, you may want to require
each of your users to register their own application rather than including your
own API token with the software."
When setting up the application I recommend using the icon located here:
https://home-assistant.io/images/favicon-192x192.png
user_key
*Required
To retrieve this value log into your account at https://pushover.net
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.pushover.html
"""
import logging

View File

@ -3,27 +3,8 @@ homeassistant.components.notify.slack
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Slack platform for notify component.
Configuration:
To use the Slack notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: slack
api_key: ABCDEFGHJKLMNOPQRSTUVXYZ
default_channel: '#general'
Variables:
api_key
*Required
The slack API token to use for sending slack messages.
You can get your slack API token here https://api.slack.com/web?sudo=1
default_channel
*Required
The default channel to post to if no channel is explicitly specified when
sending the notification message.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.slack.html
"""
import logging

View File

@ -3,54 +3,8 @@ homeassistant.components.notify.smtp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mail (SMTP) notification service.
Configuration:
To use the smtp notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: smtp
server: MAIL_SERVER
port: YOUR_SMTP_PORT
sender: SENDER_EMAIL_ADDRESS
starttls: 1 or 0
username: YOUR_SMTP_USERNAME
password: YOUR_SMTP_PASSWORD
recipient: YOUR_RECIPIENT
Variables:
server
*Required
SMTP server which is used to end the notifications. For Google Mail, eg.
smtp.gmail.com. Keep in mind that Google has some extra layers of protection
which need special attention (Hint: 'Less secure apps').
port
*Required
The port that the SMTP server is using, eg. 587 for Google Mail and STARTTLS
or 465/993 depending on your SMTP servers.
sender
*Required
E-Mail address of the sender.
starttls
*Optional
Enables STARTTLS, eg. 1 or 0.
username
*Required
Username for the SMTP account.
password
*Required
Password for the SMTP server that belongs to the given username. If the
password contains a colon it need to be wrapped in apostrophes.
recipient
*Required
Recipient of the notification.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.smtp.html
"""
import logging
import smtplib

View File

@ -3,31 +3,8 @@ homeassistant.components.notify.syslog
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Syslog notification service.
Configuration:
To use the Syslog notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: syslog
facility: SYSLOG_FACILITY
option: SYSLOG_LOG_OPTION
priority: SYSLOG_PRIORITY
Variables:
facility
*Optional
Facility according to RFC 3164 (http://tools.ietf.org/html/rfc3164). Default
is 'syslog' if no value is given.
option
*Option
Log option. Default is 'pid' if no value is given.
priority
*Optional
Priority of the messages. Default is 'info' if no value is given.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.syslog.html
"""
import logging
import syslog

View File

@ -3,31 +3,8 @@ homeassistant.components.notify.xmpp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jabber (XMPP) notification service.
Configuration:
To use the Jabber notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: xmpp
sender: YOUR_JID
password: YOUR_JABBER_ACCOUNT_PASSWORD
recipient: YOUR_RECIPIENT
Variables:
sender
*Required
The Jabber ID (JID) that will act as origin of the messages. Add your JID
including the domain, e.g. your_name@jabber.org.
password
*Required
The password for your given Jabber account.
recipient
*Required
The Jabber ID (JID) that will receive the messages.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.xmpp.html
"""
import logging

View File

@ -1,9 +1,11 @@
"""
homeassistant.components.recorder
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component that records all events and state changes. Allows other components
to query this database.
Component that records all events and state changes.
Allows other components to query this database.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/recorder.html
"""
import logging
import threading

View File

@ -3,7 +3,7 @@ homeassistant.components.rfxtrx
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides support for RFXtrx components.
For more details about this platform, please refer to the documentation at
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/rfxtrx.html
"""
import logging

View File

@ -1,39 +1,38 @@
"""
homeassistant.components.scene
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows users to set and activate scenes.
Allows users to set and activate scenes within Home Assistant.
A scene is a set of states that describe how you want certain entities to be.
For example, light A should be red with 100 brightness. Light B should be on.
A scene is active if all states of the scene match the real states.
If a scene is manually activated it will store the previous state of the
entities. These will be restored when the state is deactivated manually.
If one of the enties that are being tracked change state on its own, the
old state will not be restored when it is being deactivated.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/scene.html
"""
import logging
from collections import namedtuple
from homeassistant.core import State
from homeassistant.helpers.event import track_state_change
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.state import reproduce_state
from homeassistant.const import (
ATTR_ENTITY_ID, STATE_OFF, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF)
ATTR_ENTITY_ID, STATE_OFF, STATE_ON, SERVICE_TURN_ON)
DOMAIN = 'scene'
DEPENDENCIES = ['group']
ATTR_ACTIVE_REQUESTED = "active_requested"
STATE = 'scening'
CONF_ENTITIES = "entities"
SceneConfig = namedtuple('SceneConfig', ['name', 'states', 'fuzzy_match'])
SceneConfig = namedtuple('SceneConfig', ['name', 'states'])
def activate(hass, entity_id=None):
""" Activate a scene. """
data = {}
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_TURN_ON, data)
def setup(hass, config):
@ -43,8 +42,9 @@ def setup(hass, config):
scene_configs = config.get(DOMAIN)
if not isinstance(scene_configs, list):
logger.error('Scene config should be a list of scenes')
if not isinstance(scene_configs, list) or \
any(not isinstance(item, dict) for item in scene_configs):
logger.error('Scene config should be a list of dictionaries')
return False
component = EntityComponent(logger, DOMAIN, hass)
@ -57,12 +57,8 @@ def setup(hass, config):
target_scenes = component.extract_from_service(service)
for scene in target_scenes:
if service.service == SERVICE_TURN_ON:
scene.turn_on()
else:
scene.turn_off()
scene.activate()
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_scene_service)
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_scene_service)
return True
@ -72,14 +68,6 @@ def _process_config(scene_config):
""" Process passed in config into a format to work with. """
name = scene_config.get('name')
fuzzy_match = scene_config.get('fuzzy_match')
if fuzzy_match:
# default to 1%
if isinstance(fuzzy_match, int):
fuzzy_match /= 100.0
else:
fuzzy_match = 0.01
states = {}
c_entities = dict(scene_config.get(CONF_ENTITIES, {}))
@ -100,23 +88,16 @@ def _process_config(scene_config):
states[entity_id.lower()] = State(entity_id, state, attributes)
return SceneConfig(name, states, fuzzy_match)
return SceneConfig(name, states)
class Scene(ToggleEntity):
class Scene(Entity):
""" A scene is a group of entities and the states we want them to be. """
def __init__(self, hass, scene_config):
self.hass = hass
self.scene_config = scene_config
self.is_active = False
self.prev_states = None
self.ignore_updates = False
track_state_change(
self.hass, self.entity_ids, self.entity_state_changed)
self.update()
@property
@ -128,8 +109,8 @@ class Scene(ToggleEntity):
return self.scene_config.name
@property
def is_on(self):
return self.is_active
def state(self):
return STATE
@property
def entity_ids(self):
@ -141,82 +122,8 @@ class Scene(ToggleEntity):
""" Scene state attributes. """
return {
ATTR_ENTITY_ID: list(self.entity_ids),
ATTR_ACTIVE_REQUESTED: self.prev_states is not None,
}
def turn_on(self):
def activate(self):
""" Activates scene. Tries to get entities into requested state. """
self.prev_states = tuple(self.hass.states.get(entity_id)
for entity_id in self.entity_ids)
self._reproduce_state(self.scene_config.states.values())
def turn_off(self):
""" Deactivates scene and restores old states. """
if self.prev_states:
self._reproduce_state(self.prev_states)
self.prev_states = None
def entity_state_changed(self, entity_id, old_state, new_state):
""" Called when an entity part of this scene changes state. """
if self.ignore_updates:
return
# If new state is not what we expect, it can never be active
if self._state_as_requested(new_state):
self.update()
else:
self.is_active = False
self.prev_states = None
self.update_ha_state()
def update(self):
"""
Update if the scene is active.
Will look at each requested state and see if the current entity
has the same state and has at least the same attributes with the
same values. The real state can have more attributes.
"""
self.is_active = all(
self._state_as_requested(self.hass.states.get(entity_id))
for entity_id in self.entity_ids)
def _state_as_requested(self, cur_state):
""" Returns if given state is as requested. """
state = self.scene_config.states.get(cur_state and cur_state.entity_id)
return (cur_state is not None and state.state == cur_state.state and
all(self._compare_state_attribites(
value, cur_state.attributes.get(key))
for key, value in state.attributes.items()))
def _fuzzy_attribute_compare(self, attr_a, attr_b):
"""
Compare the attributes passed, use fuzzy logic if they are floats.
"""
if not (isinstance(attr_a, float) and isinstance(attr_b, float)):
return False
diff = abs(attr_a - attr_b) / (abs(attr_a) + abs(attr_b))
return diff <= self.scene_config.fuzzy_match
def _compare_state_attribites(self, attr1, attr2):
""" Compare the attributes passed, using fuzzy logic if specified. """
if attr1 == attr2:
return True
if not self.scene_config.fuzzy_match:
return False
if isinstance(attr1, list):
return all(self._fuzzy_attribute_compare(a, b)
for a, b in zip(attr1, attr2))
return self._fuzzy_attribute_compare(attr1, attr2)
def _reproduce_state(self, states):
""" Wraps reproduce state with Scence specific logic. """
self.ignore_updates = True
reproduce_state(self.hass, states, True)
self.ignore_updates = False
self.update_ha_state(True)
reproduce_state(self.hass, self.scene_config.states.values(), True)

View File

@ -1,161 +1,207 @@
"""
homeassistant.components.script
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
entity_id
Scripts are a sequence of actions that can be triggered manually
by the user or automatically based upon automation events, etc.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/script.html
"""
import logging
from datetime import timedelta
import homeassistant.util.dt as date_util
from itertools import islice
import threading
from homeassistant.helpers.event import track_point_in_time
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.event import track_point_in_utc_time
from homeassistant.util import split_entity_id
from homeassistant.const import (
STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF, EVENT_TIME_CHANGED)
ATTR_ENTITY_ID, EVENT_TIME_CHANGED, STATE_ON, SERVICE_TURN_ON,
SERVICE_TURN_OFF)
DOMAIN = "script"
ENTITY_ID_FORMAT = DOMAIN + '.{}'
DEPENDENCIES = ["group"]
STATE_NOT_RUNNING = 'Not Running'
CONF_ALIAS = "alias"
CONF_SERVICE = "execute_service"
CONF_SERVICE = "service"
CONF_SERVICE_OLD = "execute_service"
CONF_SERVICE_DATA = "service_data"
CONF_SEQUENCE = "sequence"
CONF_EVENT = "event"
CONF_EVENT_DATA = "event_data"
CONF_DELAY = "delay"
ATTR_ENTITY_ID = "entity_id"
ATTR_LAST_ACTION = 'last_action'
_LOGGER = logging.getLogger(__name__)
def is_on(hass, entity_id):
""" Returns if the switch is on based on the statemachine. """
return hass.states.is_state(entity_id, STATE_ON)
def turn_on(hass, entity_id):
""" Turn script on. """
_, object_id = split_entity_id(entity_id)
hass.services.call(DOMAIN, object_id)
def turn_off(hass, entity_id):
""" Turn script on. """
hass.services.call(DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id})
def setup(hass, config):
""" Load the scripts from the configuration. """
scripts = []
component = EntityComponent(_LOGGER, DOMAIN, hass)
def service_handler(service):
""" Execute a service call to script.<script name>. """
entity_id = ENTITY_ID_FORMAT.format(service.service)
script = component.entities.get(entity_id)
if script:
script.turn_on()
for name, cfg in config[DOMAIN].items():
if CONF_SEQUENCE not in cfg:
if not cfg.get(CONF_SEQUENCE):
_LOGGER.warn("Missing key 'sequence' for script %s", name)
continue
alias = cfg.get(CONF_ALIAS, name)
entity_id = "{}.{}".format(DOMAIN, name)
script = Script(hass, entity_id, alias, cfg[CONF_SEQUENCE])
hass.services.register(DOMAIN, name, script)
scripts.append(script)
script = Script(hass, alias, cfg[CONF_SEQUENCE])
component.add_entities((script,))
_, object_id = split_entity_id(script.entity_id)
hass.services.register(DOMAIN, object_id, service_handler)
def _get_entities(service):
""" Make sure that we always get a list of entities """
if isinstance(service.data[ATTR_ENTITY_ID], list):
return service.data[ATTR_ENTITY_ID]
else:
return [service.data[ATTR_ENTITY_ID]]
def turn_on_service(service):
""" Calls a service to turn script on. """
# We could turn on script directly here, but we only want to offer
# one way to do it. Otherwise no easy way to call invocations.
for script in component.extract_from_service(service):
turn_on(hass, script.entity_id)
def turn_on(service):
""" Calls a script. """
for entity_id in _get_entities(service):
domain, service = split_entity_id(entity_id)
hass.services.call(domain, service, {})
def turn_off(service):
def turn_off_service(service):
""" Cancels a script. """
for entity_id in _get_entities(service):
for script in scripts:
if script.entity_id == entity_id:
script.cancel()
for script in component.extract_from_service(service):
script.turn_off()
hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on)
hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off)
hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service)
hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service)
return True
class Script(object):
# pylint: disable=attribute-defined-outside-init
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-few-public-methods
"""
A script contains a sequence of service calls or configured delays
that are executed in order.
Each script also has a state (on/off) indicating whether the script is
running or not.
"""
def __init__(self, hass, entity_id, alias, sequence):
class Script(ToggleEntity):
""" Represents a script. """
def __init__(self, hass, name, sequence):
self.hass = hass
self.alias = alias
self._name = name
self.sequence = sequence
self.entity_id = entity_id
self._lock = threading.Lock()
self._reset()
self._cur = -1
self._last_action = None
self._listener = None
def cancel(self):
""" Cancels a running script and resets the state back to off. """
_LOGGER.info("Cancelled script %s", self.alias)
@property
def should_poll(self):
return False
@property
def name(self):
""" Returns the name of the entity. """
return self._name
@property
def state_attributes(self):
""" Returns the state attributes. """
attrs = {}
if self._last_action:
attrs[ATTR_LAST_ACTION] = self._last_action
return attrs
@property
def is_on(self):
""" True if entity is on. """
return self._cur != -1
def turn_on(self, **kwargs):
""" Turn the entity on. """
_LOGGER.info("Executing script %s", self._name)
with self._lock:
if self.listener:
self.hass.bus.remove_listener(EVENT_TIME_CHANGED,
self.listener)
self.listener = None
self._reset()
if self._cur == -1:
self._cur = 0
def _reset(self):
""" Resets a script back to default state so that it is ready to
run from the start again. """
self.actions = None
self.listener = None
self.last_action = "Not Running"
self.hass.states.set(self.entity_id, STATE_OFF, {
"friendly_name": self.alias,
"last_action": self.last_action
})
# Unregister callback if we were in a delay but turn on is called
# again. In that case we just continue execution.
self._remove_listener()
def _execute_until_done(self):
""" Executes a sequence of actions until finished or until a delay
is encountered. If a delay action is encountered, the script
registers itself to be called again in the future, when
_execute_until_done will resume.
for cur, action in islice(enumerate(self.sequence), self._cur,
None):
Returns True if finished, False otherwise. """
for action in self.actions:
if CONF_SERVICE in action:
self._call_service(action)
elif CONF_EVENT in action:
self._fire_event(action)
elif CONF_DELAY in action:
delay = timedelta(**action[CONF_DELAY])
point_in_time = date_util.now() + delay
self.listener = track_point_in_time(
self.hass, self, point_in_time)
return False
return True
if CONF_SERVICE in action or CONF_SERVICE_OLD in action:
self._call_service(action)
def __call__(self, *args, **kwargs):
""" Executes the script. """
_LOGGER.info("Executing script %s", self.alias)
elif CONF_EVENT in action:
self._fire_event(action)
elif CONF_DELAY in action:
# Call ourselves in the future to continue work
def script_delay(now):
""" Called after delay is done. """
self._listener = None
self.turn_on()
delay = timedelta(**action[CONF_DELAY])
self._listener = track_point_in_utc_time(
self.hass, script_delay, date_util.utcnow() + delay)
self._cur = cur + 1
self.update_ha_state()
return
self._cur = -1
self._last_action = None
self.update_ha_state()
def turn_off(self, **kwargs):
""" Turn script off. """
_LOGGER.info("Cancelled script %s", self._name)
with self._lock:
if self.actions is None:
self.actions = (action for action in self.sequence)
if self._cur == -1:
return
if not self._execute_until_done():
state = self.hass.states.get(self.entity_id)
state.attributes['last_action'] = self.last_action
self.hass.states.set(self.entity_id, STATE_ON,
state.attributes)
else:
self._reset()
self._cur = -1
self.update_ha_state()
self._remove_listener()
def _call_service(self, action):
""" Calls the service specified in the action. """
self.last_action = action.get(CONF_ALIAS, action[CONF_SERVICE])
_LOGGER.info("Executing script %s step %s", self.alias,
self.last_action)
domain, service = split_entity_id(action[CONF_SERVICE])
conf_service = action.get(CONF_SERVICE, action.get(CONF_SERVICE_OLD))
self._last_action = action.get(CONF_ALIAS, conf_service)
_LOGGER.info("Executing script %s step %s", self._name,
self._last_action)
domain, service = split_entity_id(conf_service)
data = action.get(CONF_SERVICE_DATA, {})
self.hass.services.call(domain, service, data)
def _fire_event(self, action):
""" Fires an event. """
self.last_action = action.get(CONF_ALIAS, action[CONF_EVENT])
_LOGGER.info("Executing script %s step %s", self.alias,
self.last_action)
self._last_action = action.get(CONF_ALIAS, action[CONF_EVENT])
_LOGGER.info("Executing script %s step %s", self._name,
self._last_action)
self.hass.bus.fire(action[CONF_EVENT], action.get(CONF_EVENT_DATA))
def _remove_listener(self):
""" Remove point in time listener, if any. """
if self._listener:
self.hass.bus.remove_listener(EVENT_TIME_CHANGED,
self._listener)
self._listener = None

View File

@ -4,36 +4,8 @@ homeassistant.components.sensor.arduino
Support for getting information from Arduino pins. Only analog pins are
supported.
Configuration:
To use the arduino sensor you will need to add something like the following
to your configuration.yaml file.
sensor:
platform: arduino
pins:
7:
name: Door switch
type: analog
0:
name: Brightness
type: analog
Variables:
pins
*Required
An array specifying the digital pins to use on the Arduino board.
These are the variables for the pins array:
name
*Required
The name for the pin that will be used in the frontend.
type
*Required
The type of the pin: 'analog'.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.arduino.html
"""
import logging

View File

@ -12,11 +12,12 @@ from datetime import timedelta
from homeassistant.util import Throttle
from homeassistant.helpers.entity import Entity
from homeassistant.const import DEVICE_DEFAULT_NAME
_LOGGER = logging.getLogger(__name__)
# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
CONF_RESOURCE = 'resource'
CONF_MONITORED_VARIABLES = 'monitored_variables'
@ -40,35 +41,68 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
"Add http:// to your URL.")
return False
except requests.exceptions.ConnectionError:
_LOGGER.error("No route to device. "
"Please check the IP address in the configuration file.")
_LOGGER.error("No route to device at %s. "
"Please check the IP address in the configuration file.",
resource)
return False
arest = ArestData(resource)
dev = []
pins = config.get('pins', None)
for variable in config['monitored_variables']:
if variable['name'] not in response['variables']:
_LOGGER.error('Variable: "%s" does not exist', variable['name'])
continue
dev.append(ArestSensor(arest, response['name'], variable['name'],
variable.get('unit')))
dev.append(ArestSensor(arest,
resource,
config.get('name', response['name']),
variable['name'],
variable=variable['name'],
unit_of_measurement=variable.get(
'unit_of_measurement')))
for pinnum, pin in pins.items():
dev.append(ArestSensor(ArestData(resource, pinnum),
resource,
config.get('name', response['name']),
pin.get('name'),
pin=pinnum,
unit_of_measurement=pin.get(
'unit_of_measurement'),
corr_factor=pin.get('correction_factor', None),
decimal_places=pin.get('decimal_places', None)))
add_devices(dev)
# pylint: disable=too-many-instance-attributes, too-many-arguments
class ArestSensor(Entity):
""" Implements an aREST sensor. """
""" Implements an aREST sensor for exposed variables. """
def __init__(self, arest, location, variable, unit_of_measurement):
def __init__(self, arest, resource, location, name, variable=None,
pin=None, unit_of_measurement=None, corr_factor=None,
decimal_places=None):
self.arest = arest
self._name = '{} {}'.format(location.title(), variable.title())
self._resource = resource
self._name = '{} {}'.format(location.title(), name.title()) \
or DEVICE_DEFAULT_NAME
self._variable = variable
self._pin = pin
self._state = 'n/a'
self._unit_of_measurement = unit_of_measurement
self._corr_factor = corr_factor
self._decimal_places = decimal_places
self.update()
if self._pin is not None:
request = requests.get('{}/mode/{}/i'.format
(self._resource, self._pin), timeout=10)
if request.status_code is not 200:
_LOGGER.error("Can't set mode. Is device offline?")
@property
def name(self):
""" The name of the sensor. """
@ -86,6 +120,16 @@ class ArestSensor(Entity):
if 'error' in values:
return values['error']
elif 'value' in values:
if self._corr_factor is not None \
and self._decimal_places is not None:
return round((float(values['value']) *
float(self._corr_factor)), self._decimal_places)
elif self._corr_factor is not None \
and self._decimal_places is None:
return round(float(values['value']) * float(self._corr_factor))
else:
return values['value']
else:
return values.get(self._variable, 'n/a')
@ -96,18 +140,34 @@ class ArestSensor(Entity):
# pylint: disable=too-few-public-methods
class ArestData(object):
""" Class for handling the data retrieval. """
""" Class for handling the data retrieval for variables. """
def __init__(self, resource):
self.resource = resource
def __init__(self, resource, pin=None):
self._resource = resource
self._pin = pin
self.data = {}
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
""" Gets the latest data from aREST device. """
try:
response = requests.get(self.resource, timeout=10)
self.data = response.json()['variables']
if self._pin is None:
response = requests.get(self._resource, timeout=10)
self.data = response.json()['variables']
else:
try:
if str(self._pin[0]) == 'A':
response = requests.get('{}/analog/{}'.format(
self._resource, self._pin[1:]), timeout=10)
self.data = {'value': response.json()['return_value']}
else:
_LOGGER.error("Wrong pin naming. "
"Please check your configuration file.")
except TypeError:
response = requests.get('{}/digital/{}'.format(
self._resource, self._pin), timeout=10)
self.data = {'value': response.json()['return_value']}
except requests.exceptions.ConnectionError:
_LOGGER.error("No route to device. Is device offline?")
_LOGGER.error("No route to device %s. Is device offline?",
self._resource)
self.data = {'error': 'error fetching'}

View File

@ -3,65 +3,8 @@ homeassistant.components.sensor.bitcoin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Bitcoin information service that uses blockchain.info and its online wallet.
Configuration:
You need to enable the API access for your online wallet to get the balance.
To do that log in and move to 'Account Setting', choose 'IP Restrictions', and
check 'Enable Api Access'. You will get an email message from blockchain.info
where you must authorize the API access.
To use the Bitcoin sensor you will need to add something like the following
to your configuration.yaml file.
sensor:
platform: bitcoin
wallet: 'YOUR WALLET_ID'
password: YOUR_ACCOUNT_PASSWORD
currency: YOUR CURRENCY
display_options:
- exchangerate
- trade_volume_btc
- miners_revenue_usd
- btc_mined
- trade_volume_usd
- difficulty
- minutes_between_blocks
- number_of_transactions
- hash_rate
- timestamp
- mined_blocks
- blocks_size
- total_fees_btc
- total_btc_sent
- estimated_btc_sent
- total_btc
- total_blocks
- next_retarget
- estimated_transaction_volume_usd
- miners_revenue_btc
- market_price_usd
Variables:
wallet
*Optional
This is your wallet identifier from https://blockchain.info to access the
online wallet.
password
*Optional
Password your your online wallet.
currency
*Optional
The currency to exchange to, eg. CHF, USD, EUR,etc. Default is USD.
display_options
*Optional
An array specifying the variables to display.
These are the variables for the display_options array. See the configuration
example above for a list of all available variables.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.bitcoin.html
"""
import logging
from datetime import timedelta

View File

@ -3,41 +3,6 @@ homeassistant.components.sensor.command_sensor
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure custom shell commands to turn a value for a sensor.
Configuration:
To use the command_line sensor you will need to add something like the
following to your configuration.yaml file.
sensor:
platform: command_sensor
name: "Command sensor"
command: sensor_command
unit_of_measurement: "°C"
correction_factor: 0.0001
decimal_places: 0
Variables:
name
*Optional
Name of the command sensor.
command
*Required
The action to take to get the value.
unit_of_measurement
*Optional
Defines the units of measurement of the sensor, if any.
correction_factor
*Optional
A float value to do some basic calculations.
decimal_places
*Optional
Number of decimal places of the value. Default is 0.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.command_sensor.html
"""
@ -133,7 +98,7 @@ class CommandSensorData(object):
_LOGGER.info('Running command: %s', self.command)
try:
return_value = subprocess.check_output(self.command.split())
return_value = subprocess.check_output(self.command, shell=True)
self.value = return_value.strip().decode('utf-8')
except subprocess.CalledProcessError:
_LOGGER.error('Command failed: %s', self.command)

View File

@ -0,0 +1,76 @@
"""
homeassistant.components.sensor.cpuspeed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Shows the current CPU speed.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.cpuspeed.html
"""
import logging
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['py-cpuinfo==0.1.6']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "CPU speed"
ATTR_VENDOR = 'Vendor ID'
ATTR_BRAND = 'Brand'
ATTR_HZ = 'GHz Advertised'
# pylint: disable=unused-variable
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the CPU speed sensor. """
try:
import cpuinfo # noqa
except ImportError:
_LOGGER.exception(
"Unable to import cpuinfo. "
"Did you maybe not install the 'py-cpuinfo' package?")
return False
add_devices([CpuSpeedSensor(config.get('name', DEFAULT_NAME))])
class CpuSpeedSensor(Entity):
""" A CPU info sensor. """
def __init__(self, name):
self._name = name
self._state = None
self._unit_of_measurement = 'GHz'
self.update()
@property
def name(self):
return self._name
@property
def state(self):
""" Returns the state of the device. """
return self._state
@property
def unit_of_measurement(self):
return self._unit_of_measurement
@property
def state_attributes(self):
""" Returns the state attributes. """
if self.info is not None:
return {
ATTR_VENDOR: self.info['vendor_id'],
ATTR_BRAND: self.info['brand'],
ATTR_HZ: round(self.info['hz_advertised_raw'][0]/10**9, 2)
}
def update(self):
""" Gets the latest data and updates the state. """
from cpuinfo import cpuinfo
self.info = cpuinfo.get_cpu_info()
self._state = round(float(self.info['hz_actual_raw'][0])/10**9, 2)

View File

@ -2,39 +2,9 @@
homeassistant.components.sensor.dht
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adafruit DHT temperature and humidity sensor.
You need a Python3 compatible version of the Adafruit_Python_DHT library
(e.g. https://github.com/mala-zaba/Adafruit_Python_DHT,
also see requirements.txt).
As this requires access to the GPIO, you will need to run home-assistant
as root.
Configuration:
To use the Adafruit DHT sensor you will need to add something like the
following to your configuration.yaml file.
sensor:
platform: dht
sensor: DHT22
pin: 23
monitored_conditions:
- temperature
- humidity
Variables:
sensor
*Required
The sensor type, DHT11, DHT22 or AM2302
pin
*Required
The pin the sensor is connected to, something like
'P8_11' for Beaglebone, '23' for Raspberry Pi
monitored_conditions
*Optional
Conditions to monitor. Available conditions are temperature and humidity.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.dht.html
"""
import logging
from datetime import timedelta

View File

@ -4,47 +4,8 @@ homeassistant.components.sensor.efergy
Monitors home energy use as measured by an efergy engage hub using its
(unofficial, undocumented) API.
Configuration:
To use the efergy sensor you will need to add something like the following
to your configuration.yaml file.
sensor:
platform: efergy
app_token: APP_TOKEN
utc_offset: UTC_OFFSET
monitored_variables:
- type: instant_readings
- type: budget
- type: cost
period: day
currency: $
Variables:
api_key
*Required
To get a new App Token, log in to your efergy account, go
to the Settings page, click on App tokens, and click "Add token".
utc_offset
*Required for some variables
Some variables (currently only the daily_cost) require that the
negative number of minutes your timezone is ahead/behind UTC time.
monitored_variables
*Required
An array specifying the variables to monitor.
period
*Optional
Some variables take a period argument. Valid options are "day", "week",
"month", and "year".
currency
*Optional
This is used to display the cost/period as the unit when monitoring the
cost. It should correspond to the actual currency used in your dashboard.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.efergy.html
"""
import logging
from requests import get

View File

@ -3,46 +3,8 @@ homeassistant.components.sensor.forecast
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Forecast.io weather service.
Configuration:
To use the Forecast sensor you will need to add something like the
following to your configuration.yaml file.
sensor:
platform: forecast
api_key: YOUR_APP_KEY
monitored_conditions:
- summary
- precip_type
- precip_intensity
- temperature
- dew_point
- wind_speed
- wind_bearing
- cloud_cover
- humidity
- pressure
- visibility
- ozone
Variables:
api_key
*Required
To retrieve this value log into your account at http://forecast.io/. You can
make 1000 requests per day. This means that you could create every 1.4 minute
one.
monitored_conditions
*Required
An array specifying the conditions to monitor.
monitored_conditions
*Required
Conditions to monitor. See the configuration example above for a
list of all available conditions to monitor.
Details for the API : https://developer.forecast.io/docs/v2
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.forecast.html
"""
import logging
from datetime import timedelta
@ -55,23 +17,34 @@ except ImportError:
forecastio = None
from homeassistant.util import Throttle
from homeassistant.const import (CONF_API_KEY, TEMP_CELCIUS, TEMP_FAHRENHEIT)
from homeassistant.const import (CONF_API_KEY, TEMP_CELCIUS)
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
# Sensor types are defined like so:
# Name, si unit, us unit, ca unit, uk unit, uk2 unit
SENSOR_TYPES = {
'summary': ['Summary', ''],
'precip_type': ['Precip', ''],
'precip_intensity': ['Precip intensity', 'mm'],
'temperature': ['Temperature', ''],
'dew_point': ['Dew point', '°C'],
'wind_speed': ['Wind Speed', 'm/s'],
'wind_bearing': ['Wind Bearing', '°'],
'cloud_cover': ['Cloud coverage', '%'],
'humidity': ['Humidity', '%'],
'pressure': ['Pressure', 'mBar'],
'visibility': ['Visibility', 'km'],
'ozone': ['Ozone', 'DU'],
'summary': ['Summary', '', '', '', '', ''],
'icon': ['Icon', '', '', '', '', ''],
'nearest_storm_distance': ['Nearest Storm Distance',
'km', 'm', 'km', 'km', 'm'],
'nearest_storm_bearing': ['Nearest Storm Bearing',
'°', '°', '°', '°', '°'],
'precip_type': ['Precip', '', '', '', '', ''],
'precip_intensity': ['Precip Intensity', 'mm', 'in', 'mm', 'mm', 'mm'],
'precip_probability': ['Precip Probability', '%', '%', '%', '%', '%'],
'temperature': ['Temperature', '°C', '°F', '°C', '°C', '°C'],
'apparent_temperature': ['Apparent Temperature',
'°C', '°F', '°C', '°C', '°C'],
'dew_point': ['Dew point', '°C', '°F', '°C', '°C', '°C'],
'wind_speed': ['Wind Speed', 'm/s', 'mph', 'km/h', 'mph', 'mph'],
'wind_bearing': ['Wind Bearing', '°', '°', '°', '°', '°'],
'cloud_cover': ['Cloud Coverage', '%', '%', '%', '%', '%'],
'humidity': ['Humidity', '%', '%', '%', '%', '%'],
'pressure': ['Pressure', 'mBar', 'mBar', 'mBar', 'mBar', 'mBar'],
'visibility': ['Visibility', 'km', 'm', 'km', 'km', 'm'],
'ozone': ['Ozone', 'DU', 'DU', 'DU', 'DU', 'DU'],
}
# Return cached results if last scan was less then this time ago
@ -90,9 +63,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.error("Latitude or longitude not set in Home Assistant config")
return False
SENSOR_TYPES['temperature'][1] = hass.config.temperature_unit
unit = hass.config.temperature_unit
try:
forecast = forecastio.load_forecast(config.get(CONF_API_KEY, None),
hass.config.latitude,
@ -104,16 +74,24 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
"Please check your settings for Forecast.io.")
return False
if 'units' in config:
units = config['units']
elif hass.config.temperature_unit == TEMP_CELCIUS:
units = 'si'
else:
units = 'us'
data = ForeCastData(config.get(CONF_API_KEY, None),
hass.config.latitude,
hass.config.longitude)
hass.config.longitude,
units)
dev = []
for variable in config['monitored_conditions']:
if variable not in SENSOR_TYPES:
_LOGGER.error('Sensor type: "%s" does not exist', variable)
else:
dev.append(ForeCastSensor(data, variable, unit))
dev.append(ForeCastSensor(data, variable))
add_devices(dev)
@ -122,14 +100,23 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class ForeCastSensor(Entity):
""" Implements an Forecast.io sensor. """
def __init__(self, weather_data, sensor_type, unit):
def __init__(self, weather_data, sensor_type):
self.client_name = 'Weather'
self._name = SENSOR_TYPES[sensor_type][0]
self.forecast_client = weather_data
self._unit = unit
self.type = sensor_type
self._state = None
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
self._unit_system = self.forecast_client.unit_system
if self._unit_system == 'si':
self._unit_of_measurement = SENSOR_TYPES[self.type][1]
elif self._unit_system == 'us':
self._unit_of_measurement = SENSOR_TYPES[self.type][2]
elif self._unit_system == 'ca':
self._unit_of_measurement = SENSOR_TYPES[self.type][3]
elif self._unit_system == 'uk':
self._unit_of_measurement = SENSOR_TYPES[self.type][4]
elif self._unit_system == 'uk2':
self._unit_of_measurement = SENSOR_TYPES[self.type][5]
self.update()
@property
@ -146,6 +133,11 @@ class ForeCastSensor(Entity):
""" Unit of measurement of this entity, if any. """
return self._unit_of_measurement
@property
def unit_system(self):
""" Unit system of this entity. """
return self._unit_system
# pylint: disable=too-many-branches
def update(self):
""" Gets the latest data from Forecast.io and updates the states. """
@ -156,7 +148,14 @@ class ForeCastSensor(Entity):
try:
if self.type == 'summary':
self._state = data.summary
elif self.type == 'icon':
self._state = data.icon
elif self.type == 'nearest_storm_distance':
self._state = data.nearestStormDistance
elif self.type == 'nearest_storm_bearing':
self._state = data.nearestStormBearing
elif self.type == 'precip_intensity':
self._state = data.precipIntensity
if data.precipIntensity == 0:
self._state = 'None'
self._unit_of_measurement = ''
@ -168,20 +167,14 @@ class ForeCastSensor(Entity):
self._unit_of_measurement = ''
else:
self._state = data.precipType
elif self.type == 'precip_probability':
self._state = round(data.precipProbability * 100, 1)
elif self.type == 'dew_point':
if self._unit == TEMP_CELCIUS:
self._state = round(data.dewPoint, 1)
elif self._unit == TEMP_FAHRENHEIT:
self._state = round(data.dewPoint * 1.8 + 32.0, 1)
else:
self._state = round(data.dewPoint, 1)
self._state = round(data.dewPoint, 1)
elif self.type == 'temperature':
if self._unit == TEMP_CELCIUS:
self._state = round(data.temperature, 1)
elif self._unit == TEMP_FAHRENHEIT:
self._state = round(data.temperature * 1.8 + 32.0, 1)
else:
self._state = round(data.temperature, 1)
self._state = round(data.temperature, 1)
elif self.type == 'apparent_temperature':
self._state = round(data.apparentTemperature, 1)
elif self.type == 'wind_speed':
self._state = data.windSpeed
elif self.type == 'wind_bearing':
@ -196,6 +189,7 @@ class ForeCastSensor(Entity):
self._state = data.visibility
elif self.type == 'ozone':
self._state = round(data.ozone, 1)
except forecastio.utils.PropertyUnavailable:
pass
@ -203,11 +197,14 @@ class ForeCastSensor(Entity):
class ForeCastData(object):
""" Gets the latest data from Forecast.io. """
def __init__(self, api_key, latitude, longitude):
def __init__(self, api_key, latitude, longitude, units):
self._api_key = api_key
self.latitude = latitude
self.longitude = longitude
self.data = None
self.unit_system = None
self.units = units
self.update()
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
@ -216,5 +213,6 @@ class ForeCastData(object):
forecast = forecastio.load_forecast(self._api_key,
self.latitude,
self.longitude,
units='si')
units=self.units)
self.data = forecast.currently()
self.unit_system = forecast.json['flags']['units']

View File

@ -3,51 +3,6 @@ homeassistant.components.sensor.glances
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Gathers system information of hosts which running glances.
Configuration:
To use the glances sensor you will need to add something like the following
to your configuration.yaml file.
sensor:
platform: glances
name: Glances sensor
host: IP_ADDRESS
port: 61208
resources:
- 'disk_use_percent'
- 'disk_use'
- 'disk_free'
- 'memory_use_percent'
- 'memory_use'
- 'memory_free'
- 'swap_use_percent'
- 'swap_use'
- 'swap_free'
- 'processor_load'
- 'process_running'
- 'process_total'
- 'process_thread'
- 'process_sleeping'
Variables:
name
*Optional
The name of the sensor. Default is 'Glances Sensor'.
host
*Required
The IP address of your host, e.g. 192.168.1.32.
port
*Optional
The network port to connect to. Default is 61208.
resources
*Required
Resources to monitor on the host. See the configuration example above for a
list of all available conditions to monitor.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.glances.html
"""

View File

@ -2,6 +2,9 @@
homeassistant.components.sensor.isy994
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for ISY994 sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/isy994.html
"""
import logging

View File

@ -3,50 +3,8 @@ homeassistant.components.modbus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Modbus sensors.
Configuration:
To use the Modbus sensors you will need to add something like the following to
your configuration.yaml file.
sensor:
platform: modbus
slave: 1
registers:
16:
name: My integer sensor
unit: C
24:
bits:
0:
name: My boolean sensor
2:
name: My other boolean sensor
coils:
0:
name: My coil switch
Variables:
slave
*Required
Slave number (ignored and can be omitted if not serial Modbus).
unit
*Required
Unit to attach to value (optional, ignored for boolean sensors).
registers
*Required
Contains a list of relevant registers to read from. It can contain a
"bits" section, listing relevant bits.
coils
*Optional
Contains a list of relevant coils to read from.
Note:
- Each named register will create an integer sensor.
- Each named bit will create a boolean sensor.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.modbus.html
"""
import logging

View File

@ -1,41 +1,11 @@
# -*- coding: utf-8 -*-
"""
homeassistant.components.sensor.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a MQTT sensor.
This generic sensor implementation uses the MQTT message payload
as the sensor value. If messages in this state_topic are published
with RETAIN flag, the sensor will receive an instant update with
last known value. Otherwise, the initial state will be undefined.
sensor:
platform: mqtt
name: "MQTT Sensor"
state_topic: "home/bedroom/temperature"
qos: 0
unit_of_measurement: "ºC"
Variables:
name
*Optional
The name of the sensor. Default is 'MQTT Sensor'.
state_topic
*Required
The MQTT topic subscribed to receive sensor values.
qos
*Optional
The maximum QoS level of the state topic. Default is 0.
unit_of_measurement
*Optional
Defines the units of measurement of the sensor, if any.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.mqtt.html
"""
import logging
from homeassistant.helpers.entity import Entity
import homeassistant.components.mqtt as mqtt
@ -50,7 +20,7 @@ DEPENDENCIES = ['mqtt']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Add MQTT Sensor """
""" Add MQTT Sensor. """
if config.get('state_topic') is None:
_LOGGER.error("Missing required variable: state_topic")
@ -66,7 +36,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
# pylint: disable=too-many-arguments, too-many-instance-attributes
class MqttSensor(Entity):
""" Represents a sensor that can be updated using MQTT """
""" Represents a sensor that can be updated using MQTT. """
def __init__(self, hass, name, state_topic, qos, unit_of_measurement):
self._state = "-"
self._hass = hass

View File

@ -3,20 +3,8 @@ homeassistant.components.sensor.mysensors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for MySensors sensors.
Configuration:
To use the MySensors sensor you will need to add something like the
following to your configuration.yaml file.
sensor:
platform: mysensors
port: '/dev/ttyACM0'
Variables:
port
*Required
Port of your connection to your MySensors device.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.mysensors.html
"""
import logging
@ -30,14 +18,16 @@ from homeassistant.const import (
CONF_PORT = "port"
CONF_DEBUG = "debug"
CONF_PERSISTENCE = "persistence"
CONF_PERSISTENCE_FILE = "persistence_file"
CONF_VERSION = "version"
ATTR_NODE_ID = "node_id"
ATTR_CHILD_ID = "child_id"
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['https://github.com/theolind/pymysensors/archive/'
'35b87d880147a34107da0d40cb815d75e6cb4af7.zip'
'#pymysensors==0.2']
'd4b809c2167650691058d1e29bfd2c4b1792b4b0.zip'
'#pymysensors==0.3']
def setup_platform(hass, config, add_devices, discovery_info=None):
@ -86,9 +76,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
return False
persistence = config.get(CONF_PERSISTENCE, True)
persistence_file = config.get(CONF_PERSISTENCE_FILE, 'mysensors.pickle')
version = config.get(CONF_VERSION, '1.4')
gateway = mysensors.SerialGateway(port, sensor_update,
persistence=persistence)
persistence=persistence,
persistence_file=persistence_file,
protocol_version=version)
gateway.metric = is_metric
gateway.debug = config.get(CONF_DEBUG, False)
gateway.start()

View File

@ -3,43 +3,8 @@ homeassistant.components.sensor.openweathermap
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OpenWeatherMap (OWM) service.
Configuration:
To use the OpenWeatherMap sensor you will need to add something like the
following to your configuration.yaml file.
sensor:
platform: openweathermap
api_key: YOUR_APP_KEY
forecast: 0 or 1
monitored_conditions:
- weather
- temperature
- wind_speed
- humidity
- pressure
- clouds
- rain
- snow
Variables:
api_key
*Required
To retrieve this value log into your account at http://openweathermap.org/
forecast
*Optional
Enables the forecast. The default is to display the current conditions.
monitored_conditions
*Required
Conditions to monitor. See the configuration example above for a
list of all available conditions to monitor.
Details for the API : http://bugs.openweathermap.org/projects/api/wiki
Only metric measurements are supported at the moment.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.openweathermap.html
"""
import logging
from datetime import timedelta

View File

@ -1,41 +1,10 @@
# -*- coding: utf-8 -*-
"""
homeassistant.components.sensor.rpi_gpio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a binary state sensor using RPi GPIO.
To avoid having to run Home Assistant as root when using this component,
run a Raspbian version released at or after September 29, 2015.
sensor:
platform: rpi_gpio
pull_mode: "UP"
value_high: "Active"
value_low: "Inactive"
ports:
11: PIR Office
12: PIR Bedroom
Variables:
pull_mode
*Optional
The internal pull to use (UP or DOWN). Default is UP.
value_high
*Optional
The value of the sensor when the port is HIGH. Default is "HIGH".
value_low
*Optional
The value of the sensor when the port is LOW. Default is "LOW".
bouncetime
*Optional
The time in milliseconds for port debouncing. Default is 50ms.
ports
*Required
An array specifying the GPIO ports to use and the name to use in the frontend.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.rpi_gpio.html
"""
import logging
from homeassistant.helpers.entity import Entity

View File

@ -1,47 +1,10 @@
"""
homeassistant.components.sensor.sabnzbd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Monitors SABnzbd NZB client API
Monitors SABnzbd NZB client API.
Configuration:
To use the SABnzbd sensor you will need to add something like the following to
your configuration.yaml file.
sensor:
platform: sabnzbd
name: SAB
api_key: YOUR_API_KEY
base_url: YOUR_SABNZBD_BASE_URL
monitored_variables:
- type: 'current_status'
- type: 'speed'
- type: 'queue_size'
- type: 'queue_remaining'
- type: 'disk_size'
- type: 'disk_free'
Variables:
base_url
*Required
This is the base URL of your SABnzbd instance including the port number if not
running on 80, e.g. http://192.168.1.32:8124/
name
*Optional
The name to use when displaying this SABnzbd instance.
monitored_variables
*Required
An array specifying the variables to monitor.
These are the variables for the monitored_variables array:
type
*Required
The variable you wish to monitor, see the configuration example above for a
list of all available variables.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.sabnzbd.html
"""
from homeassistant.util import Throttle
from datetime import timedelta

View File

@ -4,30 +4,8 @@ homeassistant.components.sensor.swiss_public_transport
The Swiss public transport sensor will give you the next two departure times
from a given location to another one. This sensor is limited to Switzerland.
Configuration:
To use the Swiss public transport sensor you will need to add something like
the following to your configuration.yaml file.
sensor:
platform: swiss_public_transport
from: STATION_ID
to: STATION_ID
Variables:
from
*Required
Start station/stop of your trip. To search for the ID of the station, use the
an URL like this: http://transport.opendata.ch/v1/locations?query=Wankdorf
to query for the station. If the score is 100 ("score":"100" in the response),
it is a perfect match.
to
*Required
Destination station/stop of the trip. Same procedure as for the start station.
Details for the API : http://transport.opendata.ch
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.swiss_public_transport.html
"""
import logging
from datetime import timedelta
@ -40,6 +18,12 @@ from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
_RESOURCE = 'http://transport.opendata.ch/v1/'
ATTR_DEPARTURE_TIME1 = 'Next departure'
ATTR_DEPARTURE_TIME2 = 'Next on departure'
ATTR_START = 'Start'
ATTR_TARGET = 'Destination'
ATTR_REMAINING_TIME = 'Remaining time'
# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
@ -60,8 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.exception(
"Unable to determine stations. "
"Check your settings and/or the availability of opendata.ch")
return None
return False
dev = []
data = PublicTransportData(journey)
@ -75,7 +58,9 @@ class SwissPublicTransportSensor(Entity):
def __init__(self, data, journey):
self.data = data
self._name = '{}-{}'.format(journey[2], journey[3])
self._name = 'Next Departure'
self._from = journey[2]
self._to = journey[3]
self.update()
@property
@ -88,12 +73,26 @@ class SwissPublicTransportSensor(Entity):
""" Returns the state of the device. """
return self._state
@property
def state_attributes(self):
""" Returns the state attributes. """
if self._times is not None:
return {
ATTR_DEPARTURE_TIME1: self._times[0],
ATTR_DEPARTURE_TIME2: self._times[1],
ATTR_START: self._from,
ATTR_TARGET: self._to,
ATTR_REMAINING_TIME: '{}'.format(
':'.join(str(self._times[2]).split(':')[:2]))
}
# pylint: disable=too-many-branches
def update(self):
""" Gets the latest data from opendata.ch and updates the states. """
times = self.data.update()
self.data.update()
self._times = self.data.times
try:
self._state = ', '.join(times)
self._state = self._times[0]
except TypeError:
pass
@ -105,6 +104,7 @@ class PublicTransportData(object):
def __init__(self, journey):
self.start = journey[0]
self.destination = journey[1]
self.times = {}
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
@ -117,16 +117,21 @@ class PublicTransportData(object):
'to=' + self.destination + '&' +
'fields[]=connections/from/departureTimestamp/&' +
'fields[]=connections/',
timeout=10)
timeout=30)
connections = response.json()['connections'][:2]
try:
return [
self.times = [
dt_util.datetime_to_time_str(
dt_util.as_local(dt_util.utc_from_timestamp(
item['from']['departureTimestamp']))
)
for item in connections
]
self.times.append(
dt_util.as_local(
dt_util.utc_from_timestamp(
connections[0]['from']['departureTimestamp'])) -
dt_util.as_local(dt_util.utcnow()))
except KeyError:
return ['n/a']
self.times = ['n/a']

View File

@ -3,60 +3,8 @@ homeassistant.components.sensor.systemmonitor
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Shows system monitor values such as: disk, memory, and processor use.
Configuration:
To use the System monitor sensor you will need to add something like the
following to your configuration.yaml file.
sensor:
platform: systemmonitor
resources:
- type: 'disk_use_percent'
arg: '/'
- type: 'disk_use'
arg: '/home'
- type: 'disk_free'
arg: '/'
- type: 'memory_use_percent'
- type: 'memory_use'
- type: 'memory_free'
- type: 'swap_use_percent'
- type: 'swap_use'
- type: 'swap_free'
- type: 'network_in'
arg: 'eth0'
- type: 'network_out'
arg: 'eth0'
- type: 'packets_in'
arg: 'eth0'
- type: 'packets_out'
arg: 'eth0'
- type: 'ipv4_address'
arg: 'eth0'
- type: 'ipv6_address'
arg: 'eth0'
- type: 'processor_use'
- type: 'process'
arg: 'octave-cli'
- type: 'last_boot'
- type: 'since_last_boot'
Variables:
resources
*Required
An array specifying the variables to monitor.
These are the variables for the resources array:
type
*Required
The variable you wish to monitor, see the configuration example above for a
sample list of variables.
arg
*Optional
Additional details for the type, eg. path, binary name, etc.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.systemmonitor.html
"""
import logging
@ -64,7 +12,7 @@ import homeassistant.util.dt as dt_util
from homeassistant.helpers.entity import Entity
from homeassistant.const import STATE_ON, STATE_OFF
REQUIREMENTS = ['psutil==3.0.0']
REQUIREMENTS = ['psutil==3.2.2']
SENSOR_TYPES = {
'disk_use_percent': ['Disk Use', '%'],
'disk_use': ['Disk Use', 'GiB'],

View File

@ -3,24 +3,8 @@ homeassistant.components.sensor.tellstick
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Shows sensor values from Tellstick sensors.
Possible config keys:
id of the sensor: Name the sensor with ID
135=Outside
only_named: Only show the named sensors
only_named=1
temperature_scale: The scale of the temperature value
temperature_scale=°C
datatype_mask: mask to determine which sensor values to show based on
https://tellcore-py.readthedocs.org
/en/v1.0.4/constants.html#module-tellcore.constants
datatype_mask=1 # only show temperature
datatype_mask=12 # only show rain rate and rain total
datatype_mask=127 # show all sensor values
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.tellstick.html
"""
import logging
from collections import namedtuple

View File

@ -3,13 +3,8 @@ homeassistant.components.sensor.temper
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for getting temperature from TEMPer devices.
Configuration:
To use the temper sensors you will need to add something like the following to
your configuration.yaml file.
sensor:
platform: temper
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.temper.html
"""
import logging
from homeassistant.helpers.entity import Entity

Some files were not shown because too many files have changed in this diff Show More