[How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Antworten
int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

[How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von int5749 »

Hallo zusammen,

Intro: Meine OH 3 Umgebung läuft auf einem Windows 10 Rechner, da ich kein Linuxer bin :)

scheinbar gab es im vergangenen Jahr dann noch einmal Interesse an der von mir genutzten und mit Hilfe dieses und des KNX-USER-FORUM (und einen besonderen Dank an Udi1Toni) entwickelten Anwesendheitssimulation. Daher möchte ich dies hier noch einmal in Summe vorstellen. Ziel sollte es sein, eine möglichst automatische (smarte) Steuerung zu erreichen und bisher läuft dies bei uns seit mittlerweile fast 3 Jahren ohne Probleme und seit einigen Tagen nun auch unter openHAB 3

Zur Präsenzerkennung nutze ich das TR-064 Binding für die Fritzbox. Die Zeit - bis eine Statusänderung erkannt wird - liegt bei wenigen Minuten, was aber für mich völlig akzeptabel ist. Da das WLAN bis auf die Strasse reicht, werden wir bereits bei Annäherung an das Haus erkannt und die Simulation meist mit betreten des Hausflurs beendet.

iOS Info: Mittlerweile gibt es in iOS eine Hardware und eine private MAC pro WLAN, welche aber dann auch immer gleich ist. Damit die Geräte immer erkannt werden, wurden beide MACs im TR-064 Binding bekannt gegeben und ich prüfe auf eine Gruppe.

Anwesendheitssimulation: Diese sollte - gerade bei einem Urlaub - möglichst nah am eigenen Verhalten sein. Daher habe ich mich für einen Zustand 7 Tage in der Vergangenheit entschieden. Zum einen ist dann immer der gleiche Wochentag (es wird somit nicht am Montag das Verhalten vom Sonntag reproduziert) und die Verschiebung der Helligkeit ist auch im Rahmen. Damit es sich nicht in der 2. Woche 100% wiederholt, habe ich beim schalten eine kleine, willkürliche Verzögerung eingebaut. Dies alles wird bei mir über JDBC in einer SQLite DB gespeichert. Das anlegen der DB habe ich mit der kostenlosen App "DB Browser für SQLite" erstellt. Dies muss "nur" installiert werden und im Anschluß kann darüber eine neue DB erstellt werden. Dazu browsed (neu-Deutsch) man einfach in des Ziel-Verzeichnis, gibt einen DB Namen an und fertig. Im nächsten Schritt benötigt JDBC einmalig den Pfad zu dieser Datenbank, welcher über die BasicUI konfiguriert wird. Im Anschluß kümmert sich openHAB (zum Glück) automatisch um das anlegen der Struktur und füllen der DB 8-)
Last but not least sollte möglichst alles lokal (ohne externe Cloud) laufen :!: :!:

Achtung: Ich gehe hier nicht auf die Konfiguration der einzelnen Bridges/Things ein und bei den Items müssen die eigenen Channel noch ergänzt werden

PS: Wer Schreibfehler findet, der darf diese als Geschenk behalten :D

Items
In der Gruppe gLights_auto sind natürlich nur die Items, welche bei einer Simulation geschaltet werden sollen.

Code: Alles auswählen

Group:Switch:OR(ON, OFF) sFboxDadiPhoneOnline		"Dad iPhone [MAP(presence.map):%s]"		<man_3>		(GhostMode, Parents)
Group:Switch:OR(ON, OFF) sFboxMumiPhoneOnline		"Mum iPhone [MAP(presence.map):%s]"		<woman_2>	(GhostMode, Parents)
Group:Switch:OR(ON, OFF) sFboxChild1iPhoneOnline	"Child1 iPhone [MAP(presence.map):%s]"	<girl_2>	(GhostMode)
Group:Switch:OR(ON, OFF) sFboxChild2iPhoneOnline	"Child2 iPhone [MAP(presence.map):%s]"	<girl_2>	(GhostMode)
Group:Switch:OR(ON, OFF)		Parents		"Eltern [(%d)]"			<present>	(All)
Group:Switch:NOR(ON, OFF)		GhostMode	"Family [(%d)]"			<present>	(All)

