Working with average of a numeric value in automations

Hey community,

is it possible to work with an average of a numeric value in the automations? For example: Take the average of the last 2 minutes of the values, which were sent from the entity?

My problem is: I’ve build a rule in my openHAB for the washing machine and the dryer for a notification when it’s finish. And now I want to migrate that to the Home Assistance. For the washing machine its quite easy, because it only knows ON and OFF. But the dryer is a little bit more difficult because it has a “Wrinkle Protect” function. That means, it tumbles the cloths for an hour at the end of the drying cycle. But the cloths are already finished at this moment. So I need to find the correct moment, after the drying cycle but when the wrinkle protect is active. And that was working well with an average in openHAB.
Here is my rule from openHAB, if someone can do something with it:

// Dryer status definition
val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_PROTECT = 3

val Number THRESHOLD_STANDBY = 1
val Number THRESHOLD_ACTIVE = 10
val Number THRESHOLD_PROTECT = 10
val Number THRESHOLD_PROTECT_AVG = 50
val Number THRESHOLD_ACTIVE_AFTER_PROTECT = 600
val Number THRESHOLD_FINISH = 1

// Temp Variables for cycles
var Number var_Durchlauf_Verbrauch_kwh
var Number var_Durchlauf_Kosten_eur
var long var_Durchlauf_Startzeit
var long var_Durchlauf_Dauer

// ===================================================
// Change of the dryer status
//
rule "Aenderung des Trockner Status"
when
    Item Trockner_Leistung_w changed
then
    Thread::sleep(250)
    var Number Leistung = Trockner_Leistung_w.state as Number
    switch (Trockner_Status.state) {
        case MODE_OFF: {
            if (Leistung > THRESHOLD_ACTIVE) {
                Trockner_Status.postUpdate(MODE_ACTIVE)
                logInfo("TROCKNER_MODE_CHANGE", "Von OFF to ACTIVE - Wert: " + Leistung)
            } else if (Leistung > THRESHOLD_STANDBY) {
                Trockner_Status.postUpdate(MODE_STANDBY)
                logInfo("TROCKNER_MODE_CHANGE", "Von OFF to STANDBY- Wert: " + Leistung)
            }
        }
        case MODE_STANDBY: {
            if (Leistung > THRESHOLD_ACTIVE) {
                Trockner_Status.postUpdate(MODE_ACTIVE)
                logInfo("TROCKNER_MODE_CHANGE", "Von STANDBY to ACTIVE - Wert: " + Leistung)
            } else if (THRESHOLD_FINISH > Leistung) {
                Trockner_Status.postUpdate(MODE_OFF)
                logInfo("TROCKNER_MODE_CHANGE", "Von STANBY to OFF - Wert: " + Leistung)
            }
        }
        case MODE_ACTIVE: {
            var Number Average_Leistung = Trockner_Leistung_w.averageSince(now.minusMinutes(1))
            logInfo("TROCKNER_LEISTUNG_CHANGED", "Wert " + Leistung + " ergibt einen Durschnitt von " + Average_Leistung)
            if (Average_Leistung != null) {
                if (THRESHOLD_FINISH > Leistung) {
                    Trockner_Status.postUpdate(MODE_OFF)
                    logInfo("TROCKNER_MODE_CHANGE", "Von ACTIVE to OFF - Wert: " + Leistung)
                } else if (THRESHOLD_PROTECT > Leistung && THRESHOLD_PROTECT_AVG > Average_Leistung) {
                    Trockner_Status.postUpdate(MODE_PROTECT)
                    logInfo("TROCKNER_MODE_CHANGE", "Von ACTIVE to PROTECT - Wert: " + Average_Leistung)
                }
            }
        }
        case MODE_PROTECT: {
            if (THRESHOLD_FINISH > Leistung) {
                Trockner_Status.postUpdate(MODE_OFF)
                logInfo("TROCKNER_MODE_CHANGE", "Von PROTECT to OFF - Wert: " + Leistung)
            } else if (Leistung > THRESHOLD_ACTIVE_AFTER_PROTECT) {
                Trockner_Status.postUpdate(MODE_ACTIVE)
                logInfo("TROCKNER_MODE_CHANGE", "Von PROTECT to ACTIVE - Wert: " + Leistung)
            }
        }
        default: {
            logInfo("TROCKNER_MODE_CHANGE", "Der Status war unbekannt und wird geändert zu: " + MODE_OFF)
            Trockner_Status.postUpdate(MODE_OFF)
        }
    }
end

// ===================================================
// Notification when finished
//
rule "Benachrichtigung bei Trockner Fertig"
when
    Item Trockner_Status changed
then
    if (Trockner_Status.state == MODE_PROTECT) {
        sendTelegram("mark", "Der Trockner ist fertig und hat den Knitterschutz gestartet")
        sendTelegram("nicole", "Der Trockner ist fertig und hat den Knitterschutz gestartet")
        Echo_Dot_Living_Room_TTS.sendCommand("Der Trockner ist fertig. Bitte die Wäsche nicht vergessen!")
    } else if (Trockner_Status.state == MODE_ACTIVE) {

        // Merke Start-Verbrauchsstand
        Trockner_Start_Gesamtverbrauch_kwh.postUpdate(Trockner_Gesamtverbrauch_kwh.state)
        sendTelegram("mark", "Der Trockner wurde gestartet")

        // Merke Startzeit
        var_Durchlauf_Startzeit = now.millis
        logInfo("TROCKNER_TIMER_LOG", "Durchlauf Startzeit: " + var_Durchlauf_Startzeit + "ms")

    } else if (Trockner_Status.state == MODE_STANDBY) {
        sendTelegram("mark", "Der Trockner wurde angeschaltet")
    } else if (Trockner_Status.state == MODE_OFF) {

        // Berechne Verbrauch des Durchlaufs mittels Startwert und aktuellem Gesamtwert
        var_Durchlauf_Verbrauch_kwh = Trockner_Gesamtverbrauch_kwh.state as DecimalType - Trockner_Start_Gesamtverbrauch_kwh.state as DecimalType
        logInfo("TROCKNER_KOSTEN_LOG", "Startverbrauch: " + Trockner_Start_Gesamtverbrauch_kwh.state + " kWh - Gesamt: " + Trockner_Gesamtverbrauch_kwh.state + " kWh")

        // Berechne Durchlaufskosten
        var_Durchlauf_Kosten_eur = var_Durchlauf_Verbrauch_kwh * ESSL_KWH
        logInfo("TROCKNER_KOSTEN_LOG", "Kosten: " + String::format("%.2f", var_Durchlauf_Kosten_eur.floatValue()) + " €")

        // Berechne Laufzeit
        logInfo("TROCKNER_ERROR_LOG", "Berechne: " + now.millis + " - " + var_Durchlauf_Startzeit)
        //var_Durchlauf_Dauer = now.millis - var_Durchlauf_Startzeit
        logInfo("TROCKNER_TIMER_LOG", "Durchlauf Dauer: " + var_Durchlauf_Dauer + "ms (" + var_Durchlauf_Dauer / 60000 + "min)")

        // Sende Nachricht
        sendTelegram("mark", "Der Trockner wurde ausgeschaltet.")// Der Durchlauf hat " +
            //var_Durchlauf_Verbrauch_kwh + " kWh verbraucht, " + var_Durchlauf_Dauer / 60000 + " Minuten gedauert und " + 
            //String::format("%.2f", var_Durchlauf_Kosten_eur.floatValue()) + " € gekostet.")
        sendTelegram("nicole", "Der Trockner wurde ausgeschaltet.")// Der Durchlauf hat " +
            //var_Durchlauf_Verbrauch_kwh + " kWh verbraucht, " + var_Durchlauf_Dauer / 60000 + " Minuten gedauert und " + 
            //String::format("%.2f", var_Durchlauf_Kosten_eur.floatValue()) + " € gekostet.")
    }
end

And here is a picture of a cycle of the dryer:

I gratefully accept any help on this.

Cheers,
Mark

Statistics sensor
Just set the max_age to two minutes.
Not sure what the sampling size needs to be but that should be the number of values you get during two minutes.
But since the max_age will discard any older values, I assume you could set sampling_size to 1000, because it won’t matter. As long as it’s not less than what you get on two minutes