Startseite » Alarmanlage und Anwesenheitssimulator mit OpenHAB

Alarmanlage und Anwesenheitssimulator mit OpenHAB

Es gibt verschiedene Gründe, eine Alarmanlage realisieren zu wollen. Und viele Aspekte, die daran beteiligt sind. Das nachfolgende Beispiel funktioniert gut bei mir. Natürlich kannst du es leicht erweitern und auf deine Bedürfnisse anpassen.

Das nachfolgende System hat zwei Aufgaben:

  1. Einen Alarm zu verursachen, wenn ein Eindringen entdeckt wurde
  2. Anwesenheit vorzutäuschen

Ein Alarm kann auf verschiedene Wege verursacht werden. Er kann optisch oder akustisch sein oder still. Darüber hinaus kann ein Signal versandt werden.

„Wenn ein Eindringen entdeckt wurde“ kann auch vielfältige Auslöser haben. Das kann ein aufgebrochenes oder eingeschlagenes Fenster oder Tür sein, das kann auch eine Person sein, die sich an einem Ort aufhält, wo niemand sein sollte (z.B. in deinem Garten während deiner Abwesenheit). Das können auch Geräusche sein, die nicht da sein sollten (zerbrechendes Glas oder Schritte).

Auch Anwesenheit kann auf verschiedene Wege vorgetäuscht werden. Geräusche, Licht, vielleicht bestimmte dynamische Lichtszenen, ein Gartensprinkler, abgeholte Post, sich bewegende Rollos, …

Letztlich muss des System noch gegen Ausfall und Sabotage gesichert werden. Was passiert bei ausfallenden Geräten? Was passiert, wenn notwendige Funkübertragungen nicht mehr verfügbar sind (z.B. weil sie gestört werden).

Dieses Kapitel wird mehrere Projekte wiederverwenden, die ich bereits an anderer Stelle umgesetzt habe. Und sich im laufe der Zeit sicherlich noch erweitern und verbessern.

Hardware für eine Alarmanlage

  • dein Raspberry Pi mit bereits funktionierendem OpenHAB
  • mögliche Sensoren (kabelgefunden oder per Funk)
    • Tür- / Fensterkontakte
    • Glasbruchsensoren
    • Bewegungsmelder (nur für drinnen zu empfehlen. draußen kann sich immer mal was bewegen)
    • Anwesenheitssensoren
    • Kameras (ggf. mit Objekterkennung)
  • Beleuchtung
    • smarte Leuchtmittel, die vielleicht schon in deinem Smarthome vorhanden sind
  • Akustik
    • smarte Lautsprecher (zur Alarm-Ausgabe und ggf. zur Geräuscherkennung)
  • Ausfallsicherheit
    • eine kleine USV, nur für den Pi
    • einen LTE-USB-Stick als Ausfall-Leitung für Alarm-Benachrichtigungen
      • auch hier sind Konstruktionen möglich, die einen Single-Point-of-Failure ausschließen

OpenHAB: Vorbereitungen

Deine Hardware musst du entsprechend deinen Bedrüfnissen nun in dein OpenHAB einbinden. Mein Beispiel geht davon aus, dass du smarte Leuchtmittel verwendet und dass du im besten Fall dynamische Szenen abspielen kannst. Mit den dynamischen Szenen täusche ich eine Aktivität des Fernsehers vor.

Alle Items müssen vorhanden sein. Inbesondere gehe ich davon aus, dass du

