EV Ladeplanung über mehrere Ladepunkte

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Antworten
int5749
Beiträge: 1173
Registriert: 4. Nov 2019 22:08
Answers: 9

EV Ladeplanung über mehrere Ladepunkte

Beitrag von int5749 »

Hallo zusammen,

nachdem ich bereits in einem anderen Threat zum Timer nun (hoffentlich nachhaltig) verstanden habe wie man diesen nutzt, habe ich heute Nacht eine andere Schwachstelle meiner Ladeplanung festgestellt. Derzeit habe ich nämlich nur 1 Switch Item für das "Komfortladen" und gestern Nacht waren zufällig mal beide Auto's verbunden und haben somit geladen. Das war nicht so geplant, aber OK.

Meine Idee: Ich möchte pro Auto die Ladeplanung aktivieren und dann muss die Rule herausfinden, an welchem Ladepunkt das Auto verbunden ist und diese dann entsprechend steuern.

Herausforderung: Die Auto's sind nicht direkt in openHAB bekannt, nur die Ladepunkte. Natürlich gibt es dann pro Ladepunkt entsprechende Item zu Fahrzeug verbunden, Fahrzeugname aus der Konfiguration, SoC, Ladestrom, Ladepunkt Name, etc.

Meine Überlegung: Sobald ein Auto an einem Ladepunkt angeschlossen wird, füllt sich ja das Item Fahrzeugname aus der Konfiguration mit dem Namen eins Fahrzeugs. Problem: Der Fiat 500 erst einmal nur als Gastfahrzeug erkannt und muss manuell umgestellt werden. Somit würde ich die beiden Items der Fahrzeugnamen in eine Gruppe packen und auf Memberof Changed triggern.

Hier hänge ich nun , denn wie würde ich dann den Ladeunkt ermitteln und wie diesen dann steuern.

Somit habe ich noch keinen Sample Code, denn das Triggern der Items ist ja standard, aber die weitere Nutzung/Filterung eben meine Hürde :-/

Bin für Ideen offen, um das smart zu lösen.

Viele Grüße und schönen Sonntag noch.
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

int5749
Beiträge: 1173
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: EV Ladeplanung über mehrere Ladepunkte

Beitrag von int5749 »

Nachdem der Nachmittag mit Grübelei drauf gegangen ist, versuche ich es gerade zu sehr auf die Spitze zu treiben.
Ich mache einfach je Ladepunkt eine Rule und die Auswertung der Batterie in der Rule wo beide Auto's angeschlossen sein könnten.
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

int5749
Beiträge: 1173
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: EV Ladeplanung über mehrere Ladepunkte

Beitrag von int5749 »

So, meine Rule für die Ladeplanung mit 2 Ladepunkten ist nun komplett überarbeitet und in 1 Rule zusammengedampft. Die Trockenübung ist bereits positiv verlaufen und ich bin auf den ersten Einsatz gespannt.

Dennoch möchte ich das Setup hier schon einmal vorstellen und freue mich über Verbesserungsvorschläge :)

Die eigentliche Regelung erfolgt weiterhin in evcc und diese Software wird mit der Rule und über das evcc Binding (ginge auch über MQTT) angesteuert.
In erster Linie läuft der Smart Charge Prozess Nachts mit Zielladung auf eine variable Uhrzeit am nächsten Morgen.

Items mit einigen Gruppen

Code: Alles auswählen

// Neu für Ladeplanung
Group gLPConnected          // Status ob Fahrzeug angeschlossen wurde, für gSmartCharge
Group gSmartCharge          // Sichtbarkeit Smart Charge wenn Fahrzeug angeschlossen ist
Group gLPSetSmartCharge     // Aktiviere Smart Charge pro Ladepunkt
Group gLPCancelSmartCharge  // Deaktiviere Smart Charge pro Ladepunkt
Group gLPVehicleTitle       // Angeschlossenes Fahrzeug
Group gLPEVChargeEndHour    // Stunde für Zielzeit
Group gLPEVChargeEndMinute  // Minute für Zielzeit
Group gLPVehicleSoC         // SoC des angeschlossenen Fahrzeugs
Group gLPTargetSoC          // Ziel SoC bei erreichen der Zielzeit, nur für Berechnung relevant
Group gLPSmartChargeStatus  // Status Text Zeile
Group gLPMaxCurrent         // max. Ladestrom pro Ladepunkt
Group gLPMode               // Lademodus pro Ladepunkt

