Hallo zusammen,
ich hab die Frage schonmal im Allgemeinen gestellt, aber hier ist sie sicher besser aufgehoben.
ich nutze ein DOIF um meinen PV Akku vorzugeben ob er nach dem PV Forecast nun geladen werden darf oder nicht.
Dazu stelle ich die maximale Ladeleistung auf 0, oder einen per reading definierten Wert.
Das klappt soweit auch gut, nur wenn ich das reading "BatMaxCharge" ändere wird keine Aktion ausgeführt, weil ja der DOIF Zweig wieder der gleiche wäre, also läd die Batterie weiter mit der alten Leistung.
Ein do always möchte ich aber nicht einfügen, weil ich sonst ständig die Befehle zur Batterie senden würde.
defmod doif_PvBatteryChargeForecast DOIF (\
([PV_SolarForecast:Battery_ChargeUnrestricted_01] == 1) or\
([PV_SolarForecast:Battery_ChargeRequest_01] == 1) or\
([Fronius_Symo1:Storage_0_Controller_StateOfCharge_Relative] < [PV_SolarForecast:Battery_OptimumTargetSoC_01:d])\
)\
(set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
DOELSE\
(set PV_Batterie BatConfigMaxChargeWatt 0;; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
attr doif_PvBatteryChargeForecast checkall all
attr doif_PvBatteryChargeForecast event-min-interval .*:3600
attr doif_PvBatteryChargeForecast event-on-change-reading .*
attr doif_PvBatteryChargeForecast readingList BatMaxCharge
attr doif_PvBatteryChargeForecast room PV
attr doif_PvBatteryChargeForecast setList BatMaxCharge:selectnumbers,0,250,6000,0,lin
attr doif_PvBatteryChargeForecast webCmd enable:disable:BatMaxCharge
attr doif_PvBatteryChargeForecast webCmdLabel ::BatMaxCharge
setstate doif_PvBatteryChargeForecast cmd_1
setstate doif_PvBatteryChargeForecast 2025-08-05 19:26:45 BatMaxCharge 2500
setstate doif_PvBatteryChargeForecast 2025-08-06 19:16:27 Device Fronius_Symo1
setstate doif_PvBatteryChargeForecast 2025-08-06 17:10:31 cmd 1
setstate doif_PvBatteryChargeForecast 2025-08-06 17:10:31 cmd_event PV_SolarForecast
setstate doif_PvBatteryChargeForecast 2025-08-06 17:10:31 cmd_nr 1
setstate doif_PvBatteryChargeForecast 2025-08-06 19:16:27 e_Fronius_Symo1_Storage_0_Controller_StateOfCharge_Relative 79.7
setstate doif_PvBatteryChargeForecast 2025-08-06 18:42:12 e_PV_SolarForecast_Battery_ChargeRequest_01 0
setstate doif_PvBatteryChargeForecast 2025-08-06 19:11:36 e_PV_SolarForecast_Battery_ChargeUnrestricted_01 1
setstate doif_PvBatteryChargeForecast 2025-08-06 18:42:12 e_PV_SolarForecast_Battery_OptimumTargetSoC_01 20 %
setstate doif_PvBatteryChargeForecast 2025-08-04 19:14:12 mode enabled
setstate doif_PvBatteryChargeForecast 2025-08-06 17:10:31 state cmd_1
Ich hab mal ein bischen probiert.
Erstmal hab ich versucht nach dem Ändern händisch ein "set doif_PvBatteryChargeForecast checkall" aufzurufen.
Selbst da hat er den Befehl nicht nochmals mit dem neuen Wert geschrieben.
Erst nachdem ich
set doif_PvBatteryChargeForecast initialize
set doif_PvBatteryChargeForecast checkall
ausgeführt habe, war alles aktuell.
Kann ich das so einstellen, das ich das gleiche Verhalten automatisch bekomme?
Gibt es eine Möglichkeit bei der Änderung von [BatMaxCharge] den Zweig nochmals auszuführen um auch den aktuellen Wert zu senden?
Oder gibt es eine bessere Möglichkeit mit solchen parametrisierten DOIFs umzugehen?
Vielen Dank
Hadl
Ich würde grundsätzlich die Aufgabe auf zwei DOIFs aufteilen. Das eine kümmert sich um das Setzen der Maximalwerte in Abhängigkeit von irgendwelchen Bedingungen, das andere ist dann für die eigentliche Steuerung a'la Thermostat zuständig. checkall habe ich nur dazu programmiert Bedingungen mal zu überprüfen. Normalerweise sind die Zustände des Devices immer korrekt und brauchen nicht überprüft zu werden.
Hallo Damian,
hab ich dann nicht das gleiche Problem, wenn ich den Maximalwert in einem Reading eines anderen DOIF's habe, dann würde ich doch bei einer Änderung des Maximalwertes "BatMaxCharge" auch nicht den Zweig nochmal ausführen der den Maximalwert schreibt, solange dies der gleiche Zweig wie mit dem alten Maximalwert ist.
Im Unterschied zu einem Thermostat ist der Wert ja nicht Teil der Bedingung und führt bei relevanter Änderung zur Ausführung eines anderen Zweigs.
Hast du mal ein Beispiel wie das aussehen könnte? Vielleicht sehe ich auch nur den Wald vor lauter Bäumen nicht.
Vielen Dank
Hadl
Ich gehe davon aus, dass dein Maximalwert der Schwellenwert ist. Bei einem Thermostat ist das die Temperatur, bis zu der geheizt wird. Dann gibt es einen Bereich wo nichts passieren soll, das nennt man Hysterese, damit beim Unterschreiten des Sollwertes nicht sofort wieder geheizt wird. Bei dir dürfte es statt heizen das Laden sein.
Hier in dem Threshold-Beispiel: https://fhem.de/commandref_DE.html#DOIF_Weitere_Anwendungsbeispiele ist der Schwellenwert der desire-Wert. Das DOIF-Device hat nur zwei Zustände. Man kann den desire-Wert von außen mit einem anderen Device in Abhängigkeit wovon auch immer setzen. Entweder wird der Schwellenwert (Minimalwert=Maximalwert-Hysterese) unterschritten - das Device heizt/lädt oder der Maximalwert wird Überschritten das Heizen/Laden wird beendet. Sollte der Zustand sich nicht ändern - man bleibt oberhalb des Maximalwertes oder unterhalb der Minimalwertes - passiert gar nichts. Das Vorgeben der Solltemperatur/Ladung und das Steuern des Heizens/Ladens sind hier also zwei unabhängige Prozesse.
Hallo Damien, ja das verstehe ich, und so macht das auch bei einem Thermostat Sinn.
Bei mir ist die Logik von PV Forecast, Akku Ladezustand und Ähnlichen anhängig.
Unter den Bedingungen gibt es dann eine Ladefreigabe oder eben keine. Der Maximale Ladestrom ist nicht Teil der Bedingung.
Der Maximale Ladestrom der bei Ladefreigabe verwendet wird, ist bei mir aktuell manuell über die Setlist angegeben. Wenn ich den veränderte hätte ich gerne die Aktualisierung gesendet.
Das geht aktuell nur, wenn die Ladefreigabe mal weg war, oder wenn ich die beiden Befehle oben verwende.
Ich hätte das gerne automatisch, auch im Hinblick darauf dass ich den Wert in Zukunft vielleicht berechne.
Du kannst deine Bedingung in ein DOIF_Reading packen, das triggert nur bei Änderung des eigenen Zustands. Das fragst du dann anstatt der Bedingung im DOIF ab und setzt es auf do always.
Statt des neuen Wertes kannst du auch abfragen, ob sich der Wert soweit ändert, dass das CMD erneut ausgeführt werden muss und darauf triggern.
Zitat von: Damian am 10 August 2025, 10:55:10Du kannst deine Bedingung in ein DOIF_Reading packen, das triggert nur bei Änderung des eigenen Zustands. Das fragst du dann anstatt der Bedingung im DOIF ab und setzt es auf do always.
Vielleicht hab ich einen Knoten im Hirn,
aber wenn ich jetzt die Bedingung (etwas vereinfacht)
"Solarforecast empfielt laden der Batterie" in ein DOIF_Reading packe, dann triggert das doch auch nur, wenn die Empfehlung da ist.
dann wird z.B. die max Ladeleistung auf BatMaxCharge=2500W gesetzt
Wenn ich dann später BatMaxCharge auf 3000W stelle und die Ladeempfehlung immer noch da ist würde doch das DOIF nichtmehr ausgeführt und die Batterie würde weiter mit 2500W laden.
Zitat von: Per am 10 August 2025, 11:34:09Statt des neuen Wertes kannst du auch abfragen, ob sich der Wert soweit ändert, dass das CMD erneut ausgeführt werden muss und darauf triggern.
Dann müsste ich mir den alten speichern und vergleichen ob der neue anders ist. Dann krieg ich bei änderungen alle Kommandos doppelt und ich muss den Bedingungzweig verdoppeln oder?
Also grob so:
DOIF ([Ladeempfehlung]==true and [$SELF:BatMaxCharge]=[$SELF:BatMaxChargeOld])
( set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];; )
DOELSEIF ([Ladeempfehlung]==true and [Maxwert]!=[MaxwertAlt])
( set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];;
setreading $SELF MaxwertAlt Maxwert
)
DOELSE
( sende Maxwert 0 an die Batterie)
richtig?
Was auch gehen könnte wäre sowas ohne "do always":
DOIF ([Ladeempfehlung]==true )
(set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];; )
DOELSEIF ([$SELF:BatMaxCharge] == [$SELF:BatMaxCharge])
(sleep 0.1; set $SELF checkall;)
DOELSE
(set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];; )
Dann würde man immer wenn sich der Maxwert ändert kurz in state 2 gehen, und 0,1s später wieder zurück in den "richtigen" state und dabei das Kommando wiederholen. Leider auch die 0, aber das wäre warscheinlich nicht so schlimm. Für mein Gehirn ist das zusätzlich schwer zu lesen, aber ich glaube es funktioniert.
Gibt es eine Möglichkeit etwas wie "repeatsame=CommandEvent" zu konfigurieren? Also immer wenn ein Event getriggert wird, welcher im aktiven Befehlsteil vorkommt, dann wird dieser Befehlsteil mit dem neuen Wert wiederholt?
Oder ähnlich wie das ? am Anfang der eckigen Klammer das den Event unterdrückt ein ! das die Wiederholung erzwingt?
set PV_Batterie BatConfigMaxChargeWatt [!$SELF:BatMaxCharge];;
Zitat von: Hadl am 10 August 2025, 21:07:18(sleep 0.1; set $SELF checkall;)
Ich glaube hier hast du das Problem, dass es nie in den DOELSE-Zweig wechselt, sondern es, wenn
Ladeempfehlung != true, auch nach 0,1s wieder zu cmd_2 fällt. Aber müsstest du testen.
Wenn man sowieso zwei Devices braucht und das nicht alles in einem DOIF lösen kann, ist vielleicht die Variante mit dem notify (https://forum.fhem.de/index.php?topic=142207.msg1345947#msg1345947) doch am einfachsten. Dein ursprüngliches DOIF könntest du dann so lassen, wie es war, und das notify übernimmt über initialize, checkall die Neuauswertung.
OK, ich sehe jetzt: dein BatMaxCharge ist nicht in der Bedingung. Dann füge noch einen weiteren Zweig dazwischen mit DOELSEIF ([$SELF: BatMaxCharge])
ohne Ausführungszweig. Damit würde dein DOIF den Zustand wechseln. Das Attribut checkall all würde ich rausnehmen, damit nicht der Zweig cmd1 vorher zuschlägt.
Hallo Passibe,
ich hab das mal ausprobiert mit den sleep und set checkall aber ohne Attribut checkall. Es scheint zu klappen.
Wenn Ich den Max Wert ändere führt der Zweig 1 aus, dann mit den set Checkall wechselt er sofort in den richtigen Zustand und sendet den aktuellen Max Wert.
Der Vorschlag von Damian dauert etwas länger, denn erst wenn ein neuer Event von einem geänderten Wert kommt, wechselt der wieder aus dem zusätzlichen Zweig zurück und sendet das Update. Das dauert oft einige Zeit.
Könnte man nicht Ausführungsteile die Trigger in sich haben bei Änderung des Triggers automatisch mit dem neuen Wert wiederholen?
Zitat von: Hadl am 13 August 2025, 23:05:11mit den sleep und set checkall aber ohne Attribut checkall
Verstehe nicht ganz? Die von mir angesprochene Lösung mit dem notify hatte kein sleep.
Das war das hier:
Zitat von: passibe am 07 August 2025, 19:03:29define notify_PvBatteryChargeForecast notify doif_PvBatteryChargeForecast: BatMaxCharge:.* {fhem("set $NAME initialize;; set $NAME checkall");;}
Dazu musst du das DOIF einfach lassen, wie es in deinem ursprünglichen Post war und brauchst zusätzlich nur das notify.
Zitat von: Hadl am 13 August 2025, 23:05:11Der Vorschlag von Damian dauert etwas länger, denn erst wenn ein neuer Event von einem geänderten Wert kommt, wechselt der wieder aus dem zusätzlichen Zweig zurück und sendet das Update. Das dauert oft einige Zeit.
Könnte man nicht Ausführungsteile die Trigger in sich haben bei Änderung des Triggers automatisch mit dem neuen Wert wiederholen?
Du kannst im Ausführungsteil des DOELSEIF-Zweiges einbauen was du willst, insbesondere das, was du wiederholen wolltest.
das hier:
Zitat von: passibe am 07 August 2025, 19:03:29define notify_PvBatteryChargeForecast notify doif_PvBatteryChargeForecast: BatMaxCharge:.* {fhem("set $NAME initialize;; set $NAME checkall");;}
Dazu musst du das DOIF einfach lassen, wie es in deinem ursprünglichen Post war und brauchst zusätzlich nur das notify.
[/quote]
Ja, das klappt auch aber mit noch einem Gerät wird's irgendwie unübersichtlich. Bin jetzt wieder zurückgegangen auf die sleep Lösung.
Zitat von: Damian am 14 August 2025, 11:24:17Du kannst im Ausführungsteil des DOELSEIF-Zweiges einbauen was du willst, insbesondere das, was du wiederholen wolltest.
Das wollte ich auch ausprobieren, aber dann habe nicht gewusst von welchen Zweig ich den Code hätte einbauen sollen. Ich hatte sonst verschachtelt nochmal die Zweige gebraucht.
Ich hatte dazu einen Vorschlag zur Erweiterung.
Mit einem neuen Attribut wie "do triggeredExec" oder noch besser einen "!" nach der eckigen Klammer im Ausführungsteil könnte man die Wiederholung bei Änderung definieren.
DOIF ([Ladeempfehlung]==true )
(set PV_Batterie BatConfigMaxChargeWatt [!$SELF:BatMaxCharge];; )
Das Doif müsste dann auf das Reading auch triggern aber nur den Zweig wiederholen der auch den Trigger in sich trägt, falls dieser noch aktuell ist.
Ich könnte mir vorstellen dass man das ganz oft braucht wenn man ein Reading im Ausführungsteil verwendet.
Zitat von: Hadl am 23 August 2025, 16:00:22Ich hatte dazu einen Vorschlag zur Erweiterung.
Mit einem neuen Attribut wie "do triggeredExec" oder noch besser einen "!" nach der eckigen Klammer im Ausführungsteil könnte man die Wiederholung bei Änderung definieren.
DOIF ([Ladeempfehlung]==true )
(set PV_Batterie BatConfigMaxChargeWatt [!$SELF:BatMaxCharge];; )
Das Doif müsste dann auf das Reading auch triggern aber nur den Zweig wiederholen der auch den Trigger in sich trägt, falls dieser noch aktuell ist.
Ich könnte mir vorstellen dass man das ganz oft braucht wenn man ein Reading im Ausführungsteil verwendet.
Das kannst du auch heute schon erreichen, indem du für den Zweig, den du per Trigger wiederholen willst Attribut repeatsame auf 2 setzt.
Das hab ich probiert, aber so wie es aussieht wiederholt er dann den Zweig dann zwar ein weiteres mal sobald ein neuer Trigger in der Bedingung kommt, aber nicht nochmal, wenn ich den Trigger (Maximale Ladeleistung) im Ausführungsteil danach ändere.
Als Ergebnis wurde also zweimal der alte Wert an die Batterie gesendet, jedoch nicht der neue.
Zitat von: Hadl am 23 August 2025, 16:00:22Ich hatte dazu einen Vorschlag zur Erweiterung.
Mit einem neuen Attribut wie "do triggeredExec" oder noch besser einen "!" nach der eckigen Klammer im Ausführungsteil könnte man die Wiederholung bei Änderung definieren.
DOIF ([Ladeempfehlung]==true )
(set PV_Batterie BatConfigMaxChargeWatt [!$SELF:BatMaxCharge];; )
Das Doif müsste dann auf das Reading auch triggern aber nur den Zweig wiederholen der auch den Trigger in sich trägt, falls dieser noch aktuell ist.
Ich könnte mir vorstellen dass man das ganz oft braucht wenn man ein Reading im Ausführungsteil verwendet.
Im Ausführungsteil eines FHEM-DOIF-Zweiges gibt es grundsätzlich keine Trigger, die gibt es nur in der Bedingung. Trigger an beliebiger Stelle im Code gibt es nur im DOIF-Perl-Modus.
PS. Nach zehn Jahren Eingewöhnung, möchte ich keine grundsätzlichen Eigenschaften des Moduls ändern
Zitat von: Damian am 25 August 2025, 09:59:37Im Ausführungsteil eines FHEM-DOIF-Zweiges gibt es grundsätzlich keine Trigger, die gibt es nur in der Bedingung. Trigger an beliebiger Stelle im Code gibt es nur im DOIF-Perl-Modus.
OK, verstanden. Das war mir nicht bewusst. Das schränkt aber die Nutzung von Readings im Ausführungsteil deutlich ein, bzw erzwingt workarounds.
Ich werde mal wenn ich Zeit habe das Beispiel auf den Perl Modus umstellen und hier schreiben welche Variante die übersichtlichere ist.
Zitat von: Damian am 25 August 2025, 09:59:37PS. Nach zehn Jahren Eingewöhnung, möchte ich keine grundsätzlichen Eigenschaften des Moduls ändern
Kann ich auf der einen Seite verstehen, wird aber die Weiterentwicklung auch blockieren.
Mein Vorschlag war schon so gedacht das er rückwärtskompatibel ist, daher das neue Attribut bzw Trigger Zeichen.
Oder meintest du das am Doif Code dadurch so viele Änderungen notwendig wären das dass Risiko von Fehlern zu groß ist?
Danke auf jeden Fall für deine Erklärungen und das sehr hilfreiche Modul.
Zitat von: Hadl am 26 August 2025, 18:11:09Oder meintest du das am Doif Code dadurch so viele Änderungen notwendig wären das dass Risiko von Fehlern zu groß ist?
Auch das, das würde den Code "auf den Kopfstellen". Der Perl-Modus entstand dagegen an einem Tag. Es ist im Grunde nur die Bedingung aus dem FHEM-Modus, die übrigens auch im FHEM-Modus nach paar Ersetzungen vom Perlinterpreter ausgeführt wird.
Das Modul ist viel besser bei den Usern angekommen, als ich ursprünglich gedacht hatte. Es hat allerdings im Laufe der Zeit schon einige Erweiterungen erhalten.
Ich habe mir jetzt nochmal die anfängliche Aufgabenstellung angesehen.
Warum wird nicht gleich PV_Batterie BatConfigMaxChargeWatt vom WebCmd gesetzt? Dann kann man auch direkt ohne Handstände drauf triggern.
Hallo Per,
ja, aktuell wird BatMaxCharge vom WebCmd gesetzt. Prinzipiell könnte auch also auch drauf triggern. Nur brauch ich den Wert nicht in der Bedingung, sondern in der Ausführung. Da unterstützt Doif Fhem keine Trigger.
Der Doif entscheidet aktuell zwischen zwei Werten die er an die Batterie sendet. Null Watt oder den Wert von BatMaxCharge. Vielleicht werden es auch mal mehr Möglichkeiten oder ein berechneter Wert.
Zitatdefmod doif_PvBatteryChargeForecast DOIF (\
([PV_SolarForecast:Battery_ChargeUnrestricted_01] == 1) or\
([PV_SolarForecast:Battery_ChargeRequest_01] == 1) or\
([Fronius_Symo1:Storage_0_Controller_StateOfCharge_Relative] < [PV_SolarForecast:Battery_OptimumTargetSoC_01:d])\
)\
(set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
DOELSE\
(set PV_Batterie BatConfigMaxChargeWatt 0;; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
Ich nehme an [$SELF:BatMaxCharge] ist numerisch. Ein do always bzw. unnötige erneute Ausführung möchtest du vermeiden.
Für erneute Ausführung (bei Änderung) braucht DOIF aber entweder einen Zustandswechsel (anderen Zweig) oder do always.
Ich würde die ersten 3 Bedingungen in ein DOIFReading (https://fhem.de/commandref_DE.html#DOIF_DOIF_Readings) packen und [$SELF:BatMaxCharge] als Bedingung hinzufügen und do always setzen.
In etwa:
attr doif_PvBatteryChargeForecast DOIF_Readings LadeEmpfehlung:{\
if(\
([PV_SolarForecast:Battery_ChargeUnrestricted_01] == 1) or \
([PV_SolarForecast:Battery_ChargeRequest_01] == 1) or \
([Fronius_Symo1:Storage_0_Controller_StateOfCharge_Relative] < [PV_SolarForecast:Battery_OptimumTargetSoC_01:d])\
) \
{ \
1;; \
} \
else \
{ \
0;;\
}\
}
attr doif_PvBatteryChargeForecast do always
defmod doif_PvBatteryChargeForecast DOIF ([$SELF:LadeEmpfehlung] and [$SELF:BatMaxCharge:d]) \
(set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
DOELSE\
(set PV_Batterie BatConfigMaxChargeWatt 0;; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
So - ungestestet - würde ich das realisieren, ohne ständig zu senden.
Damit erfolgt der entsprechende set Befehl bei Änderung BatMaxCharge oder bei Änderung des Sammelzustands Ladeempfehlung. Da BatMaxCharge numerisch ist, wird bei 0 ebenso der DOELSE Zweig aufgerufen.
Zitat von: tobi01001 am 29 August 2025, 11:26:17defmod doif_PvBatteryChargeForecast DOIF ([$SELF:LadeEmpfehlung] and [$SELF:BatMaxCharge:d]) \
(set PV_Batterie BatConfigMaxChargeWatt [$SELF:BatMaxCharge];; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
DOELSE\
(set PV_Batterie BatConfigMaxChargeWatt 0;; set PV_Batterie BatConfigMaxEnabled chargeMax;;)\
So - ungestestet - würde ich das realisieren, ohne ständig zu senden.
Damit erfolgt der entsprechende set Befehl bei Änderung BatMaxCharge oder bei Änderung des Sammelzustands Ladeempfehlung. Da BatMaxCharge numerisch ist, wird bei 0 ebenso der DOELSE Zweig aufgerufen.
Ja, das sieht auch gut aus. Mit der Dummy Bedingung auf ungleich Null funktioniert auch der Trigger und bei Null ist's eh egal welchen Zweig ich nehme. Das Doif Reading filtert dann gleiche Trigger raus.
Nur wenn's mal mehrere Bedingungen werden könnte es etwas unübersichtlicher werden.
Ich denke dann müsste ich sicherstellen dass immer nur eine Bedingung für einen Zweig wahr wird. Evtl. geht auch checkall
Danke schonmal, ich probiere das auch mal aus