Präsenzsimulation in OH5 funktioniert nicht mehr

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
Maggi
Beiträge: 36
Registriert: 22. Okt 2019 20:09
Answers: 0
Wohnort: Nordhorn

Präsenzsimulation in OH5 funktioniert nicht mehr

Beitrag von Maggi »

Moin Leute,

ich habe eine Rule für eine Präsenzsimulation übernommen, die in OH2.5 noch funktioniert hat. Leider bringt sie in OH5 einen Fehler und wird nicht gestartet.

Vielleicht hat jemand eine Idee was genau geändert werden muss, da meine Kenntnisse hier nicht ausreichen.

Ich habe in deen .items folgende Gruppen angelegt, und auch entsprechende Lampen damit verbunden.

Code: Alles auswählen

Group pSimH // Präsenzsimulation H
Group pSimV // Präsenzsimulation V
Und folgende Rule angelegt, welche durch einen virtuellen Schalter aktiv wird.

Code: Alles auswählen

import java.util.TimeZone

val java.util.Random rand = new java.util.Random

rule "Praesenzsimulation durchführen"
 when
 Time cron "0 0/20 17-22 * * ?"  // Rule soll alle 20 Minuten aktiv werden im Zeitraum von 17:00 - 22:00 Uhr
 or
 Channel "astro:sun:minus:set#event" triggered START
 then
 
 var Integer schaltintervall = 20 // Sollte mit Cron-Aufruf-Intervall übereinstimmen
 var Integer schaltueberlappung = 9 // Zufällige Überlappung, damit nicht alle Lampen gleichzeitig ausgehen (plus zus. 1 Minute)
 var DateTime datumSonnenaufgang = new DateTime((Sunrise_Time_15.state as DateTimeType).calendar.timeInMillis)
 var DateTime datumSonnenuntergang = new DateTime((Sunset_Time_15.state as DateTimeType).calendar.timeInMillis)
 val boolean istDunkel = datumSonnenaufgang.afterNow || datumSonnenuntergang.beforeNow

val Boolean log = true

