[fli4l] fli4l + WLAN-Gerä?==?utf-8?Q?te - "geofencing" - eine ?==?utf-8?Q?Übersicht/Zusammenfassung me?==?utf-8?Q?ines Setu?==?utf-8?Q?ps

K. Dreier usenetforum at gmx.net
Di Feb 28 17:07:46 CET 2017


Hallo zusammen,

ich dachte mir, daß ich mal ein Feedback geben könnte, was ich mir
hier so in den letzten Wochen mit Hilfe der Leute hier erarbeitet habe
(danke!). Vielleicht kann es ja jemand nutzen.

Mein Setup ist ein fli4l mit 4.0-testing (47100), aber das geht
natürlich auch problemlos mit 3.x. Daran angeschlossen ist ein
WLAN-Router mit entsprechenden WLAN-clients. Selbstverständlich kann
man mein Setup auch auf LAN/"RJ45"-Geräte ausdehnen.

Was war das Ziel:
Auslöser war die Überlegung, daß ich möchte, daß mein Amazon Echo
nur läuft, wenn ich zu hause bin. Da ich ein Smartphone habe, welches
"mit mir wandert", kann ich daran anknüpfen. Denn wenn ich zu hause bin
ist auch das Smartphone zu hause und umgekehrt. Ebenso wenn ich
(länger) weg bin, ist auch mein Smartphone nicht (mehr) mit dem
Heim-WLAN verbunden. Diese Logik lässt sich auf beliebig viele Geräte
ausdehnen. Manche verwenden hierfür den Begriff "geofencing".
Warum das Ganze? Noch reagiert Echo auf die Sprachbefehle von allem und
jedem. Amazon ist schon dabei, daß man das anders gestalten kann, aber
so weit war/ist es zum Zeitpunkt des Verfassens dieses Beitrags noch
nicht. Unabhängig davon würde ich diese Barriere auch nicht
implementieren, da ich z.B. auch mein Smartphone mit dem Echo "reden"
lasse (was hier aber nicht relevant ist). Da ich nicht möchte, daß
jemand zum Spaß durchs Fenster oder die Tür irgendwelche Befehle an
den Echo schickt, habe ich diesen deswegen an einen Wifi-Smartplug
angeschlossen und schalte nun diesen Smartplug via eines auf dem fli4l
laufenden Skripts: aus, wenn die relevanten Geräte nicht da sind, ein,
wenn mind. eines der relevanten Geräte mit dem WLAN verbunden ist (das
WLAN ist selbstverständlich gesichert).
Die Skripte - dazu gleich mehr - haben einen Teil, der unabhängig vom
geschalteten Gerät läuft und einen Teil, der spezifisch für das
jeweils zu schaltende Gerät ist. Klar, denn jeder Hersteller  hat
andere Befehle, um es z.B. ein- oder auszuschalten.

Die Umsetzung:
War komplizierter als gedacht. Anfangs dachte ich, daß ich einfach
anhand des Status von "/var/arping.stat/GERAET.online" überprüfen
kann, ob ein Gerät online ist. Weit gefehlt. Das scheint wohl gut und
verlässlich mit LAN-Geräten zu funktionieren, definitiv aber nicht mit
einem Smartphone, das wohl aufgrund der Stromsparfunktion für den fli4l
immer wieder mal als offline erscheint, obwohl das WLAN an und auch
verbunden ist (unzweifelhaft bei mir überprüft). Also brauchte ich
einen weiteren, zweiten Ansatz, da es natürlich blöd ist, wenn sich
ein gesteuertes Gerät abschaltet, obwohl man zuhause ist.
Ich bin deswegen auf die Idee gekommen, zusätzlich die relevanten
Geräte mittels eines anderen Skripts und dem "ping"-Befehl anzupingen
und zwar häufiger als es arping tut. Das Ergebnis dieses pings gebe ich
in eine txt-Datei aus, welche auf dem fli4l liegt (bei mir auf /data in
einem Unterordner). Im Schalt-Skript lese ich nun einerseits den Inhalt
dieser ping-Datei aus und andererseits überprüfe ich das Vorhandensein
von "GERAET.online" unter /var/arping.stat/. Da selbst das mit einer
einfachen Abfrage-if-Logik zu Problemen führte, habe ich nun eine
Mehrfach-if-Abfrage drin, siehe sogleich.

Details:
Es gibt also zwei Komponenten. Einerseits habe ich ein Skript erstellt,
welches mir alle paar Sekunden einen ping an bestimmte Geräte schickt
und das Ergebnis in eine txt-Datei schreibt. Dieses Skript, und das
andere natürlich auch, werden mittels opt_usercmd auf den fli4l in
/usr/bin/ geschaufelt, ausführbar gemacht und beim Start von fli4l
aufgerufen, laufen also im Hintergrund mit einer Schleife.
Das andere ist das eigentliche Schalt-Skript, welches die Info der
ping-Skript-Ausgabe und von arping.stat verwertet und, basierend auf dem
Ergebnis, xml-Befehle aufruft, welche den Smartplug - je nach dessen
Status - schalten.

Die Skripte:

1) Das ping-Skript
Relativ simpel. Habe für die Nachtzeit die ping-Häufigkeit
runtergefahren (= sleep länger), da ich es dort nicht brauche.

------------------
#!/bin/sh
timestart="051000"
timeend="235959"
device1="GERAETENAME1" # wie im fli4l-HOST-Eintrag definiert
device2="GERAETENAME2"
while true
do
sleep 14 # have loop of 15 seconds in total (or 600), see below
timecurrent=`date +"%H%M%SS"`
ping -c 1 -4 $device1 > /data/${device1}_ping.txt # mir langt 1 Ping;
beschränkt auf IPv4, um keine IPv6-Text-Inhalte zu erhalten
ping -c 1 -4 $device2 > /data/${device2}_ping.txt
if [ $timecurrent -ge $timestart ] && [ $timecurrent -le $timeend ] ;
then
	sleep 1
	else
	sleep 586
fi
done
---------------


2) das Schalt-Skript
Das ist deutlich komplizierter aufgrund einiger Abfragen, Definition von
Variablen, Schaltfunktionen und Zeiteinschränkungen. Das Ziel war, es
mit möglichst vielen Variablen flexibel zu halten, um weitere Geräte
hinzufügen zu können. Natürlich könnte man das noch viel variabler
gestalten, indem man z.B. die Anzahl der definierten "Boss"-Geräte
zählt und dann anhand des Zählers die if-Abfragen laufen lässt. Da
ich das nicht tue, muss ich halt für jedes weitere Gerät die
if-Abfragen hinzufügen/ergänzen. Ich habe es hier für 2 Geräte
dargestellt. Falls jemand eine elegante Lösung hat, wie man das
dahingehend skalierbar machen könnte, wäre ich an einem Feedback
interessiert.

-------------------
#!/bin/sh
timestart="052000"
timeend="235200"

# we want to look for "ON" in the txt file which is created by the
get-script below
edimax_statuslookup="ON"

# define smartplug name here
smartplug="NAMEVOMZUSCHALTENDENGERAET"

# define boss-device names here to allow for use of variables in the
rest of the script
device1="GERAETENAME1" # wie im fli4l-HOST-Eintrag definiert 
device2="GERAETENAME2"

# wait to to allow for devices to come online after fli4l was booted
sleep 30

while true
do
# get current time
timecurrent=`date +"%H%M%S"`

# this will read the _current_ edimax status which is, via the other
script, output into a txt file
# account for setup with more than 1 plug by using specific
status-scripts
# dieser Teil ist vom verwendeten Plug-Hersteller abhängig; das Skript
in der nächsten Zeile schickt einen curl-Befehl an den plug; jener
Inhalt ist hier nicht dargestellt, da es nichts mit fli4l zu tun hat
sh /data/edimax/${smartplug}/${smartplug}_get_edimax_status.sh

# look for "ON" in given file as defined above
exists_edimax=$(grep -c $edimax_statuslookup
"/data/edimax/${smartplug}/edimax_${smartplug}_status.txt")
if [ ${exists_edimax} -gt 0 ] ; then
	echo "Initial status check: Edimax '$smartplug' plug is 'on'" # used
for testing only
	edimax_status="on"
else
	echo "Initial status check: Edimax '$smartplug' plug is 'off'" # used
for testing only
	edimax_status="off"
fi

check_device1() {
local i
local check
local checks
i=4
checks=0
while [ ${i} -gt 0 ] ; do
check=$(grep -c -i "1 received" "/data/ping_${device1}.txt")
checks=$(expr ${checks} + ${check})
i=$(expr ${i} - 1)
sleep 1
done
echo ${checks}
}
exists_device1="$(check_device1)"
echo "result of check-function '$device1': ${exists_device1}" # used for
testing only

check_device2() {
local i
local check
local checks
i=4
checks=0
while [ ${i} -gt 0 ] ; do
check=$(grep -c -i "1 received" "/data/ping_${device2}.txt")
checks=$(expr ${checks} + ${check})
i=$(expr ${i} - 1)
sleep 1
done
echo ${checks}
}
exists_device2="$(check_device2)"
echo "result of check-function '$device2': ${exists_device2}" # used for
testing only

# check for boss devices and set variable according to their status
#exists=$(grep -c -i "1 received" "/data/ping_${device1}.txt")
# only ping successful; this is sufficient to set status to "true";
if [ ${exists_device1} -gt 0 ] && [ -f
/var/run/arping.stat/${device1}.online ] ; then
	device1_online="true"
	echo "$device1 is online, ping successful AND arping-file exists" #
used for testing only
# ping successful AND no arping.stat file exists for device; set status
to "true"
elif [ ${exists_device1} -gt 0 ] && [ ! -f
/var/run/arping.stat/${device1}.online ] ; then
	device1_online="true"
	echo "$device1 is online, ping successful but NO arping-file exists" #
used for testing only
# ping unsuccessful AND no arping.stat file exists for device; only then
set status to "false"
elif [ ${exists_device1} = 0 ] && [ ! -f
/var/run/arping.stat/${device1}.online ] ; then
	device1_online="false"
	echo "$device1 is offline, ping unsuccessful + NO arping-file exists" #
used for testing only
# ping unsuccessful but arping.stat file (still) exists: check for
current status of device
elif [ ${exists_device1} = 0 ] && [ -f
/var/run/arping.stat/${device1}.online ] ; then
	# device-status is "online" and arping-file exists: leave status as
"on"; file will be gone at some point and then it changes to off via
check 1 above
	if [ ${device1_online} = "true" ] ; then
	device1_online="true"
	echo "$device1 ping unsuccessful but arping-file exists AND device
status was already on - keep on" # used for testing only
	# device-status is "offline" (= !="true") and arping-file exists: leave
status as "off" as this could be residual file
	else
	device1_online="false"
	echo "$device1 ping unsuccessful but arping-file exists AND device
status was already off - keep off" # used for testing only
	fi
fi

if [ ${exists_device2} -gt 0 ] && [ -f
/var/run/arping.stat/${device2}.online ] ; then
	device2_online="true"
	echo "$device2 is online, ping successful AND arping-file exists" #
used for testing only
# ping successful AND no arping.stat file exists for device; set status
to "true"
elif [ ${exists_device2} -gt 0 ] && [ ! -f
/var/run/arping.stat/${device2}.online ] ; then
	device2_online="true"
	echo "$device2 is online, ping successful but NO arping-file exists" #
used for testing only
# ping unsuccessful AND no arping.stat file exists for device; only then
set status to "false"
elif [ ${exists_device2} = 0 ] && [ ! -f
/var/run/arping.stat/${device2}.online ] ; then
	device2_online="false"
	echo "$device2 is offline, ping unsuccessful + NO arping-file exists" #
used for testing only
# ping unsuccessful but arping.stat file (still) exists; check for
current status of device
elif [ ${exists_device2} = 0 ] && [ -f
/var/run/arping.stat/${device2}.online ] ; then
	# device-status is "online" and arping-file exists: leave status as
"on"; file will be gone at some point and then it changes to off via
check 1 above
	if [ ${device2_online} = "true" ] ; then
	device2_online="true"
	echo "$device2 ping unsuccessful but arping-file exists AND device
status was already on - keep on" # used for testing only
	# device-status is "offline" (= !="true") and arping-file exists: leave
status as "off" as this could be residual file
	else
	device2_online="false"
	echo "$device2 ping unsuccessful but arping-file exists AND device
status was already off - keep off" # used for testing only
	fi
fi

sleep 1 # why not

# now act depending on the status of boss devices and status of plug
# check if at least one of the boss devices is online
# add or remove boss devices here as required
if [ ${device1_online} = "true" ] || [ ${device2_online} = "true" ] ;
then
	echo "at least 1 boss device is connected" # used for testing only
	# check if plug is "off"; prevents constant firing of the on-script
	# if not on, turn on and set status to "on"
	if [ ${edimax_status} != "on" ] ; then
		# command to execute when at least 1 boss device is connected; turn on
plug
		sh /data/edimax/${smartplug}/${smartplug}_turn_on_edimax.sh
		edimax_status="on"
	fi
# check resulted in: none of the boss devices are online; turn off plug
and set status to "off"
elif [ ${device1_online} != "true" ] && [ ${device2_online} != "true" ]
; then
	echo "no boss device is connected" # used for testing only
	# check if plug is "on"; prevents constant firing of the off-script
	# if not off, turn off and set status to "off"
	if [ ${edimax_status} != "off" ] ; then
		# command to execute when no boss device is connected
		sh /data/edimax/${smartplug}/${smartplug}_turn_off_edimax.sh
		edimax_status="off"
	fi
fi

# work with "chill out time" with less frequent ping at night
if [ ${timecurrent} -ge ${timestart} ] && [ ${timecurrent} -le
${timeend} ] ; then
# generally longer sleep value to avoid shut off of plug when boss
device(s) involuntarily disconnect
	sleep 180
	else
	sleep 1800
fi	
done
--------------------

Fazit:
Nach vielem Testen und diversen Problemen scheint diese Variante der
beiden Skripte in Kombination miteinander nun stabil zu laufen. Es gibt
keine nächtlichen "Aufwach-Aktionen" (nicht lustig, da der Echo beim
Hochfahren redet...) und der plug bleibt im Moment brav an, wenn mind.
ein relevantes Gerät im WLAN hängt. Ziel erreicht.

Gruß
Klaus


Mehr Informationen über die Mailingliste Fli4L