Problem mit Waschmaschinen State Machine

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
oNlyLuck
Beiträge: 4
Registriert: 17. Nov 2019 12:46
Answers: 0

Problem mit Waschmaschinen State Machine

Beitrag von oNlyLuck »

Hallo zusammen,

ich habe analog zu https://community.openhab.org/t/washing ... hine/15587 eine regelbasierte State Machine für meine Waschmaschine erstellt.

Das rules-File sieht folgendermaßen aus:

Code: Alles auswählen

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3
var Timer Washing_Machine_Timer

rule "Washingmachine Consumption State Machine"
when
    Item TPL1_Power changed
then
logInfo("powerconsumption.rules", "Washing Machine rule initiated.")
    if (TPL1_Power.state < 0.2) { Washingmachine_OpState.postUpdate(MODE_OFF) logInfo("powerconsumption.rules", "Washing Machine OFF.") }
    else if (TPL1_Power.state > 10) {
    if (Washing_Machine_Timer !== null) {
    Washing_Machine_Timer.cancel()
    logInfo("powerconsumption.rules", "Timer cancelled.")
    Washingmachine_OpState.postUpdate(MODE_ACTIVE)
    logInfo("powerconsumption.rules", "Washing Machine ACTIVE.")
    }
    Washingmachine_OpState.postUpdate(MODE_ACTIVE)
    logInfo("powerconsumption.rules", "Washing Machine ACTIVE.")
      logInfo("powerconsumption.rules", "Timer not cancelled due to it being null.")
    }
    else if (TPL1_Power.state < 4) {
        if (Washingmachine_OpState.state == MODE_OFF) { Washingmachine_OpState.postUpdate(MODE_STANDBY) logInfo("powerconsumption.rules", "Washing Machine STANDBY") }
        else if (Washingmachine_OpState.state == MODE_ACTIVE) {
                if (Washing_Machine_Timer === null) {
                 logInfo("powerconsumption.rules", "Timer created.")
       Washing_Machine_Timer = createTimer(now.plusMinutes(3), [ |
       Washingmachine_OpState.postUpdate(MODE_FINISHED)
       Washing_Machine_Timer.cancel()
       logInfo("powerconsumption.rules", "Timer cancelled after execution.")
       logInfo("powerconsumption.rules", "Washing Machine FINISHED.")
       sendTelegram("bot1", "Hey Stefan, washing machine is finished.")
         sendTelegram("bot2", "Hey Alexa, washing machine is finished.")
       ])
   }
            }
        }
end
Da meine Waschmaschine teilweise minutenlang in sehr niedrigen Wattbereichen arbeitet, wollte ich bewusst zu einem Timer und nicht Thread Sleep greifen, weil durch das Blockieren teilweise mehrere (vllt. sogar zu viele) Regelinstanzen gleichzeitig laufen würden...

Nun zu meinem Problem. Leider wird der Status, dass die Waschmaschine fertig ist, nicht gesetzt. Ich kann mir leider nicht erklären warum.
In den Logs kann ich sehen, dass immer wieder ein Timer gesetzt wird, der dann auch richtigerweise abgebrochen wird.

Leider scheint die Regel aber nicht in das entsprechende IF zu laufen, wenn die Maschine fertig ist.
Ich bin mir nicht ganz sicher, ob

Code: Alles auswählen

  if (Washing_Machine_Timer === null)
immer richtig funktioniert.

Sieht jemand ggf. was das Problem ist?

Vielen Dank im Voraus!
Stefan

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

Re: Problem mit Waschmaschinen State Machine

Beitrag von udo1toni »

Du cancelst den Timer innerhalb des Timers. das führt vermutlich zum Abbruch des Codes an dieser Stelle. Es führt aber nicht dazu (!), dass die Timer-Variable auf null gesetzt wird.
Ersetze die Zeile

Code: Alles auswählen

Washing_Machine_Timer.cancel()
innerhalb des Timers mit

Code: Alles auswählen

Washing_Machine_Timer = null
vielleicht magst Du die Zeile auch ans Ende des Lambdas verschieben - also hinter das sendTelegram("bot2"...)

Ansonsten könntest Du die Rule an einigen Stellen etwas vereinfachen. Ist es wichtig, zu erfahren, dass der Timer nicht gecancelt wurde? Der zweite if-Block sähe ansonsten so aus:

Code: Alles auswählen

    else if(TPL1_Power.state > 10) {
        Washing_Machine_Timer?.cancel
        Washing_Machine_Timer = null
        Washingmachine_OpState.postUpdate(MODE_ACTIVE)
        logInfo("powerconsumption.rules", "Washing Machine ACTIVE.")
    }
Der Timer wird gecancelt, falls er aktiv war und auf jeden Fall genullt.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

oNlyLuck
Beiträge: 4
Registriert: 17. Nov 2019 12:46
Answers: 0

Re: Problem mit Waschmaschinen State Machine

Beitrag von oNlyLuck »

