Vorwort
Im Rahmen unseres Projektes Mosliboss-SmartHome sind
wir natürlich auch mit der Idee konfrontiert worden, gewisse Dinge
unterschiedlich zu steuern, wenn wir zu Hause oder abwesend sind.
Implementierung
Wir haben uns entschieden, die Anwesenheit von unseren Handys im lokalen WLAN
zu benutzen, um zu entscheiden, wer zu Hause iat. Dazu war es notwendig, bei
unserem Router permanente (lokale) IP-Adressen für die (Android-)Handys
zu definieren.
Das Prinzip wurde im Verlauf des letzten Jahres wegen gelegentlich auftretenden
falschen Negativ-Einträgen (Handy wird als abwesend beurteilt, obwohl es
anwesend war) geändert und seit mehreren Wochen haben wir nun eine Methode
implementiert, die sich fehlerfrei bewährt hat:
- Jede Minute werden mittels cron-job unsere Handys mehrmals angepingt
- Alle 5 Minuten wird gecheckt, ob eines oder beide der Handys in den letzten
5 Minuten erfolgreich angepingt werden konnte.
Cron-Jobs:
* * * * * $HOME/smarthome/handyhome/ping_handys.sh >> /mnt/ramdisk/handyhome/ping_handys.log 2>>$HOME/smarthome/handyhome/ping_handys.errlog
*/5 * * * * $HOME/smarthome/handyhome/gethandyhome.sh >> /mnt/ramdisk/handyhome/gethandyhome.log 2>>$HOME/smarthome/handyhome/gethandyhome.errlog
Unten ist das Script ping_handys.sh widergegeben, welches jede Minute
gestartet
wird, um festzustellen, ob und welches der beiden Handys mit dem lokalen WLAN
verbunden sind. Etlicher Aufwand wurde geleistet, damit das Error-Log-File
im Normalfall leer bleibt.
#!/bin/bash
# ping_handys.sh 14Jun2025/uk
mkdir -p /mnt/ramdisk/handyhome/
cd $HOME/smarthome/handyhome
source $HOME/smarthome/HA/MASTER.file
if test "$MASTER" = "no" ; then
exit
fi
PING_FILES="/mnt/ramdisk/Ping_Devices"
LOGFILE="/mnt/ramdisk/handyhome/ping_handys.log"
PING_TARGETS="$HOME/smarthome/handyhome/ping_handys.txt"
# retries=5 und delay=3 dauert für ein abwesendes Handy ca. 23 Sekunden
retries=5
delay=3
sleep 2 # Staffelung der cron-jobs
# Sicherstellen, dass die Datei ping_handys.txt existiert
if [ ! -f "$PING_TARGETS" ]; then
echo "Die Datei $PING_TARGETS wurde nicht gefunden!"
exit 1
fi
# Führt fping aus und verarbeitet die Ausgabe
while IFS= read -r ip; do
echo "$(date +%d-%m-%Y_%H:%M:%S) Pinge $ip..."
ipREPORT=`echo $ip | cut -c 3-4` # muss VOR fping stehen!!!
# Durchführung von 13 Pings, wenn IP nicht erreichbar ist
for i in $(seq 1 $retries); do
fping --retry=1 "$ip" >/dev/null 2>&1
# Prüfen, ob der Ping erfolgreich war
if [ $? -eq 0 ]; then
# Wenn erfolgreich, schreibe in die Logdatei und breche den Loop ab
echo "$(date +%d-%m-%Y_%H:%M:%S) $ipREPORT home $(date +%s)" >> "/mnt/ramdisk/handyhome/${ipREPORT}_ping_log"
echo "$(date +%d-%m-%Y_%H:%M:%S) Ping-Versuch Nr. $i"
break
else
echo "$(date +%d-%m-%Y_%H:%M:%S) $ipREPORT away $(date +%s)" >> "/mnt/ramdisk/handyhome/${ipREPORT}_ping_log"
echo "$(date +%d-%m-%Y_%H:%M:%S) Ping-Versuch Nr. $i"
fi
# Warten vor dem nächsten Versuch
sleep $delay
done
# Wenn nach $retires Versuchen der Ping immer noch fehlschlägt
if [ $? -ne 0 ]; then
echo "$(date +%d-%m-%Y_%H:%M:%S) $ipREPORT away $(date +%s)" >> "/mnt/ramdisk/handyhome/${ipREPORT}_ping_log"
fi
done < "$PING_TARGETS" # Für jede IP in der Datei ping_handys.txt
echo "$(date +%d-%m-%Y_%H:%M:%S) Ping-Prozess abgeschlossen!" >> $LOGFILE
Das Script gethandyhome.sh testet alle 5 Minuten, ob in den letzten 5 Minuten ein Ping erfolgreich war. Allenfalls "verlorene" Pings werden absichtlich nicht geloggt. Im folgenden Script müssen 'AB' und 'ab' sowie 'CD' und 'cd' durch die passenden Initialen ersetzt werden!
#!/bin/bash
# gethandyhome.sh neue Version 06Jun2025/uk 30Nov2023/uk
#
# Die Idee kam kam ursprünglich beim Studium der Seite
# https://www.tryption.ch/de/blog/systeminformationen-aus-swisscoms-internet-box-auslesen/
# und dann einfach einmal DeviceInfo weglassen... :-)
#
source $HOME/smarthome/HA/MASTER.file
if test "$MASTER" = "no" ; then
# echo "Nicht Master. gethandyhome.sh - exit! `date +%d.%m.%Y_%H:%M`"
exit
fi
sleep 5 # Staffelung der cron-jobs
#
cd $HOME/smarthome/handyhome
#
mkdir -p /mnt/ramdisk/handyhome/
OUTFILE="/mnt/ramdisk/handyhome/${0##*/}.result"
#
if test ! -r /mnt/ramdisk/handyhome/lastALLEstatus ; then
echo "no" > /mnt/ramdisk/handyhome/lastALLEstatus
fi
lastALLEstatus=`cat /mnt/ramdisk/handyhome/lastALLEstatus`
#
# Handy-IPs im Router (DHCP) fest vergeben --> siehe /etc/hosts !!!
# Im File /etc/hosts hat es zwei Einträge für die beiden Handys der
# Benutzer 'AB' und 'CD' :
# 192.168.0.nn ipAB # Handy AB
# 192.168.0.mm ipCD # Handy CD
#
echo " "
grep -q "home" /mnt/ramdisk/handyhome/AB_ping_log
if test $? -eq 0 ; then
AB="home"
else
AB="away"
fi
echo "$AB" > /mnt/ramdisk/handyhome/AB
grep -q "home" /mnt/ramdisk/handyhome/CD_ping_log
if test $? -eq 0 ; then
CD="home"
else
CD="away"
fi
echo "$CD" > /mnt/ramdisk/handyhome/CD
# Ausgabe des Status
echo "`date +%d.%m.%Y_%H:%M` AB: $AB, CD: $CD"
# Leere alte ping-log-Files:
> /mnt/ramdisk/handyhome/AB_ping_log
> /mnt/ramdisk/handyhome/CD_ping_log
# Statusänderung erkennen
currentstatus="no"
if [ "$AB" = "away" ] && [ "$CD" = "away" ]; then
currentstatus="yes"
## echo "yes" > /mnt/ramdisk/handyhome/lastALLEstatus
fi
# Wenn sich der Status von ALLE_WEG geändert hat, führe die entsprechenden Aktionen aus
echo "currentstatus = $currentstatus - lastALLEstatus $lastALLEstatus"
if [ "$currentstatus" != "$lastALLEstatus" ]; then
echo "`date +%d.%m.%Y_%H:%M` Neue ALLE-Statusänderung - WebHook-Befehle senden"
echo "$currentstatus" > /mnt/ramdisk/handyhome/lastALLEstatus
new_ALLE_status="true"
if test "$AB" = "away" && test "$CD" = "away" ; then
echo " yes " > /mnt/ramdisk/handyhome/HOME
else
echo " no " > /mnt/ramdisk/handyhome/HOME
fi
else
echo "Keine ALLE-Statusänderung"
new_ALLE_status="false"
fi
echo "HOME = `cat /mnt/ramdisk/handyhome/HOME`"
# Eintrag für AB erstellen, wenn Status von "home" zu "away" geändert wurde
rm -f /mnt/ramdisk/handyhome/neu.dat
last_ab_status=$(cat /mnt/ramdisk/handyhome/history.dat | grep "AB" | awk '{print $3}' | head -n 1) # Status aus dritter Spalte extrahieren
echo "last_ab_status $last_ab_status - AB $AB"
if [ "$last_ab_status" != "$AB" ]; then
new_entryAB="true"
echo "`date +%d.%m.%Y_%H:%M:%S` AB $AB ALLE_WEG:`cat /mnt/ramdisk/handyhome/HOME`" >> /mnt/ramdisk/handyhome/neu.dat
else
new_entryAB="false"
fi
# Eintrag für CD erstellen, wenn Status von "home" zu "away" geändert wurde
last_cd_status=$(cat /mnt/ramdisk/handyhome/history.dat | grep "CD" | awk '{print $3}' | head -n 1) # Status aus dritter Spalte extrahieren
echo "last_cd_status $last_cd_status - CD $CD"
if [ "$last_cd_status" != "$CD" ]; then
new_entryCD="true"
echo "`date +%d.%m.%Y_%H:%M:%S` CD $CD ALLE_WEG:`cat /mnt/ramdisk/handyhome/HOME`" >> /mnt/ramdisk/handyhome/neu.dat
else
new_entryCD="false"
fi
# Wenn Einträge vorhanden sind, die in neu.dat geschrieben wurden
if [ -s /mnt/ramdisk/handyhome/neu.dat ]; then
cat /mnt/ramdisk/handyhome/history.dat >> /mnt/ramdisk/handyhome/neu.dat
mv /mnt/ramdisk/handyhome/neu.dat /mnt/ramdisk/handyhome/history.dat
fi
#
# Daten von MASTER auf SLAVE kopieren:
scp -p -o ConnectTimeout=5 /mnt/ramdisk/handyhome/* $SLAVE:/mnt/ramdisk/handyhome/
#
if test "$new_entryAB" = "false" && test "$new_entryCD" = "false" ; then
echo "Kein neuer Status für AB oder CD --> exit!"
if test "$new_ALLE_status" = "false" ; then
exit
fi
else
echo "Neuer Status für AB oder CD -> neue Webseite bauen"
fi
# Web-Seite bauen:
rm -f /mnt/ramdisk/handyhome/index_new.html
echo "" >> /mnt/ramdisk/handyhome/index_new.html
echo "<h1>" >> /mnt/ramdisk/handyhome/index_new.html
echo "Aufenthalt Handys/Personen" >> /mnt/ramdisk/handyhome/index_new.html
echo "" >> /mnt/ramdisk/handyhome/index_new.html
echo "CD: `cat /mnt/ramdisk/handyhome/CD` AB: `cat /mnt/ramdisk/handyhome/AB` " >> /mnt/ramdisk/handyhome/index_new.html
echo "
" >> /mnt/ramdisk/handyhome/index_new.html
alleweg=$(cat /mnt/ramdisk/handyhome/HOME | cut -d" " -f 3)
if [ "$alleweg" = "yes" ]; then
echo "Alle sind weg: `cat /mnt/ramdisk/handyhome/HOME` - Aktion_niemand_zuhause" >> /mnt/ramdisk/handyhome/index_new.html
else
echo "Alle sind weg: `cat /mnt/ramdisk/handyhome/HOME` - Aktion_alle_zuhause" >> /mnt/ramdisk/handyhome/index_new.html
fi
echo "<h1>" >> /mnt/ramdisk/handyhome/index_new.html
echo "Updated: `date +%d-%m-%Y_%H:%M`" >> /mnt/ramdisk/handyhome/index_new.html
echo "
" >> /mnt/ramdisk/handyhome/index_new.html
echo "<h2>" >> /mnt/ramdisk/handyhome/index_new.html
echo "CD und AB - neuste Einträge
" >> /mnt/ramdisk/handyhome/index_new.html
echo "
" >> /mnt/ramdisk/handyhome/index_new.html
echo "`cat /mnt/ramdisk/handyhome/history.dat | head -n 60`" >> /mnt/ramdisk/handyhome/index_new.html
echo "
" >> /mnt/ramdisk/handyhome/index_new.html
echo "" >> /mnt/ramdisk/handyhome/index_new.html
echo "<hr>" >> /mnt/ramdisk/handyhome/index_new.html
echo "
Last (automatic) update: `date +%d-%m-%Y_%H:%M` (`uname -n`) - Created: 28Nov2023/uk" >> /mnt/ramdisk/handyhome/index_new.html
echo "" >> /mnt/ramdisk/handyhome/index_new.html
echo "<<h2>" >> /mnt/ramdisk/handyhome/index_new.html
echo "" >> /mnt/ramdisk/handyhome/index_new.html
#
# Webseite auf Web-Server schicken:
scp -p -o ConnectTimeout=5 /mnt/ramdisk/handyhome/index_new.html WEBSERVER:/var/www/HandyHome/index.html
# Falls keine generelle Statusaenderung (ALLE_WEG) vorhanden ist,
# dann keinen WebHook senden:
if test "$new_ALLE_status" = "false" ; then
echo "new_ALLE_status = $new_ALLE_status --> Keine Webhooks! - exit"
exit
else
echo "new_ALLE_status = $new_ALLE_status --> Webhooks senden!"
fi
if test "$CD" = "away" && test "$AB" = "away" ; then
echo "Niemand zu Hause"
echo "Aktion wenn niemand zu Hause ist"
# Hier kommt der entprechende Befehl hin...
else
echo "Jemand zu Hause"
echo "Aktion wenn jwmand zu Hause ist"
# Hier kommt der entprechende Befehl hin...
fi
#
Die Webseite - gespeichert im File /mnt/ramdisk/handyhome/index_new.html -
sieht dann beispielsweise so aus und kann auf den WEBSERVER kopiert werden.