Wie oft passiert dir das? Du lüftest, vergisst aber nachher doch wieder das Fenster zu schließen. Der Raum ist Kalt. Vielleicht ist die Heizung dabei die ganze Zeit gelaufen. Das muss nicht sein.
Hardware: Fenstersensoren
Ich verwende die ZigBee-Tür- und Fenstersensoren von Sonoff, da sie sehr günstig sind. Mein Erster hat in 8 Monaten knappe 20% Batteriekapazität verbraucht. Entsprechend rechne ich also mit Laufzeiten von 3 Jahren bis zum Wechsel. Das scheint mir annehmbar.
Darüber hinaus lassen sich die Sensoren an anderer Stelle auch in ein OpenHAB-basiertes Alarm-System einbinden.
Vielleicht entscheidest du dich aber auch für drahtgebundene Sensoren. Einige der nachfolgenden Punkte wirst du vielleicht anpassen müssen. Dennoch dienen sie dir als Blaupause.
Die Fenstersensoren habe ich mit Zigbee2MQTT angebunden.
OpenHAB: Things
Entsprechend meinem Schema werden die Sensoren mit dem MQTT-Bindung angesprochen.
Thing mqtt:topic:myMosquitto:WindowSensor_OfficeAlex "Fenster Alex" (mqtt:broker:myMosquitto) @ "Büro Alex" {
Channels:
Type contact : contact [ stateTopic="+/+/+/+/doorWindowSensor/+/+/0x00124b002513eb6a" , transformationPattern="REGEX:(.*contact.*)∩JSONPATH:$.contact", on="false", off="true" ]
Type number : battery [ stateTopic="+/+/+/+/doorWindowSensor/+/+/0x00124b002513eb6a" , transformationPattern="REGEX:(.*battery[^_].*)∩JSONPATH:$.battery" ]
}
OpenHAB: Items
Entsprechend einem semantischen Schema definiere ich die Items. Mit dem semantischen Schema kann die Rule gleich sehr generisch ausfallen und so eine Erweiterung des Systems schnell erfolgen.
Ich gehe davon aus, dass alle Items zu einer Item-Group zusammengefasst werden. Eine Item-Group (ig*) entspricht immer einem realen Gegenstand.
Diese Item-Groups werden dann einem Raum (semantic Group: sg*) zugeordnet. Diesen semantischen Aufbau beschreibe ich im Kontext mit Heizregeln nochmal genauer.
Die Batterie wird aufgrund der semantischen Definition automatisch überwacht.
Group:Number:COUNT(OPEN) igWindowSensor_OfficeAlex "Fenster Büro Alex [%s]" <Window> (sgOfficeAlex)["Window"]
Contact WindowSensor_OfficeAlex_contact "Kontakt [%s]" (fgPersist,igWindowSensor_OfficeAlex,fgIntrusion,tgWindow)["OpenState","Opening"] { channel="mqtt:topic:myMosquitto:WindowSensor_OfficeAlex:contact" }
Number:Dimensionless WindowSensor_OfficeAlex_battery "Batterie [%.1f %%]" <Battery> (igWindowSensor_OfficeAlex)["Battery","Measurement","Energy"] { channel="mqtt:topic:myMosquitto:WindowSensor_OfficeAlex:battery" }
OpenHAB: Rules
Im Folgenden wird eine Warnung generiert, wenn ein Fenster oder Tür mindestens 30min lang offen steht. Außerdem wird die Warnung wiederholt. Allerdings nur, wenn es draußen zu warm oder zu kalt ist, damit sich das lohnt. Die Wiederholung findet statt, indem der Fensterstatus kurz auf geschlossen, dann wieder auf offen gesetzt wird.
Falls du kein Item hast, welches die Außentemperatur enthält, kannst du diese Zeilen auch streichen. Ich verwende die Daten eines Wetter-Bindings.
Vergiss nicht, deinen Telegram-Bot dafür zu konfigurieren.
import java.util.Map
import org.openhab.core.model.script.ScriptServiceUtil
var Map<String, Timer> timers = newHashMap
rule "Fenster/Tür zu lange offen"
when
Member of tgWindow changed to OPEN
then {
if(!timers.containsKey(triggeringItem.name)){
timers.put(triggeringItem.name, createTimer(now.plusMinutes(30), [ |
if(triggeringItem.state == OPEN){
//detect itemGroup (ig) of the item
val String igName = triggeringItem.getGroupNames.findFirst[ String groupName | groupName.startsWith("ig") ]
val GroupItem igItem = ScriptServiceUtil.getItemRegistry.getItem(igName) as GroupItem
//detect semanticGroup of the itemGroup
val String sgName = igItem.getGroupNames.findFirst[ String groupName | groupName.startsWith("sg") ]
val roomItem = ScriptServiceUtil.getItemRegistry.getItem(sgName) as GroupItem
//val NumberItem temperatureItem = roomItem.allMembers.findFirst[ item | item.hasTag("Measurement") && item.hasTag("Temperature") ]
//val float temperature = (temperatureItem.state as Number).floatValue
//Environment
val float temperatureEnvironment = (OpenWeatherMapWetterinformationen_Current_Aussentemperatur.state as Number).floatValue()
if(
(temperatureEnvironment < 18) //draussen ist es zu kalt
|| (temperatureEnvironment > 25) //draussen ist es zu warm
){
getActions("telegram","telegram:telegramBot:home_Bot").sendTelegram(-000000000L,"noch offen: %s in %s", igItem.label, roomItem.label)
}
timers.get(triggeringItem.name).reschedule(now.plusMinutes(30))
}
]))
}
else {
timers.get(triggeringItem.name).reschedule(now.plusMinutes(30))
}
}
end