Merge pull request #1502 from balloob/dev

0.15
This commit is contained in:
Paulus Schoutsen 2016-03-12 11:29:30 -08:00
commit 6797365d4f
433 changed files with 6939 additions and 5439 deletions

View File

@ -51,15 +51,15 @@ omit =
homeassistant/components/zwave.py
homeassistant/components/*/zwave.py
homeassistant/components/rfxtrx.py
homeassistant/components/*/rfxtrx.py
homeassistant/components/mysensors.py
homeassistant/components/*/mysensors.py
homeassistant/components/nest.py
homeassistant/components/*/nest.py
homeassistant/components/rfxtrx.py
homeassistant/components/*/rfxtrx.py
homeassistant/components/rpi_gpio.py
homeassistant/components/*/rpi_gpio.py
@ -123,6 +123,7 @@ omit =
homeassistant/components/notify/telegram.py
homeassistant/components/notify/twitter.py
homeassistant/components/notify/xmpp.py
homeassistant/components/scene/hunterdouglas_powerview.py
homeassistant/components/sensor/arest.py
homeassistant/components/sensor/bitcoin.py
homeassistant/components/sensor/cpuspeed.py
@ -139,8 +140,8 @@ omit =
homeassistant/components/sensor/openweathermap.py
homeassistant/components/sensor/rest.py
homeassistant/components/sensor/sabnzbd.py
homeassistant/components/sensor/steam_online.py
homeassistant/components/sensor/speedtest.py
homeassistant/components/sensor/steam_online.py
homeassistant/components/sensor/swiss_public_transport.py
homeassistant/components/sensor/systemmonitor.py
homeassistant/components/sensor/temper.py
@ -150,8 +151,8 @@ omit =
homeassistant/components/sensor/twitch.py
homeassistant/components/sensor/worldclock.py
homeassistant/components/switch/arest.py
homeassistant/components/switch/edimax.py
homeassistant/components/switch/dlink.py
homeassistant/components/switch/edimax.py
homeassistant/components/switch/hikvisioncam.py
homeassistant/components/switch/mystrom.py
homeassistant/components/switch/orvibo.py
@ -162,6 +163,7 @@ omit =
homeassistant/components/thermostat/proliphix.py
homeassistant/components/thermostat/radiotherm.py
[report]
# Regexes for lines to exclude from consideration
exclude_lines =

View File

