Verbrauchsmessung Balkonkraftwerk mit openHab

Im August 2023 habe ich das Balkonkraftwerk auf meiner Flachdachgarage in Betrieb genommen. Natürlich ist es schön zu wissen dass man nun selbst Strom erzeugt und den Bezug vom Strombetreiber reduziert, schöner ist es jedoch wenn man die Zahlen hierfür klar vor sich hat. Aus diesem Grund habe ich mich hingesetzt und einige Scripte geschrieben welche mir helfen Verbrauchsmessung Balkonkraftwerk mit openHab auszuwerten und anzeigen zu lassen.

Die Idee

Das Balkonkraftwerk befindet sich auf meiner Flachdachgarage neben dem Haus. Das Haus und die Garage sind über ein ausreichend dimensioniertes Kabel miteinander verbunden worüber die Garage heute den Strom bezieht. In der Garage wurde eine neue Dose installiert an welche das Balkonkraftwerk angeschlossen ist. Die Dose selbst läuft über eine ‘Shelly Plus 1 PM*’ (mit einer 1 gekennzeichnet) welche die Verbrauchsdaten misst. Am Hauptsicherungskasten im Haus ist eine ‘Shelly 3EM*’ installiert (mit einer 2 gekennzeichnet) welche die Verbrauchsdaten aller 3 Phasen misst. Diese Verbrauchsdaten werden bereits per MQTT an openHab gesendet (die Konfiguration hierzu ist in ‘Shelly Verbrauchsdaten über MQTT an openHab senden‘ beschrieben).

Balkonkraftwerk Aufbau

Um nun Dinge wie die Eigenverbrauchsquote des Balkonkraftwerkes oder den Strombezug vom Netzbetreiber zu berechnen benötigen wir einige Messpunkte anhand derer wir die notwendigen Daten halbwegs genau berechnen können.

Verbrauchsmessung Balkonkraftwerk Messpunkte definieren

Die Shellys senden Events per MQTT sobald sich ein Wert verändert. Das heisst, dass wir bei jeder kleinen Änderung einen neuen Wert über den “neuen aktuellen Wert erhalten”. Merken wir uns nun den “altwert”, also den Wert der letzten Nachricht sowie den Zeitpunkt der neuen Nachricht so können wir den Verbrauch in einer Zeitspanne berechnen. Hierzu nehmen wir einfach den alten Wert und multiplizieren diesen mit der Zeit welche zwischen beiden eingegangenen Nachrichten liegt.

Das klingt erstmal etwas “komplex”, funktioniert in der Realität aber ausgezeichnet. Für die eigentliche Berechnung der aktuellen Werte benötige ich nun also 9 Items. Dazu möchte ich gerne noch eine Übersicht über die aktuellen Tageswerte haben welche in weiteren 6 Items abgelegt werden.

Number		stromUpdateTimeStamp   		"letztes Stromupdate [%d]"
Number		stromBezugAltwert			"Strombezug altwert [%d]"
Number 		stromBezugWert			 	"Strombezug Wert [%d]"
Number 		stromEinspeisungAltwert		"Stromeinspeisung Altwert [%d]"
Number 		stromEinspeisungWert			"Stromeinspeisung Wert [%d]"

Number		stromErzeugungAltwert			"Stromerzeugung Altwert[%d]"
Number		stromErzeugungWert			"Stromerzeugung Wert[%d]"
Number		stromErzeugerUpdateTimeStamp		"letzte Update Erzeugung [%d]"

Number		stromErzeugungKwhToday			"Stromerzeugung [%d] kWh"
Number		stromBezugKwhToday			"Strombezug [%d] kWh"
Number		stromEinspeisungKwhToday		"Stromeinspeisung [%d] kWh"
Number		stromVerbrauchKwhToday			"Stromverbrauch [%d] kWh"
Number		stromEigennutzungProzent		"Eigennutzung [%d]"
Number		stromEigennutzungKwhToday		"Eigennutzung [%d] kWh"