Wichtige Items und Gruppen der Alarmanlage

  • gWatchdog
    • Damit fasse ich den manuellen Modus, sowie den nächtlichen automatischen Modus zusammen. Ist einer der Beiden aktiv, ist das Alarmsystem aktiv. So können Beide zuverlässig funktionieren, ohne sich gegenseitig zu beeinflussen.
    • WatchdogManual
      • Dieses Item kannst du mittels OpenHAB GUI (oder in diesem Fall auch mittels Alexa) ein- und ausschalten. Es ist nur dafür gedacht, manuell betätigt zu werden.
      • Dieses Item wird weiter unten nicht weiter beschrieben und muss von dir auf deine Bedürfnisse eingerichtet werden!
    • WatchdogNightshift
      • Dieser Modus soll nächtlich laufen. Von dem Zeitpunkt, wo ich ins Bett gehe, bis ich aufstehe. Automatisch wird es nachts zu einem bestimmten Zeitpunkt aktiviert und später wieder deaktiviert. Das kann mittels Kalender geschehen, aber auch mittels eigenem .rules-File. In meinem Fall aktiviere ich es zusätzlich manuell. Wenn ich meinen „Haus-Aus-Knopf“ am Bettrand betätige, wird die Alarmanlage scharf. Später in der Nacht würde sie automatisch aktiviert. Das Ereignis schaltet einen Schalter von „ON“ dann nur nochmal auf „ON“.
      • Dieses Item wird weiter unten nicht weiter beschrieben und muss von dir auf deine Bedürfnisse eingerichtet werden!
    • Weitere unabhängige Modi sind denkbar. Teile als Kommentar doch bitte deine Vorschläge mit mir 😉
  • WatchdogTimestamp
    • Hier wird der Zeitpunkt der Aktivierung des WatchdogManual gespeichert. Damit kann die Alarmanlage leicht verzögert aktiviert werden. Wenn ich sie also EInschalte, habe ich noch ein paar Minuten Zeit das Haus zu verlassen. Das wird im watchdog.rules-File weiter unten berücksichtigt.
  • TestDummy
    • Dieser aktiviert einen Test-Modus, um die Routinen zu testen. Regelmäßige Alarmanlagentest sind wichtig!

Group:Switch:OR(ON, OFF)	gWatchdog				
Switch						WatchdogManual			"Watchdog"	(fgPersist,gWatchdog,tgWatchdogEvents)		{ alexa="Switch" }
Switch						WatchdogNightshift					(fgPersist,gWatchdog)
DateTime					WatchdogTimestamp

Switch						TestDummy

OpenHAB: Rules

Die nachfolgende watchdog.rules muss in jedem Fall auf deine Bedürfnisse angepasst werden und kann nicht einfach kopiert werden.

Folgende Situationen werden dabei betrachtet:

Leuchtsimulation

  • rule „Watchdog Leuchtsimulation
    • Für jeden Raum werden Timer gesetzt, die Anwesenheit simulieren. Dabei lässt sich möglichst nicht mehr unterscheiden, ob dies eine Simulation ist, oder ob tatsächlich jemand anwesend ist. Verschiedene Räume werden unterschiedlich behandelt.
    • Auf die Verwendung von semantischen Gruppen habe ich hier verzichtet, da die Funktionen ohnehin konkret auf deine Bedürfnisse angepasst werden müssen!

import java.util.Map
import java.util.List
import org.openhab.core.model.script.ScriptServiceUtil

var Map<String, Timer> timers = newHashMap

rule "Watchdog Leuchtsimulation"
when
	Item WatchdogManual changed to ON
	or Time cron "0 0 6 ? * * *" 