if (log) logInfo('rules','Präsenzsimulation: Rule gestartet. istDunkel=' + istDunkel.toString() + ' praesenzSimulation=' + praesenzSimulation.state.toString())
 
 if (praesenzSimulation.state == OFF) {
 if (log) logInfo('rules','Präsenzsimulation: Präsenzsimulation ausgesetzt - nicht aktiv!')
 } else if ((praesenzSimulation.state == ON) && (!istDunkel)) {
 if (log) logInfo('rules','Präsenzsimulation: Präsenzsimulation ausgesetzt - aktiv, aber es ist noch nicht dunkel!')
 } else { // es ist dunkel und die Simulation wurde aktiviert
 if (log) logInfo('rules','Präsenzsimulation: Präsenzsimulation wird ausgeführt')
 // Je Präsenzsimulations-Lichtergruppe soll mindestens ein Licht geschalten sein. (pSimH und pSimV)
 var pSimHAnzahl = (pSimH.members.size)
 var pSimVAnzahl = (pSimV.members.size)

// je Gruppe eine zufallsgenerierte Lampen schalten für Zufallszeit zwischen schaltintervall + schaltüberlappung in Minuten
 var Integer schaltzeitH = rand.nextInt(schaltueberlappung) + schaltintervall + 1
 var Integer schaltzeitV = rand.nextInt(schaltueberlappung) + schaltintervall + 1
 var Integer counterH = 0
 var lampeHON = true
 var lampeH = 0
 var boolean exitFlag = false
 
 // LampeH suchen, welche noch nicht AN ist, maximal 30 Versuche, sonst endlosschleife, wenn alle Lampen an wären
 while (lampeHON && !exitFlag) {
 lampeH = rand.nextInt(pSimHAnzahl)
 lampeHON = (pSimH.members.get(lampeH).state == ON) || (pSimH.members.get(lampeH).state > 0)
 if (log) logInfo('rules', 'Präsenzsimulation: Versuch Nr. ' + counterH + ' Ermittelte LampeH (Index) ' + lampeH + '/' + pSimH.members.get(lampeH).name + ' Status lampeHON ' + lampeHON.toString())
 counterH = counterH + 1
 if (counterH > 30) exitFlag = true
 }
 if (!exitFlag) {
 // LampeH schalten und Timer für Ausschalten setzen
 if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeH an: ' + pSimH.members.get(lampeH).name + ' für ' + schaltzeitH + ' Minuten')
 pSimH.members.get(lampeH).sendCommand(ON)
 createTimer(now.plusSeconds(schaltzeitH * 60)) [|
 pSimH.members.get(lampeH).sendCommand(OFF)
 if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeH aus: ' + pSimH.members.get(lampeH).name + ' nach ' + schaltzeitH + ' Minuten')
 ]
 } else {
 logInfo('rules','Präsenzsimulation: Keine freie LampeH gefunden!')
 }
 // LampeV suchen, welche noch nicht AN ist, maximal 30 Versuche, sonst ergibt sich evtl eine Endlosschleife, wenn alle Lampen an wären
 var Integer counterV = 0
 var lampeVON = true
 var lampeV = 0
 exitFlag = false
 while (lampeVON && !exitFlag) {
 lampeV = rand.nextInt(pSimVAnzahl)
 lampeVON = (pSimV.members.get(lampeV).state == ON) || (pSimV.members.get(lampeV).state > 0)
 if (log) logInfo('rules', 'Präsenzsimulation: Versuch Nr. ' + counterH + ' Ermittelte LampeV (Index) ' + lampeV + '/' + pSimV.members.get(lampeV).name + ' Status lampeVON ' + lampeVON.toString())
 counterV = counterV + 1
 if (counterV > 30) exitFlag = true
 }

if (!exitFlag) {
 // LampeV schalten und Timer für Ausschalten setzen
 if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeV an: ' + pSimV.members.get(lampeV).name + ' für ' + schaltzeitV + ' Minuten')
 pSimV.members.get(lampeV).sendCommand(ON)
 createTimer(now.plusSeconds(schaltzeitV * 60)) [|
 pSimV.members.get(lampeV).sendCommand(OFF)
 if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeV aus: ' + pSimV.members.get(lampeV).name + ' nach ' + schaltzeitV + ' Minuten')
 ] 
 } else {
 if (log) logInfo('rules','Präsenzsimulation: Keine freie LampeV gefunden!')
 }
 }
end

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

Re: Präsenzsimulation in OH5 funktioniert nicht mehr

Beitrag von peter-pan »