Auswertung der MQTT-Events des Stromzählers

Als erstes widme ich mich den Events des Hauptstromzählers. Auf Basis des aktuellen Wertes kann ich entscheiden, ob ich gerade Strom vom Betreiber beziehe oder ob ich Strom ins Netz einspeise (positiver Wert = ich beziehe etwas vom Betreiber). Nachfolgend mein Script:

rule "Stromzaehler Wert Change"
	when
		Item MQTTThing_aktueller_Stromverbrauch changed
	then
		var Number aktuellerWert = MQTTThing_aktueller_Stromverbrauch.state
		val Number letztesUpdateValue = stromUpdateTimeStamp.state;
		var ZonedDateTime now = ZonedDateTime.now();
		var Number vStromBezugAltwert = stromBezugAltwert.state;
		var Number vStromBezugWert = stromBezugWert.state;
		var Number vStromEinspeisungAltwert = stromEinspeisungAltwert.state;
		var Number vStromEinspeisungWert = stromEinspeisungWert.state;
		
		if (vStromBezugWert === NULL || vStromBezugAltwert === NULL) {
			vStromBezugWert = 0;
			vStromBezugAltwert = 0;
			vStromEinspeisungAltwert = 0;
			vStromEinspeisungWert = 0;
		}
		
		var ZonedDateTime letztesUpdate;
		if (letztesUpdateValue === NULL) {
			letztesUpdate = ZonedDateTime.of(LocalDate.now(), LocalTime.MIN, ZoneId.systemDefault());
		} else {
			letztesUpdate = ZonedDateTime.ofInstant(java.time.Instant.ofEpochMilli(letztesUpdateValue.longValue), ZoneId.systemDefault());
		}

		var double zeitspanne = Double.valueOf(java.time.temporal.ChronoUnit.MILLIS.between(letztesUpdate, now)) / 1000;
		if (aktuellerWert > 0) {
			vStromBezugWert += vStromBezugAltwert * zeitspanne;
			stromBezugAltwert.postUpdate(aktuellerWert);
			stromEinspeisungAltwert.postUpdate(0);
		} else {
			aktuellerWert = aktuellerWert * -1;
			vStromEinspeisungWert += vStromEinspeisungAltwert * zeitspanne;
			stromBezugAltwert.postUpdate(0);
			stromEinspeisungAltwert.postUpdate(aktuellerWert);
		}
		
		stromBezugWert.postUpdate(vStromBezugWert)
		stromEinspeisungWert.postUpdate(vStromEinspeisungWert)
		stromUpdateTimeStamp.postUpdate(now.toInstant().toEpochMilli())
end

Ich berechne als erstes die Zeitspanne zwischen dem aktuellen und dem letzten Event. Anschließend prüfe ich, ob ich gerade Strom vom Betreiber beziehe oder ob mein Balkonkraftwerk Strom ins Netz einspeist. Entsprechend dieser Prüfung aktualisiere ich die jeweiligen Werte der Items, setze die Altwerte auf die aktuellen Werte und setze die Timestamp auf die aktuelle Zeit.

Auswertung der MQTT-Events des Balkonkraftwerks

Nachdem wir über den Stromzähler nun wissen ob wir gerade Strom einspeisen oder vom Netz beziehen fehlt uns noch die Information, wie viel Strom unser Balkonkraftwerk gerade erzeugt. Diesen Wert erhalten wir direkt von der Shelly an welche das Balkonkraftwerk angeschlossen ist. Auch hier erstmal mein Script:

