Anwesenheit in Rule

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Bronco17
Beiträge: 4
Registriert: 16. Mai 2020 11:01

Anwesenheit in Rule

Beitrag von Bronco17 »

Hallo,
ich habe ein Problem mit der Rule welches ein Switch schalten per Anwesenheit.

Code: Alles auswählen

rule "Quooker anwesenheit"
when
    Item iPhone_1 changed from OFF to ON or
    Item iPhone_2 changed from OFF to ON
then
    sendCommand(Quooker_Switch, ON)
end

rule "Wasser abwesenheit"
when
    Item iPhone_1 changed from ON to OFF or
    Item iPhone_2 changed from ON to OFF
then
    if (iPhone_1.state == OFF && iPhone_2.state == OFF) { Quooker_Switch.sendCommand (OFF) }
end
Sobalt ein iPhon anwesend ist und das zweite iPhone auf ON ändert, schaltet der Switch auf OF

Code: Alles auswählen

2020-06-26 16:06:05.615 [INFO ] [thome.model.script.iPhone 2 Home] - 2 ist zu Hause.

==> /var/log/openhab2/events.log <==

2020-06-26 16:06:05.618 [vent.ItemStateChangedEvent] - iPhone_2 changed from OFF to ON

2020-06-26 16:06:05.635 [ome.event.ItemCommandEvent] - Item 'Quooker_Switch' received command ON

2020-06-26 16:06:17.841 [vent.ItemStateChangedEvent] - Quooker_String changed from on to off

2020-06-26 16:06:17.846 [vent.ItemStateChangedEvent] - Quooker_Switch changed from ON to OFF
Wo ist der Fehler?

Gruss
Bronco17

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

Re: Anwesenheit in Rule

Beitrag von udo1toni »

Ich sehe da nur ein Quooker_String Item, welches von on nach off wechselt. Das hat aber nichts mit Deinen Rules zu tun, da es dort nicht auftaucht.
Die Rules sehen syntaktisch und von der Logik ok aus.

Allerdings gibt es zwei Dinge. Das eine: es wäre sinnvoller, ein Group Item zu verwenden:

Code: Alles auswählen

Group:Switch:OR(ON,OFF) iPhones
Switch iPhone_1 “iPhone 1“ (iPhones)
Switch iPhone_2 “iPhone 2“ (iPhones)
Das verodern der beiden Status passiert nun in der Gruppe. Die Rule (eine reicht) wird zur simpelsten möglichen:

Code: Alles auswählen

rule “quooker schalten“
when
    Item iPhones changed
then
    Quooker_Switch.sendCommand(newState)
end
Das Zweite ist, dass gerade iPhones gerne mal offline erkannt werden, obwohl sie im lokalen Netz eingeloggt sind. Es Kommt also sehr darauf an, wie die Items iPhone_1 und iPhone_2 mit ihrem Status versehen werden.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Bronco17
Beiträge: 4
Registriert: 16. Mai 2020 11:01

Re: Anwesenheit in Rule

Beitrag von Bronco17 »

Besten Dank udo.

Der Status von den iPhones (ON, anwesend, OFF, abwesend) passen.

Schaltet ein iPhone auf OFF bleibt der Quooker-Switch auf ON.
Schaltet das zweite iPhone auch auf OFF, schaltet der Quooker-Switch auf OFF.

Schaltet nun ein iPhone auf ON, schaltet der Quooker-Switch auf ON. So weit so gut
Schaltet das zweite iPhone auch auf ON, schaltet der Quooker-Switch auf OFF. Warum?
Diese Fehlschaltung des Quooker-Switch kommt nur vor, wenn ein iPhone bereits ON ist und das zweie iPhone auf ON schaltet, geht der Switch auf OFF.
Obwohl der log den richtigen befehl registriert, wechselt der Quooker-Switch auf OFF

Code: Alles auswählen

2020-06-27 12:31:55.998 [INFO ] [rthome.model.script.iPhone 2 Home] - 2 ist zu Hause.

2020-06-27 12:40:09.244 [INFO ] [thome.model.script.iPhone 1 Home] - 1 ist zu Hause.
 
2020-06-27 12:40:10.085 [ome.event.ItemCommandEvent] - Item 'Quooker_Switch' received command ON
 
2020-06-27 12:40:54.577 [vent.ItemStateChangedEvent] - Quooker_Switch changed from ON to OFF 
Ich weiss nicht, ob die Gruppenschaltung zum Ziel führt.
Den der Quooker-Switch "Marke MyStrom" sollte eingeschaltet sein sobald ein iPhone zuhause ist und abgeschaltet, wenn kein iPhone registriert ist.

