[[Uebersicht|← Zurück zur Homepage]] # Node-RED Energiemanagement – Programm (v10) ## Flow-Übersicht **Tab:** `Energiemanagement` (ID: `tab_energiemanagement`) **Takt:** alle 5 Minuten + einmalig nach 5 s beim Start --- ## Haupt-Chain (sequenziell) ``` inject_5min → ha_pv_aktuell sensor.opendtu_d71ef0_ac_power → msg.pv_aktuell → ha_tibber_level sensor.daheim_aktuelles_preisniveau → msg.tibber_level → ha_tibber_preis sensor.daheim_aktueller_strompreis → msg.tibber_preis → ha_tibber_1h sensor.daheim_preis_nachste_1h → msg.tibber_1h → ha_tibber_2h sensor.daheim_preis_nachste_2h → msg.tibber_2h → ha_tibber_3h sensor.daheim_preis_nachste_3h → msg.tibber_3h → ha_tibber_4h sensor.daheim_preis_nachste_4h → msg.tibber_4h → ha_forecast_verbleibend solcast_prognose_verbleibende_leistung → msg.forecast_verbleibend → ha_forecast_heute_gesamt solcast_prognose_heute → msg.forecast_heute_gesamt → ha_forecast_morgen solcast_prognose_morgen → msg.forecast_morgen → ha_soc_b1 sensor.mtv01_soc_batterie → msg.soc_b1 → ha_soc_b2 sensor.mtv02_soc_batterie → msg.soc_b2 → ha_soc_b3 sensor.mtv03_soc_batterie → msg.soc_b3 → ha_max_soc_ist_b1 number.garage_mtv01_maximaler_soc → msg.max_soc_ist_b1 → ha_max_soc_ist_b2 number.marstek_venus_modbus_maximaler_soc_2 → msg.max_soc_ist_b2 → ha_max_soc_ist_b3 number.marstek_venus_modbus_maximaler_soc_3 → msg.max_soc_ist_b3 → entscheidungslogik (Function, v10) ├─ debug_entscheidung (Debug-Node, Sidebar) ├─ sqlite_log → sqlite_db (Logging) ├─ testmodus_check → [Steuerung B1/B2/B3 Ladeziel + Ladeleistung] └─ notify_check → ha_notify (iPhone Push) ``` **DB-Init-Chain** (einmalig beim Start): ``` sqlite_init → sqlite_create_table → sqlite_db_init ``` --- ## Dateneingänge | Sensor | Kanal | Wert | |---|---|---| | `solar/dtu/ac/power` | MQTT | PV-Leistung aktuell (W) | | `sensor.daheim_aktuelles_preisniveau` | HA API | Tibber Level (CHEAP etc.) | | `sensor.daheim_aktueller_strompreis` | HA API | Tibber Preis (ct/kWh) | | `sensor.daheim_preis_nachste_1h` bis `_4h` | HA API | Tibber Vorschau 4 Stunden | | `sensor.solcast_pv_forecast_prognose_verbleibende_leistung_heute` | HA API | PV-Forecast verbleibend (kWh) | | `sensor.solcast_pv_forecast_prognose_heute` | HA API | PV-Forecast heute gesamt (kWh) | | `sensor.solcast_pv_forecast_prognose_morgen` | HA API | PV-Forecast morgen (kWh) | | `sensor.mtv01_soc_batterie` | HA API | SOC Batterie 1 (%) | | `sensor.mtv02_soc_batterie` | HA API | SOC Batterie 2 (%) | | `sensor.mtv03_soc_batterie` | HA API | SOC Batterie 3 (%) | | `number.garage_mtv01_maximaler_soc` | HA API | Ist-Ladeziel B1 (%) | | `number.marstek_venus_modbus_maximaler_soc_2` | HA API | Ist-Ladeziel B2 (%) | | `number.marstek_venus_modbus_maximaler_soc_3` | HA API | Ist-Ladeziel B3 (%) | --- ## Steuerausgänge | Batterie | Ladeziel-Entity | Ladeleistung-Entity | |---|---|---| | B1 | `number.marstek_venus_modbus_maximaler_soc` | `number.marstek_venus_modbus_ladeleistung_einstellen` | | B2 | `number.marstek_venus_modbus_maximaler_soc_2` | `number.marstek_venus_modbus_ladeleistung_einstellen_2` | | B3 | `number.marstek_venus_modbus_maximaler_soc_3` | `number.marstek_venus_modbus_ladeleistung_einstellen_3` | --- ## Entscheidungslogik (v10) ### Eingangsvariablen ```javascript var soc_b1 = parseFloat(msg.soc_b1) || 0; var soc_b2 = parseFloat(msg.soc_b2) || 0; var soc_b3 = parseFloat(msg.soc_b3) || 0; var soc_avg = (soc_b1 + soc_b2 + soc_b3) / 3; var max_soc_ist_b1 = parseFloat(msg.max_soc_ist_b1) || 0; var max_soc_ist_b2 = parseFloat(msg.max_soc_ist_b2) || 0; var max_soc_ist_b3 = parseFloat(msg.max_soc_ist_b3) || 0; ``` ### msg.payload Ausgabe (erweitert in v10) ```javascript max_soc_ist_b1: Math.round(max_soc_ist_b1 * 10) / 10, max_soc_ist_b2: Math.round(max_soc_ist_b2 * 10) / 10, max_soc_ist_b3: Math.round(max_soc_ist_b3 * 10) / 10, version: 'v10', ``` ### Testmodus ```javascript var TESTMODUS = true; // Zeile ~15 in entscheidungslogik ``` - `true`: nur Logging in SQLite + Debug, keine Steuerung - `false`: setzt Ladeziel + Ladeleistung per HA-API --- ## iPhone-Benachrichtigung - Service: `notify.mobile_app_iphone2025` - Auslöser: erster Wechsel auf günstigen Tibber-Level (einmalig pro Preisänderung) - Letzter Level gespeichert in `global.letzter_tibber_level` --- ## SQLite Logging ### Tabelle `entscheidungen` ```sql CREATE TABLE IF NOT EXISTS entscheidungen ( id INTEGER PRIMARY KEY AUTOINCREMENT, zeitstempel DATETIME, soc_b1 REAL, soc_b2 REAL, soc_b3 REAL, pv_aktuell REAL, tibber_preis REAL, tibber_level TEXT, forecast_heute REAL, forecast_morgen REAL, restverbrauch_kwh REAL, pv_netto_kwh REAL, ladeziel REAL, ladeleistung_je REAL, entscheidung TEXT, max_soc_ist_b1 REAL, -- [v10] max_soc_ist_b2 REAL, -- [v10] max_soc_ist_b3 REAL, -- [v10] version TEXT -- [v10] ); ``` ### Nützliche Abfragen ```bash # Letzte 20 Einträge sqlite3 /data/energiemanagement.db \ "SELECT zeitstempel, soc_b1, soc_b2, soc_b3, tibber_level, ladeziel, ladeleistung_je, entscheidung \ FROM entscheidungen ORDER BY id DESC LIMIT 20;" # Alle LADEN-Entscheidungen sqlite3 /data/energiemanagement.db \ "SELECT * FROM entscheidungen WHERE entscheidung LIKE 'LADEN%';" # Tagesübersicht sqlite3 /data/energiemanagement.db \ "SELECT DATE(zeitstempel), COUNT(*), entscheidung \ FROM entscheidungen GROUP BY DATE(zeitstempel), entscheidung;" # PV_LADEN Einträge sqlite3 /data/energiemanagement.db \ "SELECT zeitstempel, pv_aktuell, ladeleistung_je, soc_b1, soc_b2, soc_b3 \ FROM entscheidungen WHERE entscheidung='PV_LADEN';" ``` ### Tabelle neu erstellen ```bash sqlite3 /data/energiemanagement.db "DROP TABLE entscheidungen;" # Dann DB Init Node in Node-RED anklicken ``` --- [[Hinweise/Impressum|Impressum]] | [[Hinweise/Datenschutzerklärung|Datenschutz]]