Group				gLights_auto
Group 				gNetDevices

Switch Absence			"Anwesendheitssimulation"	<vacation>
Switch Night								            	{channel="knx:device:bridge:THEBEN_Lichtsensor"}

	// Close House Switch
Switch myCloseItSwitchVis
Switch myCloseItSwitch			{autoupdate="false"}

	// Sun Protection
Switch ManSunProtection			"manuelle Beschattung"
Switch SunProtection			"Sonnenschutzautomatik"			{channel="knx:device:bridge:GiraTS2:swc1"}  // zusätzlich kann die Beschattung auch im Wohnzimmer geschaltet werden
Switch mySunProtectionVis

	// Dad iOS
Switch sFboxDadiPhonePhysic		    "Dad iPhone Physic [MAP(presence.map):%s]"  	<man_3>	(sFboxDadiPhoneOnline)	{ channel="tr064:....."}
Switch sFboxDadiPhonePrivate		"Dad iPhone Private [MAP(presence.map):%s]"	    <man_3>	(sFboxDadiPhoneOnline)	{ channel="tr064:....."}

	// Mum iOS
Switch sFboxMumiPhonePhysic		    "Mum iPhone Physic [MAP(presence.map):%s]"	    <woman_2>	(sFboxMumiPhoneOnline)	{ channel="tr064:....."}
Switch sFboxMumiPhonePrivate		"Mum iPhone Private [MAP(presence.map):%s]"	    <woman_2>	(sFboxMumiPhoneOnline)	{ channel="tr064:....."}

	// Child1 iOS
Switch sFboxChild1iPhonePhysic		"Child1 iPhone Physic [MAP(presence.map):%s]"	<girl_2>	(sFboxChild1iPhoneOnline)	{ channel="tr064:....."}
Switch sFboxChild1iPhonePrivate     "Child1 iPhone Private [MAP(presence.map):%s]"	<girl_2>	(sFboxChild1iPhoneOnline)	{ channel="tr064:....."}

	// Child2 iOS
Switch sFboxChild2iPhonePhysic		"Child2 iPhone Physic [MAP(presence.map):%s]"	<girl_2>	(sFboxChild2iPhoneOnline)	{ channel="tr064:....."}

Switch Lampe_OG_Schlafz_Decke		"Schlafzimmerdecke"	<light>			(gLights_auto, OG_Schlaf, Lampen)	{channel="knx:...."}
Switch Lampe_OG_Schlafz_Bett_links	"Nachttisch links"	<poweroutlet>	(gLights_auto, OG_Schlaf, Lampen)	{channel="knx:...."}
Switch Lampe_OG_Schlafz_Bett_rechts	"Nachttisch rechts"	<poweroutlet>	(gLights_auto, OG_Schlaf, Lampen)	{channel="knx:...."}
Verwendete Rules:

Ghostmode

Code: Alles auswählen

rule Ghost
when
	Item GhostMode changed
then
	if (GhostMode.state == OFF) {
		Absence.postUpdate(OFF)                                         // Stoppe Anwesendheitssimulation
	} else if (GhostMode.state == ON) {
		gNetDevices.allMembers.filter(f|(f.state)!==OFF).forEach[ n|    //Schalte alle Netzdevices aus, z.B. Musiccast
			n.sendCommand(OFF)
			logInfo("NetDevice", n.name + " received OFF")
		]
		if (Night.state == ON) {
			Absence.postUpdate(ON)                                      // Starte Anwesendheitssimulation
		}
		if (Night.state == ON && Rollladen.state < 100) {
			Rollladen.members.filter(f|(f.state as DecimalType).intValue!==100).forEach[ s|     //schliesse alle Rollladen, die nicht schon unten sind
			s.sendCommand(DOWN)
			logInfo("Shutter", s.name + " received DOWN")
			]
			Steckd_Zaunwand.sendCommand(OFF)                        // Schalte Licht im Garten aus
		}
	}