Benutzeravatar
peter-pan
Beiträge: 2564
Registriert: 28. Nov 2018 12:03
Answers: 25
Wohnort: Schwäbisch Gmünd

Re: Anwesenheit in Rule

Beitrag von peter-pan »

Bist du sicher, dass du die Rule von Udo richtig eingerichtet hast ? Eigentlich sollte diese "ON" triggern, wenn das erste Gerät "anwesend" ist und erst dann wieder triggern (OFF), wenn das letzte Gerät wieder "gegangen" ist.
Pi5/8GB(PiOS Lite 64-bit(bookworm)/SSD 120GB - OH4.1.1 openhabian

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

Re: Anwesenheit in Rule

Beitrag von udo1toni »

Bronco17 hat geschrieben: 27. Jun 2020 12:58 Ich weiss nicht, ob die Gruppenschaltung zum Ziel führt.
Den der Quooker-Switch "Marke MyStrom" sollte eingeschaltet sein sobald ein iPhone zuhause ist und abgeschaltet, wenn kein iPhone registriert ist.
Genau das passiert über die Gruppe und die Minimal-Rule. Probiere es aus ;)

Wie gesagt, Deine Rules erscheinen mir syntaktisch und funktional korrekt. Der Fehler scheint von anderer Stelle zu kommen.

Du kannst zur Absicherung noch etwas Logging einbauen:

Code: Alles auswählen

rule "Quooker anwesenheit"
when
    Item iPhone_1 changed from OFF to ON or
    Item iPhone_2 changed from OFF to ON
then
    logInfo("iphones","{} wurde ON erkannt",triggeringItem.name)
    Quooker_Switch.sendCommand(ON)
end

rule "Wasser abwesenheit"
when
    Item iPhone_1 changed from ON to OFF or
    Item iPhone_2 changed from ON to OFF
then
    logInfo("iphones","{} wurde OFF erkannt",triggeringItem.name)
    logInfo("iphones","Status iPhone_1: {}",iPhone_1.state)
    logInfo("iphones","Status iPhone_2: {}",iPhone_2.state)
    if (iPhone_1.state == OFF && iPhone_2.state == OFF) 
        Quooker_Switch.sendCommand (OFF)
end
Oder, mit Gruppe und meiner Rule:

Code: Alles auswählen

rule “quooker schalten“
when
    Item iPhones changed
then
    logInfo("iphones","Gruppe iPhones Status von {} auf {} gewechselt.",previousState,newState)
    Quooker_Switch.sendCommand(newState)
end
Wie gesagt, ich kann Dir garantieren, dass die Gruppe exakt das tut, was Du im Sinn hast. Sobald mindestens eines der beiden Items ON ist, ist auch die Gruppe ON. Sobald alle Items auf OFF sind, ist auch die Gruppe OFF. Sobald der Status der Gruppe sich ändert, folgt Quooker_Switch dem Status.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Bronco17
Beiträge: 4
Registriert: 16. Mai 2020 11:01

Re: Anwesenheit in Rule

Beitrag von Bronco17 »

Sorry udo1toni, dass ich meine Zweifel an der Gruppenschaltung gehabt habe.
Habe nun die Rule auf die Gruppe geändert.

Leider gibt mir das Visual Studio Code bei (newState) einen Fehler.
  • Type mismatch: cannot convert from State to String(org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types)
    A request has failed.
Das Item iPhones in der Rule hat folgende Werte
  • Item iPhones | ON
    Members:
    Item iPhone_1 | ON
    Item iPhone_2 | ON

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

Re: Anwesenheit in Rule

Beitrag von udo1toni »

Welche Version von openHAB läuft denn? newState ist relativ neu dabei. Du kannst stattdessen auch iPhones.state einsetzen. Falls VSCode immer noch motzt, kannst Du auch iPhones.state.toString verwenden (das sollte aber höchstens beim .sendCommand notwendig sein)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Bronco17
Beiträge: 4
Registriert: 16. Mai 2020 11:01

Re: Anwesenheit in Rule

Beitrag von Bronco17 »

Bei mir läuft die Version openHAB 2.5.5-1 auf einem Raspberry Pi 3 Model B Rev 1.2
Mit iPhones.state.toString hat es geklappt :D
Rule wurde intensiv getestet und läuft!
Dankeschön für deine Hilfe.

der_pman
Beiträge: 6
Registriert: 26. Jul 2021 19:27

Re: Anwesenheit in Rule

Beitrag von der_pman »

Hi Leute,

ich möchte das Thema noch einmal aufgreifen.
Ich habe Udo's Tips zum Gruppen-Item übernommen, und das funktioniert super.
Allerdings bekomme ich meine Wunsch-Regel noch nicht ans laufen
Ich möchte wenn in der Zeit von 8-21 Uhr jemand nach Hause kommt die Zirkulationspumpe für das warme Wasser alle 25 Minuten für 5 Minuten aktivieren.

