This is my first significant post to the community having ported from ST just a couple weeks ago.
Below is a simple BASH script and setup for presence sensing using cell phones and home WiFi. Yes I know the cell phones WiFi sleeps but this script deals with that as well as event noise on signal boundaries... at least on Android devices.
I am big on privacy so I never implemented a third party presence sensing solution on ST and was planning to implement on HE once ported. I expected to run into the same issues as everyone else when trying to use cell phones as a presence sensing solution so I was planning to use a multi mode solution as others have done, but would avoid the third party options like Life360 and Amazon geo-fencing. However, to my surprise it was relatively easy to implement a rock solid cell phone presence sensing solution, the details follow.
My network topology and setup do provide me an advantage but this should work for other setups with some tweaking. I have four WiFi access points at my residence (all with 2.4Ghz and 5Ghz transmitters). Three for the main WiFi and one for guest use. The main WiFi reaches into the street on all sides of the house while the guest access point is located below grade and limits connectivity to within a few feet of the house (done on purpose for security). Cell Phones are Android Pixels and set to use use non random MAC address for the home SSID and therefore get a static DHCP IP address when connecting.
So after logging and mapping my WiFi response times at the signal boundaries and each cell phones particular WiFi sleep pattern (it differs between models), I determined I do not need a multi mode setup. However, I did setup and test two methods, each worked well with no third party solutions involved. I will outline one below and the second more complicated one in a different post.
With any sensor system you need to consider the noise that will be present with the sensing event. In the first case the sensing event is the connecting and disconnecting from a WiFi network. Both can be quite noisy at the edges of signal boundaries. Both need to be dealt with individually as their "noise" is different. Chaotic and random connections and disconnections at signal boundaries have very different noise when I am waiting for an arrival event vs a departure event. Arrival events are much easier to deal with as there can be no false connection events. An arrival event can be considered an actual arrival event IF I have a confirmed departure event in the past and I am currently not present. Departure events on the other hand have many false events due to connections dropping at boundaries and WiFi sleep on phones.
Solution #1) A simple BASH script (code below) running on an always on computer that fpings the static IP's of the cell phones every 5 seconds (this could be a raspberry pi). A ping response signifies present but a non response requires a specific time threshold be crossed before a departure is logged (to eliminate false departs due to WiFi sleep and dropped connections). Arrivals and departures are sent to the HE via Maker API.
There are two important properties of this setup. One is the time fping will wait for a response on signal boundaries. This should be set to a value small enough that it provides a solid WiFi connection to the cell phone, but not too small that it causes a phone to be logged as disconnected when it is not, and also not too long where there is chaotic connection dropping and re-connecting. This establishes a perimeter inside of where reliable cell connections are possible. The second is the time to wait to log a departure event. This needs to be long enough to accommodate all the WiFi sleeps on each phone. Technically there is no noise associated with making this limit very long until you begin to approach the limits of what you consider a valid departure event (so start off long 5min or more).
This code is working perfectly on my Android phones and has a fping time of 1 sec and a depart timer of 5min. I originally started with fping at 500ms and depart at 3min, those setting produced many false departures and Alexa kept greeting me when I took out the dog.
Enjoy:
#!/bin/bash
#Static Phone WiFi IP's
ip1='10.10.2.60'
ip2='10.10.2.61'
ip3='10.10.2.62'
ip1='10.10.2.63'
user1time=0
user2time=0
user3time=0
user4time=0
fpingtime=1000 #time in mS to wait for ping response
depart=300 #time in Sec that you must be gone to be considered departed
while :
do
#Read current local set presence
inputfile="/home/user/presence.txt"
i="0"
while IFS="," read a b; do
i=$((i + 1))
if [ $i = "1" ]; then
user1P=$b
elif [ $i = "2" ]; then
user2P=$b
elif [ $i = "3" ]; then
user3P=$b
elif [ $i = "4" ]; then
user4P=$b
fi
done < $inputfile
phone=$(fping -c 1 -t$fpingtime $ip1 $ip2 $ip3 $ip4)
#echo $phone
datetime=$(date "+%m-%d-%y_%H:%M:%S")
if [[ "$phone" == *"$ip1"* ]]; then user1="1"; else user1="0"; fi
if [[ "$phone" == *"$ip2"* ]]; then user2="1"; else user2="0"; fi
if [[ "$phone" == *"$ip3"* ]]; then user3="1"; else user3="0"; fi
if [[ "$phone" == *"$ip4"* ]]; then user4="1"; else user4="0"; fi
#echo
#echo $datetime
#echo "user1 current:"$user1",stored:"$user1P
#echo "user2 current:"$user2",stored:"$user2P
#echo "user3 current:"$user3",stored:"$user3P
#echo "user4 current:"$user4",stored:"$user4P
#echo
#if [ "$user1" = "0" ]; then #code to log all no response events on a phone
# timenow=$(date +%s)
# if [ $user1time = "0" ]; then user1time=$(date +%s); fi
# timediff=$(("$timenow" - "$user1time"))
# timeh=$(date -ud "@$timediff" +"%H:%M:%S")
# line=$datetime" user1 current:"$user1",stored:"$user1P",time:"$timeh
# echo $line >> /home/user/user1_ping.log
#fi
#user1 arrive and depart logic
if [ "$user1" = "1" ]; then #is present
if [ "$user1P" = "0" ]; then #status is curently not present update and log arrival
timenow=$(date +%s)
timediff=$(("$timenow" - "$user1time"))
if [[ "$timediff" -lt "86400" ]]; then
line=$(date -ud "@$timediff" +"%H:%M:%S")
else #code to deal with multiday depatrues
days=$(("$diff" / "86400"))
timediff=$(("$timediff" - ("$days" * "86400")))
timeh=$(date -ud "@$timediff" +"%H:%M:%S")
line=$days":"$timeh
fi
echo "user1 arrived: "$(date +%m-%d-%y_%H:%M:%S)", was gone: "$line >> /home/user/user1_presence.log
user1time=0 #reset departed timer
HEVariable=$(wget -qO- --timeout=5 --tries=1 http://10.10.2.90/apps/api/23/devices/20/arrived?access_token=xxxxxxxxxxxxxxxxxxxx)
txt="user1,1"
sed -i -e "1s/.*/$txt/" /home/user/presence.txt #update current status
#echo $HEVariable #HE response
else
user1time=0 #reset timer for when not long enough to be departed
fi
elif [ "$user1" = "0" ]; then #is NOT present
if [ $user1time = "0" ]; then user1time=$(date +%s); fi #start depart timer if not started already
timenow=$(date +%s)
timediff=$(("$timenow" - "$user1time"))
if [[ "$timediff" -lt "86400" ]]; then
line=$(date -ud "@$timediff" +"%H:%M:%S")
else
days=$(("$timediff" / "86400"))
echo "days:"$days
timediff=$(("$timediff" - ("$days" * "86400")))
timeh=$(date -ud "@$timediff" +"%H:%M:%S")
line=$days":"$timeh
fi
echo "user1 current not present time "$line #how long been gone
if [ "$user1P" = "1" ]; then #status is still present
if [[ "$timediff" -gt "$depart" ]]; then #been gone long enough to be not present
timenow=$(date +%s)
timediff=$(("$timenow" - "$user1time"))
if [[ "$timediff" -lt "86400" ]]; then
line=$(date -ud "@$timediff" +"%H:%M:%S")
else
days=$(("$timediff" / "86400"))
timediff=$(("$timediff" - ("$days" * "86400")))
timeh=$(date -ud "@$timediff" +"%H:%M:%S")
line=$days":"$timeh
fi
echo "user1 departed: "$(date +%m-%d-%y_%H:%M:%S)", timer reached: "$line >> /home/user/user1_presence.log
HEVariable=$(wget -qO- --timeout=5 --tries=1 http://10.10.2.90/apps/api/23/devices/20/departed?access_token=xxxxxxxxxxxxxxxxx)
txt="user1,0"
sed -i -e "1s/.*/$txt/" /home/user/presence.txt
echo "user1 has departed"
#echo $HEVariable
fi
fi
fi
#additional users here
sleep 4
done
exit