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.
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?
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?
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
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
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
Hallo, bin noch nicht auf die 3er Version umgestiegen, daher muss ich hier auf später vertrösten…
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
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 🙂
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
Hallo Florian,
ich habe den Fehler bei mir gefunden. Lag an der Persistence – Datei. Mit mapd, wie in deiner Fassung,funktioniert es jetzt.