Fix PEP257 issues
This commit is contained in:
parent
4f536ac63d
commit
897b5c668f
|
@ -0,0 +1 @@
|
|||
"""Init file for Home Assistant."""
|
|
@ -1,4 +1,4 @@
|
|||
""" Starts home assistant. """
|
||||
"""Starts home assistant."""
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
|
@ -20,7 +20,7 @@ from homeassistant.const import (
|
|||
|
||||
|
||||
def validate_python():
|
||||
""" Validate we're running the right Python version. """
|
||||
"""Validate we're running the right Python version."""
|
||||
major, minor = sys.version_info[:2]
|
||||
req_major, req_minor = REQUIRED_PYTHON_VER
|
||||
|
||||
|
@ -31,8 +31,7 @@ def validate_python():
|
|||
|
||||
|
||||
def ensure_config_path(config_dir):
|
||||
""" Validates configuration directory. """
|
||||
|
||||
"""Validate the configuration directory."""
|
||||
lib_dir = os.path.join(config_dir, 'lib')
|
||||
|
||||
# Test if configuration directory exists
|
||||
|
@ -60,7 +59,7 @@ def ensure_config_path(config_dir):
|
|||
|
||||
|
||||
def ensure_config_file(config_dir):
|
||||
""" Ensure configuration file exists. """
|
||||
"""Ensure configuration file exists."""
|
||||
config_path = config_util.ensure_config_exists(config_dir)
|
||||
|
||||
if config_path is None:
|
||||
|
@ -71,7 +70,7 @@ def ensure_config_file(config_dir):
|
|||
|
||||
|
||||
def get_arguments():
|
||||
""" Get parsed passed in arguments. """
|
||||
"""Get parsed passed in arguments."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Home Assistant: Observe, Control, Automate.")
|
||||
parser.add_argument('--version', action='version', version=__version__)
|
||||
|
@ -136,25 +135,25 @@ def get_arguments():
|
|||
|
||||
|
||||
def daemonize():
|
||||
""" Move current process to daemon process """
|
||||
# create first fork
|
||||
"""Move current process to daemon process."""
|
||||
# Create first fork
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
sys.exit(0)
|
||||
|
||||
# decouple fork
|
||||
# Decouple fork
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# create second fork
|
||||
# Create second fork
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def check_pid(pid_file):
|
||||
""" Check that HA is not already running """
|
||||
# check pid file
|
||||
"""Check that HA is not already running."""
|
||||
# Check pid file
|
||||
try:
|
||||
pid = int(open(pid_file, 'r').readline())
|
||||
except IOError:
|
||||
|
@ -171,7 +170,7 @@ def check_pid(pid_file):
|
|||
|
||||
|
||||
def write_pid(pid_file):
|
||||
""" Create PID File """
|
||||
"""Create a PID File."""
|
||||
pid = os.getpid()
|
||||
try:
|
||||
open(pid_file, 'w').write(str(pid))
|
||||
|
@ -181,7 +180,7 @@ def write_pid(pid_file):
|
|||
|
||||
|
||||
def install_osx():
|
||||
""" Setup to run via launchd on OS X """
|
||||
"""Setup to run via launchd on OS X."""
|
||||
with os.popen('which hass') as inp:
|
||||
hass_path = inp.read().strip()
|
||||
|
||||
|
@ -213,7 +212,7 @@ def install_osx():
|
|||
|
||||
|
||||
def uninstall_osx():
|
||||
""" Unload from launchd on OS X """
|
||||
"""Unload from launchd on OS X."""
|
||||
path = os.path.expanduser("~/Library/LaunchAgents/org.homeassistant.plist")
|
||||
os.popen('launchctl unload ' + path)
|
||||
|
||||
|
@ -221,9 +220,10 @@ def uninstall_osx():
|
|||
|
||||
|
||||
def setup_and_run_hass(config_dir, args, top_process=False):
|
||||
"""
|
||||
Setup HASS and run. Block until stopped. Will assume it is running in a
|
||||
subprocess unless top_process is set to true.
|
||||
"""Setup HASS and run.
|
||||
|
||||
Block until stopped. Will assume it is running in a subprocess unless
|
||||
top_process is set to true.
|
||||
"""
|
||||
if args.demo_mode:
|
||||
config = {
|
||||
|
@ -243,7 +243,7 @@ def setup_and_run_hass(config_dir, args, top_process=False):
|
|||
|
||||
if args.open_ui:
|
||||
def open_browser(event):
|
||||
""" Open the webinterface in a browser. """
|
||||
"""Open the webinterface in a browser."""
|
||||
if hass.config.api is not None:
|
||||
import webbrowser
|
||||
webbrowser.open(hass.config.api.base_url)
|
||||
|
@ -259,12 +259,12 @@ def setup_and_run_hass(config_dir, args, top_process=False):
|
|||
|
||||
|
||||
def run_hass_process(hass_proc):
|
||||
""" Runs a child hass process. Returns True if it should be restarted. """
|
||||
"""Run a child hass process. Returns True if it should be restarted."""
|
||||
requested_stop = threading.Event()
|
||||
hass_proc.daemon = True
|
||||
|
||||
def request_stop(*args):
|
||||
""" request hass stop, *args is for signal handler callback """
|
||||
"""Request hass stop, *args is for signal handler callback."""
|
||||
requested_stop.set()
|
||||
hass_proc.terminate()
|
||||
|
||||
|
@ -289,7 +289,7 @@ def run_hass_process(hass_proc):
|
|||
|
||||
|
||||
def main():
|
||||
""" Starts Home Assistant. """
|
||||
"""Start Home Assistant."""
|
||||
validate_python()
|
||||
|
||||
args = get_arguments()
|
||||
|
@ -297,7 +297,7 @@ def main():
|
|||
config_dir = os.path.join(os.getcwd(), args.config)
|
||||
ensure_config_path(config_dir)
|
||||
|
||||
# os x launchd functions
|
||||
# OS X launchd functions
|
||||
if args.install_osx:
|
||||
install_osx()
|
||||
return 0
|
||||
|
@ -311,7 +311,7 @@ def main():
|
|||
install_osx()
|
||||
return 0
|
||||
|
||||
# daemon functions
|
||||
# Daemon functions
|
||||
if args.pid_file:
|
||||
check_pid(args.pid_file)
|
||||
if args.daemon:
|
||||
|
|
|
@ -34,8 +34,7 @@ ERROR_LOG_FILENAME = 'home-assistant.log'
|
|||
|
||||
|
||||
def setup_component(hass, domain, config=None):
|
||||
""" Setup a component and all its dependencies. """
|
||||
|
||||
"""Setup a component and all its dependencies."""
|
||||
if domain in hass.config.components:
|
||||
return True
|
||||
|
||||
|
@ -58,7 +57,7 @@ def setup_component(hass, domain, config=None):
|
|||
|
||||
|
||||
def _handle_requirements(hass, component, name):
|
||||
""" Installs requirements for component. """
|
||||
"""Install the requirements for a component."""
|
||||
if hass.config.skip_pip or not hasattr(component, 'REQUIREMENTS'):
|
||||
return True
|
||||
|
||||
|
@ -126,7 +125,7 @@ def _setup_component(hass, domain, config):
|
|||
|
||||
|
||||
def prepare_setup_platform(hass, config, domain, platform_name):
|
||||
""" Loads a platform and makes sure dependencies are setup. """
|
||||
"""Load a platform and makes sure dependencies are setup."""
|
||||
_ensure_loader_prepared(hass)
|
||||
|
||||
platform_path = PLATFORM_FORMAT.format(domain, platform_name)
|
||||
|
@ -158,7 +157,7 @@ def prepare_setup_platform(hass, config, domain, platform_name):
|
|||
|
||||
|
||||
def mount_local_lib_path(config_dir):
|
||||
""" Add local library to Python Path """
|
||||
"""Add local library to Python Path."""
|
||||
sys.path.insert(0, os.path.join(config_dir, 'lib'))
|
||||
|
||||
|
||||
|
@ -166,8 +165,7 @@ def mount_local_lib_path(config_dir):
|
|||
def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
|
||||
verbose=False, daemon=False, skip_pip=False,
|
||||
log_rotate_days=None):
|
||||
"""
|
||||
Tries to configure Home Assistant from a config dict.
|
||||
"""Try to configure Home Assistant from a config dict.
|
||||
|
||||
Dynamically loads required components and its dependencies.
|
||||
"""
|
||||
|
@ -209,7 +207,7 @@ def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
|
|||
|
||||
_LOGGER.info('Home Assistant core initialized')
|
||||
|
||||
# give event decorators access to HASS
|
||||
# Give event decorators access to HASS
|
||||
event_decorators.HASS = hass
|
||||
service.HASS = hass
|
||||
|
||||
|
@ -222,9 +220,9 @@ def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
|
|||
|
||||
def from_config_file(config_path, hass=None, verbose=False, daemon=False,
|
||||
skip_pip=True, log_rotate_days=None):
|
||||
"""
|
||||
Reads the configuration file and tries to start all the required
|
||||
functionality. Will add functionality to 'hass' parameter if given,
|
||||
"""Read the configuration file and try to start all the functionality.
|
||||
|
||||
Will add functionality to 'hass' parameter if given,
|
||||
instantiates a new Home Assistant object if 'hass' is not given.
|
||||
"""
|
||||
if hass is None:
|
||||
|
@ -244,7 +242,7 @@ def from_config_file(config_path, hass=None, verbose=False, daemon=False,
|
|||
|
||||
|
||||
def enable_logging(hass, verbose=False, daemon=False, log_rotate_days=None):
|
||||
""" Setup the logging for home assistant. """
|
||||
"""Setup the logging."""
|
||||
if not daemon:
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
fmt = ("%(log_color)s%(asctime)s %(levelname)s (%(threadName)s) "
|
||||
|
@ -297,7 +295,7 @@ def enable_logging(hass, verbose=False, daemon=False, log_rotate_days=None):
|
|||
|
||||
|
||||
def process_ha_config_upgrade(hass):
|
||||
""" Upgrade config if necessary. """
|
||||
"""Upgrade config if necessary."""
|
||||
version_path = hass.config.path('.HA_VERSION')
|
||||
|
||||
try:
|
||||
|
@ -322,11 +320,11 @@ def process_ha_config_upgrade(hass):
|
|||
|
||||
|
||||
def process_ha_core_config(hass, config):
|
||||
""" Processes the [homeassistant] section from the config. """
|
||||
"""Process the [homeassistant] section from the config."""
|
||||
hac = hass.config
|
||||
|
||||
def set_time_zone(time_zone_str):
|
||||
""" Helper method to set time zone in HA. """
|
||||
"""Helper method to set time zone."""
|
||||
if time_zone_str is None:
|
||||
return
|
||||
|
||||
|
@ -397,6 +395,6 @@ def process_ha_core_config(hass, config):
|
|||
|
||||
|
||||
def _ensure_loader_prepared(hass):
|
||||
""" Ensure Home Assistant loader is prepared. """
|
||||
"""Ensure Home Assistant loader is prepared."""
|
||||
if not loader.PREPARED:
|
||||
loader.prepare(hass)
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
"""
|
||||
homeassistant.config
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Module to help with parsing and generating configuration files.
|
||||
"""
|
||||
"""Module to help with parsing and generating configuration files."""
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
@ -43,16 +38,18 @@ DEFAULT_COMPONENTS = {
|
|||
|
||||
|
||||
def get_default_config_dir():
|
||||
""" Put together the default configuration directory based on OS. """
|
||||
"""Put together the default configuration directory based on OS."""
|
||||
data_dir = os.getenv('APPDATA') if os.name == "nt" \
|
||||
else os.path.expanduser('~')
|
||||
return os.path.join(data_dir, CONFIG_DIR_NAME)
|
||||
|
||||
|
||||
def ensure_config_exists(config_dir, detect_location=True):
|
||||
""" Ensures a config file exists in given config dir.
|
||||
Creating a default one if needed.
|
||||
Returns path to the config file. """
|
||||
"""Ensure a config file exists in given configuration directory.
|
||||
|
||||
Creating a default one if needed.
|
||||
Return path to the config file.
|
||||
"""
|
||||
config_path = find_config_file(config_dir)
|
||||
|
||||
if config_path is None:
|
||||
|
@ -64,8 +61,10 @@ def ensure_config_exists(config_dir, detect_location=True):
|
|||
|
||||
|
||||
def create_default_config(config_dir, detect_location=True):
|
||||
""" Creates a default configuration file in given config dir.
|
||||
Returns path to new config file if success, None if failed. """
|
||||
"""Create a default configuration file in given configuration directory.
|
||||
|
||||
Return path to new config file if success, None if failed.
|
||||
"""
|
||||
config_path = os.path.join(config_dir, YAML_CONFIG_FILE)
|
||||
|
||||
info = {attr: default for attr, default, _, _ in DEFAULT_CONFIG}
|
||||
|
@ -108,14 +107,14 @@ def create_default_config(config_dir, detect_location=True):
|
|||
|
||||
|
||||
def find_config_file(config_dir):
|
||||
""" Looks in given directory for supported config files. """
|
||||
"""Look in given directory for supported configuration files."""
|
||||
config_path = os.path.join(config_dir, YAML_CONFIG_FILE)
|
||||
|
||||
return config_path if os.path.isfile(config_path) else None
|
||||
|
||||
|
||||
def load_yaml_config_file(config_path):
|
||||
""" Parse a YAML configuration file. """
|
||||
"""Parse a YAML configuration file."""
|
||||
conf_dict = load_yaml(config_path)
|
||||
|
||||
if not isinstance(conf_dict, dict):
|
||||
|
|
|
@ -132,12 +132,13 @@ class JobPriority(util.OrderedEnum):
|
|||
|
||||
|
||||
class EventOrigin(enum.Enum):
|
||||
"""Represents origin of an event."""
|
||||
"""Represent the origin of an event."""
|
||||
|
||||
local = "LOCAL"
|
||||
remote = "REMOTE"
|
||||
|
||||
def __str__(self):
|
||||
"""Return the event."""
|
||||
return self.value
|
||||
|
||||
|
||||
|
@ -166,6 +167,7 @@ class Event(object):
|
|||
}
|
||||
|
||||
def __repr__(self):
|
||||
"""Return the representation."""
|
||||
# pylint: disable=maybe-no-member
|
||||
if self.data:
|
||||
return "<Event {}[{}]: {}>".format(
|
||||
|
@ -176,6 +178,7 @@ class Event(object):
|
|||
str(self.origin)[0])
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Return the comparison."""
|
||||
return (self.__class__ == other.__class__ and
|
||||
self.event_type == other.event_type and
|
||||
self.data == other.data and
|
||||
|
@ -246,7 +249,7 @@ class EventBus(object):
|
|||
"""
|
||||
@ft.wraps(listener)
|
||||
def onetime_listener(event):
|
||||
"""Remove listener from eventbus and then fires listener."""
|
||||
"""Remove listener from eventbus and then fire listener."""
|
||||
if hasattr(onetime_listener, 'run'):
|
||||
return
|
||||
# Set variable so that we will never run twice.
|
||||
|
@ -281,8 +284,7 @@ class EventBus(object):
|
|||
|
||||
|
||||
class State(object):
|
||||
"""
|
||||
Object to represent a state within the state machine.
|
||||
"""Object to represent a state within the state machine.
|
||||
|
||||
entity_id: the entity that is represented.
|
||||
state: the state of the entity
|
||||
|
@ -369,12 +371,14 @@ class State(object):
|
|||
json_dict.get('attributes'), last_changed, last_updated)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Return the comparison of the state."""
|
||||
return (self.__class__ == other.__class__ and
|
||||
self.entity_id == other.entity_id and
|
||||
self.state == other.state and
|
||||
self.attributes == other.attributes)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return the representation of the states."""
|
||||
attr = "; {}".format(util.repr_helper(self.attributes)) \
|
||||
if self.attributes else ""
|
||||
|
||||
|
@ -524,6 +528,7 @@ class ServiceCall(object):
|
|||
self.call_id = call_id
|
||||
|
||||
def __repr__(self):
|
||||
"""Return the represenation of the service."""
|
||||
if self.data:
|
||||
return "<ServiceCall {}.{}: {}>".format(
|
||||
self.domain, self.service, util.repr_helper(self.data))
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
""" Exceptions used by Home Assistant """
|
||||
"""Exceptions used by Home Assistant."""
|
||||
|
||||
|
||||
class HomeAssistantError(Exception):
|
||||
""" General Home Assistant exception occured. """
|
||||
"""General Home Assistant exception occurred."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class InvalidEntityFormatError(HomeAssistantError):
|
||||
""" When an invalid formatted entity is encountered. """
|
||||
"""When an invalid formatted entity is encountered."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class NoEntitySpecifiedError(HomeAssistantError):
|
||||
""" When no entity is specified. """
|
||||
"""When no entity is specified."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TemplateError(HomeAssistantError):
|
||||
""" Error during template rendering. """
|
||||
"""Error during template rendering."""
|
||||
|
||||
def __init__(self, exception):
|
||||
"""Initalize the error."""
|
||||
super().__init__('{}: {}'.format(exception.__class__.__name__,
|
||||
exception))
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
"""
|
||||
homeassistant.loader
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Provides methods for loading Home Assistant components.
|
||||
|
||||
This module has quite some complex parts. I have tried to add as much
|
||||
|
@ -33,7 +30,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def prepare(hass):
|
||||
""" Prepares the loading of components. """
|
||||
"""Prepare the loading of components."""
|
||||
global PREPARED # pylint: disable=global-statement
|
||||
|
||||
# Load the built-in components
|
||||
|
@ -74,17 +71,18 @@ def prepare(hass):
|
|||
|
||||
|
||||
def set_component(comp_name, component):
|
||||
""" Sets a component in the cache. """
|
||||
"""Set a component in the cache."""
|
||||
_check_prepared()
|
||||
|
||||
_COMPONENT_CACHE[comp_name] = component
|
||||
|
||||
|
||||
def get_component(comp_name):
|
||||
""" Tries to load specified component.
|
||||
Looks in config dir first, then built-in components.
|
||||
Only returns it if also found to be valid. """
|
||||
"""Try to load specified component.
|
||||
|
||||
Looks in config dir first, then built-in components.
|
||||
Only returns it if also found to be valid.
|
||||
"""
|
||||
if comp_name in _COMPONENT_CACHE:
|
||||
return _COMPONENT_CACHE[comp_name]
|
||||
|
||||
|
@ -145,14 +143,14 @@ def get_component(comp_name):
|
|||
|
||||
|
||||
def load_order_components(components):
|
||||
"""
|
||||
Takes in a list of components we want to load:
|
||||
- filters out components we cannot load
|
||||
- filters out components that have invalid/circular dependencies
|
||||
- Will make sure the recorder component is loaded first
|
||||
- Will ensure that all components that do not directly depend on
|
||||
the group component will be loaded before the group component.
|
||||
- returns an OrderedSet load order.
|
||||
"""Take in a list of components we want to load.
|
||||
|
||||
- filters out components we cannot load
|
||||
- filters out components that have invalid/circular dependencies
|
||||
- Will make sure the recorder component is loaded first
|
||||
- Will ensure that all components that do not directly depend on
|
||||
the group component will be loaded before the group component.
|
||||
- returns an OrderedSet load order.
|
||||
"""
|
||||
_check_prepared()
|
||||
|
||||
|
@ -175,8 +173,8 @@ def load_order_components(components):
|
|||
|
||||
|
||||
def load_order_component(comp_name):
|
||||
"""
|
||||
Returns an OrderedSet of components in the correct order of loading.
|
||||
"""Return an OrderedSet of components in the correct order of loading.
|
||||
|
||||
Raises HomeAssistantError if a circular dependency is detected.
|
||||
Returns an empty list if component could not be loaded.
|
||||
"""
|
||||
|
@ -184,10 +182,10 @@ def load_order_component(comp_name):
|
|||
|
||||
|
||||
def _load_order_component(comp_name, load_order, loading):
|
||||
""" Recursive function to get load order of components. """
|
||||
"""Recursive function to get load order of components."""
|
||||
component = get_component(comp_name)
|
||||
|
||||
# if None it does not exist, error already thrown by get_component
|
||||
# If None it does not exist, error already thrown by get_component.
|
||||
if component is None:
|
||||
return OrderedSet()
|
||||
|
||||
|
@ -198,7 +196,7 @@ def _load_order_component(comp_name, load_order, loading):
|
|||
if dependency in load_order:
|
||||
continue
|
||||
|
||||
# If we are already loading it, we have a circular dependency
|
||||
# If we are already loading it, we have a circular dependency.
|
||||
if dependency in loading:
|
||||
_LOGGER.error('Circular dependency detected: %s -> %s',
|
||||
comp_name, dependency)
|
||||
|
@ -221,7 +219,7 @@ def _load_order_component(comp_name, load_order, loading):
|
|||
|
||||
|
||||
def _check_prepared():
|
||||
""" Issues a warning if loader.prepare() has never been called. """
|
||||
"""Issue a warning if loader.prepare() has never been called."""
|
||||
if not PREPARED:
|
||||
_LOGGER.warning((
|
||||
"You did not call loader.prepare() yet. "
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
"""
|
||||
homeassistant.remote
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
A module containing drop in replacements for core parts that will interface
|
||||
with a remote instance of Home Assistant.
|
||||
Support for an interface to work with a remote instance of Home Assistant.
|
||||
|
||||
If a connection error occurs while communicating with the API a
|
||||
HomeAssistantError will be raised.
|
||||
|
@ -34,23 +31,25 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class APIStatus(enum.Enum):
|
||||
""" Represents API status. """
|
||||
# pylint: disable=no-init,invalid-name,too-few-public-methods
|
||||
"""Represent API status."""
|
||||
|
||||
# pylint: disable=no-init,invalid-name,too-few-public-methods
|
||||
OK = "ok"
|
||||
INVALID_PASSWORD = "invalid_password"
|
||||
CANNOT_CONNECT = "cannot_connect"
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
def __str__(self):
|
||||
"""Return the state."""
|
||||
return self.value
|
||||
|
||||
|
||||
class API(object):
|
||||
""" Object to pass around Home Assistant API location and credentials. """
|
||||
# pylint: disable=too-few-public-methods
|
||||
"""Object to pass around Home Assistant API location and credentials."""
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
def __init__(self, host, api_password=None, port=None, use_ssl=False):
|
||||
"""Initalize the API."""
|
||||
self.host = host
|
||||
self.port = port or SERVER_PORT
|
||||
self.api_password = api_password
|
||||
|
@ -65,14 +64,14 @@ class API(object):
|
|||
self._headers[HTTP_HEADER_HA_AUTH] = api_password
|
||||
|
||||
def validate_api(self, force_validate=False):
|
||||
""" Tests if we can communicate with the API. """
|
||||
"""Test if we can communicate with the API."""
|
||||
if self.status is None or force_validate:
|
||||
self.status = validate_api(self)
|
||||
|
||||
return self.status == APIStatus.OK
|
||||
|
||||
def __call__(self, method, path, data=None):
|
||||
""" Makes a call to the Home Assistant API. """
|
||||
"""Make a call to the Home Assistant API."""
|
||||
if data is not None:
|
||||
data = json.dumps(data, cls=JSONEncoder)
|
||||
|
||||
|
@ -96,15 +95,17 @@ class API(object):
|
|||
raise HomeAssistantError(error)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return the representation of the API."""
|
||||
return "API({}, {}, {})".format(
|
||||
self.host, self.api_password, self.port)
|
||||
|
||||
|
||||
class HomeAssistant(ha.HomeAssistant):
|
||||
""" Home Assistant that forwards work. """
|
||||
# pylint: disable=super-init-not-called,too-many-instance-attributes
|
||||
"""Home Assistant that forwards work."""
|
||||
|
||||
# pylint: disable=super-init-not-called,too-many-instance-attributes
|
||||
def __init__(self, remote_api, local_api=None):
|
||||
"""Initalize the forward instance."""
|
||||
if not remote_api.validate_api():
|
||||
raise HomeAssistantError(
|
||||
"Remote API at {}:{} not valid: {}".format(
|
||||
|
@ -122,6 +123,7 @@ class HomeAssistant(ha.HomeAssistant):
|
|||
self.config.api = local_api
|
||||
|
||||
def start(self):
|
||||
"""Start the instance."""
|
||||
# Ensure a local API exists to connect with remote
|
||||
if self.config.api is None:
|
||||
if not bootstrap.setup_component(self, 'api'):
|
||||
|
@ -141,7 +143,7 @@ class HomeAssistant(ha.HomeAssistant):
|
|||
'local api {}').format(self.remote_api, self.config.api))
|
||||
|
||||
def stop(self):
|
||||
""" Stops Home Assistant and shuts down all threads. """
|
||||
"""Stop Home Assistant and shuts down all threads."""
|
||||
_LOGGER.info("Stopping")
|
||||
|
||||
self.bus.fire(ha.EVENT_HOMEASSISTANT_STOP,
|
||||
|
@ -154,16 +156,19 @@ class HomeAssistant(ha.HomeAssistant):
|
|||
|
||||
|
||||
class EventBus(ha.EventBus):
|
||||
""" EventBus implementation that forwards fire_event to remote API. """
|
||||
# pylint: disable=too-few-public-methods
|
||||
"""EventBus implementation that forwards fire_event to remote API."""
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
def __init__(self, api, pool=None):
|
||||
"""Initalize the eventbus."""
|
||||
super().__init__(pool)
|
||||
self._api = api
|
||||
|
||||
def fire(self, event_type, event_data=None, origin=ha.EventOrigin.local):
|
||||
""" Forward local events to remote target,
|
||||
handles remote event as usual. """
|
||||
"""Forward local events to remote target.
|
||||
|
||||
Handles remote event as usual.
|
||||
"""
|
||||
# All local events that are not TIME_CHANGED are forwarded to API
|
||||
if origin == ha.EventOrigin.local and \
|
||||
event_type != ha.EVENT_TIME_CHANGED:
|
||||
|
@ -175,9 +180,10 @@ class EventBus(ha.EventBus):
|
|||
|
||||
|
||||
class EventForwarder(object):
|
||||
""" Listens for events and forwards to specified APIs. """
|
||||
"""Listens for events and forwards to specified APIs."""
|
||||
|
||||
def __init__(self, hass, restrict_origin=None):
|
||||
"""Initalize the event forwarder."""
|
||||
self.hass = hass
|
||||
self.restrict_origin = restrict_origin
|
||||
|
||||
|
@ -188,8 +194,7 @@ class EventForwarder(object):
|
|||
self._lock = threading.Lock()
|
||||
|
||||
def connect(self, api):
|
||||
"""
|
||||
Attach to a Home Assistant instance and forward events.
|
||||
"""Attach to a Home Assistant instance and forward events.
|
||||
|
||||
Will overwrite old target if one exists with same host/port.
|
||||
"""
|
||||
|
@ -203,7 +208,7 @@ class EventForwarder(object):
|
|||
self._targets[key] = api
|
||||
|
||||
def disconnect(self, api):
|
||||
""" Removes target from being forwarded to. """
|
||||
"""Remove target from being forwarded to."""
|
||||
with self._lock:
|
||||
key = (api.host, api.port)
|
||||
|
||||
|
@ -217,7 +222,7 @@ class EventForwarder(object):
|
|||
return did_remove
|
||||
|
||||
def _event_listener(self, event):
|
||||
""" Listen and forwards all events. """
|
||||
"""Listen and forward all events."""
|
||||
with self._lock:
|
||||
# We don't forward time events or, if enabled, non-local events
|
||||
if event.event_type == ha.EVENT_TIME_CHANGED or \
|
||||
|
@ -229,16 +234,12 @@ class EventForwarder(object):
|
|||
|
||||
|
||||
class StateMachine(ha.StateMachine):
|
||||
"""
|
||||
Fires set events to an API.
|
||||
Uses state_change events to track states.
|
||||
"""
|
||||
"""Fire set events to an API. Uses state_change events to track states."""
|
||||
|
||||
def __init__(self, bus, api):
|
||||
"""Initalize the statemachine."""
|
||||
super().__init__(None)
|
||||
|
||||
self._api = api
|
||||
|
||||
self.mirror()
|
||||
|
||||
bus.listen(ha.EVENT_STATE_CHANGED, self._state_changed_listener)
|
||||
|
@ -251,16 +252,16 @@ class StateMachine(ha.StateMachine):
|
|||
return remove_state(self._api, entity_id)
|
||||
|
||||
def set(self, entity_id, new_state, attributes=None):
|
||||
""" Calls set_state on remote API . """
|
||||
"""Call set_state on remote API."""
|
||||
set_state(self._api, entity_id, new_state, attributes)
|
||||
|
||||
def mirror(self):
|
||||
""" Discards current data and mirrors the remote state machine. """
|
||||
"""Discard current data and mirrors the remote state machine."""
|
||||
self._states = {state.entity_id: state for state
|
||||
in get_states(self._api)}
|
||||
|
||||
def _state_changed_listener(self, event):
|
||||
""" Listens for state changed events and applies them. """
|
||||
"""Listen for state changed events and applies them."""
|
||||
if event.data['new_state'] is None:
|
||||
self._states.pop(event.data['entity_id'], None)
|
||||
else:
|
||||
|
@ -268,12 +269,14 @@ class StateMachine(ha.StateMachine):
|
|||
|
||||
|
||||
class JSONEncoder(json.JSONEncoder):
|
||||
""" JSONEncoder that supports Home Assistant objects. """
|
||||
# pylint: disable=too-few-public-methods,method-hidden
|
||||
"""JSONEncoder that supports Home Assistant objects."""
|
||||
|
||||
# pylint: disable=too-few-public-methods,method-hidden
|
||||
def default(self, obj):
|
||||
""" Converts Home Assistant objects and hands
|
||||
other objects to the original method. """
|
||||
"""Convert Home Assistant objects.
|
||||
|
||||
Hand other objects to the original method.
|
||||
"""
|
||||
if hasattr(obj, 'as_dict'):
|
||||
return obj.as_dict()
|
||||
|
||||
|
@ -291,7 +294,7 @@ class JSONEncoder(json.JSONEncoder):
|
|||
|
||||
|
||||
def validate_api(api):
|
||||
""" Makes a call to validate API. """
|
||||
"""Make a call to validate API."""
|
||||
try:
|
||||
req = api(METHOD_GET, URL_API)
|
||||
|
||||
|
@ -309,8 +312,7 @@ def validate_api(api):
|
|||
|
||||
|
||||
def connect_remote_events(from_api, to_api):
|
||||
""" Sets up from_api to forward all events to to_api. """
|
||||
|
||||
"""Setup from_api to forward all events to to_api."""
|
||||
data = {
|
||||
'host': to_api.host,
|
||||
'api_password': to_api.api_password,
|
||||
|
@ -335,7 +337,7 @@ def connect_remote_events(from_api, to_api):
|
|||
|
||||
|
||||
def disconnect_remote_events(from_api, to_api):
|
||||
""" Disconnects forwarding events from from_api to to_api. """
|
||||
"""Disconnect forwarding events from from_api to to_api."""
|
||||
data = {
|
||||
'host': to_api.host,
|
||||
'port': to_api.port
|
||||
|
@ -359,7 +361,7 @@ def disconnect_remote_events(from_api, to_api):
|
|||
|
||||
|
||||
def get_event_listeners(api):
|
||||
""" List of events that is being listened for. """
|
||||
"""List of events that is being listened for."""
|
||||
try:
|
||||
req = api(METHOD_GET, URL_API_EVENTS)
|
||||
|
||||
|
@ -373,8 +375,7 @@ def get_event_listeners(api):
|
|||
|
||||
|
||||
def fire_event(api, event_type, data=None):
|
||||
""" Fire an event at remote API. """
|
||||
|
||||
"""Fire an event at remote API."""
|
||||
try:
|
||||
req = api(METHOD_POST, URL_API_EVENTS_EVENT.format(event_type), data)
|
||||
|
||||
|
@ -387,8 +388,7 @@ def fire_event(api, event_type, data=None):
|
|||
|
||||
|
||||
def get_state(api, entity_id):
|
||||
""" Queries given API for state of entity_id. """
|
||||
|
||||
"""Query given API for state of entity_id."""
|
||||
try:
|
||||
req = api(METHOD_GET, URL_API_STATES_ENTITY.format(entity_id))
|
||||
|
||||
|
@ -405,8 +405,7 @@ def get_state(api, entity_id):
|
|||
|
||||
|
||||
def get_states(api):
|
||||
""" Queries given API for all states. """
|
||||
|
||||
"""Query given API for all states."""
|
||||
try:
|
||||
req = api(METHOD_GET,
|
||||
URL_API_STATES)
|
||||
|
@ -424,7 +423,7 @@ def get_states(api):
|
|||
def remove_state(api, entity_id):
|
||||
"""Call API to remove state for entity_id.
|
||||
|
||||
Returns True if entity is gone (removed/never existed).
|
||||
Return True if entity is gone (removed/never existed).
|
||||
"""
|
||||
try:
|
||||
req = api(METHOD_DELETE, URL_API_STATES_ENTITY.format(entity_id))
|
||||
|
@ -442,11 +441,10 @@ def remove_state(api, entity_id):
|
|||
|
||||
|
||||
def set_state(api, entity_id, new_state, attributes=None):
|
||||
"""
|
||||
Tells API to update state for entity_id.
|
||||
Returns True if success.
|
||||
"""
|
||||
"""Tell API to update state for entity_id.
|
||||
|
||||
Return True if success.
|
||||
"""
|
||||
attributes = attributes or {}
|
||||
|
||||
data = {'state': new_state,
|
||||
|
@ -471,16 +469,16 @@ def set_state(api, entity_id, new_state, attributes=None):
|
|||
|
||||
|
||||
def is_state(api, entity_id, state):
|
||||
""" Queries API to see if entity_id is specified state. """
|
||||
"""Query API to see if entity_id is specified state."""
|
||||
cur_state = get_state(api, entity_id)
|
||||
|
||||
return cur_state and cur_state.state == state
|
||||
|
||||
|
||||
def get_services(api):
|
||||
"""
|
||||
Returns a list of dicts. Each dict has a string "domain" and
|
||||
a list of strings "services".
|
||||
"""Return a list of dicts.
|
||||
|
||||
Each dict has a string "domain" and a list of strings "services".
|
||||
"""
|
||||
try:
|
||||
req = api(METHOD_GET, URL_API_SERVICES)
|
||||
|
@ -495,7 +493,7 @@ def get_services(api):
|
|||
|
||||
|
||||
def call_service(api, domain, service, service_data=None):
|
||||
""" Calls a service at the remote API. """
|
||||
"""Call a service at the remote API."""
|
||||
try:
|
||||
req = api(METHOD_POST,
|
||||
URL_API_SERVICES_SERVICE.format(domain, service),
|
||||
|
|
Loading…
Reference in New Issue