Code: Alles auswählen

rule "Cron Zirkulation"
when
	Time cron "0 0/25 8-21 * * ?"
then

	if Item iPhones changed
	{
		logInfo("Z-Cron","Zirkulation eingeschaltet")
		WWPumpe.sendCommand(ON)
		createTimer(now.plusSeconds(300)) [| WWPumpe.sendCommand(OFF) ]
	}
end
Allerdings bekomme ich diese Fehlermeldung
2022-04-12 17:20:08.081 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'Zirkulation.rules' has errors, therefore ignoring it: [6,5]: mismatched input 'Item' expecting '('

[6,10]: no viable alternative at input 'iPhones'
Habt Ihr vielleicht einen Vorschlag wie ich diese Regel umsetzen kann?

Gruß und Danke
der_pman
Ich weis das ich nix weis - und davon eine ganze Menge ;)

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

Re: Anwesenheit in Rule

Beitrag von udo1toni »

Du musst unbedingt zwei Dinge unterscheiden, und zwar Ereignisse und Zustände.

Ein Item hat einen Zustand (state). Ändert sich der Zustand oder wird er auch nur aktualisiert, so ist diese Änderung oder Aktualisierung ein Ereignis, welches zu einem bestimmten Zeitpunkt auftritt.
Rules werden ausschließlich durch Ereignisse gestartet, deshalb heißt es auch, sie werden getriggert.
Alle Trigger einer Rule werden im when-Teil der Rule aufgelistet. Dabei ist es gleichgültig, welcher der Trigger die Rule auslöst, sie wird bei jedem Ereignis einmal ausgeführt.

Es gibt für Deine Aufgabenstellung zwei unterschiedliche Lösungsansätze, die einfache (aber auch ungenaue) und die "smarte" aber aufwändigere.
dein Ansatz entspricht erst mal der einfachen Variante. Deine Rule wird zwischen 8 Uhr und 22 Uhr beginnend zur vollen Stunde alle 25 Minuten ausgelöst. Das heißt: 8:00:00, 8:25:00, 8:50:00, 9:00:00(!) ... 21:00:00, 21:25:00, 21:50:00. Es wäre vermutlich besser, die Rule alle 20 Minuten triggern zu lassen, oder alternativ all 30 Minuten. Eventuell könnte ein Trigger "0 */25 8-21 * * ?" hier das gewünschte Verhalten bringen (regelmäßig alle 25 Minuten)
Jetzt muss die Rule prüfen, ob eines der iPhones da ist (dies ist ein Zustand, kein Ereignis!) so:

Code: Alles auswählen

if(iPhones.state == ON)
Anschließend sollte der Code zum Einschalten und Ausschalten so funktionieren, wie er da steht.

Code: Alles auswählen

rule "Cron Zirkulation"
when
    Time cron "0 */25 8-21 * * ?"
then
    if(iPhones.state == ON) {
        logInfo("Z-Cron","Zirkulation eingeschaltet")
        WWPumpe.sendCommand(ON)
        createTimer(now.plusSeconds(300)) [ |
            WWPumpe.sendCommand(OFF)
        ]
    }
end
Wie gesagt ist das zumindest nicht sonderlich smart. Das Problem dabei: Nehmen wir an, Du kommst nach Hause und Dein iPhone verbindet sich exakt um 8:00:01 mit dem WLAN (bzw. es wird exakt zu diesem Zeitpunkt als vorhanden registirert, da passieren ja auch noch ein paar Dinge vorher, je nachdem, wie die Erkennung umgesetzt ist). Die erste Zirkulation findet dann um 08:25:00 Uhr statt, denn die Rule lief ja um 08:00:00 und zu dem Zeitpunkt war iPhones noch OFF.

Smarter wäre also eine Rule, welche direkt triggert, wenn das erste Telefon erkannt wird und dann innerhalb der Rule prüft, ob auch der Zeitrahmen passt. so:

Code: Alles auswählen

var Timer tZPumpe = null

rule "Cron Zirkulation"
when
    Time cron "0 0 8,22 * * ?" or                                      // Um 8 Uhr und um 22 Uhr
    Item iPhones changed                                               // Wenn Anwesend oder Abwesend
