diff --git a/.coveragerc b/.coveragerc index ea9f302fbb1..272ace975c4 100644 --- a/.coveragerc +++ b/.coveragerc @@ -36,6 +36,9 @@ omit = homeassistant/components/rfxtrx.py homeassistant/components/*/rfxtrx.py + homeassistant/components/mysensors.py + homeassistant/components/*/mysensors.py + homeassistant/components/binary_sensor/arest.py homeassistant/components/binary_sensor/rest.py homeassistant/components/browser.py @@ -73,6 +76,7 @@ omit = homeassistant/components/media_player/plex.py homeassistant/components/media_player/sonos.py homeassistant/components/media_player/squeezebox.py + homeassistant/components/notify/free_mobile.py homeassistant/components/notify/instapush.py homeassistant/components/notify/nma.py homeassistant/components/notify/pushbullet.py @@ -92,7 +96,6 @@ omit = homeassistant/components/sensor/eliqonline.py homeassistant/components/sensor/forecast.py homeassistant/components/sensor/glances.py - homeassistant/components/sensor/mysensors.py homeassistant/components/sensor/openweathermap.py homeassistant/components/sensor/rest.py homeassistant/components/sensor/rpi_gpio.py 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/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index 63bc989f3df..2658e005aea 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -68,7 +68,8 @@ class ManualAlarm(alarm.AlarmControlPanel): @property def state(self): """ Returns the state of the device. """ - if self._state in (STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY) and \ + if self._state in (STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_AWAY) and \ self._pending_time and self._state_ts + self._pending_time > \ dt_util.utcnow(): return STATE_ALARM_PENDING 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( 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/components/automation/numeric_state.py b/homeassistant/components/automation/numeric_state.py index f2baf760748..61e68aa8e8e 100644 --- a/homeassistant/components/automation/numeric_state.py +++ b/homeassistant/components/automation/numeric_state.py @@ -6,6 +6,7 @@ Offers numeric state listening automation rules. For more details about this automation rule, please refer to the documentation at https://home-assistant.io/components/automation/#numeric-state-trigger """ +from functools import partial import logging from homeassistant.const import CONF_VALUE_TEMPLATE @@ -20,6 +21,14 @@ CONF_ABOVE = "above" _LOGGER = logging.getLogger(__name__) +def _renderer(hass, value_template, state): + """Render state value.""" + if value_template is None: + return state.state + + return template.render(hass, value_template, {'state': state}) + + def trigger(hass, config, action): """ Listen for state changes based on `config`. """ entity_id = config.get(CONF_ENTITY_ID) @@ -38,12 +47,7 @@ def trigger(hass, config, action): CONF_BELOW, CONF_ABOVE) return False - if value_template is not None: - renderer = lambda value: template.render(hass, - value_template, - {'state': value}) - else: - renderer = lambda value: value.state + renderer = partial(_renderer, hass, value_template) # pylint: disable=unused-argument def state_automation_listener(entity, from_s, to_s): @@ -79,12 +83,7 @@ def if_action(hass, config): CONF_BELOW, CONF_ABOVE) return None - if value_template is not None: - renderer = lambda value: template.render(hass, - value_template, - {'state': value}) - else: - renderer = lambda value: value.state + renderer = partial(_renderer, hass, value_template) def if_numeric_state(): """ Test numeric state condition. """ diff --git a/homeassistant/components/automation/sun.py b/homeassistant/components/automation/sun.py index 064f6a0a16a..0616c0a48e6 100644 --- a/homeassistant/components/automation/sun.py +++ b/homeassistant/components/automation/sun.py @@ -80,18 +80,30 @@ def if_action(hass, config): return None if before is None: - before_func = lambda: None + def before_func(): + """Return no point in time.""" + return None elif before == EVENT_SUNRISE: - before_func = lambda: sun.next_rising(hass) + before_offset + def before_func(): + """Return time before sunrise.""" + return sun.next_rising(hass) + before_offset else: - before_func = lambda: sun.next_setting(hass) + before_offset + def before_func(): + """Return time before sunset.""" + return sun.next_setting(hass) + before_offset if after is None: - after_func = lambda: None + def after_func(): + """Return no point in time.""" + return None elif after == EVENT_SUNRISE: - after_func = lambda: sun.next_rising(hass) + after_offset + def after_func(): + """Return time after sunrise.""" + return sun.next_rising(hass) + after_offset else: - after_func = lambda: sun.next_setting(hass) + after_offset + def after_func(): + """Return time after sunset.""" + return sun.next_setting(hass) + after_offset def time_if(): """ Validate time based if-condition """ diff --git a/homeassistant/components/automation/time.py b/homeassistant/components/automation/time.py index 7fc2c0d40e2..e8cf9c3b6ee 100644 --- a/homeassistant/components/automation/time.py +++ b/homeassistant/components/automation/time.py @@ -32,8 +32,8 @@ def trigger(hass, config, action): _error_time(config[CONF_AFTER], CONF_AFTER) return False hours, minutes, seconds = after.hour, after.minute, after.second - elif (CONF_HOURS in config or CONF_MINUTES in config - or CONF_SECONDS in config): + elif (CONF_HOURS in config or CONF_MINUTES in config or + CONF_SECONDS in config): hours = convert(config.get(CONF_HOURS), int) minutes = convert(config.get(CONF_MINUTES), int) seconds = convert(config.get(CONF_SECONDS), int) diff --git a/homeassistant/components/device_tracker/asuswrt.py b/homeassistant/components/device_tracker/asuswrt.py index b90e1ee4448..472440d7307 100644 --- a/homeassistant/components/device_tracker/asuswrt.py +++ b/homeassistant/components/device_tracker/asuswrt.py @@ -58,8 +58,8 @@ class AsusWrtDeviceScanner(object): def __init__(self, config): self.host = config[CONF_HOST] - self.username = config[CONF_USERNAME] - self.password = config[CONF_PASSWORD] + self.username = str(config[CONF_USERNAME]) + self.password = str(config[CONF_PASSWORD]) self.lock = threading.Lock() 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'] diff --git a/homeassistant/components/device_tracker/snmp.py b/homeassistant/components/device_tracker/snmp.py index 868f701673a..cd0e8239c38 100644 --- a/homeassistant/components/device_tracker/snmp.py +++ b/homeassistant/components/device_tracker/snmp.py @@ -105,8 +105,7 @@ class SnmpScanner(object): return if errstatus: _LOGGER.error('SNMP error: %s at %s', errstatus.prettyPrint(), - errindex and restable[-1][int(errindex)-1] - or '?') + errindex and restable[-1][int(errindex)-1] or '?') return for resrow in restable: diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 46556b3eca4..a661dac0c1e 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -242,8 +242,8 @@ class Tplink3DeviceScanner(TplinkDeviceScanner): _LOGGER.info("Loading wireless clients...") - url = 'http://{}/cgi-bin/luci/;stok={}/admin/wireless?form=statistics' \ - .format(self.host, self.stok) + url = ('http://{}/cgi-bin/luci/;stok={}/admin/wireless?' + 'form=statistics').format(self.host, self.stok) referer = 'http://{}/webpages/index.html'.format(self.host) response = requests.post(url, diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 2ded702dc6b..67454d11974 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -1,2 +1,2 @@ """ DO NOT MODIFY. Auto-generated by build_frontend script """ -VERSION = "72a8220d0db0f7f3702228cd556b8c40" +VERSION = "63d38b69fc6582e75f892abc140a893a" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index edc9635dbf4..86e5daca0aa 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -275,7 +275,7 @@ var n=this._rootDataHost;return n?n._scopeElementClass(t,e):void 0},stamp:functi html /deep/ .fixed-right { top: 0; right: 0; - bottom: 0; + botttom: 0; } html /deep/ .fixed-bottom { @@ -286,7 +286,7 @@ var n=this._rootDataHost;return n?n._scopeElementClass(t,e):void 0},stamp:functi html /deep/ .fixed-left { top: 0; - bottom: 0; + botttom: 0; left: 0; }