Add enable and disable services for recorder (#45778)

This commit is contained in:
adrian-vlad 2021-02-24 15:26:05 +02:00 committed by GitHub
parent 470121e5b0
commit 44293a3738
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 191 additions and 2 deletions

View File

@ -48,6 +48,8 @@ from .util import (
_LOGGER = logging.getLogger(__name__)
SERVICE_PURGE = "purge"
SERVICE_ENABLE = "enable"
SERVICE_DISABLE = "disable"
ATTR_KEEP_DAYS = "keep_days"
ATTR_REPACK = "repack"
@ -58,6 +60,8 @@ SERVICE_PURGE_SCHEMA = vol.Schema(
vol.Optional(ATTR_REPACK, default=False): cv.boolean,
}
)
SERVICE_ENABLE_SCHEMA = vol.Schema({})
SERVICE_DISABLE_SCHEMA = vol.Schema({})
DEFAULT_URL = "sqlite:///{hass_config_path}"
DEFAULT_DB_FILE = "home-assistant_v2.db"
@ -199,6 +203,23 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
DOMAIN, SERVICE_PURGE, async_handle_purge_service, schema=SERVICE_PURGE_SCHEMA
)
async def async_handle_enable_sevice(service):
instance.set_enable(True)
hass.services.async_register(
DOMAIN, SERVICE_ENABLE, async_handle_enable_sevice, schema=SERVICE_ENABLE_SCHEMA
)
async def async_handle_disable_service(service):
instance.set_enable(False)
hass.services.async_register(
DOMAIN,
SERVICE_DISABLE,
async_handle_disable_service,
schema=SERVICE_DISABLE_SCHEMA,
)
return await instance.async_db_ready
@ -255,6 +276,12 @@ class Recorder(threading.Thread):
self.get_session = None
self._completed_database_setup = None
self.enabled = True
def set_enable(self, enable):
"""Enable or disable recording events and states."""
self.enabled = enable
@callback
def async_initialize(self):
"""Initialize the recorder."""
@ -413,6 +440,9 @@ class Recorder(threading.Thread):
self._commit_event_session_or_recover()
return
if not self.enabled:
return
try:
if event.event_type == EVENT_STATE_CHANGED:
dbevent = Events.from_event(event, event_data="{}")

View File

@ -24,3 +24,9 @@ purge:
default: false
selector:
boolean:
disable:
description: Stop the recording of events and state changes
enabled:
description: Start the recording of events and state changes

View File