rule "Stromerzeugung Wert Change"
    when
		Item MQTTThing_Balkonkraftwerk_Garage_Erzeugung changed
	then
		var Number aktuellerWert = MQTTThing_Balkonkraftwerk_Garage_Erzeugung.state
        	val Number letztesUpdateValue = stromErzeugerUpdateTimeStamp.state;
        	var ZonedDateTime now = ZonedDateTime.now();
		var Number vStromAltwert = stromErzeugungAltwert.state;
        	var Number vStromWert = stromErzeugungWert.state;	

			if (vStromWert === NULL || vStromAltwert === NULL) {
			vStromWert = 0;
			vStromAltwert = 0;
		}

        	var ZonedDateTime letztesUpdate;
        	if (letztesUpdateValue === NULL) {
			letztesUpdate = ZonedDateTime.of(LocalDate.now(), LocalTime.MIN, ZoneId.systemDefault());
		} else {
			letztesUpdate = ZonedDateTime.ofInstant(java.time.Instant.ofEpochMilli(letztesUpdateValue.longValue), ZoneId.systemDefault());
		}

        	var double zeitspanne = Double.valueOf(java.time.temporal.ChronoUnit.MILLIS.between(letztesUpdate, now)) / 1000;
        	vStromWert += vStromAltwert * zeitspanne;
       
		stromErzeugungAltwert.postUpdate(aktuellerWert);
		stromErzeugungWert.postUpdate(vStromWert);
        	stromErzeugerUpdateTimeStamp.postUpdate(now.toInstant().toEpochMilli());
end

Wer das erste Script verstanden hat, für den ist dieses Script selbsterklärend. Wir nehmen den alten Wert des Balkonkraftwerkes und multiplizieren diesen mit der Zeit zwischen dem letzten und dem aktuellen Event. Nun aktualisieren wir noch die entsprechenden Items und schon haben wir die gewünschten Werte.

Berechnung der Tageswerte

Ein wenig mehr habe ich über die Berechnung der Tageswerte gegrübelt. Ich möchte gerne für jeden Kalendertag die Gesamtwerte verfügbar haben. Diese müssen täglich um 0 Uhr zurück gesetzt werden, so dass die Zählung für den neuen Tag wieder korrekt ist. Um es mit der Berechnung nicht zu übertreiben habe ich mich dazu entschieden diese nur alle 15 Minuten durchzuführen. Hierdurch kam es jedoch bei dem täglichen Reset zu einem Problem so dass ich hier eine 2te Prüfung einbaute und nicht nur beim Tageswechsel sondern auch dann wenn der Bezug > 2 KwH in der erste Stunde des Tages (also zwischen 0 und 1 Uhr) ist.

Erneut, anbei erstmal mein Script:

rule "Stromerzeugung Tagswerte"
    when
		Time cron "0 */15 * * * *" // alle 15 Minuten genügt
	then
		// Check if next day
		val Number letztesUpdateValue = stromUpdateTimeStamp.state;
		var ZonedDateTime letztesUpdate;
		if (letztesUpdateValue === NULL) {
			letztesUpdate = ZonedDateTime.of(LocalDate.now(), LocalTime.MIN, ZoneId.systemDefault());
		} else {
			letztesUpdate = ZonedDateTime.ofInstant(java.time.Instant.ofEpochMilli(letztesUpdateValue.longValue), ZoneId.systemDefault());
		}
		
		var Number stromVerbrauchKwhTodayValue = stromVerbrauchKwhToday.state
		
		if ((((stromVerbrauchKwhTodayValue === NULL) || (stromVerbrauchKwhTodayValue > 2)) && (letztesUpdate.toLocalTime().getHour() == 0)) || letztesUpdate.toLocalDate().isBefore(LocalDate.now())) {
			logInfo("rules.stromerzeugung.tageswerte", "Tageswechsel  reset to 0");
			
			// Tageswechsel
			stromBezugAltwert.postUpdate(0);
			stromEinspeisungAltwert.postUpdate(0);
			stromBezugWert.postUpdate(0);
			stromEinspeisungWert.postUpdate(0);
		
			stromErzeugungAltwert.postUpdate(0);
			stromErzeugungWert.postUpdate(0);

			stromUpdateTimeStamp.postUpdate(ZonedDateTime.now().toInstant().toEpochMilli());
			stromErzeugerUpdateTimeStamp.postUpdate(ZonedDateTime.now().toInstant().toEpochMilli());
			
			stromVerbrauchKwhToday.postUpdate(0);
			stromErzeugungKwhToday.postUpdate(0);
			stromEinspeisungKwhToday.postUpdate(0);
			stromBezugKwhToday.postUpdate(0);			
			
			stromEigennutzungKwhToday.postUpdate(0);
			stromEigennutzungProzent.postUpdate(100);
		} else {
			var Number stromBezug = stromBezugWert.state
			var Number stromErzeugung = stromErzeugungWert.state;
			var Number stromEinspeisung = stromEinspeisungWert.state

			if (stromBezug === NULL || stromBezug == 0) {
				stromBezug = 0;
				stromErzeugung = 0;
				stromEinspeisung = 0;
			}
			stromVerbrauchKwhToday.postUpdate((stromBezug + stromErzeugung - stromEinspeisung) / 60 / 60 / 1000);
			stromErzeugungKwhToday.postUpdate((stromErzeugung) / 60 / 60 / 1000);
			stromEinspeisungKwhToday.postUpdate((stromEinspeisung) / 60 / 60 / 1000);
			stromBezugKwhToday.postUpdate((stromBezug) / 60 / 60 / 1000);
			stromEigennutzungKwhToday.postUpdate((stromErzeugung - stromEinspeisung) / 60 / 60 / 1000);
			
			if (stromEinspeisung == 0 || stromErzeugung == 0) {
				stromEigennutzungProzent.postUpdate(100);
			} else {
				stromEigennutzungProzent.postUpdate(100 - (stromEinspeisung / stromErzeugung * 100));
			}
		}
end

Eigentlich ist auch hier keine grosse Magie zu finden. Der Tagesverbrauch ergibt sich aus dem Bezug vom Stromanbieter + dem Eigenverbrauch. Der Eigenverbrauch selbst entspricht dem Wert der Erzeugung abzgl. dem Wert der Einspeisung. Diese Werte werden alle 15 Minuten berechnet und in den entsprechenden Items abgelegt.

Verbrauchsmessung Balkonkraftwerk Visualisierung

So nun haben wir also viele Items welche munter irgend welche Daten speichern und berechnen. Das ist für den ersten Schritt ja schonmal schön, besser wäre es aber doch wenn man diese nun auch noch sauber anzeigen könnte, oder? Zu diesem Zweck habe ich mir 2 neue Seiten angelegt:

aktuelle Werte des Balkonkraftwerkes

Als erstes möchte ich gerne auf einen Blick sehen, wie sich der Verbrauch in meinem Haus gerade jetzt darstellt. Zu diesem Zweck habe ich ein Dashboard erstellt, welches den aktuellen Strombezug, die aktuelle Erzeugung sowie die Tageswerte bis zum aktuellen Zeitpunkt darstellt:

Balkonkraftwerk Liveansicht

Das dargestellte Beispiel ist von einem eher durchschnittlichen Tag mit einigen Wolken. Das Balkonkraftwerk hat bis 14 Uhr 2.22 kWh erzeugt wobei ich 89,32% dieser Erzeugung selbst genutzt habe. Daraus resultiert dass ich 0.24 kWh Strom “verschenkt” habe. Selbiges ist auch in einigen Graphen dargestellt.

historische Analyse der Daten

Neben der Tagesaktuellen Liveansicht ist die historische Sicht auf die Erzeugungswerte des Balkonkraftwerkes natürlich mit die interessanteste Sicht. Auch hierzu habe ich mir ein kleines Dashboard gebaut welches mit auf einen Blick alle relevanten Werte eines Monates anzeigt.