Ich bin zwar auch nur User, aber vielleicht verrätst du mal als erstes, wie die Fehlermeldung lautet. Vielleicht hilft das ja schon ein Stück weiter.
Pi5/8GB(PiOS Lite 64-bit(trixie)/SSD 120GB - OH5.1.4 openhabian
(Test openHAB 5.2.0.M5 - RPi 5/8 / M.2 SSD)

Maggi
Beiträge: 36
Registriert: 22. Okt 2019 20:09
Answers: 0
Wohnort: Nordhorn

Re: Präsenzsimulation in OH5 funktioniert nicht mehr

Beitrag von Maggi »

Als Fehlermeldung tauch folgendes auf.

failed: An error occurred during the script execution: Cannot invoke "org.eclipse.xtext.common.types.JvmType.eIsProxy()" because "type" is null in Anwesenheitssimulation
Das passiert scheinbar noch vor dem ersten Log.

Maggi
Beiträge: 36
Registriert: 22. Okt 2019 20:09
Answers: 0
Wohnort: Nordhorn

Re: Präsenzsimulation in OH5 funktioniert nicht mehr

Beitrag von Maggi »

Ich habe den Syntax mal durch Gemini gejagt und mir wurde der Code tatsächlich angepasst und funktioniert jetzt :-D
Die Änderungen hat Gemini auch gleich dazu geschrieben.
Ich bin begeistert.

### Modernisierter openHAB 3/4 Code:

Code: Alles auswählen

import java.util.Random

// Globale Instanz für die Zufallszahlen
val Random rand = new Random()

rule "Praesenzsimulation durchführen"
when
    Time cron "0 0/20 17-22 * * ?" // Alle 20 Minuten zwischen 17:00 und 22:00 Uhr
    or
    Channel "astro:sun:minus:set#event" triggered START
then
    val Integer schaltintervall = 20
    val Integer schaltueberlappung = 9
    
    // openHAB 3/4 Datums-Handling (ZonedDateTime / Instant)
    val datumSonnenaufgang = (Sunrise_Time_15.state as DateTimeType).zonedDateTime
    val datumSonnenuntergang = (Sunset_Time_15.state as DateTimeType).zonedDateTime
    val Boolean istDunkel = datumSonnenaufgang.isAfter(now) || datumSonnenuntergang.isBefore(now)

    val Boolean log = true

    if (log) logInfo("rules", "Präsenzsimulation: Rule gestartet. istDunkel=" + istDunkel + " praesenzSimulation=" + praesenzSimulation.state)
 
    if (praesenzSimulation.state == OFF) {
        if (log) logInfo("rules", "Präsenzsimulation: Präsenzsimulation ausgesetzt - nicht aktiv!")
    } else if (praesenzSimulation.state == ON && !istDunkel) {
        if (log) logInfo("rules", "Präsenzsimulation: Präsenzsimulation ausgesetzt - aktiv, aber es ist noch nicht dunkel!")
    } else { // Es ist dunkel und die Simulation ist aktiviert
        if (log) logInfo("rules", "Präsenzsimulation: Präsenzsimulation wird ausgeführt")

        val pSimHAnzahl = pSimH.members.size
        val pSimVAnzahl = pSimV.members.size

        // Schaltdauer ermitteln
        val Integer schaltzeitH = rand.nextInt(schaltueberlappung) + schaltintervall + 1
        val Integer schaltzeitV = rand.nextInt(schaltueberlappung) + schaltintervall + 1
        
        // --- Gruppe H schalten ---
        var Integer counterH = 0
        var Boolean lampeHON = true
        var Integer lampeH = 0
        var Boolean exitFlagH = false
 
        while (lampeHON && !exitFlagH) {
            lampeH = rand.nextInt(pSimHAnzahl)
            val memberH = pSimH.members.get(lampeH)
            
            // Sauberer Check für Switch (ON) und Dimmer (DecimalType > 0)
            lampeHON = memberH.state == ON || (memberH.state instanceof DecimalType && (memberH.state as DecimalType) > 0)
            
            if (log) logInfo("rules", "Präsenzsimulation: Versuch Nr. " + counterH + " Ermittelte LampeH (Index) " + lampeH + "/" + memberH.name + " Status lampeHON " + lampeHON)
            counterH = counterH + 1
            if (counterH > 30) exitFlagH = true
        }

        if (!exitFlagH) {
            val zielLampeH = pSimH.members.get(lampeH)
            if (log) logInfo("rules", "Präsenzsimulation: Schalte LampeH an: " + zielLampeH.name + " für " + schaltzeitH + " Minuten")
            zielLampeH.sendCommand(ON)
            
            createTimer(now.plusMinutes(schaltzeitH)) [|
                zielLampeH.sendCommand(OFF)
                if (log) logInfo("rules", "Präsenzsimulation: Schalte LampeH aus: " + zielLampeH.name + " nach " + schaltzeitH + " Minuten")
            ]
        } else {
            logInfo("rules", "Präsenzsimulation: Keine freie LampeH gefunden!")
        }

        // --- Gruppe V schalten ---
        var Integer counterV = 0
        var Boolean lampeVON = true
        var Integer lampeV = 0
        var Boolean exitFlagV = false

        while (lampeVON && !exitFlagV) {
            lampeV = rand.nextInt(pSimVAnzahl)
            val memberV = pSimV.members.get(lampeV)
            
            // Sauberer Check für Switch (ON) und Dimmer (DecimalType > 0)
            lampeVON = memberV.state == ON || (memberV.state instanceof DecimalType && (memberV.state as DecimalType) > 0)
            
            if (log) logInfo("rules", "Präsenzsimulation: Versuch Nr. " + counterV + " Ermittelte LampeV (Index) " + lampeV + "/" + memberV.name + " Status lampeVON " + lampeVON)
            counterV = counterV + 1
            if (counterV > 30) exitFlagV = true
        }

        if (!exitFlagV) {
            val zielLampeV = pSimV.members.get(lampeV)
            if (log) logInfo("rules", "Präsenzsimulation: Schalte LampeV an: " + zielLampeV.name + " für " + schaltzeitV + " Minuten")
            zielLampeV.sendCommand(ON)
            
            createTimer(now.plusMinutes(schaltzeitV)) [|
                zielLampeV.sendCommand(OFF)
                if (log) logInfo("rules", "Präsenzsimulation: Schalte LampeV aus: " + zielLampeV.name + " nach " + schaltzeitV + " Minuten")
            ] 
        } else {
            if (log) logInfo("rules", "Präsenzsimulation: Keine freie LampeV gefunden!")
        }
    }
end

Diese Regel verwendet den alten **openHAB 2 Syntax** (Joda-Time sowie Deprecated-APIs wie `.calendar.timeInMillis`).

In **openHAB 3 und 4** basiert das Datums-Handling auf dem Java 8 `java.time` Standard (ZonedDateTime / Instant). Zudem wurde die Syntax für den Typvergleich und Type-Casts modernisiert.


### Die wichtigsten Anpassungen im Überblick:

1. **Datumsfunktionen / Zeitbibliothek:**
* `.calendar.timeInMillis` entfällt. In openHAB 3/4 greift man direkt über `.zonedDateTime` auf das Objekt zu.
* `afterNow` / `beforeNow` wurden durch die Standard Java-Methoden `isAfter(now)` und `isBefore(now)` ersetzt.
* `now.plusSeconds(schaltzeitH * 60)` wurde vereinfacht zu `now.plusMinutes(schaltzeitH)`.


2. **Typ-Sicherheit (Typenvergleich):**
* Ein Vergleich `member.state > 0` erzeugt bei String- oder Switch-Items Laufzeitfehler. Dies wurde zu `member.state instanceof DecimalType && (member.state as DecimalType) > 0` korrigiert, um Dimmer-Items korrekt und sicher auszuwerten.


3. **Timer-Gefahr behoben:**
* Variablen innerhalb des Timers wurden lokal fixiert (`val zielLampeH = ...`). In der alten Version konnte es unter ungünstigen Bedingungen passieren, dass die Variable `lampeH` überschrieben wurde, bevor der Timer ausführt, was zum Ausschalten der falschen Lampe geführt hätte.


4. **Bugfix beim Logging:**
* Im Log der V-Gruppe wurde im Original `counterH` statt `counterV` ausgegeben.

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

Re: Präsenzsimulation in OH5 funktioniert nicht mehr

Beitrag von peter-pan »

Na dann ist ja wieder alles in Butter.
Es gab einige Veränderungen nach OH2.x auf OH3 bzw.4 und 5. Darunter waren auch die Zeitfunktionen. Ja und das mit den Typen ist auch so eine Sache, wenn man Vergleiche anstellt. Bei alphanumerischen bzw. character-Typen ist das immer ein bisschen kritisch (</>).
Viel Spass weiterhin
Pi5/8GB(PiOS Lite 64-bit(trixie)/SSD 120GB - OH5.1.4 openhabian
(Test openHAB 5.2.0.M5 - RPi 5/8 / M.2 SSD)

Antworten