String LP1_Title                        "[%s]"                                              {channel="evcc:device:sunergy:loadpoint0#title"}
Switch LP1_VehicleConnected             "Loadpoint1 vehicle connected"  (gLPConnected)      {channel="evcc:device:sunergy:loadpoint0#vehicleConnected"}
String LP1_VehicleTitle                 "Loadpoint1 vehicle title"      (gLPVehicleTitle)   {channel="evcc:device:sunergy:loadpoint0#vehicleTitle"}
Number:Dimensionless LP1_VehicleSoC     "Loadpoint1 vehicle so c"       (gLPVehicleSoC)     {channel="evcc:device:sunergy:loadpoint0#vehicleSoC"}
Number:Dimensionless LP1_TargetSoC      "Loadpoint1 target so c"        (gLPTargetSoC)      {channel="evcc:device:sunergy:loadpoint0#targetSoC"}
Number:ElectricCurrent LP1_MaxCurrent   "Loadpoint1 max current"        (gLPMaxCurrent)     {channel="evcc:device:sunergy:loadpoint0#maxCurrent"}
String LP1_Mode                         "Loadpoint1 mode"               (gLPMode)           {channel="evcc:device:sunergy:loadpoint0#mode"}
Switch vLP1_SmartCharge     (gSmartCharge)  // Aktivierung SmartCharge LP1
String LP1_SmartChargeStatus    "[%s]"                          (gLPSmartChargeStatus)
Switch LP1_SmartCharge			"Smartes Zielladen EV"			<ladesaeule>
Switch LP1_SetSmartCharge		"Aktiviere Timer"               (gLPSetSmartCharge)
Switch LP1_DeleteSmartCharge	"Lösche Timer"  (gLPCancelSmartCharge)  {autoupdate="false"}
Number LP1_EVChargeEndHour		"Ladepunkt 1 Zielstunde [%d]"	<time>  (gLPEVChargeEndHour)
Number LP1_EVChargeEndMinute	"Ladepunkt 1 Zielminute [%d]"	<time>  (gLPEVChargeEndMinute)

String LP2_Title                        "[%s]" {channel="evcc:device:sunergy:loadpoint1#title"}
Switch LP2_VehicleConnected             "Loadpoint2 vehicle connected" (gLPConnected)  {channel="evcc:device:sunergy:loadpoint1#vehicleConnected"}
String LP2_VehicleTitle                 "Loadpoint2 vehicle title"    (gLPVehicleTitle)   {channel="evcc:device:sunergy:loadpoint1#vehicleTitle"}
Number:Length LP2_VehicleRange          "Reichweite"        {channel="evcc:device:sunergy:loadpoint1#vehicleRange"}
Number:Energy LP2_VehicleCapacity       "Batteriegröße"     {channel="evcc:device:sunergy:loadpoint1#vehicleCapacity"}
Number:Length LP2_VehicleOdometer       "Kilometerstand"    {channel="evcc:device:sunergy:loadpoint1#vehicleOdometer"}

Number:Dimensionless LP2_VehicleSoC     "Ladestand"     (gLPVehicleSoC)    {channel="evcc:device:sunergy:loadpoint1#vehicleSoC"}
Number:Dimensionless LP2_TargetSoC      "Ziel Ladestand"    (gLPTargetSoC)  {channel="evcc:device:sunergy:loadpoint1#targetSoC"}
Number:ElectricCurrent LP2_MaxCurrent   "max. Ladestrom"  (gLPMaxCurrent) {channel="evcc:device:sunergy:loadpoint1#maxCurrent"}
String LP2_Mode                         "Loadpoint1 mode"   (gLPMode) {channel="evcc:device:sunergy:loadpoint1#mode"}
Switch vLP2_SmartCharge     (gSmartCharge)  // Aktivierung SmartCharge LP2
String LP2_SmartChargeStatus    "[%s]"                          (gLPSmartChargeStatus)
Switch LP2_SmartCharge			"Smartes Zielladen EV"			<ladesaeule>
Switch LP2_SetSmartCharge		"Aktiviere Timer"               (gLPSetSmartCharge)
Switch LP2_DeleteSmartCharge	"Lösche Timer"  (gLPCancelSmartCharge)  {autoupdate="false"}
Number LP2_EVChargeEndHour		"Ladepunkt 2 Zielstunde [%d]"	<time>  (gLPEVChargeEndHour)
Number LP2_EVChargeEndMinute	"Ladepunkt 2 Zielminute [%d]"	<time>  (gLPEVChargeEndMinute)
Rule

Code: Alles auswählen

rule "Smart Charge"
when
    Member of gLPSetSmartCharge received command or
    Member of gLPCancelSmartCharge received command
then
    val actions = getActions("pushover", "pushover:pushover-account:account")

    // Wer war es?
    val vLPSC = triggeringItem.name.split("_").get(0)
    var vTimerName = "timer_" + vLPSC

    if (receivedCommand==OFF) {
        chargeTimers.get(vTimerName)?.cancel;
        gLPSmartChargeStatus.members.filter[ i | i.name.contains(vLPSC.toString)].head.postUpdate(NULL)
        gSmartCharge.members.filter[ i | i.name.contains(vLPSC.toString)].head.postUpdate(ON)
        return;
    } else if (receivedCommand==ON) {

        // Doppelter Boden ob Fahrzeug verbunden ist
        if(!(gLPConnected.members.filter[ i | i.name.contains(vLPSC.toString)].head.state == ON)) {
            actions.sendMessageToDevice("J", "Kein Fahrzeug am Ladepunkt verbunden", "EV Smart Start")
            return;
        }
    
        // Welches Auto ist verbunden
        val vVehicleName = gLPVehicleTitle.members.filter[ i | i.name.contains(vLPSC.toString)].head.state

        if (vVehicleName.toString == "EV6 GT-Line") {
		    vBatCapacity = 0.74
        } else if (vVehicleName.toString == "Knutschkugel") {
    		vBatCapacity = 0.373
        } else {
            gLPSmartChargeStatus.members.filter[ i | i.name.contains(vLPSC.toString)].head.postUpdate(NULL)
            actions.sendMessageToDevice("J", "Batteriekapazität unbekannt", "EV Smart Start")
            return;
        }

        // Vehicle SoC
        if(!(gLPVehicleSoC.members.filter[ i | i.name.contains(vLPSC.toString)].head.state instanceof Number)) {
            logWarn("smartCharge", "{} liefert keinen aktuellen Ladezustand! Abbruch.", vVehicleName)
            return;
        }
        val Integer iVSoc = (gLPVehicleSoC.members.filter[ i | i.name.contains(vLPSC.toString)].head.state as Number).intValue

        // Set Target Time
        var Integer iHour = 6
        if(!(gLPEVChargeEndHour.members.filter[ i | i.name.contains(vLPSC.toString)].head.state instanceof Number)) {
            logWarn("smartCharge","Kann Zielstunde nicht lesen! Nutze Vorgabe 6 Uhr")
        } else {
            iHour = (gLPEVChargeEndHour.members.filter[ i | i.name.contains(vLPSC.toString)].head.state as Number).intValue
        }
        var Integer iMinute = 40
        if(!(gLPEVChargeEndMinute.members.filter[ i | i.name.contains(vLPSC.toString)].head.state instanceof Number)) {
            logWarn("smartCharge","Kann Zielminute nicht lesen! Nutze Vorgabe 40 Minuten")
        } else {
            iMinute = (gLPEVChargeEndMinute.members.filter[ i | i.name.contains(vLPSC.toString)].head.state as Number).intValue
        }

        // Target SoC
        var Integer iTSoc = 85
        if(!(gLPTargetSoC.members.filter[ i | i.name.contains(vLPSC.toString)].head.state instanceof Number)) {
            logWarn("smartCharge","Kann Zirl SOC nicht lesen! Nutze Vorgabe 85%")
        } else {
            iTSoc = (gLPTargetSoC.members.filter[ i | i.name.contains(vLPSC.toString)].head.state as Number).intValue
        }

        // Get Max Current Power Item
        val vLPMaxCurrent = (gLPMaxCurrent.members.filter[ i | i.name.contains(vLPSC.toString)].head)

        // Get Lodpoint Operation Mode Item
        val vLPMode = (gLPMode.members.filter[ i | i.name.contains(vLPSC.toString)].head)

        val Integer iDelta = ((iTSoc as Number).intValue - (iVSoc as Number).intValue)

        val vPower = ((iDelta * vBatCapacity) - 4.140).floatValue
        val Integer iDuration = ((vPower / 0.138) + 45).intValue

        val chargeEnd = LocalDateTime.of(LocalDate.now.plusDays(1), LocalTime.of(iHour,iMinute,0))
        val chargeStart = chargeEnd.minusMinutes(iDuration)

        if (chargeStart > LocalDateTime.now) {
            gLPSmartChargeStatus.members.filter[ i | i.name.contains(vLPSC.toString)].head.postUpdate(chargeStart.toString)

            // handle timer
            chargeTimers.get(vTimerName)?.cancel;
            chargeTimers.put(vTimerName, createTimer(now().with(chargeStart)) [|
                tChargeCurrent?.cancel                              // beende einen möglichen Timer
                vLPMaxCurrent.sendCommand((6 as Number).intValue)   // setzte initiale Stromstärke

                // starte Ladung
                vLPMode.sendCommand("off")
                tChargeCurrent = createTimer(now.plusMinutes(15),[| //15 Min
                    if((vLPMaxCurrent.state as Number).intValue < 12) {
                        vLPMaxCurrent.sendCommand((vLPMaxCurrent.state as Number).intValue + 2)
                        tChargeCurrent.reschedule(now.plusMinutes(15)) //15 Min
                    }
                ])
            ])
    //    chargeTimers.remove(vTimerName) //notwendig??
            gSmartCharge.members.filter[ i | i.name.contains(vLPSC.toString)].head.postUpdate(OFF)
        } else {
            gLPSmartChargeStatus.members.filter[ i | i.name.contains(vLPSC.toString)].head.postUpdate("ACHTUNG, Zeit reicht nicht")
        }
    }
