Add SQLite dashboard cache
This commit is contained in:
98
app/actuators/cache_db.py
Normal file
98
app/actuators/cache_db.py
Normal file
@@ -0,0 +1,98 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from threading import RLock
|
||||
|
||||
from app.ha.models import HaEntitySummary
|
||||
|
||||
|
||||
class DashboardCache:
|
||||
def __init__(self, path: str | Path) -> None:
|
||||
self._path = Path(path).resolve()
|
||||
self._path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self._lock = RLock()
|
||||
self._init()
|
||||
|
||||
def load_entities_payload(self) -> dict[str, object]:
|
||||
with self._lock, self._connect() as connection:
|
||||
rows = connection.execute(
|
||||
"select entity_id, payload from ha_entities order by entity_id"
|
||||
).fetchall()
|
||||
updated_at = self._get_meta(connection, "ha_entities_updated_at")
|
||||
groups_json = self._get_meta(connection, "discovery_groups") or "[]"
|
||||
try:
|
||||
groups = json.loads(groups_json)
|
||||
except ValueError:
|
||||
groups = []
|
||||
return {
|
||||
"updated_at": updated_at,
|
||||
"discovery_groups": groups if isinstance(groups, list) else [],
|
||||
"entities": [json.loads(row[1]) for row in rows],
|
||||
}
|
||||
|
||||
def save_entities_payload(
|
||||
self,
|
||||
*,
|
||||
entities: list[HaEntitySummary],
|
||||
discovery_groups: list[dict[str, object]],
|
||||
) -> None:
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
rows = [
|
||||
(entity.entity_id, entity.model_dump_json())
|
||||
for entity in entities
|
||||
]
|
||||
with self._lock, self._connect() as connection:
|
||||
connection.execute("delete from ha_entities")
|
||||
connection.executemany(
|
||||
"insert into ha_entities(entity_id, payload) values (?, ?)",
|
||||
rows,
|
||||
)
|
||||
self._set_meta(connection, "ha_entities_updated_at", now)
|
||||
self._set_meta(
|
||||
connection,
|
||||
"discovery_groups",
|
||||
json.dumps(discovery_groups, ensure_ascii=True, sort_keys=True),
|
||||
)
|
||||
|
||||
def _init(self) -> None:
|
||||
with self._connect() as connection:
|
||||
connection.execute(
|
||||
"""
|
||||
create table if not exists ha_entities (
|
||||
entity_id text primary key,
|
||||
payload text not null
|
||||
)
|
||||
"""
|
||||
)
|
||||
connection.execute(
|
||||
"""
|
||||
create table if not exists cache_meta (
|
||||
key text primary key,
|
||||
value text
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
def _connect(self) -> sqlite3.Connection:
|
||||
return sqlite3.connect(self._path, timeout=30)
|
||||
|
||||
@staticmethod
|
||||
def _get_meta(connection: sqlite3.Connection, key: str) -> str | None:
|
||||
row = connection.execute(
|
||||
"select value from cache_meta where key = ?",
|
||||
(key,),
|
||||
).fetchone()
|
||||
return str(row[0]) if row is not None and row[0] is not None else None
|
||||
|
||||
@staticmethod
|
||||
def _set_meta(connection: sqlite3.Connection, key: str, value: str) -> None:
|
||||
connection.execute(
|
||||
"""
|
||||
insert into cache_meta(key, value) values (?, ?)
|
||||
on conflict(key) do update set value = excluded.value
|
||||
""",
|
||||
(key, value),
|
||||
)
|
||||
Reference in New Issue
Block a user