end
Zur Beruhigung der Nerven eine Info

Code: Alles auswählen

rule AbsenceMode            // Nachricht über Statusänderung
when
	Item Absence changed
then
	val mailActions = getActions("mail","mail:smtp:xxx")
	if (Absence.state == ON) {
		mailActions.sendMail("xxx@api.prowlapp.com", "Attention", "Anwesenheitssimulation gestartet !!")
	} else if (Absence.state == OFF) {
		mailActions.sendMail("xxx@api.prowlapp.com", "Attention", "Anwesenheitssimulation gestoppt !!")
	}
end
Anwesendheitssimulation

Code: Alles auswählen

rule "Presence Simulator"
when
	Time cron "0 */1 * * * ?"           //prüfe jede Minunte
then
	if (Absence.state == ON) {
		println("-> Presence Simulation")
		gLights_auto.members.filter(f|f.state.toString!==f.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString).forEach[ m|
				Thread::sleep((2000 + Math::random * 1000.0).intValue)      //verschiebe die Zeit etwas, damit es in 7 Tagen nicht wieder exact gleich ist
				m.sendCommand(m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString)
				logInfo("Presence","Restore {} to historic state: {}",m.name, m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state)
		]
	}
end
An die Reglen gekoppelt eine Regel für den Abend

Code: Alles auswählen

rule NightStarts
when
	Item Night changed
then
	if (Night.state == ON  && now.toLocalTime.getHour >= 15) {
       	ManSunProtection.sendCommand(OFF)       // schalte manuelle Beschattung aus
		SunProtection.sendCommand(OFF)          // schalte automatische BEschattung aus
		mySunProtectionVis.postUpdate(ON)       // aktiviere Button in Sitemap

		gShutterOG.members.filter(f|(f.state as DecimalType).intValue!==100).forEach[ s|        //fahre alle Rollladen im OG runter
			s.sendCommand(DOWN)
			logInfo("Shutter", s.name + " received DOWN")
		]

		Lampe_Haustuere.sendCommand(ON)     // schalte Lampe an der Haustüre ein

		if (Parents.state == OFF) {
			gShutterEG.members.filter(f|(f.state as DecimalType).intValue!==100).forEach[ s|    // Wenn Eltern nicht zu Hause sind, fahre auch EG alle Rollladen runter
				s.sendCommand(DOWN)
				logInfo("Shutter", s.name + " received DOWN")
			]
			if (GhostMode.state == OFF) {
				// Ein Kind ist zu Hause, also keine Anwesendheitssimulation notwendig
			} else if (GhostMode.state == ON) {
				Absence.postUpdate(ON)	// Starte Anwesendheitssimulation
			}
		} else if (Parents.state == ON) {
			// Hier fahre ich die Rollladen im EG in einen bestimmten Zustand
            //z.B. bleiben die Rollladen zum Garten offen
			
			// Hier schalte ich dann Deko Lampen im Wohnzimmer
			myCloseItSwitchVis.postUpdate(ON)   // aktiviert einen Button in der Sitemap
			myCloseItSwitch.postUpdate(OFF)     // default wert aktiviert
		}
	} else if (Night.state == OFF) {
        // Nacht ist vorbei, nur vorbereitet
	}
end
Zusätzlich ein wenig Bequemlichkeit

Code: Alles auswählen

rule Sunset_Event_15
when
	Channel 'astro:sun:sunset_15:set#event' triggered START
then
	logInfo("Astro", "Sun set +15")
	if (Parents.state == ON && Rollladen.state < 100) {
        // Eltern zu Hause, Garten Rollladen nicht unten und Sonnenuntergang ist 15 Min vorbei
        // => in der Regel ist es nun dunkel genug = Gartendekolampen schalten ein
	} else if (Rollladen.state == 100) {
		// Eltern nicht ON = nicht da oder undefinierter Zustand und Rollladen alle unten = keine Gartenbeleuchtung notwendig
	} else {
        // vorbereitet
	}