end
Auszug aus der Sitemap

Code: Alles auswählen

			Frame item=LP2_Title {
				Text item=LP2_VehicleTitle label="" icon="smaevcharger" {
					Text item=LP2_VehicleCapacity
					Text item=LP2_VehicleSoC
					Text item=LP2_VehicleRange
					Text item=LP2_VehicleOdometer
				}
				Switch item=LP2_Mode label="Lademodus" mappings=[off="AUS", pv="PV",minpv="Min+PV", now="Schnell"] visibility=[LP2_VehicleConnected == ON]
				Setpoint item=LP2_MaxCurrent label="Max Current" minValue=6 maxValue=16 step=1 visibility=[LP2_VehicleConnected == ON]
				Slider item=LP2_TargetSoC minValue=10 maxValue=100 step=5 visibility=[LP2_VehicleConnected == ON]
				Text label="Smart Charge" visibility=[LP2_VehicleConnected == ON] {
					Text item=LP2_SmartChargeStatus
					Slider item=LP2_EVChargeEndHour minValue=0 maxValue=23 step=1
					Slider item=LP2_EVChargeEndMinute minValue=0 maxValue=59 step=5
					Switch item=LP2_SetSmartCharge mappings=[ON="Smart Charge"] visibility=[vLP2_SmartCharge == ON]
					Switch item=LP2_DeleteSmartCharge mappings=[OFF="Cancel"] visibility=[vLP2_SmartCharge == OFF]
				}
			}
Offene Punkte für finale Version
  • Harmonisierung der Items über die Ladepunkte (Odometer, etc) <Kosmetik
  • Ggfs auftretende Fehler bereinigen oder abfangen
  • Abfrage ob Zeitpunkt der Aktivierung bereits nach 0:00 liegt um dann beim Timer nicht einen Tag zu addieren
Viele Grüße
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

int5749
Beiträge: 1173
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: EV Ladeplanung über mehrere Ladepunkte

Beitrag von int5749 »

So, ich muss diesen Thread noch einmal nach oben holen, denn einige Punkte sind für mich noch ein Rätsel.

Vorweg: Die Rule scheint zu laufen, ich meine auch bei Timern für bei Ladepunkte in der selben Nacht.

Jedoch scheint das nur für den Start zu gelten, die stufenweise Regelung scheint nicht so recht zu laufen.

Frage: Welche Informationen werden denn in den Timer übergeben, oder welche müsste ich übergeben, damit im Charge-Timer dann auch der richtige Ladepunkt geregelt wird? Hierbei stehe ich noch auf dem Schlauch :/
Derzeit vermute ich, dass die Regelung so nur zufällig läuft und ich ggfs in dem Timer noch einmal den entsprechenden Ladepunkt filtern muss? Aber wie würde dieser dann identifiziert?

Im Moment sehe ich wohl den Wald vor lauter Bäumen nicht :/
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

Antworten