diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 9a2cc400d5c..3a91e972a70 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -3,7 +3,7 @@ FINGERPRINTS = { "compatibility.js": "83d9c77748dafa9db49ae77d7f3d8fb0", "core.js": "1f7f88d8f5dada08bce1d935cfa5f33e", - "frontend.html": "be258a53166b82f4ebd5232037e1cbd5", + "frontend.html": "ca9efa7e4506aa6b1a668703c8d0f800", "mdi.html": "c1dde43ccf5667f687c418fc8daf9668", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-config.html": "412b3e24515ffa1ee8074ce974cf4057", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 83d93603f21..0de54ad7c77 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -73,7 +73,7 @@ window.hassUtil.dynamicContentUpdater = function (root, newElementTag, attribute var rootEl = Polymer.dom(root); var customEl; - if (rootEl.lastChild && rootEl.lastChild.tagName.toLowerCase() === newElementTag) { + if (rootEl.lastChild && rootEl.lastChild.tagName === newElementTag) { customEl = rootEl.lastChild; } else { if (rootEl.lastChild) { @@ -722,4 +722,4 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th this.hass.callService('media_player', service, serviceData); }, }); -}()); \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 3335cdcb436..396ea6fa8a1 100644 Binary files a/homeassistant/components/frontend/www_static/frontend.html.gz and b/homeassistant/components/frontend/www_static/frontend.html.gz differ diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 5d223c8da4b..e509ed07a08 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 5d223c8da4b4380bf79d8f0285ce7824063e89ef +Subproject commit e509ed07a08d35152b9eea6e263411dfc027867b diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index beae637f6ea..0bc47086c6b 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","98cfb1f23c1a1b783c1afe58d3f57bc9"],["/frontend/panels/dev-event-91347dedf3b4fa9b49ccf4c0a28a03c4.html","f74c44ab9bfbdc81badb56518ef8113d"],["/frontend/panels/dev-info-61610e015a411cfc84edd2c4d489e71d.html","6568377ee31cbd78fedc003b317f7faf"],["/frontend/panels/dev-service-a9247f255174b084fad2c04bdb9ec7a9.html","4d5f34f8ebc6c5fc4bdcff1ef7b4eb35"],["/frontend/panels/dev-state-90f3bede9602241552ef7bb7958198c6.html","277716ed9b76fa4313a1653dc757741b"],["/frontend/panels/dev-template-c249a4fc18a3a6994de3d6330cfe6cbb.html","8d7eaec6389ea1417cec667798740399"],["/frontend/panels/map-e10704a3469e44d1714eac9ed8e4b6a0.html","b9528c06194ad4b8b22e369fe4211500"],["/static/compatibility-83d9c77748dafa9db49ae77d7f3d8fb0.js","5f05c83be2b028d577962f9625904806"],["/static/core-1f7f88d8f5dada08bce1d935cfa5f33e.js","8a58624e6ea5958e817bf6cd5658e3a2"],["/static/frontend-be258a53166b82f4ebd5232037e1cbd5.html","d1beaa80677d302b41c7eb1ffff49296"],["/static/mdi-c1dde43ccf5667f687c418fc8daf9668.html","6a3c9317736ca26e3390316335be9ba5"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","32b5a9b7ada86304bec6b43d3f2194f0"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.toString().match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a))return e.add(new Request(a,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);var n="index.html";!t&&n&&(a=addDirectoryIndex(a,n),t=urlsToCacheKeys.has(a));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,n;for(a=0;a None: +@asyncio.coroutine +def async_get_instance(): + """Throw error if recorder not initialized.""" + if _INSTANCE is None: + raise RuntimeError("Recorder not initialized.") + + yield from _INSTANCE.async_db_ready.wait() + + return _INSTANCE + + +def get_instance(): """Throw error if recorder not initialized.""" if _INSTANCE is None: raise RuntimeError("Recorder not initialized.") @@ -200,7 +212,7 @@ class Recorder(threading.Thread): self.recording_start = dt_util.utcnow() self.db_url = uri self.db_ready = threading.Event() - self.start_recording = threading.Event() + self.async_db_ready = asyncio.Event(loop=hass.loop) self.engine = None # type: Any self._run = None # type: Any @@ -209,11 +221,6 @@ class Recorder(threading.Thread): self.exclude = exclude.get(CONF_ENTITIES, []) + \ exclude.get(CONF_DOMAINS, []) - def start_recording(event): - """Start recording.""" - self.start_recording.set() - - hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_recording) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, self.shutdown) hass.bus.listen(MATCH_ALL, self.event_listener) @@ -229,6 +236,7 @@ class Recorder(threading.Thread): self._setup_connection() self._setup_run() self.db_ready.set() + self.async_db_ready.set() break except SQLAlchemyError as err: _LOGGER.error("Error during connection setup: %s (retrying " @@ -239,8 +247,6 @@ class Recorder(threading.Thread): async_track_time_interval( self.hass, self._purge_old_data, timedelta(days=2)) - _wait(self.start_recording, "Waiting to start recording") - while True: event = self.queue.get() @@ -297,9 +303,6 @@ class Recorder(threading.Thread): """Tell the recorder to shut down.""" global _INSTANCE # pylint: disable=global-statement self.queue.put(None) - if not self.start_recording.is_set(): - _LOGGER.warning("Recorder never started correctly") - self.start_recording.set() self.join() _INSTANCE = None @@ -505,7 +508,7 @@ def _wait(event, message): event.wait(10) if event.is_set(): return - msg = message + " ({} seconds)".format(retry) + msg = "{} ({} seconds)".format(message, retry) _LOGGER.warning(msg) if not event.is_set(): raise HomeAssistantError(msg) diff --git a/homeassistant/helpers/restore_state.py b/homeassistant/helpers/restore_state.py index 1e463d316d4..86cd3e7037f 100644 --- a/homeassistant/helpers/restore_state.py +++ b/homeassistant/helpers/restore_state.py @@ -6,7 +6,8 @@ from datetime import timedelta from homeassistant.core import HomeAssistant, CoreState, callback from homeassistant.const import EVENT_HOMEASSISTANT_START from homeassistant.components.history import get_states, last_recorder_run -from homeassistant.components.recorder import DOMAIN as _RECORDER +from homeassistant.components.recorder import ( + async_get_instance, DOMAIN as _RECORDER) import homeassistant.util.dt as dt_util _LOGGER = logging.getLogger(__name__) @@ -57,6 +58,8 @@ def async_get_last_state(hass, entity_id: str): hass.state) return None + yield from async_get_instance() # Ensure recorder ready + if _LOCK not in hass.data: hass.data[_LOCK] = asyncio.Lock(loop=hass.loop) diff --git a/tests/helpers/test_restore_state.py b/tests/helpers/test_restore_state.py index d411ef2073a..3a4c058f853 100644 --- a/tests/helpers/test_restore_state.py +++ b/tests/helpers/test_restore_state.py @@ -11,7 +11,8 @@ from homeassistant.components import input_boolean, recorder from homeassistant.helpers.restore_state import ( async_get_last_state, DATA_RESTORE_CACHE) -from tests.common import get_test_home_assistant, init_recorder_component +from tests.common import ( + get_test_home_assistant, mock_coro, init_recorder_component) @asyncio.coroutine @@ -29,7 +30,9 @@ def test_caching_data(hass): with patch('homeassistant.helpers.restore_state.last_recorder_run', return_value=MagicMock(end=dt_util.utcnow())), \ patch('homeassistant.helpers.restore_state.get_states', - return_value=states): + return_value=states), \ + patch('homeassistant.helpers.restore_state.async_get_instance', + return_value=mock_coro()): state = yield from async_get_last_state(hass, 'input_boolean.b1') assert DATA_RESTORE_CACHE in hass.data