Anwesenheits-Überwachung / HandyHome

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.


Last update: 21Jun2025 - Created: 24May2024/uk