@ -2,6 +2,7 @@
**Related issue (if applicable):** #
**Example entry for `configuration.yaml` (if applicable):**
```yaml
@ -9,17 +10,17 @@
**Checklist:**
- [ ] Local tests with `tox` ran successfully.
- [ ] No CI failures. **Your PR cannot be merged unless CI is green!**
- [ ] Local tests with `tox` run successfully.
- [ ] TravisCI does not fail. **Your PR cannot be merged unless CI is green!**
- [ ] [Fork is up to date][fork] and was rebased on the `dev` branch before creating the PR.
- [ ] Commits have been [squashed][squash].
- If code communicates with devices:
- [ ] 3rd party library/libraries for communication is/are added as dependencies via the `REQUIREMENTS` variable ([example][ex-requir]).
- [ ] 3rd party dependencies are imported inside functions that use them ([example][ex-import]).
- [ ] `requirements_all.txt` is up-to-date, `script/gen_requirements_all.py` ran and the updated file is included in the PR.
- [ ] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]).
- [ ] New dependencies are only imported inside functions that use them ([example][ex-import]).
- [ ] New dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.
- [ ] New files were added to `.coveragerc`.
- If the code does not depend on external Python module:
- [ ] Tests to verify that the code works are included.
- [ ] [Commits will be squashed][squash] when the PR is ready to be merged.
- If the code does not interact with devices:
- [ ] Tests have been added to verify that the new code works.
[fork]: http://stackoverflow.com/a/7244456
[squash]: https://github.com/ginatrapani/todo.txt-android/wiki/Squash-All-Commits-Related-to-a-Single-Issue-into-a-Single-Commit

View File

@ -71,7 +71,7 @@ When you are done with development and ready to commit your changes, run `build_
To test your code before submission, used the `tox` tool.
```shell
```bash
> pip install -U tox
> tox
```

View File

@ -6,19 +6,17 @@ VOLUME /config
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN pip3 install --no-cache-dir colorlog
RUN pip3 install --no-cache-dir colorlog cython
# For the nmap tracker
RUN apt-get update && \
apt-get install -y --no-install-recommends nmap net-tools && \
apt-get install -y --no-install-recommends nmap net-tools cython3 libudev-dev sudo && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY script/build_python_openzwave script/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
RUN script/build_python_openzwave && \
mkdir -p /usr/local/share/python-openzwave && \
ln -sf /usr/src/app/build/python-openzwave/openzwave/config /usr/local/share/python-openzwave/config
COPY requirements_all.txt requirements_all.txt
RUN pip3 install --no-cache-dir -r requirements_all.txt

View File

@ -101,9 +101,10 @@ def track_devices(hass, entity_id, old_state, new_state):
@track_time_change(hour=7, minute=0, second=0)
def wake_up(hass, now):
"""
Turn it on in the morning (7 AM) if there are people home and
it is not already on.
"""Turn light on in the morning.
Turn the light on at 7 AM if there are people home and it is not already
on.
"""
if not TARGET_ID:
return
@ -126,8 +127,9 @@ def all_lights_off(hass, entity_id, old_state, new_state):
@service(DOMAIN, SERVICE_FLASH)
def flash_service(hass, call):
"""
Service that will turn the target off for 10 seconds if on and vice versa.
"""Service that will toggle the target.
Set the light to off for 10 seconds if on and vice versa.
"""
if not TARGET_ID:
return

View File

@ -20,7 +20,6 @@ DEPENDENCIES = []
def setup(hass, config):
"""Setup our skeleton component."""
# States are in the format DOMAIN.OBJECT_ID.
hass.states.set('hello_world.Hello_World', 'Works!')

View File

@ -0,0 +1 @@
"""Init file for Home Assistant."""

View File

@ -12,21 +12,26 @@ from multiprocessing import Process
import homeassistant.config as config_util
from homeassistant import bootstrap
from homeassistant.const import (
EVENT_HOMEASSISTANT_START, RESTART_EXIT_CODE, __version__)
__version__,
EVENT_HOMEASSISTANT_START,
REQUIRED_PYTHON_VER,
RESTART_EXIT_CODE,
)
def validate_python():
"""Validate we're running the right Python version."""
major, minor = sys.version_info[:2]
req_major, req_minor = REQUIRED_PYTHON_VER
if major < 3 or (major == 3 and minor < 4):
print("Home Assistant requires atleast Python 3.4")
if major < req_major or (major == req_major and minor < req_minor):
print("Home Assistant requires at least Python {}.{}".format(
req_major, req_minor))
sys.exit(1)
def ensure_config_path(config_dir):
""" Validates configuration directory. """
"""Validate the configuration directory."""
lib_dir = os.path.join(config_dir, 'lib')
# Test if configuration directory exists
@ -130,25 +135,25 @@ def get_arguments():
def daemonize():
""" Move current process to daemon process """
# create first fork
"""Move current process to daemon process."""
# Create first fork
pid = os.fork()
if pid > 0:
sys.exit(0)
# decouple fork
# Decouple fork
os.setsid()
os.umask(0)
# create second fork
# Create second fork
pid = os.fork()
if pid > 0:
sys.exit(0)
def check_pid(pid_file):
""" Check that HA is not already running """
# check pid file
"""Check that HA is not already running."""
# Check pid file
try:
pid = int(open(pid_file, 'r').readline())
except IOError:
@ -165,7 +170,7 @@ def check_pid(pid_file):
def write_pid(pid_file):
""" Create PID File """
"""Create a PID File."""
pid = os.getpid()
try:
open(pid_file, 'w').write(str(pid))
@ -175,7 +180,7 @@ def write_pid(pid_file):
def install_osx():
""" Setup to run via launchd on OS X """
"""Setup to run via launchd on OS X."""
with os.popen('which hass') as inp:
hass_path = inp.read().strip()
@ -207,7 +212,7 @@ def install_osx():
def uninstall_osx():
""" Unload from launchd on OS X """
"""Unload from launchd on OS X."""
path = os.path.expanduser("~/Library/LaunchAgents/org.homeassistant.plist")
os.popen('launchctl unload ' + path)
@ -215,9 +220,10 @@ def uninstall_osx():
def setup_and_run_hass(config_dir, args, top_process=False):
"""
Setup HASS and run. Block until stopped. Will assume it is running in a
subprocess unless top_process is set to true.
"""Setup HASS and run.
Block until stopped. Will assume it is running in a subprocess unless
top_process is set to true.
"""
if args.demo_mode:
config = {
@ -253,12 +259,12 @@ def setup_and_run_hass(config_dir, args, top_process=False):
def run_hass_process(hass_proc):
""" Runs a child hass process. Returns True if it should be restarted. """
"""Run a child hass process. Returns True if it should be restarted."""
requested_stop = threading.Event()
hass_proc.daemon = True
def request_stop(*args):
""" request hass stop, *args is for signal handler callback """
"""Request hass stop, *args is for signal handler callback."""
requested_stop.set()
hass_proc.terminate()
@ -283,7 +289,7 @@ def run_hass_process(hass_proc):
def main():
""" Starts Home Assistant. """
"""Start Home Assistant."""
validate_python()
args = get_arguments()
@ -291,7 +297,7 @@ def main():
config_dir = os.path.join(os.getcwd(), args.config)
ensure_config_path(config_dir)
# os x launchd functions
# OS X launchd functions
if args.install_osx:
install_osx()
return 0
@ -305,7 +311,7 @@ def main():
install_osx()
return 0
# daemon functions
# Daemon functions
if args.pid_file:
check_pid(args.pid_file)
if args.daemon:

View File

@ -35,7 +35,6 @@ ERROR_LOG_FILENAME = 'home-assistant.log'
def setup_component(hass, domain, config=None):
"""Setup a component and all its dependencies."""
if domain in hass.config.components:
return True
@ -58,7 +57,7 @@ def setup_component(hass, domain, config=None):
def _handle_requirements(hass, component, name):
""" Installs requirements for component. """
"""Install the requirements for a component."""
if hass.config.skip_pip or not hasattr(component, 'REQUIREMENTS'):
return True
@ -126,7 +125,7 @@ def _setup_component(hass, domain, config):
def prepare_setup_platform(hass, config, domain, platform_name):
""" Loads a platform and makes sure dependencies are setup. """
"""Load a platform and makes sure dependencies are setup."""
_ensure_loader_prepared(hass)
platform_path = PLATFORM_FORMAT.format(domain, platform_name)
@ -158,7 +157,7 @@ def prepare_setup_platform(hass, config, domain, platform_name):
def mount_local_lib_path(config_dir):
""" Add local library to Python Path """
"""Add local library to Python Path."""
sys.path.insert(0, os.path.join(config_dir, 'lib'))
@ -166,8 +165,7 @@ def mount_local_lib_path(config_dir):
def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
verbose=False, daemon=False, skip_pip=False,
log_rotate_days=None):
"""
Tries to configure Home Assistant from a config dict.
"""Try to configure Home Assistant from a config dict.
Dynamically loads required components and its dependencies.
"""
@ -209,7 +207,7 @@ def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
_LOGGER.info('Home Assistant core initialized')
# give event decorators access to HASS
# Give event decorators access to HASS
event_decorators.HASS = hass
service.HASS = hass
@ -222,9 +220,9 @@ def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
def from_config_file(config_path, hass=None, verbose=False, daemon=False,
skip_pip=True, log_rotate_days=None):
"""
Reads the configuration file and tries to start all the required
functionality. Will add functionality to 'hass' parameter if given,
"""Read the configuration file and try to start all the functionality.
Will add functionality to 'hass' parameter if given,
instantiates a new Home Assistant object if 'hass' is not given.
"""
if hass is None:
@ -244,7 +242,7 @@ def from_config_file(config_path, hass=None, verbose=False, daemon=False,
def enable_logging(hass, verbose=False, daemon=False, log_rotate_days=None):
""" Setup the logging for home assistant. """
"""Setup the logging."""
if not daemon:
logging.basicConfig(level=logging.INFO)
fmt = ("%(log_color)s%(asctime)s %(levelname)s (%(threadName)s) "
@ -322,11 +320,11 @@ def process_ha_config_upgrade(hass):
def process_ha_core_config(hass, config):
""" Processes the [homeassistant] section from the config. """
"""Process the [homeassistant] section from the config."""
hac = hass.config
def set_time_zone(time_zone_str):
""" Helper method to set time zone in HA. """
"""Helper method to set time zone."""
if time_zone_str is None:
return

View File

@ -1,16 +1,11 @@
"""
homeassistant.components
~~~~~~~~~~~~~~~~~~~~~~~~
This package contains components that can be plugged into Home Assistant.
Component design guidelines:
Each component defines a constant DOMAIN that is equal to its filename.
Each component that tracks states should create state entity names in the
- Each component defines a constant DOMAIN that is equal to its filename.
- Each component that tracks states should create state entity names in the
format "<DOMAIN>.<OBJECT_ID>".
Each component should publish services only under its own domain.
- Each component should publish services only under its own domain.
"""
import itertools as it
import logging
@ -26,8 +21,10 @@ _LOGGER = logging.getLogger(__name__)
def is_on(hass, entity_id=None):
""" Loads up the module to call the is_on method.
If there is no entity id given we will check all. """
"""Load up the module to call the is_on method.
If there is no entity id given we will check all.
"""
if entity_id:
group = get_component('group')
@ -53,7 +50,7 @@ def is_on(hass, entity_id=None):
def turn_on(hass, entity_id=None, **service_data):
""" Turns specified entity on if possible. """
"""Turn specified entity on if possible."""
if entity_id is not None:
service_data[ATTR_ENTITY_ID] = entity_id
@ -61,7 +58,7 @@ def turn_on(hass, entity_id=None, **service_data):
def turn_off(hass, entity_id=None, **service_data):
""" Turns specified entity off. """
"""Turn specified entity off."""
if entity_id is not None:
service_data[ATTR_ENTITY_ID] = entity_id
@ -69,7 +66,7 @@ def turn_off(hass, entity_id=None, **service_data):
def toggle(hass, entity_id=None, **service_data):
""" Toggles specified entity. """
"""Toggle specified entity."""
if entity_id is not None:
service_data[ATTR_ENTITY_ID] = entity_id
@ -77,8 +74,7 @@ def toggle(hass, entity_id=None, **service_data):
def setup(hass, config):
""" Setup general services related to homeassistant. """
"""Setup general services related to Home Assistant."""
def handle_turn_service(service):
"""Method to handle calls to homeassistant.turn_on/off."""
entity_ids = extract_entity_ids(hass, service)

View File

@ -1,14 +1,15 @@
"""
homeassistant.components.alarm_control_panel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with a alarm control panel.
Component to interface with an alarm control panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel/
"""
import logging
import os
from homeassistant.components import verisure
from homeassistant.const import (
ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
ATTR_CODE, ATTR_CODE_FORMAT, 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
@ -31,9 +32,6 @@ SERVICE_TO_METHOD = {
SERVICE_ALARM_TRIGGER: 'alarm_trigger'
}
ATTR_CODE = 'code'
ATTR_CODE_FORMAT = 'code_format'
ATTR_TO_PROPERTY = [
ATTR_CODE,
ATTR_CODE_FORMAT
@ -49,7 +47,7 @@ def setup(hass, config):
component.setup(config)
def alarm_service_handler(service):
""" Maps services to methods on Alarm. """
"""Map services to methods on Alarm."""
target_alarms = component.extract_from_service(service)
if ATTR_CODE not in service.data:
@ -120,11 +118,11 @@ def alarm_trigger(hass, code=None, entity_id=None):
# pylint: disable=no-self-use
class AlarmControlPanel(Entity):
""" ABC for alarm control devices. """
"""An abstract class for alarm control devices."""
@property
def code_format(self):
""" regex for code format or None if no code is required. """
"""Regex for code format or None if no code is required."""
return None
def alarm_disarm(self, code=None):

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.alarm_control_panel.alarmdotcom
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Interfaces with Verisure alarm control panel.
Interfaces with Alarm.com alarm control panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.alarmdotcom/
@ -24,7 +22,6 @@ DEFAULT_NAME = 'Alarm.com'
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup an Alarm.com control panel."""
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
@ -42,9 +39,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-arguments, too-many-instance-attributes
# pylint: disable=abstract-method
class AlarmDotCom(alarm.AlarmControlPanel):
""" Represents a Alarm.com status. """
"""Represent an Alarm.com status."""
def __init__(self, hass, name, code, username, password):
"""Initialize the Alarm.com status."""
from pyalarmdotcom.pyalarmdotcom import Alarmdotcom
self._alarm = Alarmdotcom(username, password, timeout=10)
self._hass = hass
@ -60,7 +58,7 @@ class AlarmDotCom(alarm.AlarmControlPanel):
@property
def name(self):
""" Returns the name of the device. """
"""Return the name of the alarm."""
return self._name
@property
@ -70,7 +68,7 @@ class AlarmDotCom(alarm.AlarmControlPanel):
@property
def state(self):
""" Returns the state of the device. """
"""Return the state of the device."""
if self._alarm.state == 'Disarmed':
return STATE_ALARM_DISARMED
elif self._alarm.state == 'Armed Stay':

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.alarm_control_panel.manual
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for manual alarms.
For more details about this platform, please refer to the documentation at
@ -24,8 +22,7 @@ DEFAULT_TRIGGER_TIME = 120
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the manual alarm platform. """
"""Setup the manual alarm platform."""
add_devices([ManualAlarm(
hass,
config.get('name', DEFAULT_ALARM_NAME),
@ -47,6 +44,7 @@ class ManualAlarm(alarm.AlarmControlPanel):
"""
def __init__(self, hass, name, code, pending_time, trigger_time):
"""Initalize the manual alarm panel."""
self._state = STATE_ALARM_DISARMED
self._hass = hass
self._name = name
@ -62,12 +60,12 @@ class ManualAlarm(alarm.AlarmControlPanel):
@property
def name(self):
""" Returns the name of the device. """
"""Return the name of the device."""
return self._name
@property
def state(self):
""" Returns the state of the device. """
"""Return 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 > \

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.alarm_control_panel.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This platform enables the possibility to control a MQTT alarm.
For more details about this platform, please refer to the documentation at
@ -26,8 +24,7 @@ DEPENDENCIES = ['mqtt']
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the MQTT platform. """
"""Setup the MQTT platform."""
if config.get('state_topic') is None:
_LOGGER.error("Missing required variable: state_topic")
return False
@ -51,10 +48,11 @@ 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. """
"""Represent a MQTT alarm status."""
def __init__(self, hass, name, state_topic, command_topic, qos,
payload_disarm, payload_arm_home, payload_arm_away, code):
"""Initalize the MQTT alarm panel."""
self._state = STATE_UNKNOWN
self._hass = hass
self._name = name
@ -80,22 +78,22 @@ class MqttAlarm(alarm.AlarmControlPanel):
@property
def should_poll(self):
""" No polling needed """
"""No polling needed."""
return False
@property
def name(self):
""" Returns the name of the device. """
"""Return the name of the device."""
return self._name
@property
def state(self):
""" Returns the state of the device. """
"""Return the state of the device."""
return self._state
@property
def code_format(self):
""" One or more characters if code is defined """
"""One or more characters if code is defined."""
return None if self._code is None else '.+'
def alarm_disarm(self, code=None):

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.alarm_control_panel.nx584
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for NX584 alarm control panels.
For more details about this platform, please refer to the documentation at
@ -16,12 +14,11 @@ from homeassistant.const import (
STATE_UNKNOWN)
REQUIREMENTS = ['pynx584==0.2']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Setup nx584. """
"""Setup nx584 platform."""
host = config.get('host', 'localhost:5007')
try:
@ -32,8 +29,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class NX584Alarm(alarm.AlarmControlPanel):
""" NX584-based alarm panel. """
"""Represents the NX584-based alarm panel."""
def __init__(self, hass, host, name):
"""Initalize the nx584 alarm panel."""
from nx584 import client
self._hass = hass
self._host = host
@ -51,17 +50,17 @@ class NX584Alarm(alarm.AlarmControlPanel):
@property
def name(self):
""" Returns the name of the device. """
"""Return the name of the device."""
return self._name
@property
def code_format(self):
""" Characters if code is defined. """
"""The characters if code is defined."""
return '[0-9]{4}([0-9]{2})?'
@property
def state(self):
""" Returns the state of the device. """
"""Return the state of the device."""
try:
part = self._alarm.list_partitions()[0]
zones = self._alarm.list_zones()

View File

@ -1,10 +1,8 @@
"""
homeassistant.components.alarm_control_panel.verisure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Interfaces with Verisure alarm control panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/verisure/
https://home-assistant.io/components/alarm_control_panel.verisure/
"""
import logging
@ -19,8 +17,7 @@ _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Verisure platform. """
"""Setup the Verisure platform."""
alarms = []
if int(hub.config.get('alarm', '1')):
hub.update_alarms()
@ -33,30 +30,31 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=abstract-method
class VerisureAlarm(alarm.AlarmControlPanel):
""" Represents a Verisure alarm status. """
"""Represent a Verisure alarm status."""
def __init__(self, device_id):
"""Initalize the Verisure alarm panel."""
self._id = device_id
self._state = STATE_UNKNOWN
self._digits = int(hub.config.get('code_digits', '4'))
@property
def name(self):
""" Returns the name of the device. """
"""Return the name of the device."""
return 'Alarm {}'.format(self._id)
@property
def state(self):
""" Returns the state of the device. """
"""Return the state of the device."""
return self._state
@property
def code_format(self):
""" code format as regex """
"""The code format as regex."""
return '^\\d{%s}$' % self._digits
def update(self):
""" Update alarm status """
"""Update alarm status."""
hub.update_alarms()
if hub.alarm_status[self._id].status == 'unarmed':

View File

@ -97,21 +97,24 @@ def _handle_alexa(handler, path_match, data):
class SpeechType(enum.Enum):
"""Alexa speech types."""
"""The Alexa speech types."""
plaintext = "PlainText"
ssml = "SSML"
class CardType(enum.Enum):
"""Alexa card types."""
"""The Alexa card types."""
simple = "Simple"
link_account = "LinkAccount"
class AlexaResponse(object):
"""Helps generating the response for Alexa."""
"""Help generating the response for Alexa."""
def __init__(self, hass, intent=None):
"""Initialize the response."""
self.hass = hass
self.speech = None
self.card = None
@ -163,7 +166,7 @@ class AlexaResponse(object):
}
def as_dict(self):
"""Returns response in an Alexa valid dict."""
"""Return response in an Alexa valid dict."""
response = {
'shouldEndSession': self.should_end_session
}

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.apcupsd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets up and provides access to the status output of APCUPSd via its Network
Information Server (NIS).
Support for status output of APCUPSd via its Network Information Server (NIS).
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/apcupsd/
@ -54,11 +51,14 @@ def setup(hass, config):
class APCUPSdData(object):
"""Stores the data retrieved from APCUPSd.
For each entity to use, acts as the single point responsible for fetching
updates from the server.
"""
Stores the data retrieved from APCUPSd for each entity to use, acts as the
single point responsible for fetching updates from the server.
"""
def __init__(self, host, port):
"""Initialize the data oject."""
from apcaccess import status
self._host = host
self._port = port
@ -78,7 +78,5 @@ class APCUPSdData(object):
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self, **kwargs):
"""
Fetch the latest status from APCUPSd and store it in self._status.
"""
"""Fetch the latest status from APCUPSd."""
self._status = self._get_status()

View File

@ -34,7 +34,6 @@ _LOGGER = logging.getLogger(__name__)
def setup(hass, config):
"""Register the API with the HTTP interface."""
# /api - for validation purposes
hass.http.register_path('GET', URL_API, _handle_get_api)
@ -96,7 +95,7 @@ def setup(hass, config):
def _handle_get_api(handler, path_match, data):
"""Renders the debug interface."""
"""Render the debug interface."""
handler.write_json_message("API running.")
@ -114,7 +113,7 @@ def _handle_get_api_stream(handler, path_match, data):
restrict = restrict.split(',')
def write_message(payload):
"""Writes a message to the output."""
"""Write a message to the output."""
with write_lock:
msg = "data: {}\n\n".format(payload)
@ -127,7 +126,7 @@ def _handle_get_api_stream(handler, path_match, data):
block.set()
def forward_events(event):
"""Forwards events to the open request."""
"""Forward events to the open request."""
nonlocal gracefully_closed
if block.is_set() or event.event_type == EVENT_TIME_CHANGED:
@ -171,17 +170,17 @@ def _handle_get_api_stream(handler, path_match, data):
def _handle_get_api_config(handler, path_match, data):
"""Returns the Home Assistant configuration."""
"""Return the Home Assistant configuration."""
handler.write_json(handler.server.hass.config.as_dict())
def _handle_get_api_states(handler, path_match, data):
"""Returns a dict containing all entity ids and their state."""
"""Return a dict containing all entity ids and their state."""
handler.write_json(handler.server.hass.states.all())
def _handle_get_api_states_entity(handler, path_match, data):
"""Returns the state of a specific entity."""
"""Return the state of a specific entity."""
entity_id = path_match.group('entity_id')
state = handler.server.hass.states.get(entity_id)
@ -193,7 +192,7 @@ def _handle_get_api_states_entity(handler, path_match, data):
def _handle_post_state_entity(handler, path_match, data):
"""Handles updating the state of an entity.
"""Handle updating the state of an entity.
This handles the following paths:
/api/states/<entity_id>
@ -240,15 +239,14 @@ def _handle_delete_state_entity(handler, path_match, data):
def _handle_get_api_events(handler, path_match, data):
"""Handles getting overview of event listeners."""
"""Handle getting overview of event listeners."""
handler.write_json(events_json(handler.server.hass))
def _handle_api_post_events_event(handler, path_match, event_data):
"""Handles firing of an event.
"""Handle firing of an event.
This handles the following paths:
/api/events/<event_type>
This handles the following paths: /api/events/<event_type>
Events from /api are threated as remote events.
"""
@ -276,16 +274,15 @@ def _handle_api_post_events_event(handler, path_match, event_data):
def _handle_get_api_services(handler, path_match, data):
"""Handles getting overview of services."""
"""Handle getting overview of services."""
handler.write_json(services_json(handler.server.hass))
# pylint: disable=invalid-name
def _handle_post_api_services_domain_service(handler, path_match, data):
"""Handles calling a service.
"""Handle calling a service.
This handles the following paths:
/api/services/<domain>/<service>
This handles the following paths: /api/services/<domain>/<service>
"""
domain = path_match.group('domain')
service = path_match.group('service')
@ -298,7 +295,7 @@ def _handle_post_api_services_domain_service(handler, path_match, data):
# pylint: disable=invalid-name
def _handle_post_api_event_forward(handler, path_match, data):
"""Handles adding an event forwarding target."""
"""Handle adding an event forwarding target."""
try:
host = data['host']
api_password = data['api_password']
@ -331,7 +328,7 @@ def _handle_post_api_event_forward(handler, path_match, data):
def _handle_delete_api_event_forward(handler, path_match, data):
"""Handles deleting an event forwarding target."""
"""Handle deleting an event forwarding target."""
try:
host = data['host']
except KeyError:
@ -354,12 +351,12 @@ def _handle_delete_api_event_forward(handler, path_match, data):
def _handle_get_api_components(handler, path_match, data):
"""Returns all the loaded components."""
"""Return all the loaded components."""
handler.write_json(handler.server.hass.config.components)
def _handle_get_api_error_log(handler, path_match, data):
"""Returns the logged errors for this session."""
"""Return the logged errors for this session."""
handler.write_file(handler.server.hass.config.path(ERROR_LOG_FILENAME),
False)

View File

@ -1,8 +1,5 @@
"""
components.arduino
~~~~~~~~~~~~~~~~~~
Arduino component that connects to a directly attached Arduino board which
runs with the Firmata firmware.
Support for Arduino boards running with the Firmata firmware.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/arduino/
@ -21,7 +18,6 @@ _LOGGER = logging.getLogger(__name__)
def setup(hass, config):
"""Setup the Arduino component."""
if not validate_config(config,
{DOMAIN: ['port']},
_LOGGER):
@ -53,15 +49,16 @@ def setup(hass, config):
class ArduinoBoard(object):
""" Represents an Arduino board. """
"""Representation of an Arduino board."""
def __init__(self, port):
"""Initialize the board."""
from PyMata.pymata import PyMata
self._port = port
self._board = PyMata(self._port, verbose=False)
def set_mode(self, pin, direction, mode):
""" Sets the mode and the direction of a given pin. """
"""Set the mode and the direction of a given pin."""
if mode == 'analog' and direction == 'in':
self._board.set_pin_mode(pin,
self._board.INPUT,
@ -89,19 +86,19 @@ class ArduinoBoard(object):
return self._board.get_analog_response_table()
def set_digital_out_high(self, pin):
""" Sets a given digital pin to high. """
"""Set a given digital pin to high."""
self._board.digital_write(pin, 1)
def set_digital_out_low(self, pin):
""" Sets a given digital pin to low. """
"""Set a given digital pin to low."""
self._board.digital_write(pin, 0)
def get_digital_in(self, pin):
""" Gets the value from a given digital pin. """
"""Get the value from a given digital pin."""
self._board.digital_read(pin)
def get_analog_in(self, pin):
""" Gets the value from a given analog pin. """
"""Get the value from a given analog pin."""
self._board.analog_read(pin)
def get_firmata(self):
@ -109,6 +106,6 @@ class ArduinoBoard(object):
return self._board.get_firmata_version()
def disconnect(self):
""" Disconnects the board and closes the serial connection. """
"""Disconnect the board and close the serial connection."""
self._board.reset()
self._board.close()

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to setup simple automation rules via the config file.
Allow to setup simple automation rules via the config file.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/automation/
@ -12,13 +10,14 @@ from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.const import CONF_PLATFORM
from homeassistant.components import logbook
from homeassistant.helpers.service import call_from_config
from homeassistant.helpers.service import validate_service_call
DOMAIN = 'automation'
DEPENDENCIES = ['group']
CONF_ALIAS = 'alias'
CONF_SERVICE = 'service'
CONF_CONDITION = 'condition'
CONF_ACTION = 'action'
@ -35,25 +34,25 @@ _LOGGER = logging.getLogger(__name__)
def setup(hass, config):
""" Sets up automation. """
"""Setup the automation."""
config_key = DOMAIN
found = 1
while config_key in config:
# check for one block syntax
# Check for one block syntax
if isinstance(config[config_key], dict):
config_block = _migrate_old_config(config[config_key])
name = config_block.get(CONF_ALIAS, config_key)
_setup_automation(hass, config_block, name, config)
# check for multiple block syntax
# Check for multiple block syntax
elif isinstance(config[config_key], list):
for list_no, config_block in enumerate(config[config_key]):
name = config_block.get(CONF_ALIAS,
"{}, {}".format(config_key, list_no))
_setup_automation(hass, config_block, name, config)
# any scalar value is incorrect
# Any scalar value is incorrect
else:
_LOGGER.error('Error in config in section %s.', config_key)
@ -64,8 +63,7 @@ def setup(hass, config):
def _setup_automation(hass, config_block, name, config):
""" Setup one instance of automation """
"""Setup one instance of automation."""
action = _get_action(hass, config_block.get(CONF_ACTION, {}), name)
if action is None:
@ -83,10 +81,10 @@ def _setup_automation(hass, config_block, name, config):
def _get_action(hass, config, name):
""" Return an action based on a config. """
if CONF_SERVICE not in config:
_LOGGER.error('Error setting up %s, no action specified.', name)
"""Return an action based on a configuration."""
validation_error = validate_service_call(config)
if validation_error:
_LOGGER.error(validation_error)
return None
def action():
@ -100,7 +98,7 @@ def _get_action(hass, config, name):
def _migrate_old_config(config):
""" Migrate old config to new. """
"""Migrate old configuration to new."""
if CONF_PLATFORM not in config:
return config
@ -134,8 +132,7 @@ def _migrate_old_config(config):
def _process_if(hass, config, p_config, action):
""" Processes if checks. """
"""Process if checks."""
cond_type = p_config.get(CONF_CONDITION_TYPE,
DEFAULT_CONDITION_TYPE).lower()
@ -178,7 +175,7 @@ def _process_if(hass, config, p_config, action):
def _process_trigger(hass, config, trigger_configs, name, action):
""" Setup triggers. """
"""Setup the triggers."""
if isinstance(trigger_configs, dict):
trigger_configs = [trigger_configs]
@ -195,7 +192,7 @@ def _process_trigger(hass, config, trigger_configs, name, action):
def _resolve_platform(method, hass, config, platform):
""" Find automation platform. """
"""Find the automation platform."""
if platform is None:
return None
platform = prepare_setup_platform(hass, config, DOMAIN, platform)

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers event listening automation rules.
Offer event listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#event-trigger
@ -15,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
def trigger(hass, config, action):
""" Listen for events based on config. """
"""Listen for events based on configuration."""
event_type = config.get(CONF_EVENT_TYPE)
if event_type is None:
@ -25,7 +23,7 @@ def trigger(hass, config, action):
event_data = config.get(CONF_EVENT_DATA)
def handle_event(event):
""" Listens for events and calls the action when data matches. """
"""Listen for events and calls the action when data matches."""
if not event_data or all(val == event.data.get(key) for key, val
in event_data.items()):
action()

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers MQTT listening automation rules.
Offer MQTT listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#mqtt-trigger
@ -17,7 +15,7 @@ CONF_PAYLOAD = 'payload'
def trigger(hass, config, action):
""" Listen for state changes based on `config`. """
"""Listen for state changes based on configuration."""
topic = config.get(CONF_TOPIC)
payload = config.get(CONF_PAYLOAD)
@ -27,7 +25,7 @@ def trigger(hass, config, action):
return False
def mqtt_automation_listener(msg_topic, msg_payload, qos):
""" Listens for MQTT messages. """
"""Listen for MQTT messages."""
if payload is None or payload == msg_payload:
action()

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.numeric_state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers numeric state listening automation rules.
Offer numeric state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#numeric-state-trigger
@ -21,7 +19,7 @@ _LOGGER = logging.getLogger(__name__)
def _renderer(hass, value_template, state):
"""Render state value."""
"""Render the state value."""
if value_template is None:
return state.state
@ -29,7 +27,7 @@ def _renderer(hass, value_template, state):
def trigger(hass, config, action):
""" Listen for state changes based on `config`. """
"""Listen for state changes based on configuration."""
entity_id = config.get(CONF_ENTITY_ID)
if entity_id is None:
@ -50,8 +48,7 @@ def trigger(hass, config, action):
# pylint: disable=unused-argument
def state_automation_listener(entity, from_s, to_s):
""" Listens for state changes and calls action. """
"""Listen for state changes and calls action."""
# Fire action if we go from outside range into range
if _in_range(above, below, renderer(to_s)) and \
(from_s is None or not _in_range(above, below, renderer(from_s))):
@ -64,8 +61,7 @@ def trigger(hass, config, action):
def if_action(hass, config):
""" Wraps action method with state based condition. """
"""Wrap action method with state based condition."""
entity_id = config.get(CONF_ENTITY_ID)
if entity_id is None:
@ -93,7 +89,7 @@ def if_action(hass, config):
def _in_range(range_start, range_end, value):
""" Checks if value is inside the range """
"""Check if value is inside the range."""
try:
value = float(value)
except ValueError:

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers state listening automation rules.
Offer state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#state-trigger
@ -25,7 +23,7 @@ CONF_FOR = "for"
def get_time_config(config):
""" Helper function to extract the time specified in the config """
"""Helper function to extract the time specified in the configuration."""
if CONF_FOR not in config:
return None
@ -51,7 +49,7 @@ def get_time_config(config):
def trigger(hass, config, action):
""" Listen for state changes based on `config`. """
"""Listen for state changes based on configuration."""
entity_id = config.get(CONF_ENTITY_ID)
if entity_id is None:
@ -72,17 +70,15 @@ def trigger(hass, config, action):
return None
def state_automation_listener(entity, from_s, to_s):
""" Listens for state changes and calls action. """
"""Listen for state changes and calls action."""
def state_for_listener(now):
""" Fires on state changes after a delay and calls action. """
"""Fire on state changes after a delay and calls action."""
hass.bus.remove_listener(
EVENT_STATE_CHANGED, for_state_listener)
action()
def state_for_cancel_listener(entity, inner_from_s, inner_to_s):
""" Fires on state changes and cancels
for listener if state changed. """
"""Fire on changes and cancel for listener if changed."""
if inner_to_s == to_s:
return
hass.bus.remove_listener(EVENT_TIME_CHANGED, for_time_listener)
@ -106,7 +102,7 @@ def trigger(hass, config, action):
def if_action(hass, config):
""" Wraps action method with state based condition. """
"""Wrap action method with state based condition."""
entity_id = config.get(CONF_ENTITY_ID)
state = config.get(CONF_STATE)

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.sun
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers sun based automation rules.
Offer sun based automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#sun-trigger
@ -29,7 +27,7 @@ _LOGGER = logging.getLogger(__name__)
def trigger(hass, config, action):
""" Listen for events based on config. """
"""Listen for events based on configuration."""
event = config.get(CONF_EVENT)
if event is None:
@ -55,7 +53,7 @@ def trigger(hass, config, action):
def if_action(hass, config):
""" Wraps action method with sun based condition. """
"""Wrap action method with sun based condition."""
before = config.get(CONF_BEFORE)
after = config.get(CONF_AFTER)
@ -106,8 +104,7 @@ def if_action(hass, config):
return sun.next_setting(hass) + after_offset
def time_if():
""" Validate time based if-condition """
"""Validate time based if-condition."""
now = dt_util.now()
before = before_func()
after = after_func()
@ -126,6 +123,7 @@ def if_action(hass, config):
def _parse_offset(raw_offset):
"""Parse the offset."""
if raw_offset is None:
return timedelta(0)

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers template automation rules.
Offer template automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#template-trigger
@ -16,7 +14,7 @@ _LOGGER = logging.getLogger(__name__)
def trigger(hass, config, action):
""" Listen for state changes based on `config`. """
"""Listen for state changes based on configuration."""
value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is None:
@ -27,7 +25,7 @@ def trigger(hass, config, action):
already_triggered = False
def event_listener(event):
""" Listens for state changes and calls action. """
"""Listen for state changes and calls action."""
nonlocal already_triggered
template_result = _check_template(hass, value_template)
@ -43,8 +41,7 @@ def trigger(hass, config, action):
def if_action(hass, config):
""" Wraps action method with state based condition. """
"""Wrap action method with state based condition."""
value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is None:
@ -55,7 +52,7 @@ def if_action(hass, config):
def _check_template(hass, value_template):
""" Checks if result of template is true """
"""Check if result of template is true."""
try:
value = template.render(hass, value_template, {})
except TemplateError:

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.time
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers time listening automation rules.
Offer time listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#time-trigger
@ -24,7 +22,7 @@ _LOGGER = logging.getLogger(__name__)
def trigger(hass, config, action):
""" Listen for state changes based on `config`. """
"""Listen for state changes based on configuration."""
if CONF_AFTER in config:
after = dt_util.parse_time_str(config[CONF_AFTER])
if after is None:
@ -42,7 +40,7 @@ def trigger(hass, config, action):
return False
def time_automation_listener(now):
""" Listens for time changes and calls action. """
"""Listen for time changes and calls action."""
action()
track_time_change(hass, time_automation_listener,
@ -52,7 +50,7 @@ def trigger(hass, config, action):
def if_action(hass, config):
""" Wraps action method with time based condition. """
"""Wrap action method with time based condition."""
before = config.get(CONF_BEFORE)
after = config.get(CONF_AFTER)
weekday = config.get(CONF_WEEKDAY)
@ -76,7 +74,7 @@ def if_action(hass, config):
return None
def time_if():
""" Validate time based if-condition """
"""Validate time based if-condition."""
now = dt_util.now()
if before is not None and now > now.replace(hour=before.hour,
minute=before.minute):

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.automation.zone
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers zone automation rules.
Offer zone automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#zone-trigger
@ -22,7 +20,7 @@ DEFAULT_EVENT = EVENT_ENTER
def trigger(hass, config, action):
""" Listen for state changes based on `config`. """
"""Listen for state changes based on configuration."""
entity_id = config.get(CONF_ENTITY_ID)
zone_entity_id = config.get(CONF_ZONE)
@ -35,7 +33,7 @@ def trigger(hass, config, action):
event = config.get(CONF_EVENT, DEFAULT_EVENT)
def zone_automation_listener(entity, from_s, to_s):
""" Listens for state changes and calls action. """
"""Listen for state changes and calls action."""
if from_s and None in (from_s.attributes.get(ATTR_LATITUDE),
from_s.attributes.get(ATTR_LONGITUDE)) or \
None in (to_s.attributes.get(ATTR_LATITUDE),
@ -57,7 +55,7 @@ def trigger(hass, config, action):
def if_action(hass, config):
""" Wraps action method with zone based condition. """
"""Wrap action method with zone based condition."""
entity_id = config.get(CONF_ENTITY_ID)
zone_entity_id = config.get(CONF_ZONE)

View File

@ -1,6 +1,5 @@
"""
Component to interface with binary sensors (sensors which only know two states)
that can be monitored.
Component to interface with binary sensors.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/binary_sensor/
@ -10,7 +9,7 @@ import logging
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity import Entity
from homeassistant.const import (STATE_ON, STATE_OFF)
from homeassistant.components import (bloomsky, mysensors, zwave, wink)
from homeassistant.components import (bloomsky, mysensors, zwave, wemo, wink)
DOMAIN = 'binary_sensor'
SCAN_INTERVAL = 30
@ -38,6 +37,7 @@ DISCOVERY_PLATFORMS = {
bloomsky.DISCOVER_BINARY_SENSORS: 'bloomsky',
mysensors.DISCOVER_BINARY_SENSORS: 'mysensors',
zwave.DISCOVER_BINARY_SENSORS: 'zwave',
wemo.DISCOVER_BINARY_SENSORS: 'wemo',
wink.DISCOVER_BINARY_SENSORS: 'wink'
}

View File

@ -1,5 +1,5 @@
"""
Provides a binary sensor to track online status of a UPS.
Support for tracking the online status of a UPS.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.apcupsd/
@ -17,8 +17,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class OnlineStatus(BinarySensorDevice):
"""Binary sensor to represent UPS online status."""
"""Represent UPS online status."""
def __init__(self, config, data):
"""Initialize the APCUPSd device."""
self._config = config
self._data = data
self._state = None
@ -26,17 +28,14 @@ class OnlineStatus(BinarySensorDevice):
@property
def name(self):
""" The name of the UPS online status sensor. """
"""Return the name of the UPS online status sensor."""
return self._config.get("name", DEFAULT_NAME)
@property
def is_on(self):
"""True if the UPS is online, else False."""
"""Return true if the UPS is online, else false."""
return self._state == apcupsd.VALUE_ONLINE
def update(self):
"""
Get the status report from APCUPSd (or cache) and set this entity's
state.
"""
"""Get the status report from APCUPSd and set this entity's state."""
self._state = self._data.status[apcupsd.KEY_STATUS]

View File

@ -1,5 +1,5 @@
"""
The arest sensor will consume an exposed aREST API of a device.
Support for exposed aREST RESTful API of a device.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.arest/
@ -22,7 +22,7 @@ CONF_PIN = 'pin'
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Get the aREST binary sensor."""
"""Setup the aREST binary sensor."""
resource = config.get(CONF_RESOURCE)
pin = config.get(CONF_PIN)
@ -53,9 +53,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-instance-attributes, too-many-arguments
class ArestBinarySensor(BinarySensorDevice):
"""Implements an aREST binary sensor for a pin."""
"""Implement an aREST binary sensor for a pin."""
def __init__(self, arest, resource, name, pin):
"""Initialize the aREST device."""
self.arest = arest
self._resource = resource
self._name = name
@ -70,30 +71,32 @@ class ArestBinarySensor(BinarySensorDevice):
@property
def name(self):
"""The name of the binary sensor."""
"""Return the name of the binary sensor."""
return self._name
@property
def is_on(self):
"""True if the binary sensor is on."""
"""Return true if the binary sensor is on."""
return bool(self.arest.data.get('state'))
def update(self):
"""Gets the latest data from aREST API."""
"""Get the latest data from aREST API."""
self.arest.update()
# pylint: disable=too-few-public-methods
class ArestData(object):
"""Class for handling the data retrieval for pins."""
def __init__(self, resource, pin):
"""Initialize the aREST data object."""
self._resource = resource
self._pin = pin
self.data = {}
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Gets the latest data from aREST device."""
"""Get the latest data from aREST device."""
try:
response = requests.get('{}/digital/{}'.format(
self._resource, self._pin), timeout=10)

View File

@ -35,7 +35,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class BloomSkySensor(BinarySensorDevice):
""" Represents a single binary sensor in a BloomSky device. """
"""Represent a single binary sensor in a BloomSky device."""
def __init__(self, bs, device, sensor_name):
"""Initialize a BloomSky binary sensor."""
@ -53,7 +53,7 @@ class BloomSkySensor(BinarySensorDevice):
@property
def unique_id(self):
"""Unique ID for this sensor."""
"""Return the unique ID for this sensor."""
return self._unique_id
@property
@ -63,7 +63,7 @@ class BloomSkySensor(BinarySensorDevice):
@property
def is_on(self):
"""If binary sensor is on."""
"""Return true if binary sensor is on."""
return self._state
def update(self):

View File

@ -1,6 +1,5 @@
"""
Allows to configure custom shell commands to turn a value into a logical value
for a binary sensor.
Support for custom shell commands to to retrieve values.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.command/
@ -25,7 +24,7 @@ MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Add the Command Sensor."""
"""Setup the Command Sensor."""
if config.get('command') is None:
_LOGGER.error('Missing required variable: "command"')
return False
@ -44,11 +43,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-arguments
class CommandBinarySensor(BinarySensorDevice):
"""
Represents a binary sensor that is returning a value of a shell commands.
"""
"""Represent a command line binary sensor."""
def __init__(self, hass, data, name, payload_on,
payload_off, value_template):
"""Initialize the Command line binary sensor."""
self._hass = hass
self.data = data
self._name = name
@ -60,16 +59,16 @@ class CommandBinarySensor(BinarySensorDevice):
@property
def name(self):
"""The name of the sensor."""
"""Return the name of the sensor."""
return self._name
@property
def is_on(self):
"""True if the binary sensor is on."""
"""Return true if the binary sensor is on."""
return self._state
def update(self):
"""Gets the latest data and updates the state."""
"""Get the latest data and updates the state."""
self.data.update()
value = self.data.value

View File

@ -17,7 +17,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class DemoBinarySensor(BinarySensorDevice):
"""A Demo binary sensor."""
def __init__(self, name, state, sensor_class):
"""Initialize the demo sensor."""
self._name = name
self._state = state
self._sensor_type = sensor_class

View File

@ -1,5 +1,5 @@
"""
Allows to configure a MQTT binary sensor.
Support for MQTT binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.mqtt/
@ -7,7 +7,8 @@ https://home-assistant.io/components/binary_sensor.mqtt/
import logging
import homeassistant.components.mqtt as mqtt
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.binary_sensor import (BinarySensorDevice,
SENSOR_CLASSES)
from homeassistant.const import CONF_VALUE_TEMPLATE
from homeassistant.helpers import template
@ -24,15 +25,20 @@ DEPENDENCIES = ['mqtt']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Add MQTT binary sensor."""
if config.get('state_topic') is None:
_LOGGER.error('Missing required variable: state_topic')
return False
sensor_class = config.get('sensor_class')
if sensor_class not in SENSOR_CLASSES:
_LOGGER.warning('Unknown sensor class: %s', sensor_class)
sensor_class = None
add_devices([MqttBinarySensor(
hass,
config.get('name', DEFAULT_NAME),
config.get('state_topic', None),
sensor_class,
config.get('qos', DEFAULT_QOS),
config.get('payload_on', DEFAULT_PAYLOAD_ON),
config.get('payload_off', DEFAULT_PAYLOAD_OFF),
@ -41,13 +47,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-arguments, too-many-instance-attributes
class MqttBinarySensor(BinarySensorDevice):
"""Represents a binary sensor that is updated by MQTT."""
def __init__(self, hass, name, state_topic, qos, payload_on, payload_off,
value_template):
"""Representation a binary sensor that is updated by MQTT."""
def __init__(self, hass, name, state_topic, sensor_class, qos, payload_on,
payload_off, value_template):
"""Initialize the MQTT binary sensor."""
self._hass = hass
self._name = name
self._state = False
self._state_topic = state_topic
self._sensor_class = sensor_class
self._payload_on = payload_on
self._payload_off = payload_off
self._qos = qos
@ -73,10 +82,15 @@ class MqttBinarySensor(BinarySensorDevice):
@property
def name(self):
"""The name of the binary sensor."""
"""Return the name of the binary sensor."""
return self._name
@property
def is_on(self):
"""True if the binary sensor is on."""
"""Return true if the binary sensor is on."""
return self._state
@property
def sensor_class(self):
"""Return the class of this sensor."""
return self._sensor_class

View File

@ -90,7 +90,7 @@ class MySensorsBinarySensor(BinarySensorDevice):
@property
def should_poll(self):
"""MySensor gateway pushes its state to HA."""
"""Mysensor gateway pushes its state to HA."""
return False
@property

View File

@ -26,7 +26,6 @@ BINARY_TYPES = ['fan',
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup Nest binary sensors."""
logger = logging.getLogger(__name__)
try:
for structure in nest.NEST.structures:

View File

@ -66,6 +66,7 @@ class NX584ZoneSensor(BinarySensorDevice):
"""Represents a NX584 zone as a sensor."""
def __init__(self, zone, zone_type):
"""Initialize the nx594 binary sensor."""
self._zone = zone
self._zone_type = zone_type
@ -81,7 +82,7 @@ class NX584ZoneSensor(BinarySensorDevice):
@property
def name(self):
"""Name of the binary sensor."""
"""Return the name of the binary sensor."""
return self._zone['name']
@property
@ -95,6 +96,7 @@ class NX584Watcher(threading.Thread):
"""Event listener thread to process NX584 events."""
def __init__(self, client, zone_sensors):
"""Initialize nx584 watcher thread."""
super(NX584Watcher, self).__init__()
self.daemon = True
self._client = client
@ -115,7 +117,7 @@ class NX584Watcher(threading.Thread):
self._process_zone_event(event)
def _run(self):
# Throw away any existing events so we don't replay history
"""Throw away any existing events so we don't replay history."""
self._client.get_events()
while True:
events = self._client.get_events()
@ -123,6 +125,7 @@ class NX584Watcher(threading.Thread):
self._process_events(events)
def run(self):
"""Run the watcher."""
while True:
try:
self._run()

View File

@ -1,5 +1,5 @@
"""
The rest binary sensor will consume responses sent by an exposed REST API.
Support for RESTful binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.rest/
@ -52,7 +52,7 @@ class RestBinarySensor(BinarySensorDevice):
@property
def name(self):
"""Name of the binary sensor."""
"""Return the name of the binary sensor."""
return self._name
@property

View File

@ -1,5 +1,5 @@
"""
Allows to configure a binary sensor using RPi GPIO.
Support for binary sensor using RPi GPIO.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.rpi_gpio/
@ -20,8 +20,7 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Sets up the Raspberry PI GPIO devices."""
"""Setup the Raspberry PI GPIO devices."""
pull_mode = config.get('pull_mode', DEFAULT_PULL_MODE)
bouncetime = config.get('bouncetime', DEFAULT_BOUNCETIME)
invert_logic = config.get('invert_logic', DEFAULT_INVERT_LOGIC)
@ -36,10 +35,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-arguments, too-many-instance-attributes
class RPiGPIOBinarySensor(BinarySensorDevice):
"""Represents a binary sensor that uses Raspberry Pi GPIO."""
def __init__(self, name, port, pull_mode, bouncetime, invert_logic):
# pylint: disable=no-member
"""Represent a binary sensor that uses Raspberry Pi GPIO."""
def __init__(self, name, port, pull_mode, bouncetime, invert_logic):
"""Initialize the RPi binary sensor."""
# pylint: disable=no-member
self._name = name or DEVICE_DEFAULT_NAME
self._port = port
self._pull_mode = pull_mode
@ -50,9 +50,10 @@ class RPiGPIOBinarySensor(BinarySensorDevice):
self._state = rpi_gpio.read_input(self._port)
def read_gpio(port):
"""Reads state from GPIO."""
"""Read state from GPIO."""
self._state = rpi_gpio.read_input(self._port)
self.update_ha_state()
rpi_gpio.edge_detect(self._port, read_gpio, self._bouncetime)
@property
@ -62,10 +63,10 @@ class RPiGPIOBinarySensor(BinarySensorDevice):
@property
def name(self):
"""The name of the sensor."""
"""Return the name of the sensor."""
return self._name
@property
def is_on(self):
"""Returns the state of the entity."""
"""Return the state of the entity."""
return self._state != self._invert_logic

View File

@ -23,6 +23,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class BinarySensor(BinarySensorDevice, Sensor):
"""A binary sensor which is on when its state == CONF_VALUE_ON."""
required = (CONF_VALUE_ON,)
@property

View File

@ -1,7 +1,8 @@
"""
homeassistant.components.binary_sensor.template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for exposing a templated binary_sensor
Support for exposing a templated binary sensor.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.template/
"""
import logging
@ -22,7 +23,6 @@ _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup template binary sensors."""
sensors = []
if config.get(CONF_SENSORS) is None:
_LOGGER.error('Missing configuration data for binary_sensor platform')
@ -70,11 +70,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class BinarySensorTemplate(BinarySensorDevice):
"""A virtual binary_sensor that triggers from another sensor."""
"""A virtual binary sensor that triggers from another sensor."""
# pylint: disable=too-many-arguments
def __init__(self, hass, device, friendly_name, sensor_class,
value_template):
"""Initialize the Template binary sensor."""
self._hass = hass
self._device = device
self._name = friendly_name
@ -90,25 +91,32 @@ class BinarySensorTemplate(BinarySensorDevice):
hass.bus.listen(EVENT_STATE_CHANGED, self._event_listener)
def _event_listener(self, event):
if not hasattr(self, 'hass'):
return
self.update_ha_state(True)
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def sensor_class(self):
"""Return the sensor class of the sensor."""
return self._sensor_class
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def is_on(self):
"""Return true if sensor is on."""
return self._state
def update(self):
"""Get the latest data and update the state."""
try:
value = template.render(self._hass, self._template)
except TemplateError as ex:

View File

@ -0,0 +1,75 @@
"""
Support for WeMo sensors.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.wemo/
"""
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.loader import get_component
DEPENDENCIES = ['wemo']
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument, too-many-function-args
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Register discovered WeMo binary sensors."""
import pywemo.discovery as discovery
if discovery_info is not None:
location = discovery_info[2]
mac = discovery_info[3]
device = discovery.device_from_description(location, mac)
if device:
add_devices_callback([WemoBinarySensor(device)])
class WemoBinarySensor(BinarySensorDevice):
"""Represents a WeMo binary sensor."""
def __init__(self, device):
"""Initialize the WeMo sensor."""
self.wemo = device
self._state = None
wemo = get_component('wemo')
wemo.SUBSCRIPTION_REGISTRY.register(self.wemo)
wemo.SUBSCRIPTION_REGISTRY.on(self.wemo, None, self._update_callback)
def _update_callback(self, _device, _params):
"""Called by the wemo device callback to update state."""
_LOGGER.info(
'Subscription update for %s',
_device)
self.update_ha_state(True)
@property
def should_poll(self):
"""No polling needed with subscriptions."""
return False
@property
def unique_id(self):
"""Return the id of this WeMo device."""
return "{}.{}".format(self.__class__, self.wemo.serialnumber)
@property
def name(self):
"""Return the name of the sevice if any."""
return self.wemo.name
@property
def is_on(self):
"""True if sensor is on."""
return self._state
def update(self):
"""Update WeMo state."""
try:
self._state = self.wemo.get_state(True)
except AttributeError:
_LOGGER.warning('Could not update status for %s', self.name)

View File

@ -22,7 +22,7 @@ SENSOR_TYPES = {
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Sets up the Wink platform."""
"""Setup the Wink platform."""
import pywink
if discovery_info is None:
@ -42,16 +42,17 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class WinkBinarySensorDevice(BinarySensorDevice, Entity):
"""Represents a Wink sensor."""
"""Representation of a Wink sensor."""
def __init__(self, wink):
"""Initialize the Wink binary sensor."""
self.wink = wink
self._unit_of_measurement = self.wink.UNIT
self.capability = self.wink.capability()
@property
def is_on(self):
"""Return True if the binary sensor is on."""
"""Return true if the binary sensor is on."""
if self.capability == "loudness":
return self.wink.loudness_boolean()
elif self.capability == "vibration":
@ -68,12 +69,12 @@ class WinkBinarySensorDevice(BinarySensorDevice, Entity):
@property
def unique_id(self):
""" Returns the id of this wink sensor """
"""Return the ID of this wink sensor."""
return "{}.{}".format(self.__class__, self.wink.device_id())
@property
def name(self):
""" Returns the name of the sensor if any. """
"""Return the name of the sensor if any."""
return self.wink.name()
def update(self):

View File

@ -19,8 +19,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class ZigBeeBinarySensor(ZigBeeDigitalIn, BinarySensorDevice):
"""
Use multiple inheritance to turn a ZigBeeDigitalIn into a
BinarySensorDevice.
"""
"""Use ZigBeeDigitalIn as binary sensor."""
pass

View File

@ -23,17 +23,19 @@ DEPENDENCIES = []
PHILIO = 0x013c
PHILIO_SLIM_SENSOR = 0x0002
PHILIO_SLIM_SENSOR_MOTION = (PHILIO, PHILIO_SLIM_SENSOR, 0)
WENZHOU = 0x0118
WENZHOU_SLIM_SENSOR_MOTION = (WENZHOU, PHILIO_SLIM_SENSOR, 0)
WORKAROUND_NO_OFF_EVENT = 'trigger_no_off_event'
DEVICE_MAPPINGS = {
PHILIO_SLIM_SENSOR_MOTION: WORKAROUND_NO_OFF_EVENT,
WENZHOU_SLIM_SENSOR_MOTION: WORKAROUND_NO_OFF_EVENT,
}
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the Z-Wave platform for sensors."""
if discovery_info is None or NETWORK is None:
return
@ -63,9 +65,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class ZWaveBinarySensor(BinarySensorDevice, ZWaveDeviceEntity):
"""Represents a binary sensor within Z-Wave."""
"""Representation of a binary sensor within Z-Wave."""
def __init__(self, value, sensor_class):
"""Initialize the sensor."""
self._sensor_type = sensor_class
# pylint: disable=import-error
from openzwave.network import ZWaveNetwork
@ -98,12 +101,10 @@ class ZWaveBinarySensor(BinarySensorDevice, ZWaveDeviceEntity):
class ZWaveTriggerSensor(ZWaveBinarySensor):
"""
Represents a stateless sensor which triggers events just 'On'
within Z-Wave.
"""
"""Representation of a stateless sensor within Z-Wave."""
def __init__(self, sensor_value, sensor_class, hass, re_arm_sec=60):
"""Initialize the sensor."""
super(ZWaveTriggerSensor, self).__init__(sensor_value, sensor_class)
self._hass = hass
self.re_arm_sec = re_arm_sec

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.bloomsky
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for BloomSky weather station.
For more details about this component, please refer to the documentation at
@ -60,10 +58,10 @@ class BloomSky(object):
"""Handle all communication with the BloomSky API."""
# API documentation at http://weatherlution.com/bloomsky-api/
API_URL = "https://api.bloomsky.com/api/skydata"
def __init__(self, api_key):
"""Initialize the BookSky."""
self._api_key = api_key
self.devices = {}
_LOGGER.debug("Initial bloomsky device load...")
@ -71,10 +69,7 @@ class BloomSky(object):
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def refresh_devices(self):
"""
Uses the API to retreive a list of devices associated with an
account along with all the sensors on the device.
"""
"""Use the API to retreive a list of devices."""
_LOGGER.debug("Fetching bloomsky update")
response = requests.get(self.API_URL,
headers={"Authorization": self._api_key},
@ -84,7 +79,7 @@ class BloomSky(object):
elif response.status_code != 200:
_LOGGER.error("Invalid HTTP response: %s", response.status_code)
return
# create dictionary keyed off of the device unique id
# Create dictionary keyed off of the device unique id
self.devices.update({
device["DeviceID"]: device for device in response.json()
})

View File

@ -10,9 +10,7 @@ SERVICE_BROWSE_URL = "browse_url"
def setup(hass, config):
"""
Listen for browse_url events and open the url in the default web browser.
"""
"""Listen for browse_url events."""
import webbrowser
hass.services.register(DOMAIN, SERVICE_BROWSE_URL,

View File

@ -42,7 +42,7 @@ MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n'
# pylint: disable=too-many-branches
def setup(hass, config):
"""Initialize camera component."""
"""Setup the camera component."""
component = EntityComponent(
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
DISCOVERY_PLATFORMS)

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.camera.bloomsky
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for a camera of a BloomSky weather station.
For more details about this component, please refer to the documentation at
@ -18,17 +16,17 @@ DEPENDENCIES = ["bloomsky"]
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" set up access to BloomSky cameras """
"""Setup access to BloomSky cameras."""
bloomsky = get_component('bloomsky')
for device in bloomsky.BLOOMSKY.devices.values():
add_devices_callback([BloomSkyCamera(bloomsky.BLOOMSKY, device)])
class BloomSkyCamera(Camera):
""" Represents the images published from the BloomSky's camera. """
"""Representation of the images published from the BloomSky's camera."""
def __init__(self, bs, device):
""" set up for access to the BloomSky camera images """
"""Setup for access to the BloomSky camera images."""
super(BloomSkyCamera, self).__init__()
self._name = device["DeviceName"]
self._id = device["DeviceID"]
@ -37,7 +35,7 @@ class BloomSkyCamera(Camera):
self._last_url = ""
# _last_image will store images as they are downloaded so that the
# frequent updates in home-assistant don't keep poking the server
# to download the same image over and over
# to download the same image over and over.
self._last_image = ""
self._logger = logging.getLogger(__name__)
@ -46,7 +44,7 @@ class BloomSkyCamera(Camera):
try:
self._url = self._bloomsky.devices[self._id]["Data"]["ImageURL"]
self._bloomsky.refresh_devices()
# if the url hasn't changed then the image hasn't changed
# If the URL hasn't changed then the image hasn't changed.
if self._url != self._last_url:
response = requests.get(self._url, timeout=10)
self._last_url = self._url
@ -59,5 +57,5 @@ class BloomSkyCamera(Camera):
@property
def name(self):
""" The name of this BloomSky device. """
"""Return the name of this BloomSky device."""
return self._name

View File

@ -21,6 +21,7 @@ class DemoCamera(Camera):
"""A Demo camera."""
def __init__(self, name):
"""Initialize demo camera component."""
super().__init__()
self._name = name

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.camera.foscam
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This component provides basic support for Foscam IP cameras.
For more details about this platform, please refer to the documentation at
@ -18,7 +16,7 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Adds a Foscam IP Camera. """
"""Setup a Foscam IP Camera."""
if not validate_config({DOMAIN: config},
{DOMAIN: ['username', 'password', 'ip']}, _LOGGER):
return None
@ -31,6 +29,7 @@ class FoscamCamera(Camera):
"""An implementation of a Foscam IP camera."""
def __init__(self, device_info):
"""Initialize a Foscam camera."""
super(FoscamCamera, self).__init__()
ip_address = device_info.get('ip')
@ -49,7 +48,6 @@ class FoscamCamera(Camera):
def camera_image(self):
"""Return a still image reponse from the camera."""
# Send the request to snap a picture and return raw jpg data
response = requests.get(self._snap_picture_url)
@ -57,5 +55,5 @@ class FoscamCamera(Camera):
@property
def name(self):
""" Return the name of this device. """
"""Return the name of this camera."""
return self._name

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.camera.generic
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for IP Cameras.
For more details about this platform, please refer to the documentation at
@ -19,7 +17,7 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Adds a generic IP Camera. """
"""Setup a generic IP Camera."""
if not validate_config({DOMAIN: config}, {DOMAIN: ['still_image_url']},
_LOGGER):
return None
@ -29,11 +27,10 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
# pylint: disable=too-many-instance-attributes
class GenericCamera(Camera):
"""
A generic implementation of an IP camera that is reachable over a URL.
"""
"""A generic implementation of an IP camera."""
def __init__(self, device_info):
"""Initialize a generic camera."""
super().__init__()
self._name = device_info.get('name', 'Generic Camera')
self._username = device_info.get('username')

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.camera.mjpeg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for IP Cameras.
For more details about this platform, please refer to the documentation at
@ -23,7 +21,7 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Adds a mjpeg IP Camera. """
"""Setup a MJPEG IP Camera."""
if not validate_config({DOMAIN: config}, {DOMAIN: ['mjpeg_url']},
_LOGGER):
return None
@ -33,11 +31,10 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
# pylint: disable=too-many-instance-attributes
class MjpegCamera(Camera):
"""
A generic implementation of an IP camera that is reachable over a URL.
"""
"""An implementation of an IP camera that is reachable over a URL."""
def __init__(self, device_info):
"""Initialize a MJPEG camera."""
super().__init__()
self._name = device_info.get('name', 'Mjpeg Camera')
self._username = device_info.get('username')
@ -45,7 +42,7 @@ class MjpegCamera(Camera):
self._mjpeg_url = device_info['mjpeg_url']
def camera_stream(self):
""" Return a mjpeg stream image response directly from the camera. """
"""Return a MJPEG stream image response directly from the camera."""
if self._username and self._password:
return requests.get(self._mjpeg_url,
auth=HTTPBasicAuth(self._username,
@ -57,7 +54,6 @@ class MjpegCamera(Camera):
def camera_image(self):
"""Return a still image response from the camera."""
def process_response(response):
"""Take in a response object, return the jpg from it."""
data = b''
@ -88,5 +84,5 @@ class MjpegCamera(Camera):
@property
def name(self):
""" Return the name of this device. """
"""Return the name of this camera."""
return self._name

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.camera.uvc
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Ubiquiti's UVC cameras.
For more details about this platform, please refer to the documentation at
@ -63,6 +61,7 @@ class UnifiVideoCamera(Camera):
"""A Ubiquiti Unifi Video Camera."""
def __init__(self, nvr, uuid, name):
"""Initialize an Unifi camera."""
super(UnifiVideoCamera, self).__init__()
self._nvr = nvr
self._uuid = uuid
@ -73,23 +72,28 @@ class UnifiVideoCamera(Camera):
@property
def name(self):
"""Return the name of this camera."""
return self._name
@property
def is_recording(self):
"""Return true if the camera is recording."""
caminfo = self._nvr.get_camera(self._uuid)
return caminfo['recordingSettings']['fullTimeRecordEnabled']
@property
def brand(self):
"""Return the brand of this camera."""
return 'Ubiquiti'
@property
def model(self):
"""Return the model of this camera."""
caminfo = self._nvr.get_camera(self._uuid)
return caminfo['model']
def _login(self):
"""Login to the camera."""
from uvcclient import camera as uvc_camera
from uvcclient import store as uvc_store
@ -131,6 +135,7 @@ class UnifiVideoCamera(Camera):
return True
def camera_image(self):
"""Return the image of this camera."""
from uvcclient import camera as uvc_camera
if not self._camera:
if not self._login():

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.configurator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A component to allow pieces of code to request configuration from the user.
Support to allow pieces of code to request configuration from the user.
Initiate a request by calling the `request_config` method with a callback.
This will return a request id that has to be used for future calls.
@ -38,9 +35,10 @@ _LOGGER = logging.getLogger(__name__)
def request_config(
hass, name, callback, description=None, description_image=None,
submit_caption=None, fields=None):
""" Create a new request for config.
Will return an ID to be used for sequent calls. """
"""Create a new request for configuration.
Will return an ID to be used for sequent calls.
"""
instance = _get_instance(hass)
request_id = instance.request_config(
@ -62,7 +60,7 @@ def notify_errors(request_id, error):
def request_done(request_id):
""" Mark a config request as done. """
"""Mark a configuration request as done."""
try:
_REQUESTS.pop(request_id).request_done(request_id)
except KeyError:
@ -71,7 +69,7 @@ def request_done(request_id):
def setup(hass, config):
""" Set up Configurator. """
"""Setup the configurator component."""
return True
@ -89,11 +87,10 @@ def _get_instance(hass):
class Configurator(object):
"""
Class to keep track of current configuration requests.
"""
"""The class to keep track of current configuration requests."""
def __init__(self, hass):
"""Initialize the configurator."""
self.hass = hass
self._cur_id = 0
self._requests = {}
@ -105,7 +102,6 @@ class Configurator(object):
self, name, callback,
description, description_image, submit_caption, fields):
"""Setup a request for configuration."""
entity_id = generate_entity_id(ENTITY_ID_FORMAT, name, hass=self.hass)
if fields is None:
@ -147,7 +143,7 @@ class Configurator(object):
self.hass.states.set(entity_id, STATE_CONFIGURE, new_data)
def request_done(self, request_id):
""" Remove the config request. """
"""Remove the configuration request."""
if not self._validate_request_id(request_id):
return
@ -180,7 +176,7 @@ class Configurator(object):
callback(call.data.get(ATTR_FIELDS, {}))
def _generate_unique_id(self):
""" Generates a unique configurator id. """
"""Generate a unique configurator ID."""
self._cur_id += 1
return "{}-{}".format(id(self), self._cur_id)

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.conversation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to have conversations with Home Assistant.
Support for functionality to have conversations with Home Assistant.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/conversation/
@ -25,19 +23,18 @@ REQUIREMENTS = ['fuzzywuzzy==0.8.0']
def setup(hass, config):
""" Registers the process service. """
"""Register the process service."""
from fuzzywuzzy import process as fuzzyExtract
logger = logging.getLogger(__name__)
def process(service):
""" Parses text into commands for Home Assistant. """
"""Parse text into commands."""
if ATTR_TEXT not in service.data:
logger.error("Received process service call without a text")
return
text = service.data[ATTR_TEXT].lower()
match = REGEX_TURN_COMMAND.match(text)
if not match:
@ -45,11 +42,8 @@ def setup(hass, config):
return
name, command = match.groups()
entities = {state.entity_id: state.name for state in hass.states.all()}
entity_ids = fuzzyExtract.extractOne(name,
entities,
entity_ids = fuzzyExtract.extractOne(name, entities,
score_cutoff=65)[2]
if not entity_ids:

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_sun_light_trigger
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to turn on lights based on the state of the sun and
devices.
Provides functionality to turn on lights based on the states.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/device_sun_light_trigger/
@ -12,9 +9,9 @@ from datetime import timedelta
import homeassistant.util.dt as dt_util
from homeassistant.const import STATE_HOME, STATE_NOT_HOME
from homeassistant.helpers.event import track_point_in_time, track_state_change
from . import device_tracker, group, light, sun
from homeassistant.helpers.event import track_point_in_time
from homeassistant.helpers.event_decorators import track_state_change
from homeassistant.loader import get_component
DOMAIN = "device_sun_light_trigger"
DEPENDENCIES = ['light', 'device_tracker', 'group', 'sun']
@ -29,28 +26,26 @@ CONF_LIGHT_GROUP = 'light_group'
CONF_DEVICE_GROUP = 'device_group'
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
def setup(hass, config):
""" Triggers to turn lights on or off based on device precense. """
"""The triggers to turn lights on or off based on device presence."""
logger = logging.getLogger(__name__)
device_tracker = get_component('device_tracker')
group = get_component('group')
light = get_component('light')
sun = get_component('sun')
disable_turn_off = 'disable_turn_off' in config[DOMAIN]
light_group = config[DOMAIN].get(CONF_LIGHT_GROUP,
light.ENTITY_ID_ALL_LIGHTS)
light_profile = config[DOMAIN].get(CONF_LIGHT_PROFILE, LIGHT_PROFILE)
device_group = config[DOMAIN].get(CONF_DEVICE_GROUP,
device_tracker.ENTITY_ID_ALL_DEVICES)
logger = logging.getLogger(__name__)
device_entity_ids = group.get_entity_ids(hass, device_group,
device_tracker.DOMAIN)
if not device_entity_ids:
logger.error("No devices found to track")
return False
# Get the light IDs from the specified group
@ -58,77 +53,75 @@ def setup(hass, config):
if not light_ids:
logger.error("No lights found to turn on ")
return False
def calc_time_for_light_when_sunset():
""" Calculates the time when to start fading lights in when sun sets.
Returns None if no next_setting data available. """
"""Calculate the time when to start fading lights in when sun sets.
Returns None if no next_setting data available.
"""
next_setting = sun.next_setting(hass)
if next_setting:
return next_setting - LIGHT_TRANSITION_TIME * len(light_ids)
else:
if not next_setting:
return None
def schedule_light_on_sun_rise(entity, old_state, new_state):
"""The moment sun sets we want to have all the lights on.
We will schedule to have each light start after one another
and slowly transition in."""
return next_setting - LIGHT_TRANSITION_TIME * len(light_ids)
def turn_light_on_before_sunset(light_id):
""" Helper function to turn on lights slowly if there
are devices home and the light is not on yet. """
if device_tracker.is_on(hass) and not light.is_on(hass, light_id):
"""Helper function to turn on lights.
Speed is slow if there are devices home and the light is not on yet.
"""
if not device_tracker.is_on(hass) or light.is_on(hass, light_id):
return
light.turn_on(hass, light_id,
transition=LIGHT_TRANSITION_TIME.seconds,
profile=light_profile)
def turn_on(light_id):
""" Lambda can keep track of function parameters but not local
parameters. If we put the lambda directly in the below statement
only the last light will be turned on.. """
return lambda now: turn_light_on_before_sunset(light_id)
start_point = calc_time_for_light_when_sunset()
if start_point:
for index, light_id in enumerate(light_ids):
track_point_in_time(
hass, turn_on(light_id),
(start_point + index * LIGHT_TRANSITION_TIME))
# Track every time sun rises so we can schedule a time-based
# pre-sun set event
track_state_change(hass, sun.ENTITY_ID, schedule_light_on_sun_rise,
sun.STATE_BELOW_HORIZON, sun.STATE_ABOVE_HORIZON)
@track_state_change(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON,
sun.STATE_ABOVE_HORIZON)
def schedule_lights_at_sun_set(hass, entity, old_state, new_state):
"""The moment sun sets we want to have all the lights on.
# If the sun is already above horizon
# schedule the time-based pre-sun set event
We will schedule to have each light start after one another
and slowly transition in.
"""
start_point = calc_time_for_light_when_sunset()
if not start_point:
return
def turn_on(light_id):
"""Lambda can keep track of function parameters.
No local parameters. If we put the lambda directly in the below
statement only the last light will be turned on.
"""
return lambda now: turn_light_on_before_sunset(light_id)
for index, light_id in enumerate(light_ids):
track_point_in_time(hass, turn_on(light_id),
start_point + index * LIGHT_TRANSITION_TIME)
# If the sun is already above horizon schedule the time-based pre-sun set
# event.
if sun.is_on(hass):
schedule_light_on_sun_rise(None, None, None)
schedule_lights_at_sun_set(hass, None, None, None)
def check_light_on_dev_state_change(entity, old_state, new_state):
""" Function to handle tracked device state changes. """
@track_state_change(device_entity_ids, STATE_NOT_HOME, STATE_HOME)
def check_light_on_dev_state_change(hass, entity, old_state, new_state):
"""Handle tracked device state changes."""
# pylint: disable=unused-variable
lights_are_on = group.is_on(hass, light_group)
light_needed = not (lights_are_on or sun.is_on(hass))
# Specific device came home ?
if entity != device_tracker.ENTITY_ID_ALL_DEVICES and \
new_state.state == STATE_HOME:
# These variables are needed for the elif check
now = dt_util.now()
start_point = calc_time_for_light_when_sunset()
# Do we need lights?
if light_needed:
logger.info(
"Home coming event for %s. Turning lights on", entity)
logger.info("Home coming event for %s. Turning lights on", entity)
light.turn_on(hass, light_ids, profile=light_profile)
# Are we in the time span were we would turn on the lights
@ -141,7 +134,6 @@ def setup(hass, config):
# Check for every light if it would be on if someone was home
# when the fading in started and turn it on if so
for index, light_id in enumerate(light_ids):
if now > start_point + index * LIGHT_TRANSITION_TIME:
light.turn_on(hass, light_id)
@ -150,24 +142,16 @@ def setup(hass, config):
# will all the following then, break.
break
# Did all devices leave the house?
elif (entity == device_group and
new_state.state == STATE_NOT_HOME and lights_are_on and
not disable_turn_off):
if not disable_turn_off:
@track_state_change(device_group, STATE_HOME, STATE_NOT_HOME)
def turn_off_lights_when_all_leave(hass, entity, old_state, new_state):
"""Handle device group state change."""
# pylint: disable=unused-variable
if not group.is_on(hass, light_group):
return
logger.info(
"Everyone has left but there are lights on. Turning them off")
light.turn_off(hass, light_ids)
# Track home coming of each device
track_state_change(
hass, device_entity_ids, check_light_on_dev_state_change,
STATE_NOT_HOME, STATE_HOME)
# Track when all devices are gone to shut down lights
track_state_change(
hass, device_group, check_light_on_dev_state_change,
STATE_HOME, STATE_NOT_HOME)
return True

View File

@ -1,14 +1,11 @@
"""
homeassistant.components.device_tracker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to keep track of devices.
Provide functionality to keep track of devices.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/device_tracker/
"""
# pylint: disable=too-many-instance-attributes, too-many-arguments
# pylint: disable=too-many-locals
import csv
from datetime import timedelta
import logging
import os
@ -36,7 +33,6 @@ ENTITY_ID_ALL_DEVICES = group.ENTITY_ID_FORMAT.format('all_devices')
ENTITY_ID_FORMAT = DOMAIN + '.{}'
CSV_DEVICES = "known_devices.csv"
YAML_DEVICES = 'known_devices.yaml'
CONF_TRACK_NEW = "track_new_devices"
@ -72,7 +68,7 @@ _LOGGER = logging.getLogger(__name__)
def is_on(hass, entity_id=None):
""" Returns if any or specified device is home. """
"""Return the state if any or a specified device is home."""
entity = entity_id or ENTITY_ID_ALL_DEVICES
return hass.states.is_state(entity, STATE_HOME)
@ -86,17 +82,15 @@ def see(hass, mac=None, dev_id=None, host_name=None, location_name=None,
(ATTR_DEV_ID, dev_id),
(ATTR_HOST_NAME, host_name),
(ATTR_LOCATION_NAME, location_name),
(ATTR_GPS, gps)) if value is not None}
(ATTR_GPS, gps),
(ATTR_GPS_ACCURACY, gps_accuracy),
(ATTR_BATTERY, battery)) if value is not None}
hass.services.call(DOMAIN, SERVICE_SEE, data)
def setup(hass, config):
""" Setup device tracker """
"""Setup device tracker."""
yaml_path = hass.config.path(YAML_DEVICES)
csv_path = hass.config.path(CSV_DEVICES)
if os.path.isfile(csv_path) and not os.path.isfile(yaml_path) and \
convert_csv_config(csv_path, yaml_path):
os.remove(csv_path)
conf = config.get(DOMAIN, {})
if isinstance(conf, list):
@ -169,8 +163,10 @@ def setup(hass, config):
class DeviceTracker(object):
""" Track devices """
"""Representation of a device tracker."""
def __init__(self, hass, consider_home, track_new, home_range, devices):
"""Initialize a device tracker."""
self.hass = hass
self.devices = {dev.dev_id: dev for dev in devices}
self.mac_to_dev = {dev.mac: dev for dev in devices if dev.mac}
@ -187,7 +183,7 @@ class DeviceTracker(object):
def see(self, mac=None, dev_id=None, host_name=None, location_name=None,
gps=None, gps_accuracy=None, battery=None):
""" Notify device tracker that you see a device. """
"""Notify the device tracker that you see a device."""
with self.lock:
if mac is None and dev_id is None:
raise HomeAssistantError('Neither mac or device id passed in')
@ -226,7 +222,7 @@ class DeviceTracker(object):
update_config(self.hass.config.path(YAML_DEVICES), dev_id, device)
def setup_group(self):
""" Initializes group for all tracked devices. """
"""Initialize group for all tracked devices."""
entity_ids = (dev.entity_id for dev in self.devices.values()
if dev.track)
self.group = group.Group(
@ -242,7 +238,7 @@ class DeviceTracker(object):
class Device(Entity):
""" Tracked device. """
"""Represent a tracked device."""
host_name = None
location_name = None
@ -251,12 +247,13 @@ class Device(Entity):
last_seen = None
battery = None
# Track if the last update of this device was HOME
# Track if the last update of this device was HOME.
last_update_home = False
_state = STATE_NOT_HOME
def __init__(self, hass, consider_home, home_range, track, dev_id, mac,
name=None, picture=None, away_hide=False):
"""Initialize a device."""
self.hass = hass
self.entity_id = ENTITY_ID_FORMAT.format(dev_id)
@ -289,22 +286,22 @@ class Device(Entity):
@property
def name(self):
""" Returns the name of the entity. """
"""Return the name of the entity."""
return self.config_name or self.host_name or DEVICE_DEFAULT_NAME
@property
def state(self):
""" State of the device. """
"""Return the state of the device."""
return self._state
@property
def entity_picture(self):
"""Picture of the device."""
"""Return the picture of the device."""
return self.config_picture
@property
def state_attributes(self):
""" Device state attributes. """
"""Return the device state attributes."""
attr = {}
if self.gps:
@ -370,23 +367,8 @@ class Device(Entity):
self.last_update_home = True
def convert_csv_config(csv_path, yaml_path):
""" Convert CSV config file format to YAML. """
used_ids = set()
with open(csv_path) as inp:
for row in csv.DictReader(inp):
dev_id = util.ensure_unique_string(
(util.slugify(row['name']) or DEVICE_DEFAULT_NAME).lower(),
used_ids)
used_ids.add(dev_id)
device = Device(None, None, None, row['track'] == '1', dev_id,
row['device'], row['name'], row['picture'])
update_config(yaml_path, dev_id, device)
return True
def load_config(path, hass, consider_home, home_range):
""" Load devices from YAML config file. """
"""Load devices from YAML configuration file."""
if not os.path.isfile(path):
return []
return [
@ -422,7 +404,7 @@ def setup_scanner_platform(hass, config, scanner, see_device):
def update_config(path, dev_id, device):
""" Add device to YAML config file. """
"""Add device to YAML configuration file."""
with open(path, 'a') as out:
out.write('\n')
out.write('{}:\n'.format(device.dev_id))

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.actiontec
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning an Actiontec MI424WR
(Verizon FIOS) router for device presence.
Support for Actiontec MI424WR (Verizon FIOS) routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.actiontec/
@ -20,7 +17,7 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)
@ -34,7 +31,7 @@ _LEASES_REGEX = re.compile(
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns an Actiontec scanner. """
"""Validate the configuration and return an Actiontec scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
@ -46,12 +43,10 @@ Device = namedtuple("Device", ["mac", "ip", "last_update"])
class ActiontecDeviceScanner(object):
"""
This class queries a an actiontec router for connected devices.
Adapted from DD-WRT scanner.
"""
"""This class queries a an actiontec router for connected devices."""
def __init__(self, config):
"""Initialize the scanner."""
self.host = config[CONF_HOST]
self.username = config[CONF_USERNAME]
self.password = config[CONF_PASSWORD]
@ -62,15 +57,12 @@ class ActiontecDeviceScanner(object):
_LOGGER.info("actiontec scanner initialized")
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [client.mac for client in self.last_results]
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
if not self.last_results:
return None
for client in self.last_results:
@ -80,9 +72,9 @@ class ActiontecDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the Actiontec MI424WR router is up
to date. Returns boolean if scanning successful.
"""Ensure the information from the router is up to date.
Return boolean if scanning successful.
"""
_LOGGER.info("Scanning")
if not self.success_init:

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.aruba
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a Aruba Access Point for device
presence.
Support for Aruba Access Points.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.aruba/
@ -31,7 +28,7 @@ _DEVICES_REGEX = re.compile(
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns a Aruba scanner. """
"""Validate the configuration and return a Aruba scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
@ -43,9 +40,10 @@ def get_scanner(hass, config):
class ArubaDeviceScanner(object):
""" This class queries a Aruba Acces Point for connected devices. """
"""This class queries a Aruba Access Point for connected devices."""
def __init__(self, config):
"""Initialize the scanner."""
self.host = config[CONF_HOST]
self.username = config[CONF_USERNAME]
self.password = config[CONF_PASSWORD]
@ -54,20 +52,17 @@ class ArubaDeviceScanner(object):
self.last_results = {}
# Test the router is accessible
# Test the router is accessible.
data = self.get_aruba_data()
self.success_init = data is not None
def scan_devices(self):
"""
Scans for new devices and return a list containing found device IDs.
"""
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [client['mac'] for client in self.last_results]
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
if not self.last_results:
return None
for client in self.last_results:
@ -77,9 +72,9 @@ class ArubaDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the Aruba Access Point is up to date.
Returns boolean if scanning successful.
"""Ensure the information from the Aruba Access Point is up to date.
Return boolean if scanning successful.
"""
if not self.success_init:
return False
@ -94,7 +89,6 @@ class ArubaDeviceScanner(object):
def get_aruba_data(self):
"""Retrieve data from Aruba Access Point and return parsed result."""
import pexpect
connect = "ssh {}@{}"
ssh = pexpect.spawn(connect.format(self.username, self.host))

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.asuswrt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a ASUSWRT router for device
presence.
Support for ASUSWRT routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.asuswrt/
@ -18,7 +15,7 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)
@ -39,7 +36,7 @@ _IP_NEIGH_REGEX = re.compile(
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns an ASUS-WRT scanner. """
"""Validate the configuration and return an ASUS-WRT scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
@ -51,12 +48,10 @@ def get_scanner(hass, config):
class AsusWrtDeviceScanner(object):
"""
This class queries a router running ASUSWRT firmware
for connected devices. Adapted from DD-WRT scanner.
"""
"""This class queries a router running ASUSWRT firmware."""
def __init__(self, config):
"""Initialize the scanner."""
self.host = config[CONF_HOST]
self.username = str(config[CONF_USERNAME])
self.password = str(config[CONF_PASSWORD])
@ -65,20 +60,17 @@ class AsusWrtDeviceScanner(object):
self.last_results = {}
# Test the router is accessible
# Test the router is accessible.
data = self.get_asuswrt_data()
self.success_init = data is not None
def scan_devices(self):
"""
Scans for new devices and return a list containing found device IDs.
"""
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [client['mac'] for client in self.last_results]
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
if not self.last_results:
return None
for client in self.last_results:
@ -88,9 +80,9 @@ class AsusWrtDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the ASUSWRT router is up to date.
Returns boolean if scanning successful.
"""Ensure the information from the ASUSWRT router is up to date.
Return boolean if scanning successful.
"""
if not self.success_init:
return False
@ -138,9 +130,8 @@ class AsusWrtDeviceScanner(object):
_LOGGER.warning("Could not parse lease row: %s", lease)
continue
# For leases where the client doesn't set a hostname, ensure
# it is blank and not '*', which breaks the entity_id down
# the line
# 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 = ''

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.ddwrt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a DD-WRT router for device
presence.
Support for DD-WRT routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ddwrt/
@ -19,7 +16,7 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)
@ -30,7 +27,7 @@ _MAC_REGEX = re.compile(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})')
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns a DD-WRT scanner. """
"""Validate the configuration and return a DD-WRT scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
@ -43,12 +40,10 @@ def get_scanner(hass, config):
# pylint: disable=too-many-instance-attributes
class DdWrtDeviceScanner(object):
"""
This class queries a wireless router running DD-WRT firmware
for connected devices. Adapted from Tomato scanner.
"""
"""This class queries a wireless router running DD-WRT firmware."""
def __init__(self, config):
"""Initialize the scanner."""
self.host = config[CONF_HOST]
self.username = config[CONF_USERNAME]
self.password = config[CONF_PASSWORD]
@ -65,19 +60,15 @@ class DdWrtDeviceScanner(object):
self.success_init = data is not None
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
"""Scan for new devices and return a list with 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. """
"""Return the name of the given device or None if we don't know."""
with self.lock:
# if not initialised and not already scanned and not found
# If not initialised and not already scanned and not found.
if device not in self.mac2name:
url = 'http://{}/Status_Lan.live.asp'.format(self.host)
data = self.get_ddwrt_data(url)
@ -90,15 +81,15 @@ class DdWrtDeviceScanner(object):
if not dhcp_leases:
return None
# remove leading and trailing single quotes
# Remove leading and trailing single quotes.
cleaned_str = dhcp_leases.strip().strip('"')
elements = cleaned_str.split('","')
num_clients = int(len(elements)/5)
self.mac2name = {}
for idx in range(0, num_clients):
# this is stupid but the data is a single array
# This is stupid but the data is a single array
# every 5 elements represents one hosts, the MAC
# is the third element and the name is the first
# is the third element and the name is the first.
mac_index = (idx * 5) + 2
if mac_index < len(elements):
mac = elements[mac_index]
@ -108,9 +99,9 @@ class DdWrtDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the DD-WRT router is up to date.
Returns boolean if scanning successful.
"""Ensure the information from the DD-WRT router is up to date.
Return boolean if scanning successful.
"""
if not self.success_init:
return False
@ -135,7 +126,7 @@ class DdWrtDeviceScanner(object):
# regex's out values so I guess I have to do the same,
# LAME!!!
# remove leading and trailing single quotes
# Remove leading and trailing single quotes.
clean_str = active_clients.strip().strip("'")
elements = clean_str.split("','")

View File

@ -1,19 +1,11 @@
"""
homeassistant.components.device_tracker.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform for the device tracker.
device_tracker:
platform: demo
"""
"""Demo platform for the device tracker."""
import random
from homeassistant.components.device_tracker import DOMAIN
def setup_scanner(hass, config, see):
""" Set up a demo tracker. """
"""Setup the demo tracker."""
def offset():
"""Return random offset."""
return (random.randrange(500, 2000)) / 2e5 * random.choice((-1, 1))

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.fritz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a FRITZ!Box router for device
presence.
Support for FRITZ!Box routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.fritz/
@ -17,15 +14,14 @@ from homeassistant.util import Throttle
REQUIREMENTS = ['fritzconnection==0.4.6']
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)
# noinspection PyUnusedLocal
def get_scanner(hass, config):
""" Validates config and returns FritzBoxScanner. """
"""Validate the configuration and return FritzBoxScanner."""
if not validate_config(config,
{DOMAIN: []},
_LOGGER):
@ -37,22 +33,12 @@ def get_scanner(hass, config):
# pylint: disable=too-many-instance-attributes
class FritzBoxScanner(object):
"""
This class queries a FRITZ!Box router. It is using the
fritzconnection library for communication with the router.
"""This class queries a FRITZ!Box router."""
The API description can be found under:
https://pypi.python.org/pypi/fritzconnection/0.4.6
This scanner retrieves the list of known hosts and checks their
corresponding states (on, or off).
Due to a bug of the fritzbox api (router side) it is not possible
to track more than 16 hosts.
"""
def __init__(self, config):
"""Initialize the scanner."""
self.last_results = []
self.host = '169.254.1.1' # This IP is valid for all fritzboxes
self.host = '169.254.1.1' # This IP is valid for all FRITZ!Box router.
self.username = 'admin'
self.password = ''
self.success_init = True
@ -68,7 +54,7 @@ class FritzBoxScanner(object):
if CONF_PASSWORD in config.keys():
self.password = config[CONF_PASSWORD]
# Establish a connection to the FRITZ!Box
# Establish a connection to the FRITZ!Box.
try:
self.fritz_box = fc.FritzHosts(address=self.host,
user=self.username,
@ -77,7 +63,7 @@ class FritzBoxScanner(object):
self.fritz_box = None
# At this point it is difficult to tell if a connection is established.
# So just check for null objects ...
# So just check for null objects.
if self.fritz_box is None or not self.fritz_box.modelname:
self.success_init = False
@ -99,7 +85,7 @@ class FritzBoxScanner(object):
return active_hosts
def get_device_name(self, mac):
""" Returns the name of the given device or None if is not known. """
"""Return the name of the given device or None if is not known."""
ret = self.fritz_box.get_specific_host_entry(mac)["NewHostName"]
if ret == {}:
return None
@ -107,7 +93,7 @@ class FritzBoxScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
""" Retrieves latest information from the FRITZ!Box. """
"""Retrieve latest information from the FRITZ!Box."""
if not self.success_init:
return False

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.device_tracker.icloud
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning iCloud devices.
Support for iCloud connected devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.icloud/
@ -26,7 +24,7 @@ def setup_scanner(hass, config, see):
from pyicloud.exceptions import PyiCloudFailedLoginException
from pyicloud.exceptions import PyiCloudNoDevicesException
# Get the username and password from the configuration
# Get the username and password from the configuration.
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
@ -45,7 +43,7 @@ def setup_scanner(hass, config, see):
return False
def keep_alive(now):
""" Keeps authenticating iCloud connection. """
"""Keep authenticating iCloud connection."""
api.authenticate()
_LOGGER.info("Authenticate against iCloud")

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.device_tracker.locative
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Locative platform for the device tracker.
Support for the Locative platform.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.locative/
@ -20,12 +18,10 @@ URL_API_LOCATIVE_ENDPOINT = "/api/locative"
def setup_scanner(hass, config, see):
""" Set up an endpoint for the Locative app. """
"""Setup an endpoint for the Locative application."""
# POST would be semantically better, but that currently does not work
# since Locative 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_LOCATIVE_ENDPOINT,
partial(_handle_get_api_locative, hass, see))
@ -35,7 +31,6 @@ def setup_scanner(hass, config, see):
def _handle_get_api_locative(hass, see, handler, path_match, data):
"""Locative message received."""
if not _check_data(handler, data):
return
@ -76,6 +71,7 @@ def _handle_get_api_locative(hass, see, handler, path_match, data):
def _check_data(handler, data):
"""Check the data."""
if 'latitude' not in data or 'longitude' not in data:
handler.write_text("Latitude and longitude not specified.",
HTTP_UNPROCESSABLE_ENTITY)

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.luci
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a OpenWRT router for device
presence.
Support for OpenWRT (luci) routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.luci/
@ -20,14 +17,14 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# 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. """
"""Validate the configuration and return a Luci scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
@ -40,20 +37,13 @@ def get_scanner(hass, config):
# pylint: disable=too-many-instance-attributes
class LuciDeviceScanner(object):
"""
This class queries a wireless router running OpenWrt firmware
for connected devices. Adapted from Tomato scanner.
"""This class queries a wireless router running OpenWrt firmware.
# opkg install luci-mod-rpc
for this to work on the router.
The API is described here:
http://luci.subsignal.org/trac/wiki/Documentation/JsonRpcHowTo
(Currently, we do only wifi iwscan, and no DHCP lease access.)
Adapted from Tomato scanner.
"""
def __init__(self, config):
"""Initialize the scanner."""
host = config[CONF_HOST]
username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
@ -70,17 +60,12 @@ class LuciDeviceScanner(object):
self.success_init = self.token is not None
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
"""Scan for new devices and return a list with 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. """
"""Return the name of the given device or None if we don't know."""
with self.lock:
if self.mac2name is None:
url = 'http://{}/cgi-bin/luci/rpc/uci'.format(self.host)
@ -100,8 +85,8 @@ class LuciDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the Luci router is up to date.
"""Ensure the information from the Luci router is up to date.
Returns boolean if scanning successful.
"""
if not self.success_init:

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.device_tracker.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MQTT platform for the device tracker.
Support for tracking MQTT enabled devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.mqtt/
@ -22,7 +20,7 @@ _LOGGER = logging.getLogger(__name__)
def setup_scanner(hass, config, see):
""" Set up a MQTT tracker. """
"""Setup the MQTT tracker."""
devices = config.get(CONF_DEVICES)
qos = util.convert(config.get(CONF_QOS), int, DEFAULT_QOS)

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.netgear
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a Netgear router for device
presence.
Support for Netgear routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.netgear/
@ -15,7 +12,7 @@ from homeassistant.components.device_tracker import DOMAIN
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)
@ -23,7 +20,7 @@ REQUIREMENTS = ['pynetgear==0.3.2']
def get_scanner(hass, config):
""" Validates config and returns a Netgear scanner. """
"""Validate the configuration and returns a Netgear scanner."""
info = config[DOMAIN]
host = info.get(CONF_HOST)
username = info.get(CONF_USERNAME)
@ -39,9 +36,10 @@ def get_scanner(hass, config):
class NetgearDeviceScanner(object):
""" This class queries a Netgear wireless router using the SOAP-API. """
"""Queries a Netgear wireless router using the SOAP-API."""
def __init__(self, host, username, password):
"""Initialize the scanner."""
import pynetgear
self.last_results = []
@ -66,15 +64,13 @@ class NetgearDeviceScanner(object):
_LOGGER.error("Failed to Login")
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return (device.mac for device in self.last_results)
def get_device_name(self, mac):
""" Returns the name of the given device or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
try:
return next(device.name for device in self.last_results
if device.mac == mac)
@ -83,8 +79,8 @@ class NetgearDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Retrieves latest information from the Netgear router.
"""Retrieve latest information from the Netgear router.
Returns boolean if scanning successful.
"""
if not self.success_init:

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.device_tracker.nmap
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a network with nmap.
Support for scanning a network with nmap.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.nmap_scanner/
@ -30,7 +28,7 @@ REQUIREMENTS = ['python-nmap==0.4.3']
def get_scanner(hass, config):
""" Validates config and returns a Nmap scanner. """
"""Validate the configuration and return a Nmap scanner."""
if not validate_config(config, {DOMAIN: [CONF_HOSTS]},
_LOGGER):
return None
@ -58,6 +56,7 @@ class NmapDeviceScanner(object):
"""This class scans for devices using nmap."""
def __init__(self, config):
"""Initialize the scanner."""
self.last_results = []
self.hosts = config[CONF_HOSTS]
@ -68,17 +67,13 @@ class NmapDeviceScanner(object):
_LOGGER.info("nmap scanner initialized")
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [device.mac for device in self.last_results]
def get_device_name(self, mac):
""" Returns the name of the given device or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
filter_named = [device.name for device in self.last_results
if device.mac == mac]
@ -89,8 +84,8 @@ class NmapDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Scans the network for devices.
"""Scan the network for devices.
Returns boolean if scanning successful.
"""
_LOGGER.info("Scanning")

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.device_tracker.owntracks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OwnTracks platform for the device tracker.
Support the OwnTracks platform.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.owntracks/
@ -28,13 +26,15 @@ _LOGGER = logging.getLogger(__name__)
LOCK = threading.Lock()
CONF_MAX_GPS_ACCURACY = 'max_gps_accuracy'
def setup_scanner(hass, config, see):
"""Setup an OwnTracks tracker."""
max_gps_accuracy = config.get(CONF_MAX_GPS_ACCURACY)
def owntracks_location_update(topic, payload, qos):
"""MQTT message received."""
# Docs on available data:
# http://owntracks.org/booklet/tech/json/#_typelocation
try:
@ -45,7 +45,9 @@ def setup_scanner(hass, config, see):
'Unable to parse payload as JSON: %s', payload)
return
if not isinstance(data, dict) or data.get('_type') != 'location':
if (not isinstance(data, dict) or data.get('_type') != 'location') or (
'acc' in data and max_gps_accuracy is not None and data[
'acc'] > max_gps_accuracy):
return
dev_id, kwargs = _parse_see_args(topic, data)
@ -64,7 +66,6 @@ def setup_scanner(hass, config, see):
def owntracks_event_update(topic, payload, qos):
# pylint: disable=too-many-branches, too-many-statements
"""MQTT event (geofences) received."""
# Docs on available data:
# http://owntracks.org/booklet/tech/json/#_typetransition
try:
@ -124,12 +125,20 @@ def setup_scanner(hass, config, see):
kwargs['location_name'] = new_region
_set_gps_from_zone(kwargs, zone)
_LOGGER.info("Exit to %s", new_region)
see(**kwargs)
see_beacons(dev_id, kwargs)
else:
_LOGGER.info("Exit to GPS")
# Check for GPS accuracy
if not ('acc' in data and
max_gps_accuracy is not None and
data['acc'] > max_gps_accuracy):
see(**kwargs)
see_beacons(dev_id, kwargs)
else:
_LOGGER.info("Inaccurate GPS reported")
beacons = MOBILE_BEACONS_ACTIVE[dev_id]
if location in beacons:
@ -143,8 +152,7 @@ def setup_scanner(hass, config, see):
return
def see_beacons(dev_id, kwargs_param):
""" Set active beacons to the current location """
"""Set active beacons to the current location."""
kwargs = kwargs_param.copy()
# the battery state applies to the tracking device, not the beacon
kwargs.pop('battery', None)
@ -154,16 +162,13 @@ def setup_scanner(hass, config, see):
see(**kwargs)
mqtt.subscribe(hass, LOCATION_TOPIC, owntracks_location_update, 1)
mqtt.subscribe(hass, EVENT_TOPIC, owntracks_event_update, 1)
return True
def _parse_see_args(topic, data):
""" Parse the OwnTracks location parameters,
into the format see expects. """
"""Parse the OwnTracks location parameters, into the format see expects."""
parts = topic.split('/')
dev_id = '{}_{}'.format(parts[1], parts[2])
host_name = parts[1]
@ -180,8 +185,7 @@ def _parse_see_args(topic, data):
def _set_gps_from_zone(kwargs, zone):
""" Set the see parameters from the zone parameters """
"""Set the see parameters from the zone parameters."""
if zone is not None:
kwargs['gps'] = (
zone.attributes['latitude'],

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.snmp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports fetching WiFi associations
through SNMP.
Support for fetching WiFi associations through SNMP.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.snmp/
@ -17,7 +14,7 @@ from homeassistant.const import CONF_HOST
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
_LOGGER = logging.getLogger(__name__)
@ -29,7 +26,7 @@ CONF_BASEOID = "baseoid"
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns an snmp scanner """
"""Validate the configuration and return an snmp scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_COMMUNITY, CONF_BASEOID]},
_LOGGER):
@ -41,10 +38,10 @@ def get_scanner(hass, config):
class SnmpScanner(object):
"""
This class queries any SNMP capable Acces Point for connected devices.
"""
"""Queries any SNMP capable Access Point for connected devices."""
def __init__(self, config):
"""Initialize the scanner."""
from pysnmp.entity.rfc3413.oneliner import cmdgen
self.snmp = cmdgen.CommandGenerator()
@ -61,25 +58,23 @@ class SnmpScanner(object):
self.success_init = data is not None
def scan_devices(self):
"""
Scans for new devices and return a list containing found device IDs.
"""
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [client['mac'] for client in self.last_results]
return [client['mac'] for client in self.last_results
if client.get('mac')]
# Supressing no-self-use warning
# pylint: disable=R0201
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
# We have no names
return None
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the WAP is up to date.
Returns boolean if scanning successful.
"""Ensure the information from the WAP is up to date.
Return boolean if scanning successful.
"""
if not self.success_init:
return False
@ -93,8 +88,7 @@ class SnmpScanner(object):
return True
def get_snmp_data(self):
""" Fetch mac addresses from WAP via SNMP. """
"""Fetch MAC addresses from WAP via SNMP."""
devices = []
errindication, errstatus, errindex, restable = self.snmp.nextCmd(
@ -111,6 +105,7 @@ class SnmpScanner(object):
for resrow in restable:
for _, val in resrow:
mac = binascii.hexlify(val.asOctets()).decode('utf-8')
_LOGGER.debug('Found mac %s', mac)
mac = ':'.join([mac[i:i+2] for i in range(0, len(mac), 2)])
devices.append({'mac': mac})
return devices

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.thomson
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a THOMSON router for device
presence.
Support for THOMSON routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.thomson/
@ -18,7 +15,7 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
_LOGGER = logging.getLogger(__name__)
@ -35,7 +32,7 @@ _DEVICES_REGEX = re.compile(
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns a THOMSON scanner. """
"""Validate the configuration and return a THOMSON scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
@ -47,12 +44,10 @@ def get_scanner(hass, config):
class ThomsonDeviceScanner(object):
"""
This class queries a router running THOMSON firmware
for connected devices. Adapted from ASUSWRT scanner.
"""
"""This class queries a router running THOMSON firmware."""
def __init__(self, config):
"""Initialize the scanner."""
self.host = config[CONF_HOST]
self.username = config[CONF_USERNAME]
self.password = config[CONF_PASSWORD]
@ -61,20 +56,17 @@ class ThomsonDeviceScanner(object):
self.last_results = {}
# Test the router is accessible
# Test the router is accessible.
data = self.get_thomson_data()
self.success_init = data is not None
def scan_devices(self):
""" Scans for new devices and return a
list containing found device ids. """
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [client['mac'] for client in self.last_results]
def get_device_name(self, device):
""" Returns the name of the given device
or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
if not self.last_results:
return None
for client in self.last_results:
@ -84,9 +76,9 @@ class ThomsonDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the THOMSON router is up to date.
Returns boolean if scanning successful.
"""Ensure the information from the THOMSON router is up to date.
Return boolean if scanning successful.
"""
if not self.success_init:
return False
@ -97,7 +89,7 @@ class ThomsonDeviceScanner(object):
if not data:
return False
# flag C stands for CONNECTED
# Flag C stands for CONNECTED
active_clients = [client for client in data.values() if
client['status'].find('C') != -1]
self.last_results = active_clients

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.tomato
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a Tomato router for device
presence.
Support for Tomato routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tomato/
@ -20,7 +17,7 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
CONF_HTTP_ID = "http_id"
@ -29,7 +26,7 @@ _LOGGER = logging.getLogger(__name__)
def get_scanner(hass, config):
""" Validates config and returns a Tomato scanner. """
"""Validate the configuration and returns a Tomato scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME,
CONF_PASSWORD, CONF_HTTP_ID]},
@ -40,14 +37,10 @@ def get_scanner(hass, config):
class TomatoDeviceScanner(object):
""" This class queries a wireless router running Tomato firmware
for connected devices.
A description of the Tomato API can be found on
http://paulusschoutsen.nl/blog/2013/10/tomato-api-documentation/
"""
"""This class queries a wireless router running Tomato firmware."""
def __init__(self, config):
"""Initialize the scanner."""
host, http_id = config[CONF_HOST], config[CONF_HTTP_ID]
username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
@ -68,16 +61,13 @@ class TomatoDeviceScanner(object):
self.success_init = self._update_tomato_info()
def scan_devices(self):
""" Scans for new devices and return a
list containing found device ids. """
"""Scan for new devices and return a list with found device IDs."""
self._update_tomato_info()
return [item[1] for item in self.last_results['wldev']]
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
"""Return the name of the given device or None if we don't know."""
filter_named = [item[0] for item in self.last_results['dhcpd_lease']
if item[2] == device]
@ -88,19 +78,17 @@ class TomatoDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_tomato_info(self):
""" Ensures the information from the Tomato router is up to date.
Returns boolean if scanning successful. """
"""Ensure the information from the Tomato router is up to date.
Return boolean if scanning successful.
"""
with self.lock:
self.logger.info("Scanning")
try:
response = requests.Session().send(self.req, timeout=3)
# Calling and parsing the Tomato api here. We only need the
# wldev and dhcpd_lease values. For API description see:
# http://paulusschoutsen.nl/
# blog/2013/10/tomato-api-documentation/
# wldev and dhcpd_lease values.
if response.status_code == 200:
for param, value in \
@ -109,7 +97,6 @@ class TomatoDeviceScanner(object):
if param == 'wldev' or param == 'dhcpd_lease':
self.last_results[param] = \
json.loads(value.replace("'", '"'))
return True
elif response.status_code == 401:
@ -117,29 +104,25 @@ class TomatoDeviceScanner(object):
self.logger.exception((
"Failed to authenticate, "
"please check your username and password"))
return False
except requests.exceptions.ConnectionError:
# We get this if we could not connect to the router or
# an invalid http_id was supplied
# an invalid http_id was supplied.
self.logger.exception((
"Failed to connect to the router"
" or invalid http_id supplied"))
return False
except requests.exceptions.Timeout:
# We get this if we could not connect to the router or
# an invalid http_id was supplied
# an invalid http_id was supplied.
self.logger.exception(
"Connection to the router timed out")
return False
except ValueError:
# If json decoder could not parse the response
# If JSON decoder could not parse the response.
self.logger.exception(
"Failed to parse response from router")
return False

View File

@ -1,13 +1,11 @@
"""
homeassistant.components.device_tracker.tplink
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a TP-Link router for device
presence.
Support for TP-Link routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tplink/
"""
import base64
import hashlib
import logging
import re
import threading
@ -27,12 +25,15 @@ _LOGGER = logging.getLogger(__name__)
def get_scanner(hass, config):
""" Validates config and returns a TP-Link scanner. """
"""Validate the configuration and return a TP-Link scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
return None
scanner = Tplink4DeviceScanner(config[DOMAIN])
if not scanner.success_init:
scanner = Tplink3DeviceScanner(config[DOMAIN])
if not scanner.success_init:
@ -45,12 +46,10 @@ def get_scanner(hass, config):
class TplinkDeviceScanner(object):
"""
This class queries a wireless router running TP-Link firmware
for connected devices.
"""
"""This class queries a wireless router running TP-Link firmware."""
def __init__(self, config):
"""Initialize the scanner."""
host = config[CONF_HOST]
username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
@ -66,29 +65,21 @@ class TplinkDeviceScanner(object):
self.success_init = self._update_info()
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return self.last_results
# pylint: disable=no-self-use
def get_device_name(self, device):
"""
The TP-Link firmware doesn't save the name of the wireless device.
"""
"""The firmware doesn't save the name of the wireless device."""
return None
@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.
"""
"""Ensure the information from the TP-Link router is up to date.
Return boolean if scanning successful.
"""
with self.lock:
_LOGGER.info("Loading wireless clients...")
@ -107,34 +98,24 @@ class TplinkDeviceScanner(object):
class Tplink2DeviceScanner(TplinkDeviceScanner):
"""
This class queries a wireless router running newer version of TP-Link
firmware for connected devices.
"""
"""This class queries a router with newer version of TP-Link firmware."""
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
"""Scan for new devices and return a list with 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.
"""
"""The firmware doesn't save the name of the wireless device."""
return self.last_results.get(device)
@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.
"""
"""Ensure the information from the TP-Link router is up to date.
Return boolean if scanning successful.
"""
with self.lock:
_LOGGER.info("Loading wireless clients...")
@ -172,46 +153,36 @@ class Tplink2DeviceScanner(TplinkDeviceScanner):
class Tplink3DeviceScanner(TplinkDeviceScanner):
"""
This class queries the Archer C9 router running version 150811 or higher
of TP-Link firmware for connected devices.
"""
"""This class queries the Archer C9 router with version 150811 or high."""
def __init__(self, config):
"""Initialize the scanner."""
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.
"""
"""Scan for new devices and return a list with 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.
"""The 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.
"""
"""Retrieve 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
# If possible implement rsa encryption of password here.
response = requests.post(url,
params={'operation': 'login',
'username': self.username,
@ -232,11 +203,10 @@ class Tplink3DeviceScanner(TplinkDeviceScanner):
@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.
"""
"""Ensure the information from the TP-Link router is up to date.
Return boolean if scanning successful.
"""
with self.lock:
if (self.stok == '') or (self.sysauth == ''):
self._get_auth_tokens()
@ -281,3 +251,81 @@ class Tplink3DeviceScanner(TplinkDeviceScanner):
return True
return False
class Tplink4DeviceScanner(TplinkDeviceScanner):
"""This class queries an Archer C7 router with TP-Link firmware 150427."""
def __init__(self, config):
"""Initialize the scanner."""
self.credentials = ''
self.token = ''
super(Tplink4DeviceScanner, self).__init__(config)
def scan_devices(self):
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return self.last_results
# pylint: disable=no-self-use
def get_device_name(self, device):
"""The firmware doesn't save the name of the wireless device."""
return None
def _get_auth_tokens(self):
"""Retrieve auth tokens from the router."""
_LOGGER.info("Retrieving auth tokens...")
url = 'http://{}/userRpm/LoginRpm.htm?Save=Save'.format(self.host)
# Generate md5 hash of password
password = hashlib.md5(self.password.encode('utf')).hexdigest()
credentials = '{}:{}'.format(self.username, password).encode('utf')
# Encode the credentials to be sent as a cookie.
self.credentials = base64.b64encode(credentials).decode('utf')
# Create the authorization cookie.
cookie = 'Authorization=Basic {}'.format(self.credentials)
response = requests.get(url, headers={'cookie': cookie})
try:
result = re.search(r'window.parent.location.href = '
r'"https?:\/\/.*\/(.*)\/userRpm\/Index.htm";',
response.text)
if not result:
return False
self.token = result.group(1)
return True
except ValueError:
_LOGGER.error("Couldn't fetch auth tokens!")
return False
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""Ensure the information from the TP-Link router is up to date.
Return boolean if scanning successful.
"""
with self.lock:
if (self.credentials == '') or (self.token == ''):
self._get_auth_tokens()
_LOGGER.info("Loading wireless clients...")
url = 'http://{}/{}/userRpm/WlanStationRpm.htm' \
.format(self.host, self.token)
referer = 'http://{}'.format(self.host)
cookie = 'Authorization=Basic {}'.format(self.credentials)
page = requests.get(url, headers={
'cookie': cookie,
'referer': referer
})
result = self.parse_macs.findall(page.text)
if not result:
return False
self.last_results = [mac.replace("-", ":") for mac in result]
return True

View File

@ -1,8 +1,5 @@
"""
homeassistant.components.device_tracker.ubus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a OpenWRT router for device
presence.
Support for OpenWRT (ubus) routers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ubus/
@ -20,14 +17,14 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
# Return cached results if last scan was less then this time ago
# 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. """
"""Validate the configuration and return an ubus scanner."""
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
@ -41,23 +38,13 @@ def get_scanner(hass, config):
# 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
This class queries a wireless router running OpenWrt firmware.
Adapted from Tomato scanner.
"""
def __init__(self, config):
"""Initialize the scanner."""
host = config[CONF_HOST]
username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
@ -73,17 +60,12 @@ class UbusDeviceScanner(object):
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.
"""
"""Scan for new devices and return a list with 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. """
"""Return 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,
@ -112,8 +94,8 @@ class UbusDeviceScanner(object):
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the Luci router is up to date.
"""Ensure the information from the Luci router is up to date.
Returns boolean if scanning successful.
"""
if not self.success_init:
@ -142,7 +124,6 @@ class UbusDeviceScanner(object):
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,
@ -167,7 +148,7 @@ def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params):
def _get_session_id(url, username, password):
""" Get authentication token for the given host+username+password. """
"""Get the authentication token for the given host+username+password."""
res = _req_json_rpc(url, "00000000000000000000000000000000", 'call',
'session', 'login', username=username,
password=password)

View File

@ -1,7 +1,8 @@
"""
homeassistant.components.device_tracker.unifi
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a Unifi WAP controller
Support for Unifi WAP controllers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.unifi/
"""
import logging
import urllib
@ -17,7 +18,7 @@ CONF_PORT = 'port'
def get_scanner(hass, config):
""" Sets up unifi device_tracker """
"""Setup Unifi device_tracker."""
from unifi.controller import Controller
if not validate_config(config, {DOMAIN: [CONF_USERNAME,
@ -50,10 +51,12 @@ class UnifiScanner(object):
"""Provide device_tracker support from Unifi WAP client data."""
def __init__(self, controller):
"""Initialize the scanner."""
self._controller = controller
self._update()
def _update(self):
"""Get the clients from the device."""
try:
clients = self._controller.get_clients()
except urllib.error.HTTPError as ex:
@ -63,12 +66,12 @@ class UnifiScanner(object):
self._clients = {client['mac']: client for client in clients}
def scan_devices(self):
""" Scans for devices. """
"""Scan for devices."""
self._update()
return self._clients.keys()
def get_device_name(self, mac):
""" Returns the name (if known) of the device.
"""Return the name (if known) of the device.
If a name has been set in Unifi, then return that, else
return the hostname if it has been detected.

View File

@ -15,7 +15,7 @@ from homeassistant.const import (
EVENT_PLATFORM_DISCOVERED)
DOMAIN = "discovery"
REQUIREMENTS = ['netdisco==0.5.2']
REQUIREMENTS = ['netdisco==0.5.4']
SCAN_INTERVAL = 300 # seconds
@ -55,10 +55,7 @@ def listen(hass, service, callback):
def discover(hass, service, discovered=None, component=None, hass_config=None):
"""Fire discovery event.
Can ensure a component is loaded.
"""
"""Fire discovery event. Can ensure a component is loaded."""
if component is not None:
bootstrap.setup_component(hass, component, hass_config)
@ -73,7 +70,7 @@ def discover(hass, service, discovered=None, component=None, hass_config=None):
def setup(hass, config):
""" Starts a discovery service. """
"""Start a discovery service."""
logger = logging.getLogger(__name__)
from netdisco.service import DiscoveryService
@ -90,7 +87,7 @@ def setup(hass, config):
component = SERVICE_HANDLERS.get(service)
# We do not know how to handle this service
# We do not know how to handle this service.
if not component:
return

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.downloader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to download files.
Support for functionality to download files.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/downloader/
@ -28,8 +26,7 @@ CONF_DOWNLOAD_DIR = 'download_dir'
# pylint: disable=too-many-branches
def setup(hass, config):
""" Listens for download events to download files. """
"""Listen for download events to download files."""
logger = logging.getLogger(__name__)
if not validate_config(config, {DOMAIN: [CONF_DOWNLOAD_DIR]}, logger):
@ -50,14 +47,13 @@ def setup(hass, config):
return False
def download_file(service):
""" Starts thread to download file specified in the url. """
"""Start thread to download file specified in the URL."""
if ATTR_URL not in service.data:
logger.error("Service called but 'url' parameter not specified.")
return
def do_download():
""" Downloads the file. """
"""Download the file."""
try:
url = service.data[ATTR_URL]

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.ecobee
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ecobee component
Support for Ecobee.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/ecobee/
@ -31,7 +29,7 @@ _LOGGER = logging.getLogger(__name__)
ECOBEE_CONFIG_FILE = 'ecobee.conf'
_CONFIGURING = {}
# Return cached results if last scan was less then this time ago
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180)
@ -46,7 +44,7 @@ def request_configuration(network, hass, config):
# pylint: disable=unused-argument
def ecobee_configuration_callback(callback_data):
""" Actions to do when our configuration callback is called. """
"""The actions to do when our configuration callback is called."""
network.request_tokens()
network.update()
setup_ecobee(hass, network, config)
@ -93,9 +91,10 @@ def setup_ecobee(hass, network, config):
# pylint: disable=too-few-public-methods
class EcobeeData(object):
""" Gets the latest data and update the states. """
"""Get the latest data and update the states."""
def __init__(self, config_file):
"""Initialize the Ecobee data object."""
from pyecobee import Ecobee
self.ecobee = Ecobee(config_file)
@ -107,8 +106,8 @@ class EcobeeData(object):
def setup(hass, config):
"""
Setup Ecobee.
"""Setup Ecobee.
Will automatically load thermostat and sensor components to support
devices discovered on the network.
"""

View File

@ -1,9 +1,4 @@
"""
homeassistant.components.frontend
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides a frontend for Home Assistant.
"""
"""Handle the frontend for Home Assistant."""
import re
import os
import logging
@ -58,7 +53,7 @@ def setup(hass, config):
def _handle_get_api_bootstrap(handler, path_match, data):
""" Returns all data needed to bootstrap Home Assistant. """
"""Return all data needed to bootstrap Home Assistant."""
hass = handler.server.hass
handler.write_json({
@ -70,7 +65,7 @@ def _handle_get_api_bootstrap(handler, path_match, data):
def _handle_get_root(handler, path_match, data):
""" Renders the frontend. """
"""Render the frontend."""
handler.send_response(HTTP_OK)
handler.send_header('Content-type', 'text/html; charset=utf-8')
handler.end_headers()
@ -95,7 +90,7 @@ def _handle_get_root(handler, path_match, data):
def _handle_get_service_worker(handler, path_match, data):
""" Returns service worker for the frontend. """
"""Return service worker for the frontend."""
if handler.server.development:
sw_path = "home-assistant-polymer/build/service_worker.js"
else:
@ -106,7 +101,7 @@ def _handle_get_service_worker(handler, path_match, data):
def _handle_get_static(handler, path_match, data):
""" Returns a static file for the frontend. """
"""Return a static file for the frontend."""
req_file = util.sanitize_path(path_match.group('file'))
# Strip md5 hash out
@ -120,9 +115,7 @@ def _handle_get_static(handler, path_match, data):
def _handle_get_local(handler, path_match, data):
"""
Returns a static file from the hass.config.path/www for the frontend.
"""
"""Return a static file from the hass.config.path/www for the frontend."""
req_file = util.sanitize_path(path_match.group('file'))
path = handler.server.hass.config.path('www', req_file)

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by update_mdi script """
VERSION = "2f4adc5d3ad6d2f73bf69ed29b7594fd"
"""DO NOT MODIFY. Auto-generated by update_mdi script."""
VERSION = "e85dc66e1a0730e44f79ed11501cd79a"

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "a4d021cb50ed079fcfda7369ed2f0d4a"
"""DO NOT MODIFY. Auto-generated by build_frontend script."""
VERSION = "30bcc0eacc13a2317000824741dc9ac0"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit 81ae753eb06a32bcac62cbee0981b1d24580e878
Subproject commit 0fed700045d6faba8eda8ec713ee9e6bc763507c

File diff suppressed because one or more lines are too long

View File

@ -33,13 +33,13 @@ _LOGGER = logging.getLogger(__name__)
def is_closed(hass, entity_id=None):
"""Returns if the garage door is closed based on the statemachine."""
"""Return if the garage door is closed based on the statemachine."""
entity_id = entity_id or ENTITY_ID_ALL_GARAGE_DOORS
return hass.states.is_state(entity_id, STATE_CLOSED)
def close_door(hass, entity_id=None):
"""Closes all or specified garage door."""
"""Close all or a specified garage door."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.services.call(DOMAIN, SERVICE_CLOSE, data)
@ -58,7 +58,7 @@ def setup(hass, config):
component.setup(config)
def handle_garage_door_service(service):
"""Handles calls to the garage door services."""
"""Handle calls to the garage door services."""
target_locks = component.extract_from_service(service)
for item in target_locks:
@ -81,7 +81,8 @@ def setup(hass, config):
class GarageDoorDevice(Entity):
"""Represents a garage door."""
"""Representation of a garage door."""
# pylint: disable=no-self-use
@property
def is_closed(self):
@ -98,7 +99,7 @@ class GarageDoorDevice(Entity):
@property
def state(self):
"""Returns the state of the garage door."""
"""Return the state of the garage door."""
closed = self.is_closed
if closed is None:
return STATE_UNKNOWN

View File

@ -19,7 +19,9 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
class DemoGarageDoor(GarageDoorDevice):
"""Provides a demo garage door."""
def __init__(self, name, state):
"""Initialize the garage door."""
self._name = name
self._state = state

View File

@ -13,7 +13,7 @@ REQUIREMENTS = ['python-wink==0.6.2']
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Sets up the Wink garage door platform."""
"""Setup the Wink garage door platform."""
import pywink
if discovery_info is None:
@ -32,19 +32,20 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class WinkGarageDoorDevice(GarageDoorDevice):
"""Represents a Wink garage door."""
"""Representation of a Wink garage door."""
def __init__(self, wink):
"""Initialize the garage door."""
self.wink = wink
@property
def unique_id(self):
"""Returns the id of this wink garage door."""
"""Return the ID of this wink garage door."""
return "{}.{}".format(self.__class__, self.wink.device_id())
@property
def name(self):
"""Returns the name of the garage door if any."""
"""Return the name of the garage door if any."""
return self.wink.name()
def update(self):
@ -53,11 +54,11 @@ class WinkGarageDoorDevice(GarageDoorDevice):
@property
def is_closed(self):
"""Returns true if door is closed."""
"""Return true if door is closed."""
return self.wink.state() == 0
def close_door(self):
"""Closes the door."""
"""Close the door."""
self.wink.set_state(0)
def open_door(self):

View File

@ -1,6 +1,5 @@
"""
Component that records all events and state changes and feeds the data to
a Graphite installation.
Component that sends data to aGraphite installation.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/graphite/
@ -35,8 +34,10 @@ def setup(hass, config):
class GraphiteFeeder(threading.Thread):
"""Feeds data to Graphite."""
"""Feed data to Graphite."""
def __init__(self, hass, host, port, prefix):
"""Initialize the feeder."""
super(GraphiteFeeder, self).__init__(daemon=True)
self._hass = hass
self._host = host

View File

@ -1,11 +1,11 @@
"""
homeassistant.components.group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to group devices that can be turned on or off.
Provides functionality to group entities.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/group/
"""
import threading
import homeassistant.core as ha
from homeassistant.const import (
ATTR_ENTITY_ID, CONF_ICON, CONF_NAME, STATE_CLOSED, STATE_HOME,
@ -41,7 +41,7 @@ def _get_group_on_off(state):
def is_on(hass, entity_id):
""" Returns if the group state is in its ON-state. """
"""Test if the group state is in its ON-state."""
state = hass.states.get(entity_id)
if state:
@ -54,8 +54,7 @@ def is_on(hass, entity_id):
def expand_entity_ids(hass, entity_ids):
""" Returns the given list of entity ids and expands group ids into
the entity ids it represents if found. """
"""Return entity_ids with group entity ids replaced by their members."""
found_ids = []
for entity_id in entity_ids:
@ -86,7 +85,7 @@ def expand_entity_ids(hass, entity_ids):
def get_entity_ids(hass, entity_id, domain_filter=None):
""" Get the entity ids that make up this group. """
"""Get members of this group."""
entity_id = entity_id.lower()
try:
@ -107,7 +106,7 @@ def get_entity_ids(hass, entity_id, domain_filter=None):
def setup(hass, config):
""" Sets up all groups found definded in the configuration. """
"""Setup all groups found definded in the configuration."""
for object_id, conf in config.get(DOMAIN, {}).items():
if not isinstance(conf, dict):
conf = {CONF_ENTITIES: conf}
@ -127,12 +126,12 @@ def setup(hass, config):
class Group(Entity):
""" Tracks a group of entity ids. """
"""Track a group of entity ids."""
# pylint: disable=too-many-instance-attributes, too-many-arguments
def __init__(self, hass, name, entity_ids=None, user_defined=True,
icon=None, view=False, object_id=None):
"""Initialize a group."""
self.hass = hass
self._name = name
self._state = STATE_UNKNOWN
@ -146,6 +145,7 @@ class Group(Entity):
self.group_on = None
self.group_off = None
self._assumed_state = False
self._lock = threading.Lock()
if entity_ids is not None:
self.update_tracked_entity_ids(entity_ids)
@ -154,26 +154,32 @@ class Group(Entity):
@property
def should_poll(self):
"""No need to poll because groups will update themselves."""
return False
@property
def name(self):
"""Return the name of the group."""
return self._name
@property
def state(self):
"""Return the state of the group."""
return self._state
@property
def icon(self):
"""Return the icon of the group."""
return self._icon
@property
def hidden(self):
"""If group should be hidden or not."""
return not self._user_defined or self._view
@property
def state_attributes(self):
"""Return the state attributes for the group."""
data = {
ATTR_ENTITY_ID: self.tracking,
ATTR_ORDER: self._order,
@ -186,11 +192,11 @@ class Group(Entity):
@property
def assumed_state(self):
"""Return True if unable to access real state of entity."""
"""Test if any member has an assumed state."""
return self._assumed_state
def update_tracked_entity_ids(self, entity_ids):
""" Update the tracked entity IDs. """
"""Update the member entity IDs."""
self.stop()
self.tracking = tuple(ent_id.lower() for ent_id in entity_ids)
self.group_on, self.group_off = None, None
@ -200,30 +206,30 @@ class Group(Entity):
self.start()
def start(self):
""" Starts the tracking. """
"""Start tracking members."""
track_state_change(
self.hass, self.tracking, self._state_changed_listener)
def stop(self):
""" Unregisters the group from Home Assistant. """
"""Unregister the group from Home Assistant."""
self.hass.states.remove(self.entity_id)
self.hass.bus.remove_listener(
ha.EVENT_STATE_CHANGED, self._state_changed_listener)
def update(self):
""" Query all the tracked states and determine current group state. """
"""Query all members and determine current group state."""
self._state = STATE_UNKNOWN
self._update_group_state()
def _state_changed_listener(self, entity_id, old_state, new_state):
""" Listener to receive state changes of tracked entities. """
"""Respond to a member state changing."""
self._update_group_state(new_state)
self.update_ha_state()
@property
def _tracking_states(self):
"""States that the group is tracking."""
"""The states that the group is tracking."""
states = []
for entity_id in self.tracking:
@ -242,8 +248,11 @@ class Group(Entity):
"""
# pylint: disable=too-many-branches
# To store current states of group entities. Might not be needed.
with self._lock:
states = None
gr_state, gr_on, gr_off = self._state, self.group_on, self.group_off
gr_state = self._state
gr_on = self.group_on
gr_off = self.group_off
# We have not determined type of group yet
if gr_on is None:
@ -283,8 +292,9 @@ class Group(Entity):
if states is None:
states = self._tracking_states
self._assumed_state = any(state.attributes.get(ATTR_ASSUMED_STATE)
for state in states)
self._assumed_state = any(
state.attributes.get(ATTR_ASSUMED_STATE) for state
in states)
elif tr_state.attributes.get(ATTR_ASSUMED_STATE):
self._assumed_state = True

View File

@ -1,6 +1,4 @@
"""
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
@ -11,7 +9,7 @@ from collections import defaultdict
from datetime import timedelta
from itertools import groupby
import homeassistant.components.recorder as recorder
from homeassistant.components import recorder, script
import homeassistant.util.dt as dt_util
from homeassistant.const import HTTP_BAD_REQUEST
@ -19,6 +17,7 @@ DOMAIN = 'history'
DEPENDENCIES = ['recorder', 'http']
SIGNIFICANT_DOMAINS = ('thermostat',)
IGNORE_DOMAINS = ('zone', 'scene',)
URL_HISTORY_PERIOD = re.compile(
r'/api/history/period(?:/(?P<date>\d{4}-\d{1,2}-\d{1,2})|)')
@ -38,17 +37,18 @@ def last_5_states(entity_id):
def get_significant_states(start_time, end_time=None, entity_id=None):
"""Return states changes during UTC period start_time - end_time.
"""
Return states changes during UTC period start_time - end_time.
Significant states are all states where there is a state change,
as well as all states from certain domains (for instance
thermostat so that we get current temperature in our graphs).
"""
where = """
(domain in ({}) or last_changed=last_updated)
AND last_updated > ?
""".format(",".join(["'%s'" % x for x in SIGNIFICANT_DOMAINS]))
(domain IN ({}) OR last_changed=last_updated)
AND domain NOT IN ({}) AND last_updated > ?
""".format(",".join("'%s'" % x for x in SIGNIFICANT_DOMAINS),
",".join("'%s'" % x for x in IGNORE_DOMAINS))
data = [start_time]
@ -63,15 +63,14 @@ def get_significant_states(start_time, end_time=None, entity_id=None):
query = ("SELECT * FROM states WHERE {} "
"ORDER BY entity_id, last_updated ASC").format(where)
states = recorder.query_states(query, data)
states = (state for state in recorder.query_states(query, data)
if _is_significant(state))
return states_to_json(states, start_time, entity_id)
def state_changes_during_period(start_time, end_time=None, entity_id=None):
"""
Return states changes during UTC period start_time - end_time.
"""
"""Return states changes during UTC period start_time - end_time."""
where = "last_changed=last_updated AND last_changed > ? "
data = [start_time]
@ -92,7 +91,7 @@ def state_changes_during_period(start_time, end_time=None, entity_id=None):
def get_states(utc_point_in_time, entity_ids=None, run=None):
""" Returns the states at a specific point in time. """
"""Return the states at a specific point in time."""
if run is None:
run = recorder.run_information(utc_point_in_time)
@ -121,7 +120,7 @@ def get_states(utc_point_in_time, entity_ids=None, run=None):
def states_to_json(states, start_time, entity_id):
"""Converts SQL results into JSON friendly data structure.
"""Convert SQL results into JSON friendly data structure.
This takes our state list and turns it into a JSON friendly data
structure {'entity_id': [list of states], 'entity_id2': [list of states]}
@ -130,7 +129,6 @@ def states_to_json(states, start_time, entity_id):
each list of states, otherwise our graphs won't start on the Y
axis correctly.
"""
result = defaultdict(list)
entity_ids = [entity_id] if entity_id is not None else None
@ -156,7 +154,7 @@ def get_state(utc_point_in_time, entity_id, run=None):
# pylint: disable=unused-argument
def setup(hass, config):
""" Setup history hooks. """
"""Setup the history hooks."""
hass.http.register_path(
'GET',
re.compile(
@ -200,3 +198,13 @@ def _api_history_period(handler, path_match, data):
handler.write_json(
get_significant_states(start_time, end_time, entity_id).values())
def _is_significant(state):
"""Test if state is significant for history charts.
Will only test for things that are not filtered out in SQL.
"""
# scripts that are not cancellable will never change state
return (state.domain != 'script' or
state.attributes.get(script.ATTR_CAN_CANCEL))

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.http
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module provides an API and a HTTP interface for debug purposes.
For more details about the RESTful API, please refer to the documentation at
@ -52,7 +50,7 @@ _LOGGER = logging.getLogger(__name__)
def setup(hass, config):
""" Sets up the HTTP API and debug interface. """
"""Set up the HTTP API and debug interface."""
conf = config.get(DOMAIN, {})
api_password = util.convert(conf.get(CONF_API_PASSWORD), str)
@ -88,14 +86,15 @@ def setup(hass, config):
# pylint: disable=too-many-instance-attributes
class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle HTTP requests in a threaded fashion."""
# pylint: disable=too-few-public-methods
# pylint: disable=too-few-public-methods
allow_reuse_address = True
daemon_threads = True
# pylint: disable=too-many-arguments
def __init__(self, server_address, request_handler_class,
hass, api_password, development, ssl_certificate, ssl_key):
"""Initialize the server."""
super().__init__(server_address, request_handler_class)
self.server_address = server_address
@ -119,9 +118,9 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
self.socket = context.wrap_socket(self.socket, server_side=True)
def start(self):
""" Starts the HTTP server. """
"""Start the HTTP server."""
def stop_http(event):
""" Stops the HTTP server. """
"""Stop the HTTP server."""
self.shutdown()
self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http)
@ -140,19 +139,18 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
self.serve_forever()
def register_path(self, method, url, callback, require_auth=True):
""" Registers a path with the server. """
"""Register a path with the server."""
self.paths.append((method, url, callback, require_auth))
def log_message(self, fmt, *args):
""" Redirect built-in log to HA logging """
"""Redirect built-in log to HA logging."""
# pylint: disable=no-self-use
_LOGGER.info(fmt, *args)
# pylint: disable=too-many-public-methods,too-many-locals
class RequestHandler(SimpleHTTPRequestHandler):
"""
Handles incoming HTTP requests
"""Handle incoming HTTP requests.
We extend from SimpleHTTPRequestHandler instead of Base so we
can use the guess content type methods.
@ -161,13 +159,13 @@ class RequestHandler(SimpleHTTPRequestHandler):
server_version = "HomeAssistant/1.0"
def __init__(self, req, client_addr, server):
""" Contructor, call the base constructor and set up session """
"""Constructor, call the base constructor and set up session."""
# Track if this was an authenticated request
self.authenticated = False
SimpleHTTPRequestHandler.__init__(self, req, client_addr, server)
def log_message(self, fmt, *arguments):
""" Redirect built-in log to HA logging """
"""Redirect built-in log to HA logging."""
if self.server.api_password is None:
_LOGGER.info(fmt, *arguments)
else:
@ -176,7 +174,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
if isinstance(arg, str) else arg for arg in arguments))
def _handle_request(self, method): # pylint: disable=too-many-branches
""" Does some common checks and calls appropriate method. """
"""Perform some common checks and call appropriate method."""
url = urlparse(self.path)
# Read query input. parse_qs gives a list for each value, we want last
@ -306,7 +304,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.wfile.write(message.encode("UTF-8"))
def write_file(self, path, cache_headers=True):
""" Returns a file to the user. """
"""Return a file to the user."""
try:
with open(path, 'rb') as inp:
self.write_file_pointer(self.guess_type(path), inp,
@ -318,10 +316,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
_LOGGER.exception("Unable to serve %s", path)
def write_file_pointer(self, content_type, inp, cache_headers=True):
"""
Helper function to write a file pointer to the user.
Does not do error handling.
"""
"""Helper function to write a file pointer to the user."""
do_gzip = 'gzip' in self.headers.get(HTTP_HEADER_ACCEPT_ENCODING, '')
self.send_response(HTTP_OK)
@ -354,7 +349,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.copyfile(inp, self.wfile)
def set_cache_header(self):
""" Add cache headers if not in development """
"""Add cache headers if not in development."""
if self.server.development:
return
@ -369,7 +364,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.date_time_string(time.time()+cache_time))
def set_session_cookie_header(self):
""" Add the header for the session cookie and return session id. """
"""Add the header for the session cookie and return session ID."""
if not self.authenticated:
return None
@ -391,9 +386,9 @@ class RequestHandler(SimpleHTTPRequestHandler):
return self.get_cookie_session_id() is not None
def get_cookie_session_id(self):
"""
Extracts the current session id from the
cookie or returns None if not set or invalid
"""Extract the current session ID from the cookie.
Return None if not set or invalid.
"""
if 'Cookie' not in self.headers:
return None
@ -417,7 +412,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
return None
def destroy_session(self):
""" Destroys session. """
"""Destroy the session."""
session_id = self.get_cookie_session_id()
if session_id is None:
@ -433,9 +428,10 @@ def session_valid_time():
class SessionStore(object):
""" Responsible for storing and retrieving http sessions """
"""Responsible for storing and retrieving HTTP sessions."""
def __init__(self):
""" Set up the session store """
"""Setup the session store."""
self._sessions = {}
self._lock = threading.RLock()
@ -468,7 +464,7 @@ class SessionStore(object):
self._sessions.pop(key, None)
def create(self):
""" Creates a new session. """
"""Create a new session."""
with self._lock:
session_id = util.get_random_string(20)

View File

@ -1,7 +1,5 @@
"""
homeassistant.components.ifttt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This component enable you to trigger Maker IFTTT recipes.
Support to trigger Maker IFTTT recipes.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/ifttt/
@ -38,15 +36,14 @@ def trigger(hass, event, value1=None, value2=None, value3=None):
def setup(hass, config):
""" Setup the ifttt service component. """
"""Setup the IFTTT service component."""
if not validate_config(config, {DOMAIN: ['key']}, _LOGGER):
return False
key = config[DOMAIN]['key']
def trigger_service(call):
""" Handle ifttt trigger service calls. """
"""Handle IFTTT trigger service calls."""
event = call.data.get(ATTR_EVENT)
value1 = call.data.get(ATTR_VALUE1)
value2 = call.data.get(ATTR_VALUE2)

View File

@ -31,8 +31,10 @@ CONF_USERNAME = 'username'
CONF_PASSWORD = 'password'
CONF_SSL = 'ssl'
CONF_VERIFY_SSL = 'verify_ssl'
CONF_BLACKLIST = 'blacklist'
# pylint: disable=too-many-locals
def setup(hass, config):
"""Setup the InfluxDB component."""
from influxdb import InfluxDBClient, exceptions
@ -52,6 +54,7 @@ def setup(hass, config):
ssl = util.convert(conf.get(CONF_SSL), bool, DEFAULT_SSL)
verify_ssl = util.convert(conf.get(CONF_VERIFY_SSL), bool,
DEFAULT_VERIFY_SSL)
blacklist = conf.get(CONF_BLACKLIST, [])
try:
influx = InfluxDBClient(host=host, port=port, username=username,
@ -67,7 +70,8 @@ def setup(hass, config):
def influx_event_listener(event):
"""Listen for new messages on the bus and sends them to Influx."""
state = event.data.get('new_state')
if state is None or state.state in (STATE_UNKNOWN, ''):
if state is None or state.state in (STATE_UNKNOWN, '') \
or state.entity_id in blacklist:
return
try:

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.input_boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to keep track of user controlled booleans for within automation.
For more details about this component, please refer to the documentation
@ -86,7 +84,7 @@ def setup(hass, config):
class InputBoolean(ToggleEntity):
""" Represent a boolean input. """
"""Representation of a boolean input."""
def __init__(self, object_id, name, state, icon):
"""Initialize a boolean input."""
@ -97,22 +95,22 @@ class InputBoolean(ToggleEntity):
@property
def should_poll(self):
"""If entitiy should be polled."""
"""If entity should be polled."""
return False
@property
def name(self):
"""Name of the boolean input."""
"""Return name of the boolean input."""
return self._name
@property
def icon(self):
"""Icon to be used for this entity."""
"""Returh the icon to be used for this entity."""
return self._icon
@property
def is_on(self):
"""True if entity is on."""
"""Return true if entity is on."""
return self._state
def turn_on(self, **kwargs):

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.input_select
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to offer a way to select an option from a list.
For more details about this component, please refer to the documentation
@ -92,7 +90,7 @@ def setup(hass, config):
class InputSelect(Entity):
""" Represent a select input. """
"""Representation of a select input."""
# pylint: disable=too-many-arguments
def __init__(self, object_id, name, state, options, icon):
@ -110,22 +108,22 @@ class InputSelect(Entity):
@property
def name(self):
""" Name of the select input. """
"""Return the name of the select input."""
return self._name
@property
def icon(self):
""" Icon to be used for this entity. """
"""Return the icon to be used for this entity."""
return self._icon
@property
def state(self):
""" State of the component. """
"""Return the state of the component."""
return self._current_option
@property
def state_attributes(self):
""" State attributes. """
"""Return the state attributes."""
return {
ATTR_OPTIONS: self._options,
}

View File

@ -1,6 +1,4 @@
"""
homeassistant.components.insteon_hub
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Insteon Hub.
For more details about this component, please refer to the documentation at
@ -24,8 +22,8 @@ _LOGGER = logging.getLogger(__name__)
def setup(hass, config):
"""
Setup Insteon Hub component.
"""Setup Insteon Hub component.
This will automatically import associated lights.
"""
if not validate_config(
@ -58,20 +56,21 @@ def setup(hass, config):
class InsteonToggleDevice(ToggleEntity):
""" Abstract Class for an Insteon node. """
"""An abstract Class for an Insteon node."""
def __init__(self, node):
"""Initialize the device."""
self.node = node
self._value = 0
@property
def name(self):
""" Returns the name of the node. """
"""Return the the name of the node."""
return self.node.DeviceName
@property
def unique_id(self):
""" Returns the id of this insteon node. """
"""Return the ID of this insteon node."""
return self.node.DeviceID
def update(self):
@ -84,11 +83,13 @@ class InsteonToggleDevice(ToggleEntity):
@property
def is_on(self):
""" Returns boolean response if the node is on. """
"""Return the boolean response if the node is on."""
return self._value != 0
def turn_on(self, **kwargs):
"""Turn device on."""
self.node.send_command('on')
def turn_off(self, **kwargs):
"""Turn device off."""
self.node.send_command('off')

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