Skip to content

Commit

Permalink
add config panel for recorder
Browse files Browse the repository at this point in the history
  • Loading branch information
sanyatuning committed Dec 22, 2021
1 parent eda9291 commit 98b5da3
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 46 deletions.
87 changes: 44 additions & 43 deletions homeassistant/components/recorder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import voluptuous as vol

from homeassistant.components import persistent_notification
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_EXCLUDE,
Expand Down Expand Up @@ -55,7 +56,13 @@

from . import history, migration, purge, statistics, websocket_api
from .const import (
CONF_AUTO_PURGE,
CONF_COMMIT_INTERVAL,
CONF_DB_INTEGRITY_CHECK,
CONF_DB_MAX_RETRIES,
CONF_DB_RETRY_WAIT,
CONF_DB_URL,
CONF_PURGE_KEEP_DAYS,
DATA_INSTANCE,
DOMAIN,
MAX_QUEUE_BACKLOG,
Expand Down Expand Up @@ -129,14 +136,8 @@
DB_LOCK_TIMEOUT = 30
DB_LOCK_QUEUE_CHECK_TIMEOUT = 1

CONF_AUTO_PURGE = "auto_purge"
CONF_DB_URL = "db_url"
CONF_DB_MAX_RETRIES = "db_max_retries"
CONF_DB_RETRY_WAIT = "db_retry_wait"
CONF_PURGE_KEEP_DAYS = "purge_keep_days"
CONF_PURGE_INTERVAL = "purge_interval"
CONF_EVENT_TYPES = "event_types"
CONF_COMMIT_INTERVAL = "commit_interval"

INVALIDATED_ERR = "Database connection invalidated"
CONNECTIVITY_ERR = "Error in database connectivity during commit"
Expand Down Expand Up @@ -236,33 +237,29 @@ def run_information_with_session(session, point_in_time: datetime | None = None)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the recorder."""
hass.data[DOMAIN] = {}
conf = config[DOMAIN]
entity_filter = convert_include_exclude_filter(conf)
auto_purge = conf[CONF_AUTO_PURGE]
keep_days = conf[CONF_PURGE_KEEP_DAYS]
commit_interval = conf[CONF_COMMIT_INTERVAL]
db_max_retries = conf[CONF_DB_MAX_RETRIES]
db_retry_wait = conf[CONF_DB_RETRY_WAIT]
db_url = conf.get(CONF_DB_URL) or DEFAULT_URL.format(
hass_config_path=hass.config.path(DEFAULT_DB_FILE)
)
exclude = conf[CONF_EXCLUDE]
if not hass.config_entries.async_entries(DOMAIN):
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=(config[DOMAIN])
)
)
return True


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
) -> bool:
"""Set up the recorder."""
exclude = config_entry.data[CONF_EXCLUDE]
exclude_t = exclude.get(CONF_EVENT_TYPES, [])
if EVENT_STATE_CHANGED in exclude_t:
_LOGGER.warning(
"State change events are excluded, recorder will not record state changes."
"This will become an error in Home Assistant Core 2022.2"
)
instance = hass.data[DATA_INSTANCE] = Recorder(
hass=hass,
auto_purge=auto_purge,
keep_days=keep_days,
commit_interval=commit_interval,
uri=db_url,
db_max_retries=db_max_retries,
db_retry_wait=db_retry_wait,
entity_filter=entity_filter,
exclude_t=exclude_t,
hass=hass, config_entry=config_entry, exclude_t=exclude_t
)
instance.async_initialize()
instance.start()
Expand Down Expand Up @@ -484,36 +481,32 @@ class Recorder(threading.Thread):
stop_requested: bool

def __init__(
self,
hass: HomeAssistant,
auto_purge: bool,
keep_days: int,
commit_interval: int,
uri: str,
db_max_retries: int,
db_retry_wait: int,
entity_filter: Callable[[str], bool],
exclude_t: list[str],
self, hass: HomeAssistant, config_entry: ConfigEntry, exclude_t: list[str]
) -> None:
"""Initialize the recorder."""
threading.Thread.__init__(self, name="Recorder")

self.hass = hass
self.auto_purge = auto_purge
self.keep_days = keep_days
self.commit_interval = commit_interval
self.config_entry = config_entry

conf = dict(config_entry.data)
self.auto_purge = conf[CONF_AUTO_PURGE]
self.keep_days = conf[CONF_PURGE_KEEP_DAYS]
self.commit_interval = conf[CONF_COMMIT_INTERVAL]
self.queue: queue.SimpleQueue[RecorderTask] = queue.SimpleQueue()
self.recording_start = dt_util.utcnow()
self.db_url = uri
self.db_max_retries = db_max_retries
self.db_retry_wait = db_retry_wait
self.db_url = conf.get(CONF_DB_URL) or DEFAULT_URL.format(
hass_config_path=hass.config.path(DEFAULT_DB_FILE)
)
self.db_max_retries = conf[CONF_DB_MAX_RETRIES]
self.db_retry_wait = conf[CONF_DB_RETRY_WAIT]
self.async_db_ready: asyncio.Future = asyncio.Future()
self.async_recorder_ready = asyncio.Event()
self._queue_watch = threading.Event()
self.engine: Any = None
self.run_info: Any = None

self.entity_filter = entity_filter
self.entity_filter = convert_include_exclude_filter(conf)
self.exclude_t = exclude_t

self._timechanges_seen = 0
Expand All @@ -533,6 +526,14 @@ def __init__(

self.enabled = True

def update_config(self, config_entry: ConfigEntry):
"""Update config in runtime."""
conf = dict(config_entry.data)
self.auto_purge = conf[CONF_AUTO_PURGE]
self.commit_interval = conf[CONF_COMMIT_INTERVAL]
self.entity_filter = convert_include_exclude_filter(conf)
self.keep_days = conf[CONF_PURGE_KEEP_DAYS]

def set_enable(self, enable):
"""Enable or disable recording events and states."""
self.enabled = enable
Expand Down
31 changes: 31 additions & 0 deletions homeassistant/components/recorder/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Config flow to connect with Home Assistant."""
from __future__ import annotations

import logging
from typing import Any

from homeassistant import config_entries
from homeassistant.data_entry_flow import FlowResult

from .const import DOMAIN


@config_entries.HANDLERS.register(DOMAIN)
class RecorderFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Recorder configuration flow."""

@property
def logger(self) -> logging.Logger:
"""Return logger."""
return logging.getLogger(__name__)

async def async_step_import(self, user_input: dict[str, Any]) -> FlowResult:
"""Import data."""
# Only allow 1 instance.
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")

return self.async_create_entry(
title="Recorder",
data=user_input,
)
6 changes: 6 additions & 0 deletions homeassistant/components/recorder/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
SQLITE_URL_PREFIX = "sqlite://"
DOMAIN = "recorder"

CONF_AUTO_PURGE = "auto_purge"
CONF_COMMIT_INTERVAL = "commit_interval"
CONF_DB_URL = "db_url"
CONF_DB_MAX_RETRIES = "db_max_retries"
CONF_DB_RETRY_WAIT = "db_retry_wait"
CONF_DB_INTEGRITY_CHECK = "db_integrity_check"
CONF_PURGE_KEEP_DAYS = "purge_keep_days"

MAX_QUEUE_BACKLOG = 30000

Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/recorder/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"domain": "recorder",
"name": "Recorder",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/recorder",
"requirements": ["sqlalchemy==1.4.27"],
"codeowners": ["@home-assistant/core"],
Expand Down
72 changes: 69 additions & 3 deletions homeassistant/components/recorder/websocket_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""The Energy websocket API."""
"""The Recorder websocket API."""
from __future__ import annotations

import logging
Expand All @@ -7,9 +7,21 @@
import voluptuous as vol

from homeassistant.components import websocket_api
from homeassistant.const import CONF_EXCLUDE, CONF_INCLUDE
from homeassistant.core import HomeAssistant, callback

from .const import DATA_INSTANCE, MAX_QUEUE_BACKLOG
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entityfilter import INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER

from .const import (
CONF_AUTO_PURGE,
CONF_COMMIT_INTERVAL,
CONF_DB_MAX_RETRIES,
CONF_DB_RETRY_WAIT,
CONF_DB_URL,
CONF_PURGE_KEEP_DAYS,
DATA_INSTANCE,
MAX_QUEUE_BACKLOG,
)
from .statistics import validate_statistics
from .util import async_migration_in_progress

Expand All @@ -26,10 +38,64 @@ def async_setup(hass: HomeAssistant) -> None:
websocket_api.async_register_command(hass, ws_clear_statistics)
websocket_api.async_register_command(hass, ws_update_statistics_metadata)
websocket_api.async_register_command(hass, ws_info)
websocket_api.async_register_command(hass, ws_config)
websocket_api.async_register_command(hass, ws_update_config)
websocket_api.async_register_command(hass, ws_backup_start)
websocket_api.async_register_command(hass, ws_backup_end)


@websocket_api.websocket_command(
{
vol.Required("type"): "recorder/config",
}
)
@callback
def ws_config(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
) -> None:
"""Return config of the recorder."""
instance: Recorder = hass.data[DATA_INSTANCE]
connection.send_result(msg["id"], dict(instance.config_entry.data))


@websocket_api.websocket_command(
{
vol.Required("type"): "recorder/update_config",
vol.Required("config"): vol.Schema(
{
vol.Optional(CONF_AUTO_PURGE): cv.boolean,
vol.Optional(CONF_COMMIT_INTERVAL): cv.positive_int,
vol.Optional(CONF_DB_URL): cv.string,
vol.Optional(CONF_DB_MAX_RETRIES): cv.positive_int,
vol.Optional(CONF_DB_RETRY_WAIT): cv.positive_int,
vol.Optional(CONF_EXCLUDE): INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER,
vol.Optional(CONF_INCLUDE): INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER,
vol.Optional(CONF_PURGE_KEEP_DAYS): vol.All(
vol.Coerce(int), vol.Range(min=1)
),
}
),
}
)
@callback
def ws_update_config(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
) -> None:
"""Update the recoder config."""
instance: Recorder = hass.data[DATA_INSTANCE]
config_entry = instance.config_entry
data_to_save = {**config_entry.data, **msg["config"]}
_LOGGER.warning(
"Updating Recorder configuration from %s to %s",
config_entry.data,
data_to_save,
)

hass.config_entries.async_update_entry(config_entry, data=data_to_save)
instance.update_config(config_entry)
connection.send_result(msg["id"])


@websocket_api.websocket_command(
{
vol.Required("type"): "recorder/validate_statistics",
Expand Down
1 change: 1 addition & 0 deletions homeassistant/generated/config_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@
"rainmachine",
"rdw",
"recollect_waste",
"recorder",
"renault",
"rfxtrx",
"ridwell",
Expand Down

0 comments on commit 98b5da3

Please sign in to comment.