Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions homeassistant/components/recorder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/recorder/
"""
import asyncio
import logging
import queue
import threading
Expand All @@ -20,7 +21,7 @@
from homeassistant.core import HomeAssistant, callback, split_entity_id
from homeassistant.const import (
ATTR_ENTITY_ID, CONF_ENTITIES, CONF_EXCLUDE, CONF_DOMAINS,
CONF_INCLUDE, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
CONF_INCLUDE, EVENT_HOMEASSISTANT_STOP,
EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL)
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
Expand Down Expand Up @@ -83,7 +84,18 @@ def session_scope():
session.close()


def get_instance() -> 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.")
Expand Down Expand Up @@ -200,7 +212,7 @@ def __init__(self, hass: HomeAssistant, purge_days: int, uri: str,
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

Expand All @@ -209,11 +221,6 @@ def __init__(self, hass: HomeAssistant, purge_days: int, uri: str,
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)

Expand All @@ -229,6 +236,7 @@ def run(self):
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 "
Expand All @@ -239,8 +247,6 @@ def run(self):
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()

Expand Down Expand Up @@ -297,9 +303,6 @@ def shutdown(self, event):
"""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

Expand Down Expand Up @@ -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)
5 changes: 4 additions & 1 deletion homeassistant/helpers/restore_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
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__)
Expand Down Expand Up @@ -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)

Expand Down
7 changes: 5 additions & 2 deletions tests/helpers/test_restore_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
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
Expand All @@ -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
Expand Down