Rule | Timer | Trotz cancel läuft der Timer weiter. | ECMAScript-2021

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
./mf
Beiträge: 44
Registriert: 8. Jan 2022 00:15
Answers: 1

Rule | Timer | Trotz cancel läuft der Timer weiter. | ECMAScript-2021

Beitrag von ./mf »

Ich verzweifel gerade ein wenig ... :-D

Es sollen die "Member" einer Sprinkler_Gruppe solange laufen, wie die Zeit "in Minuten" angegeben wurde. (Zum TEST habe ich hier nur Sekunden im Script)

Wenn ich nun SP1, SP2, und SP3 aktiviere und SP3 direkt ausschalte, werden auch SP1 und SP2 abgestellt. Das ist auch korrekt so. Davon ab, soll noch ein Interlock rein. Dass nur einer der Gruppen-Member aktiv sein kann. Das hängt mit dem Wasserdruck hier zusammen.

Aber das größte Problem ist, dass die "beiden" Timer von SP1 und SP2 weiterzulaufen scheinen. Denn beide melden im LOG, dass der Timer beendet ist. Nach genau 10sec, welche eingestellt sind.

Meine Frage ist daher, wie kann ich den Timer "sp_timer" so entfernen, dass er für alle Sprinkler weg ist...

Der Übersicht halber, habe ich das Script von der Rule getrennt gepostet.

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: Garten_SprinklerValves
    type: core.GroupStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: >
        // SCRIPT HIER 
    type: script.ScriptAction

Code: Alles auswählen

var logger = log("Sprinkler");

var item = items.getItem(event.itemName);
var state = item.state;

var spNext = items.getItem(item.name + "_nextSprinkler").state;
var spDuration = items.getItem(item.name + "_Duration").state;
var spAutomatic = items.getItem("GartenSprinkler_AutomaticNext").state;

if (state == "ON") {

  if ( spAutomatic == "ON" && spNext == "0" ) {
    logger.info("AUTOMATIC STOP AFTER :: " + item.name);
    items.getItem("GartenSprinkler_AutomaticNext").sendCommand("OFF");
  }

  logger.info("SET TIMER :: " + item.name + " :: " + spDuration + " min");
  sp_timer = actions.ScriptExecution.createTimer(time.ZonedDateTime.now().plusSeconds(spDuration), function() {
    logger.info("TIMER ENDS :: " + item.name + " :: " + spDuration + " min");
    item.sendCommandIfDifferent("OFF");
  });


}

if (state == "OFF") {

  // stop complete automatic process, because sprinkler was set manually to OFF
  if (typeof sp_timer != "undefined" && sp_timer != null) {
    sp_timer.cancel();
    sp_timer = null;
    logger.info("TIMER STOP BY :: " + item.name + " :: ALL_VALVES=OFF // AUTOMATIC=OFF");
    items.getItem("Garten_SprinklerValves").sendCommandIfDifferent("OFF"); // GROUP OFF
    items.getItem("GartenSprinkler_AutomaticNext").sendCommandIfDifferent("OFF"); // AUTOMATIC OFF
  }

  if ( spAutomatic == "ON") {
    logger.info("AUTOMATIC STILL ACTIVE :: START NEXT SPRINKLER :: " + spNext);
    items.getItem("Garten_Sprinkler"+spNext).sendCommandIfDifferent("ON");
  }

}

OpenHAB 3.2 im Docker auf Pi4-4GB

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

Re: Rule | Timer | Trotz cancel läuft der Timer weiter. | ECMAScript-2021

Beitrag von int5749 »

Timer müssen global definiert sein, damit man diese auch ausserhalb der rule beeinflussen kann. Zudem geht dies derzeit nur in einer DSL rule, nicht über die MainUI.

Lasse mich aber gerne korrigieren, wenn es doh anders gehen sollte?
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

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

Re: Rule | Timer | Trotz cancel läuft der Timer weiter. | ECMAScript-2021

Beitrag von udo1toni »

Genau. Man kann vermutlich im vorliegenden Fall die lokale Variable für den laufenden Timer auch wieder aus der Versenkung hervorholen, aber das ist doch irgendwie alles eher Murks...