then
    var Boolean bPumpe = false                                         // Default ist aus
    if(now.getHour > 7 && now.getHour < 22 && iPhones.state == ON)     // Zeitfenster erfüllt und anwesend
        bPumpe = true                                                  // an

    if(bPumpe && tZPumpe === null) {                                   // Pumpe soll laufen, Timer läuft aber nicht

        logInfo("zpumpe","Zirkulation Interval gestartet!")

        tZPumpe = createTimer(now.plusSeconds(1),[|                    // erzeuge Timer und führe ihn auch gleich aus
            var Integer iTime = 20 * 60                                // Ausschaltdauer setzen
            if(WWPumpe.state != ON)                                    // Falls Pumpe gerade aus, 
                iTime = 5 * 60                                         // Einschaltdauer setzen

            logInfo("zpumpe","Timer: Pumpe schaltet nun für {} Sekunden {}.",iTime,if(WWPumpe.state != ON) "ein" else "aus")

            WWPumpe.sendCommand(if(WWPumpe.state != ON) ON else OFF)   // Toggle Pumpe
            tZPumpe.reschedule(now.plusSeconds(iTime))                 // und lass den Timer in iTime Sekunden erneut ausführen
        ])
    } else if(!bPumpe) {                                               // Pumpe soll nicht laufen
        tZPumpe?.cancel                                                // falls ein Timer läuft, abbrechen
        tZPumpe = null                                                 // und Variable leeren
        if(WWPumpe.state != OFF)                                       // Falls Pumpe gerade läuft
            WWPumpe.sendCommand(OFF)                                   // Ausschalten

        logInfo("zpumpe","Zirkulation Interval beendet!")

    }
end
Die Rule triggert, wenn sich der Zustand des Items ändert (von ON auf OFF oder auch von OFF auf ON), sowie um 8 Uhr und um 22 Uhr.
Sobald die Rule ausgeführt wird, wird berechnet, ob die Zirkulation mit Interval gestartet werden soll oder nicht, also ob das Zeitfenster erfüllt und jemand anwesend ist.
Im nächsten Schritt wird geprüft, ob die Zirkulation laufen soll, aber der Timer nicht aktiv ist. Ist dies der Fall, so wird der Timer angelegt und die Rule ist beendet.
Andernfalls wird geprüft, ob die Zirkulation abgeschaltet werden soll. Ist dies der Fall, so wird ein eventuell laufender Timer beendet und deinitialisiert. Falls die Pumpe gerade läuft, wird diese angehalten. damit ist die Rule beendet.

Die eigentliche Arbeit - das zyklische Schalten der Pumpe - geschieht nun ausschließlich über den Timer Code, weshalb ich den hier nochmal extra einfüge (nur zur Anschauung):

Code: Alles auswählen

var Integer iTime = 20 * 60                                // Ausschaltdauer setzen
if(WWPumpe.state != ON)                                    // Falls Pumpe gerade aus, 
    iTime = 5 * 60                                         // Einschaltdauer setzen

logInfo("zpumpe","Timer: Pumpe schaltet nun für {} Sekunden {}.",iTime,if(WWPumpe.state != ON) "ein" else "aus")

WWPumpe.sendCommand(if(WWPumpe.state != ON) ON else OFF)   // Toggle Pumpe
tZPumpe.reschedule(now.plusSeconds(iTime))                 // und lass den Timer in iTime Sekunden erneut ausführen
Erreicht der Scheduler die geplante Zeit, so wird der Code ausgeführt.
Zunächst wird die Variable iTime mit der Ausschaltdauer vorbelegt.
Falls die Pumpe gerade nicht läuft, wird iTime auf die Einschaltdauer gesetzt
Anschließend wird die Pumpe getoggelt, falls sie also ausgeschaltet ist, wird sie eingeschaltet und umgekehrt.
Zum Schluss wird der Timer neu geplant, mit der vorher ausgewählten Zeit.

Die log Meldung verdient auch noch ein paar Worte :)

Code: Alles auswählen

logInfo("zpumpe","Timer: Pumpe schaltet nun für {} Sekunden {}.",iTime,if(WWPumpe.state != ON) "ein" else "aus")
Die beiden geschweiften Klammerpaare werden substituiert, d.h. mit dem Inhalt der Variablen ersetzt, die angehängt sind. Zum einen ist das die Schaltdauer, zum anderen der Zustand, welcher aus dem aktuellen Zustand abgeleitet wird. Ist die Pumpe gerade nicht an, so wird eingeschaltet, ansonsten ausgeschaltet. Das Konstrukt if(a) b else c heißt übrigens ternärer Operator, also wenn a zutrifft nimm b, ansonsten c. Überaus praktisch, wie man sehen kann :)

Weil es immer wieder für Verwirrung sorgt: = -> Zuweisung eines Wertes. == -> Vergleich linker Wert mit rechter Wert. === -> Prüfung, ob Zeiger auf der linken Seite und Zeiger auf der rechten Seite gleich sind. Bei Prüfung auf null soll mit === getestet werden (für ungleich mit !==).
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten