From ab48a94d2a8ba9b8abfbb49a67af38d242363118 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 26 Oct 2015 21:32:04 -0700 Subject: [PATCH 1/8] Version bump to 0.7.7.dev0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 07eee5c793b..9d09aa52e97 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """ Constants used by Home Assistant components. """ -__version__ = "0.7.6" +__version__ = "0.7.7.dev0" # Can be used to specify a catch all when registering state or event listeners. MATCH_ALL = '*' From 52b1080ccd6626e7cad5c11d7a260bfa737d37cb Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 26 Oct 2015 21:11:24 +0100 Subject: [PATCH 2/8] Catch invalid chat ids --- homeassistant/components/notify/telegram.py | 26 +++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/notify/telegram.py b/homeassistant/components/notify/telegram.py index 23b915baf1e..46f1acb1e75 100644 --- a/homeassistant/components/notify/telegram.py +++ b/homeassistant/components/notify/telegram.py @@ -15,6 +15,14 @@ from homeassistant.components.notify import ( from homeassistant.const import CONF_API_KEY _LOGGER = logging.getLogger(__name__) + +try: + import telegram +except ImportError: + _LOGGER.exception( + "Unable to import python-telegram-bot. " + "Did you maybe not install the 'python-telegram-bot' package?") + REQUIREMENTS = ['python-telegram-bot==2.8.7'] @@ -26,18 +34,10 @@ def get_service(hass, config): _LOGGER): return None - try: - import telegram - except ImportError: - _LOGGER.exception( - "Unable to import python-telegram-bot. " - "Did you maybe not install the 'python-telegram-bot' package?") - return None - try: bot = telegram.Bot(token=config[DOMAIN][CONF_API_KEY]) username = bot.getMe()['username'] - _LOGGER.info("Telegram bot is' %s'", username) + _LOGGER.info("Telegram bot is '%s'.", username) except urllib.error.HTTPError: _LOGGER.error("Please check your access token.") return None @@ -52,7 +52,6 @@ class TelegramNotificationService(BaseNotificationService): """ Implements notification service for Telegram. """ def __init__(self, api_key, chat_id): - import telegram self._api_key = api_key self._chat_id = chat_id self.bot = telegram.Bot(token=self._api_key) @@ -62,5 +61,8 @@ class TelegramNotificationService(BaseNotificationService): title = kwargs.get(ATTR_TITLE) - self.bot.sendMessage(chat_id=self._chat_id, - text=title + " " + message) + try: + self.bot.sendMessage(chat_id=self._chat_id, + text=title + " " + message) + except telegram.error.TelegramError: + _LOGGER.error("Your chat id '%s' is not valid.", self._chat_id) From bef0b2b01e4c8259957b79db47529de120fef3d1 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 27 Oct 2015 23:51:16 +0100 Subject: [PATCH 3/8] Make pins optional --- homeassistant/components/sensor/arest.py | 54 +++++++++++++----------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/sensor/arest.py b/homeassistant/components/sensor/arest.py index 22f84e1ecd9..bd1f5edcaea 100644 --- a/homeassistant/components/sensor/arest.py +++ b/homeassistant/components/sensor/arest.py @@ -28,10 +28,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): resource = config.get(CONF_RESOURCE) var_conf = config.get(CONF_MONITORED_VARIABLES) + pins = config.get('pins', None) - if None in (resource, var_conf): + + if resource is None: _LOGGER.error('Not all required config keys present: %s', - ', '.join((CONF_RESOURCE, CONF_MONITORED_VARIABLES))) + CONF_RESOURCE) return False try: @@ -49,31 +51,35 @@ def setup_platform(hass, config, add_devices, discovery_info=None): arest = ArestData(resource) dev = [] - pins = config.get('pins', None) - for variable in config['monitored_variables']: - if variable['name'] not in response['variables']: - _LOGGER.error('Variable: "%s" does not exist', variable['name']) - continue + if var_conf is not None: + for variable in config['monitored_variables']: + if variable['name'] not in response['variables']: + _LOGGER.error('Variable: "%s" does not exist', + variable['name']) + continue - dev.append(ArestSensor(arest, - resource, - config.get('name', response['name']), - variable['name'], - variable=variable['name'], - unit_of_measurement=variable.get( - 'unit_of_measurement'))) + dev.append(ArestSensor(arest, + resource, + config.get('name', response['name']), + variable['name'], + variable=variable['name'], + unit_of_measurement=variable.get( + 'unit_of_measurement'))) - for pinnum, pin in pins.items(): - dev.append(ArestSensor(ArestData(resource, pinnum), - resource, - config.get('name', response['name']), - pin.get('name'), - pin=pinnum, - unit_of_measurement=pin.get( - 'unit_of_measurement'), - corr_factor=pin.get('correction_factor', None), - decimal_places=pin.get('decimal_places', None))) + if pins is not None: + for pinnum, pin in pins.items(): + dev.append(ArestSensor(ArestData(resource, pinnum), + resource, + config.get('name', response['name']), + pin.get('name'), + pin=pinnum, + unit_of_measurement=pin.get( + 'unit_of_measurement'), + corr_factor=pin.get('correction_factor', + None), + decimal_places=pin.get('decimal_places', + None))) add_devices(dev) From b3b2f2e326b7211d707a74ae907b01a3428f7950 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 28 Oct 2015 00:18:03 +0100 Subject: [PATCH 4/8] Fix pylint and flake issues --- homeassistant/components/sensor/arest.py | 1 - homeassistant/components/switch/wemo.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/arest.py b/homeassistant/components/sensor/arest.py index bd1f5edcaea..d1533e14798 100644 --- a/homeassistant/components/sensor/arest.py +++ b/homeassistant/components/sensor/arest.py @@ -30,7 +30,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): var_conf = config.get(CONF_MONITORED_VARIABLES) pins = config.get('pins', None) - if resource is None: _LOGGER.error('Not all required config keys present: %s', CONF_RESOURCE) diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index c710a914d80..8781b5adf0f 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -15,7 +15,7 @@ REQUIREMENTS = ['pywemo==0.3.2'] _LOGGER = logging.getLogger(__name__) -# pylint: disable=unused-argument +# pylint: disable=unused-argument, too-many-function-args def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Find and return WeMo switches. """ import pywemo From 0a36c96a557cb58b185d20c763ff7f52814c0c2e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 27 Oct 2015 19:51:50 -0700 Subject: [PATCH 5/8] Fill in service info for thermostat --- .../components/thermostat/services.yaml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/homeassistant/components/thermostat/services.yaml b/homeassistant/components/thermostat/services.yaml index e69de29bb2d..0d4f4726204 100644 --- a/homeassistant/components/thermostat/services.yaml +++ b/homeassistant/components/thermostat/services.yaml @@ -0,0 +1,24 @@ + +set_away_mode: + description: Turn away mode on/off for a thermostat + + fields: + entity_id: + description: Name(s) of entities to change + example: 'light.kitchen' + + away_mode: + description: New value of away mode + example: true + +set_temperature: + description: Set temperature of thermostat + + fields: + entity_id: + description: Name(s) of entities to change + example: 'light.kitchen' + + temperature: + description: New target temperature for thermostat + example: 25 From 16a3511c0a614d85294a4a0575a9a1112712bb48 Mon Sep 17 00:00:00 2001 From: pavoni Date: Wed, 28 Oct 2015 10:57:10 +0000 Subject: [PATCH 6/8] Catch request exceptions and log a warning --- homeassistant/components/sensor/efergy.py | 37 ++++++++++++----------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/sensor/efergy.py b/homeassistant/components/sensor/efergy.py index 8bc8a668cca..7aa33b181dd 100644 --- a/homeassistant/components/sensor/efergy.py +++ b/homeassistant/components/sensor/efergy.py @@ -8,7 +8,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.efergy.html """ import logging -from requests import get +from requests import get, RequestException from homeassistant.helpers.entity import Entity @@ -80,19 +80,22 @@ class EfergySensor(Entity): 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' + try: + 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' + except RequestException: + _LOGGER.warning('Could not update status for %s', self.name) From 12495c717e9c901e106fd3f46c79049e73d5e7eb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 28 Oct 2015 12:24:33 -0700 Subject: [PATCH 7/8] Fix script regression --- homeassistant/components/script.py | 21 +++++++++++++-------- homeassistant/helpers/entity_component.py | 6 ++++-- tests/components/test_script.py | 14 +++++++++++++- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/script.py b/homeassistant/components/script.py index 3f892fdfa80..6d5f0ea37a1 100644 --- a/homeassistant/components/script.py +++ b/homeassistant/components/script.py @@ -16,7 +16,7 @@ import threading from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.event import track_point_in_utc_time -from homeassistant.util import split_entity_id +from homeassistant.util import slugify, split_entity_id from homeassistant.const import ( ATTR_ENTITY_ID, EVENT_TIME_CHANGED, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF) @@ -70,14 +70,17 @@ def setup(hass, config): if script: script.turn_on() - for name, cfg in config[DOMAIN].items(): - if not cfg.get(CONF_SEQUENCE): - _LOGGER.warn("Missing key 'sequence' for script %s", name) + for object_id, cfg in config[DOMAIN].items(): + if object_id != slugify(object_id): + _LOGGER.warn("Found invalid key for script: %s. Use %s instead.", + object_id, slugify(object_id)) continue - alias = cfg.get(CONF_ALIAS, name) - script = Script(hass, alias, cfg[CONF_SEQUENCE]) + if not cfg.get(CONF_SEQUENCE): + _LOGGER.warn("Missing key 'sequence' for script %s", object_id) + continue + alias = cfg.get(CONF_ALIAS, object_id) + script = Script(hass, object_id, alias, cfg[CONF_SEQUENCE]) component.add_entities((script,)) - _, object_id = split_entity_id(script.entity_id) hass.services.register(DOMAIN, object_id, service_handler) def turn_on_service(service): @@ -100,8 +103,10 @@ def setup(hass, config): class Script(ToggleEntity): """ Represents a script. """ - def __init__(self, hass, name, sequence): + # pylint: disable=too-many-instance-attributes + def __init__(self, hass, object_id, name, sequence): self.hass = hass + self.entity_id = ENTITY_ID_FORMAT.format(object_id) self._name = name self.sequence = sequence self._lock = threading.Lock() diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 708bf6e93a9..d3c0514dcad 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -65,8 +65,10 @@ class EntityComponent(object): if entity is not None and entity not in self.entities.values(): entity.hass = self.hass - entity.entity_id = generate_entity_id( - self.entity_id_format, entity.name, self.entities.keys()) + if getattr(entity, 'entity_id', None) is None: + entity.entity_id = generate_entity_id( + self.entity_id_format, entity.name, + self.entities.keys()) self.entities[entity.entity_id] = entity diff --git a/tests/components/test_script.py b/tests/components/test_script.py index d3974661bc6..e4abed18ec9 100644 --- a/tests/components/test_script.py +++ b/tests/components/test_script.py @@ -47,7 +47,18 @@ class TestScript(unittest.TestCase): } })) - self.assertIsNone(self.hass.states.get(ENTITY_ID)) + self.assertEqual(0, len(self.hass.states.entity_ids('script'))) + + def test_setup_with_invalid_object_id(self): + self.assertTrue(script.setup(self.hass, { + 'script': { + 'test hello world': { + 'sequence': [] + } + } + })) + + self.assertEqual(0, len(self.hass.states.entity_ids('script'))) def test_firing_event(self): event = 'test_event' @@ -61,6 +72,7 @@ class TestScript(unittest.TestCase): self.assertTrue(script.setup(self.hass, { 'script': { 'test': { + 'alias': 'Test Script', 'sequence': [{ 'event': event, 'event_data': { From 5f40115605c26b3c04197af7521b29c624df86aa Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 28 Oct 2015 12:43:04 -0700 Subject: [PATCH 8/8] Version bump to 0.7.7 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 9d09aa52e97..00f8ee408a3 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """ Constants used by Home Assistant components. """ -__version__ = "0.7.7.dev0" +__version__ = "0.7.7" # Can be used to specify a catch all when registering state or event listeners. MATCH_ALL = '*'