end
Auszug aus der Sitemap

Code: Alles auswählen

sitemap presence label="Anwesendheitssimulation"
{
// ###################################################################################
	Frame {
		Switch item=myCloseItSwitch label="Aussen" icon="stophand" visibility=[myCloseItSwitchVis=="ON"] mappings=[ON="Rollladen schliessen!"]
		Text label="Haus Status" icon="shield" {
			Group item=Comfort icon="settings" label="Komfortfunktionen"{
				Switch item=Absence mappings=[OFF="Aus", ON="Ein"]
				Switch item=SunProtection icon="sun" mappings=[OFF="Aus", ON="Ein"]
			}
			Switch item=ManSunProtection visibility=[mySunProtectionVis=="OFF"] 
			Group item=GhostMode icon="users"
		}
	}
// ###################################################################################
}
Ich hoffe ich habe nicht ein Item oder Thing vergessen ;)

Für weitere Tipps und Anregungen freue ich mich auf die Antworten.

Viele Grüße und für die, welche es nutzen möchten => viel Spaß beim Nachbau
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

Chaosmax
Beiträge: 16
Registriert: 29. Dez 2020 12:29

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von Chaosmax »

danke für die Rule zur Anwesendheitssimulation. Hatte ich noch auf meiner ToDo aber keine Idee wie das umzusetzen ist.
Schon erstaunlich, dass das auf so wenige Zeilen zu reduzieren ist. Ich hätte mir einen "Wolf" geschrieben.
Jetzt bis übermorgen warten und schauen, ob es bei mir auch funktioniert.

eiGelbGeek
Beiträge: 226
Registriert: 11. Aug 2019 06:39
Answers: 4

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von eiGelbGeek »

int5749 hat geschrieben: 22. Jan 2021 09:09
Anwesendheitssimulation

Code: Alles auswählen

rule "Presence Simulator"
when
	Time cron "0 */1 * * * ?"           //prüfe jede Minunte
then
	if (Absence.state == ON) {
		println("-> Presence Simulation")
		gLights_auto.members.filter(f|f.state.toString!==f.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString).forEach[ m|
				Thread::sleep((2000 + Math::random * 1000.0).intValue)      //verschiebe die Zeit etwas, damit es in 7 Tagen nicht wieder exact gleich ist
				m.sendCommand(m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString)
				logInfo("Presence","Restore {} to historic state: {}",m.name, m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state)
		]
	}
end
Das ist ziemlich cool und elegant, wenn man den Code verstanden hat :D einzig den Thread::sleep würde ich noch durch einen Timer ersetzen.

Müsste dann so aussehen (ungetestet)

Code: Alles auswählen

rule "Presence Simulator"
when
	Time cron "0 */1 * * * ?"           //prüfe jede Minunte
then
	if (Absence.state == ON) {
		println("-> Presence Simulation")
		gLights_auto.members.filter(f|f.state.toString!==f.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString).forEach[ m|
				//verschiebe die Zeit etwas, damit es in 7 Tagen nicht wieder exact gleich ist
				createTimer(now.plusMillis((2000 + Math::random * 1000.0).intValue), [|
					m.sendCommand(m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString)
					logInfo("Presence","Restore {} to historic state: {}",m.name, m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state)])
		]
	}
end

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von int5749 »

eiGelbGeek hat geschrieben: 27. Feb 2021 12:29 Das ist ziemlich cool und elegant, wenn man den Code verstanden hat :D
Ja, ich nutze dies mittlerweile in einiges Rules und Danke @udo1toni noch immer dafür :)
eiGelbGeek hat geschrieben: 27. Feb 2021 12:29 einzig den Thread::sleep würde ich noch durch einen Timer ersetzen.
Ich meine, es gabe da "Probleme" wenn zu viele Timer laufen, was in dem Umfeld wohl eher selten passiert, und bisher war ich mit einer Pause gut gefahren 8-)
Warum würdest Du einen Timer bevorzugen?
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