then {
	if(WatchdogManual.state == ON){
		//Optische Bestätigung: Watchdog ist an!
		Everywhere_Interface.sendCommand('{"effect": "blink"}')
	
	
		val java.util.Random rand = new java.util.Random()
		var sunset = (LokaleSonnendaten_Set_Startzeit.state as DateTimeType).getZonedDateTime()
		var randMinutes = 0
		
		//if(sunset.isBefore( now )){ sunset = now; }

		//Büro Alex
		//von (Dunkel) bis (23:00 - 01:00) : Licht
		timers.put('begin_BueroAlex',createTimer(sunset, [ |
			logInfo("Watchdog", "Büro Alex: An")
			BueroAlex_Helligkeit.sendCommand(100)
			
			val endMinutes = 23*60 + rand.nextInt(120)
			timers.put('end_BueroAlex',createTimer(now.truncatedTo(java.time.temporal.ChronoUnit.DAYS).plusMinutes(endMinutes), [ |
				logInfo("Watchdog", "Büro Alex: Aus")
				BueroAlex_Helligkeit.sendCommand(0)
			]))
		]))
		
		//Küche
		//	von (Dunkel + (30 - 180min)) bis (45 - 90min lang) : Licht + Ton
		randMinutes = 30 + rand.nextInt(150)
		timers.put('begin_Kueche',createTimer(sunset.plusMinutes(randMinutes), [ |
			logInfo("Watchdog", "Küche: An")
			//TODO: Licht
			
			val endMinutes = 45 + rand.nextInt(45)
			timers.put('end_Kueche',createTimer(now.plusMinutes(endMinutes), [ |
				logInfo("Watchdog", "Küche: Aus")
				//TODO: Licht aus
			]))
		]))

		//Wohnzimmer
		//	von (Dunkel + (30 - 90min)) bis (22:30 - 00:30) : TV-Simulation + Ton
		randMinutes = 30 + rand.nextInt(60)
		timers.put('begin_Wohnzimmer',createTimer(sunset.plusMinutes(randMinutes), [ |
			//Licht
			logInfo("Watchdog", "Wohnzimmer Tisch: An")
			WzTisch_Helligkeit.sendCommand(100)
			
			logInfo("Watchdog", "Wohnzimmer Couch: TV-Simulation")
			WzCouch_Lightshow.sendCommand("TV-Simulation") //TV-Simluation
			
			//Ton
			logInfo("Watchdog", "Wohnzimmer Echo: Musik")
			Echo_Wohnzimmer_TextCommand.sendCommand("echo spiele Robin Schulz")
			
			val endMinutes = 22*60 + 30 + rand.nextInt(120)
			timers.put('end_Wohnzimmer',createTimer(now.truncatedTo(java.time.temporal.ChronoUnit.DAYS).plusMinutes(endMinutes), [ |
				//TODO: Licht und Ton aus
				logInfo("Watchdog", "Wohnzimmer (Tisch, Couch, Echo): Aus")
				WzTisch_Helligkeit.sendCommand(0)
				WzCouch_Helligkeit.sendCommand(0) //TV-Simluation
				Echo_Wohnzimmer_TextCommand.sendCommand("echo stop")
			]))
		]))

		//Schlafzimmer
		//	von (21:00 - 23:30) bis (23:35 - 00:30) : Licht
		randMinutes = 21*60 + rand.nextInt(150)
		timers.put('begin_Schlafzimmer',createTimer(now.truncatedTo(java.time.temporal.ChronoUnit.DAYS).plusMinutes(randMinutes), [ |
			//Licht
			logInfo("Watchdog", "Schlafzimmer : An")
			SchlafzimmerRoom_Helligkeit.sendCommand(100)
			
			val endMinutes = 5 + rand.nextInt(60)
			timers.put('end_Schlafzimmer',createTimer(now.plusMinutes(endMinutes), [ |
				//Licht aus
				logInfo("Watchdog", "Schlafzimmer : Aus")
				SchlafzimmerRoom_Helligkeit.sendCommand(0)
			]))
		]))
		
		
		//Musiksimulation
		//createTimer(now, [ |
		//	Echo_BueroAlex_TextCommand.sendCommand("echo spiele Robin Schulz")
		//	while(gWatchdog.state == ON){
		//		Thread::sleep(500)
		//	}
		//	Echo_BueroAlex_TextCommand.sendCommand("echo stop")
		//])
	}
}
end

Steuermechanismen der Alarmanlage

  • rule „Watchdog changed Timestamp
    • Hier wird lediglich die Aktivierungszeit der Alarmanlage gespeichert, um Alarme nicht in den ersten 5min auszulösen. Z.B. wenn du die Alarmanlage aktivierst und dann noch das Haus verlassen willst.
//Verzögerung, bis Alarm tatsächlich scharf: 5min
rule "Watchdog changed Timestamp"
when
	Item gWatchdog changed to ON
then {
	WatchdogTimestamp.postUpdate(new DateTimeType)
}
end

  • rule „Fault and disturbance detection
    • Ich habe Zigbee-Steckdosen dauerhaft in Betrieb, einfach nur um Störungen auf der 2,4GHz-Frequenz zu erkennen. Es wäre möglich, dass ein Angreifer versucht, dein Netz zu stören um Alarmkomponenten außer Betrieb zu setzen. Wenn diese dauerhaft plappernden Steckdosen sich nicht mehr melden, kann ein Problem vermutet werden. Dann fragt die Regel nach. Kommt dann immer noch keine Antwort, wird Alarm ausgelöst. Oder eine Wartungsmeldung versandt, wenn der Alarmmodus gerade inaktiv ist. Ich habe die hier hier angegebenen Zeiten sogar noch weiter verkürzt.
    • Vergiss nicht, deinen Telegram-Bot dafür zu konfigurieren.
