Der Quellcode zum Projekt ist auf GitHub verfügbar https://github.com/mschubi72/ESP32_Laderegler
Derzeitiger Aufbau:
Seit Anfang 2022 habe ich eine Balkonsolaranlage. Leider wird relativ viel Energie eingespeist, deshalb muss ein Zwischenspeicher her.
Fertige Lösungen sind zu teuer, so dass mein Solarlader ein reines DIY Projekt wird.
Folgende Anforderungen:
Ich habe angefangen die Software zu schreiben. Da ich nicht der geborene C/C++ Entwickler bin, sicher etwas Kraut und Rüben, aber es soll ja einfach nur funktionieren. Den Softwarestand checke ich ab und zu mal bei GitHub ein (https://github.com/mschubi72/ESP32_Laderegler).
Auch bei der Hardwareanschaffung und Verkabelung hat sich was getan. Die Hauptkomponenten sind verdrahtet.
Am Tag muss der Laderegler entscheiden, wann und wie viel geladen wird. Ich nehme hier einfach Übergänge von Zuständen an.
Faktoren sind die Solarstromerzeugung, Solarstromüberschuß (Einspeisung ins öffentliche Netz), Ladeleistung zum Akku. Da der ganze Ladeprozess doch einige Verluste mit sich bringt, lege ich die Schwelle bei mehr als 20 Watt Überschuss an. Unabhängig vom State wird bei voller Batterie der Ladevorgang abgeschaltet (separate Prüfung).
Daraus ergeben sich folgende Zustände (states):
State # | Solarstrom | Einspeisung | Ladeleistung | Bemerkung |
---|---|---|---|---|
State-0 | 0 | ⇐ 0 | 0 | Wenn kein Solarstrom, dann alles andere egal |
State-1 | >0 | ⇐ 0 | 0 | Keine Einspeisung, Keine Ladeleistung |
State-2 | >0 | >0 & < 20W | 0 | es wird unterhalb Schwelle eingespeist, keine Ladeleistung |
State-3 | >0 | >20W | 0 | Einspeisung oberhalb Schwelle, aber noch keine Ladung |
State-4 | >0 | ⇐ 0 | >0 | Keine Einspeisung, es wird aber noch geladen |
State-5 | >0 | >0 & < 20W | >0 | Einspeisung unter Schwelle, wird geladen→Ideal Status |
State-6 | >0 | >20W | >0 | Einspeisung oberhalb Schwelle, es wird geladen→Ladeleistung steigern |
Folgende Übergänge sind möglich:
State old | state new | Bemerkung | Action |
---|---|---|---|
State-0 | State-0 | keine Änderung | |
State-1 | Solarstrom, aber kein Überschuss→keine Ladeleistung | ||
State-2 | Solarstrom, Überschuss unter Schwelle→keine Ladeleistung | ||
State-3 | Solarstrom, Überschuss über Schwelle→beginn mit laden, aber Ladeleistung ist noch null, da gerade eingeschalten | Laden mit kleinster Leistung beginnen | |
State-1 | State-0 | ||
State-1 | |||
State-2 | |||
State-3 | Laden mit kleinster Leistung beginnen | ||
State-2 | State-0 | ||
State-1 | |||
State-2 | |||
State-3 | Laden mit kleinster Leistung beginnen | ||
State-3 | State-0 | ||
State-1 | |||
State-2 | |||
| Wenn genug Überschuss, dann Laden einschalten, sonst Fehler | ||
State-4 | Laden wurde begonnen, gibt keine Einspeisung mehr | Laden abstellen | |
State-5 | Laden wurde begonnen, Einspeisung unter Schwelle→ Ladeleistung OK | ||
State-6 | Laden wurde begonnen, Einspeisung über Schwelle | Ladeleistung vergrößern | |
State-4 | State-4 | Es wird mit zu viel Power geladen | Ladeleistung verringern |
State-5 | Laden OK | ||
State-6 | noch Überschuss | Ladeleistung erhöhen | |
State-0 bis 3 | Ladeleistung kann nicht weiter verringert werden | Laden beenden | |
State-5 | State-4 | Es wird mit zu viel Power geladen | Ladeleistung verringern |
State-5 | Laden OK | ||
State-6 | Gibt zu viel Überschuss | Ladeleistung vergrößern | |
State-6 | State-4 | Es wird mit zu viel Power geladen | Ladeleistung verringern |
State-5 | Laden OK | ||
State-6 | Ladeleistung erhöhen | Ladeleistung erhöhen |
Zum Erfassen der Ladeleistung und Einspeisleistung und dem entsprechenden Schaltvorgängen nutze ich einen Sonoff Dual R3, der mit ESPHome umgeflashed wurde. Der Webserver ist auch enabled. Somit Schalte ich die Ausgänge einfach per REST API POST Kommandos. Die Leistungsübermittlung etc. aber weiterhin über die ESP32 API direkt zum Homeassistant.
Wichtig ist die Leiterplattenversion. Ab Version 2.0 des Dual R3 (wie bei mir) wird der BL0939 Chip zum Erfassen von Strom/Spannung/Leistung genutzt. Vorherige Revisionen den CSE7761. (siehe https://esphome.io/devices/sonoff.html#sonoff-dual-r3-v1-x-v2-x)
Folgendes YAML File für ESPHome:
substitutions: devicename: lader-power long_devicename: Sonoff DualR3 Lader # # Dual r3 V2.0 # esphome: name: $devicename esp32: board: esp32dev framework: type: arduino # Enable logging logger: # level: VERY_VERBOSE # Enable Home Assistant API api: ota: password: "0a46d9b044d9acb408d44bf02d620ffb" wifi: ssid: !secret wifi_ssid password: !secret wifi_password # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "Lader-Power Fallback Hotspot" password: "7jnCyGWRuDsb" captive_portal: web_server: port: 80 uart: tx_pin: GPIO25 rx_pin: GPIO26 baud_rate: 4800 parity: NONE stop_bits: 2 sensor: - platform: wifi_signal name: "$long_devicename WiFi Signal" update_interval: 60s - platform: bl0939 update_interval: 5s voltage: name: "$devicename Voltage" current_1: name: "$devicename Current OUT" current_2: name: "$devicename Current IN" active_power_1: name: "$devicename Power OUT" active_power_2: name: "$devicename Power IN" output: - platform: gpio pin: GPIO27 id: relay1 - platform: gpio pin: GPIO14 id: relay2 switch: - platform: output name: "$devicename relay OUT" output: relay1 id: sw1 - platform: output name: "$devicename relay IN" output: relay2 id: sw2 status_led: pin: number: GPIO13 inverted: yes binary_sensor: - platform: gpio pin: number: GPIO0 mode: INPUT_PULLUP inverted: True name: "$devicename button" on_press: - logger.log: "$devicename button" - switch.toggle: sw2 - platform: gpio pin: number: GPIO32 mode: INPUT_PULLUP inverted: True name: "$devicename switch OUT" on_press: - logger.log: "$devicename switch OUT" - switch.toggle: sw1 - platform: gpio pin: number: GPIO33 mode: INPUT_PULLUP inverted: True name: "$devicename switch IN" on_press: - logger.log: "$devicename switch IN" - switch.toggle: sw2
Die Abfrage der zwei Relais erfolgt über REST API GET
http://<ip/fqdn>/switch/lader-power_relay_in
Es wird einfach der Componenten Name genommen und alle Leerzeichen durch Unterstriche ersetzt werden. Deshalb “Lader-Power Relay In” zu “lade-power_relay_in”. Der JSON Returnwert sieht dann so aus:
{ "id": "switch-lader-power_relay_in", "value": false, "state": "OFF" }
Geschaltet wird mit einem Postrequest:
http://<ip/fqdn>/switch/lader-power_relay_in/turn_on http://<ip/fqdn>/switch/lader-power_relay_in/turn_off http://<ip/fqdn>/switch/lader-power_relay_in/toggle
Derzeitige Ansicht:
Nicht wundern, dass die Akkus noch in Folie sind. Durch die Tüten lassen sie sich sehr gut rausheben. War übrigens selber über das Gewicht der LiPOFe positiv überrascht.
Meine ESP32 “Testumgebung” zum Entwickeln…
Links oben das Modul zur RS485 Kommunikation, in der Mitte oben der ADS1115 AD Wandler. Das Display ist noch “raw” - aktuell erzeugte Solarleistung, aktueller Verbrauch laut Zähler, Icon Ladezustand Akku, Spannung Akku (auf dem Foto eine Testfakewert), am Ende das Symbol, wenn geladen wird.