Prüfung möglich, ob eine Regel gerade läuft?

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
Scooter
Beiträge: 10
Registriert: 9. Jun 2022 09:26
Answers: 0

Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von Scooter »

Hallo,

gibt es eine einfache Möglichkeit, (zum Beispiel bei But only if) um zu prüfen, ob eine bestimmte andere Regel bereits läuft?

Hintergrund: Ich steuere einige Verbraucher anhand der Einspeisung meiner Photovoltaikanlage. Damit bei wechselnder Sonneneinstrahlung mit Wolken keine zu kurzen Schaltzyklen herauskommen (Hysterese) habe ich zwei kleine Skripte geschrieben, welche eine Zeit lang laufen und einen Counter hinauf-oder herunterzählen. Hat dieser Counter nun eine bestimmte Schwelle erreicht wird ein Gerät aus bzw. eingeschalten.

Problem: Es gibt ein Einschaltskript und ein Ausschaltskript , beide werden von der Einspeisung der Photovoltaikanlage angestoßen und so kann es sein, sie parallel zu laufen beginnen. Gut wäre nun die oben nachgefragte Prüfmöglichkeit, ob das jeweils andere Skript bereits läuft.

Beste Grüße

Scooter

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

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von udo1toni »

Kannst Du mal den Code Deiner Rules zeigen? Ich bin mir ziemlich sicher, dass die Vorgehensweise so nicht gut ist.

Grundsätzlich sollte eine Rule nie unnötig lange laufen. Um z.B. eine Mindesteinschalt- oder -ausschaltdauer zu erzielen, wäre ein Timer der richtige Ansatz. Die Rule läuft und legt einen Timer an, danach ist die Rule fertig, Dauer (je nach komplexität) vielleicht eine Millisekunde. der Timer sperrt das Toggeln für x Minuten. erst danach ist der Zugriff wieder erlaubt. dazu muss in der entsprechenden Rule lediglich geprüft werden, ob der Timer existiert. Im Timer selbst wird dann lediglich der Timer gelöscht. Auch dieser Vorgang frisst kaum Rechenzeit, vielleicht noch eine weitere Millisekunde (eher weniger)
Hingegen in einer Rule über while irgendwelche Zähler zu erhöhen und dann vielleicht mit Thread::sleep() künstliche Pausen einzulegen, mag den netten Effekt haben, dass man sich anzeigen lassen kann, wie lange die Rule noch gesperrt ist, aber dafür steigt die Prozessorlast ungemütlich an, und außer beim Testen und beim Vorführen schaust Du eh nie drauf...
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Scooter
Beiträge: 10
Registriert: 9. Jun 2022 09:26
Answers: 0

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von Scooter »

Hello & danke!

Mit wären halt die variablen Schwellenwerte (hier hysteresisCounterPoolpumpe) wichtig, damit ich die unterschiedichen Ausschaltzeiten der Geräte unterschiedlich gewichten kann. Bei Bezug schalten sich letzendlich alle ab, halt in einstellbarer Reihenfolge. Verzögerung von 1,5 sec wäre drinnen, Prozessorlast macht mir deswegen auch keine Sorgen. Läuft super, nur die doppelten Starts bekomm ich nicht in den Griff.

Hier eine einfache Regel eines Ausschalttimers (<Code from Blockly, sorry .... not speaking Java :roll: )

lG Scooter

Code: Alles auswählen

var counterpoolpumpe, zaehleraus, aktuellerverbrauch;

var thread = Java.type('java.lang.Thread')