rule "Fault and disturbance detection"
when
	Time cron "0 * * ? * * *" 
then {
	//if 5min nothing received: ask
	if(now.minusMinutes(5).isAfter((fgFaultDetection.state as DateTimeType).getZonedDateTime())){
		val GenericItem faultItem = fgFaultDetection.members.findFirst [ GenericItem i | now.minusMinutes(5).isAfter((i.state as DateTimeType).getZonedDateTime()) ]
		val String faultIGName = faultItem.getGroupNames.findFirst[ String groupName | groupName.startsWith("ig") ]
		val GroupItem faultIG = ScriptServiceUtil.getItemRegistry.getItem(faultIGName) as GroupItem
		val SwitchItem switchItem = faultIG.members.findFirst[ a | a.tags.contains("Switch") && a.tags.contains("Power")]
		switchItem.sendCommand(switchItem.state)
	}
	
	//if 8min nothing received: alert
	if(now.minusMinutes(8).isAfter((fgFaultDetection.state as DateTimeType).getZonedDateTime())){
		val GenericItem faultItem = fgFaultDetection.members.findFirst [ GenericItem i | now.minusMinutes(8).isAfter((i.state as DateTimeType).getZonedDateTime()) ]
		//TODO: WatchdogDummyAlertContact.sendCommand(ON)
		if(gWatchdog.state != ON){
			getActions("telegram","telegram:telegramBot:home_Bot").sendTelegram(-000000000L,
				"Wartung nötig: %s hat sich länger als 8min nicht gemeldet!",
				faultItem.name
			)
		}
	}
}
end	

  • rule „End Watchdog Alarm
    • Wenn ein Alarm beendet wird, passieren zwei Dinge: ein laufender Alarm muss abgebrochen werden und ein regulärer Aktiv-Status wird inaktiv.
//To end an Alarm, but also just to end the Night
rule "End Watchdog Alarm"
when
	Item gWatchdog changed to OFF
then {
	if(Everywhere_Lightshow.state.toString == "Alarm"){
		Everywhere_Farbtemperatur.sendCommand(67)
	}
	
	//Everywhere_Helligkeit.sendCommand(0)
	gAlexa_PlayAlarmSound.members.forEach[ StringItem item |
		item.sendCommand('') //...PlayAlarmSound wird mit '' unterbrochen
	]
	gAlexa_Volume.members.forEach[ DimmerItem item |
		item.sendCommand(20)
	]
	
	timers.keySet().forEach[String key |
		if(key.startsWith("begin")){
			timers.get(key).cancel()
		}
		if(key.startsWith("end")){
			timers.get(key).reschedule(now)
		}
	]
}
end

  • rule „Test Alarm start“ / rule „Test Alarm end
    • Zwei Regeln um verschiedene Tests durchzuführen
rule "Test Alarm start"
when
	Item TestDummy changed to ON
then {
	//Everywhere_Lightshow.sendCommand("Alarm")
	BueroAlex_Lightshow.sendCommand("Alarm")
}
end	

rule "Test Alarm end"
when
	Item TestDummy changed to OFF
then {
	//if(Everywhere_Lightshow.state.toString == "Alarm"){
	//	Everywhere_Farbtemperatur.sendCommand(67)
	//}
	if(BueroAlex_Lightshow.state.toString == "Alarm"){
		BueroAlex_Farbtemperatur.sendCommand(67)
	}
}
end

  • rule „Smart Button – Start Nightshift
    • Drücke ich den „Haus-Aus-Knopf“, wird auch der nächtliche Alarm aktiviert.
rule "Smart Button - Start Nightshift"
when
	//Channel "mqtt:topic:99a3e7ba:SmartButton1:action" triggered
	Item SmartButton1_DimmerSwitch changed
then {
	if(
		KalenderWecken_CurrentEventPresence.state == OFF
		|| SmartButton1_DimmerSwitch == NULL
	){
		WatchdogNightshift.sendCommand(ON)
	}
}
end

  • rule „End Nightshift
    • Schalte zu einem bestimmten Zeitpunkt automatisch