Der Ansatz ist aber von vornherein vermutlich schlecht. Du möchtest ja, dass immer nur ein Regner eingeschaltet ist. Deshalb bietet es sich an, die Liste der Regner zu durchlaufen. Gleichzeitig soll zwischen den einzelnen Schaltvorgängen eine Zeitspanne liegen, weshalb ein Timer naheliegt.
Sinnvoll ist es aber nun, den Timer zum Durchlaufen der Gruppe zu verwenden. Je nach Wunsch sind verschiedene Ausbaustufen möglich:

1. Über einen Schalter wird die Beregnung gestartet. Alle Regner werden nacheinander aktiviert, mit fester Reihenfolge und fester Laufzeit für alle Regner. Über den gleichen Schalter kann der gesamte Vorgang abgebrochen werden.
2. wie 1., aber man kann individuell auswählen, ob einzelne Regner ausgenommen werden sollen.
3. wie 1., aber man kann eine individuelle Beregnungszeit pro Regner einstellen.
4. entweder man kombiniert 2. und 3., oder man nimmt eine Zeitspanne 0 als "diesen Regner auslassen".

Die einfachste Variante sähe ungefähr so aus:

Code: Alles auswählen

var Timer tSprinkler = null
var Integer iSprinkler = 0

rule "Sprinkler"
when
    Item Sprinkler received command
then
    tSprinkler?.cancel
    if(receivedCommand == ON) {
        iSprinkler = 0
        tSprinkler = createTimer(now.plusSeconds(1),[|
            gSprinkler.members.filter[s|s.state != OFF].forEach[i|
                i.sendCommand(OFF)
            ]
            iSprinkler ++
            if(iSprinkler > gSprinkler.members.size)
                return;
            gSprinkler.members.sortBy[ name ].filter[s,n|n==iSprinkler-1].head.sendCommand(ON)
            tSprinkler.reschedule(now.plusMinutes(10))
        ])
    } else 
        gSprinkler.members.filter[s|s.state != OFF].forEach[i|
            i.sendCommand(OFF)
        ]
end
Empfängt das Item Sprinkler einen Befehl so wird die Rule ausgelöst.
Zuerst wird ein eventuell laufender Timer abgebrochen.
Sollte das Kommando ON gewesen sein, so wird ein Timer eine Sekunde in der Zukunft mit einem Codeblock angelegt und die Rule ist beendet.
Andernfalls werden alle laufenden Sprinkler abgeschaltet.

Läuft der Timer ab, so wird der Codeblock ausgeführt.
Zunächst werden alle laufenden Sprinkler abgeschaltet.
Anschließend wird die Zählvariable hochgezählt.
Sollte die Zählvariable die Anzahl der Sprinkler überschritten haben, so wird der Timer beendet.
Andernfalls wird der n-te Sprinkler der Liste eingeschaltet. (n == iSprinkler -1, weil die Liste 0-basiert ist)
Zum Schluss wird der Timer in zehn Minuten erneut ausgeführt.

gSprinkler ist ein Group Item, welches alle Sprinkler enthält. Es ist egal, wie die Items heißen, es ist egal, wie viele Sprinkler in der Gruppe sind.
Soll das ganze mit individualisierten Zeiten laufen, wird es ein wenig aufwändiger.
Man braucht sinnvollerweise eine zweite Gruppe für die Zeiten. Die Itemnamen müssen so gewählt sein, dass sich aus dem Namen des Sprinklers der Name des Zeit-Items ableiten lässt (z.B. MeinSprinkler01 und MeinSprinkler01_Zeit). In der Timer-Schleife muss nun aus der zweiten Gruppe das passende Item zum Sprinkler selektiert, und die Zeit ausgelesen werden. Soll die Option zum Überspringen ebenfalls umgesetzt werden, muss natürlich noch weiterer Aufwand getrieben werden, z.B. indem der Timer direkt nach einer Millisekunde wieder aufgerufen wird, ohne vorher den aktuellen Sprinkler zu starten.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten