From 8983a97c704fc17e9ff6ae4c8480407343845127 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 3 Jan 2016 21:25:15 -0800 Subject: [PATCH 01/25] Fix calling turn_on for groups with mixed content --- homeassistant/components/__init__.py | 10 +++++++++- homeassistant/helpers/__init__.py | 2 +- tests/components/test_init.py | 27 +++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/__init__.py b/homeassistant/components/__init__.py index e0b008cab5e..10e18216ea0 100644 --- a/homeassistant/components/__init__.py +++ b/homeassistant/components/__init__.py @@ -87,13 +87,21 @@ def setup(hass, config): lambda item: util.split_entity_id(item)[0]) for domain, ent_ids in by_domain: + # We want to block for all calls and only return when all calls + # have been processed. If a service does not exist it causes a 10 + # second delay while we're blocking waiting for a response. + # But services can be registered on other HA instances that are + # listening to the bus too. So as a in between solution, we'll + # block only if the service is defined in the current HA instance. + blocking = hass.services.has_service(domain, service.service) + # Create a new dict for this call data = dict(service.data) # ent_ids is a generator, convert it to a list. data[ATTR_ENTITY_ID] = list(ent_ids) - hass.services.call(domain, service.service, data, True) + hass.services.call(domain, service.service, data, blocking) hass.services.register(ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service) hass.services.register(ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service) diff --git a/homeassistant/helpers/__init__.py b/homeassistant/helpers/__init__.py index 021146d1c32..95dfe7dd65e 100644 --- a/homeassistant/helpers/__init__.py +++ b/homeassistant/helpers/__init__.py @@ -36,7 +36,7 @@ def extract_entity_ids(hass, service): service_ent_id = service.data[ATTR_ENTITY_ID] if isinstance(service_ent_id, str): - return group.expand_entity_ids(hass, [service_ent_id.lower()]) + return group.expand_entity_ids(hass, [service_ent_id]) return [ent_id for ent_id in group.expand_entity_ids(hass, service_ent_id)] diff --git a/tests/components/test_init.py b/tests/components/test_init.py index 4ff334c1b1e..cb170a5c24b 100644 --- a/tests/components/test_init.py +++ b/tests/components/test_init.py @@ -6,20 +6,22 @@ Tests core compoments. """ # pylint: disable=protected-access,too-many-public-methods import unittest +from unittest.mock import patch import homeassistant.core as ha -import homeassistant.loader as loader from homeassistant.const import ( STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF) import homeassistant.components as comps +from tests.common import get_test_home_assistant + class TestComponentsCore(unittest.TestCase): """ Tests homeassistant.components module. """ def setUp(self): # pylint: disable=invalid-name """ Init needed objects. """ - self.hass = ha.HomeAssistant() + self.hass = get_test_home_assistant() self.assertTrue(comps.setup(self.hass, {})) self.hass.states.set('light.Bowl', STATE_ON) @@ -58,3 +60,24 @@ class TestComponentsCore(unittest.TestCase): self.hass.pool.block_till_done() self.assertEqual(1, len(runs)) + + @patch('homeassistant.core.ServiceRegistry.call') + def test_turn_on_to_not_block_for_domains_without_service(self, mock_call): + self.hass.services.register('light', SERVICE_TURN_ON, lambda x: x) + + # We can't test if our service call results in services being called + # because by mocking out the call service method, we mock out all + # So we mimick how the service registry calls services + service_call = ha.ServiceCall('homeassistant', 'turn_on', { + 'entity_id': ['light.test', 'sensor.bla', 'light.bla'] + }) + self.hass.services._services['homeassistant']['turn_on'](service_call) + + self.assertEqual(2, mock_call.call_count) + self.assertEqual( + ('light', 'turn_on', {'entity_id': ['light.bla', 'light.test']}, + True), + mock_call.call_args_list[0][0]) + self.assertEqual( + ('sensor', 'turn_on', {'entity_id': ['sensor.bla']}, False), + mock_call.call_args_list[1][0]) From a174a06e5c48d443e310b0334113403395647e01 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 4 Jan 2016 19:25:52 +0100 Subject: [PATCH 02/25] No need to call update() here This also fixes a problem where the sensor is left uninitialized when the energy meter temporarily has lost connection with the hub. This caused the ELIQ Online server to return HTTP error 400: "user have no current power data", which in turn caused the used eliq library to fail during JSON parsing (issue reported). --- homeassistant/components/sensor/eliqonline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/sensor/eliqonline.py b/homeassistant/components/sensor/eliqonline.py index 151b679b10e..891144c4b5f 100644 --- a/homeassistant/components/sensor/eliqonline.py +++ b/homeassistant/components/sensor/eliqonline.py @@ -46,7 +46,6 @@ class EliqSensor(Entity): self.api = api self.channel_id = channel_id - self.update() @property def name(self): From 66f12afbb14e5f60e5fa505c7021e835ed50cb87 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 4 Jan 2016 21:12:10 +0100 Subject: [PATCH 03/25] don't fail if error don't fail if request for updated data raises exception in underlying library --- homeassistant/components/sensor/eliqonline.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/eliqonline.py b/homeassistant/components/sensor/eliqonline.py index 891144c4b5f..f8aaf024813 100644 --- a/homeassistant/components/sensor/eliqonline.py +++ b/homeassistant/components/sensor/eliqonline.py @@ -46,6 +46,7 @@ class EliqSensor(Entity): self.api = api self.channel_id = channel_id + self.update() @property def name(self): @@ -69,5 +70,8 @@ class EliqSensor(Entity): def update(self): """ Gets the latest data. """ - response = self.api.get_data_now(channelid=self.channel_id) - self._state = int(response.power) + try: + response = self.api.get_data_now(channelid=self.channel_id) + self._state = int(response.power) + except: + pass From 82cd2f4ed6fdfc71c6fb52f9b6bcfbe674434b00 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 4 Jan 2016 21:31:42 +0100 Subject: [PATCH 04/25] Update eliqonline.py --- homeassistant/components/sensor/eliqonline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/eliqonline.py b/homeassistant/components/sensor/eliqonline.py index f8aaf024813..91b82f5dc88 100644 --- a/homeassistant/components/sensor/eliqonline.py +++ b/homeassistant/components/sensor/eliqonline.py @@ -73,5 +73,5 @@ class EliqSensor(Entity): try: response = self.api.get_data_now(channelid=self.channel_id) self._state = int(response.power) - except: + except TypeError: # raised by eliqonline library on any HTTP error pass From 5576649d60ec349bcc4c99a3630b1f4970775a3d Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 4 Jan 2016 21:36:39 +0100 Subject: [PATCH 05/25] Update eliqonline.py --- homeassistant/components/sensor/eliqonline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/eliqonline.py b/homeassistant/components/sensor/eliqonline.py index 91b82f5dc88..4e6b8a5c342 100644 --- a/homeassistant/components/sensor/eliqonline.py +++ b/homeassistant/components/sensor/eliqonline.py @@ -73,5 +73,5 @@ class EliqSensor(Entity): try: response = self.api.get_data_now(channelid=self.channel_id) self._state = int(response.power) - except TypeError: # raised by eliqonline library on any HTTP error + except TypeError: # raised by eliqonline library on any HTTP error pass From aac44f3a2b1ada16bd02885e21e567faa62bc7c1 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 7 Jan 2016 11:48:42 +0100 Subject: [PATCH 06/25] Use the same unit for pressure as for the forecast sensor --- homeassistant/components/sensor/openweathermap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/openweathermap.py b/homeassistant/components/sensor/openweathermap.py index 14e8d60c7c6..230a0f8cc68 100644 --- a/homeassistant/components/sensor/openweathermap.py +++ b/homeassistant/components/sensor/openweathermap.py @@ -20,7 +20,7 @@ SENSOR_TYPES = { 'temperature': ['Temperature', ''], 'wind_speed': ['Wind speed', 'm/s'], 'humidity': ['Humidity', '%'], - 'pressure': ['Pressure', 'hPa'], + 'pressure': ['Pressure', 'mbar'], 'clouds': ['Cloud coverage', '%'], 'rain': ['Rain', 'mm'], 'snow': ['Snow', 'mm'] From 35c29dac3f6614715c53ed127b4f242dcfe4ee57 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 7 Jan 2016 11:50:02 +0100 Subject: [PATCH 07/25] Use mbar instead of hPa --- homeassistant/components/sensor/yr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/yr.py b/homeassistant/components/sensor/yr.py index e4003cf7e9c..24f565feb48 100644 --- a/homeassistant/components/sensor/yr.py +++ b/homeassistant/components/sensor/yr.py @@ -25,7 +25,7 @@ SENSOR_TYPES = { 'precipitation': ['Condition', 'mm'], 'temperature': ['Temperature', '°C'], 'windSpeed': ['Wind speed', 'm/s'], - 'pressure': ['Pressure', 'hPa'], + 'pressure': ['Pressure', 'mbar'], 'windDirection': ['Wind direction', '°'], 'humidity': ['Humidity', '%'], 'fog': ['Fog', '%'], From d69c1b848ac85615f3bcf8f8e84109aa360f47c9 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 7 Jan 2016 11:57:45 +0100 Subject: [PATCH 08/25] Fix docstrings --- homeassistant/components/media_player/plex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/plex.py b/homeassistant/components/media_player/plex.py index 6925f942be4..52dd399cedf 100644 --- a/homeassistant/components/media_player/plex.py +++ b/homeassistant/components/media_player/plex.py @@ -35,7 +35,7 @@ SUPPORT_PLEX = SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK def config_from_file(filename, config=None): - ''' Small configuration file management function''' + """ Small configuration file management function. """ if config: # We're writing configuration try: @@ -85,7 +85,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): # pylint: disable=too-many-branches def setup_plexserver(host, token, hass, add_devices_callback): - ''' Setup a plexserver based on host parameter''' + """ Setup a plexserver based on host parameter. """ import plexapi.server import plexapi.exceptions From bb8af3a2d5fc97fc4942fbdc4cb1379c745555ac Mon Sep 17 00:00:00 2001 From: pavoni Date: Fri, 8 Jan 2016 16:00:26 +0000 Subject: [PATCH 09/25] Bump pywemo version, turn off polling, tidy trace. --- homeassistant/components/switch/wemo.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index ad21463ea17..ed56305542d 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -12,7 +12,7 @@ from homeassistant.components.switch import SwitchDevice from homeassistant.const import ( STATE_ON, STATE_OFF, STATE_STANDBY, EVENT_HOMEASSISTANT_STOP) -REQUIREMENTS = ['pywemo==0.3.7'] +REQUIREMENTS = ['pywemo==0.3.8'] _LOGGER = logging.getLogger(__name__) _WEMO_SUBSCRIPTION_REGISTRY = None @@ -69,15 +69,14 @@ class WemoSwitch(SwitchDevice): def _update_callback(self, _device, _params): """ Called by the wemo device callback to update state. """ _LOGGER.info( - 'Subscription update for %s, sevice=%s', - self.name, _device) + 'Subscription update for %s', + _device) self.update_ha_state(True) @property def should_poll(self): - """ No polling should be needed with subscriptions """ - # but leave in for initial version in case of issues. - return True + """ No polling needed with subscriptions """ + return False @property def unique_id(self): From 5a1fed39803e321f579eea2dfbd2041223a97873 Mon Sep 17 00:00:00 2001 From: pavoni Date: Fri, 8 Jan 2016 16:00:56 +0000 Subject: [PATCH 10/25] Bump pywemo version. --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index 5566e67fb9f..5a31ff4c379 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -173,7 +173,7 @@ hikvision==0.4 orvibo==1.1.0 # homeassistant.components.switch.wemo -pywemo==0.3.7 +pywemo==0.3.8 # homeassistant.components.tellduslive tellive-py==0.5.2 From d3cd304f68a3594029f8a97f2a48630a6ffd47ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Sandstr=C3=B6m?= Date: Fri, 8 Jan 2016 19:50:49 +0100 Subject: [PATCH 11/25] correced status text --- homeassistant/components/alarm_control_panel/verisure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index cc9f8dde69d..ea48209a0fd 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -67,7 +67,7 @@ class VerisureAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_DISARMED elif verisure.ALARM_STATUS[self._id].status == 'armedhome': self._state = STATE_ALARM_ARMED_HOME - elif verisure.ALARM_STATUS[self._id].status == 'armedaway': + elif verisure.ALARM_STATUS[self._id].status == 'armed': self._state = STATE_ALARM_ARMED_AWAY elif verisure.ALARM_STATUS[self._id].status != 'pending': _LOGGER.error( From 15a046f20c378386ec51b5590c2e146379c59807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Sandstr=C3=B6m?= Date: Fri, 8 Jan 2016 19:52:03 +0100 Subject: [PATCH 12/25] update module version --- homeassistant/components/verisure.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/verisure.py b/homeassistant/components/verisure.py index 5a4d7c7ea99..164835f07c7 100644 --- a/homeassistant/components/verisure.py +++ b/homeassistant/components/verisure.py @@ -28,7 +28,7 @@ DISCOVER_SWITCHES = 'verisure.switches' DISCOVER_ALARMS = 'verisure.alarm_control_panel' DEPENDENCIES = ['alarm_control_panel'] -REQUIREMENTS = ['vsure==0.4.3'] +REQUIREMENTS = ['vsure==0.4.5'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 5566e67fb9f..2156490269c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -191,7 +191,7 @@ python-nest==2.6.0 radiotherm==1.2 # homeassistant.components.verisure -vsure==0.4.3 +vsure==0.4.5 # homeassistant.components.zwave pydispatcher==2.0.5 From 3db6faab4da6652563efd37af6e7d44e9894b999 Mon Sep 17 00:00:00 2001 From: Philip Lundrigan Date: Fri, 8 Jan 2016 13:30:16 -0700 Subject: [PATCH 13/25] Fix yr test --- tests/components/sensor/test_yr.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/components/sensor/test_yr.py b/tests/components/sensor/test_yr.py index f58aefbce43..780176dd1b8 100644 --- a/tests/components/sensor/test_yr.py +++ b/tests/components/sensor/test_yr.py @@ -4,12 +4,14 @@ tests.components.sensor.test_yr Tests Yr sensor. """ +from datetime import datetime from unittest.mock import patch import pytest import homeassistant.core as ha import homeassistant.components.sensor as sensor +import homeassistant.util.dt as dt_util @pytest.mark.usefixtures('betamax_session') @@ -26,14 +28,18 @@ class TestSensorYr: self.hass.stop() def test_default_setup(self, betamax_session): + now = datetime(2016, 1, 5, 1, tzinfo=dt_util.UTC) + with patch('homeassistant.components.sensor.yr.requests.Session', return_value=betamax_session): - assert sensor.setup(self.hass, { - 'sensor': { - 'platform': 'yr', - 'elevation': 0, - } - }) + with patch('homeassistant.components.sensor.yr.dt_util.utcnow', + return_value=now): + assert sensor.setup(self.hass, { + 'sensor': { + 'platform': 'yr', + 'elevation': 0, + } + }) state = self.hass.states.get('sensor.yr_symbol') From 825c91f0c3a3d3a672c97f29bb0d31188c2ed6ae Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 8 Jan 2016 16:58:44 -0800 Subject: [PATCH 14/25] Add calling service functionality to Alexa --- homeassistant/components/alexa.py | 6 +++ .../components/automation/__init__.py | 23 ++------ homeassistant/helpers/service.py | 37 +++++++++++++ tests/components/test_alexa.py | 53 ++++++++++++++++++- 4 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 homeassistant/helpers/service.py diff --git a/homeassistant/components/alexa.py b/homeassistant/components/alexa.py index 0b06f3c9a79..66ac9de0b43 100644 --- a/homeassistant/components/alexa.py +++ b/homeassistant/components/alexa.py @@ -11,6 +11,7 @@ import logging from homeassistant.const import HTTP_OK, HTTP_UNPROCESSABLE_ENTITY from homeassistant.util import template +from homeassistant.helpers.service import call_from_config DOMAIN = 'alexa' DEPENDENCIES = ['http'] @@ -23,6 +24,7 @@ API_ENDPOINT = '/api/alexa' CONF_INTENTS = 'intents' CONF_CARD = 'card' CONF_SPEECH = 'speech' +CONF_ACTION = 'action' def setup(hass, config): @@ -80,6 +82,7 @@ def _handle_alexa(handler, path_match, data): speech = config.get(CONF_SPEECH) card = config.get(CONF_CARD) + action = config.get(CONF_ACTION) # pylint: disable=unsubscriptable-object if speech is not None: @@ -89,6 +92,9 @@ def _handle_alexa(handler, path_match, data): response.add_card(CardType[card['type']], card['title'], card['content']) + if action is not None: + call_from_config(handler.server.hass, action, True) + handler.write_json(response.as_dict()) diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index 23d83f554ca..9c464f6954e 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -9,9 +9,9 @@ https://home-assistant.io/components/automation/ import logging from homeassistant.bootstrap import prepare_setup_platform -from homeassistant.util import split_entity_id -from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM +from homeassistant.const import CONF_PLATFORM from homeassistant.components import logbook +from homeassistant.helpers.service import call_from_config DOMAIN = 'automation' @@ -19,8 +19,6 @@ DEPENDENCIES = ['group'] CONF_ALIAS = 'alias' CONF_SERVICE = 'service' -CONF_SERVICE_ENTITY_ID = 'entity_id' -CONF_SERVICE_DATA = 'data' CONF_CONDITION = 'condition' CONF_ACTION = 'action' @@ -96,22 +94,7 @@ def _get_action(hass, config, name): _LOGGER.info('Executing %s', name) logbook.log_entry(hass, name, 'has been triggered', DOMAIN) - domain, service = split_entity_id(config[CONF_SERVICE]) - service_data = config.get(CONF_SERVICE_DATA, {}) - - if not isinstance(service_data, dict): - _LOGGER.error("%s should be a dictionary", CONF_SERVICE_DATA) - service_data = {} - - if CONF_SERVICE_ENTITY_ID in config: - try: - service_data[ATTR_ENTITY_ID] = \ - config[CONF_SERVICE_ENTITY_ID].split(",") - except AttributeError: - service_data[ATTR_ENTITY_ID] = \ - config[CONF_SERVICE_ENTITY_ID] - - hass.services.call(domain, service, service_data) + call_from_config(hass, config) return action diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py new file mode 100644 index 00000000000..632b3d39cbb --- /dev/null +++ b/homeassistant/helpers/service.py @@ -0,0 +1,37 @@ +"""Service calling related helpers.""" +import logging + +from homeassistant.util import split_entity_id +from homeassistant.const import ATTR_ENTITY_ID + +CONF_SERVICE = 'service' +CONF_SERVICE_ENTITY_ID = 'entity_id' +CONF_SERVICE_DATA = 'data' + +_LOGGER = logging.getLogger(__name__) + + +def call_from_config(hass, config, blocking=False): + """Call a service based on a config hash.""" + if CONF_SERVICE not in config: + _LOGGER.error('Missing key %s: %s', CONF_SERVICE, config) + return + + domain, service = split_entity_id(config[CONF_SERVICE]) + service_data = config.get(CONF_SERVICE_DATA) + + if service_data is None: + service_data = {} + elif isinstance(service_data, dict): + service_data = dict(service_data) + else: + _LOGGER.error("%s should be a dictionary", CONF_SERVICE_DATA) + service_data = {} + + entity_id = config.get(CONF_SERVICE_ENTITY_ID) + if isinstance(entity_id, str): + service_data[ATTR_ENTITY_ID] = entity_id.split(",") + elif entity_id is not None: + service_data[ATTR_ENTITY_ID] = entity_id + + hass.services.call(domain, service, service_data, blocking) diff --git a/tests/components/test_alexa.py b/tests/components/test_alexa.py index 741cfff4bb8..42acf5b3f62 100644 --- a/tests/components/test_alexa.py +++ b/tests/components/test_alexa.py @@ -27,12 +27,13 @@ API_URL = "http://127.0.0.1:{}{}".format(SERVER_PORT, alexa.API_ENDPOINT) HA_HEADERS = {const.HTTP_HEADER_HA_AUTH: API_PASSWORD} hass = None +calls = [] @patch('homeassistant.components.http.util.get_local_ip', return_value='127.0.0.1') def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name - """ Initalizes a Home Assistant server. """ + """Initalize a Home Assistant server for testing this module.""" global hass hass = ha.HomeAssistant() @@ -42,6 +43,8 @@ def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name {http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD, http.CONF_SERVER_PORT: SERVER_PORT}}) + hass.services.register('test', 'alexa', lambda call: calls.append(call)) + bootstrap.setup_component(hass, alexa.DOMAIN, { 'alexa': { 'intents': { @@ -61,7 +64,20 @@ def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name 'GetZodiacHoroscopeIntent': { 'speech': { 'type': 'plaintext', - 'text': 'You told us your sign is {{ ZodiacSign }}.' + 'text': 'You told us your sign is {{ ZodiacSign }}.', + } + }, + 'CallServiceIntent': { + 'speech': { + 'type': 'plaintext', + 'text': 'Service called', + }, + 'action': { + 'service': 'test.alexa', + 'data': { + 'hello': 1 + }, + 'entity_id': 'switch.test', } } } @@ -231,6 +247,39 @@ class TestAlexa(unittest.TestCase): text = req.json().get('response', {}).get('outputSpeech', {}).get('text') self.assertEqual('You are both home, you silly', text) + def test_intent_request_calling_service(self): + data = { + 'version': '1.0', + 'session': { + 'new': False, + 'sessionId': 'amzn1.echo-api.session.0000000-0000-0000-0000-00000000000', + 'application': { + 'applicationId': 'amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe' + }, + 'attributes': {}, + 'user': { + 'userId': 'amzn1.account.AM3B00000000000000000000000' + } + }, + 'request': { + 'type': 'IntentRequest', + 'requestId': ' amzn1.echo-api.request.0000000-0000-0000-0000-00000000000', + 'timestamp': '2015-05-13T12:34:56Z', + 'intent': { + 'name': 'CallServiceIntent', + } + } + } + call_count = len(calls) + req = _req(data) + self.assertEqual(200, req.status_code) + self.assertEqual(call_count + 1, len(calls)) + call = calls[-1] + self.assertEqual('test', call.domain) + self.assertEqual('alexa', call.service) + self.assertEqual(['switch.test'], call.data.get('entity_id')) + self.assertEqual(1, call.data.get('hello')) + def test_session_ended_request(self): data = { 'version': '1.0', From a2c6cde83d05faf674462be59c3b0e27267566ca Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 9 Jan 2016 13:20:51 +0100 Subject: [PATCH 15/25] Update pyowm to 2.3.0 --- homeassistant/components/sensor/openweathermap.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/openweathermap.py b/homeassistant/components/sensor/openweathermap.py index 230a0f8cc68..84784a19546 100644 --- a/homeassistant/components/sensor/openweathermap.py +++ b/homeassistant/components/sensor/openweathermap.py @@ -13,7 +13,7 @@ from homeassistant.util import Throttle from homeassistant.const import (CONF_API_KEY, TEMP_CELCIUS, TEMP_FAHRENHEIT) from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['pyowm==2.2.1'] +REQUIREMENTS = ['pyowm==2.3.0'] _LOGGER = logging.getLogger(__name__) SENSOR_TYPES = { 'weather': ['Condition', ''], diff --git a/requirements_all.txt b/requirements_all.txt index 5566e67fb9f..c703dbd28ba 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -135,7 +135,7 @@ python-forecastio==1.3.3 https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3 # homeassistant.components.sensor.openweathermap -pyowm==2.2.1 +pyowm==2.3.0 # homeassistant.components.sensor.rpi_gpio # homeassistant.components.switch.rpi_gpio From d61eb93c033434e31c29c73591a6bc96a72e48e7 Mon Sep 17 00:00:00 2001 From: pavoni Date: Sat, 9 Jan 2016 16:16:41 +0000 Subject: [PATCH 16/25] Remove throttle doesn't play well with subscriptions. --- homeassistant/components/light/vera.py | 1 - homeassistant/components/switch/vera.py | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/homeassistant/components/light/vera.py b/homeassistant/components/light/vera.py index bcf27eab5f7..95e0d849762 100644 --- a/homeassistant/components/light/vera.py +++ b/homeassistant/components/light/vera.py @@ -86,5 +86,4 @@ class VeraLight(VeraSwitch): else: self.vera_device.switch_on() - self.last_command_send = time.time() self.is_on_status = True diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index 91a83086570..1f67d3cfa69 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -87,8 +87,6 @@ class VeraSwitch(ToggleEntity): else: self._name = self.vera_device.name self.is_on_status = False - # for debouncing status check after command is sent - self.last_command_send = 0 self.controller.register(vera_device) self.controller.on( @@ -132,12 +130,10 @@ class VeraSwitch(ToggleEntity): return attr def turn_on(self, **kwargs): - self.last_command_send = time.time() self.vera_device.switch_on() self.is_on_status = True def turn_off(self, **kwargs): - self.last_command_send = time.time() self.vera_device.switch_off() self.is_on_status = False @@ -152,10 +148,7 @@ class VeraSwitch(ToggleEntity): return self.is_on_status def update(self): - # We need to debounce the status call after turning switch on or off - # because the vera has some lag in updating the device status try: - if (self.last_command_send + 5) < time.time(): - self.is_on_status = self.vera_device.is_switched_on() + self.is_on_status = self.vera_device.is_switched_on() except RequestException: _LOGGER.warning('Could not update status for %s', self.name) From 9faedf0e67e90f013842cdbd6840eb59484acef9 Mon Sep 17 00:00:00 2001 From: Philip Lundrigan Date: Fri, 8 Jan 2016 12:54:22 -0700 Subject: [PATCH 17/25] Default to MQTT protocol v3.1.1 (fix #854) --- homeassistant/components/mqtt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index b5ea258c5cc..86dce3d511b 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -149,9 +149,9 @@ class MQTT(object): } if client_id is None: - self._mqttc = mqtt.Client() + self._mqttc = mqtt.Client(protocol=mqtt.MQTTv311) else: - self._mqttc = mqtt.Client(client_id) + self._mqttc = mqtt.Client(client_id, protocol=mqtt.MQTTv311) self._mqttc.user_data_set(self.userdata) From b64680e4a827c7191c24b05c373306e8e9b0f8f0 Mon Sep 17 00:00:00 2001 From: pavoni Date: Sat, 9 Jan 2016 21:13:34 +0000 Subject: [PATCH 18/25] Revise to depend on vera subscription data updates, rather than talking to device. --- homeassistant/components/sensor/vera.py | 10 ++++------ homeassistant/components/switch/vera.py | 12 +++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py index c7b95ce5d53..ef581f22dc3 100644 --- a/homeassistant/components/sensor/vera.py +++ b/homeassistant/components/sensor/vera.py @@ -119,18 +119,18 @@ class VeraSensor(Entity): attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%' if self.vera_device.is_armable: - armed = self.vera_device.refresh_value('Armed') + armed = self.vera_device.get_value('Armed') attr[ATTR_ARMED] = 'True' if armed == '1' else 'False' if self.vera_device.is_trippable: - last_tripped = self.vera_device.refresh_value('LastTrip') + last_tripped = self.vera_device.get_value('LastTrip') if last_tripped is not None: utc_time = dt_util.utc_from_timestamp(int(last_tripped)) attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str( utc_time) else: attr[ATTR_LAST_TRIP_TIME] = None - tripped = self.vera_device.refresh_value('Tripped') + tripped = self.vera_device.get_value('Tripped') attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False' attr['Vera Device Id'] = self.vera_device.vera_device_id @@ -143,7 +143,6 @@ class VeraSensor(Entity): def update(self): if self.vera_device.category == "Temperature Sensor": - self.vera_device.refresh_value('CurrentTemperature') current_temp = self.vera_device.get_value('CurrentTemperature') vera_temp_units = self.vera_device.veraController.temperature_units @@ -161,10 +160,9 @@ class VeraSensor(Entity): self.current_value = current_temp elif self.vera_device.category == "Light Sensor": - self.vera_device.refresh_value('CurrentLevel') self.current_value = self.vera_device.get_value('CurrentLevel') elif self.vera_device.category == "Sensor": - tripped = self.vera_device.refresh_value('Tripped') + tripped = self.vera_device.get_value('Tripped') self.current_value = 'Tripped' if tripped == '1' else 'Not Tripped' else: self.current_value = 'Unknown' diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index 1f67d3cfa69..0e29583bf5c 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -111,18 +111,18 @@ class VeraSwitch(ToggleEntity): attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%' if self.vera_device.is_armable: - armed = self.vera_device.refresh_value('Armed') + armed = self.vera_device.get_value('Armed') attr[ATTR_ARMED] = 'True' if armed == '1' else 'False' if self.vera_device.is_trippable: - last_tripped = self.vera_device.refresh_value('LastTrip') + last_tripped = self.vera_device.get_value('LastTrip') if last_tripped is not None: utc_time = dt_util.utc_from_timestamp(int(last_tripped)) attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str( utc_time) else: attr[ATTR_LAST_TRIP_TIME] = None - tripped = self.vera_device.refresh_value('Tripped') + tripped = self.vera_device.get_value('Tripped') attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False' attr['Vera Device Id'] = self.vera_device.vera_device_id @@ -133,6 +133,7 @@ class VeraSwitch(ToggleEntity): self.vera_device.switch_on() self.is_on_status = True + def turn_off(self, **kwargs): self.vera_device.switch_off() self.is_on_status = False @@ -148,7 +149,4 @@ class VeraSwitch(ToggleEntity): return self.is_on_status def update(self): - try: - self.is_on_status = self.vera_device.is_switched_on() - except RequestException: - _LOGGER.warning('Could not update status for %s', self.name) + self.is_on_status = self.vera_device.is_switched_on() From af21f72d179312b3295fbfc7249751e978a7cf80 Mon Sep 17 00:00:00 2001 From: pavoni Date: Sat, 9 Jan 2016 22:58:28 +0000 Subject: [PATCH 19/25] Update pyvera version. --- homeassistant/components/light/vera.py | 2 +- homeassistant/components/sensor/vera.py | 6 ++---- homeassistant/components/switch/vera.py | 6 ++---- requirements_all.txt | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/light/vera.py b/homeassistant/components/light/vera.py index 95e0d849762..76718e71eb4 100644 --- a/homeassistant/components/light/vera.py +++ b/homeassistant/components/light/vera.py @@ -16,7 +16,7 @@ from homeassistant.components.light import ATTR_BRIGHTNESS from homeassistant.const import EVENT_HOMEASSISTANT_STOP -REQUIREMENTS = ['pyvera==0.2.2'] +REQUIREMENTS = ['pyvera==0.2.3'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py index ef581f22dc3..6ef5d469c60 100644 --- a/homeassistant/components/sensor/vera.py +++ b/homeassistant/components/sensor/vera.py @@ -15,7 +15,7 @@ from homeassistant.const import ( ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME, TEMP_CELCIUS, TEMP_FAHRENHEIT, EVENT_HOMEASSISTANT_STOP) -REQUIREMENTS = ['pyvera==0.2.2'] +REQUIREMENTS = ['pyvera==0.2.3'] _LOGGER = logging.getLogger(__name__) @@ -85,9 +85,7 @@ class VeraSensor(Entity): self.current_value = '' self._temperature_units = None - self.controller.register(vera_device) - self.controller.on( - vera_device, self._update_callback) + self.controller.register(vera_device, self._update_callback) def _update_callback(self, _device): """ Called by the vera device callback to update state. """ diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index 0e29583bf5c..0acc33bea4e 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -19,7 +19,7 @@ from homeassistant.const import ( ATTR_LAST_TRIP_TIME, EVENT_HOMEASSISTANT_STOP) -REQUIREMENTS = ['pyvera==0.2.2'] +REQUIREMENTS = ['pyvera==0.2.3'] _LOGGER = logging.getLogger(__name__) @@ -88,9 +88,7 @@ class VeraSwitch(ToggleEntity): self._name = self.vera_device.name self.is_on_status = False - self.controller.register(vera_device) - self.controller.on( - vera_device, self._update_callback) + self.controller.register(vera_device, self._update_callback) def _update_callback(self, _device): """ Called by the vera device callback to update state. """ diff --git a/requirements_all.txt b/requirements_all.txt index 5a31ff4c379..64792267213 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -59,7 +59,7 @@ tellcore-py==1.1.2 # homeassistant.components.light.vera # homeassistant.components.sensor.vera # homeassistant.components.switch.vera -pyvera==0.2.2 +pyvera==0.2.3 # homeassistant.components.wink # homeassistant.components.light.wink From 12b5caed70721b3f924b316239627cbba81021be Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 9 Jan 2016 15:51:51 -0800 Subject: [PATCH 20/25] ps - strip entity IDs in service call --- homeassistant/helpers/service.py | 3 ++- tests/helpers/test_service.py | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/helpers/test_service.py diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 632b3d39cbb..530f72fa22f 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -30,7 +30,8 @@ def call_from_config(hass, config, blocking=False): entity_id = config.get(CONF_SERVICE_ENTITY_ID) if isinstance(entity_id, str): - service_data[ATTR_ENTITY_ID] = entity_id.split(",") + service_data[ATTR_ENTITY_ID] = [ent.strip() for ent in + entity_id.split(",")] elif entity_id is not None: service_data[ATTR_ENTITY_ID] = entity_id diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py new file mode 100644 index 00000000000..32a36edc5f1 --- /dev/null +++ b/tests/helpers/test_service.py @@ -0,0 +1,39 @@ +""" +tests.helpers.test_service +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Test service helpers. +""" +from datetime import timedelta +import unittest +from unittest.mock import patch + +import homeassistant.core as ha +from homeassistant.const import SERVICE_TURN_ON +from homeassistant.helpers import service + +from tests.common import get_test_home_assistant, mock_service + + +class TestServiceHelpers(unittest.TestCase): + """ + Tests the Home Assistant service helpers. + """ + + def setUp(self): # pylint: disable=invalid-name + """ things to be run when tests are started. """ + self.hass = get_test_home_assistant() + self.calls = mock_service(self.hass, 'test_domain', 'test_service') + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_split_entity_string(self): + service.call_from_config(self.hass, { + 'service': 'test_domain.test_service', + 'entity_id': 'hello.world, sensor.beer' + }) + self.hass.pool.block_till_done() + self.assertEqual(['hello.world', 'sensor.beer'], + self.calls[-1].data.get('entity_id')) From 73cdf00512fd24e961656afb012a02e371626f39 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 9 Jan 2016 16:01:27 -0800 Subject: [PATCH 21/25] More service helper tests --- homeassistant/helpers/service.py | 9 +++++++-- tests/helpers/test_service.py | 33 ++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 530f72fa22f..15cfe9b97c6 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -13,11 +13,16 @@ _LOGGER = logging.getLogger(__name__) def call_from_config(hass, config, blocking=False): """Call a service based on a config hash.""" - if CONF_SERVICE not in config: + if not isinstance(config, dict) or CONF_SERVICE not in config: _LOGGER.error('Missing key %s: %s', CONF_SERVICE, config) return - domain, service = split_entity_id(config[CONF_SERVICE]) + try: + domain, service = split_entity_id(config[CONF_SERVICE]) + except ValueError: + _LOGGER.error('Invalid service specified: %s', config[CONF_SERVICE]) + return + service_data = config.get(CONF_SERVICE_DATA) if service_data is None: diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py index 32a36edc5f1..aa2cab07d0d 100644 --- a/tests/helpers/test_service.py +++ b/tests/helpers/test_service.py @@ -4,11 +4,9 @@ tests.helpers.test_service Test service helpers. """ -from datetime import timedelta import unittest from unittest.mock import patch -import homeassistant.core as ha from homeassistant.const import SERVICE_TURN_ON from homeassistant.helpers import service @@ -37,3 +35,34 @@ class TestServiceHelpers(unittest.TestCase): self.hass.pool.block_till_done() self.assertEqual(['hello.world', 'sensor.beer'], self.calls[-1].data.get('entity_id')) + + def test_not_mutate_input(self): + orig = { + 'service': 'test_domain.test_service', + 'entity_id': 'hello.world, sensor.beer', + 'data': { + 'hello': 1, + }, + } + service.call_from_config(self.hass, orig) + self.hass.pool.block_till_done() + self.assertEqual({ + 'service': 'test_domain.test_service', + 'entity_id': 'hello.world, sensor.beer', + 'data': { + 'hello': 1, + }, + }, orig) + + @patch('homeassistant.helpers.service._LOGGER.error') + def test_fail_silently_if_no_service(self, mock_log): + service.call_from_config(self.hass, None) + self.assertEqual(1, mock_log.call_count) + + service.call_from_config(self.hass, {}) + self.assertEqual(2, mock_log.call_count) + + service.call_from_config(self.hass, { + 'service': 'invalid' + }) + self.assertEqual(3, mock_log.call_count) From 438e78610d4ca9261bfcb8ab210043d0b1a52fc4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 9 Jan 2016 16:21:08 -0800 Subject: [PATCH 22/25] Update PyChromecast dependency --- homeassistant/components/media_player/cast.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 87117cfd367..c0717edc860 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -20,7 +20,7 @@ from homeassistant.components.media_player import ( SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO) -REQUIREMENTS = ['pychromecast==0.6.13'] +REQUIREMENTS = ['pychromecast==0.6.14'] 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 | \ diff --git a/requirements_all.txt b/requirements_all.txt index 2444fac84c6..74cf5a1e993 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -69,7 +69,7 @@ pyvera==0.2.2 python-wink==0.3.1 # homeassistant.components.media_player.cast -pychromecast==0.6.13 +pychromecast==0.6.14 # homeassistant.components.media_player.kodi jsonrpc-requests==0.1 From 4b4fb038e3e8c3914448ac0a40d9a85f2e29235b Mon Sep 17 00:00:00 2001 From: pavoni Date: Sun, 10 Jan 2016 12:30:47 +0000 Subject: [PATCH 23/25] Update for new library, slightly revise switch logic. --- homeassistant/components/light/vera.py | 7 +++--- homeassistant/components/sensor/vera.py | 6 ++--- homeassistant/components/switch/vera.py | 30 +++++++++++++++---------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/light/vera.py b/homeassistant/components/light/vera.py index 76718e71eb4..59abbe6b29d 100644 --- a/homeassistant/components/light/vera.py +++ b/homeassistant/components/light/vera.py @@ -14,7 +14,7 @@ from homeassistant.components.switch.vera import VeraSwitch from homeassistant.components.light import ATTR_BRIGHTNESS -from homeassistant.const import EVENT_HOMEASSISTANT_STOP +from homeassistant.const import EVENT_HOMEASSISTANT_STOP, STATE_ON REQUIREMENTS = ['pyvera==0.2.3'] @@ -59,7 +59,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): lights = [] for device in devices: - extra_data = device_data.get(device.deviceId, {}) + extra_data = device_data.get(device.device_id, {}) exclude = extra_data.get('exclude', False) if exclude is not True: @@ -86,4 +86,5 @@ class VeraLight(VeraSwitch): else: self.vera_device.switch_on() - self.is_on_status = True + self._state = STATE_ON + self.update_ha_state() diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py index 6ef5d469c60..b381974ab31 100644 --- a/homeassistant/components/sensor/vera.py +++ b/homeassistant/components/sensor/vera.py @@ -56,7 +56,7 @@ def get_devices(hass, config): vera_sensors = [] for device in devices: - extra_data = device_data.get(device.deviceId, {}) + extra_data = device_data.get(device.device_id, {}) exclude = extra_data.get('exclude', False) if exclude is not True: @@ -89,12 +89,10 @@ class VeraSensor(Entity): def _update_callback(self, _device): """ Called by the vera device callback to update state. """ - _LOGGER.info( - 'Subscription update for %s', self.name) self.update_ha_state(True) def __str__(self): - return "%s %s %s" % (self.name, self.vera_device.deviceId, self.state) + return "%s %s %s" % (self.name, self.vera_device.device_id, self.state) @property def state(self): diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index 0acc33bea4e..3f5d2a08cb8 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -12,12 +12,16 @@ from requests.exceptions import RequestException import homeassistant.util.dt as dt_util from homeassistant.helpers.entity import ToggleEntity +from homeassistant.components.switch import SwitchDevice + from homeassistant.const import ( ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME, - EVENT_HOMEASSISTANT_STOP) + EVENT_HOMEASSISTANT_STOP, + STATE_ON, + STATE_OFF) REQUIREMENTS = ['pyvera==0.2.3'] @@ -60,7 +64,7 @@ def get_devices(hass, config): vera_switches = [] for device in devices: - extra_data = device_data.get(device.deviceId, {}) + extra_data = device_data.get(device.device_id, {}) exclude = extra_data.get('exclude', False) if exclude is not True: @@ -75,7 +79,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): add_devices(get_devices(hass, config)) -class VeraSwitch(ToggleEntity): +class VeraSwitch(SwitchDevice): """ Represents a Vera Switch. """ def __init__(self, vera_device, controller, extra_data=None): @@ -86,15 +90,17 @@ class VeraSwitch(ToggleEntity): self._name = self.extra_data.get('name') else: self._name = self.vera_device.name - self.is_on_status = False + self._state = STATE_OFF self.controller.register(vera_device, self._update_callback) def _update_callback(self, _device): """ Called by the vera device callback to update state. """ - _LOGGER.info( - 'Subscription update for %s', self.name) - self.update_ha_state(True) + if self.vera_device.is_switched_on(): + self._state = STATE_ON + else: + self._state = STATE_OFF + self.update_ha_state() @property def name(self): @@ -129,12 +135,14 @@ class VeraSwitch(ToggleEntity): def turn_on(self, **kwargs): self.vera_device.switch_on() - self.is_on_status = True + self._state = STATE_ON + self.update_ha_state() def turn_off(self, **kwargs): self.vera_device.switch_off() - self.is_on_status = False + self._state = STATE_OFF + self.update_ha_state() @property def should_poll(self): @@ -144,7 +152,5 @@ class VeraSwitch(ToggleEntity): @property def is_on(self): """ True if device is on. """ - return self.is_on_status + return self._state == STATE_ON - def update(self): - self.is_on_status = self.vera_device.is_switched_on() From fca8ad5b0b85cde597ab9f3bcdf7acb82dce99d8 Mon Sep 17 00:00:00 2001 From: pavoni Date: Sun, 10 Jan 2016 12:48:36 +0000 Subject: [PATCH 24/25] Tidy. --- homeassistant/components/light/vera.py | 1 - homeassistant/components/switch/vera.py | 4 ---- 2 files changed, 5 deletions(-) diff --git a/homeassistant/components/light/vera.py b/homeassistant/components/light/vera.py index 59abbe6b29d..42a5e7b7899 100644 --- a/homeassistant/components/light/vera.py +++ b/homeassistant/components/light/vera.py @@ -7,7 +7,6 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.vera/ """ import logging -import time from requests.exceptions import RequestException from homeassistant.components.switch.vera import VeraSwitch diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index 3f5d2a08cb8..4094fe61f4f 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -7,11 +7,9 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.vera/ """ import logging -import time from requests.exceptions import RequestException import homeassistant.util.dt as dt_util -from homeassistant.helpers.entity import ToggleEntity from homeassistant.components.switch import SwitchDevice from homeassistant.const import ( @@ -138,7 +136,6 @@ class VeraSwitch(SwitchDevice): self._state = STATE_ON self.update_ha_state() - def turn_off(self, **kwargs): self.vera_device.switch_off() self._state = STATE_OFF @@ -153,4 +150,3 @@ class VeraSwitch(SwitchDevice): def is_on(self): """ True if device is on. """ return self._state == STATE_ON - From 6c94650603280e88a42ff959ce67556dfb04d211 Mon Sep 17 00:00:00 2001 From: xifle Date: Sun, 10 Jan 2016 15:00:14 +0100 Subject: [PATCH 25/25] Accept lower & upper case for owntracks 'home' region --- homeassistant/components/device_tracker/owntracks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/owntracks.py b/homeassistant/components/device_tracker/owntracks.py index e81952eb770..e1b0e1de306 100644 --- a/homeassistant/components/device_tracker/owntracks.py +++ b/homeassistant/components/device_tracker/owntracks.py @@ -71,7 +71,7 @@ def setup_scanner(hass, config, see): location = '' if data['event'] == 'enter': - if data['desc'] == 'home': + if data['desc'].lower() == 'home': location = STATE_HOME else: location = data['desc']