From 90392ec30358558d603056adb7a5f7c0b861413a Mon Sep 17 00:00:00 2001 From: Ryan Kraus Date: Fri, 3 Jul 2015 03:13:10 -0400 Subject: [PATCH 01/10] Added app name display to Chromecast component. --- homeassistant/components/media_player/cast.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 77cdf79a112..b26fa647b00 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -153,7 +153,8 @@ class CastDevice(MediaPlayerDevice): @property def media_title(self): """ Title of current playing media. """ - return self.media_status.title if self.media_status else None + title = self.media_status.title if self.media_status else None + return title if title else self.cast.app_display_name @property def media_artist(self): From 8b7a406fe79f577bc80aa98f11fd81af69162de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Tue, 7 Jul 2015 22:33:40 +0200 Subject: [PATCH 02/10] Use xy_color instead of color in the configuration example --- config/configuration.yaml.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/configuration.yaml.example b/config/configuration.yaml.example index c99f760f21f..5acca361a30 100644 --- a/config/configuration.yaml.example +++ b/config/configuration.yaml.example @@ -159,5 +159,5 @@ scene: light.tv_back_light: on light.ceiling: state: on - color: [0.33, 0.66] + xy_color: [0.33, 0.66] brightness: 200 From 237778a8bc79f00da8c54485cff0ae74f79d5840 Mon Sep 17 00:00:00 2001 From: Ryan Kraus Date: Tue, 7 Jul 2015 23:04:16 -0400 Subject: [PATCH 03/10] Update to PyISY 1.0.5 Updated Home Assistant to use PyISY version 1.0.5 to fix error when no climate module is present as well as update HTTPS connections to use TLS. --- homeassistant/components/isy994.py | 6 ++++-- requirements.txt | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/isy994.py b/homeassistant/components/isy994.py index 2ff9b5caeaf..d750c3b09be 100644 --- a/homeassistant/components/isy994.py +++ b/homeassistant/components/isy994.py @@ -28,6 +28,7 @@ DISCOVER_SENSORS = "isy994.sensors" ISY = None SENSOR_STRING = 'Sensor' HIDDEN_STRING = '{HIDE ME}' +CONF_TLS_VER = 'tls' # setup logger _LOGGER = logging.getLogger(__name__) @@ -42,7 +43,6 @@ def setup(hass, config): import PyISY except ImportError: _LOGGER.error("Error while importing dependency PyISY.") - return False # pylint: disable=global-statement @@ -74,10 +74,12 @@ def setup(hass, config): global HIDDEN_STRING SENSOR_STRING = str(config[DOMAIN].get('sensor_string', SENSOR_STRING)) HIDDEN_STRING = str(config[DOMAIN].get('hidden_string', HIDDEN_STRING)) + tls_version = config[DOMAIN].get(CONF_TLS_VER, None) # connect to ISY controller global ISY - ISY = PyISY.ISY(addr, port, user, password, use_https=https, log=_LOGGER) + ISY = PyISY.ISY(addr, port, user, password, use_https=https, + tls_ver=tls_version, log=_LOGGER) if not ISY.connected: return False diff --git a/requirements.txt b/requirements.txt index 341fcd3cf81..9f7e788f47c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ python-nest>=2.3.1 pydispatcher>=2.0.5 # ISY994 bindings (*.isy994) -PyISY>=1.0.2 +PyISY>=1.0.5 # PSutil (sensor.systemmonitor) psutil>=3.0.0 From 7530109ce85c008ac4a1abdc42cd0b7b67708425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Wed, 8 Jul 2015 20:26:37 +0200 Subject: [PATCH 04/10] Implement the colorloop effect for hue lights --- homeassistant/components/light/__init__.py | 12 +++++++++++- homeassistant/components/light/hue.py | 10 +++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 51a3c61dbd5..54919a73331 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -88,6 +88,10 @@ ATTR_FLASH = "flash" FLASH_SHORT = "short" FLASH_LONG = "long" +# Apply an effect to the light, can be EFFECT_COLORLOOP +ATTR_EFFECT = "effect" +EFFECT_COLORLOOP = "colorloop" + LIGHT_PROFILES_FILE = "light_profiles.csv" # Maps discovered services to their platforms @@ -114,7 +118,8 @@ def is_on(hass, entity_id=None): # pylint: disable=too-many-arguments def turn_on(hass, entity_id=None, transition=None, brightness=None, - rgb_color=None, xy_color=None, profile=None, flash=None): + rgb_color=None, xy_color=None, profile=None, flash=None, + effect=None): """ Turns all or specified light on. """ data = { key: value for key, value in [ @@ -125,6 +130,7 @@ def turn_on(hass, entity_id=None, transition=None, brightness=None, (ATTR_RGB_COLOR, rgb_color), (ATTR_XY_COLOR, xy_color), (ATTR_FLASH, flash), + (ATTR_EFFECT, effect), ] if value is not None } @@ -253,6 +259,10 @@ def setup(hass, config): elif dat[ATTR_FLASH] == FLASH_LONG: params[ATTR_FLASH] = FLASH_LONG + if ATTR_EFFECT in dat: + if dat[ATTR_EFFECT] == EFFECT_COLORLOOP: + params[ATTR_EFFECT] = EFFECT_COLORLOOP + for light in target_lights: light.turn_on(**params) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 65a288f82d5..0b2cf1e2dd7 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -9,7 +9,8 @@ import homeassistant.util as util from homeassistant.const import CONF_HOST, DEVICE_DEFAULT_NAME from homeassistant.components.light import ( Light, ATTR_BRIGHTNESS, ATTR_XY_COLOR, ATTR_TRANSITION, - ATTR_FLASH, FLASH_LONG, FLASH_SHORT) + ATTR_FLASH, FLASH_LONG, FLASH_SHORT, ATTR_EFFECT, + EFFECT_COLORLOOP) MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) @@ -191,6 +192,13 @@ class HueLight(Light): else: command['alert'] = 'none' + effect = kwargs.get(ATTR_EFFECT) + + if effect == EFFECT_COLORLOOP: + command['effect'] = 'colorloop' + else: + command['effect'] = 'none' + self.bridge.set_light(self.light_id, command) def turn_off(self, **kwargs): From 370355b94b4bbbbeb3e82f46c5d72e5cea912fca Mon Sep 17 00:00:00 2001 From: Gustav Ahlberg Date: Wed, 8 Jul 2015 21:39:50 +0200 Subject: [PATCH 05/10] Added functionallity so that the tellstick switch can send it's signals repeatedly Because the tellstick sends its actions via radio and from most receivers it's impossible to know if the signal was received or not. --- homeassistant/components/switch/tellstick.py | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/switch/tellstick.py b/homeassistant/components/switch/tellstick.py index 84f5d2b31d5..6f9070d28fb 100644 --- a/homeassistant/components/switch/tellstick.py +++ b/homeassistant/components/switch/tellstick.py @@ -3,6 +3,12 @@ homeassistant.components.switch.tellstick ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Support for Tellstick switches. + +Because the tellstick sends its actions via radio and from most +receivers it's impossible to know if the signal was received or not. +Therefore you can configure the switch to try to send each signal repeatedly +with the config parameter signal_repetitions (default is 1). +signal_repetitions: 3 """ import logging @@ -11,6 +17,8 @@ from homeassistant.const import ATTR_FRIENDLY_NAME from homeassistant.helpers.entity import ToggleEntity import tellcore.constants as tellcore_constants +SINGAL_REPETITIONS = 1 + # pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): @@ -22,6 +30,8 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): "Failed to import tellcore") return + signal_repetitions = config.get('signal_repetitions', SINGAL_REPETITIONS) + core = telldus.TelldusCore() switches_and_lights = core.devices() @@ -29,7 +39,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): for switch in switches_and_lights: if not switch.methods(tellcore_constants.TELLSTICK_DIM): - switches.append(TellstickSwitchDevice(switch)) + switches.append(TellstickSwitchDevice(switch, signal_repetitions)) add_devices_callback(switches) @@ -39,9 +49,10 @@ class TellstickSwitchDevice(ToggleEntity): last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON | tellcore_constants.TELLSTICK_TURNOFF) - def __init__(self, tellstick): + def __init__(self, tellstick, signal_repetitions): self.tellstick = tellstick self.state_attr = {ATTR_FRIENDLY_NAME: tellstick.name} + self.signal_repetitions = signal_repetitions @property def name(self): @@ -63,8 +74,10 @@ class TellstickSwitchDevice(ToggleEntity): def turn_on(self, **kwargs): """ Turns the switch on. """ - self.tellstick.turn_on() + for _ in range(self.signal_repetitions): + self.tellstick.turn_on() def turn_off(self, **kwargs): """ Turns the switch off. """ - self.tellstick.turn_off() + for _ in range(self.signal_repetitions): + self.tellstick.turn_off() From 18bcf3ea000c803bec6a8e83716dcf4e6d4beb21 Mon Sep 17 00:00:00 2001 From: miniconfig Date: Thu, 9 Jul 2015 12:05:19 -0400 Subject: [PATCH 06/10] Added a new sensor to read data from the efergy energy monitor --- homeassistant/components/sensor/efergy.py | 138 ++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 homeassistant/components/sensor/efergy.py diff --git a/homeassistant/components/sensor/efergy.py b/homeassistant/components/sensor/efergy.py new file mode 100644 index 00000000000..d0391e5c37b --- /dev/null +++ b/homeassistant/components/sensor/efergy.py @@ -0,0 +1,138 @@ +""" +homeassistant.components.sensor.efergy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Monitors home energy use as measured by an efergy +engage hub using its (unofficial, undocumented) API. + +Configuration: + +To use the efergy sensor you will need to add something +like the following to your config/configuration.yaml + +sensor: + platform: efergy + app_token: APP_TOKEN + utc_offset: UTC_OFFSET + monitored_variables: + - type: instant_readings + - type: budget + - type: cost + period: day + currency: $ + +Variables: + +api_key +*Required +To get a new App Token, log in to your efergy account, go +to the Settings page, click on App tokens, and click "Add token". + +utc_offset +*Required for some variables +Some variables (currently only the daily_cost) require that the +negative number of minutes your timezone is ahead/behind UTC time. + +monitored_variables +*Required +An array specifying the variables to monitor. + +period +*Optional +Some variables take a period argument. Valid options are "day", +1"week", "month", and "year" + +currency +*Optional +This is used to display the cost/period as the unit when monitoring the +cost. It should correspond to the actual currency used in your dashboard. +""" +import logging +from requests import get + +from homeassistant.helpers.entity import Entity + +_LOGGER = logging.getLogger(__name__) +_RESOURCE = 'https://engage.efergy.com/mobile_proxy/' +SENSOR_TYPES = { + 'instant_readings': ['Energy Usage', 'kW'], + 'budget': ['Energy Budget', ''], + 'cost': ['Energy Cost', ''], +} + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the efergy sensor. """ + app_token = config.get("app_token") + if not app_token: + _LOGGER.error( + "Configuration Error" + "Please make sure you have configured your app token") + return None + utc_offset = str(config.get("utc_offset")) + dev = [] + for variable in config['monitored_variables']: + if 'period' not in variable: + variable['period'] = '' + if 'currency' not in variable: + variable['currency'] = '' + if variable['type'] not in SENSOR_TYPES: + _LOGGER.error('Sensor type: "%s" does not exist', variable) + else: + dev.append(EfergySensor(variable['type'], app_token, utc_offset, + variable['period'], variable['currency'])) + + add_devices(dev) + + +# pylint: disable=too-many-instance-attributes +class EfergySensor(Entity): + """ Implements an Efergy sensor. """ + + # pylint: disable=too-many-arguments + def __init__(self, sensor_type, app_token, utc_offset, period, currency): + self._name = SENSOR_TYPES[sensor_type][0] + self.type = sensor_type + self.app_token = app_token + self.utc_offset = utc_offset + self._state = None + self.period = period + self.currency = currency + if self.type == 'cost': + self._unit_of_measurement = self.currency + '/' + self.period + else: + self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] + + @property + def name(self): + """ Returns the name. """ + return self._name + + @property + def state(self): + """ Returns the state of the device. """ + return self._state + + @property + def unit_of_measurement(self): + """ Unit of measurement of this entity, if any. """ + return self._unit_of_measurement + + def update(self): + """ Gets the efergy monitor data from the web service """ + if self.type == 'instant_readings': + url_string = _RESOURCE + 'getInstant?token=' + self.app_token + response = get(url_string) + self._state = response.json()['reading'] / 1000 + elif self.type == 'budget': + url_string = _RESOURCE + 'getBudget?token=' + self.app_token + response = get(url_string) + self._state = response.json()['status'] + elif self.type == 'cost': + url_string = _RESOURCE + 'getCost?token=' + self.app_token \ + + '&offset=' + self.utc_offset + '&period=' \ + + self.period + response = get(url_string) + self._state = response.json()['sum'] + else: + self._state = 'Unknown' From 67135a7150d4f5d48271dfd3179f5be55c3ad7a1 Mon Sep 17 00:00:00 2001 From: Ryan Kraus Date: Fri, 10 Jul 2015 00:29:07 -0400 Subject: [PATCH 07/10] Implimented Ignore CEC for Chromecasts 1) Added the ability to ignore CEC data from Chromecasts using pending updates to PyChromecast library. 2) Modified cast device to not allow the same device to be imported twice. This can happen when cast is setup as a media_player in the config when the discovery component is active. --- .../www_static/polymer/home-assistant-js | 2 +- homeassistant/components/media_player/cast.py | 18 ++++++++++++++++-- requirements.txt | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/www_static/polymer/home-assistant-js b/homeassistant/components/frontend/www_static/polymer/home-assistant-js index 14f2bb779eb..015edf9c28a 160000 --- a/homeassistant/components/frontend/www_static/polymer/home-assistant-js +++ b/homeassistant/components/frontend/www_static/polymer/home-assistant-js @@ -1 +1 @@ -Subproject commit 14f2bb779eb165bce236dcdc69d83e08ab73da1c +Subproject commit 015edf9c28a63122aa8f6bc153f0c0ddfaad1caa diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 77cdf79a112..4e33034d821 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -25,10 +25,12 @@ from homeassistant.components.media_player import ( SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO) +CONF_IGNORE_CEC = 'ignore_cec' CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png' SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \ SUPPORT_NEXT_TRACK | SUPPORT_YOUTUBE +KNOWN_HOSTS = [] # pylint: disable=unused-argument @@ -43,12 +45,22 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False - if discovery_info: + # import CEC IGNORE attributes + ignore_cec = config.get(CONF_IGNORE_CEC, []) + if isinstance(ignore_cec, list): + pychromecast.IGNORE_CEC += ignore_cec + else: + logger.error('Chromecast conig, %s must be a list.', CONF_IGNORE_CEC) + + hosts = [] + + if discovery_info and discovery_info[0] not in KNOWN_HOSTS: hosts = [discovery_info[0]] else: hosts = (host_port[0] for host_port - in pychromecast.discover_chromecasts()) + in pychromecast.discover_chromecasts() + if host_port[0] not in KNOWN_HOSTS) casts = [] @@ -57,6 +69,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): casts.append(CastDevice(host)) except pychromecast.ChromecastConnectionError: pass + else: + KNOWN_HOSTS.append(host) add_devices(casts) diff --git a/requirements.txt b/requirements.txt index 9f7e788f47c..67e9f1c5249 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ phue>=0.8 ledcontroller>=1.0.7 # Chromecast bindings (media_player.cast) -pychromecast>=0.6.6 +pychromecast>=0.6.7 # Keyboard (keyboard) pyuserinput>=0.1.9 From 1bfde8a1e5d5ce6e930486683465158a4f2e7a60 Mon Sep 17 00:00:00 2001 From: Ryan Kraus Date: Fri, 10 Jul 2015 00:34:52 -0400 Subject: [PATCH 08/10] Rolling home-assistant-js back to newest Accidentally rolled home-assistant-js back. Brought it back to the current version. --- .../components/frontend/www_static/polymer/home-assistant-js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/frontend/www_static/polymer/home-assistant-js b/homeassistant/components/frontend/www_static/polymer/home-assistant-js index 015edf9c28a..14f2bb779eb 160000 --- a/homeassistant/components/frontend/www_static/polymer/home-assistant-js +++ b/homeassistant/components/frontend/www_static/polymer/home-assistant-js @@ -1 +1 @@ -Subproject commit 015edf9c28a63122aa8f6bc153f0c0ddfaad1caa +Subproject commit 14f2bb779eb165bce236dcdc69d83e08ab73da1c From f3ff8ca9ca7241cc1edd70eef1c5d254192bbe90 Mon Sep 17 00:00:00 2001 From: Ryan Kraus Date: Fri, 10 Jul 2015 00:54:29 -0400 Subject: [PATCH 09/10] Bumped PyChromecast version in requirements Bumped PyChromecast version to a hypothetical 0.6.9 since the newest is already 0.6.8. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 67e9f1c5249..b4b79b19763 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ phue>=0.8 ledcontroller>=1.0.7 # Chromecast bindings (media_player.cast) -pychromecast>=0.6.7 +pychromecast>=0.6.9 # Keyboard (keyboard) pyuserinput>=0.1.9 From b3479a4ab611ac1c8273fbbd19ea1fa127223b8e Mon Sep 17 00:00:00 2001 From: Ryan Kraus Date: Sat, 11 Jul 2015 00:28:37 -0400 Subject: [PATCH 10/10] Created init.d script Created a Debian init.d compatible service script. --- scripts/homeassistant.daemon | 88 ++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100755 scripts/homeassistant.daemon diff --git a/scripts/homeassistant.daemon b/scripts/homeassistant.daemon new file mode 100755 index 00000000000..4c504557dec --- /dev/null +++ b/scripts/homeassistant.daemon @@ -0,0 +1,88 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: homeassistant +# Required-Start: $local_fs $network $named $time $syslog +# Required-Stop: $local_fs $network $named $time $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Description: Home\ Assistant +### END INIT INFO + +# /etc/init.d Service Script for Home Assistant +# Created with: https://gist.github.com/naholyr/4275302#file-new-service-sh +# +# Installation: +# 1) Populate RUNAS and RUNDIR folders +# 2) Create Log -- sudo touch /var/log/homeassistant.log +# 3) Set Log Ownership -- sudo chown USER:GROUP /var/log/homeassistant.log +# 4) Create PID File -- sudo touch /var/run/homeassistant.pid +# 5) Set PID File Ownership -- sudo chown USER:GROUP /var/run/homeassistant.pid +# 6) Install init.d script -- cp homeassistant.daemon /etc/init.d/homeassistant +# 7) Setup HA for Auto Start -- sudo update-rc.d homeassistant defaults +# 8) Run HA -- sudo service homeassistant start +# +# After installation, HA should start automatically. If HA does not start, +# check the log file output for errors. (/var/log/homeassistant.log) +# +# For this script, it is assumed that you are using a local Virtual Environment +# per the install directions as http://home-assistant.io +# If you are not, the SCRIPT variable must be modified to point to the correct +# Python environment. + +SCRIPT="./bin/python -m homeassistant" +RUNAS= +RUNDIR= +PIDFILE=/var/run/homeassistant.pid +LOGFILE=/var/log/homeassistant.log + +start() { + if [ -f /var/run/$PIDNAME ] && kill -0 $(cat /var/run/$PIDNAME); then + echo 'Service already running' >&2 + return 1 + fi + echo 'Starting service…' >&2 + local CMD="cd $RUNDIR; $SCRIPT &> \"$LOGFILE\" & echo \$!" + su -c "$CMD" $RUNAS > "$PIDFILE" + echo 'Service started' >&2 +} + +stop() { + if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then + echo 'Service not running' >&2 + return 1 + fi + echo 'Stopping service…' >&2 + kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE" + echo 'Service stopped' >&2 +} + +uninstall() { + echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] " + local SURE + read SURE + if [ "$SURE" = "yes" ]; then + stop + rm -f "$PIDFILE" + echo "Notice: log file is not be removed: '$LOGFILE'" >&2 + update-rc.d -f homeassistant remove + rm -fv "$0" + fi +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + uninstall) + uninstall + ;; + retart) + stop + start + ;; + *) + echo "Usage: $0 {start|stop|restart|uninstall}" +esac