counterpoolpumpe = itemRegistry.getItem('hysteresisCounterPoolpumpe').getState();
zaehleraus = 0;
while (123 == 123) {
  thread.sleep(1500);
  aktuellerverbrauch = itemRegistry.getItem('Shelly3EM_KumulierterVerbrauch').getState();
  if (aktuellerverbrauch >= 0) {
    zaehleraus = (typeof zaehleraus == 'number' ? zaehleraus : 0) + 1;
  }
  if (aktuellerverbrauch >= 100) {
    zaehleraus = (typeof zaehleraus == 'number' ? zaehleraus : 0) + 2;
  }
  if (aktuellerverbrauch >= 300) {
    zaehleraus = (typeof zaehleraus == 'number' ? zaehleraus : 0) + 3;
  }
  if (aktuellerverbrauch <= -300) {
    zaehleraus = (typeof zaehleraus == 'number' ? zaehleraus : 0) + -1;
  }
  if (aktuellerverbrauch <= -400) {
    zaehleraus = (typeof zaehleraus == 'number' ? zaehleraus : 0) + -2;
  }
  if (zaehleraus >= counterpoolpumpe) {
    zaehleraus = 0;
    events.sendCommand('5Poolpumpe_Betrieb', 'OFF');
    break;
  }
  if (zaehleraus <= counterpoolpumpe * -1) {
    zaehleraus = 0;
    break;
  }
  events.postUpdate('Poolpumpenzaehler', zaehleraus);
}
events.postUpdate('Poolpumpenzaehler', zaehleraus);

Scooter
Beiträge: 10
Registriert: 9. Jun 2022 09:26
Answers: 0

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von Scooter »

He he, Idee gehabt:

Ein "Stop"-Thing als Point erstellen, welches am Anfang des Scrits z. B. als "true" gesetzt wird und am Ende als "false".
bei "But only if" dann vorher dieses thing abfragen, ob es "false" ist.
Ist zwar ziemlich unelegant um die Ecke programmiert, sollte aber mögich sein.

lG

Scooter

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

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von udo1toni »

Jain. Prinzipiell geht das schon, aber sicher ist es halt nicht.

Und wo wir bei "Um die Ecke" sind, das trifft ja auch auf Deine Rule zu ;)

Dieses Konstrukt: (typeof zaehleraus == 'number' ? zaehleraus : 0) beispielsweise ist in dem Kontext komplett unsinnig, zaehleraus ist immer vom Typ Number, weil Du es beim Eintritt in die Rule so definierst und vorbelegst. Die Rule wird niemals verlassen und wieder betreten, also ist die Variable beim Eintritt immer 0 und damit eine gültige Zahl.
Das Konstrukt 123 == 123 ist auch lustig ;) schreib einfach true hin und gut.
Also, abgesehen davon, dass man das so halt nicht macht ;)

Auch wenn Du "kein Java sprichst" hier mal das Gegenstück dazu:

Code: Alles auswählen

var Timer tPool = null
val Long  lPool = 1500000000 // 1,5 Sekunden als Nanosekunden
var Number nHysterese = 10   // default Wert falls Hysterese nicht gelesen werden kann

rule "Pumpe aus Zähler"
when
    // der Rule Trigger
then
    if(tPool !== null) // falls Timer schon existiert
        return;        // Abbruch

    if(hysteresisCounterPoolpumpe.state instanceof Number)
        nHysterese = hysteresisCounterPoolpumpe.state as Number
    
    tPool = createTimer(now.plusNanos(lPool),[
        var Integer nAus      = if(Poolpumpenzaehler.state instanceof Number) (Poolpumpenzaehler.state as Number).intValue else 0
        var Number nVerbrauch = if(Shelly3EM_KumulierterVerbrauch.state instanceof Number) (Shelly3EM_KumulierterVerbrauch.state as Number) else 0
        
        if(nVerbrauch <-400)
            nAus -= 2
        else if(nVerbrauch <-300)
            nAus -= 1
        else if(nVerbrauch > 300)
            nAus += 3
        else if(nVerbrauch > 100)
            nAus += 2
        else if(nVerbrauch > 0)
            nAus += 1

        if(nAus > nHysterese)
            5Poolpumpe_Betrieb.sendCommand(OFF)
        if(Math::abs(nAus) > nHysterese) {
            nAus = 0
            tPool = null
        } else
            tPool.reschedule(now.plusNanos(lPool))
        
        Poolpumpenzaehler.postUpdate(nAus)
    ])
end
Wenn der Messzyklus zwei Sekunden betrüge, könnte man auf die Nanos verzichten und stattdessen plusSeconds(2) schreiben :)

