HA - SQLite Insights: Datenbank-Layout / Beispiel-SQL-Queries
Um bessere SQL-Abfragen zusammenstellen zu können, habe ich mir das Datenbankschema von Home-Assistant nĂ€her angesehen. ZunĂ€chst hauptsĂ€chlich um bestimmte historische Daten zu korrigieren, spĂ€ter um die Energievorhersage meiner PV-Anlage zu verbessern, was eine effizientere Steuerung der Heizung ermöglicht. Details zu den Abfragen fĂŒr die PV-Prognose folgen in einem gesonderten Artikel..
Mittels SQL-Query können direkte Abfragen oder Ănderungen an der Datenbank vorgenommen werden:
Siehe auch die unterschiedlichen Möglichkeiten fĂŒr einen direkten Zugriff auf dei Datenbank: 3 Varianten: SQLite Datenbank Zugriff - Home Assistant.
Ein Blick in SQLite3 Editor in VSCode, zeigt die einzelnen Tabellen und deren Beziehungen.
Interessant fĂŒr aktuelle Daten innerhalb von 10 Tagen ist die Tabelle "states". Die Tabelle "statistics" liefert auch Ă€ltere Daten: Pro Stunde einen Wert.Â
 | Tabellenname | Zweck |
---|---|---|
States (alle aktuellen Statusinformationen: bis 10 Tage) | states_meta | Liste aller EntitĂ€ten: Eindeutige Kennung (entity_id), Beispiel sensor.temperatur und die zugehörige interne Datenbank-id in Form einer fortlaufenden Nummer (metadata_id). Die Tabelle ĂŒbersetzt die metadata_id auf die entity_id |
states | Alle Statusinformationen aller EntitÀten: Verwendet die id aus states_meta. | |
Statistik und LTS / Langzeitstatistik | statistics_meta |
Liste aller EntitÀten mit Statistikdaten: id zu entity_id (z.B. sensor.temperatur). |
statistics |
Alle LTS-Statusinformationen (Pro Stunde ein Wert, gespeichert auch lÀnger als 10 Tage). Verwendet die id aus statistics_meta. Handelt es sich bei dem Sensor nicht um einen fortlaufenden ZÀhler, sondern einen ZÀhler vom Typ Messung (Eigenschaft: state_class=measurement), wird neben dem Durchschnittswert auch ein Maximal und Minimal-Wert gespeichert. |
|
statistiscs_short_term |
Statusinformationen der letzten 10 Tage im 5-Minutentakt. Verwendet die id aus statistics_meta. Handelt es sich bei dem Sensor nicht um einen fortlaufenden ZĂ€hler, sondern einen ZĂ€hler vom Typ Messung (Eigenschaft: state_class=measurement), wird neben dem Durchschnittswert auch ein Maximal und Minimal-Wert gespeichert. |
States- Daten (aktuelle Werte aller EntitÀten)
Die eindeutigen Kennungen (entity_id) aller EntitÀten sind in der Tabelle "states_meta" gelistet:
id | metadata_id | entity_id |
---|---|---|
1 | 20 | sensor.pv_spannung_dc |
2 | 21 | sensor.pv_strom_dc |
3 | 22 | sensor.pv_leistung_ac |
Die eigentlichen Werte der EntitÀten werden in der Tabelle "states" gespeichert, darin unter Verwendung der metadata_id:
state_id | state | last_changed_ts | last_reported_ts | last_updated_ts | attributes_id | metadata_id |
1 | 800.00 | 1743775748.382725 | 1743775743.2130053 | 1743775743.2130053 | 1 | 20 |
2 | 810.00 | 1743775848.382725 | 1743775843.2130053 | 1743775843.2130053 | 2 | 20 |
3 | 799.10 | 1743775948.382725 | 1743775943.2130053 | 1743775943.2130053 | 3 | 20 |
Die gelisteten Werte in diesem Beispiel gehören also alle zu "sensor.pv_spannung_dc", da die metadata_id "20" verwendet wird und diese in states_meta auf "sensor.pv_spannung_dc" ĂŒbersetzt wird. Die attributes_id verweist auf einen zusĂ€tzlichen Eintrag in der Tabelle "state_attributes". Ăber eine angepasste SQL-Abfrage können die Daten der 3 Tabelle zusammengefasst und in einem lesbaren Format ausgegeben werden:
Letzte Stunde, alle Status - Daten aller EntitĂ€ten inklusive entity_id und shared_attrs:Â
Folgende Query listet sÀmtliche Statusinformationen aller EntitÀten der letzten Stunde:
SELECT STRFTIME('%Y.%m.%d %H:%M', datetime(last_updated_ts, 'unixepoch', 'localtime')) AS date,
states_meta.entity_id,
states.state,
shared_attrs
FROM states
INNER JOIN states_meta ON states_meta.metadata_id = states.metadata_id
INNER JOIN state_attributes ON state_attributes.attributes_id = states.attributes_id
WHERE last_updated_ts BETWEEN strftime('%s', 'now', '-1 hour') AND strftime('%s', 'now')
Aktueller Status fĂŒr eine bestimmte EntitĂ€t
SQL-Query:
select datetime(last_updated_ts, 'unixepoch', 'localtime') AS readabledate,state from states where metadata_id = ( SELECT metadata_id FROM states_meta
WHERE entity_id = 'sensor.flowmeter_sum') order by last_updated_ts desc limit 10;
Ausgabe:
readabledate | state |
---|---|
2025-04-04 14:17:38 | 5812.24 |
2025-04-04 14:07:08 | 5812.23 |
2025-04-04 13:55:26 | 5812.22 |
Aktueller Status fĂŒr eine bestimmte EntitĂ€t inklusive shared_attrs
ZusĂ€tzlich zum aktuellen Status (state) besitzen bestimmte EntitĂ€ten zusĂ€tzliche Eigenschaften, abgelegt in einer zusĂ€tzlichen Spalte: shared_attrs. FĂŒr das Auslesen einer EntitĂ€t und deren zusĂ€tzlichen Eigenschaften (shated_attrs) kann die folgende Query verwendet werden:
SELECT STRFTIME('%Y.%m.%d %H:%M',datetime(last_updated_ts, 'unixepoch', 'localtime')) as readabledate,states_meta.entity_id,states.state,shared_attrs FROM states
INNER JOIN states_meta ON states_meta.metadata_id = states.metadata_id
INNER JOIN state_attributes ON state_attributes.attributes_id = states.attributes_id
WHERE states_meta.entity_id = 'sensor.fronius_storage_chast' order by last_updated_ts DESC limit 1
Ausgabe:
readabledate | entity_id | state | shared_attrs |
---|---|---|---|
2025.04.04 13:38 | sensor.fronius_storage_chast | FULL | {"integration":"sunspec","suns ... |
Status einer bestimmten EntitÀt zu einem bestimmten Zeitpunkt, als Beispiel gestern zur selben Zeit
SQL-Query
SELECT STRFTIME('%Y.%m.%d %H:%M',datetime(last_updated_ts, 'unixepoch', 'localtime')) as date,states_meta.entity_id,states.state,shared_attrs FROM states
INNER JOIN states_meta ON states_meta.metadata_id = states.metadata_id
INNER JOIN state_attributes ON state_attributes.attributes_id = states.attributes_id
WHERE states_meta.entity_id = 'sensor.fronius_storage_chast' and
last_updated_ts < (SELECT unixepoch(datetime('now'),'-1 days')) order by last_updated_ts DESC limit 1
Ausgabe:
date | entity_id | state | shared_attrs |
---|---|---|---|
2025.04.03 12:46 | sensor.fronius_storage_chast | FULL | {"integration":"sunspec","suns ... |
EntitÀten mit zusÀtzlichen Daten in shared_attrs: z.B. Wetterdaten
Die folgende Abfrage ruft die letzten zehn DatensÀtze zur EntitÀt "weather.home" ab. Enthalten sind das formatierte Datum, die EntitÀts-ID, der Zustand und gemeinsame Attribute aus der shared_attrs- Tabelle. Die Ergebnisse wurden in folgender SQL-Abfrage nach dem letzten Aktualisierungszeitpunkt sortiert:
SELECT STRFTIME('%Y.%m.%d %H:%M',datetime(last_updated_ts, 'unixepoch', 'localtime')) as readabledate,states_meta.entity_id,states.state,shared_attrs FROM states
INNER JOIN states_meta ON states_meta.metadata_id = states.metadata_id
INNER JOIN state_attributes ON state_attributes.attributes_id = states.attributes_id
WHERE states_meta.entity_id like '%weather.home' and
last_updated_ts < (SELECT unixepoch(datetime('now'),'-0 days')) order by last_updated_ts DESC limit 10
Ausgabe:
readabledate | entity_id | state | shared_attrs |
---|---|---|---|
2025.04.04 13:38 | weather.home | sunny | {"temperature":18.9,"dew_point":8.8,"temperature_unit":"°C","humidity":52,"cloud_coverage":0.0,"uv_index":3.2,"pressure":1017.7,"pressure_unit":"hPa","wind_bearing":61.7,"wind_speed":15.5,"wind_speed_unit":"km/h","visibility_unit":"km","precipitation_unit":"mm","friendly_name":"Forecast Home"}... |
2025.04.04 13:27 | weather.home | sunny | {"temperature":18.9,"dew_point":8.8,"temperature_unit":"°C","humidity":52,"cloud_coverage":0.0,"uv_index":3.2,"pressure":1017.7,"pressure_unit":"hPa","wind_bearing":61.7,"wind_speed":15.5,"wind_speed_unit":"km/h","visibility_unit":"km","precipitation_unit":"mm","friendly_name":"Forecast Home"}... |
2025.04.04 12:26 | weather.home | sunny | {"temperature":18.7,"dew_point":8.0,"temperature_unit":"°C","humidity":50,"cloud_coverage":0.0,"uv_index":4.0,"pressure":1018.5,"pressure_unit":"hPa","wind_bearing":63.1,"wind_speed":15.8,"wind_speed_unit":"km/h","visibility_unit":"km","precipitation_unit":"mm","friendly_name":"Forecast Home"}... |
Um bestimmte Werte aus der Spalte shared_attrs als eigene Spalten anzuzeigen, können die JSON-Daten mit folgender SQL-Abfrage extrahiert werden:Â
SELECT STRFTIME('%Y.%m.%d %H:%M',datetime(last_updated_ts, 'unixepoch', 'localtime')) as readabledate,states_meta.entity_id,states.state,json_extract(shared_attrs, '$.temperature') AS temperature,json_extract(shared_attrs, '$.cloud_coverage') AS cloud_coverage, shared_attrs FROM states
INNER JOIN states_meta ON states_meta.metadata_id = states.metadata_id
INNER JOIN state_attributes ON state_attributes.attributes_id = states.attributes_id
WHERE states_meta.entity_id like '%weather.home' and
last_updated_ts < (SELECT unixepoch(datetime('now'),'-0 days')) order by last_updated_ts DESC limit 10
Ausgabe:
readabledate | entity_id | state | temperature | cloud_coverage | shared_attrs |
---|---|---|---|---|---|
2025.04.04 13:38 | weather.home | sunny | 18.9 | 0.0 | {"temperature":18.9,"dew_point":8. ... |
2025.04.04 13:27 | weather.home | sunny | 18.9 | 0.0 | {"temperature":18.9,"dew_point":8. ... |
2025.04.04 12:26 | weather.home | sunny | 18.7 | 0.0 | {"temperature":18.7,"dew_point":8. ... |
Historische Daten: Werte von den Statistik-Tabellen
Wie auch die Status-Tabelle verwenden die Statistik-Tabellen nicht direkt die eindeutige EntitĂ€ts-ID (z.B. sensor.temperatur), sondern eine Meta-Tabelle (statistics_meta) fĂŒr die Ăbersetzung der EintitĂ€ts-ID (Spalte: statistic_id) auf eine id (Nummer)
id | statistic_id | source | unit_of_measurement | has_mean | has_sum | name | mean_type |
---|---|---|---|---|---|---|---|
1 | sensor.openweathermap_temperature | recorder | °C | NULL |
False | NULL |
1 |
30 | sensor.displaykueche_power | recorder | W | NULL |
False | NULL |
1 |
88 | sensor.grid_consumption_energy | recorder | Wh | NULL |
True | NULL |
0 |
Alternativ zur Status-Tabelle (states), können die Werte einer bestimmten EntitĂ€t ĂŒber eine SQL-Query aus der Tabelle "statistics" gelesen werden. Die metatdata_id wird auch hier ĂŒber eine Sub-Query aus der Tabelle statistics_meta ĂŒbersetzt:
Datenbank Query:
select datetime(created_ts, 'unixepoch', 'localtime') AS readabledate, * from statistics WHERE metadata_id = ( SELECT id FROM statistics_meta WHERE statistic_id = 'sensor.flowmeter_sum') AND strftime('%Y%m%d',datetime(created_ts, 'unixepoch','localtime')) > strftime('%Y%m%d', datetime('now','localtime','-3 days'));
Ausgabe:
readabledate | id | mean | min | max | state | sum | metadata_id | created_ts | start_ts |
---|---|---|---|---|---|---|---|---|---|
2025-04-03 00:00:10 | 6212270 | NULL |
NULL |
NULL |
5795.28 | 18346.070000000367 | 606 | 1743638410.8686857 | 1743634800.0 |
2025-04-03 01:00:10 | 6212828 | NULL |
NULL |
NULL |
5795.34 | 18346.13000000037 | 606 | 1743642010.2952905 | 1743638400.0 |
2025-04-03 02:00:10 | 6213384 | NULL |
NULL |
NULL |
5795.39 | 18346.18000000037 | 606 | 1743645610.320077 | 1743642000.0 |
Die Statistik-Tabelle hat eine weitere Besonderheit: AbhÀngig vom Sensor-Typ werden unterschiedliche Spalten der Datenbanktabelle verwendet: Sensoren des Typs state_class=total oder total_increasing speichern deren Werte in den Spalten: "state" und "sum". Ein Sensor des Typs "state_class = measurement" verwendet die Spalten mean, min und max.
Hier die eine SQL-Query fĂŒr einen Sensor des Typs: "state_class = measurement":
select datetime(created_ts, 'unixepoch', 'localtime') AS readabledate,* from statistics WHERE metadata_id = ( SELECT id FROM statistics_meta WHERE statistic_id = 'sensor.eg_temperatur') AND strftime('%Y%m%d',datetime(created_ts, 'unixepoch','localtime')) > strftime('%Y%m%d', datetime('now','localtime','-3 days'));
Ausgabe:
readabledate | id | created | start | mean | min | max | state | sum | metadata_id | created_ts | start_ts |
---|---|---|---|---|---|---|---|---|---|---|---|
2025-04-03 00:00:10 | 6212150 | NULL |
NULL |
23.0 | 23.0 | 23.0 | NULL |
NULL |
319 | 1743638410.8686857 | 1743634800.0 |
2025-04-03 01:00:10 | 6212708 | NULL |
NULL |
23.0 | 23.0 | 23.0 | NULL |
NULL |
319 | 1743642010.2952905 | 1743638400.0 |
2025-04-03 02:00:10 | 6213264 | NULL |
NULL |
23.0 | 23.0 |
23.0 |
NULL |
NULL |
319 | 1743645610.320077 | 1743642000.0 |
Die Tabelle "statistics" speichert stĂŒndliche Werte, ohne diese zu löschen. Anders die Tabelle statistics_short_term: diese speichert die Werte im 5-Minuten-Takt und löscht die Daten, wie auch die "states"-Tabelle nach 10 Tagen. Vom Datenbank-Layout ist die Tabelle statistics und statistics_short_term ident. Beide verwenden die Tabelle statistics_meta und beide befĂŒllen abhĂ€ngig vom Sensor-Typ state und sum oder mean, min und max.
Als Beispiel werden fĂŒr die Detailansicht eines Sensors fĂŒr: Minimum, Mittel und Maximum die Daten aus den Spalten "mean", "min" und "max" der Tabelle "statistics_short_term" verwendet:
Fazit
Das Home-Assistant Datenbankschema erlaubt eine effiziente Auswertung von EntitĂ€tsdaten durch die Verwendung von Tabellen fĂŒr aktuelle und historische Informationen. Die Tabelle "states" bietet Zugang zu aktuellen Daten, wĂ€hrend "statistics" fĂŒr Langzeitdaten mit stĂŒndlichem Intervall genutzt wird. EntitĂ€ten und ihre zusĂ€tzlichen Attribute können durch SQL-Abfragen zielgerichtet und individuell ausgewertet werden.

{{percentage}} % positiv
