Diese Seite wurde vor mehr als 2 Jahren erstellt und vor über einem Monat zuletzt bearbeitet. Eventuell ist längst ihr Mindesthaltbarkeitsdatum überschritten!
Projekt der Woche: Live-Anzeige der PV- und Verbrauchs-Daten am Zählerschrank mit Minimal-Aufwand. Der Mikrocontroller verbindet sich zum WLAN und fragt zyklisch die Daten aus dem Wechselrichter ab. Diese Parameter können dann direkt weiter verarbeitet werden, z.B. Relais steuern, oder einfach angezeigt werden – je nach Geschmack.
Diese weitere Verarbeitung und die Anzeige sind nicht Teil dieser Seite, im Code ist jedoch die Ansteuerung eines I2C OLEDs integriert.
$random
Arduino oder ähnliches mit LAN/WLAN, bei mir ein NodeMCU Lua Lolin V3, ESP8622-12EESP8266-Boards gibt es auch mit integriertem OLED-Display, z.B. hier.
Die Fronius-API stellt die Daten im JSON-Format bereit. Die Doku der API (V1) ist hier zu finden, für den Arduino hat sich die ArduinoJson-Library von Benoît Blanchon bewährt. ArduinoJson in der Version 5.x in der IDE hinzufügen, nicht die 6.x – diese ist noch im Beta-Stadium.
Zum Test sind hier zwei JSON-Dateien online verfügbar:
Dieser Code ist schnell zusammengetippt. C
/C++
ist nicht gerade meine Stärke, um es vorsichtig auszudrücken. Um
so seltsamer ist es, dass mir bisher beim Testen keine segfault begegnet ist... SSID, PSK sowie Hostnamen des ESPs
bzw. des Wechselrichters anpassen.
Noch einmal deutlicher: Mit diesem Code sollte man keine Herz-Lungen-Maschine betreiben! Das Skript benötigt neben dem Wechselrichter auch einen Verbrauchs-Zähler wie z.B. einen Fronius Smart Meter 63A-3 für die Abfrage von GetMeterRealtimeData
!
#include <ArduinoJson.h> // Arduino JSON (5.x stable, nicht 6.x)
#include <ESP8266WiFi.h> // ESP8266 WiFi
#include <WiFiClient.h> // ESP8266 Wifi-Client
#include <ESP8266HTTPClient.h> // ESP8266 HTTP-Client
#include <Wire.h> // Wire / I2C
#include <SSD1306Ascii.h> // 1306 OLED Display
#include <SSD1306AsciiWire.h> // 1306 OLED Display über I2C
// WiFi SSID und PSK
const char *ssid = "meine_ssid";
const char *password = "mein_psk";
const char *host_name = "esp_pva_01";
// Wechselrichter Hostname oder IP-Adresse
const String inverterHostname = "symo.local,lan";
// Fronius Solar API URLs "Meter Data" und "Flow Data"
String urlMeter = "http://" + inverterHostname + "/solar_api/v1/GetMeterRealtimeData.cgi?Scope=Device&DeviceId=0";
String urlFlow = "http://" + inverterHostname + "/solar_api/v1/GetPowerFlowRealtimeData.fcgi";
// Display-Setup
#define I2C_ADDRESS 0x3C
// Reset-Pin des Displays, falls benötigt
#define RST_PIN -1
//#define RST_PIN 16
// Display initialisieren
SSD1306AsciiWire oled;
// setup()
void setup() {
// 1s warten
delay(1000);
// I2C an
// Wire.begin(int sda, int scl);
Wire.begin();
Wire.setClock(400000L);
// Display an
#if RST_PIN >= 0
oled.begin(&Adafruit128x32, I2C_ADDRESS, RST_PIN);
#else
oled.begin(&Adafruit128x32, I2C_ADDRESS);
#endif
// Serielle Schnittstelle an, 115200/8/N/1
Serial.begin(115200);
oled.setFont(System5x7);
oled.clear();
oled.println("Seriell 115200");
// Heltec Wifi Kit 8: GPIO16, Einschlafen des Displays verhindern
//digitalWrite(16, LOW);
// WiFi aus
WiFi.mode(WIFI_OFF);
// 1s warten
delay(1000);
// WiFi Client-Modus, AP-Modus aus
WiFi.mode(WIFI_STA);
// Hostname setzen, falls gewünscht. Default ist "ESP_[MACADR]"
//WiFi.hostname(host_name);
// WiFi verbinden
WiFi.begin(ssid, password);
oled.println("Verbinde WiFi ...");
Serial.println();
Serial.println("ESP8266 WiFi-Client für Fronius Solar Api V1");
Serial.println("https://www.onderka.com/hausautomation-technik-und-elektronik/nodemcu-json-daten-von-fronius-wechselrichter-einlesen/");
Serial.println();
Serial.print("Verbinde ");
// Auf Verbindung warten
while (WiFi.status() != WL_CONNECTED) {
// Alle 0.5s einen Punkt
delay(500);
Serial.print(".");
}
Serial.println(" Verbunden.");
oled.clear();
oled.println("WiFi verbunden");
oled.println();
oled.println(WiFi.localIP());
oled.println(WiFi.macAddress());
// Verbindungs-Informationen
Serial.println();
Serial.print("SSID: ");
Serial.println(ssid);
Serial.print("Kanal: ");
Serial.println(WiFi.channel());
Serial.print("Signal (RX): ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.print("IP-Adresse: ");
Serial.println(WiFi.localIP());
Serial.print("MAC-Adresse: ");
Serial.println(WiFi.macAddress());
Serial.println();
// Ende setup()
delay(2000);
}
// loop()
void loop() {
// HTTP-Clients initialisieren
HTTPClient http;
const size_t capacityMeter = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
const size_t capacityFlow = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
// JSON-Puffer initialisieren
DynamicJsonBuffer jsonBufferMeter(capacityMeter);
DynamicJsonBuffer jsonBufferFlow(capacityFlow);
// URL #1 - Meter Data
http.begin(urlMeter);
int httpCodeMeter = http.GET();
// JSON-Antwort
String httpResponseMeter = http.getString();
// HTTP-Client beenden
http.end();
Serial.print("URL: ");
Serial.println(urlMeter);
Serial.print("HTTP Status: ");
Serial.println(httpCodeMeter);
JsonObject& jsonMeter = jsonBufferMeter.parseObject(httpResponseMeter);
if (!jsonMeter.success()) {
// JSON nicht erfolgreich geparst
Serial.println("JSON-Parser: Fehler");
} else {
Serial.println("JSON-Parser: OK");
}
// URL #2 - Flow Data
http.begin(urlFlow);
int httpCodeFlow = http.GET();
// JSON-Antwort
String httpResponseFlow = http.getString();
// HTTP-Client beenden
http.end();
Serial.print("URL: ");
Serial.println(urlFlow);
Serial.print("HTTP Status: ");
Serial.println(httpCodeFlow);
JsonObject& jsonFlow = jsonBufferFlow.parseObject(httpResponseFlow);
if (!jsonFlow.success()) {
// JSON nicht erfolgreich geparst
Serial.println("JSON-Parser: Fehler");
} else {
Serial.println("JSON-Parser: OK");
}
Serial.println();
// Timestamp Daten Power Meter
String ts_meter = ( jsonMeter["Head"]["Timestamp"] | "Leer" );
// Momentanverbrauch Phase1/2/3
float p_phase1 = ( jsonMeter["Body"]["Data"]["PowerReal_P_Phase_1"] | 0 );
float p_phase2 = ( jsonMeter["Body"]["Data"]["PowerReal_P_Phase_2"] | 0 );
float p_phase3 = ( jsonMeter["Body"]["Data"]["PowerReal_P_Phase_3"] | 0 );
// Spannung Phase1/2/3
float u_phase1 = ( jsonMeter["Body"]["Data"]["Voltage_AC_Phase_1"] | 0 );
float u_phase2 = ( jsonMeter["Body"]["Data"]["Voltage_AC_Phase_2"] | 0 );
float u_phase3 = ( jsonMeter["Body"]["Data"]["Voltage_AC_Phase_3"] | 0 );
// Strom Phase1/2/3
float i_phase1 = jsonMeter["Body"]["Data"]["Current_AC_Phase_1"].as<float>();
float i_phase2 = jsonMeter["Body"]["Data"]["Current_AC_Phase_2"].as<float>();
float i_phase3 = jsonMeter["Body"]["Data"]["Current_AC_Phase_3"].as<float>();
// Momentane Leistung Summe
float p_summe = ( jsonMeter["Body"]["Data"]["PowerReal_P_Sum"] | 0 );
// Momentane Blindleistung Summe
float p_sum_ap = ( jsonMeter["Body"]["Data"]["PowerApparent_S_Sum"] | 0 );
// Durchschnitt Netzfrequenz
float net_freq = jsonMeter["Body"]["Data"]["Frequency_Phase_Average"].as<float>();
// Timestamp Daten Power Flow
String ts_flow = ( jsonFlow["Head"]["Timestamp"] | "Leer" );
// Energie Tag
float p_day = ( jsonFlow["Body"]["Data"]["Inverters"]["1"]["E_Day"] | 0 );
// Energie Jahr
float p_year = ( jsonFlow["Body"]["Data"]["Inverters"]["1"]["E_Year"] | 0 );
// Energie Gesamt
float p_total = ( jsonFlow["Body"]["Data"]["Inverters"]["1"]["E_Total"] | 0 );
// Einspeisung / Bezug: Negativ Einspeisung, positiv Bezug
float in_out = ( jsonFlow["Body"]["Data"]["Site"]["P_Grid"] | 0 );
// Verbrauch momentan
float cons = ( jsonFlow["Body"]["Data"]["Site"]["P_Load"] | 0 );
// Produktion momentan
float prod = ( jsonFlow["Body"]["Data"]["Site"]["P_PV"] | 0 );
// Autonomie (% Produktion an Verbrauch)
float autonomy = ( jsonFlow["Body"]["Data"]["Site"]["rel_Autonomy"] | 0 );
// Selbstverbrauch (% Eigenverbrauch an Produktion)
float selfcons = ( jsonFlow["Body"]["Data"]["Site"]["rel_SelfConsumption"] | 0 );
// Ausgabe seriell
Serial.print("Timestamp Meter: ");
Serial.println(ts_meter);
Serial.print("Timestamp Flow: ");
Serial.println(ts_flow);
Serial.print("Spannung Phase 1: ");
Serial.print(u_phase1);
Serial.println(" V");
Serial.print("Spannung Phase 2: ");
Serial.print(u_phase2);
Serial.println(" V");
Serial.print("Spannung Phase 3: ");
Serial.print(u_phase3);
Serial.println(" V");
Serial.print("Strom Phase 1: ");
Serial.print(i_phase1);
Serial.println(" A");
Serial.print("Strom Phase 2: ");
Serial.print(i_phase2);
Serial.println(" A");
Serial.print("Strom Phase 3: ");
Serial.print(i_phase3);
Serial.println(" A");
Serial.print("Leistung Phase 1: ");
Serial.print(p_phase1 * -1);
Serial.println(" W");
Serial.print("Leistung Phase 2: ");
Serial.print(p_phase2 * -1);
Serial.println(" W");
Serial.print("Leistung Phase 3: ");
Serial.print(p_phase3 * -1);
Serial.println(" W");
Serial.print("Leistung Summe: ");
Serial.print(p_summe * -1);
Serial.println(" W");
Serial.print("Scheinleistung: ");
Serial.print(p_sum_ap);
Serial.println(" W");
Serial.print("Netzfrequenz: ");
Serial.print(net_freq);
Serial.println(" Hz");
Serial.print("Produktion Tag: ");
Serial.print(p_day / 1000);
Serial.println(" kWh");
Serial.print("Produktion Jahr: ");
Serial.print(p_year / 1000);
Serial.println(" kWh");
Serial.print("Produktion Gesamt: ");
Serial.print(p_total / 1000);
Serial.println(" kWh");
Serial.println();
// Negativ Einspeisung, positiv Bezug
if ( in_out >= 0) {
// Bezug
Serial.print("Strom Bezug: ");
Serial.print(in_out);
Serial.println(" W");
Serial.println("Strom Einspeisung: 0.00 W");
} else {
// Einspeisung
Serial.println("Strom Bezug: 0.00 W");
Serial.print("Strom Einspeisung: ");
Serial.print(in_out * -1);
Serial.println(" W");
}
Serial.print("Verbrauch Haus: ");
Serial.print(cons * -1);
Serial.println(" W");
Serial.print("Leistung PV: ");
Serial.print(prod);
Serial.println(" W");
Serial.print("Autonomie: ");
Serial.print(autonomy);
Serial.println(" %");
Serial.print("Eigenverbrauch: ");
Serial.print(selfcons);
Serial.println(" %");
Serial.println();
// OLED
oled.clear();
oled.print("Verbrauch: ");
oled.print(cons * -1);
oled.println(" W");
oled.print("Produktion: ");
oled.print(prod);
oled.println(" W");
// Negativ Einspeisung, positiv Bezug
if ( in_out >= 0) {
// Bezug
oled.print("Bezug: ");
oled.print(in_out);
oled.println(" W");
oled.println("Einspeisg.: 0.00 W");
} else {
// Einspeisung
oled.println("Bezug: 0.00 W");
oled.print("Einspeisg.: ");
oled.print(in_out * -1);
oled.println(" W");
}
// 10s warten
delay(10000);
// Ende loop()
}
// EOF