[[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]]