├── 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 | --------------------------------------------------------------------------------