Fix PEEP257 issues
This commit is contained in:
parent
d784610c52
commit
b534244e40
42 changed files with 335 additions and 308 deletions
|
@ -1,16 +1,11 @@
|
||||||
"""
|
"""
|
||||||
homeassistant.components
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
This package contains components that can be plugged into Home Assistant.
|
This package contains components that can be plugged into Home Assistant.
|
||||||
|
|
||||||
Component design guidelines:
|
Component design guidelines:
|
||||||
|
- Each component defines a constant DOMAIN that is equal to its filename.
|
||||||
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 that tracks states should create state entity names in the
|
- Each component should publish services only under its own domain.
|
||||||
format "<DOMAIN>.<OBJECT_ID>".
|
|
||||||
|
|
||||||
Each component should publish services only under its own domain.
|
|
||||||
"""
|
"""
|
||||||
import itertools as it
|
import itertools as it
|
||||||
import logging
|
import logging
|
||||||
|
@ -26,8 +21,10 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def is_on(hass, entity_id=None):
|
def is_on(hass, entity_id=None):
|
||||||
""" Loads up the module to call the is_on method.
|
"""Load up the module to call the is_on method.
|
||||||
If there is no entity id given we will check all. """
|
|
||||||
|
If there is no entity id given we will check all.
|
||||||
|
"""
|
||||||
if entity_id:
|
if entity_id:
|
||||||
group = get_component('group')
|
group = get_component('group')
|
||||||
|
|
||||||
|
@ -53,7 +50,7 @@ def is_on(hass, entity_id=None):
|
||||||
|
|
||||||
|
|
||||||
def turn_on(hass, entity_id=None, **service_data):
|
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:
|
if entity_id is not None:
|
||||||
service_data[ATTR_ENTITY_ID] = entity_id
|
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):
|
def turn_off(hass, entity_id=None, **service_data):
|
||||||
""" Turns specified entity off. """
|
"""Turn specified entity off."""
|
||||||
if entity_id is not None:
|
if entity_id is not None:
|
||||||
service_data[ATTR_ENTITY_ID] = entity_id
|
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):
|
def toggle(hass, entity_id=None, **service_data):
|
||||||
""" Toggles specified entity. """
|
"""Toggle specified entity."""
|
||||||
if entity_id is not None:
|
if entity_id is not None:
|
||||||
service_data[ATTR_ENTITY_ID] = entity_id
|
service_data[ATTR_ENTITY_ID] = entity_id
|
||||||
|
|
||||||
|
@ -77,10 +74,9 @@ def toggle(hass, entity_id=None, **service_data):
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
""" Setup general services related to homeassistant. """
|
"""Setup general services related to Home Assistant."""
|
||||||
|
|
||||||
def handle_turn_service(service):
|
def handle_turn_service(service):
|
||||||
""" Method to handle calls to homeassistant.turn_on/off. """
|
"""Method to handle calls to homeassistant.turn_on/off."""
|
||||||
entity_ids = extract_entity_ids(hass, service)
|
entity_ids = extract_entity_ids(hass, service)
|
||||||
|
|
||||||
# Generic turn on/off method requires entity id
|
# Generic turn on/off method requires entity id
|
||||||
|
|
|
@ -97,21 +97,24 @@ def _handle_alexa(handler, path_match, data):
|
||||||
|
|
||||||
|
|
||||||
class SpeechType(enum.Enum):
|
class SpeechType(enum.Enum):
|
||||||
"""Alexa speech types."""
|
"""The Alexa speech types."""
|
||||||
|
|
||||||
plaintext = "PlainText"
|
plaintext = "PlainText"
|
||||||
ssml = "SSML"
|
ssml = "SSML"
|
||||||
|
|
||||||
|
|
||||||
class CardType(enum.Enum):
|
class CardType(enum.Enum):
|
||||||
"""Alexa card types."""
|
"""The Alexa card types."""
|
||||||
|
|
||||||
simple = "Simple"
|
simple = "Simple"
|
||||||
link_account = "LinkAccount"
|
link_account = "LinkAccount"
|
||||||
|
|
||||||
|
|
||||||
class AlexaResponse(object):
|
class AlexaResponse(object):
|
||||||
"""Helps generating the response for Alexa."""
|
"""Help generating the response for Alexa."""
|
||||||
|
|
||||||
def __init__(self, hass, intent=None):
|
def __init__(self, hass, intent=None):
|
||||||
|
"""Initialize the response."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.speech = None
|
self.speech = None
|
||||||
self.card = None
|
self.card = None
|
||||||
|
@ -125,7 +128,7 @@ class AlexaResponse(object):
|
||||||
self.variables = {}
|
self.variables = {}
|
||||||
|
|
||||||
def add_card(self, card_type, title, content):
|
def add_card(self, card_type, title, content):
|
||||||
""" Add a card to the response. """
|
"""Add a card to the response."""
|
||||||
assert self.card is None
|
assert self.card is None
|
||||||
|
|
||||||
card = {
|
card = {
|
||||||
|
@ -141,7 +144,7 @@ class AlexaResponse(object):
|
||||||
self.card = card
|
self.card = card
|
||||||
|
|
||||||
def add_speech(self, speech_type, text):
|
def add_speech(self, speech_type, text):
|
||||||
""" Add speech to the response. """
|
"""Add speech to the response."""
|
||||||
assert self.speech is None
|
assert self.speech is None
|
||||||
|
|
||||||
key = 'ssml' if speech_type == SpeechType.ssml else 'text'
|
key = 'ssml' if speech_type == SpeechType.ssml else 'text'
|
||||||
|
@ -163,7 +166,7 @@ class AlexaResponse(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
"""Returns response in an Alexa valid dict."""
|
"""Return response in an Alexa valid dict."""
|
||||||
response = {
|
response = {
|
||||||
'shouldEndSession': self.should_end_session
|
'shouldEndSession': self.should_end_session
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,11 +51,14 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class APCUPSdData(object):
|
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):
|
def __init__(self, host, port):
|
||||||
|
"""Initialize the data oject."""
|
||||||
from apcaccess import status
|
from apcaccess import status
|
||||||
self._host = host
|
self._host = host
|
||||||
self._port = port
|
self._port = port
|
||||||
|
@ -75,7 +78,5 @@ class APCUPSdData(object):
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
def update(self, **kwargs):
|
def update(self, **kwargs):
|
||||||
"""
|
"""Fetch the latest status from APCUPSd."""
|
||||||
Fetch the latest status from APCUPSd and store it in self._status.
|
|
||||||
"""
|
|
||||||
self._status = self._get_status()
|
self._status = self._get_status()
|
||||||
|
|
|
@ -34,7 +34,6 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Register the API with the HTTP interface."""
|
"""Register the API with the HTTP interface."""
|
||||||
|
|
||||||
# /api - for validation purposes
|
# /api - for validation purposes
|
||||||
hass.http.register_path('GET', URL_API, _handle_get_api)
|
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):
|
def _handle_get_api(handler, path_match, data):
|
||||||
"""Renders the debug interface."""
|
"""Render the debug interface."""
|
||||||
handler.write_json_message("API running.")
|
handler.write_json_message("API running.")
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,7 +113,7 @@ def _handle_get_api_stream(handler, path_match, data):
|
||||||
restrict = restrict.split(',')
|
restrict = restrict.split(',')
|
||||||
|
|
||||||
def write_message(payload):
|
def write_message(payload):
|
||||||
"""Writes a message to the output."""
|
"""Write a message to the output."""
|
||||||
with write_lock:
|
with write_lock:
|
||||||
msg = "data: {}\n\n".format(payload)
|
msg = "data: {}\n\n".format(payload)
|
||||||
|
|
||||||
|
@ -127,7 +126,7 @@ def _handle_get_api_stream(handler, path_match, data):
|
||||||
block.set()
|
block.set()
|
||||||
|
|
||||||
def forward_events(event):
|
def forward_events(event):
|
||||||
"""Forwards events to the open request."""
|
"""Forward events to the open request."""
|
||||||
nonlocal gracefully_closed
|
nonlocal gracefully_closed
|
||||||
|
|
||||||
if block.is_set() or event.event_type == EVENT_TIME_CHANGED:
|
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):
|
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())
|
handler.write_json(handler.server.hass.config.as_dict())
|
||||||
|
|
||||||
|
|
||||||
def _handle_get_api_states(handler, path_match, data):
|
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())
|
handler.write_json(handler.server.hass.states.all())
|
||||||
|
|
||||||
|
|
||||||
def _handle_get_api_states_entity(handler, path_match, data):
|
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')
|
entity_id = path_match.group('entity_id')
|
||||||
|
|
||||||
state = handler.server.hass.states.get(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):
|
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:
|
This handles the following paths:
|
||||||
/api/states/<entity_id>
|
/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):
|
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))
|
handler.write_json(events_json(handler.server.hass))
|
||||||
|
|
||||||
|
|
||||||
def _handle_api_post_events_event(handler, path_match, event_data):
|
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:
|
This handles the following paths: /api/events/<event_type>
|
||||||
/api/events/<event_type>
|
|
||||||
|
|
||||||
Events from /api are threated as remote events.
|
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):
|
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))
|
handler.write_json(services_json(handler.server.hass))
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
def _handle_post_api_services_domain_service(handler, path_match, data):
|
def _handle_post_api_services_domain_service(handler, path_match, data):
|
||||||
"""Handles calling a service.
|
"""Handle calling a service.
|
||||||
|
|
||||||
This handles the following paths:
|
This handles the following paths: /api/services/<domain>/<service>
|
||||||
/api/services/<domain>/<service>
|
|
||||||
"""
|
"""
|
||||||
domain = path_match.group('domain')
|
domain = path_match.group('domain')
|
||||||
service = path_match.group('service')
|
service = path_match.group('service')
|
||||||
|
@ -298,7 +295,7 @@ def _handle_post_api_services_domain_service(handler, path_match, data):
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
def _handle_post_api_event_forward(handler, path_match, data):
|
def _handle_post_api_event_forward(handler, path_match, data):
|
||||||
"""Handles adding an event forwarding target."""
|
"""Handle adding an event forwarding target."""
|
||||||
try:
|
try:
|
||||||
host = data['host']
|
host = data['host']
|
||||||
api_password = data['api_password']
|
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):
|
def _handle_delete_api_event_forward(handler, path_match, data):
|
||||||
"""Handles deleting an event forwarding target."""
|
"""Handle deleting an event forwarding target."""
|
||||||
try:
|
try:
|
||||||
host = data['host']
|
host = data['host']
|
||||||
except KeyError:
|
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):
|
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)
|
handler.write_json(handler.server.hass.config.components)
|
||||||
|
|
||||||
|
|
||||||
def _handle_get_api_error_log(handler, path_match, data):
|
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),
|
handler.write_file(handler.server.hass.config.path(ERROR_LOG_FILENAME),
|
||||||
False)
|
False)
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class ArduinoBoard(object):
|
class ArduinoBoard(object):
|
||||||
"""Represents an Arduino board."""
|
"""Representation of an Arduino board."""
|
||||||
|
|
||||||
def __init__(self, port):
|
def __init__(self, port):
|
||||||
|
"""Initialize the board."""
|
||||||
from PyMata.pymata import PyMata
|
from PyMata.pymata import PyMata
|
||||||
self._port = port
|
self._port = port
|
||||||
self._board = PyMata(self._port, verbose=False)
|
self._board = PyMata(self._port, verbose=False)
|
||||||
|
@ -104,6 +106,6 @@ class ArduinoBoard(object):
|
||||||
return self._board.get_firmata_version()
|
return self._board.get_firmata_version()
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
"""Disconnects the board and closes the serial connection."""
|
"""Disconnect the board and close the serial connection."""
|
||||||
self._board.reset()
|
self._board.reset()
|
||||||
self._board.close()
|
self._board.close()
|
||||||
|
|
|
@ -30,7 +30,7 @@ DISCOVER_CAMERAS = 'bloomsky.camera'
|
||||||
|
|
||||||
# pylint: disable=unused-argument,too-few-public-methods
|
# pylint: disable=unused-argument,too-few-public-methods
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
""" Setup BloomSky component. """
|
"""Setup BloomSky component."""
|
||||||
if not validate_config(
|
if not validate_config(
|
||||||
config,
|
config,
|
||||||
{DOMAIN: [CONF_API_KEY]},
|
{DOMAIN: [CONF_API_KEY]},
|
||||||
|
@ -55,13 +55,13 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class BloomSky(object):
|
class BloomSky(object):
|
||||||
""" Handle all communication with the BloomSky API. """
|
"""Handle all communication with the BloomSky API."""
|
||||||
|
|
||||||
# API documentation at http://weatherlution.com/bloomsky-api/
|
# API documentation at http://weatherlution.com/bloomsky-api/
|
||||||
|
|
||||||
API_URL = "https://api.bloomsky.com/api/skydata"
|
API_URL = "https://api.bloomsky.com/api/skydata"
|
||||||
|
|
||||||
def __init__(self, api_key):
|
def __init__(self, api_key):
|
||||||
|
"""Initialize the BookSky."""
|
||||||
self._api_key = api_key
|
self._api_key = api_key
|
||||||
self.devices = {}
|
self.devices = {}
|
||||||
_LOGGER.debug("Initial bloomsky device load...")
|
_LOGGER.debug("Initial bloomsky device load...")
|
||||||
|
@ -69,10 +69,7 @@ class BloomSky(object):
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
def refresh_devices(self):
|
def refresh_devices(self):
|
||||||
"""
|
"""Use the API to retreive a list of devices."""
|
||||||
Uses the API to retreive a list of devices associated with an
|
|
||||||
account along with all the sensors on the device.
|
|
||||||
"""
|
|
||||||
_LOGGER.debug("Fetching bloomsky update")
|
_LOGGER.debug("Fetching bloomsky update")
|
||||||
response = requests.get(self.API_URL,
|
response = requests.get(self.API_URL,
|
||||||
headers={"Authorization": self._api_key},
|
headers={"Authorization": self._api_key},
|
||||||
|
@ -82,7 +79,7 @@ class BloomSky(object):
|
||||||
elif response.status_code != 200:
|
elif response.status_code != 200:
|
||||||
_LOGGER.error("Invalid HTTP response: %s", response.status_code)
|
_LOGGER.error("Invalid HTTP response: %s", response.status_code)
|
||||||
return
|
return
|
||||||
# create dictionary keyed off of the device unique id
|
# Create dictionary keyed off of the device unique id
|
||||||
self.devices.update({
|
self.devices.update({
|
||||||
device["DeviceID"]: device for device in response.json()
|
device["DeviceID"]: device for device in response.json()
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,9 +10,7 @@ SERVICE_BROWSE_URL = "browse_url"
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""
|
"""Listen for browse_url events."""
|
||||||
Listen for browse_url events and open the url in the default web browser.
|
|
||||||
"""
|
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
hass.services.register(DOMAIN, SERVICE_BROWSE_URL,
|
hass.services.register(DOMAIN, SERVICE_BROWSE_URL,
|
||||||
|
|
|
@ -36,6 +36,7 @@ def request_config(
|
||||||
hass, name, callback, description=None, description_image=None,
|
hass, name, callback, description=None, description_image=None,
|
||||||
submit_caption=None, fields=None):
|
submit_caption=None, fields=None):
|
||||||
"""Create a new request for configuration.
|
"""Create a new request for configuration.
|
||||||
|
|
||||||
Will return an ID to be used for sequent calls.
|
Will return an ID to be used for sequent calls.
|
||||||
"""
|
"""
|
||||||
instance = _get_instance(hass)
|
instance = _get_instance(hass)
|
||||||
|
@ -86,8 +87,10 @@ def _get_instance(hass):
|
||||||
|
|
||||||
|
|
||||||
class Configurator(object):
|
class Configurator(object):
|
||||||
"""Class to keep track of current configuration requests."""
|
"""The class to keep track of current configuration requests."""
|
||||||
|
|
||||||
def __init__(self, hass):
|
def __init__(self, hass):
|
||||||
|
"""Initialize the configurator."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._cur_id = 0
|
self._cur_id = 0
|
||||||
self._requests = {}
|
self._requests = {}
|
||||||
|
@ -173,7 +176,7 @@ class Configurator(object):
|
||||||
callback(call.data.get(ATTR_FIELDS, {}))
|
callback(call.data.get(ATTR_FIELDS, {}))
|
||||||
|
|
||||||
def _generate_unique_id(self):
|
def _generate_unique_id(self):
|
||||||
"""Generates a unique configurator ID."""
|
"""Generate a unique configurator ID."""
|
||||||
self._cur_id += 1
|
self._cur_id += 1
|
||||||
return "{}-{}".format(id(self), self._cur_id)
|
return "{}-{}".format(id(self), self._cur_id)
|
||||||
|
|
||||||
|
|
|
@ -23,19 +23,18 @@ REQUIREMENTS = ['fuzzywuzzy==0.8.0']
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Registers the process service."""
|
"""Register the process service."""
|
||||||
from fuzzywuzzy import process as fuzzyExtract
|
from fuzzywuzzy import process as fuzzyExtract
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def process(service):
|
def process(service):
|
||||||
"""Parses text into commands."""
|
"""Parse text into commands."""
|
||||||
if ATTR_TEXT not in service.data:
|
if ATTR_TEXT not in service.data:
|
||||||
logger.error("Received process service call without a text")
|
logger.error("Received process service call without a text")
|
||||||
return
|
return
|
||||||
|
|
||||||
text = service.data[ATTR_TEXT].lower()
|
text = service.data[ATTR_TEXT].lower()
|
||||||
|
|
||||||
match = REGEX_TURN_COMMAND.match(text)
|
match = REGEX_TURN_COMMAND.match(text)
|
||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
|
@ -43,11 +42,8 @@ def setup(hass, config):
|
||||||
return
|
return
|
||||||
|
|
||||||
name, command = match.groups()
|
name, command = match.groups()
|
||||||
|
|
||||||
entities = {state.entity_id: state.name for state in hass.states.all()}
|
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]
|
score_cutoff=65)[2]
|
||||||
|
|
||||||
if not entity_ids:
|
if not entity_ids:
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Provides functionality to turn on lights based on the state of the sun and
|
Provides functionality to turn on lights based on the states.
|
||||||
devices home.
|
|
||||||
|
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/device_sun_light_trigger/
|
https://home-assistant.io/components/device_sun_light_trigger/
|
||||||
|
@ -29,7 +28,7 @@ CONF_DEVICE_GROUP = 'device_group'
|
||||||
|
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Triggers to turn lights on or off based on device presence."""
|
"""The triggers to turn lights on or off based on device presence."""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
device_tracker = get_component('device_tracker')
|
device_tracker = get_component('device_tracker')
|
||||||
group = get_component('group')
|
group = get_component('group')
|
||||||
|
@ -57,16 +56,20 @@ def setup(hass, config):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def calc_time_for_light_when_sunset():
|
def calc_time_for_light_when_sunset():
|
||||||
""" Calculates the time when to start fading lights in when sun sets.
|
"""Calculate the time when to start fading lights in when sun sets.
|
||||||
Returns None if no next_setting data available. """
|
|
||||||
|
Returns None if no next_setting data available.
|
||||||
|
"""
|
||||||
next_setting = sun.next_setting(hass)
|
next_setting = sun.next_setting(hass)
|
||||||
if not next_setting:
|
if not next_setting:
|
||||||
return None
|
return None
|
||||||
return next_setting - LIGHT_TRANSITION_TIME * len(light_ids)
|
return next_setting - LIGHT_TRANSITION_TIME * len(light_ids)
|
||||||
|
|
||||||
def turn_light_on_before_sunset(light_id):
|
def turn_light_on_before_sunset(light_id):
|
||||||
""" Helper function to turn on lights slowly if there
|
"""Helper function to turn on lights.
|
||||||
are devices home and the light is not on yet. """
|
|
||||||
|
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):
|
if not device_tracker.is_on(hass) or light.is_on(hass, light_id):
|
||||||
return
|
return
|
||||||
light.turn_on(hass, light_id,
|
light.turn_on(hass, light_id,
|
||||||
|
@ -78,8 +81,8 @@ def setup(hass, config):
|
||||||
@track_state_change(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON,
|
@track_state_change(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON,
|
||||||
sun.STATE_ABOVE_HORIZON)
|
sun.STATE_ABOVE_HORIZON)
|
||||||
def schedule_lights_at_sun_set(hass, entity, old_state, new_state):
|
def schedule_lights_at_sun_set(hass, entity, old_state, new_state):
|
||||||
"""
|
"""The moment sun sets we want to have all the lights on.
|
||||||
The moment sun sets we want to have all the lights on.
|
|
||||||
We will schedule to have each light start after one another
|
We will schedule to have each light start after one another
|
||||||
and slowly transition in.
|
and slowly transition in.
|
||||||
"""
|
"""
|
||||||
|
@ -88,10 +91,10 @@ def setup(hass, config):
|
||||||
return
|
return
|
||||||
|
|
||||||
def turn_on(light_id):
|
def turn_on(light_id):
|
||||||
"""
|
"""Lambda can keep track of function parameters.
|
||||||
Lambda can keep track of function parameters but not local
|
|
||||||
parameters. If we put the lambda directly in the below statement
|
No local parameters. If we put the lambda directly in the below
|
||||||
only the last light will be turned on.
|
statement only the last light will be turned on.
|
||||||
"""
|
"""
|
||||||
return lambda now: turn_light_on_before_sunset(light_id)
|
return lambda now: turn_light_on_before_sunset(light_id)
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,8 @@ SERVICE_HANDLERS = {
|
||||||
|
|
||||||
|
|
||||||
def listen(hass, service, callback):
|
def listen(hass, service, callback):
|
||||||
"""
|
"""Setup listener for discovery of specific service.
|
||||||
Setup listener for discovery of specific service.
|
|
||||||
Service can be a string or a list/tuple.
|
Service can be a string or a list/tuple.
|
||||||
"""
|
"""
|
||||||
if isinstance(service, str):
|
if isinstance(service, str):
|
||||||
|
@ -70,7 +70,7 @@ def discover(hass, service, discovered=None, component=None, hass_config=None):
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Starts a discovery service."""
|
"""Start a discovery service."""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from netdisco.service import DiscoveryService
|
from netdisco.service import DiscoveryService
|
||||||
|
|
|
@ -26,7 +26,7 @@ CONF_DOWNLOAD_DIR = 'download_dir'
|
||||||
|
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Listens for download events to download files."""
|
"""Listen for download events to download files."""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
if not validate_config(config, {DOMAIN: [CONF_DOWNLOAD_DIR]}, logger):
|
if not validate_config(config, {DOMAIN: [CONF_DOWNLOAD_DIR]}, logger):
|
||||||
|
@ -47,13 +47,13 @@ def setup(hass, config):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def download_file(service):
|
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:
|
if ATTR_URL not in service.data:
|
||||||
logger.error("Service called but 'url' parameter not specified.")
|
logger.error("Service called but 'url' parameter not specified.")
|
||||||
return
|
return
|
||||||
|
|
||||||
def do_download():
|
def do_download():
|
||||||
"""Downloads the file."""
|
"""Download the file."""
|
||||||
try:
|
try:
|
||||||
url = service.data[ATTR_URL]
|
url = service.data[ATTR_URL]
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ def request_configuration(network, hass, config):
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def ecobee_configuration_callback(callback_data):
|
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.request_tokens()
|
||||||
network.update()
|
network.update()
|
||||||
setup_ecobee(hass, network, config)
|
setup_ecobee(hass, network, config)
|
||||||
|
@ -91,8 +91,10 @@ def setup_ecobee(hass, network, config):
|
||||||
|
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
class EcobeeData(object):
|
class EcobeeData(object):
|
||||||
"""Gets the latest data and update the states."""
|
"""Get the latest data and update the states."""
|
||||||
|
|
||||||
def __init__(self, config_file):
|
def __init__(self, config_file):
|
||||||
|
"""Initialize the Ecobee data object."""
|
||||||
from pyecobee import Ecobee
|
from pyecobee import Ecobee
|
||||||
self.ecobee = Ecobee(config_file)
|
self.ecobee = Ecobee(config_file)
|
||||||
|
|
||||||
|
@ -104,8 +106,8 @@ class EcobeeData(object):
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""
|
"""Setup Ecobee.
|
||||||
Setup Ecobee.
|
|
||||||
Will automatically load thermostat and sensor components to support
|
Will automatically load thermostat and sensor components to support
|
||||||
devices discovered on the network.
|
devices discovered on the network.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Component that records all events and state changes and feeds the data to
|
Component that sends data to aGraphite installation.
|
||||||
a Graphite installation.
|
|
||||||
|
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/graphite/
|
https://home-assistant.io/components/graphite/
|
||||||
|
@ -35,8 +34,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class GraphiteFeeder(threading.Thread):
|
class GraphiteFeeder(threading.Thread):
|
||||||
"""Feeds data to Graphite."""
|
"""Feed data to Graphite."""
|
||||||
|
|
||||||
def __init__(self, hass, host, port, prefix):
|
def __init__(self, hass, host, port, prefix):
|
||||||
|
"""Initialize the feeder."""
|
||||||
super(GraphiteFeeder, self).__init__(daemon=True)
|
super(GraphiteFeeder, self).__init__(daemon=True)
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self._host = host
|
self._host = host
|
||||||
|
|
|
@ -106,7 +106,7 @@ def get_entity_ids(hass, entity_id, domain_filter=None):
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Set 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():
|
for object_id, conf in config.get(DOMAIN, {}).items():
|
||||||
if not isinstance(conf, dict):
|
if not isinstance(conf, dict):
|
||||||
conf = {CONF_ENTITIES: conf}
|
conf = {CONF_ENTITIES: conf}
|
||||||
|
@ -129,7 +129,6 @@ class Group(Entity):
|
||||||
"""Track a group of entity ids."""
|
"""Track a group of entity ids."""
|
||||||
|
|
||||||
# pylint: disable=too-many-instance-attributes, too-many-arguments
|
# pylint: disable=too-many-instance-attributes, too-many-arguments
|
||||||
|
|
||||||
def __init__(self, hass, name, entity_ids=None, user_defined=True,
|
def __init__(self, hass, name, entity_ids=None, user_defined=True,
|
||||||
icon=None, view=False, object_id=None):
|
icon=None, view=False, object_id=None):
|
||||||
"""Initialize a group."""
|
"""Initialize a group."""
|
||||||
|
@ -160,30 +159,27 @@ class Group(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Name of the group."""
|
"""Return the name of the group."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""State of the group."""
|
"""Return the state of the group."""
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
"""Icon of the group."""
|
"""Return the icon of the group."""
|
||||||
return self._icon
|
return self._icon
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hidden(self):
|
def hidden(self):
|
||||||
"""If group should be hidden or not.
|
"""If group should be hidden or not."""
|
||||||
|
|
||||||
true if group is a view or not user defined.
|
|
||||||
"""
|
|
||||||
return not self._user_defined or self._view
|
return not self._user_defined or self._view
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
"""State attributes for the group."""
|
"""Return the state attributes for the group."""
|
||||||
data = {
|
data = {
|
||||||
ATTR_ENTITY_ID: self.tracking,
|
ATTR_ENTITY_ID: self.tracking,
|
||||||
ATTR_ORDER: self._order,
|
ATTR_ORDER: self._order,
|
||||||
|
@ -215,7 +211,7 @@ class Group(Entity):
|
||||||
self.hass, self.tracking, self._state_changed_listener)
|
self.hass, self.tracking, self._state_changed_listener)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Unregisters the group from Home Assistant."""
|
"""Unregister the group from Home Assistant."""
|
||||||
self.hass.states.remove(self.entity_id)
|
self.hass.states.remove(self.entity_id)
|
||||||
|
|
||||||
self.hass.bus.remove_listener(
|
self.hass.bus.remove_listener(
|
||||||
|
@ -233,7 +229,7 @@ class Group(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _tracking_states(self):
|
def _tracking_states(self):
|
||||||
"""States that the group is tracking."""
|
"""The states that the group is tracking."""
|
||||||
states = []
|
states = []
|
||||||
|
|
||||||
for entity_id in self.tracking:
|
for entity_id in self.tracking:
|
||||||
|
|
|
@ -70,9 +70,7 @@ def get_significant_states(start_time, end_time=None, entity_id=None):
|
||||||
|
|
||||||
|
|
||||||
def state_changes_during_period(start_time, end_time=None, entity_id=None):
|
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 > ? "
|
where = "last_changed=last_updated AND last_changed > ? "
|
||||||
data = [start_time]
|
data = [start_time]
|
||||||
|
|
||||||
|
@ -93,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):
|
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:
|
if run is None:
|
||||||
run = recorder.run_information(utc_point_in_time)
|
run = recorder.run_information(utc_point_in_time)
|
||||||
|
|
||||||
|
@ -122,8 +120,7 @@ def get_states(utc_point_in_time, entity_ids=None, run=None):
|
||||||
|
|
||||||
|
|
||||||
def states_to_json(states, start_time, entity_id):
|
def states_to_json(states, start_time, entity_id):
|
||||||
"""
|
"""Convert SQL results into JSON friendly data structure.
|
||||||
Converts SQL results into JSON friendly data structure.
|
|
||||||
|
|
||||||
This takes our state list and turns it into a JSON friendly data
|
This takes our state list and turns it into a JSON friendly data
|
||||||
structure {'entity_id': [list of states], 'entity_id2': [list of states]}
|
structure {'entity_id': [list of states], 'entity_id2': [list of states]}
|
||||||
|
@ -157,7 +154,7 @@ def get_state(utc_point_in_time, entity_id, run=None):
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Setup history hooks."""
|
"""Setup the history hooks."""
|
||||||
hass.http.register_path(
|
hass.http.register_path(
|
||||||
'GET',
|
'GET',
|
||||||
re.compile(
|
re.compile(
|
||||||
|
@ -204,8 +201,7 @@ def _api_history_period(handler, path_match, data):
|
||||||
|
|
||||||
|
|
||||||
def _is_significant(state):
|
def _is_significant(state):
|
||||||
"""
|
"""Test if state is significant for history charts.
|
||||||
Test if state is significant for history charts.
|
|
||||||
|
|
||||||
Will only test for things that are not filtered out in SQL.
|
Will only test for things that are not filtered out in SQL.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -50,7 +50,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Sets up the HTTP API and debug interface."""
|
"""Set up the HTTP API and debug interface."""
|
||||||
conf = config.get(DOMAIN, {})
|
conf = config.get(DOMAIN, {})
|
||||||
|
|
||||||
api_password = util.convert(conf.get(CONF_API_PASSWORD), str)
|
api_password = util.convert(conf.get(CONF_API_PASSWORD), str)
|
||||||
|
@ -86,6 +86,7 @@ def setup(hass, config):
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
|
class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
"""Handle HTTP requests in a threaded fashion."""
|
"""Handle HTTP requests in a threaded fashion."""
|
||||||
|
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
allow_reuse_address = True
|
allow_reuse_address = True
|
||||||
daemon_threads = True
|
daemon_threads = True
|
||||||
|
@ -93,6 +94,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
def __init__(self, server_address, request_handler_class,
|
def __init__(self, server_address, request_handler_class,
|
||||||
hass, api_password, development, ssl_certificate, ssl_key):
|
hass, api_password, development, ssl_certificate, ssl_key):
|
||||||
|
"""Initialize the server."""
|
||||||
super().__init__(server_address, request_handler_class)
|
super().__init__(server_address, request_handler_class)
|
||||||
|
|
||||||
self.server_address = server_address
|
self.server_address = server_address
|
||||||
|
@ -116,9 +118,9 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
self.socket = context.wrap_socket(self.socket, server_side=True)
|
self.socket = context.wrap_socket(self.socket, server_side=True)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Starts the HTTP server."""
|
"""Start the HTTP server."""
|
||||||
def stop_http(event):
|
def stop_http(event):
|
||||||
"""Stops the HTTP server."""
|
"""Stop the HTTP server."""
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
|
|
||||||
self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http)
|
self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http)
|
||||||
|
@ -137,7 +139,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
self.serve_forever()
|
self.serve_forever()
|
||||||
|
|
||||||
def register_path(self, method, url, callback, require_auth=True):
|
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))
|
self.paths.append((method, url, callback, require_auth))
|
||||||
|
|
||||||
def log_message(self, fmt, *args):
|
def log_message(self, fmt, *args):
|
||||||
|
@ -148,16 +150,16 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
|
|
||||||
# pylint: disable=too-many-public-methods,too-many-locals
|
# pylint: disable=too-many-public-methods,too-many-locals
|
||||||
class RequestHandler(SimpleHTTPRequestHandler):
|
class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
"""
|
"""Handle incoming HTTP requests.
|
||||||
Handles incoming HTTP requests
|
|
||||||
|
|
||||||
We extend from SimpleHTTPRequestHandler instead of Base so we
|
We extend from SimpleHTTPRequestHandler instead of Base so we
|
||||||
can use the guess content type methods.
|
can use the guess content type methods.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
server_version = "HomeAssistant/1.0"
|
server_version = "HomeAssistant/1.0"
|
||||||
|
|
||||||
def __init__(self, req, client_addr, server):
|
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
|
# Track if this was an authenticated request
|
||||||
self.authenticated = False
|
self.authenticated = False
|
||||||
SimpleHTTPRequestHandler.__init__(self, req, client_addr, server)
|
SimpleHTTPRequestHandler.__init__(self, req, client_addr, server)
|
||||||
|
@ -172,7 +174,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
if isinstance(arg, str) else arg for arg in arguments))
|
if isinstance(arg, str) else arg for arg in arguments))
|
||||||
|
|
||||||
def _handle_request(self, method): # pylint: disable=too-many-branches
|
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)
|
url = urlparse(self.path)
|
||||||
|
|
||||||
# Read query input. parse_qs gives a list for each value, we want last
|
# Read query input. parse_qs gives a list for each value, we want last
|
||||||
|
@ -302,7 +304,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
self.wfile.write(message.encode("UTF-8"))
|
self.wfile.write(message.encode("UTF-8"))
|
||||||
|
|
||||||
def write_file(self, path, cache_headers=True):
|
def write_file(self, path, cache_headers=True):
|
||||||
"""Returns a file to the user."""
|
"""Return a file to the user."""
|
||||||
try:
|
try:
|
||||||
with open(path, 'rb') as inp:
|
with open(path, 'rb') as inp:
|
||||||
self.write_file_pointer(self.guess_type(path), inp,
|
self.write_file_pointer(self.guess_type(path), inp,
|
||||||
|
@ -314,10 +316,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
_LOGGER.exception("Unable to serve %s", path)
|
_LOGGER.exception("Unable to serve %s", path)
|
||||||
|
|
||||||
def write_file_pointer(self, content_type, inp, cache_headers=True):
|
def write_file_pointer(self, content_type, inp, cache_headers=True):
|
||||||
"""
|
"""Helper function to write a file pointer to the user."""
|
||||||
Helper function to write a file pointer to the user.
|
|
||||||
Does not do error handling.
|
|
||||||
"""
|
|
||||||
do_gzip = 'gzip' in self.headers.get(HTTP_HEADER_ACCEPT_ENCODING, '')
|
do_gzip = 'gzip' in self.headers.get(HTTP_HEADER_ACCEPT_ENCODING, '')
|
||||||
|
|
||||||
self.send_response(HTTP_OK)
|
self.send_response(HTTP_OK)
|
||||||
|
@ -387,9 +386,9 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
return self.get_cookie_session_id() is not None
|
return self.get_cookie_session_id() is not None
|
||||||
|
|
||||||
def get_cookie_session_id(self):
|
def get_cookie_session_id(self):
|
||||||
"""
|
"""Extract the current session ID from the cookie.
|
||||||
Extracts the current session id from the cookie or returns None if not
|
|
||||||
set or invalid.
|
Return None if not set or invalid.
|
||||||
"""
|
"""
|
||||||
if 'Cookie' not in self.headers:
|
if 'Cookie' not in self.headers:
|
||||||
return None
|
return None
|
||||||
|
@ -413,7 +412,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def destroy_session(self):
|
def destroy_session(self):
|
||||||
"""Destroys session."""
|
"""Destroy the session."""
|
||||||
session_id = self.get_cookie_session_id()
|
session_id = self.get_cookie_session_id()
|
||||||
|
|
||||||
if session_id is None:
|
if session_id is None:
|
||||||
|
@ -430,6 +429,7 @@ def session_valid_time():
|
||||||
|
|
||||||
class SessionStore(object):
|
class SessionStore(object):
|
||||||
"""Responsible for storing and retrieving HTTP sessions."""
|
"""Responsible for storing and retrieving HTTP sessions."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Setup the session store."""
|
"""Setup the session store."""
|
||||||
self._sessions = {}
|
self._sessions = {}
|
||||||
|
@ -464,7 +464,7 @@ class SessionStore(object):
|
||||||
self._sessions.pop(key, None)
|
self._sessions.pop(key, None)
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
"""Creates a new session."""
|
"""Create a new session."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
session_id = util.get_random_string(20)
|
session_id = util.get_random_string(20)
|
||||||
|
|
||||||
|
|
|
@ -84,9 +84,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class InputBoolean(ToggleEntity):
|
class InputBoolean(ToggleEntity):
|
||||||
"""Represent a boolean input."""
|
"""Representation of a boolean input."""
|
||||||
|
|
||||||
def __init__(self, object_id, name, state, icon):
|
def __init__(self, object_id, name, state, icon):
|
||||||
""" Initialize a boolean input. """
|
"""Initialize a boolean input."""
|
||||||
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
||||||
self._name = name
|
self._name = name
|
||||||
self._state = state
|
self._state = state
|
||||||
|
|
|
@ -90,10 +90,11 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class InputSelect(Entity):
|
class InputSelect(Entity):
|
||||||
"""Represent a select input."""
|
"""Representation of a select input."""
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
def __init__(self, object_id, name, state, options, icon):
|
def __init__(self, object_id, name, state, options, icon):
|
||||||
""" Initialize a select input. """
|
"""Initialize a select input."""
|
||||||
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
||||||
self._name = name
|
self._name = name
|
||||||
self._current_option = state
|
self._current_option = state
|
||||||
|
|
|
@ -22,8 +22,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""
|
"""Setup Insteon Hub component.
|
||||||
Setup Insteon Hub component.
|
|
||||||
This will automatically import associated lights.
|
This will automatically import associated lights.
|
||||||
"""
|
"""
|
||||||
if not validate_config(
|
if not validate_config(
|
||||||
|
@ -56,8 +56,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class InsteonToggleDevice(ToggleEntity):
|
class InsteonToggleDevice(ToggleEntity):
|
||||||
""" An abstract Class for an Insteon node."""
|
"""An abstract Class for an Insteon node."""
|
||||||
|
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
|
"""Initialize the device."""
|
||||||
self.node = node
|
self.node = node
|
||||||
self._value = 0
|
self._value = 0
|
||||||
|
|
||||||
|
@ -85,7 +87,9 @@ class InsteonToggleDevice(ToggleEntity):
|
||||||
return self._value != 0
|
return self._value != 0
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
|
"""Turn device on."""
|
||||||
self.node.send_command('on')
|
self.node.send_command('on')
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs):
|
||||||
|
"""Turn device off."""
|
||||||
self.node.send_command('off')
|
self.node.send_command('off')
|
||||||
|
|
|
@ -29,8 +29,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""
|
"""Setup ISY994 component.
|
||||||
Setup ISY994 component.
|
|
||||||
This will automatically import associated lights, switches, and sensors.
|
This will automatically import associated lights, switches, and sensors.
|
||||||
"""
|
"""
|
||||||
import PyISY
|
import PyISY
|
||||||
|
@ -97,6 +97,7 @@ def stop(event):
|
||||||
|
|
||||||
class ISYDeviceABC(ToggleEntity):
|
class ISYDeviceABC(ToggleEntity):
|
||||||
"""An abstract Class for an ISY device."""
|
"""An abstract Class for an ISY device."""
|
||||||
|
|
||||||
_attrs = {}
|
_attrs = {}
|
||||||
_onattrs = []
|
_onattrs = []
|
||||||
_states = []
|
_states = []
|
||||||
|
@ -105,6 +106,7 @@ class ISYDeviceABC(ToggleEntity):
|
||||||
_name = None
|
_name = None
|
||||||
|
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
|
"""Initialize the device."""
|
||||||
# setup properties
|
# setup properties
|
||||||
self.node = node
|
self.node = node
|
||||||
|
|
||||||
|
@ -182,7 +184,7 @@ class ISYDeviceABC(ToggleEntity):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_update(self, event):
|
def on_update(self, event):
|
||||||
"""Handles the update received event."""
|
"""Handle the update received event."""
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -203,7 +205,7 @@ class ISYDeviceABC(ToggleEntity):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
"""Turns the device on."""
|
"""Turn the device on."""
|
||||||
if self.domain is not 'sensor':
|
if self.domain is not 'sensor':
|
||||||
attrs = [kwargs.get(name) for name in self._onattrs]
|
attrs = [kwargs.get(name) for name in self._onattrs]
|
||||||
self.node.on(*attrs)
|
self.node.on(*attrs)
|
||||||
|
@ -211,7 +213,7 @@ class ISYDeviceABC(ToggleEntity):
|
||||||
_LOGGER.error('ISY cannot turn on sensors.')
|
_LOGGER.error('ISY cannot turn on sensors.')
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs):
|
||||||
"""Turns the device off."""
|
"""Turn the device off."""
|
||||||
if self.domain is not 'sensor':
|
if self.domain is not 'sensor':
|
||||||
self.node.off()
|
self.node.off()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -39,7 +39,7 @@ def media_next_track(hass):
|
||||||
|
|
||||||
|
|
||||||
def media_prev_track(hass):
|
def media_prev_track(hass):
|
||||||
"""Press the keyboard button for prev track. """
|
"""Press the keyboard button for prev track."""
|
||||||
hass.services.call(DOMAIN, SERVICE_MEDIA_PREVIOUS_TRACK)
|
hass.services.call(DOMAIN, SERVICE_MEDIA_PREVIOUS_TRACK)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ ATTR_ENTITY_ID = 'entity_id'
|
||||||
|
|
||||||
|
|
||||||
def log_entry(hass, name, message, domain=None, entity_id=None):
|
def log_entry(hass, name, message, domain=None, entity_id=None):
|
||||||
"""Adds an entry to the logbook."""
|
"""Add an entry to the logbook."""
|
||||||
data = {
|
data = {
|
||||||
ATTR_NAME: name,
|
ATTR_NAME: name,
|
||||||
ATTR_MESSAGE: message
|
ATTR_MESSAGE: message
|
||||||
|
@ -55,7 +55,7 @@ def log_entry(hass, name, message, domain=None, entity_id=None):
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Listens for download events to download files."""
|
"""Listen for download events to download files."""
|
||||||
def log_message(service):
|
def log_message(service):
|
||||||
"""Handle sending notification message service calls."""
|
"""Handle sending notification message service calls."""
|
||||||
message = service.data.get(ATTR_MESSAGE)
|
message = service.data.get(ATTR_MESSAGE)
|
||||||
|
@ -100,9 +100,11 @@ def _handle_get_logbook(handler, path_match, data):
|
||||||
|
|
||||||
class Entry(object):
|
class Entry(object):
|
||||||
"""A human readable version of the log."""
|
"""A human readable version of the log."""
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments, too-few-public-methods
|
# pylint: disable=too-many-arguments, too-few-public-methods
|
||||||
def __init__(self, when=None, name=None, message=None, domain=None,
|
def __init__(self, when=None, name=None, message=None, domain=None,
|
||||||
entity_id=None):
|
entity_id=None):
|
||||||
|
"""Initialize the entry."""
|
||||||
self.when = when
|
self.when = when
|
||||||
self.name = name
|
self.name = name
|
||||||
self.message = message
|
self.message = message
|
||||||
|
@ -121,8 +123,7 @@ class Entry(object):
|
||||||
|
|
||||||
|
|
||||||
def humanify(events):
|
def humanify(events):
|
||||||
"""
|
"""Generator that converts a list of events into Entry objects.
|
||||||
Generator that converts a list of events into Entry objects.
|
|
||||||
|
|
||||||
Will try to group events if possible:
|
Will try to group events if possible:
|
||||||
- if 2+ sensor updates in GROUP_BY_MINUTES, show last
|
- if 2+ sensor updates in GROUP_BY_MINUTES, show last
|
||||||
|
|
|
@ -26,8 +26,10 @@ LOGGER_LOGS = 'logs'
|
||||||
|
|
||||||
class HomeAssistantLogFilter(logging.Filter):
|
class HomeAssistantLogFilter(logging.Filter):
|
||||||
"""A log filter."""
|
"""A log filter."""
|
||||||
|
|
||||||
# pylint: disable=no-init,too-few-public-methods
|
# pylint: disable=no-init,too-few-public-methods
|
||||||
def __init__(self, logfilter):
|
def __init__(self, logfilter):
|
||||||
|
"""Initialize the filter."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.logfilter = logfilter
|
self.logfilter = logfilter
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
"""
|
"""
|
||||||
homeassistant.components.modbus
|
Support for Modbus.
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
Modbus component, using pymodbus (python3 branch).
|
|
||||||
|
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/modbus/
|
https://home-assistant.io/components/modbus/
|
||||||
|
@ -38,8 +36,7 @@ TYPE = None
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
""" Setup Modbus component. """
|
"""Setup Modbus component."""
|
||||||
|
|
||||||
# Modbus connection type
|
# Modbus connection type
|
||||||
# pylint: disable=global-statement, import-error
|
# pylint: disable=global-statement, import-error
|
||||||
global TYPE
|
global TYPE
|
||||||
|
@ -69,15 +66,14 @@ def setup(hass, config):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def stop_modbus(event):
|
def stop_modbus(event):
|
||||||
""" Stop Modbus service. """
|
"""Stop Modbus service."""
|
||||||
NETWORK.close()
|
NETWORK.close()
|
||||||
|
|
||||||
def start_modbus(event):
|
def start_modbus(event):
|
||||||
""" Start Modbus service. """
|
"""Start Modbus service."""
|
||||||
NETWORK.connect()
|
NETWORK.connect()
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus)
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus)
|
||||||
|
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_modbus)
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_modbus)
|
||||||
|
|
||||||
# Tells the bootstrapper that the component was successfully initialized
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -62,10 +62,7 @@ def setup(hass, config):
|
||||||
|
|
||||||
# Process events from a remote server that are received on a queue.
|
# Process events from a remote server that are received on a queue.
|
||||||
def _event_receiver(topic, payload, qos):
|
def _event_receiver(topic, payload, qos):
|
||||||
"""
|
"""Receive events published by and fire them on this hass instance."""
|
||||||
Receive events published by the other HA instance and fire them on
|
|
||||||
this hass instance.
|
|
||||||
"""
|
|
||||||
event = json.loads(payload)
|
event = json.loads(payload)
|
||||||
event_type = event.get('event_type')
|
event_type = event.get('event_type')
|
||||||
event_data = event.get('event_data')
|
event_data = event.get('event_data')
|
||||||
|
|
|
@ -157,6 +157,7 @@ def pf_callback_factory(map_sv_types, devices, add_devices, entity_class):
|
||||||
|
|
||||||
class GatewayWrapper(object):
|
class GatewayWrapper(object):
|
||||||
"""Gateway wrapper class."""
|
"""Gateway wrapper class."""
|
||||||
|
|
||||||
def __init__(self, gateway, version, optimistic):
|
def __init__(self, gateway, version, optimistic):
|
||||||
"""Setup class attributes on instantiation.
|
"""Setup class attributes on instantiation.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""
|
"""
|
||||||
|
Support for tracking the proximity of a device.
|
||||||
|
|
||||||
Component to monitor the proximity of devices to a particular zone and the
|
Component to monitor the proximity of devices to a particular zone and the
|
||||||
direction of travel.
|
direction of travel.
|
||||||
|
|
||||||
|
@ -77,11 +79,13 @@ def setup(hass, config): # pylint: disable=too-many-locals,too-many-statements
|
||||||
|
|
||||||
|
|
||||||
class Proximity(Entity): # pylint: disable=too-many-instance-attributes
|
class Proximity(Entity): # pylint: disable=too-many-instance-attributes
|
||||||
"""Represents a Proximity."""
|
"""Representation of a Proximity."""
|
||||||
|
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
def __init__(self, hass, zone_friendly_name, dist_to, dir_of_travel,
|
def __init__(self, hass, zone_friendly_name, dist_to, dir_of_travel,
|
||||||
nearest, ignored_zones, proximity_devices, tolerance,
|
nearest, ignored_zones, proximity_devices, tolerance,
|
||||||
proximity_zone):
|
proximity_zone):
|
||||||
# pylint: disable=too-many-arguments
|
"""Initialize the proximity."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.friendly_name = zone_friendly_name
|
self.friendly_name = zone_friendly_name
|
||||||
self.dist_to = dist_to
|
self.dist_to = dist_to
|
||||||
|
@ -115,8 +119,8 @@ class Proximity(Entity): # pylint: disable=too-many-instance-attributes
|
||||||
ATTR_NEAREST: self.nearest,
|
ATTR_NEAREST: self.nearest,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# pylint: disable=too-many-branches,too-many-statements,too-many-locals
|
||||||
def check_proximity_state_change(self, entity, old_state, new_state):
|
def check_proximity_state_change(self, entity, old_state, new_state):
|
||||||
# pylint: disable=too-many-branches,too-many-statements,too-many-locals
|
|
||||||
"""Function to perform the proximity checking."""
|
"""Function to perform the proximity checking."""
|
||||||
entity_name = new_state.name
|
entity_name = new_state.name
|
||||||
devices_to_calculate = False
|
devices_to_calculate = False
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""
|
"""
|
||||||
|
Support for recording details.
|
||||||
|
|
||||||
Component that records all events and state changes. Allows other components
|
Component that records all events and state changes. Allows other components
|
||||||
to query this database.
|
to query this database.
|
||||||
|
|
||||||
|
@ -80,8 +82,9 @@ def row_to_event(row):
|
||||||
|
|
||||||
|
|
||||||
def run_information(point_in_time=None):
|
def run_information(point_in_time=None):
|
||||||
"""
|
"""Return information about current run.
|
||||||
Returns information about current run or the run that covers point_in_time.
|
|
||||||
|
There is also the run that covers point_in_time.
|
||||||
"""
|
"""
|
||||||
_verify_instance()
|
_verify_instance()
|
||||||
|
|
||||||
|
@ -106,8 +109,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class RecorderRun(object):
|
class RecorderRun(object):
|
||||||
"""Represents a recorder run."""
|
"""Representation of arecorder run."""
|
||||||
|
|
||||||
def __init__(self, row=None):
|
def __init__(self, row=None):
|
||||||
|
"""Initialize the recorder run."""
|
||||||
self.end = None
|
self.end = None
|
||||||
|
|
||||||
if row is None:
|
if row is None:
|
||||||
|
@ -122,8 +127,8 @@ class RecorderRun(object):
|
||||||
self.closed_incorrect = bool(row[3])
|
self.closed_incorrect = bool(row[3])
|
||||||
|
|
||||||
def entity_ids(self, point_in_time=None):
|
def entity_ids(self, point_in_time=None):
|
||||||
"""
|
"""Return the entity ids that existed in this run.
|
||||||
Return the entity ids that existed in this run.
|
|
||||||
Specify point_in_time if you want to know which existed at that point
|
Specify point_in_time if you want to know which existed at that point
|
||||||
in time inside the run.
|
in time inside the run.
|
||||||
"""
|
"""
|
||||||
|
@ -140,15 +145,18 @@ class RecorderRun(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def where_after_start_run(self):
|
def where_after_start_run(self):
|
||||||
"""
|
"""Return SQL WHERE clause.
|
||||||
Returns SQL WHERE clause to select rows created after the start of the
|
|
||||||
run.
|
Selection of the rows created after the start of the run.
|
||||||
"""
|
"""
|
||||||
return "created >= {} ".format(_adapt_datetime(self.start))
|
return "created >= {} ".format(_adapt_datetime(self.start))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def where_limit_to_run(self):
|
def where_limit_to_run(self):
|
||||||
""" Return a SQL WHERE clause to limit results to this run. """
|
"""Return a SQL WHERE clause.
|
||||||
|
|
||||||
|
For limiting the results to this run.
|
||||||
|
"""
|
||||||
where = self.where_after_start_run
|
where = self.where_after_start_run
|
||||||
|
|
||||||
if self.end is not None:
|
if self.end is not None:
|
||||||
|
@ -159,7 +167,9 @@ class RecorderRun(object):
|
||||||
|
|
||||||
class Recorder(threading.Thread):
|
class Recorder(threading.Thread):
|
||||||
"""A threaded recorder class."""
|
"""A threaded recorder class."""
|
||||||
|
|
||||||
def __init__(self, hass):
|
def __init__(self, hass):
|
||||||
|
"""Initialize the recorder."""
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
|
@ -206,14 +216,11 @@ class Recorder(threading.Thread):
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
|
||||||
def event_listener(self, event):
|
def event_listener(self, event):
|
||||||
"""
|
"""Listen for new events and put them in the process queue."""
|
||||||
Listens for new events on the EventBus and puts them in the process
|
|
||||||
queue.
|
|
||||||
"""
|
|
||||||
self.queue.put(event)
|
self.queue.put(event)
|
||||||
|
|
||||||
def shutdown(self, event):
|
def shutdown(self, event):
|
||||||
"""Tells the recorder to shut down."""
|
"""Tell the recorder to shut down."""
|
||||||
self.queue.put(self.quit_object)
|
self.queue.put(self.quit_object)
|
||||||
self.block_till_done()
|
self.block_till_done()
|
||||||
|
|
||||||
|
@ -262,7 +269,7 @@ class Recorder(threading.Thread):
|
||||||
") VALUES (?, ?, ?, ?, ?, ?)", info, RETURN_LASTROWID)
|
") VALUES (?, ?, ?, ?, ?, ?)", info, RETURN_LASTROWID)
|
||||||
|
|
||||||
def query(self, sql_query, data=None, return_value=None):
|
def query(self, sql_query, data=None, return_value=None):
|
||||||
""" Query the database. """
|
"""Query the database."""
|
||||||
try:
|
try:
|
||||||
with self.conn, self.lock:
|
with self.conn, self.lock:
|
||||||
_LOGGER.debug("Running query %s", sql_query)
|
_LOGGER.debug("Running query %s", sql_query)
|
||||||
|
@ -290,7 +297,7 @@ class Recorder(threading.Thread):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def block_till_done(self):
|
def block_till_done(self):
|
||||||
"""Blocks till all events processed."""
|
"""Block till all events processed."""
|
||||||
self.queue.join()
|
self.queue.join()
|
||||||
|
|
||||||
def _setup_connection(self):
|
def _setup_connection(self):
|
||||||
|
@ -474,6 +481,6 @@ def _adapt_datetime(datetimestamp):
|
||||||
|
|
||||||
|
|
||||||
def _verify_instance():
|
def _verify_instance():
|
||||||
"""Throws error if recorder not initialized."""
|
"""Throw error if recorder not initialized."""
|
||||||
if _INSTANCE is None:
|
if _INSTANCE is None:
|
||||||
raise RuntimeError("Recorder not initialized.")
|
raise RuntimeError("Recorder not initialized.")
|
||||||
|
|
|
@ -59,7 +59,7 @@ def read_input(port):
|
||||||
|
|
||||||
|
|
||||||
def edge_detect(port, event_callback, bounce):
|
def edge_detect(port, event_callback, bounce):
|
||||||
"""Adds detection for RISING and FALLING events."""
|
"""Add detection for RISING and FALLING events."""
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
GPIO.add_event_detect(
|
GPIO.add_event_detect(
|
||||||
port,
|
port,
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""
|
"""
|
||||||
|
Support for scripts.
|
||||||
|
|
||||||
Scripts are a sequence of actions that can be triggered manually
|
Scripts are a sequence of actions that can be triggered manually
|
||||||
by the user or automatically based upon automation events, etc.
|
by the user or automatically based upon automation events, etc.
|
||||||
|
|
||||||
|
@ -43,7 +45,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def is_on(hass, entity_id):
|
def is_on(hass, entity_id):
|
||||||
"""Returns if the switch is on based on the statemachine."""
|
"""Return if the switch is on based on the statemachine."""
|
||||||
return hass.states.is_state(entity_id, STATE_ON)
|
return hass.states.is_state(entity_id, STATE_ON)
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ def turn_off(hass, entity_id):
|
||||||
|
|
||||||
|
|
||||||
def toggle(hass, entity_id):
|
def toggle(hass, entity_id):
|
||||||
"""Toggles script."""
|
"""Toggle the script."""
|
||||||
hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id})
|
hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id})
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +71,7 @@ def setup(hass, config):
|
||||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||||
|
|
||||||
def service_handler(service):
|
def service_handler(service):
|
||||||
""" Execute a service call to script.<script name>. """
|
"""Execute a service call to script.<script name>."""
|
||||||
entity_id = ENTITY_ID_FORMAT.format(service.service)
|
entity_id = ENTITY_ID_FORMAT.format(service.service)
|
||||||
script = component.entities.get(entity_id)
|
script = component.entities.get(entity_id)
|
||||||
if not script:
|
if not script:
|
||||||
|
@ -94,19 +96,19 @@ def setup(hass, config):
|
||||||
hass.services.register(DOMAIN, object_id, service_handler)
|
hass.services.register(DOMAIN, object_id, service_handler)
|
||||||
|
|
||||||
def turn_on_service(service):
|
def turn_on_service(service):
|
||||||
"""Calls a service to turn script on."""
|
"""Call a service to turn script on."""
|
||||||
# We could turn on script directly here, but we only want to offer
|
# We could turn on script directly here, but we only want to offer
|
||||||
# one way to do it. Otherwise no easy way to call invocations.
|
# one way to do it. Otherwise no easy way to call invocations.
|
||||||
for script in component.extract_from_service(service):
|
for script in component.extract_from_service(service):
|
||||||
turn_on(hass, script.entity_id)
|
turn_on(hass, script.entity_id)
|
||||||
|
|
||||||
def turn_off_service(service):
|
def turn_off_service(service):
|
||||||
"""Cancels a script."""
|
"""Cancel a script."""
|
||||||
for script in component.extract_from_service(service):
|
for script in component.extract_from_service(service):
|
||||||
script.turn_off()
|
script.turn_off()
|
||||||
|
|
||||||
def toggle_service(service):
|
def toggle_service(service):
|
||||||
"""Toggles a script."""
|
"""Toggle a script."""
|
||||||
for script in component.extract_from_service(service):
|
for script in component.extract_from_service(service):
|
||||||
script.toggle()
|
script.toggle()
|
||||||
|
|
||||||
|
@ -118,9 +120,11 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class Script(ToggleEntity):
|
class Script(ToggleEntity):
|
||||||
"""Represents a script."""
|
"""Representation of a script."""
|
||||||
|
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
def __init__(self, object_id, name, sequence):
|
def __init__(self, object_id, name, sequence):
|
||||||
|
"""Initialize the script."""
|
||||||
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
||||||
self._name = name
|
self._name = name
|
||||||
self.sequence = sequence
|
self.sequence = sequence
|
||||||
|
@ -153,7 +157,7 @@ class Script(ToggleEntity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""True if entity is on."""
|
"""Return true if script is on."""
|
||||||
return self._cur != -1
|
return self._cur != -1
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
|
@ -179,7 +183,7 @@ class Script(ToggleEntity):
|
||||||
elif CONF_DELAY in action:
|
elif CONF_DELAY in action:
|
||||||
# Call ourselves in the future to continue work
|
# Call ourselves in the future to continue work
|
||||||
def script_delay(now):
|
def script_delay(now):
|
||||||
""" Called after delay is done. """
|
"""Called after delay is done."""
|
||||||
self._listener = None
|
self._listener = None
|
||||||
self.turn_on()
|
self.turn_on()
|
||||||
|
|
||||||
|
@ -206,7 +210,7 @@ class Script(ToggleEntity):
|
||||||
self._remove_listener()
|
self._remove_listener()
|
||||||
|
|
||||||
def _call_service(self, action):
|
def _call_service(self, action):
|
||||||
"""Calls the service specified in the action."""
|
"""Call the service specified in the action."""
|
||||||
# Backwards compatibility
|
# Backwards compatibility
|
||||||
if CONF_SERVICE not in action and CONF_SERVICE_OLD in action:
|
if CONF_SERVICE not in action and CONF_SERVICE_OLD in action:
|
||||||
action[CONF_SERVICE] = action[CONF_SERVICE_OLD]
|
action[CONF_SERVICE] = action[CONF_SERVICE_OLD]
|
||||||
|
@ -220,7 +224,7 @@ class Script(ToggleEntity):
|
||||||
call_from_config(self.hass, action, True)
|
call_from_config(self.hass, action, True)
|
||||||
|
|
||||||
def _fire_event(self, action):
|
def _fire_event(self, action):
|
||||||
"""Fires an event."""
|
"""Fire an event."""
|
||||||
self._last_action = action.get(CONF_ALIAS, action[CONF_EVENT])
|
self._last_action = action.get(CONF_ALIAS, action[CONF_EVENT])
|
||||||
_LOGGER.info("Executing script %s step %s", self._name,
|
_LOGGER.info("Executing script %s step %s", self._name,
|
||||||
self._last_action)
|
self._last_action)
|
||||||
|
|
|
@ -16,8 +16,10 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SCSGate:
|
class SCSGate:
|
||||||
"""Class dealing with the SCSGate device via scsgate.Reactor."""
|
"""The class for dealing with the SCSGate device via scsgate.Reactor."""
|
||||||
|
|
||||||
def __init__(self, device, logger):
|
def __init__(self, device, logger):
|
||||||
|
"""Initialize the SCSGate."""
|
||||||
self._logger = logger
|
self._logger = logger
|
||||||
self._devices = {}
|
self._devices = {}
|
||||||
self._devices_to_register = {}
|
self._devices_to_register = {}
|
||||||
|
@ -69,16 +71,16 @@ class SCSGate:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def devices(self):
|
def devices(self):
|
||||||
"""
|
"""Dictionary with known devices.
|
||||||
Dictionary with known devices. Key is device ID, value is the device
|
|
||||||
itself.
|
Key is device ID, value is the device itself.
|
||||||
"""
|
"""
|
||||||
return self._devices
|
return self._devices
|
||||||
|
|
||||||
def add_device(self, device):
|
def add_device(self, device):
|
||||||
"""
|
"""Add the specified device.
|
||||||
Adds the specified device to the list of the already registered ones.
|
|
||||||
|
|
||||||
|
The list contain already registered ones.
|
||||||
Beware: this is not what you usually want to do, take a look at
|
Beware: this is not what you usually want to do, take a look at
|
||||||
`add_devices_to_register`
|
`add_devices_to_register`
|
||||||
"""
|
"""
|
||||||
|
@ -92,7 +94,7 @@ class SCSGate:
|
||||||
self._activate_next_device()
|
self._activate_next_device()
|
||||||
|
|
||||||
def _activate_next_device(self):
|
def _activate_next_device(self):
|
||||||
"""Starts the activation of the first device."""
|
"""Start the activation of the first device."""
|
||||||
from scsgate.tasks import GetStatusTask
|
from scsgate.tasks import GetStatusTask
|
||||||
|
|
||||||
with self._devices_to_register_lock:
|
with self._devices_to_register_lock:
|
||||||
|
@ -104,7 +106,7 @@ class SCSGate:
|
||||||
self._reactor.append_task(GetStatusTask(target=device.scs_id))
|
self._reactor.append_task(GetStatusTask(target=device.scs_id))
|
||||||
|
|
||||||
def is_device_registered(self, device_id):
|
def is_device_registered(self, device_id):
|
||||||
"""Checks whether a device is already registered or not."""
|
"""Check whether a device is already registered or not."""
|
||||||
with self._devices_to_register_lock:
|
with self._devices_to_register_lock:
|
||||||
if device_id in self._devices_to_register.keys():
|
if device_id in self._devices_to_register.keys():
|
||||||
return False
|
return False
|
||||||
|
@ -124,7 +126,7 @@ class SCSGate:
|
||||||
self._reactor.stop()
|
self._reactor.stop()
|
||||||
|
|
||||||
def append_task(self, task):
|
def append_task(self, task):
|
||||||
"""Registers a new task to be executed."""
|
"""Register a new task to be executed."""
|
||||||
self._reactor.append_task(task)
|
self._reactor.append_task(task)
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,10 +144,7 @@ def setup(hass, config):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def stop_monitor(event):
|
def stop_monitor(event):
|
||||||
"""
|
"""Stop the SCSGate."""
|
||||||
Invoked when home-assistant is exiting. Performs the necessary
|
|
||||||
cleanups.
|
|
||||||
"""
|
|
||||||
_LOGGER.info("Stopping SCSGate monitor thread")
|
_LOGGER.info("Stopping SCSGate monitor thread")
|
||||||
SCSGATE.stop()
|
SCSGATE.stop()
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Sets up the shell_command component."""
|
"""Setup the shell_command component."""
|
||||||
conf = config.get(DOMAIN)
|
conf = config.get(DOMAIN)
|
||||||
|
|
||||||
if not isinstance(conf, dict):
|
if not isinstance(conf, dict):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
A component which allows you to send data to an Splunk instance utilizing the
|
Support to send data to an Splunk instance.
|
||||||
HTTP Event Collector.
|
|
||||||
|
Uses the HTTP Event Collector.
|
||||||
|
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/splunk/
|
https://home-assistant.io/components/splunk/
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Provides functionality to keep track of the sun.
|
Support for functionality to keep track of the sun.
|
||||||
|
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/sun/
|
https://home-assistant.io/components/sun/
|
||||||
|
@ -123,11 +123,12 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class Sun(Entity):
|
class Sun(Entity):
|
||||||
"""Represents the Sun."""
|
"""Representation of the Sun."""
|
||||||
|
|
||||||
entity_id = ENTITY_ID
|
entity_id = ENTITY_ID
|
||||||
|
|
||||||
def __init__(self, hass, location):
|
def __init__(self, hass, location):
|
||||||
|
"""Initialize the Sun."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.location = location
|
self.location = location
|
||||||
self._state = self.next_rising = self.next_setting = None
|
self._state = self.next_rising = self.next_setting = None
|
||||||
|
@ -135,10 +136,12 @@ class Sun(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
"""Return the name."""
|
||||||
return "Sun"
|
return "Sun"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
|
"""Return the state of the sun."""
|
||||||
if self.next_rising > self.next_setting:
|
if self.next_rising > self.next_setting:
|
||||||
return STATE_ABOVE_HORIZON
|
return STATE_ABOVE_HORIZON
|
||||||
|
|
||||||
|
@ -146,6 +149,7 @@ class Sun(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
|
"""Return the state attributes of the sun."""
|
||||||
return {
|
return {
|
||||||
STATE_ATTR_NEXT_RISING:
|
STATE_ATTR_NEXT_RISING:
|
||||||
dt_util.datetime_to_str(self.next_rising),
|
dt_util.datetime_to_str(self.next_rising),
|
||||||
|
@ -169,7 +173,7 @@ class Sun(Entity):
|
||||||
self.location.longitude)
|
self.location.longitude)
|
||||||
|
|
||||||
def update_as_of(self, utc_point_in_time):
|
def update_as_of(self, utc_point_in_time):
|
||||||
""" Calculate sun state at a point in UTC time. """
|
"""Calculate sun state at a point in UTC time."""
|
||||||
mod = -1
|
mod = -1
|
||||||
while True:
|
while True:
|
||||||
next_rising_dt = self.location.sunrise(
|
next_rising_dt = self.location.sunrise(
|
||||||
|
@ -190,7 +194,7 @@ class Sun(Entity):
|
||||||
self.next_setting = next_setting_dt
|
self.next_setting = next_setting_dt
|
||||||
|
|
||||||
def point_in_time_listener(self, now):
|
def point_in_time_listener(self, now):
|
||||||
""" Called when the state of the sun has changed. """
|
"""Called when the state of the sun has changed."""
|
||||||
self.update_as_of(now)
|
self.update_as_of(now)
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
|
||||||
|
@ -200,5 +204,5 @@ class Sun(Entity):
|
||||||
self.next_change + timedelta(seconds=1))
|
self.next_change + timedelta(seconds=1))
|
||||||
|
|
||||||
def timer_update(self, time):
|
def timer_update(self, time):
|
||||||
""" Needed to update solar elevation. """
|
"""Needed to update solar elevation."""
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
|
|
@ -61,8 +61,10 @@ def request_sensors():
|
||||||
|
|
||||||
|
|
||||||
class TelldusLiveData(object):
|
class TelldusLiveData(object):
|
||||||
"""Gets the latest data and update the states."""
|
"""Get the latest data and update the states."""
|
||||||
|
|
||||||
def __init__(self, hass, config):
|
def __init__(self, hass, config):
|
||||||
|
"""Initialize the Tellus data object."""
|
||||||
public_key = config[DOMAIN].get(CONF_PUBLIC_KEY)
|
public_key = config[DOMAIN].get(CONF_PUBLIC_KEY)
|
||||||
private_key = config[DOMAIN].get(CONF_PRIVATE_KEY)
|
private_key = config[DOMAIN].get(CONF_PRIVATE_KEY)
|
||||||
token = config[DOMAIN].get(CONF_TOKEN)
|
token = config[DOMAIN].get(CONF_TOKEN)
|
||||||
|
@ -111,7 +113,7 @@ class TelldusLiveData(object):
|
||||||
ATTR_DISCOVERED: found_devices})
|
ATTR_DISCOVERED: found_devices})
|
||||||
|
|
||||||
def request(self, what, **params):
|
def request(self, what, **params):
|
||||||
"""Sends a request to the Tellstick Live API."""
|
"""Send a request to the Tellstick Live API."""
|
||||||
from tellive.live import const
|
from tellive.live import const
|
||||||
|
|
||||||
supported_methods = const.TELLSTICK_TURNON \
|
supported_methods = const.TELLSTICK_TURNON \
|
||||||
|
|
|
@ -58,8 +58,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
class VerisureHub(object):
|
class VerisureHub(object):
|
||||||
"""A Verisure wrapper class."""
|
"""A Verisure hub wrapper class."""
|
||||||
|
|
||||||
def __init__(self, domain_config, verisure):
|
def __init__(self, domain_config, verisure):
|
||||||
|
"""Initialize the Verisure hub."""
|
||||||
self.alarm_status = {}
|
self.alarm_status = {}
|
||||||
self.lock_status = {}
|
self.lock_status = {}
|
||||||
self.climate_status = {}
|
self.climate_status = {}
|
||||||
|
@ -93,41 +95,41 @@ class VerisureHub(object):
|
||||||
|
|
||||||
@Throttle(timedelta(seconds=1))
|
@Throttle(timedelta(seconds=1))
|
||||||
def update_alarms(self):
|
def update_alarms(self):
|
||||||
"""Updates the status of the alarm."""
|
"""Update the status of the alarm."""
|
||||||
self.update_component(
|
self.update_component(
|
||||||
self.my_pages.alarm.get,
|
self.my_pages.alarm.get,
|
||||||
self.alarm_status)
|
self.alarm_status)
|
||||||
|
|
||||||
@Throttle(timedelta(seconds=1))
|
@Throttle(timedelta(seconds=1))
|
||||||
def update_locks(self):
|
def update_locks(self):
|
||||||
"""Updates the status of the locks."""
|
"""Update the status of the locks."""
|
||||||
self.update_component(
|
self.update_component(
|
||||||
self.my_pages.lock.get,
|
self.my_pages.lock.get,
|
||||||
self.lock_status)
|
self.lock_status)
|
||||||
|
|
||||||
@Throttle(timedelta(seconds=60))
|
@Throttle(timedelta(seconds=60))
|
||||||
def update_climate(self):
|
def update_climate(self):
|
||||||
"""Updates the status of the climate units."""
|
"""Update the status of the climate units."""
|
||||||
self.update_component(
|
self.update_component(
|
||||||
self.my_pages.climate.get,
|
self.my_pages.climate.get,
|
||||||
self.climate_status)
|
self.climate_status)
|
||||||
|
|
||||||
@Throttle(timedelta(seconds=60))
|
@Throttle(timedelta(seconds=60))
|
||||||
def update_mousedetection(self):
|
def update_mousedetection(self):
|
||||||
"""Updates the status of the mouse detectors."""
|
"""Update the status of the mouse detectors."""
|
||||||
self.update_component(
|
self.update_component(
|
||||||
self.my_pages.mousedetection.get,
|
self.my_pages.mousedetection.get,
|
||||||
self.mouse_status)
|
self.mouse_status)
|
||||||
|
|
||||||
@Throttle(timedelta(seconds=1))
|
@Throttle(timedelta(seconds=1))
|
||||||
def update_smartplugs(self):
|
def update_smartplugs(self):
|
||||||
"""Updates the status of the smartplugs."""
|
"""Update the status of the smartplugs."""
|
||||||
self.update_component(
|
self.update_component(
|
||||||
self.my_pages.smartplug.get,
|
self.my_pages.smartplug.get,
|
||||||
self.smartplug_status)
|
self.smartplug_status)
|
||||||
|
|
||||||
def update_component(self, get_function, status):
|
def update_component(self, get_function, status):
|
||||||
"""Updates the status of Verisure components."""
|
"""Update the status of Verisure components."""
|
||||||
if self._wrong_password_given:
|
if self._wrong_password_given:
|
||||||
_LOGGER.error('Wrong password for Verisure, update config')
|
_LOGGER.error('Wrong password for Verisure, update config')
|
||||||
return
|
return
|
||||||
|
|
|
@ -35,8 +35,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class Link(Entity):
|
class Link(Entity):
|
||||||
"""Represent a link."""
|
"""Representation of a link."""
|
||||||
|
|
||||||
def __init__(self, hass, name, url, icon):
|
def __init__(self, hass, name, url, icon):
|
||||||
|
"""Initialize the link."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._name = name
|
self._name = name
|
||||||
self._url = url
|
self._url = url
|
||||||
|
|
|
@ -64,7 +64,9 @@ def setup(hass, config):
|
||||||
|
|
||||||
class WinkToggleDevice(ToggleEntity):
|
class WinkToggleDevice(ToggleEntity):
|
||||||
"""Represents a Wink toggle (switch) device."""
|
"""Represents a Wink toggle (switch) device."""
|
||||||
|
|
||||||
def __init__(self, wink):
|
def __init__(self, wink):
|
||||||
|
"""Initialize the Wink device."""
|
||||||
self.wink = wink
|
self.wink = wink
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -79,15 +81,15 @@ class WinkToggleDevice(ToggleEntity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""True if decive is on."""
|
"""Return true if device is on."""
|
||||||
return self.wink.state()
|
return self.wink.state()
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
"""Turns the device on."""
|
"""Turn the device on."""
|
||||||
self.wink.set_state(True)
|
self.wink.set_state(True)
|
||||||
|
|
||||||
def turn_off(self):
|
def turn_off(self):
|
||||||
"""Turns the device off."""
|
"""Turn the device off."""
|
||||||
self.wink.set_state(False)
|
self.wink.set_state(False)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
|
|
@ -34,10 +34,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""
|
"""Setup the connection to the ZigBee device."""
|
||||||
Set up the connection to the ZigBee device and instantiate the helper
|
|
||||||
class for it.
|
|
||||||
"""
|
|
||||||
global DEVICE
|
global DEVICE
|
||||||
global GPIO_DIGITAL_OUTPUT_LOW
|
global GPIO_DIGITAL_OUTPUT_LOW
|
||||||
global GPIO_DIGITAL_OUTPUT_HIGH
|
global GPIO_DIGITAL_OUTPUT_HIGH
|
||||||
|
@ -69,27 +66,27 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
def close_serial_port(*args):
|
def close_serial_port(*args):
|
||||||
""" Close the serial port we're using to communicate with the ZigBee. """
|
"""Close the serial port we're using to communicate with the ZigBee."""
|
||||||
DEVICE.zb.serial.close()
|
DEVICE.zb.serial.close()
|
||||||
|
|
||||||
|
|
||||||
class ZigBeeConfig(object):
|
class ZigBeeConfig(object):
|
||||||
"""
|
"""Handle the fetching of configuration from the config file."""
|
||||||
Handles the fetching of configuration from the config file for any ZigBee
|
|
||||||
entity.
|
|
||||||
"""
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
|
"""Initialize the configuration."""
|
||||||
self._config = config
|
self._config = config
|
||||||
self._should_poll = config.get("poll", True)
|
self._should_poll = config.get("poll", True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
""" The name given to the entity. """
|
"""The name given to the entity."""
|
||||||
return self._config["name"]
|
return self._config["name"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def address(self):
|
def address(self):
|
||||||
"""
|
"""The address of the device.
|
||||||
|
|
||||||
If an address has been provided, unhexlify it, otherwise return None
|
If an address has been provided, unhexlify it, otherwise return None
|
||||||
as we're talking to our local ZigBee device.
|
as we're talking to our local ZigBee device.
|
||||||
"""
|
"""
|
||||||
|
@ -100,38 +97,33 @@ class ZigBeeConfig(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
"""
|
"""No polling needed."""
|
||||||
A bool depicting whether HA should repeatedly poll this device for its
|
|
||||||
value.
|
|
||||||
"""
|
|
||||||
return self._should_poll
|
return self._should_poll
|
||||||
|
|
||||||
|
|
||||||
class ZigBeePinConfig(ZigBeeConfig):
|
class ZigBeePinConfig(ZigBeeConfig):
|
||||||
"""
|
"""Handle the fetching of configuration from the config file."""
|
||||||
Handles the fetching of configuration from the config file for a ZigBee
|
|
||||||
GPIO pin.
|
|
||||||
"""
|
|
||||||
@property
|
@property
|
||||||
def pin(self):
|
def pin(self):
|
||||||
""" The GPIO pin number. """
|
"""The GPIO pin number."""
|
||||||
return self._config["pin"]
|
return self._config["pin"]
|
||||||
|
|
||||||
|
|
||||||
class ZigBeeDigitalPinConfig(ZigBeePinConfig):
|
class ZigBeeDigitalPinConfig(ZigBeePinConfig):
|
||||||
"""
|
"""Handle the fetching of configuration from the config file."""
|
||||||
Handles the fetching of configuration from the config file for a ZigBee
|
|
||||||
GPIO pin set to digital in or out.
|
|
||||||
"""
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
|
"""Initialize the configuration."""
|
||||||
super(ZigBeeDigitalPinConfig, self).__init__(config)
|
super(ZigBeeDigitalPinConfig, self).__init__(config)
|
||||||
self._bool2state, self._state2bool = self.boolean_maps
|
self._bool2state, self._state2bool = self.boolean_maps
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def boolean_maps(self):
|
def boolean_maps(self):
|
||||||
"""
|
"""Create dicts to map booleans to pin high/low and vice versa.
|
||||||
Create dicts to map booleans to pin high/low and vice versa. Depends on
|
|
||||||
the config item "on_state" which should be set to "low" or "high".
|
Depends on the config item "on_state" which should be set to "low"
|
||||||
|
or "high".
|
||||||
"""
|
"""
|
||||||
if self._config.get("on_state", "").lower() == "low":
|
if self._config.get("on_state", "").lower() == "low":
|
||||||
bool2state = {
|
bool2state = {
|
||||||
|
@ -148,17 +140,17 @@ class ZigBeeDigitalPinConfig(ZigBeePinConfig):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bool2state(self):
|
def bool2state(self):
|
||||||
"""
|
"""A dictionary mapping booleans to GPIOSetting objects.
|
||||||
A dictionary mapping booleans to GPIOSetting objects to translate
|
|
||||||
on/off as being pin high or low.
|
For the translation of on/off as being pin high or low.
|
||||||
"""
|
"""
|
||||||
return self._bool2state
|
return self._bool2state
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state2bool(self):
|
def state2bool(self):
|
||||||
"""
|
"""A dictionary mapping GPIOSetting objects to booleans.
|
||||||
A dictionary mapping GPIOSetting objects to booleans to translate
|
|
||||||
pin high/low as being on or off.
|
For the translation of pin high/low as being on or off.
|
||||||
"""
|
"""
|
||||||
return self._state2bool
|
return self._state2bool
|
||||||
|
|
||||||
|
@ -167,30 +159,32 @@ ZigBeeDigitalInConfig = ZigBeeDigitalPinConfig
|
||||||
|
|
||||||
|
|
||||||
class ZigBeeDigitalOutConfig(ZigBeeDigitalPinConfig):
|
class ZigBeeDigitalOutConfig(ZigBeeDigitalPinConfig):
|
||||||
|
"""A subclass of ZigBeeDigitalPinConfig.
|
||||||
|
|
||||||
|
Set _should_poll to default as False instead of True. The value will
|
||||||
|
still be overridden by the presence of a 'poll' config entry.
|
||||||
"""
|
"""
|
||||||
A subclass of ZigBeeDigitalPinConfig which sets _should_poll to default as
|
|
||||||
False instead of True. The value will still be overridden by the presence
|
|
||||||
of a 'poll' config entry.
|
|
||||||
"""
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
|
"""Initialize the ZigBee Digital out."""
|
||||||
super(ZigBeeDigitalOutConfig, self).__init__(config)
|
super(ZigBeeDigitalOutConfig, self).__init__(config)
|
||||||
self._should_poll = config.get("poll", False)
|
self._should_poll = config.get("poll", False)
|
||||||
|
|
||||||
|
|
||||||
class ZigBeeAnalogInConfig(ZigBeePinConfig):
|
class ZigBeeAnalogInConfig(ZigBeePinConfig):
|
||||||
"""
|
"""Representation of a ZigBee GPIO pin set to analog in."""
|
||||||
Handles the fetching of configuration from the config file for a ZigBee
|
|
||||||
GPIO pin set to analog in.
|
|
||||||
"""
|
|
||||||
@property
|
@property
|
||||||
def max_voltage(self):
|
def max_voltage(self):
|
||||||
""" The voltage at which the ADC will report its highest value. """
|
"""The voltage at which the ADC will report its highest value."""
|
||||||
return float(self._config.get("max_volts", DEFAULT_ADC_MAX_VOLTS))
|
return float(self._config.get("max_volts", DEFAULT_ADC_MAX_VOLTS))
|
||||||
|
|
||||||
|
|
||||||
class ZigBeeDigitalIn(Entity):
|
class ZigBeeDigitalIn(Entity):
|
||||||
""" Represents a GPIO pin configured as a digital input. """
|
"""Representation of a GPIO pin configured as a digital input."""
|
||||||
|
|
||||||
def __init__(self, hass, config):
|
def __init__(self, hass, config):
|
||||||
|
"""Initialize the device."""
|
||||||
self._config = config
|
self._config = config
|
||||||
self._state = False
|
self._state = False
|
||||||
# Get initial state
|
# Get initial state
|
||||||
|
@ -199,21 +193,21 @@ class ZigBeeDigitalIn(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
""" The name of the input. """
|
"""Return the name of the input."""
|
||||||
return self._config.name
|
return self._config.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
""" State of the polling, if needed. """
|
"""Return the state of the polling, if needed."""
|
||||||
return self._config.should_poll
|
return self._config.should_poll
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
""" Returns True if the Entity is on, else False. """
|
"""Return True if the Entity is on, else False."""
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
""" Ask the ZigBee device what its output is set to. """
|
"""Ask the ZigBee device what its output is set to."""
|
||||||
try:
|
try:
|
||||||
pin_state = DEVICE.get_gpio_pin(
|
pin_state = DEVICE.get_gpio_pin(
|
||||||
self._config.pin,
|
self._config.pin,
|
||||||
|
@ -231,8 +225,10 @@ class ZigBeeDigitalIn(Entity):
|
||||||
|
|
||||||
|
|
||||||
class ZigBeeDigitalOut(ZigBeeDigitalIn):
|
class ZigBeeDigitalOut(ZigBeeDigitalIn):
|
||||||
""" Adds functionality to ZigBeeDigitalIn to control an output. """
|
"""Representation of a GPIO pin configured as a digital input."""
|
||||||
|
|
||||||
def _set_state(self, state):
|
def _set_state(self, state):
|
||||||
|
"""Initialize the ZigBee digital out device."""
|
||||||
try:
|
try:
|
||||||
DEVICE.set_gpio_pin(
|
DEVICE.set_gpio_pin(
|
||||||
self._config.pin,
|
self._config.pin,
|
||||||
|
@ -252,17 +248,19 @@ class ZigBeeDigitalOut(ZigBeeDigitalIn):
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
""" Set the digital output to its 'on' state. """
|
"""Set the digital output to its 'on' state."""
|
||||||
self._set_state(True)
|
self._set_state(True)
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs):
|
||||||
""" Set the digital output to its 'off' state. """
|
"""Set the digital output to its 'off' state."""
|
||||||
self._set_state(False)
|
self._set_state(False)
|
||||||
|
|
||||||
|
|
||||||
class ZigBeeAnalogIn(Entity):
|
class ZigBeeAnalogIn(Entity):
|
||||||
""" Represents a GPIO pin configured as an analog input. """
|
"""Representation of a GPIO pin configured as an analog input."""
|
||||||
|
|
||||||
def __init__(self, hass, config):
|
def __init__(self, hass, config):
|
||||||
|
"""Initialize the ZigBee analog in device."""
|
||||||
self._config = config
|
self._config = config
|
||||||
self._value = None
|
self._value = None
|
||||||
# Get initial state
|
# Get initial state
|
||||||
|
@ -271,26 +269,26 @@ class ZigBeeAnalogIn(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
""" The name of the input. """
|
"""The name of the input."""
|
||||||
return self._config.name
|
return self._config.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
""" State of the polling, if needed. """
|
"""The state of the polling, if needed."""
|
||||||
return self._config.should_poll
|
return self._config.should_poll
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
""" Returns the state of the entity. """
|
"""Return the state of the entity."""
|
||||||
return self._value
|
return self._value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
""" Unit this state is expressed in. """
|
"""Return the unit this state is expressed in."""
|
||||||
return "%"
|
return "%"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
""" Get the latest reading from the ADC. """
|
"""Get the latest reading from the ADC."""
|
||||||
try:
|
try:
|
||||||
self._value = DEVICE.read_analog_pin(
|
self._value = DEVICE.read_analog_pin(
|
||||||
self._config.pin,
|
self._config.pin,
|
||||||
|
|
|
@ -106,9 +106,11 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class Zone(Entity):
|
class Zone(Entity):
|
||||||
"""Represents a Zone."""
|
"""Representation of a Zone."""
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments, too-many-instance-attributes
|
# pylint: disable=too-many-arguments, too-many-instance-attributes
|
||||||
def __init__(self, hass, name, latitude, longitude, radius, icon, passive):
|
def __init__(self, hass, name, latitude, longitude, radius, icon, passive):
|
||||||
|
"""Initialize the zone."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._name = name
|
self._name = name
|
||||||
self._latitude = latitude
|
self._latitude = latitude
|
||||||
|
@ -119,7 +121,7 @@ class Zone(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
""" Return the name of the zone."""
|
"""Return the name of the zone."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -134,7 +136,7 @@ class Zone(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
""" Return the state attributes of the zone."""
|
"""Return the state attributes of the zone."""
|
||||||
data = {
|
data = {
|
||||||
ATTR_HIDDEN: True,
|
ATTR_HIDDEN: True,
|
||||||
ATTR_LATITUDE: self._latitude,
|
ATTR_LATITUDE: self._latitude,
|
||||||
|
|
|
@ -91,25 +91,26 @@ NETWORK = None
|
||||||
|
|
||||||
|
|
||||||
def _obj_to_dict(obj):
|
def _obj_to_dict(obj):
|
||||||
"""Converts an obj into a hash for debug."""
|
"""Convert an object into a hash for debug."""
|
||||||
return {key: getattr(obj, key) for key
|
return {key: getattr(obj, key) for key
|
||||||
in dir(obj)
|
in dir(obj)
|
||||||
if key[0] != '_' and not hasattr(getattr(obj, key), '__call__')}
|
if key[0] != '_' and not hasattr(getattr(obj, key), '__call__')}
|
||||||
|
|
||||||
|
|
||||||
def _node_name(node):
|
def _node_name(node):
|
||||||
"""Returns the name of the node."""
|
"""Return the name of the node."""
|
||||||
return node.name or "{} {}".format(
|
return node.name or "{} {}".format(
|
||||||
node.manufacturer_name, node.product_name)
|
node.manufacturer_name, node.product_name)
|
||||||
|
|
||||||
|
|
||||||
def _value_name(value):
|
def _value_name(value):
|
||||||
"""Returns the name of the value."""
|
"""Return the name of the value."""
|
||||||
return "{} {}".format(_node_name(value.node), value.label)
|
return "{} {}".format(_node_name(value.node), value.label)
|
||||||
|
|
||||||
|
|
||||||
def _object_id(value):
|
def _object_id(value):
|
||||||
"""Returns the object_id of the device value.
|
"""Return the object_id of the device value.
|
||||||
|
|
||||||
The object_id contains node_id and value instance id
|
The object_id contains node_id and value instance id
|
||||||
to not collide with other entity_ids.
|
to not collide with other entity_ids.
|
||||||
"""
|
"""
|
||||||
|
@ -124,7 +125,7 @@ def _object_id(value):
|
||||||
|
|
||||||
|
|
||||||
def nice_print_node(node):
|
def nice_print_node(node):
|
||||||
"""Prints a nice formatted node to the output (debug method)."""
|
"""Print a nice formatted node to the output (debug method)."""
|
||||||
node_dict = _obj_to_dict(node)
|
node_dict = _obj_to_dict(node)
|
||||||
node_dict['values'] = {value_id: _obj_to_dict(value)
|
node_dict['values'] = {value_id: _obj_to_dict(value)
|
||||||
for value_id, value in node.values.items()}
|
for value_id, value in node.values.items()}
|
||||||
|
@ -136,7 +137,7 @@ def nice_print_node(node):
|
||||||
|
|
||||||
|
|
||||||
def get_config_value(node, value_index):
|
def get_config_value(node, value_index):
|
||||||
"""Returns the current configuration value for a specific index."""
|
"""Return the current configuration value for a specific index."""
|
||||||
try:
|
try:
|
||||||
for value in node.values.values():
|
for value in node.values.values():
|
||||||
# 112 == config command class
|
# 112 == config command class
|
||||||
|
@ -149,8 +150,8 @@ def get_config_value(node, value_index):
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""
|
"""Setup Z-Wave.
|
||||||
Setup Z-wave.
|
|
||||||
Will automatically load components to support devices found on the network.
|
Will automatically load components to support devices found on the network.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=global-statement, import-error
|
# pylint: disable=global-statement, import-error
|
||||||
|
@ -178,7 +179,7 @@ def setup(hass, config):
|
||||||
|
|
||||||
if use_debug:
|
if use_debug:
|
||||||
def log_all(signal, value=None):
|
def log_all(signal, value=None):
|
||||||
""" Log all the signals. """
|
"""Log all the signals."""
|
||||||
print("")
|
print("")
|
||||||
print("SIGNAL *****", signal)
|
print("SIGNAL *****", signal)
|
||||||
if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED,
|
if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED,
|
||||||
|
@ -249,11 +250,11 @@ def setup(hass, config):
|
||||||
NETWORK.controller.begin_command_remove_device()
|
NETWORK.controller.begin_command_remove_device()
|
||||||
|
|
||||||
def stop_zwave(event):
|
def stop_zwave(event):
|
||||||
"""Stop Z-wave."""
|
"""Stop Z-Wave."""
|
||||||
NETWORK.stop()
|
NETWORK.stop()
|
||||||
|
|
||||||
def start_zwave(event):
|
def start_zwave(event):
|
||||||
"""Startup """
|
"""Startup Z-Wave."""
|
||||||
NETWORK.start()
|
NETWORK.start()
|
||||||
|
|
||||||
polling_interval = convert(
|
polling_interval = convert(
|
||||||
|
@ -274,8 +275,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
|
|
||||||
class ZWaveDeviceEntity:
|
class ZWaveDeviceEntity:
|
||||||
"""Represents a Z-Wave node entity."""
|
"""Representation of a Z-Wave node entity."""
|
||||||
|
|
||||||
def __init__(self, value, domain):
|
def __init__(self, value, domain):
|
||||||
|
"""Initialize the z-Wave device."""
|
||||||
self._value = value
|
self._value = value
|
||||||
self.entity_id = "{}.{}".format(domain, self._object_id())
|
self.entity_id = "{}.{}".format(domain, self._object_id())
|
||||||
|
|
||||||
|
@ -286,25 +289,26 @@ class ZWaveDeviceEntity:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Returns a unique id."""
|
"""Return an unique ID."""
|
||||||
return "ZWAVE-{}-{}".format(self._value.node.node_id,
|
return "ZWAVE-{}-{}".format(self._value.node.node_id,
|
||||||
self._value.object_id)
|
self._value.object_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Returns the name of the device."""
|
"""Return the name of the device."""
|
||||||
return _value_name(self._value)
|
return _value_name(self._value)
|
||||||
|
|
||||||
def _object_id(self):
|
def _object_id(self):
|
||||||
"""
|
"""Return the object_id of the device value.
|
||||||
Returns the object_id of the device value. The object_id contains
|
|
||||||
node_id and value instance id to not collide with other entity_ids.
|
The object_id contains node_id and value instance id to not collide
|
||||||
|
with other entity_ids.
|
||||||
"""
|
"""
|
||||||
return _object_id(self._value)
|
return _object_id(self._value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return device specific state attributes."""
|
"""Return the device specific state attributes."""
|
||||||
attrs = {
|
attrs = {
|
||||||
ATTR_NODE_ID: self._value.node.node_id,
|
ATTR_NODE_ID: self._value.node.node_id,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue