Überschussleistung Laden

Allgemeine Fragen rund um die "Smart Home" Hardware/Komponenten

Moderatoren: seppy, udo1toni

Benutzeravatar
udo1toni
Beiträge: 13864
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Überschussleistung Laden

Beitrag von udo1toni »

Ah, klar... rrd4j gibt logischerweise immer eine Zahl zurück. Wobei ich aber nicht sicher bin, ob das auch der Fall ist, wenn keine Daten vorliegen. Die Zeile als solche hat also ihre Berechtigung, Du kannst aber hinten das „as Number“ weg lassen. Damit fällt auch die Klammer um den Ausdruck weg. (Öffnende Klammer nach dem if() und schließende Klammer vor dem else)


Gesendet von iPad mit Tapatalk
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Re: Überschussleistung Laden

Beitrag von shuo »

Danke Udo!

mcdandrew
Beiträge: 163
Registriert: 13. Dez 2018 17:42

Re: Überschussleistung Laden

Beitrag von mcdandrew »

Ich versuche mich seit ein paar Tagen ebenfalls einer einer Regel für die Überschussladung.
Soweit sollte es funktionieren allerdings würde ich gerne verhindern, dass bei jeder Wolke die Ladung unterbrochen wird.
Meine Idee ist es wie bereits in diesem Thread erwähnt, einen Timer laufen zu lassen, welcher bspw. nach 5 Minuten Erzeugungsleistung kleiner 1380W die Ladung unterbricht. Ich bekomme es aber nicht hin... :|

Code: Alles auswählen

val reduceFactor = 0.90 // Faktor, um newPower zu reduzieren, um weniger nahe an der verfügbaren Leistung zu sein, z.B. 0,9 setzt newPower auf 90% der möglichen Leistung

rule "PV Charging"
when
	Item huawei_last changed 	// Aktuelle Netzeinspeisung (positiver Wert) / Netzbezug (negativer Wert)
then
	//nur wenn ladenmodus == PV Überschuss 
	if(goecharger_lademodus.state == 1)
	{
		//Aktuelle Netzeinspeisung / Netzbezug
		var int verfuegbareLeistung = (huawei_last.state as Number).intValue
		
		//mögliche Leistung berechnen
		var int newPower = (verfuegbareLeistung * reduceFactor).intValue
		
		//Wenn mögliche Leistung kleiner 6A nicht laden bzw. unterbrechen
		//ToDo Timer einfügen
		if (newPower < 1380) 
		{ 
			if(goecharger_allow.state == 1)		//Wenn aktuell geladen wird, Ladung abbrechen
			{
				goecharger_allow.sendCommand(0)
			}
			return
		}
		else
		{
			//prüfen ob mögliche Leistung größer der Kabelcodierung, falls ja Leistung auf Kabelcodierung reduzieren 
			if (newPower / 230 > (goecharger_cable_current.state as Number)) 
			{
				goecharger_ampere.sendCommand(goecharger_cable_current.state as Number)
			}
			else
			{
				goecharger_ampere.sendCommand(newPower/230)
			}
			if(goecharger_allow.state == 0)		//Wenn aktuell nicht geladen wird, Ladung starten
			{
				goecharger_allow.sendCommand(1)
			}
		}
	}
end

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Re: Überschussleistung Laden

Beitrag von shuo »

Hi,

ich würde Dir empfehlen nicht mit einem Timer zu arbeiten, sondern vielmehr die Funktion des Mittelwertes zu verwenden.
Ich benutze aktuell den Mittelwert von 5 Min was ganz gut läuft. Ich hab auch als prio und eine Abhängigkeit noch mein aktuellen Verbrauch im Haus mit berücksichtigt....
Den Timer habe ich eingebaut, damit meine Wallbox nach 5 min ausschaltet. Das heißt wenn 5 min der Verbrauch höher ist als die Produktion wird abgeschalten
Hier ein Auszug:

Code: Alles auswählen

    if (Symo_PowerflowchannelpgridkW.state < 0 ){
        val Number nPV_smoothed   = if(Symo_Inverterdatachannelpac.state instanceof Number) 		(Symo_Inverterdatachannelpac.averageSince(now.minusMinutes(5), "rrd4j") as Number).floatValue else 0
        val Number nHaus_smoothed = if(Symo_Powerflowchannelpload.state instanceof Number) (Symo_Powerflowchannelpload.averageSince(now.minusMinutes(5), "rrd4j") as Number).floatValue else 500 
(Symo_Inverterdatachannelpac.averageSince(now.minusMinutes(1), "rrd4j") as Number) else 0

        val Number nPV   = if(Symo_Inverterdatachannelpac.state instanceof Number) (Symo_Inverterdatachannelpac.state as Number).floatValue else 0
        val Number nHaus = if(Symo_Powerflowchannelpload.state instanceof Number) (Symo_Powerflowchannelpload.state as Number).floatValue else 500 // zu erwartender Spitzenbedarf als Default Wert

        logInfo("Verfügbare Energie", "nPV_smoothed: {}, nHaus_smoothed: {}, nPV: {}, nHaus: {},", nPV_smoothed, nHaus_smoothed, nPV, nHaus )
        
        val Number nDiff = nPV - ( -1 * nHaus)
        val Number nDiff_smoothed = nPV_smoothed - (-1 * nHaus_smoothed)

        Available_Energy.sendCommand(nDiff)
        Charging_Energy.sendCommand(nDiff_smoothed)
        
    } else {
        Available_Energy.sendCommand(0)
        Charging_Energy.sendCommand(0)

    }

    if(((Symo_PowerflowchannelpgridkW.state as Number).floatValue > (Symo_Inverterdatachannelpac.state as Number).floatValue) 
    && tCharge === null 
    && RenaultZEServices_Zoe_Charging.state == "Charging"
    && KebaState.state == 3 ){
        tCharge = createTimer(now.plusMinutes(5),[|
            sendBroadcastNotification("Achtung. Keine Sonnenenergie. Es 100% Netzbezug beim laden. Schalte Ladevorgang ab" )
            KebaSwitch.sendCommand(OFF)
            tCharge = null
        ])}
    else if ((Symo_PowerflowchannelpgridkW.state as Number).floatValue < (Symo_Inverterdatachannelpac.state as Number).floatValue) {
        tCharge?.cancel
        tCharge = null
    }

end
Bei Fragen einfach melden

mcdandrew
Beiträge: 163
Registriert: 13. Dez 2018 17:42

Re: Überschussleistung Laden

Beitrag von mcdandrew »

Vielen Dank für deine Unterstützung...aber ganz ehrlich bei deinem Code bin ich raus :?
Das ist mir doch eine Nummer zu heftig...

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Re: Überschussleistung Laden

Beitrag von shuo »

Wenn Du möchtest, kann ich Dir mit Kommenataren helfen....
Was hast denn für eine Wallbox, bzw Wechselrichter? Welche Items stehen zur Verfügung?

Benutzeravatar
udo1toni
Beiträge: 13864
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Überschussleistung Laden

Beitrag von udo1toni »

Ich hab die Rule mal etwas umgeschrieben, damit der Code etwas klarer wird:

Code: Alles auswählen

