Presence sensing solution

This is my first significant post to the community having ported from ST just a couple weeks ago.

I am big on privacy so I had never implemented a third party presence sensing solution on ST and was planning to implement one 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 that others may not have. First, 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 edges 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. 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).

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.

#!/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//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 currently 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 departures
    			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

2 Likes