@ -8,13 +8,17 @@ from sqlalchemy.exc import OperationalError
from homeassistant.components.recorder import (
CONF_DB_URL,
CONFIG_SCHEMA,
DATA_INSTANCE,
DOMAIN,
SERVICE_DISABLE,
SERVICE_ENABLE,
SERVICE_PURGE,
SQLITE_URL_PREFIX,
Recorder,
run_information,
run_information_from_instance,
run_information_with_session,
)
from homeassistant.components.recorder.const import DATA_INSTANCE, SQLITE_URL_PREFIX
from homeassistant.components.recorder.models import Events, RecorderRuns, States
from homeassistant.components.recorder.util import session_scope
from homeassistant.const import (
@ -24,7 +28,7 @@ from homeassistant.const import (
STATE_UNLOCKED,
)
from homeassistant.core import Context, CoreState, callback
from homeassistant.setup import async_setup_component
from homeassistant.setup import async_setup_component, setup_component
from homeassistant.util import dt as dt_util
from .common import async_wait_recording_done, corrupt_db_file, wait_recording_done
@ -518,6 +522,155 @@ def test_run_information(hass_recorder):
assert run_info.closed_incorrect is False
def test_has_services(hass_recorder):
"""Test the services exist."""
hass = hass_recorder()
assert hass.services.has_service(DOMAIN, SERVICE_DISABLE)
assert hass.services.has_service(DOMAIN, SERVICE_ENABLE)
assert hass.services.has_service(DOMAIN, SERVICE_PURGE)
def test_service_disable_events_not_recording(hass, hass_recorder):
"""Test that events are not recorded when recorder is disabled using service."""
hass = hass_recorder()
assert hass.services.call(
DOMAIN,
SERVICE_DISABLE,
{},
blocking=True,
)
event_type = "EVENT_TEST"
events = []
@callback
def event_listener(event):
"""Record events from eventbus."""
if event.event_type == event_type:
events.append(event)
hass.bus.listen(MATCH_ALL, event_listener)
event_data1 = {"test_attr": 5, "test_attr_10": "nice"}
hass.bus.fire(event_type, event_data1)
wait_recording_done(hass)
assert len(events) == 1
event = events[0]
with session_scope(hass=hass) as session:
db_events = list(session.query(Events).filter_by(event_type=event_type))
assert len(db_events) == 0
assert hass.services.call(
DOMAIN,
SERVICE_ENABLE,
{},
blocking=True,
)
event_data2 = {"attr_one": 5, "attr_two": "nice"}
hass.bus.fire(event_type, event_data2)
wait_recording_done(hass)
assert len(events) == 2
assert events[0] != events[1]
assert events[0].data != events[1].data
with session_scope(hass=hass) as session:
db_events = list(session.query(Events).filter_by(event_type=event_type))
assert len(db_events) == 1
db_event = db_events[0].to_native()
event = events[1]
assert event.event_type == db_event.event_type
assert event.data == db_event.data
assert event.origin == db_event.origin
assert event.time_fired.replace(microsecond=0) == db_event.time_fired.replace(
microsecond=0
)
def test_service_disable_states_not_recording(hass, hass_recorder):
"""Test that state changes are not recorded when recorder is disabled using service."""
hass = hass_recorder()
assert hass.services.call(
DOMAIN,
SERVICE_DISABLE,
{},
blocking=True,
)
hass.states.set("test.one", "on", {})
wait_recording_done(hass)
with session_scope(hass=hass) as session:
assert len(list(session.query(States))) == 0
assert hass.services.call(
DOMAIN,
SERVICE_ENABLE,
{},
blocking=True,
)
hass.states.set("test.two", "off", {})
wait_recording_done(hass)
with session_scope(hass=hass) as session:
db_states = list(session.query(States))
assert len(db_states) == 1
assert db_states[0].event_id > 0
assert db_states[0].to_native() == _state_empty_context(hass, "test.two")
def test_service_disable_run_information_recorded(tmpdir):
"""Test that runs are still recorded when recorder is disabled."""
test_db_file = tmpdir.mkdir("sqlite").join("test_run_info.db")
dburl = f"{SQLITE_URL_PREFIX}//{test_db_file}"
hass = get_test_home_assistant()
setup_component(hass, DOMAIN, {DOMAIN: {CONF_DB_URL: dburl}})
hass.start()
wait_recording_done(hass)
with session_scope(hass=hass) as session:
db_run_info = list(session.query(RecorderRuns))
assert len(db_run_info) == 1
assert db_run_info[0].start is not None
assert db_run_info[0].end is None
assert hass.services.call(
DOMAIN,
SERVICE_DISABLE,
{},
blocking=True,
)
wait_recording_done(hass)
hass.stop()
hass = get_test_home_assistant()
setup_component(hass, DOMAIN, {DOMAIN: {CONF_DB_URL: dburl}})
hass.start()
wait_recording_done(hass)
with session_scope(hass=hass) as session:
db_run_info = list(session.query(RecorderRuns))
assert len(db_run_info) == 2
assert db_run_info[0].start is not None
assert db_run_info[0].end is not None
assert db_run_info[1].start is not None
assert db_run_info[1].end is None
hass.stop()
class CannotSerializeMe:
"""A class that the JSONEncoder cannot serialize."""