// Teil 1
    var Number nPV = 0                                                                                               // definiere Variable mit Default 0
    if(Symo_Inverterdatachannelpac.state instanceof Number)                                                          // Falls das Item gültig ist
        nPV =(Symo_Inverterdatachannelpac.state as Number).floatValue                                                // Übernimm Itemstatus 
    var Number nHaus = 500                                                                                           // definiere Variable mit Default 500
    if(Symo_Powerflowchannelpload.state instanceof Number)                                                           // ...
        nHaus = (Symo_Powerflowchannelpload.state as Number).floatValue                                              // ...
    var Number nPV_smoothed = 0                                                                                      // ...
    if(Symo_Inverterdatachannelpac.averageSince(now.minusMinutes(5), "rrd4j") instanceof Number)                     // Falls die Persistence einen gültigen Wert liefert
        nPV_smoothed = (Symo_Inverterdatachannelpac.averageSince(now.minusMinutes(5), "rrd4j") as Number).floatValue // Übernimm den Wert der Persistence
    var Number nHaus_smoothed = 500                                                                                  // ...
    if(Symo_Powerflowchannelpload.averageSince(now.minusMinutes(5), "rrd4j") instanceof Number)                      // ...
        nHaus_smoothed = (Symo_Powerflowchannelpload.averageSince(now.minusMinutes(5), "rrd4j") as Number).floatValue// ... 
    var Number nPower = 0                                                                                            // ...
    if(Symo_PowerflowchannelpgridkW.state instanceof Number)                                                         // ...
        nPower = (Symo_PowerflowchannelpgridkW.state as Number).floatValue                                           // ...
// Teil 2
    var Number nDiff = 0                                                                                             // ...
    var Number nDiff_smoothed = 0                                                                                    // ...
    if(nPV + nHaus > 0)                                                                                              // nur falls Wert größer 0
        nDiff = nPV + nHaus                                                                                          // Übernimm Wert
    if(nPV_smoothed + nHaus_smoothed > 0)                                                                            // nur falls Wert größer 0
        nDiff_smoothed = nPV_smoothed + nHaus_smoothed                                                               // Übernimm Wert
// Teil 3
    logInfo("Verfügbare Energie", "nPV_smoothed: {}, nHaus_smoothed: {}, nPV: {}, nHaus: {},", nPV_smoothed, nHaus_smoothed, nPV, nHaus )
    Available_Energy.sendCommand(nDiff)
    Charging_Energy.sendCommand(nDiff_smoothed)
// Teil 4
    if(nPower < nPV) {                                                                                               // Falls Strommenge ausreichend
        tCharge?.cancel                                                                                              // brich einen laufenden Timer ab
        tCharge = null                                                                                               // und lösche ihn
    } else {                                                                                                         // Falls Strommenge nicht ausreichend
        if(tCharge === null && RenaultZEServices_Zoe_Charging.state == "Charging" && KebaState.state == 3 )          // Falls kein Timer vorhanden und Zoe lädt auf Stufe 3(?)
            tCharge = createTimer(now.plusMinutes(5), [|                                                             // Erzeuge Abschlattimer
                sendBroadcastNotification("Achtung. Keine Sonnenenergie. 100% Netzbezug beim Laden. Schalte Ladevorgang ab" )
                KebaSwitch.sendCommand(OFF)
                tCharge = null
            ])
    }
end
Der ternäre Operator (a = if(b) c else d) ist schick, um eine lokale Konstante mit einem von zwei Werten zu belegen. In obigem Codebeispiel wird es aber leider sehr unübersichtlich, obwohl die verschiedenen Schritte recht einfach sind.

Der erste Teil des Codes überträgt alle Status der verschiedenen Items bzw. der Persistence Quelle in lokale Variablen. Dabei wird beachtet, dass Teile dieser Werte eventuell nicht zur Verfügung stehen. In diesem Fall wird dann ein Default Wert gesetzt.

Im zweiten Teil werden die Differenzen berechnet. Hier wird dafür gesorgt, dass der niedrigste Wert jeweils 0 ist.

Der dritte Teil gibt die Werte im Log aus und befüllt die Anzeige für die UI.

Im vierten Teil wird ein Timer gesteuert, falls der Verbrauch über der Produktion liegt, wird der Timer angelegt (nur, falls der Zoe gerade lädt). Falls der Verbrauch unter der Produktion liegt, wird ein eventuell laufender Timer abgebrochen.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

mcdandrew
Beiträge: 163
Registriert: 13. Dez 2018 17:42

Re: Überschussleistung Laden

Beitrag von mcdandrew »

Wenn Du möchtest, kann ich Dir mit Kommenataren helfen....
Was hast denn für eine Wallbox, bzw Wechselrichter? Welche Items stehen zur Verfügung?
Ich habe einen Huawei Wechselrichter und einen goeCharger verbaut. Die folgenden Items stehen zur Verfügung:

Wechserlrichter
Number Huawei_Last --> postiver Wert --> aktuelle Einspeiseleistung, d.h. Überschuss der ins Netz geht
--> negativer Wert --> aktueller Bezug aus dem Netz
Number Active_power --> Aktuelle AC Erzeugungsleistung der Wechselrichters

Ladestation
Number goecharger_state --> aktueller Status (Auto verbunden, Auto verbunden und lädt, Auto nicht verbunden)
Number goecharger_allow --> Ladefreigabe ja (1)/nein (0)
Number goecharger_ampere --> Ladestärke in Ampere (6 - 16A)

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Re: Überschussleistung Laden

Beitrag von shuo »

Naja, ich finde Udo hat eine vorbilldliche Erklärung hier eingestellt, die mich auch nochmal dazu bewegt hat meinen Code anzupassen und "hübscher" zu machen:)

Udo, ich hätte da mal eine Frage. Ich habe Teil 3 (Logging) benutzt um zu die Glättung zu sehen. Jetzt würde ich gerne das Regeln beginnen.
Grundsätzlich kann ich die Leistung mit dem Strom einstellen. Ich habe "respekt" vor einer do-while Schleife.
Hast eine Idee, wie ich das "elegant" lösen kann?

Also sowas wie (pseudo code):

Code: Alles auswählen

do (erhöhe / reduziere den Strom)
while (Verfügbare Leistung == Ladeleistung )

mcdandrew
Beiträge: 163
Registriert: 13. Dez 2018 17:42

Re: Überschussleistung Laden

Beitrag von mcdandrew »

Auch nach einer Stunde intensiven lesen des Codes verstehe ich es einfach nicht.

Zum Teil ist mir unklar welche Bedeutung die Variablen im Codebeispiel haben

nPV = Erzeugungsleistung des Wechselrichters
nHaus = Verbrauch im Haus

Doch was bedeutet "Symo_Inverterdatachannelpac", "Symo_Powerflowchannelpload", "nPV_smoothed " usw....?


Ich habe mich jetzt mal selbst heran getastet und denke soweit sollte der Quellcode passen.
Was mir noch fehlt ist eine Art Timer welcher ein ständiges switchen zwischen ON und OFF verhindert.
Das ständige anpassen der Ladestärke sollte kein Problem sein....bei der Rekuperation macht das Fahrzeug ja eigentlich auch nichts anderes.

Code: Alles auswählen

val reduceFactor = 0.90 // Faktor, um newPower zu reduzieren, um weniger nahe an der verfügbaren Leistung zu sein, z.B. 0,9 setzt newPower auf 90% der möglichen Leistung

//PV geführtes Laden
rule "PV laden"
when
    Item Huawei_Last changed
then
	//Lademodus: 1 = PV geführtes Laden und Charger bereit (Fahrzeug angeschlossen)
	if(goecharger_lademodus.state == 1 && goecharger_state.state == 4)
	{
		//Aktuelle Leistung (negativ = Netzbezug, postiv = Erzeugung
		var Number leistung = (Huawei_Last.state as Number).intValue
		//mögliche Leistung berechnen
		var Number newPower = (leistung * reduceFactor).intValue
		
		//Wenn mögliche Leistung kleiner 6A laden beenden
		if (newPower < 1380) 
		{ 
			goecharger_allow.sendCommand(0)		//Ladung beenden
			return
		}
		else
		{
			//prüfen ob mögliche Leistung größer der Kabelcodierung, falls ja Leistung auf Kabelcodierung reduzieren 
			if (newPower / 230 > (goecharger_cable_current.state as Number)) 
			{
				goecharger_ampere.sendCommand((goecharger_cable_current.state as Number))
				goecharger_allow.sendCommand(1)
				return
			}
			else
			{
				goecharger_ampere.sendCommand(newPower/230)
				goecharger_allow.sendCommand(1)
			}
		}
    }
end

Antworten