Offene Fenster nie wieder vergessen…

Wer kennt es nicht? Fenster aufgemacht, Anruf angenommen, dann klingelt es noch an der Türe, im Kopf ist man noch ganz woanders und dann denkt man nicht mehr daran, dass im Dachgeschoß noch das Fenster total offen ist… Gerade im Winter ärgerlich, wenn deswegen die Räume herunterkühlen. Da ich mir vor einiger Zeit an alle Fenster einen Sensor (Homematic IP Fenstergriff-Sensor (Link: Amazon, ELV Komplettgerät, ELV aus Bausatz) rangebaut habe, der den Status offen, gekippt oder geschlossen weitergeben kann, wollte ich dafür gleich einen neuen Anwendungszweck schaffen.

Zurück zu den offenen Fenstern: Damit das nicht mehr auftritt, kann openHAB helfen. Hier hilft eine Regel, die alle 1 Minute prüft, ob ein Fenster offen ist, wenn ja, dann gibt’s eine Meldung per Alexa-Text-To-Speech sowie via telegram auf’s Handy. Die Meldung via Bot / Telegram soll aber nur erfolgen, wenn bereits einmal nur per Alexa Text-To-Speech darauf hingewiesen wurde. Aber das Ganze soll natürlich noch konfigurierbar sein (An/Aus) sowie Temperaturabhängig (erst unter 15 Grad z.B.) und zuletzt soll auch die Dauer, ab wann gewarnt wird, einstellbar sein (z.B. 15 Minuten).

Voraussetzungen hierfür

  • Weather-Binding, um die Außentemperatur berücksichtigen zu können (bei mir ist das das item wetter_temperatur)
  • Persistence (bei mit mapdb), damit man weiß, wann der letzte Update eines Status eines items war (sonst wird die Rule viel komplizierter…)
  • Benennung der Fenster-Items im Format <Stockwerk>_FENSTER_<Bezeichnung>, also z.B. DG_FENSTER_SCHLAFZIMMER (wird dann automatisch in spechbares Umgewandelt, unterstütze Stockwerke KG=Keller, EG=Erdgeschoß, OG=Obergeschoß, DG=Dachgeschoß. Im Replace auf den Text einfach ggf. entspr. anpassen.

Dann kanns losgehen:

Items-File

Grundsätzlich müssen die Fensterkontakte, die später auf einen möglichen Status OPEN geprüft werden, in einer Gruppe gruppeFensterAlle stecken.

// Fenster-Offen-Warnung-Items
Switch fensterOffenWarnungAnAus         "Warnung wenn Fenster offen"    <switch>
Number fensterOffenWarnungTemperatur    "Warnen wenn Temperatur unter x Grad [%d]" <window>
Number fensterOffenWarnungMinuten       "Warnung wenn länger offen als x Minuten [%d]" <window>

Rules-File

var String logPrefix = 'Fensterüberwachung: '
var boolean log = true
rule "Fenster geöffnet"
when    Time cron "0 0/1 * * * ?" // Alle 1 Minute
then
    // Check ob Variablen passen, ansonsten defaultwert setzen
    if ((fensterOffenWarnungAnAus.state != OFF) && (fensterOffenWarnungAnAus.state != ON)) {
        fensterOffenWarnungAnAus.sendCommand(OFF)
        logInfo('rules', logPrefix + 'Setze Default-Wert für fensterOffenWarnungAnAus=Aus')
    }
    if (fensterOffenWarnungTemperatur.state == NULL) {
        fensterOffenWarnungTemperatur.postUpdate(15)
        logInfo('rules', logPrefix + 'Setze Default-Wert für fensterOffenWarnungTemperatur=15')
    }
    if (fensterOffenWarnungMinuten.state == NULL) {
        fensterOffenWarnungMinuten.postUpdate(15)
        logInfo('rules', logPrefix + 'Setze Default-Wert für fensterOffenWarnungMinuten=15')
    }
    // botmeldung nur ab zweiter Meldung
    var boolean useBot = false
    // Ist Automatik an?
    if (fensterOffenWarnungAnAus.state == ON) {
        // Ist es kalt genug?
        if (wetter_temperatur.state <= (fensterOffenWarnungTemperatur.state as DecimalType)) {
            var String meldeText = '' 
            // zuerst schauen wir, ob Fenster noch in die Liste rein müssen, wenn noch nicht enthalten
            gruppeFensterAlle.members.filter[ i | i.state.toString() == 'OPEN'].forEach[i|
                var lastUpdate = i.lastUpdate("mapdb").toDateTime;
                // Ermitteln, wie lange in Sekunden das Fenster nun offen ist
                var long offenInMinuten = (now.getMillis() - lastUpdate.getMillis())/(1000*60);
                if (log) logInfo('rules', 'letztes Update von ' + i.name + ' (Status: ' + i.state.toString() + '): ' + lastUpdate + ' - offen in Minuten: ' + offenInMinuten.toString())
                if (offenInMinuten >= (fensterOffenWarnungMinuten.state as DecimalType)) {
                    meldeText+=i.name.toString() + ' seit ' + offenInMinuten + ' Minuten, '
                }
                if (offenInMinuten > (fensterOffenWarnungMinuten.state as DecimalType)) {
                    // Nun auch per Telegram warnen - TTS ist in dem Fall bereits erfolgt
                    useBot = true
                }
            ]
            if (meldeText != '') {
                // Besser les- und hörbar machen
                meldeText = 'Achtung - es sind Fenster seit einiger Zeit komplett offen: ' + meldeText.replaceAll('KG_','Kellergeschoß_').replaceAll('EG_','Erdgeschoß ').replaceAll('OG_','Obergeschoß ').replaceAll('DG_','Dachgeschoß ').replaceAll('_',' ') + ' bitte schließen!'

                if (log) logInfo('rules', logPrefix + 'Meldung über offene Fenster wird erfolgen...')
                // Text per Telegram und Alexa rausschicken...
                ALEXA_EG_WOHNEN_TTS.sendCommand(meldeText)
                if (useBot) {
                    sendTelegram("bot1", meldeText)
                    sendTelegram("bot2", meldeText)
                }
            }

        } else {
            if (log) logInfo('rules', logPrefix + 'Es ist nicht kalt genug. Temperatur ist ' + wetter_temperatur.state.toString() + ' Schwellwert: ' + fensterOffenWarnungTemperatur.state.toString())
        }
    }
end 

Das Rule-File ist so gestrickt, dass Werte, falls sie nicht vorhanden sind, mit einem Default-Wert initialisiert werden (Automatik inaktiv, 15 Grad, 15 Minuten).

Sitemap-File

(...)
Text label="Fensterwarnung" icon=window{
     Frame label="Konfiguration Fenster" {
         Switch item=fensterOffenWarnungAnAus
         Setpoint item=fensterOffenWarnungTemperatur minValue=-30 maxValue=23 step=1
         Setpoint item=fensterOffenWarnungMinuten minValue=5 maxValue=60 step=1
     }
 }
(...)

Das Ergebnis

Wenn nun es kälter gleich 15 Grad ist, ein Fenster über 15 Minuten offen ist, dann erfolgt eine Warnung per Telegram sowie eine Textansage via Amasons Alexa.

10 Antworten auf „Offene Fenster nie wieder vergessen…“

  1. An der Regel stimmt etwas nicht. Bei mir zeigt der Log folgenden Satz:

    Fensterüberwachung: Es ist nicht kalt genug. Temperatur ist 7.83 °C Schwellwert: 10

    Hast du eine Lösung?

  2. Die Temperaturwerte hab ich nun in den Griff bekommen. Die Regel scheint dennoch fehlerhaft zu sein.

    [ntime.internal.engine.ExecuteRuleJob] – Error during the execution of rule ‚Fenster geöffnet‘: cannot invoke method public org.joda.time.DateTime org.joda.time.base.AbstractInstant.toDateTime() on null

    Hast du dafür eine Lösung?

  3. Hallo Florian,

    danke für diesen Blog Beitrag ich finde deine Beiträge klasse. Habe aber eine Frage was hast du in deiner „mapdb.persist“ ich bekomme eine Fehlermeldung.

    [ERROR] [ntime.internal.engine.ExecuteRuleJob] – Error during the execution of rule ‚Fenster geöffnet‘: cannot invoke method public org.joda.time.DateTime org.joda.time.base.AbstractInstant.toDateTime() on null

    Würde mich freuen wenn du mir da etwas zu schreiben könntest.

    Danke Jürgen

    1. Hallo Jürgen,

      leider kann ich alleien schon aus Zeitgründen hier keinen individuellen Support leisten. Bitte frage hierzu doch gerne mit Verweis auf diese Regeln (die bei mir mit OH 2.4 laufen…) in den openhab-Communities nach.

      Danke für’s Verständnis und viele Grüße!
      Florian

  4. Servus Florian,
    ist es möglich das Script auf OH3 anzupassen ?
    Dort haben sich scheinbar ein paar Dinge geändert und es funktioniert leider nicht mehr.
    Vielen Dank vorab
    Gruß Andre

    1. Hey ich hab es bei mir mit folgenden kleinen Anpassungen unter OH3 am laufen:

      Anpassung 1:
      alt:
      // Ist es kalt genug?
      if (wetter_temperatur.state <= (fensterOffenWarnungTemperatur.state as DecimalType))

      neu: (dürfte aber davon abhängen wie dein Item definiert ist, "Number:Temperature" ist es bei mir)
      val temperatur = (wetter_temperatur.state as QuantityType)
      if (temperatur <= (wetter_temperatur.state as QuantityType))

      Anpassung 2:
      alt:
      // zuerst schauen wir, ob Fenster noch in die Liste rein müssen, wenn noch nicht enthalten
      gruppeFensterAlle.members.filter[ i | i.state.toString() == ‚OPEN‘].forEach[i|
      var lastUpdate = i.lastUpdate(„mapdb“).toDateTime;
      // Ermitteln, wie lange in Sekunden das Fenster nun offen ist
      var long offenInMinuten = (now.getMillis() – lastUpdate.getMillis())/(1000*60);
      neu:
      // zuerst schauen wir, ob Fenster noch in die Liste rein müssen, wenn noch nicht enthalten
      gruppeFensterAlle.members.filter[ i | i.state.toString() == ‚OPEN‘].forEach[i|
      val lastUpdate = (i.lastUpdate(„mapdb“).toEpochSecond)
      // Ermitteln, wie lange in Sekunden das Fenster nun offen ist
      var long offenInMinuten = (ZonedDateTime.now().toEpochSecond – lastUpdate ) /60

  5. Hey Christoph,

    super tausend Dank, damit funktioniert es bei mir auch wieder 🙂

    Anpassung 1 hatte ich bereits gelöst über:
    if ((wetter_temperatur.state as QuantityType).intValue <= (fensterOffenWarnungTemperatur.state as DecimalType)) {

    Aber Anpassung 2 hat mir gefehlt.
    Nochmals danke für das Teilen 🙂

  6. Hallo Christoph und Andre,

    mit euren Lösungsansätzen bin ich denke ich schon fast am Ziel. Ich bekommen bei der zweiten Anpassung noch einen Fehler:

    // zuerst schauen wir, ob Fenster noch in die Liste rein müssen, wenn noch nicht enthalten
    gFenstS.members.filter[ i | i.state.toString() == „OPEN“].forEach[i|
    val lastUpdate = (i.lastUpdate(„rrd4j“).toEpochSecond);

    // Ermitteln, wie lange in Sekunden das Fenster nun offen ist
    var long offenInMinuten = (ZonedDateTime.now().toEpochSecond – lastUpdate) /60;

    “ [ERROR] [internal.handler.ScriptActionHandler] – Script execution of rule with UID ‚fenstersensoren-1‘ failed: cannot invoke method public default long java.time.chrono.ChronoZonedDateTime.toEpochSecond() on null in fenstersensoren“

    Bis jetzt habe ich in den diversen Openhab Foren oder Java Foren noch keine Lösung gefunden.

    Ich wollte die hier Rule von Florian so auch nicht einfach in ein Forum packen und da nach Lösungsansätzen fragen.

    ————————————————-

    var String logPrefix = ‚Fensterüberwachung: ‚
    var boolean log = true
    var String meldeText = “
    var boolean useBot = false

    val telegramAction = getActions(„telegram“,“telegrzumpostenhiergeloescht“)

    rule „Fenster geöffnet“

    when Time cron „0 0/1 * * * ?“ // Alle 1 Minute
    then
    // Check ob Variablen passen, ansonsten defaultwert setzen
    if ((fensterOffenWarnungAnAus.state != OFF) && (fensterOffenWarnungAnAus.state != ON)) {
    fensterOffenWarnungAnAus.sendCommand(OFF)
    logInfo(‚rules‘, logPrefix + ‚Setze Default-Wert für fensterOffenWarnungAnAus=Aus‘)
    }
    if (fensterOffenWarnungTemperatur.state == NULL) {
    fensterOffenWarnungTemperatur.postUpdate(15)
    logInfo(‚rules‘, logPrefix + ‚Setze Default-Wert für fensterOffenWarnungTemperatur=15‘)
    }
    if (fensterOffenWarnungMinuten.state == NULL) {
    fensterOffenWarnungMinuten.postUpdate(15)
    logInfo(‚rules‘, logPrefix + ‚Setze Default-Wert für fensterOffenWarnungMinuten=15‘)
    }
    // botmeldung nur ab zweiter Meldung

    // Ist Automatik an?
    if (fensterOffenWarnungAnAus.state == ON) {
    // Ist es kalt genug?
    if ((Owm_Home_Current_Temperature_Rule.state as DecimalType).intValue = (fensterOffenWarnungMinuten.state as DecimalType)) {
    meldeText +=i.name.toString() + ‚ seit ‚ + offenInMinuten + ‚ Minuten, ‚
    }
    if (offenInMinuten > (fensterOffenWarnungMinuten.state as DecimalType)) {
    // Nun auch per Telegram warnen – TTS ist in dem Fall bereits erfolgt
    useBot = true
    // Signalschalter_FarbeButton1 = YELLOW
    }
    ]
    if (meldeText != “) {
    // Besser les- und hörbar machen
    meldeText = ‚Achtung – es sind Fenster seit einiger Zeit komplett offen: ‚ + meldeText.replaceAll(‚KG_‘,’Kellergeschoß_‘).replaceAll(‚EG_‘,’Erdgeschoß ‚).replaceAll(‚OG_‘,’Obergeschoß ‚).replaceAll(‚DG_‘,’Dachgeschoß ‚).replaceAll(‚_‘,‘ ‚) + ‚ bitte schließen!‘

    if (log) logInfo(‚rules‘, logPrefix + ‚Meldung über offene Fenster wird erfolgen…‘)
    // Text per Telegram und Alexa rausschicken…
    //ALEXA_EG_WOHNEN_TTS.sendCommand(meldeText)
    if (useBot) {
    telegramAction.sendTelegram(meldeText)

    }
    }

    } else {
    if (log) logInfo(‚rules‘, logPrefix + ‚Es ist nicht kalt genug. Temperatur ist ‚ + Owm_Home_Current_Temperature.state.toString() + ‚ Schwellwert: ‚ + fensterOffenWarnungTemperatur.state.toString())
    }
    }
    end

  7. Hallo Florian,

    ich habe den Fehler bei mir gefunden. Lag an der Persistence – Datei. Mit mapd, wie in deiner Fassung,funktioniert es jetzt.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

Durch die weitere Nutzung der Seite wird der Verwendung von Cookies und den Inhalten der Datenschutzerklärung zugestimmt. Weitere Informationen

Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklärst du sich damit einverstanden.

Schließen