Gleich zu Anfang kannst Du aber sehen, dass die Rule abgebrochen wird, sobald ein laufender Timer entdeckt wird.
Leider fehlt in Deinem Code der Trigger, welcher eigentlich mit ausgegeben wird.

Die Rule selbst macht nichts weiter, als zu prüfen, ob der Timer existiert, und falls das nicht der Fall ist, die aktuell eingestellte Hysterese auszulesen und den Timer anzulegen. Danach ist die Rule beendet.

Ab sofort existiert im Scheduler der Timer, welcher nach 1,5 Sekunden das erste Mal den Code ausführen lässt. Das ist der Block zwischen [| und ]

Im großen und ganzen entspricht der Code dem von Blockly, mit ein paar kleineren Unterschieden.
Zunächst liest der Code den aktuellen Zählerstand jeweils vom Item ein, genau wie den aktuellen Verbrauch. Beides wird in einer lokalen Variable gespeichert. Sollte gerade kein gültiger Wert geliefert werden, so wird ein Default Wert genommen.
Der Vergleichsblock ist ähnlich Deinem Block aufgebaut, allerdings gibt es da in Deinem Code evtl. einen Fehler. Du nutzt immer nur if(), was bedeutet, dass z.B. bei einem Wert über 300 drei Bedingungen zutreffen, denn der Wert ist größer als 0, größer als 100 und größer als 300, es wird also bei einem einzigen Durchlauf 6 hinzugezählt, nicht etwa 3.

Kurzer Einschub:
Man könnte hier übrigens auch mit einer SCALE Transformation arbeiten, das sähe dann im Code so aus:

Code: Alles auswählen

nAus += Integer::parseInt(transform("SCALE","pumpe.scale",nVerbrauch))
Dafür steht dann aber im Code nicht, wie der Wert zustande kommt. Die Scale Transformation solltest Du auch aus Blockly heraus nutzen können.
Ich bin mir nicht zu 100% sicher, ob der Umweg über Integer::parseInt() notwendig ist, aber immerhin kann Scale Text liefern, also wird auch eine Zahl vermutlich eher als String herauskommen.

Die Datei pumpe.scale sähe dann so aus:

Code: Alles auswählen

[..-400]=-2
[..-300]=-1
[300..]=3
[100..]=2
[0..]=1
Die Datei wird immer von oben nach unten abgearbeitet, das erste Match wird genommen. Man muss also entweder genauere wertebereiche angeben oder auf die Reihenfolge der Einträge achten (so wie auch in meiner Rule)
Zurück zur Rule:

Das += ist eine fiese Abkürzung :) ich könnte natürlich ebensogut nAus = nAus + 1 schreiben, aber so sieht es halt viel schicker aus ;)

Wenn der Schwellwert überschritten wurde, wird die Pumpe abgeschaltet.
Liegt der Absolutwert des Zählers über dem Schwellwert so wird der Timer nicht mehr weiter ausgeführt, ansonsten wird der Timer erneut eingeplant. Erst nach diesem Schritt wird noch der aktuelle Zählerstand ins Item geschrieben. Damit ist der Code fertig ausgeführt.
Je nachdem, ob im vorletzten Schritt der Timer neu geplant wurde oder der Zähler auf 0 gesetzt und der Timer genullt wurde wird nach 1.5 Sekunden der Scheduler den Code erneut ausführen lassen.

Das Einschalten der Pumpe kann mit sehr hoher Wahrscheinlichkeit genauso abgewickelt werden. Eventuell geht das sogar aus derselben Rule heraus, je nach Trigger...
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Scooter
Beiträge: 10
Registriert: 9. Jun 2022 09:26
Answers: 0

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von Scooter »

Guten Morgen,

