├── README.md
└── presence.sh
/README.md:
--------------------------------------------------------------------------------
1 | presence
2 | =======
3 |
4 | ***Note: as of `presence` 0.5.1, triggered scans, guest scanning, and beacon scanning are removed from `presence.sh` for simplification. Please consider using [monitor](http://github.com/andrewjfreyer/monitor) instead for beacon scanning and detection and for generic device detection. It is unlikely that `presence` will receive substantive updates after version 0.5.1.***
5 |
6 | ____
7 |
8 |
9 | ***TL;DR***: *Bluetooth-based presence detection useful for [mqtt-based](http://mqtt.org) home automation. More granular, responsive, and reliable than device-reported GPS. Cheaper, more reliable, more configurable, and less mqtt-spammy than Happy Bubbles. Does not require any app to be running or installed. Does not require device pairing. Designed to run as service on a [Raspberry Pi Zero W](https://www.raspberrypi.org/products/raspberry-pi-zero-w/).*
10 |
11 | Note that the more frequently you scan for devices, the more 2.4GHz bandwidth you will use. This script may cause interference with Wi-Fi or other bluetooth devices for particularly short delays between scans.
12 |
13 |
Summary
14 |
15 | A JSON-formatted MQTT message is reported to a broker whenever a specified bluetooth device responds to a **name** query. If the device responds, the JSON message includes the name of the device and a **confidence** of 100.
16 |
17 | After a delay, another **name** query is sent and, if the device does not respond, a verification-of-absence loop begins that queries for the device (on a shorter interval) a set number of times. Each time, the device does not respond, the **confidence** is reduced, eventually to 0.
18 |
19 | A configuration file defines 'owner devices' that contains the mac addresses of the devices you'd like to regularly ping to determine presence.
20 |
21 | Topics are formatted like this:
22 |
23 | location/pi_zero_location/00:00:00:00:00:00
24 |
25 | Messages are JSON formatted and contain **name** and **confidence** fields, including a javascript-formatted timestamp and a duration of a particular scan (in ms):
26 |
27 | { confidence : 100, name : Andrew’s iPhone, scan_duration_ms: 500, timestamp : Sat Apr 21 2018 11:52:04 GMT-0600 (MDT)}
28 | { confidence : 0, name : Andrew’s iPhone or Unknown, scan_duration_ms: 5000, timestamp : Sat Apr 21 2018 11:52:04 GMT-0600 (MDT)}
29 |
30 | ___
31 |
32 | Example Use with Home Assistant
33 |
34 | The presence script can be used as an input to a number of [mqtt sensors](https://www.home-assistant.io/components/sensor.mqtt/) in [Home Assistant.](https://www.home-assistant.io). Output from these sensors can be averaged to give a highly-accurate numerical occupancy confidence.
35 |
36 | In order to detect presence in a home that has three floors and a garage, we might include one Raspberry Pi per floor. For average houses, a single well-placed sensor can probably work, but for more reliability at the edges of the house, more sensors are better.
37 |
38 |
39 | ```
40 | - platform: mqtt
41 | state_topic: 'location/first floor/00:00:00:00:00:00'
42 | value_template: '{{ value_json.confidence }}'
43 | unit_of_measurement: '%'
44 | name: 'Andrew First Floor'
45 |
46 | - platform: mqtt
47 | state_topic: 'location/second floor/00:00:00:00:00:00'
48 | value_template: '{{ value_json.confidence }}'
49 | unit_of_measurement: '%'
50 | name: 'Andrew Second Floor'
51 |
52 | - platform: mqtt
53 | state_topic: 'location/third floor/00:00:00:00:00:00'
54 | value_template: '{{ value_json.confidence }}'
55 | unit_of_measurement: '%'
56 | name: 'Andrew Third Floor'
57 |
58 | - platform: mqtt
59 | state_topic: 'location/garage/00:00:00:00:00:00'
60 | value_template: '{{ value_json.confidence }}'
61 | unit_of_measurement: '%'
62 | name: 'Andrew Garage'
63 | ```
64 |
65 | These sensors can be combined/averaged using a [min_max](https://www.home-assistant.io/components/sensor.min_max/):
66 |
67 | ```
68 | - platform: min_max
69 | name: "Andrew Home Occupancy Confidence"
70 | type: mean
71 | round_digits: 0
72 | entity_ids:
73 | - sensor.andrew_garage
74 | - sensor.andrew_third_floor
75 | - sensor.andrew_second_floor
76 | - sensor.andrew_first_floor
77 | ```
78 |
79 | So, as a result of this combination, we use the entity **sensor.andrew_home_occupancy_confidence** in automations to control the state of an **input_boolean** that represents a very high confidence of a user being home or not.
80 |
81 | As an example:
82 |
83 | ```
84 | - alias: Andrew Occupancy
85 | hide_entity: true
86 | trigger:
87 | - platform: numeric_state
88 | entity_id: sensor.andrew_home_occupancy_confidence
89 | above: 10
90 | action:
91 | - service: homeassistant.turn_on
92 | data:
93 | entity_id: input_boolean.andrew_occupancy
94 | ```
95 |
96 | ___
97 |
98 |
99 | Installation Instructions (Raspbian Jessie Lite Stretch):
100 |
101 | Setup of SD Card
102 |
103 | 1. Download latest version of **jessie lite stretch** [here](https://downloads.raspberrypi.org/raspbian_lite_latest)
104 |
105 | 2. Download etcher from [etcher.io](https://etcher.io)
106 |
107 | 3. Image **jessie lite stretch** to SD card. [Instructions here.](https://www.raspberrypi.org/magpi/pi-sd-etcher/)
108 |
109 | 4. Mount **boot** partition of imaged SD card (unplug it and plug it back in)
110 |
111 | 5. **[ENABLE SSH]** Create blank file, without any extension, in the root directory called **ssh**
112 |
113 | 6. **[SETUP WIFI]** Create **wpa_supplicant.conf** file in root directory and add Wi-Fi details for home Wi-Fi:
114 |
115 | ```
116 | country=US
117 | ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
118 | update_config=1
119 |
120 | network={
121 | ssid="Your Network Name"
122 | psk="Your Network Password"
123 | key_mgmt=WPA-PSK
124 | }
125 | ```
126 |
127 | 7. **[FIRST STARTUP]** Insert SD card and power on Raspberry Pi Zero W. On first boot, the newly-created **wpa_supplicant.conf** file and **ssh** will be moved to appropriate directories. Find the IP address of the Pi via your router. One method is scanning for open ssh ports (port 22) on your local network:
128 | ```
129 | nmap 192.168.1.0/24 -p 22
130 | ```
131 |
132 | Configuration and Setup of Raspberry Pi Zero W
133 |
134 | 1. SSH into the Raspberry Pi (password: raspberry):
135 | ```
136 | ssh pi@theipaddress
137 | ```
138 |
139 | 2. Change the default password:
140 | ```
141 | sudo passwd pi
142 | ```
143 |
144 | 3. **[PREPARATION]** Update and upgrade:
145 |
146 | ```
147 | sudo apt-get update
148 | sudo apt-get upgrade -y
149 | sudo apt-get dist-upgrade -y
150 | sudo rpi-update
151 | sudo reboot
152 | ```
153 |
154 | 5. **[BLUETOOTH]** Install Bluetooth Firmware:
155 | ```
156 | #install bluetooth drivers for Pi Zero W
157 | sudo apt-get install pi-bluetooth
158 |
159 | #verify that bluetooth is working
160 | sudo service bluetooth start
161 | sudo service bluetooth status
162 | ```
163 |
164 | 6. **[OPTIONAL: BLUEZ UPGRADE]** Compile/install latest **bluez**
165 |
166 | This is not strictly required anymore, as **pi-bluetooth** appears to have been updated to support bluez 0.5.43.
167 |
168 | ```
169 |
170 | #purge old bluez
171 | sudo apt-get --purge remove bluez
172 |
173 | #get latest version number from: https://www.kernel.org/pub/linux/bluetooth/
174 | #current version as of this writing is 5.49
175 | cd ~; wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.49.tar.xz
176 | tar xvf bluez-5.49.tar.xz
177 |
178 | #update errythang again
179 | sudo apt-get update
180 |
181 | #install necessary packages
182 | sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev
183 |
184 | #move into new unpacked directory
185 | cd bluez-5.49
186 |
187 | #set exports
188 | export LDFLAGS=-lrt
189 |
190 | #configure
191 | ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-library -disable-systemd
192 |
193 | #make & install
194 | make
195 | sudo make install
196 |
197 | #cleanup
198 | cd ~
199 | rm -r bluez-5.49/
200 | rm bluez-5.49.tar.xz
201 |
202 | #update again
203 | sudo apt-get update
204 | sudo apt-get upgrade
205 |
206 | #verify bluez version
207 | bluetoothd -v
208 | ```
209 |
210 | 7. **[REBOOT]**
211 | ```
212 | sudo reboot
213 | ```
214 |
215 | 8. **[INSTALL MOSQUITTO]**
216 | ```
217 |
218 | # get repo key
219 | wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
220 |
221 | #add repo
222 | sudo apt-key add mosquitto-repo.gpg.key
223 |
224 | #download appropriate lists file
225 | cd /etc/apt/sources.list.d/
226 | sudo wget http://repo.mosquitto.org/debian/mosquitto-stretch.list
227 |
228 | #update caches and install
229 | apt-cache search mosquitto
230 | sudo apt-get update
231 | sudo aptitude install libmosquitto-dev mosquitto mosquitto-clients
232 | ```
233 |
234 |
235 | 9. **[INSTALL PRESENCE]**
236 | ```
237 | #install git
238 | cd ~
239 | sudo apt-get install git
240 |
241 | #clone this repo
242 | git clone git://github.com/andrewjfreyer/presence
243 |
244 | #enter presence directory
245 | cd presence/
246 | ```
247 |
248 | 10. **[CONFIGURE PRESENCE]** create file named **mqtt_preferences** and include content:
249 | ```
250 | nano mqtt_preferences
251 | ```
252 |
253 | Then...
254 |
255 | ```
256 | mqtt_address="ip.address.of.broker"
257 | mqtt_port="optional broker network port number. Defaults to 1883"
258 | mqtt_user="your broker username"
259 | mqtt_password="your broker password"
260 | mqtt_topicpath="location"
261 | mqtt_room="your pi's location"
262 | ```
263 |
264 | 11. **[CONFIGURE PRESENCE]** create file named **owner_devices** and include mac addresses of devices on separate lines.
265 |
266 | ```
267 | nano owner_devices
268 | ```
269 |
270 | Then...
271 |
272 | ```
273 | 00:00:00:00:00 #comments
274 | 00:00:00:00:00
275 | ```
276 |
277 | 12. **[CONFIGURE SERVICE]** Create file at **/etc/systemd/system/presence.service** and include content:
278 |
279 | ```
280 | sudo nano /etc/systemd/system/presence.service
281 | ```
282 |
283 | Then...
284 |
285 | ```
286 | [Unit]
287 | Description=Presence service
288 |
289 | [Service]
290 | User=root
291 | ExecStart=/bin/bash /home/pi/presence/presence.sh &
292 | WorkingDirectory=/home/pi/presence
293 | Restart=always
294 | RestartSec=10
295 |
296 | [Install]
297 | WantedBy=multi-user.target
298 |
299 | ```
300 |
301 | 13. **[CONFIGURE SERVICE]** Enable service by:
302 | ```
303 | sudo systemctl enable presence.service
304 | sudo systemctl start presence.service
305 | ```
306 |
307 | That's it. Your broker should be receiving messages and the presence service will restart each time the Raspberry Pi boots.
308 |
309 |
--------------------------------------------------------------------------------
/presence.sh:
--------------------------------------------------------------------------------
1 |
2 | #!/bin/bash
3 |
4 | # ----------------------------------------------------------------------------------------
5 | # GENERAL INFORMATION
6 | # ----------------------------------------------------------------------------------------
7 | #
8 | # Written by Andrew J Freyer
9 | # GNU General Public License
10 | # http://github.com/andrewjfreyer/presence
11 | #
12 | # ----------------------------------------------------------------------------------------
13 |
14 | # ----------------------------------------------------------------------------------------
15 | # INCLUDES & VARIABLES
16 | # ----------------------------------------------------------------------------------------
17 |
18 | #VERSION NUMBER
19 | VERSION=0.5.1
20 |
21 | #COLOR OUTPUT FOR RICH DEBUG
22 | ORANGE='\033[0;33m'
23 | RED='\033[0;31m'
24 | NC='\033[0m'
25 | GREEN='\033[0;32m'
26 | PURPLE='\033[1;35m'
27 |
28 | #BASE DIRECTORY REGARDLESS OF INSTALLATION; ELSE MANUALLY SET HERE
29 | base_directory=$(dirname "$(readlink -f "$0")")
30 |
31 | #FIND MQTT PATH, ELSE MANUALLY SET HERE
32 | mosquitto_pub_path=$(which mosquitto_pub)
33 | mosquitto_sub_path=$(which mosquitto_sub)
34 |
35 | #ERROR CHECKING FOR MOSQUITTO PUBLICATION
36 | [ -z "$mosquitto_pub_path" ] && echo "Required package 'mosquitto_pub' not found. Please install." && exit 1
37 | [ -z "$mosquitto_sub_path" ] && echo "Required package 'mosquitto_sub' not found. Please install." && exit 1
38 |
39 | # ----------------------------------------------------------------------------------------
40 | # LOAD PREFERENCES
41 | # ----------------------------------------------------------------------------------------
42 |
43 | #OR LOAD FROM A SOURCE FILE
44 | if [ ! -f "$base_directory/behavior_preferences" ]; then
45 | echo -e "${GREEN}presence $VERSION ${RED}WARNING: ${NC}Behavior preferences are not defined:${NC}"
46 | echo -e "/behavior_preferences. Creating file and setting default values.${NC}"
47 | echo -e ""
48 |
49 | #DEFAULT VALUES
50 | echo "
51 | #DELAY BETWEEN SCANS OF OWNER DEVICES WHEN AWAY FROM HOME
52 | delay_between_owner_scans_away=6
53 |
54 | #DELAY BETWEEN SCANS OF OWNER DEVICES WHEN HOME
55 | delay_between_owner_scans_present=30
56 |
57 | #HOW MANY VERIFICATIONS ARE REQUIRED TO DETERMINE A DEVICE IS AWAY
58 | verification_of_away_loop_size=6
59 |
60 | #HOW LONG TO DELAY BETWEEN VERIFICATIONS THAT A DEVICE IS AWAY
61 | verification_of_away_loop_delay=3
62 |
63 | #PREFERRED HCI DEVICE
64 | hci_device='hci0'" > "$base_directory/behavior_preferences"
65 | fi
66 |
67 | # ----------------------------------------------------------------------------------------
68 | # VARIABLE DEFINITIONS
69 | # ----------------------------------------------------------------------------------------
70 |
71 | #SET PREFERENCES FROM FILE
72 | DELAY_CONFIG="$base_directory/behavior_preferences" ; [ -f $DELAY_CONFIG ] && source $DELAY_CONFIG
73 |
74 | #LOAD DEFAULT VALUES IF NOT PRESENT
75 | [ -z "$hci_device" ] && hci_device='hci0'
76 | [ -z "$name_scan_timeout" ] && name_scan_timeout=5
77 | [ -z "$delay_between_owner_scans_away" ] && delay_between_owner_scans_away=6
78 | [ -z "$delay_between_owner_scans_present" ] && delay_between_owner_scans_present=30
79 | [ -z "$verification_of_away_loop_size" ] && verification_of_away_loop_size=6
80 | [ -z "$verification_of_away_loop_delay" ] && verification_of_away_loop_delay=3
81 |
82 | #LOAD PREFERENCES IF PRESENT
83 | MQTT_CONFIG=$base_directory/mqtt_preferences ; [ -f $MQTT_CONFIG ] && source $MQTT_CONFIG
84 | [ ! -f "$MQTT_CONFIG" ] && echo "warning: please configure mqtt preferences file. exiting." && echo "" > "$MQTT_CONFIG" && exit 1
85 |
86 | #FILL ADDRESS ARRAY WITH SUPPORT FOR COMMENTS
87 | [ ! -f "$base_directory/owner_devices" ] && "" > "$base_directory/owner_devices"
88 | macaddress_owners=($(cat "$base_directory/owner_devices" | grep -oiE "([0-9a-f]{2}:){5}[0-9a-f]{2}" ))
89 | [ -z "$macaddress_owners" ] && echo "warning: no owner devices are specified. exiting." && exit 1
90 |
91 |
92 | #NUMBER OF CLIENTS THAT ARE MONITORED
93 | number_of_owners=$((${#macaddress_owners[@]}))
94 |
95 | # ----------------------------------------------------------------------------------------
96 | # HELP TEXT
97 | # ----------------------------------------------------------------------------------------
98 |
99 | show_help_text() {
100 | echo "Usage:"
101 | echo " presence -h show usage information"
102 | echo " presence -d print debug messages and mqtt messages"
103 | echo " presence -b binary output only; either 100 or 0 confidence"
104 | echo " presence -c only post confidence status changes for owners/guests"
105 | echo " presence -V print version"
106 | }
107 |
108 | # ----------------------------------------------------------------------------------------
109 | # PROCESS OPTIONS (technique: https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash)
110 | # ----------------------------------------------------------------------------------------
111 |
112 | OPTIND=1
113 |
114 | # INITIALIZE OUR OWN VARIABLES:
115 | debug=0
116 | binary_only=0
117 | changes_only=0
118 |
119 | while getopts "h?Vdbct:" opt; do
120 | case "$opt" in
121 | h|\?)
122 | show_help_text
123 | exit 0
124 | ;;
125 | V)
126 | echo "$VERSION"
127 | exit 0
128 | ;;
129 | d) debug=1
130 | ;;
131 | b) binary_only=1
132 | ;;
133 | c) changes_only=1
134 | ;;
135 | *) echo "warning: unknown or depreciated option: $opt"
136 | esac
137 | done
138 |
139 | #RESET OPTION INDEX
140 | shift $((OPTIND-1))
141 |
142 | #SHIFT IF NECESSARY
143 | [ "$1" = "--" ] && shift
144 |
145 | # ----------------------------------------------------------------------------------------
146 | # DEBUG FUNCTION
147 | # ----------------------------------------------------------------------------------------
148 |
149 | debug_echo () {
150 | if [ "$debug" == "1" ]; then
151 | (>&2 echo -e "${ORANGE}DEBUG MSG: $1${NC}")
152 | fi
153 | }
154 |
155 | # ----------------------------------------------------------------------------------------
156 | # SCAN
157 | # ----------------------------------------------------------------------------------------
158 |
159 | scan () {
160 | if [ ! -z "$1" ]; then
161 | local result=$(hcitool -i $hci_device name "$1" 2>&1 | grep -v 'not available' | grep -vE "hcitool|timeout|invalid|error" )
162 | debug_echo "Scan result: [$result]"
163 | echo "$result"
164 | fi
165 | }
166 |
167 | # ----------------------------------------------------------------------------------------
168 | # PUBLISH MESSAGE
169 | # ----------------------------------------------------------------------------------------
170 |
171 | publish () {
172 | if [ ! -z "$1" ]; then
173 |
174 | #SET NAME FOR 'UNKONWN'
175 | local name="$3"
176 |
177 | #IF NO NAME, RETURN "UNKNOWN"
178 | if [ -z "$3" ]; then
179 | name="Unknown"
180 | fi
181 |
182 | #TIMESTAMP
183 | stamp=$(date "+%a %b %d %Y %H:%M:%S GMT%z (%Z)")
184 |
185 | #DEBUGGING
186 | [ "$debug" == "1" ] && (>&2 echo -e "${PURPLE}$mqtt_topicpath$1 { confidence : $2, name : $name, scan_duration_ms: $4, timestamp : $stamp} ${NC}")
187 |
188 | #POST TO MQTT
189 | $mosquitto_pub_path -h "$mqtt_address" -p "${mqtt_port:=1883}" -u "$mqtt_user" -P "$mqtt_password" -t "$mqtt_topicpath$1" -m "{\"confidence\":\"$2\",\"name\":\"$name\",\"scan_duration_ms\":\"$4\",\"timestamp\":\"$stamp\"}"
190 | fi
191 | }
192 |
193 | # ----------------------------------------------------------------------------------------
194 | # MAIN LOOP
195 | # ----------------------------------------------------------------------------------------
196 |
197 | device_statuses=() #STORES STATUS FOR EACH BLUETOOTH DEVICES
198 | device_names=() #STORES DEVICE NAMES FOR BOTH BEACONS AND BLUETOOTH DEVICES
199 | one_owner_home=0 #FLAG FOR AT LEAST ONE OWNER BEING HOME
200 |
201 | # ----------------------------------------------------------------------------------------
202 | # START THE OPERATIONAL LOOP
203 | # ----------------------------------------------------------------------------------------
204 |
205 | #MAIN LOOP
206 | while true; do
207 |
208 | #RESET AT LEAST ONE DEVICE HOME
209 | one_owner_home=0
210 |
211 | #--------------------------------------
212 | # UPDATE STATUS OF ALL USERS WITH NAME QUERY
213 | #--------------------------------------
214 | for ((index=0; index<${#macaddress_owners[*]}; index++));
215 | do
216 | #CLEAR PER-LOOP VARIABLES
217 | name_scan_result=""
218 | name_scan_result_verify=""
219 | ok_to_publish=1
220 |
221 | #OBTAIN INDIVIDUAL ADDRESS
222 | current_device_address="${macaddress_owners[$index]}"
223 |
224 | #CHECK FOR ADDITIONAL BLANK LINES IN ADDRESS FILE
225 | if [ -z "$current_device_address" ]; then
226 | continue
227 | fi
228 |
229 | #MARK BEGINNING OF SCAN OPERATION
230 | start_timer=$(date +%s%N)
231 |
232 | #OBTAIN RESULTS AND APPEND EACH TO THE SAME
233 | name_scan_result=$(scan $current_device_address)
234 |
235 | #MARK END OF SCAN OPERATION
236 | end_time=$(date +%s%N)
237 |
238 | #CALCULATE DIFFERENCE
239 | duration_timer=$(( (end_time - start_timer) / 1000000 ))
240 |
241 | #THIS DEVICE NAME IS PRESENT
242 | if [ "$name_scan_result" != "" ]; then
243 |
244 | #STATE IS SAME && ONLY REPORT CHANGES THEN DISABLE PUBLICATION
245 | [ "${device_statuses[$index]}" == '100' ] && [ "$changes_only" == 1 ] && ok_to_publish=0
246 |
247 | #NO DUPLICATE MESSAGES
248 | [ "$ok_to_publish" == "1" ] && publish "/$mqtt_room/$current_device_address" '100' "$name_scan_result" "$duration_timer"
249 |
250 | #USER STATUS
251 | device_statuses[$index]="100"
252 |
253 | #SET AT LEAST ONE DEVICE HOME
254 | one_owner_home=1
255 |
256 | #SET NAME ARRAY
257 | device_names[$index]="$name_scan_result"
258 |
259 | else
260 |
261 | #USER STATUS
262 | status="${device_statuses[$index]}"
263 |
264 | if [ -z "$status" ]; then
265 | status="0"
266 | fi
267 |
268 | #BY DEFAULT, SET REPETITION TO PREFERENCE
269 | repetitions="$verification_of_away_loop_size"
270 |
271 | #IF WE ARE JUST STARTING OR, ALTERNATIVELY, WE HAVE RECORDED THE STATUS
272 | #OF NOT HOME ALREADY, ONLY SCAN ONE MORE TIME.
273 | if [ "$status" == 0 ];then
274 | repetitions=1
275 | fi
276 |
277 | #SHOULD VERIFY ABSENSE
278 | for repetition in $(seq 1 $repetitions);
279 | do
280 | #RESET OK TO PUBLISH
281 | ok_to_publish=1
282 |
283 | #VERIFICATION LOOP DELAY
284 | sleep "$verification_of_away_loop_delay"
285 |
286 | #GET PERCENTAGE
287 | percentage=$(($status * ( $repetitions - $repetition) / $repetitions))
288 |
289 | #ONLY SCAN IF OUR STATUS IS NOT ALREADY 0
290 | if [ "$status" != 0 ];then
291 |
292 | #MARK BEGINNING OF SCAN OPERATION
293 | start_timer=$(date +%s%N)
294 |
295 | #PERFORM SCAN
296 | name_scan_result_verify=$(scan $current_device_address)
297 |
298 | #MARK END OF SCAN OPERATION
299 | end_time=$(date +%s%N)
300 |
301 | #CALCULATE DIFFERENCE
302 | duration_timer=$(( (end_time - start_timer) / 1000000 ))
303 |
304 | #CHECK SCAN
305 | if [ "$name_scan_result_verify" != "" ]; then
306 |
307 | #STATE IS SAME && ONLY REPORT CHANGES THEN DISABLE PUBLICATION
308 | [ "${device_statuses[$index]}" == '100' ] && [ "$changes_only" == 1 ] && ok_to_publish=0
309 |
310 | #PUBLISH
311 | [ "$ok_to_publish" == "1" ] && publish "/$mqtt_room/$current_device_address" '100' "$name_scan_result_verify" "$duration_timer"
312 |
313 | #SET AT LEAST ONE DEVICE HOME
314 | one_owner_home=1
315 |
316 | #WE KNOW THAT WE MUST HAVE BEEN AT A PREVIOUSLY-SEEN USER STATUS
317 | device_statuses[$index]="100"
318 |
319 | #UPDATE NAME ARRAY
320 | device_names[$index]="$name_scan_result_verify"
321 |
322 | #MUST BREAK CONFIDENCE SCANNING LOOP; 100' ISCOVERED
323 | break
324 | fi
325 | fi
326 |
327 | #RETREIVE LAST-KNOWN NAME FOR PUBLICATION; SINCE WE OBVIOUSLY DIDN'T RECEIVE A NAME SCAN RESULT
328 | expectedName="${device_names[$index]}"
329 |
330 | if [ "$percentage" == "0" ]; then
331 | #STATE IS SAME && ONLY REPORT CHANGES THEN DISABLE PUBLICATION
332 | [ "${device_statuses[$index]}" == '0' ] && [ "$changes_only" == 1 ] && ok_to_publish=0
333 |
334 | #PRINT ZERO CONFIDENCE OF A DEVICE AT HOME
335 | [ "$ok_to_publish" == "1" ] && publish "/$mqtt_room/$current_device_address" "0" "$expectedName" "$duration_timer"
336 | else
337 | #STATE IS SAME && ONLY REPORT CHANGES THEN DISABLE PUBLICATION
338 | [ "${device_statuses[$index]}" == '$percentage' ] && [ "$changes_only" == 1 ] && ok_to_publish=0
339 |
340 | #IF BINARY ONLY, THEN DISABLE PUBLICATION
341 | [ "$binary_only" == "1" ] && ok_to_publish=0
342 |
343 | #REPORT CONFIDENCE DROP
344 | [ "$ok_to_publish" == "1" ] && publish "/$mqtt_room/$current_device_address" "$percentage" "$expectedName" "$duration_timer"
345 | fi
346 |
347 | #UPDATE STATUS ARRAY
348 | device_statuses[$index]="$percentage"
349 | done
350 | fi
351 | done
352 |
353 | #CHECK STATUS ARRAY FOR ANY DEVICE MARKED AS 'HOME'
354 | wait_duration=0
355 |
356 | #DETERMINE APPROPRIATE DELAY
357 | if [ "$one_owner_home" == 1 ]; then
358 | wait_duration=$delay_between_owner_scans_present
359 | else
360 | wait_duration=$delay_between_owner_scans_away
361 | fi
362 |
363 | sleep "$wait_duration"
364 | done
365 |
--------------------------------------------------------------------------------