rule "End Nightshift"
when
	Item KalenderWatchdog_CurrentEventPresence changed to OFF
then {
	WatchdogNightshift.sendCommand(OFF)
}
end

Alarme

  • rule „Watchdog Alarm
    • Bei welchen Auslösern soll reagiert werden?
    • Betrachte dabei, dass in den ersten 5min nach Scharfschaltung kein Alarm ausgelöst werden soll.
    • Schalte alle Lichter ein und lasse sie rot blinken (Everywhere_Lightshow.sendCommand(„Alarm“) mittels dynamischer Szenen)
    • Lass alle SmartSpeaker Alarm schlagen!
    • Versende Meldungen an dich selbst!
    • Gib ggf. eine Alarmmeldung direkt an eine dafür geschaffene Stelle weiter!
rule "Watchdog Alarm"
when
	Item gCamAlert changed
	or Item fgIntrusion changed
then {
	if( gWatchdog.state == ON && now.minusMinutes(5).isAfter((WatchdogTimestamp.state as DateTimeType).getZonedDateTime())){
		
		logInfo("Test", "triggeringItemName: {}", triggeringItemName)
		//Licht-Alarm
		Everywhere_Lightshow.sendCommand("Alarm")
		
		//Alexa-Warnrufe
		createTimer(now, [ |
			gAlexa_PlayAlarmSound.members.forEach[ StringItem item |
				item.sendCommand('ECHO:system_alerts_rhythmic_02')
			]
			
			Thread::sleep(10000)
			
			gAlexa_PlayAlarmSound.members.forEach[ StringItem item |
				item.sendCommand('')
			]
			
			if(gWatchdog.state == ON){
				gAlexa_Volume.members.forEach[ DimmerItem item |
					item.sendCommand(80)
				]
				gAlexa_TTS.members.forEach[ StringItem item |
					item.sendCommand("Eindringling entdeckt! Notruf wurde abgesetzt. Polizei ist unterwegs.")
				]
			
				Thread::sleep(4000)
			}
			
			if(gWatchdog.state == ON){
				gAlexa_PlayAlarmSound.members.forEach[ StringItem item |
					item.sendCommand('ECHO:system_alerts_rhythmic_02')
				]
			}
		])
		
		//Telegram-Meldungen
		fgIntrusion.members.forEach[ GenericItem item |
			if(item.state == OFF){
				var groupLabels = ""
				item.groupNames.forEach[ String groupName |
					var groupLabel = ScriptServiceUtil.getItemRegistry.getItem(groupName).label
					groupLabels = groupLabels + " " + groupLabel
				]
				getActions("telegram","telegram:telegramBot:home_Bot").sendTelegram(-000000000L,
					"Eindringling-Alarm wurde ausgelöst!: %s - %s",
					groupLabels,
					item.label
				)
			}
		]
	}
}
end

  • rule „Send telegram on object sighted (Vordertuer)“ / rule „Send telegram on object sighted (Hintertuer)
    • Regeln um Meldungen an mich zu versenden, wenn eine Person auf einer Kamera entdeckt wurde
    • Wenn eine Person in deiner Abwesenheit an deiner Hintertür ist, kann das ein unbefugtes Eindringen sein. Eine Person an der Vordertür hingegen kann normaler Verhalten sein (Postbote)
      • Bei der Verwendung von Kameras auch im eigenen Bereich sind immer rechtliche Richtlinien zu betrachten!
// --- TensorPi ---
rule "Send telegram on object sighted (Vordertuer)"
when
	Item Tensorpi_Vordertuer_time changed
then
	getActions("telegram","telegram:telegramBot:home_Bot").sendTelegramPhoto(-000000000L,
		Tensorpi_Vordertuer_last_img.state.toString,
		Tensorpi_Vordertuer_object.state.toString)
end

// --- TensorPi2 ---
rule "Send telegram on object sighted (Hintertuer)"
when
	Item Tensorpi_Hintertuer_time changed
then
	if(gWatchdog.state == ON){
		getActions("telegram","telegram:telegramBot:home_Bot").sendTelegramPhoto(-000000000L,
			Tensorpi_Hintertuer_last_img.state.toString,
			Tensorpi_Hintertuer_object.state.toString)
	}
end

Kommentar verfassen

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

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..

Translate »