Vielen Dank für deine Rückmeldung!

Hatte komplett übersehen, dass einen Timer abbrechen das Objekt nicht auf "null" setzt bzw. hatte nicht richtig verstanden, wann man abbricht und wann man auf "null" setzen sollte. :shock:

Habe den Code entsprechend angepasst und werde heute Abend bei einem Waschgang das nochmal monitoren :)

Gruß
Stefan

CarstenKlein
Beiträge: 2
Registriert: 25. Aug 2019 11:35
Answers: 0

Re: Problem mit Waschmaschinen State Machine

Beitrag von CarstenKlein »

Hallo,
ich würde mich gerne mal an dieses Thema dranhängen.
Auch ich möchte, dass mir meine Waschmaschine die an einer HS110 hängt, mitgeteilt bekommen, wenn der Waschvorgang fertig ist.

Ich bin zwar schon lange mit Openhab2 beschäftigt, aber meist sind das Basic Sachen und die meisten Rules bekomme ich dann auch in PaperUI mit der RulesEngine hin.

Mein erster Versuch sah so aus:

Code: Alles auswählen

rule "Watt Test"
when 
	Item Waschmaschine_Power received update
then
	var WaschmaschineWatts = Waschmaschine_Power.state as Number
	if (WaschmaschineWatts < 4.0) {
		 logInfo("Test", "Waschmaschine fertig")
		 // sendCommand(TestLampe_Helligkeit, 50)
		 sendTelegram("bot1", "Die Waschmaschine ist fertig.")
	}	 else if ( WaschmaschineWatts > 4.0) {
		 logInfo("Test", "Die Waschmaschine laeuft noch")
		 // sendCommand(TestLampe_Helligkeit, OFF)
    
	}
end
Das funktioniert auch soweit, aber logischerweise musste ich dann feststellen, dass mir so natürlich alle paar Sekunden eine Nachricht geschickt wird, wenn die Maschine unter 4Watt verbraucht.

Bei weiterem googlen kam ich dann auch auf den im ersten Thread verlinkten Post und zu dieser Seite:
http://discoveration.de/smarthome/wasch ... rtig/1230/
mit diesem Code:

Code: Alles auswählen

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3
 
rule "Washingmachine Status"
when
    Item Washingmachine_Power received update
then
    // > 1.5 aktiv
    // 1.5 - 0.2 standby
    // < 0.2 aus
    if (Washingmachine_Power.state < 0.2) { 
           postUpdate(Washingmachine_State, MODE_OFF) 
        } else if (Washingmachine_Power.state > 1.5) {
           postUpdate(Washingmachine_State, MODE_ACTIVE)        
        } else if (Washingmachine_Power.state <= 1.5) {
           if (Washingmachine_State.state == MODE_OFF) {
              postUpdate(Washingmachine_State, MODE_STANDBY)
           } else if (Washingmachine_State.state == MODE_ACTIVE) {
              postUpdate(Washingmachine_State, MODE_FINISHED)
              sendTelegram("Marco", "Die Waschmaschine ist fertig.")
              sendTelegram("Julia", "Die Waschmaschine ist fertig.")
           }
       }
end
daraus habe ich dann folgendes gemascht:

Code: Alles auswählen

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3

 
rule "Waschmaschine Status"
when
    Item Waschmaschine_Power received update
then
   var WaschmaschineWatts = Waschmaschine_Power.state as Number
    // > 1.5 aktiv
    // 1.5 - 0.2 standby
    // < 0.2 aus
    if (WaschmaschineWatts < 0.4) { 
           postUpdate(WaschmaschineWatts, MODE_OFF) 
           logInfo("Test", "MODE_OFF")
        } else if (WaschmaschineWatts > 4) {
           postUpdate(WaschmaschineWatts, MODE_ACTIVE)
           logInfo("Test", "MODE_ACTIVE")        
        } else if (WaschmaschineWatts <= 4) {
           if (WaschmaschineWatts == MODE_OFF) {
              postUpdate(WaschmaschineWatts, MODE_STANDBY)
              logInfo("Test", "MODE_STANDBY")  
           } else if (WaschmaschineWatts == MODE_ACTIVE) {
              postUpdate(WaschmaschineWatts, MODE_FINISHED)
              logInfo("Test", "MODE_FINISHED")  
              sendTelegram("bot1", "Die Waschmaschine ist fertig.")
           }
       }
end
Da habe ich allerdings stupide einfach nur meine Namen geändert, muss aber dazu sagen, dass ich das nicht ganz verstehe wie die Regel funktionieren soll. Ich habe hier schon etliche Stunden dran rum gespielt, aber es tut sich leider immer rein gar nichts.
Für was z.B. sind die postUpdate(Washingmachine_State, MODE_xxx) Wohin soll den etwas gepostet werden ich will doch nur eine Telegram Nachricht erhalten und das hat mit meiner ersten simplen Version ja auch schon funktioniert.

Vielleicht könnte mir hier jemand einen klein Tip geben, was ich hier noch ändern muss, damit ich hier mal etwas weiter komme.

Vielen Dank schon mal.
Gruß Carsten

rico.neuber
Beiträge: 1
Registriert: 19. Apr 2020 19:33
Answers: 0

Re: Problem mit Waschmaschinen State Machine

Beitrag von rico.neuber »

Hallo Carsten,

hast du das Problem mittlerweile lösen können? Ich frage, weil ich exakt das gleiche Problem habe und auch einen HS110 verbaut habe.

Viele Grüße,
Rico

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

Re: Problem mit Waschmaschinen State Machine

Beitrag von udo1toni »

Ich habe das hier nicht weiter verfolgt, deshalb erst jetzt ein Rückmeldung von mir.

Die Originalrule arbeitet mit Konstanten für den Betriebsszustand. Diese sind im Kopf der Datei definiert (MODE_XYZ).
Wenn der Itemstatus sichändert, triggert die Rule. Ist der Wert kleiner 0.2, wird der OpState auf OFF gesetzt, ist er höher als 10 wird geprüft, ob der Timer läuft, dieser wird gegebenenfalls beendet und der OpState wird auf ACTIVE gesetzt.
Ist der Status < 4 und der OpState OFF, wird OpState auf STANDBY gesetzt. Falls OpState auf ACTIVE steht und kein Timer angelegt ist, wird der Timer angelegt. Nach Ablauf des Timers (der Status war unter 4 und ist in den letzten drei Minuten nicht mehr über 10 gestiegen) wird die Ende-Meldung ausgegeben.

Der Code sollte so funktionieren, wobei er ein paar Schönheitsfehler hat. Ob man mit Konstanten arbeitet, ist Geschmacksache.

Hier die etwas aufgehübschte Variante:

Code: Alles auswählen

//Globale Variablen und Konstanten zu beginn der Datei definieren!

val MODE_OFF = 0
val MODE_STANDBY = 1
val MODE_ACTIVE = 2
val MODE_FINISHED = 3

var Timer tWashing_Machine = null

rule "Washingmachine Consumption State Machine"
when
    Item TPL1_Power changed
then
    if(!(TPL1_Power.state instanceof Number)) {
        logWarn("washing","Can't get valid power! {}",TPL1_Power.state)
        return;
    }
    
    val nPower = (TPL1_Power.state as Number).floatValue
    logInfo("washing", "Washing Machine rule initiated.")

    if (nPower < 0.2 && Washingmachine_OpState.state != MODE_OFF) { 

        Washingmachine_OpState.postUpdate(MODE_OFF) 
        logInfo("washing", "Washing Machine OFF.") 

    } else if(nPower > 10 && Washingmachine_OpState.state != MODE_ACTIVE) {

        Washingmachine_OpState.postUpdate(MODE_ACTIVE)
        logInfo("washing", "Washing Machine ACTIVE.")

        if(tWashing_Machine !== null) {

            tWashing_Machine.cancel
            logInfo("washing", "Timer cancelled.")

        } else {

            logInfo("washing", "Timer not cancelled due to it being null.")

        }
    } else if (nPower < 4) {

        if(Washingmachine_OpState.state == MODE_OFF) {

            Washingmachine_OpState.postUpdate(MODE_STANDBY) 
            logInfo("washing", "Washing Machine STANDBY") 

        } else if (Washingmachine_OpState.state == MODE_ACTIVE) {

            if(tWashing_Machine === null) {

                logInfo("washing", "Timer created.")
                tWashing_Machine = createTimer(now.plusMinutes(3), [ |

                    Washingmachine_OpState.postUpdate(MODE_FINISHED)
                    logInfo("washing", "Timer expired. Washing Machine FINISHED.")
                    sendTelegram("bot1", "Hey Stefan, washing machine is finished.")
                    sendTelegram("bot2", "Hey Alexa, washing machine is finished.")
                    tWashing_Machine = null

                ])
            }
        }
    }
end
Das Number Item Washingmachine_OpState hält den Status, der auch in der UI angezeigt wird. Dabei können die Namen der Konstanten mit einer map-Datei aus den Nummern erzeugt werden (Natürlich ist hier Freitext möglich)
Das Numer Item TPL1_Power liefert die aufgenommene Leistung.
Im Unterschied zum Original nutze ich eine zurLaufzeit erzeugte Konstante, die also zu Beginn der Rule mit der aktuellen Leistung gefüllt wird. Das spart etwas Text.
Im Unterschied zum Original prüfe ich, ob der aktuelle OpState vom Soll abweicht. Es soll ja nicht ständig im Log die Meldung auftauchen, dass der OpState auf OFF gesetzt wurde, obwohl er schon auf OFF war.
Zwei Zeilen waren unnötigerweise doppelt, außerdem wurde eine Meldung immer ausgegebn, die nur fallweise ausgegeben werden sollte.
Die Leerzeilen habe ich der Übersichtlichkeit halber eingefügt.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten