From a94a5ac9b5577068864b26a1fbaab213b76628bb Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Sat, 8 Oct 2016 23:40:50 +0200 Subject: [PATCH 01/13] Coerce device IDs from known_devices to be slugs (#3764) * Slugify & consider_home test fix [due to load valid PR] * undo schema change * Fix slugify error --- .../components/device_tracker/__init__.py | 8 +++++--- homeassistant/helpers/config_validation.py | 14 ++++++++++++-- tests/components/device_tracker/test_init.py | 19 +++++++++++++++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index a05b57cff33..3fa8361a44d 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -46,6 +46,7 @@ CONF_TRACK_NEW = 'track_new_devices' DEFAULT_TRACK_NEW = True CONF_CONSIDER_HOME = 'consider_home' +DEFAULT_CONSIDER_HOME = 180 CONF_SCAN_INTERVAL = 'interval_seconds' DEFAULT_SCAN_INTERVAL = 12 @@ -119,8 +120,9 @@ def setup(hass: HomeAssistantType, config: ConfigType): return False else: conf = conf[0] if len(conf) > 0 else {} - consider_home = conf[CONF_CONSIDER_HOME] - track_new = conf[CONF_TRACK_NEW] + consider_home = conf.get(CONF_CONSIDER_HOME, + timedelta(seconds=DEFAULT_CONSIDER_HOME)) + track_new = conf.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW) devices = load_config(yaml_path, hass, consider_home) @@ -415,7 +417,7 @@ def load_config(path: str, hass: HomeAssistantType, consider_home: timedelta): for dev_id, device in devices.items(): try: device = dev_schema(device) - device['dev_id'] = cv.slug(dev_id) + device['dev_id'] = cv.slugify(dev_id) except vol.Invalid as exp: log_exception(exp, dev_id, devices) else: diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 7236debbe88..1d368a37d3c 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -17,7 +17,7 @@ from homeassistant.const import ( from homeassistant.core import valid_entity_id from homeassistant.exceptions import TemplateError import homeassistant.util.dt as dt_util -from homeassistant.util import slugify +from homeassistant.util import slugify as util_slugify from homeassistant.helpers import template as template_helper # pylint: disable=invalid-name @@ -218,12 +218,22 @@ def slug(value): if value is None: raise vol.Invalid('Slug should not be None') value = str(value) - slg = slugify(value) + slg = util_slugify(value) if value == slg: return value raise vol.Invalid('invalid slug {} (try {})'.format(value, slg)) +def slugify(value): + """Coerce a value to a slug.""" + if value is None: + raise vol.Invalid('Slug should not be None') + slg = util_slugify(str(value)) + if len(slg) > 0: + return slg + raise vol.Invalid('Unable to slugify {}'.format(value)) + + def string(value: Any) -> str: """Coerce value to string, except for None.""" if value is not None: diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index f195712285a..3e5b4dc96b2 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -60,12 +60,27 @@ class TestComponentsDeviceTracker(unittest.TestCase): """Test when known devices contains invalid data.""" files = {'empty.yaml': '', 'nodict.yaml': '100', - 'allok.yaml': 'my_device:\n name: Device'} + 'badkey.yaml': '@:\n name: Device', + 'noname.yaml': 'my_device:\n', + 'allok.yaml': 'My Device:\n name: Device', + 'oneok.yaml': ('My Device!:\n name: Device\n' + 'bad_device:\n nme: Device')} args = {'hass': self.hass, 'consider_home': timedelta(seconds=60)} with patch_yaml_files(files): assert device_tracker.load_config('empty.yaml', **args) == [] assert device_tracker.load_config('nodict.yaml', **args) == [] - assert len(device_tracker.load_config('allok.yaml', **args)) == 1 + assert device_tracker.load_config('noname.yaml', **args) == [] + assert device_tracker.load_config('badkey.yaml', **args) == [] + + res = device_tracker.load_config('allok.yaml', **args) + assert len(res) == 1 + assert res[0].name == 'Device' + assert res[0].dev_id == 'my_device' + + res = device_tracker.load_config('oneok.yaml', **args) + assert len(res) == 1 + assert res[0].name == 'Device' + assert res[0].dev_id == 'my_device' def test_reading_yaml_config(self): """Test the rendering of the YAML configuration.""" From dba5c74c8f2a9c466ce6dca30947290dd8722f6b Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sat, 8 Oct 2016 23:03:32 +0300 Subject: [PATCH 02/13] Fix command line cover template (#3754) The command line cover value template is optional so we need to check it's not none before assigning hass to it. Fixes #3649 Signed-off-by: Roi Dayan --- homeassistant/components/cover/command_line.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/cover/command_line.py b/homeassistant/components/cover/command_line.py index d70d43463cf..27e1c810cf4 100644 --- a/homeassistant/components/cover/command_line.py +++ b/homeassistant/components/cover/command_line.py @@ -38,7 +38,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device_name, device_config in devices.items(): value_template = device_config.get(CONF_VALUE_TEMPLATE) - value_template.hass = hass + if value_template is not None: + value_template.hass = hass covers.append( CommandCover( From 78cbfa3f9630d5272e1e7a159bfe477e98a58fe6 Mon Sep 17 00:00:00 2001 From: mtl010957 Date: Sat, 8 Oct 2016 15:57:40 -0400 Subject: [PATCH 03/13] Fixed issue #3760, handle X10 unit numbers greater than 9. (#3763) --- homeassistant/components/light/x10.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/light/x10.py b/homeassistant/components/light/x10.py index 499bd7513a6..30ede3eac18 100644 --- a/homeassistant/components/light/x10.py +++ b/homeassistant/components/light/x10.py @@ -41,7 +41,7 @@ def get_status(): def get_unit_status(code): """Get on/off status for given unit.""" - unit = int(code[1]) + unit = int(code[1:]) return get_status()[16 - int(unit)] == '1' From 46b58db2ff9f10cc6f6e48dd39fcc1239eac44fe Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 8 Oct 2016 14:42:47 -0700 Subject: [PATCH 04/13] Version bump to 0.30.1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index cba668d88cf..4948190b9d0 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 30 -PATCH_VERSION = '0' +PATCH_VERSION = '1' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 4, 2) From 8c1317f278b96b11bf933ce3305f20e741dcaa3c Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Mon, 10 Oct 2016 22:31:15 -0700 Subject: [PATCH 05/13] Wrap found target in list (#3809) * Wrap found target in list * Fix test_messages_to_targets_route --- homeassistant/components/notify/__init__.py | 2 +- tests/components/notify/test_demo.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index e56dfa5586d..c779c78d15e 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -100,7 +100,7 @@ def setup(hass, config): kwargs[ATTR_TITLE] = title.render() if targets.get(call.service) is not None: - kwargs[ATTR_TARGET] = targets[call.service] + kwargs[ATTR_TARGET] = [targets[call.service]] else: kwargs[ATTR_TARGET] = call.data.get(ATTR_TARGET) diff --git a/tests/components/notify/test_demo.py b/tests/components/notify/test_demo.py index b996b479ef9..0d41f0606e5 100644 --- a/tests/components/notify/test_demo.py +++ b/tests/components/notify/test_demo.py @@ -152,7 +152,7 @@ data_template: assert { 'message': 'my message', - 'target': 'test target id', + 'target': ['test target id'], 'title': 'my title', 'data': {'hello': 'world'} } == data From 47544552958b3e849a3e16bdf31ffabd1dafcf03 Mon Sep 17 00:00:00 2001 From: Ellis Percival Date: Mon, 10 Oct 2016 15:53:18 +0100 Subject: [PATCH 06/13] Make 'pin' optional for zigbee device config. (#3799) --- homeassistant/components/zigbee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/zigbee.py b/homeassistant/components/zigbee.py index 4b4da350199..8a9271745c9 100644 --- a/homeassistant/components/zigbee.py +++ b/homeassistant/components/zigbee.py @@ -55,7 +55,7 @@ CONFIG_SCHEMA = vol.Schema({ PLATFORM_SCHEMA = vol.Schema({ vol.Required(CONF_NAME): cv.string, - vol.Required(CONF_PIN): cv.positive_int, + vol.Optional(CONF_PIN): cv.positive_int, vol.Optional(CONF_ADDRESS): cv.string, }, extra=vol.ALLOW_EXTRA) From f18f18196219d0b64300859bc626a83f7649c1a3 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 10 Oct 2016 13:46:23 +0200 Subject: [PATCH 07/13] Hotfix device name with autodiscovery (#3791) --- homeassistant/components/homematic.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/homematic.py b/homeassistant/components/homematic.py index b09f53ae748..6e4727f8188 100644 --- a/homeassistant/components/homematic.py +++ b/homeassistant/components/homematic.py @@ -353,7 +353,8 @@ def _get_devices(device_type, keys): name = _create_ha_name( name=device.NAME, channel=channel, - param=param + param=param, + count=len(channels) ) device_dict = { CONF_PLATFORM: "homematic", @@ -377,22 +378,22 @@ def _get_devices(device_type, keys): return device_arr -def _create_ha_name(name, channel, param): +def _create_ha_name(name, channel, param, count): """Generate a unique object name.""" # HMDevice is a simple device - if channel == 1 and param is None: + if count == 1 and param is None: return name # Has multiple elements/channels - if channel > 1 and param is None: + if count > 1 and param is None: return "{} {}".format(name, channel) # With multiple param first elements - if channel == 1 and param is not None: + if count == 1 and param is not None: return "{} {}".format(name, param) # Multiple param on object with multiple elements - if channel > 1 and param is not None: + if count > 1 and param is not None: return "{} {} {}".format(name, channel, param) @@ -600,12 +601,6 @@ class HMDevice(Entity): if self._state: self._state = self._state.upper() - # Generate name - if not self._name: - self._name = _create_ha_name(name=self._address, - channel=self._channel, - param=self._state) - @property def should_poll(self): """Return false. Homematic states are pushed by the XML RPC Server.""" From 574df0f4209cce5d6c6ff8512c68de11a83d0c25 Mon Sep 17 00:00:00 2001 From: Teemu Mikkonen Date: Tue, 11 Oct 2016 09:17:27 +0300 Subject: [PATCH 08/13] Fix for html5 notification tag problem. Fixes #3774 (#3790) --- homeassistant/components/notify/html5.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/notify/html5.py b/homeassistant/components/notify/html5.py index a868552d051..7173538032c 100644 --- a/homeassistant/components/notify/html5.py +++ b/homeassistant/components/notify/html5.py @@ -344,12 +344,15 @@ class HTML5NotificationService(BaseNotificationService): # Pick out fields that should go into the notification directly vs # into the notification data dictionary. - for key, val in data.copy().items(): + data_tmp = {} + + for key, val in data.items(): if key in HTML5_SHOWNOTIFICATION_PARAMETERS: payload[key] = val - del data[key] + else: + data_tmp[key] = val - payload[ATTR_DATA] = data + payload[ATTR_DATA] = data_tmp if (payload[ATTR_DATA].get(ATTR_URL) is None and payload.get(ATTR_ACTIONS) is None): From 016e8f833dbf2f41f3f39cdde461bf0844f6e6e9 Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Sun, 9 Oct 2016 18:15:58 +0200 Subject: [PATCH 09/13] slugify (#3777) --- homeassistant/components/device_tracker/volvooncall.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/volvooncall.py b/homeassistant/components/device_tracker/volvooncall.py index 8f5cf5fff7a..746bbea6ccf 100644 --- a/homeassistant/components/device_tracker/volvooncall.py +++ b/homeassistant/components/device_tracker/volvooncall.py @@ -14,6 +14,7 @@ import requests import homeassistant.helpers.config_validation as cv from homeassistant.helpers.event import track_point_in_utc_time from homeassistant.util.dt import utcnow +from homeassistant.util import slugify from homeassistant.const import ( CONF_PASSWORD, CONF_SCAN_INTERVAL, @@ -87,7 +88,7 @@ def setup_scanner(hass, config, see): vehicle_url = rel["vehicle"] + '/' attributes = query("attributes", vehicle_url) - dev_id = "volvo_" + attributes["registrationNumber"] + dev_id = "volvo_" + slugify(attributes["registrationNumber"]) host_name = "%s %s/%s" % (attributes["registrationNumber"], attributes["vehicleType"], attributes["modelYear"]) From dfe9af7110b067a44f7d687bf28108316aa53aa0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Oct 2016 00:21:01 -0700 Subject: [PATCH 10/13] Version bump to 0.30.2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 4948190b9d0..31d1c50f82e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 30 -PATCH_VERSION = '1' +PATCH_VERSION = '2' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 4, 2) From 0b327cd4d96169392e551e326b25746dfa225329 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Tue, 11 Oct 2016 20:33:41 -0700 Subject: [PATCH 11/13] Notify: Only attach target if in call data (#3831) * Only pass through the target if it has a value * Target will no longer be none --- homeassistant/components/notify/__init__.py | 2 +- tests/components/notify/test_demo.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index c779c78d15e..b30777a0cf2 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -101,7 +101,7 @@ def setup(hass, config): if targets.get(call.service) is not None: kwargs[ATTR_TARGET] = [targets[call.service]] - else: + elif call.data.get(ATTR_TARGET) is not None: kwargs[ATTR_TARGET] = call.data.get(ATTR_TARGET) message.hass = hass diff --git a/tests/components/notify/test_demo.py b/tests/components/notify/test_demo.py index 0d41f0606e5..a0d9f28fe1a 100644 --- a/tests/components/notify/test_demo.py +++ b/tests/components/notify/test_demo.py @@ -64,7 +64,6 @@ class TestNotifyDemo(unittest.TestCase): data = self.events[0].data assert { 'message': 'my message', - 'target': None, 'title': 'my title', 'data': {'hello': 'world'} } == data @@ -92,7 +91,6 @@ data_template: self.assertTrue(len(self.events) == 1) assert { 'message': 'Test 123 4', - 'target': None, 'data': { 'push': { 'sound': @@ -124,7 +122,6 @@ data_template: assert { 'message': 'Test 123 4', 'title': 'Test', - 'target': None, 'data': { 'push': { 'sound': From 73547c8c4b61abe9d8d0e7f27cb64bd42953fc6f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 12 Oct 2016 06:16:11 +0200 Subject: [PATCH 12/13] Fix slack targets (#3826) --- homeassistant/components/notify/slack.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/notify/slack.py b/homeassistant/components/notify/slack.py index 75ebb9b26fe..7c0a2b4d118 100644 --- a/homeassistant/components/notify/slack.py +++ b/homeassistant/components/notify/slack.py @@ -68,7 +68,10 @@ class SlackNotificationService(BaseNotificationService): """Send a message to a user.""" import slacker - targets = kwargs.get(ATTR_TARGET, [self._default_channel]) + if kwargs.get(ATTR_TARGET) is None: + targets = [self._default_channel] + else: + targets = kwargs.get(ATTR_TARGET) data = kwargs.get('data') attachments = data.get('attachments') if data else None From e4685de45984360cbd953b70b9a9f5714507aa4b Mon Sep 17 00:00:00 2001 From: Keith Lamprecht Date: Wed, 12 Oct 2016 00:59:34 -0400 Subject: [PATCH 13/13] Restore Optional Target Config Attribute (notify.pushover) (#3769) * Restore Optional Target Config Attribute * Fix Tabs * Change indents to spaces * Make a target fix * Change to simpler not syntax --- homeassistant/components/notify/pushover.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/notify/pushover.py b/homeassistant/components/notify/pushover.py index bd7542c21cd..04aa7627963 100644 --- a/homeassistant/components/notify/pushover.py +++ b/homeassistant/components/notify/pushover.py @@ -63,6 +63,9 @@ class PushoverNotificationService(BaseNotificationService): targets = kwargs.get(ATTR_TARGET) + if not isinstance(targets, list): + targets = [targets] + for target in targets: if target is not None: data['device'] = target