eiGelbGeek
Beiträge: 226
Registriert: 11. Aug 2019 06:39
Answers: 4

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von eiGelbGeek »

int5749 hat geschrieben: 27. Feb 2021 14:44 Warum würdest Du einen Timer bevorzugen?
https://community.openhab.org/t/thread- ... _gelb_geek

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von int5749 »

Aber genau dort steht doch

Code: Alles auswählen

I will use Thread::sleep

    The amount of time I want to wait is short (seconds)
    I want to execute some code after the sleep (i.e. I’m waiting for something to happen such as Persistence catching up before executing the rest of a rule’s logic)
    I have no plans to change what I do or set another Thread::sleep should the state not be just right after the sleep

I will use a Timer

    The amount of time I want to wait is relatively long (minutes)
    I may want to cancel or reschedule the code based on subsequent events
    I have additional stuff I want to do in a rule after the timer is created that doesn’t need to wait for the timer code to execute
Somit ist aus meiner Sicht Thread::sleep die richtige Wahl, da ich nur ganz wenige Sekunden verschiebe und somit dann sogar automatisch die folgenden.
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

Benutzeravatar
sihui
Beiträge: 1827
Registriert: 11. Apr 2018 19:03
Answers: 21

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von sihui »

int5749 hat geschrieben: 28. Feb 2021 21:27 Somit ist aus meiner Sicht Thread::sleep die richtige Wahl
Thread::sleep hält den Thread, von dem nur eine Handvoll zur Verfügung stehen, für den genannten Zeitraum an. Thread:sleep sollte nur im Millisekunden Bereich genutzt werden, niemals mit höheren Werten.
Wenn du dir mal im events.log anschaust was alles auf dem Bus in wenigen Augenblicken passiert und du hältst einen gewichtigen Anteil davon für mehrere Sekunden an ist das extrem kontraproduktiv.
Spätestens beim weiteren Ausbau deiner Hausautomation fällt dir diese Geschichte wieder vor die Füße ... dann liest man in den Foren Überschriften wie "Reaktion auf einen Schalter dauert zu lange" oder "Mein openHAB ist so langsam".
openHAB3 mit Zwave, Alexa, ESPEasy, MQTT, Logitech Harmony, Philips HUE und ZigBee Hardware auf Proxmox VE.

eiGelbGeek
Beiträge: 226
Registriert: 11. Aug 2019 06:39
Answers: 4

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von eiGelbGeek »

int5749 hat geschrieben: 28. Feb 2021 21:27 Somit ist aus meiner Sicht Thread::sleep die richtige Wahl, da ich nur ganz wenige Sekunden verschiebe und somit dann sogar automatisch die folgenden.
Du hältst jede Minute für 2 Sekunden dein System an..... Kann man machen, muss man aber nicht :mrgreen:

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: [How to] OH3 - Anwesendheitssimulation mit Präsenzerkennung

Beitrag von int5749 »

eiGelbGeek hat geschrieben: 1. Mär 2021 12:58 Du hältst jede Minute für 2 Sekunden dein System an..... Kann man machen, muss man aber nicht :mrgreen:
OK, das und auch die anderen Punkte überzeugt mich :) und ich habe dies wie folgt umgebaut

Code: Alles auswählen

var Timer t_presence = null			//Timer, für Presence Simulation

rule "Presence Simulator"
when
	Time cron "0 */1 * * * ?"
then
	if (Absence.state == ON) {
		println("-> Presence Simulation")
		t_presence?.cancel															// timer beenden, falls vorhanden
		t_presence = null															// Zeiger löschen
		gLights_auto.members.filter(f|f.state.toString!==f.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString).forEach[ m|
			var int randomTime = (new java.util.Random).nextInt(5)
			t_presence = createTimer(now.plusSeconds(randomTime), [ |
			m.sendCommand(m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state.toString)
			logInfo("Presence","Restore {} to historic state: {}",m.name, m.historicState(new DateTimeType().zonedDateTime.minusDays(7),"jdbc").state)
			])
		]
	}
end

Viele Grüße
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

Antworten