Das angezeigte Dashboard zeigt hierbei eine Kombination aus 4 Werten an. Die Gesamte Tagesproduktion des Balkonkraftwerkes in blau, die eigengenutzte Energie in grün, die ins Netz eingespeiste Energie in Gelb und die vom Stromanbieter bezogene Energie in rot.

Die Werte des Eigenverbrauches und des Netzbezuges wurden hierbei gestapelt dargestellt um den gesamten Strombedarf eines Tages auf einen Blick zu sehen.

Balkonkraftwerk Auswertung -Gesamtübersicht aller täglichen Werte
Balkonkraftwerk Auswertung -Gesamtübersicht aller täglichen Werte

Ein weiteres schönes Feature des Diagramme ist, dass man einzelne Sichten per “Knopfdruck” deaktivieren kann. Somit ist es möglich sich z.B. nur die durch das Balkonkraftwerk erzeugte Energie anzeigen zu lassen, oder aber eben die Werte der Einspeisung oder Eigennutzung. Zusätzlich lassen sich die Diagramme von Haus aus downloaden oder als Tabelle exportieren.

Hier einmal alle Diagramme für den August 2023 im Überblick. Hierbei bitte nicht wundern, die Auswertung beginnt in der Tat erst am 6. August … 🙂

Verbrauchsmessung Balkonkraftwerk – ich bin gespannt

Noch habe ich kein wirkliches Gefühl dafür, wie lange es dauern wird bis sich das angeschaffte Balkonkraftwerk amortisieren wird. Der August war nun wirklich kein sonderlich guter Monat, es hat viel Geregnet. Dazu waren wir ein paar Tage weg was die Eigennutzungsquote leicht nach unten trieb. Ich werde das nun weiter verfolgen und bin gespannt, wie sich das ganze über das nächste Jahr entwickelt. Immerhin konnte das Balkonkraftwerk im August schonmal 86 kWh erzeugen wovon ich 76 kWh selbst nutzen konnte. Die Eigennutzungsquote im August betrug somit 88,37%, für den Anfang schonmal gar nicht so übel …

Artikel teilen

This article was written by Thomas Schiffler

Alles was mit IT zu tun hat steht bei mir hoch im Kurs. Hierbei dreht sich vieles um Java, Python oder auch mal PHP. Unser Zuhause ist mit diversen Raspberry PIs ausgestattet mit welchen ich versuche unser Leben durch etwas Automatisierung ein wenig smarter zu gestalten. Hierbei möchte ich die Technik und die dahinter eingesetzten Tools / Frameworks verstehen und nicht einfach nur Anwenden. Ich selbst bezeichne mich als ITler aus Leidenschaft :) Seit 2020 ist das Thema Chatbot / Voicebot / Conversational.ai in meinen Focus gerückt. In diesem Bereich investiere ich gerade viel Zeit.

0 thoughts on “Verbrauchsmessung Balkonkraftwerk mit openHab”

  1. Danke für die hervorragende Arbeit. Mir ist jedoch aufgefallen, dass ich die openhabPvLiveansicht nicht einbinden kann.
    Der Code wird nach dem Speichern auf
    config:
    label: EnergieÜbersicht
    order: “2”
    sidebar: true
    slots: null

    eingekürzt obwohl nach dem kopieren kein Fehler gemeldet wird.

    m.f.G Christian Emerich

    1. Hi Christian,
      ich habe gerade bei mir nochmal in die Konfiguration reingeschaut und diese mit der verglichen die hier veröffentlicht ist verglichen. Der Code selbst ist erstmal gleich
      Warum er die Slots bei Dir auf null setzt kann ich leider nicht sagen – wenn Du möchtest können wir mal einen Videocall machen und gemeinsam drauf gucken?
      Falls Du darauf Lust hast schreib mich gerne über das Kontaktformular an dann schauen wir mal ob wir ein gemeinsames Zeitfenster und eine Lösung finden
      Gruß Thomas

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert