Hi,
ich wollte heute mal herausfinden, warum meine HA-Backups so groß sind, und bin dann letztlich auf die home-assistant_v2.db gestossen, die auf der HAOS platte 5 gb in anspruch nimmt
-rw-r--r-- 1 root root 5.2G Sep 4 11:13 home-assistant_v2.db
-rw-r--r-- 1 root root 64.0K Sep 4 11:13 home-assistant_v2.db-shm
-rw-r--r-- 1 root root 17.3M Sep 4 11:13 home-assistant_v2.db-wal
und im komprimierten Backup dann ganz grob 3/4 der komprimierten Größe:
Also hab ich mich mit der Unterstützung von ChatGPT (sorry) auf die Suche gemacht.
Schritt 1: Welche Tabellen brauchen den Platz? AW: state_attributes
sqlite3 -readonly home-assistant_v2.db "
SELECT
name,
printf('%.2f GB', SUM(pgsize)/1024.0/1024/1024) AS size
FROM dbstat
GROUP BY name
ORDER BY SUM(pgsize) DESC;
"
╭────────────────────────────────────────────────┬─────────╮
│ name │ size │
╞════════════════════════════════════════════════╪═════════╡
│ state_attributes │ 2.31 GB │
│ states │ 0.63 GB │
│ statistics │ 0.29 GB │
│ ix_states_context_id_bin │ 0.21 GB │
│ ix_states_metadata_id_last_updated_ts │ 0.16 GB │
│ ix_states_last_updated_ts │ 0.14 GB │
Schritt 2: Was in state_attributes braucht den Platz? AW: solar_forecast_energy_ai_* ganz vorn dabei
sqlite3 -readonly home-assistant_v2.db "
SELECT
sm.entity_id,
COUNT(*) AS states,
COUNT(DISTINCT s.attributes_id) AS attribute_sets
FROM states s
JOIN states_meta sm ON s.metadata_id = sm.metadata_id
GROUP BY s.metadata_id
ORDER BY attribute_sets DESC
LIMIT 50;
"
╭───────────────────────────────────────────────────────────────────────────┬────────┬────────────────╮
│ entity_id │ states │ attribute_sets │
╞═══════════════════════════════════════════════════════════════════════════╪════════╪════════════════╡
│ sensor.solar_forecast_ml_external_sensors_status │ 231158 │ 213663 │
│ sensor.solar_forecast_energy_ai_wallbox_empfehlung │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_erklarung_der_wallbox_empfehlung │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_vertrauen_der_wallbox_empfehlung │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_wallbox_prognoseunsicherheit │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_nachster_empfohlener_ladestart │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_empfohlenes_ladeende │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_benotigte_ladeenergie │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_erwarteter_pv_ladeanteil │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_geschatzte_ladekosten │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_geschatzter_kostenvorteil_der_ladeplanung │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_abfahrtsbereitschaft │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_wallbox_datenqualitat │ 90863 │ 90863 │
│ binary_sensor.solar_forecast_energy_ai_wallbox_ladefenster_aktiv │ 90863 │ 90863 │
│ binary_sensor.solar_forecast_energy_ai_pv_laden_empfohlen │ 90863 │ 90863 │
│ binary_sensor.solar_forecast_energy_ai_wallbox_rest_pv_fenster_aktiv │ 90863 │ 90863 │
│ binary_sensor.solar_forecast_energy_ai_niedrigpreis_laden_empfohlen │ 90863 │ 90863 │
│ binary_sensor.solar_forecast_energy_ai_abfahrtsziel_gefahrdet │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_grund_der_wallbox_empfehlung │ 90863 │ 90863 │
│ sensor.solar_forecast_energy_ai_lokaler_temperaturprognose_mae │ 50761 │ 50744 │
│ sensor.solar_forecast_energy_ai_lokale_temperaturprognose_abweichung │ 50761 │ 50744 │
│ binary_sensor.solar_forecast_stats_pv_surplus_available │ 54639 │ 43105 │
│ sensor.walli_laden_heute │ 41182 │ 41151 │
│ sensor.walli_laden_lfd_monat │ 41164 │ 41142 │
│ sensor.walli_laden_lfd_woche │ 41164 │ 41142 │
│ sensor.walli_laden_lfd_jahr │ 41162 │ 41141 │
│ sensor.walli_laden_total │ 41162 │ 41141 │
│ sensor.solar_forecast_ml_sfml_total_actual_today │ 34778 │ 34768 │
│ sensor.solar_forecast_ml_sfml_total_yield_today │ 34778 │ 34768 │
│ sensor.solar_forecast_ml_gruppe_1_power │ 34778 │ 34768 │
│ sensor.solar_forecast_ml_gruppe_1_actual_today │ 34778 │ 34768 │
│ sensor.solar_forecast_ml_gruppe_2_power │ 34778 │ 34768 │
│ sensor.solar_forecast_ml_gruppe_2_actual_today │ 34778 │ 34768 │
│ sensor.solar_forecast_ml_sfml_total_power │ 34778 │ 34768 │
│ sensor.wallbox_laden_tag │ 20670 │ 20618 │
│ sensor.wallbox_w │ 20652 │ 20517 │
│ sensor.wallbox_laden_m │ 20652 │ 20515 │
│ sensor.wallbox_laden_jahr │ 20650 │ 20433 │
│ sensor.wallbox_laden_total │ 20650 │ 20433 │
│ sensor.octopus_tag_taglich │ 18034 │ 18010 │
│ sensor.octopus_tag_monatlich │ 18016 │ 18001 │
│ sensor.octopus_tag_jahrlich │ 18014 │ 18000 │
│ sensor.octopus_netzbezug_tag_ab_01_05_2026 │ 18014 │ 18000 │
│ sensor.stromeinspeisung_heute │ 11381 │ 11354 │
│ sensor.strom_einspeisung_w │ 11363 │ 11345 │
│ sensor.strom_einspeisung_m │ 11363 │ 11345 │
│ sensor.strom_einspeisung_y │ 11361 │ 11344 │
│ weather.luedenscheid │ 8781 │ 8776 │
│ sensor.stromverbrauch_heute │ 7081 │ 7054 │
│ sensor.strom_netzbezug_w │ 7063 │ 7045 │
╰───────────────────────────────────────────────────────────────────────────┴────────┴────────────────╯
Schritt 3: Sind da Datensätze dupliziert? AW: Nein
sqlite3 -readonly home-assistant_v2.db "
SELECT
COUNT(*) AS total_attribute_rows,
COUNT(DISTINCT shared_attrs) AS unique_attribute_contents
FROM state_attributes;
"
╭──────────────────────┬──────────────────────╮
│ total_attribute_rows │ unique_attribute_... │
╞══════════════════════╪══════════════════════╡
│ 2838644 │ 2838644 │
╰──────────────────────┴──────────────────────╯
Schritt 4: Gibt es große Cluster? AW: es wird spannend
Grund hierfür: Vermutung: es gab zwischendurch einen Bug, denn zB solar_forecast_energy_ai_wallbox_empfehlung ändert sich vllt 5 mal pro Tag in der UI.
SELECT
date(last_updated_ts, 'unixepoch') AS utc_day,
COUNT(*) AS changes
FROM states s
JOIN states_meta sm ON s.metadata_id = sm.metadata_id
WHERE sm.entity_id = 'sensor.solar_forecast_energy_ai_wallbox_empfehlung'
GROUP BY utc_day
ORDER BY changes DESC
LIMIT 30;
"
╭────────────┬─────────╮
│ utc_day │ changes │
╞════════════╪═════════╡
│ 2026-08-25 │ 13717 │
│ 2026-08-30 │ 11820 │
│ 2026-08-26 │ 10194 │
│ 2026-08-29 │ 9874 │
│ 2026-09-02 │ 9379 │
│ 2026-09-01 │ 8747 │
│ 2026-08-27 │ 8514 │
│ 2026-09-03 │ 7363 │
│ 2026-08-31 │ 6342 │
│ 2026-08-28 │ 3783 │
│ 2026-09-04 │ 1140 │
╰────────────┴─────────╯
13717 Änderungen an einem Tag?
UI sieht nicht danach aus…
Schritt 5: Was ändert sich da eigentlich? AW: (fast) nichts
SELECT
state,
COUNT(*) AS changes
FROM states s
JOIN states_meta sm ON s.metadata_id = sm.metadata_id
WHERE sm.entity_id = 'sensor.solar_forecast_energy_ai_wallbox_empfehlung'
AND last_updated_ts >= strftime('%s', '2026-08-25 11:00:00')
AND last_updated_ts < strftime('%s', '2026-08-25 14:00:00')
GROUP BY state
ORDER BY changes DESC;
"
╭────────┬─────────╮
│ state │ changes │
╞════════╪═════════╡
│ charge │ 5903 │
│ defer │ 401 │
╰────────┴─────────╯
Verstehe ich so: wir schreiben tausende male den gleichen Wert rein.
Stichprobe: Was ändert sich zwischen zwei Werten? AW: intent_id
➜ /homeassistant sqlite3 -readonly home-assistant_v2.db "
WITH x AS (
SELECT
sa.shared_attrs,
ROW_NUMBER() OVER (ORDER BY s.last_updated_ts) AS rn
FROM states s
JOIN states_meta sm ON s.metadata_id = sm.metadata_id
JOIN state_attributes sa ON s.attributes_id = sa.attributes_id
WHERE sm.entity_id = 'sensor.solar_forecast_energy_ai_wallbox_empfehlung'
AND s.last_updated_ts >= strftime('%s', '2026-08-25 11:00:00')
AND s.last_updated_ts < strftime('%s', '2026-08-25 14:00:00')
),
a AS (SELECT shared_attrs FROM x WHERE rn = 1),
b AS (SELECT shared_attrs FROM x WHERE rn = 2)
SELECT
'A' AS record,
key,
value
FROM a, json_each(a.shared_attrs)
UNION ALL
SELECT
'B' AS record,
key,
value
FROM b, json_each(b.shared_attrs)
ORDER BY key, record;
"
╭────────┬───────────────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ record │ key │ value │
╞════════╪═══════════════════════════════════╪═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ A │ advisory_only │ 1 │
│ B │ advisory_only │ 1 │
│ A │ allocation_origin │ stats_household_then_heat_pump_then_battery_then_calibration_reserve_then_wallbox_then_grid_export │
│ B │ allocation_origin │ stats_household_then_heat_pump_then_battery_then_calibration_reserve_then_wallbox_then_grid_export │
│ A │ battery_energy_demand_kwh │ 10.0 │
│ B │ battery_energy_demand_kwh │ 10.0 │
│ A │ charging_efficiency_percent │ 90 │
│ B │ charging_efficiency_percent │ 90 │
│ A │ control_services_called │ 0 │
│ B │ control_services_called │ 0 │
│ A │ demand_confidence_percent │ 95 │
│ B │ demand_confidence_percent │ 95 │
│ A │ demand_source │ soc │
│ B │ demand_source │ soc │
│ A │ departure_time │ 2026-08-26T05:00:00+00:00 │
│ B │ departure_time │ 2026-08-26T05:00:00+00:00 │
│ A │ device_class │ enum │
│ B │ device_class │ enum │
│ A │ explanation_evidence │ ["Benötigte Wallbox-Energie 11.11 kWh bei 90 % Ladeeffizienz","Aus Fahrzeug-Ladezustand und Ziel 100 % berechnet","PV-Anteil 11.11 kWh, Prognoseband 11.11–11.11 kWh","Aktueller Strompreis 30.4 ct/kWh"] │
│ B │ explanation_evidence │ ["Benötigte Wallbox-Energie 11.11 kWh bei 90 % Ladeeffizienz","Aus Fahrzeug-Ladezustand und Ziel 100 % berechnet","PV-Anteil 11.11 kWh, Prognoseband 11.11–11.11 kWh","Aktueller Strompreis 30.4 ct/kWh"] │
│ A │ explanation_headline │ Jetzt verbleibenden PV-Überschuss nutzen │
│ B │ explanation_headline │ Jetzt verbleibenden PV-Überschuss nutzen │
│ A │ forecast_uncertainty_percent │ 31 │
│ B │ forecast_uncertainty_percent │ 31 │
│ A │ friendly_name │ Solar Forecast Energy AI Wallbox-Empfehlung │
│ B │ friendly_name │ Solar Forecast Energy AI Wallbox-Empfehlung │
│ A │ intent_id │ 650fa5bdb972f840 │
│ B │ intent_id │ 5025270adddd4fa4 │
│ A │ master_enabled │ 0 │
│ B │ master_enabled │ 0 │
│ A │ passive_signal │ 1 │
│ B │ passive_signal │ 1 │
│ A │ reason │ pv_surplus │
│ B │ reason │ pv_surplus │
│ A │ recommendation_confidence_percent │ 56 │
│ B │ recommendation_confidence_percent │ 56 │
│ A │ valid_until │ 2026-08-25T15:00:00+00:00 │
│ B │ valid_until │ 2026-08-25T15:00:00+00:00 │
╰────────┴───────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Eigentliche Frage(n)
Warum sehen wir so viele Schreibvorgänge, könnte man das evtl. deduplizieren, oder braucht SFML die unterschiedlichen Einträge? Und ist das überhaupt mit dem recorder switch noch notwendig, oder kann ich die DB purgen und es sammelt sich nicht wieder an?
Ohne jetzt alle states durchgeschaut zu haben, anhand der gleichen Counts kriege ich das Gefühl, dass das insgesamt ein Muster ist, also nicht nur für die Wallbox Empfehlung passiert.
Ich könnte jetzt natürlich auch für die backups sowas wie AI Empfehlung weglassen, aber so richtig zufriedenstellend finde ich das nicht. Sorry für den ganzen AI-Content.
Liebe Grüße
nightrunner sein Informatikersohn