ich dank`dir herzlich und schau mir das mal so an

lG

Scooter

Harka
Beiträge: 489
Registriert: 30. Apr 2021 13:13
Answers: 19

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von Harka »

falls Du mit der Umsetzung nach Blockly nicht weiter kommst - frag ruhig noch mal. Bis auf die optionale SCALE Transformation sollte alles zu machen sein.
PS: zaehleraus = (typeof zaehleraus == 'number' ? zaehleraus : 0) + 1; produziert der change-Block für die "verkürzte" +=1

Scooter
Beiträge: 10
Registriert: 9. Jun 2022 09:26
Answers: 0

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von Scooter »

Danke, ich wusste, der Regelcode wird peinlich ..... :oops: .....

Bin seit fast 30 Jahren raus aus dem Geschäft (Basic am Sinclair ZX81, danach Sprectrum dann Tubopascal, Assembler, VB und AUS)
Ohne dem Blockly hätt ich mit OH gar nicht angefangen - Für einfach Dinge passts ja, aber irgendwann steht man halt an, weil die Blöcke fehlen. :?
Neu Java zu lernen steht in keiner Relation zum Effekt.

War aber eine interessante Lehrstunde in "The Art Of Coding" :lol:

lG

Scooter

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

Re: Prüfung möglich, ob eine Regel gerade läuft?

Beitrag von udo1toni »

Nur, um das mal klarzustellen: Das ist kein Java! Wenn Du mehr als nur ein Hello World mit VB programmiert hast, solltest Du keine Schwierigkeiten mit objektorientierter Programmierung haben. Die DSL ist eine wirklich sehr simple Programmiersprache. Ja, der Code sieht vielleicht komplex aus, aber wenn Du die Schlüsselworte kennst, ist es echt überschaubar.

Kleiner Vergleich VB <-> DSL:
Das Schlüsselwort then ist Bestandteil des Grundgerüsts einer Rule.

Jede Rule ist exakt(!) folgendermaßen aufgebaut:

Code: Alles auswählen

rule "Rulename, eindeutig" <--Rule Kopf
when                       <- Schlüsselwort, welches den Trigger-Teil einleitet
    <Trigger>             // falls mehr als ein Trigger gewünscht ist, werden die Trigger mit or getrennt. Es gibt kein and!
then                       <- Schlüsselwort, welches den auszuführenden Codeblock einleitet
    <Code>
end                        <- Schlüsselwort, welches das Ende der Rule markiert
Die Einrückungen sind nicht notwendig, sie dienen nur der besseren Lesbarkeit.

In VB kennst Du THEN als Bestandteil der bedingten Verzweigung IF.
In openHAB wird if etwas anders geschrieben
VB:

Code: Alles auswählen

IF a = b THEN 
    tu was
    tu noch was
    und das auch noch
END IF
DSL:

Code: Alles auswählen

if(a == b) {
    tu was
    tu noch was
    und das auch noch
}
Der erste Punkt ist also, dass die Bedingung in Klammern steht. Der zweite Punkt ist, dass ein Vergleich auf Gleichheit mit == geschrieben wird. Der dritte Punkt ist, dass der auszuführende Code in geschweifte Klammern eingeschlossen ist.
Möchte man in VB nur einen Befehl abhängig halten, so schreibt man einfach direkt nach dem THEN weiter und das END IF entfällt.
in der DSL lässt man dann einfach die geschweiften Klammern weg.

Das ist also wirklich sehr ähnlich, und wenn man den Code ein-, zweimal gesehen hat, denkt man gar nicht mehr drüber nach.

Ich habe übrigens auf einem Ti 94-A angefangen (nur im Kaufhaus...) und später bei einem Freund auf einem C-64 etwas mehr programmiert. Mein erster eigener Rechner war dann auch ein Amiga, auf dem ich dann für Physik Kurvendiskussionen programmiert habe (ja, in Basic).
Aber zugegeben, ich habe immer programmiert, auch wenn ich nur Laie bin (oder meinetwegen Amateur), weshalb ich vielleicht weniger Berührungsängste habe.

Blockly ist ganz nett, aber hauptsächlich, weil man immer eine vollständige Liste aller möglichen Befehle vor Augen hat. Wie man die Befehle kombinieren muss, um das gewünschte Ergebnis zu erzielen, muss man dennoch selbst wissen.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten