From 2f3e335246b9f26c38fbea1e35300dcab2beff1f Mon Sep 17 00:00:00 2001 From: Pierre Belanger Date: Tue, 16 Jul 2024 10:48:52 -0400 Subject: [PATCH] [feat] Auto MAC address detection --- CHANGELOG.md | 20 ++++++++++--- env.sh | 6 ++-- mqtt-discovery.sh | 2 +- run.sh | 41 ++++++++++++++++----------- subroutines.sh | 71 ++++++++++++++++++++++++++++++++++++----------- version.sh | 2 +- 6 files changed, 101 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92864a7..4d71014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,24 @@ # Changelog -## 0.1.1 +## 0.2.0 ### Changed -

WARNING WARNING WARNING
-DO NOT UPGRADE PRIOR TO READ THE 0.1.0 UPGRADE INSTRUCTIONS
-WARNING WARNING WARNING

+

**WARNING WARNING WARNING**
+Upgrading from 0.0.10 or previous? DO NOT UPGRADE PRIOR TO READ THE 0.1.0 UPGRADE INSTRUCTIONS.

+ +- NEW Feature: BLE MAC address auto-detection (unless presence detection is disable) +- CHG: Removed setting ble\_mac\_list; obsoleted by mac-auto-detection + +## 0.1.2 + +### Changed + +- CHG: Fix allow empty setting BLE MAC addr (Docker standalone) + +## 0.1.1 + +### Changed - CHG: Fix upgrade forcing to redeploy the key to the car diff --git a/env.sh b/env.sh index 69e9fcb..b62acc1 100755 --- a/env.sh +++ b/env.sh @@ -2,7 +2,7 @@ # # shellcheck shell=dash # -export SW_VERSION=0.1.1 +export SW_VERSION=0.2.0 ### LOAD LIBRARIES (FUNCTIONS & ENVIRONMENT ) ################################# echo "[$(date +%H:%M:%S)] loading libproduct.sh" @@ -34,14 +34,14 @@ export PRESENCE_DETECTION_LOOP_DELAY=${PRESENCE_DETECTION_LOOP_DELAY:-120} export PRESENCE_DETECTION_TTL=${PRESENCE_DETECTION_TTL:-240} export BLE_LN_REGEX='S[0-9A-Fa-f]{16}C' +export BLTCTL_COMMAND_DEVICES=false export KEYS_DIR=/share/tesla_ble_mqtt -export MAC_REGEX='([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' +export MAC_REGEX='([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})' export VIN_REGEX='[A-HJ-NPR-Z0-9]{17}' ### LOG CONFIG VARS ########################################################### log_info "Configuration Options are: BLE_CMD_RETRY_DELAY=$BLE_CMD_RETRY_DELAY - BLE_MAC_LIST=$BLE_MAC_LIST DEBUG=$DEBUG MQTT_SERVER=$MQTT_SERVER MQTT_PORT=$MQTT_PORT diff --git a/mqtt-discovery.sh b/mqtt-discovery.sh index a52f3f5..814c4ce 100644 --- a/mqtt-discovery.sh +++ b/mqtt-discovery.sh @@ -46,7 +46,7 @@ function setupHADevicePanelCardsMain() { configHADeviceEnvVars $vin # If detection is enable, show presence - if [ $PRESENCE_DETECTION_TTL -gt 0 ] && [ -n "$BLE_MAC_LIST" ]; then + if [ $PRESENCE_DETECTION_TTL -gt 0 ]; then log_debug "setupHADevicePanelCardsMain() vin:$vin presence detection enable" setupHADevicePresenceSensor $vin fi diff --git a/run.sh b/run.sh index 317eeb6..bc58f2f 100755 --- a/run.sh +++ b/run.sh @@ -10,7 +10,6 @@ echo "[$(date +%H:%M:%S)] Starting... loading /app/env.sh" . /app/env.sh # Replace | with ' ' white space -BLE_MAC_LIST=$(echo $BLE_MAC_LIST | sed -e 's/[|,;]/ /g') VIN_LIST=$(echo $VIN_LIST | sed -e 's/[|,;]/ /g') vin_count=0 @@ -18,8 +17,21 @@ for vin in $VIN_LIST; do # Populate BLE Local Names list vin_count=$((vin_count + 1)) BLE_LN=$(vinToBLEln $vin) - log_debug "Adding $BLE_LN to BLE_LN_LIST, count $vin_count" + log_debug "Adding $BLE_LN to BLE_LN_LIST, vin_count:$vin_count" BLE_LN_LIST="$BLE_LN_LIST $BLE_LN" + if [ -f $KEYS_DIR/${vin}_macaddr ]; then + BLE_MAC=$(cat $KEYS_DIR/${vin}_macaddr) + log_debug "Found BLE_MAC:$BLE_MAC in $KEYS_DIR/${vin}_macaddr; adding to BLE_MAC_LIST" + BLE_MAC_LIST="$BLE_MAC_LIST $BLE_MAC" + else + log_debug "Adding default value FF:FF:FF:FF:FF:FF to BLE_MAC_LIST" + BLE_MAC_LIST="$BLE_MAC_LIST FF:FF:FF:FF:FF:FF" + # Request bluetooth_read to run the "devices" command + # shellcheck disable=SC2034 + BLTCTL_COMMAND_DEVICES=true + fi + log_debug "Adding default value 0 to PRESENCE_EXPIRE_TIME_LIST" + PRESENCE_EXPIRE_TIME_LIST="$PRESENCE_EXPIRE_TIME_LIST 0" if [ -f $KEYS_DIR/${vin}_private.pem ] && [ -f $KEYS_DIR/${vin}_public.pem ]; then @@ -41,20 +53,17 @@ for vin in $VIN_LIST; do delete_legacies $vin fi # END TEMPORARY done +# remove leading white space +BLE_LN_LIST=$(echo $BLE_LN_LIST | sed -e 's/^ //g') +BLE_MAC_LIST=$(echo $BLE_MAC_LIST | sed -e 's/^ //g') +PRESENCE_EXPIRE_TIME_LIST=$(echo $PRESENCE_EXPIRE_TIME_LIST | sed -e 's/^ //g') -# Populate PRESENCE_EXPIRE_TIME_LIST only if Presence Detection is enable -if [ $PRESENCE_DETECTION_TTL -gt 0 ]; then - log_info "Presence detection is enable with a TTL of $PRESENCE_DETECTION_TTL seconds" - ble_mac_addr_count=0 - # shellcheck disable=SC2034 - for ble_mac in $BLE_MAC_LIST; do - ble_mac_addr_count=$((ble_mac_addr_count + 1)) - log_debug "Adding 0 to PRESENCE_EXPIRE_TIME_LIST, count $ble_mac_addr_count" - PRESENCE_EXPIRE_TIME_LIST="$PRESENCE_EXPIRE_TIME_LIST 0" - done -else - log_info "Presence detection is not enabled due to TTL of $PRESENCE_DETECTION_TTL seconds" -fi +# log _LIST values +log_debug "VIN_LIST:$VIN_LIST" +log_debug "BLE_LN:$BLE_LN" +log_debug "BLE_LN_LIST:$BLE_LN_LIST" +log_debug "BLE_MAC_LIST:$BLE_MAC_LIST" +log_debug "PRESENCE_EXPIRE_TIME_LIST:$PRESENCE_EXPIRE_TIME_LIST" # Setup HA auto discovery, or skip if HA backend is disable, and discard old MQTT messages discardMessages=yes @@ -79,7 +88,7 @@ while :; do # Don't run presence detection if TTL is 0 # If PRESENCE_DETECTION_TTL > 0 and BLE_MAC_LIST is not empty - if [ $PRESENCE_DETECTION_TTL -gt 0 ] && [ -n "$BLE_MAC_LIST" ]; then + if [ $PRESENCE_DETECTION_TTL -gt 0 ]; then log_info "Launch BLE scanning for car presence every $PRESENCE_DETECTION_LOOP_DELAY seconds" listen_to_ble $vin_count # Run listen_to_ble every 3m diff --git a/subroutines.sh b/subroutines.sh index de58864..384b999 100755 --- a/subroutines.sh +++ b/subroutines.sh @@ -34,16 +34,29 @@ replace_value_at_position() { # Function check_presence() { - TYPE="$1" # BLE MAC, LN - MATCH="$2" + BLE_LN="$1" + BLE_MAC="$1" CURRENT_TIME_EPOCH=$(date +%s) + MATCH="($BLE_LN|$BLE_MAC)" + + if [ $BLE_MAC == "FF:FF:FF:FF:FF:FF" ]; then + log_debug "check_presence; looking BLE_MAC for BLE_LN:$BLE_LN" + if grepOutput=$(echo "${BLTCTL_OUT}" | grep $BLE_LN | tail -1); then + BLE_MAC=$(echo $grepOutput | grep -Eo $MAC_REGEX) + log_info "check_presence; found BLE MAC addr:$BLE_MAC for BLE_LN:$BLE_LN" + else + log_debug "check_presence; did not find BLE MAC addr for BLE_LN:$BLE_LN" + fi + fi + # return value to calling function + echo $BLE_MAC if echo "${BLTCTL_OUT}" | grep -Eq "$MATCH"; then - log_info "VIN $VIN $TYPE $MATCH presence detected" + log_info "vin:$VIN ble_ln:$BLE_LN match:$MATCH presence detected" if [ $CURRENT_TIME_EPOCH -ge $PRESENCE_EXPIRE_TIME ]; then - log_info "VIN $VIN $MATCH TTL expired, set presence ON" + log_info "vin:$VIN ble_ln:$BLE_LN TTL expired, set presence ON" set +e # We need a function for mosquitto_pub w/ retry MQTT_OUT=$(eval $MOSQUITTO_PUB_BASE --nodelay -t "$MQTT_TOPIC" -m ON 2>&1) @@ -57,14 +70,14 @@ check_presence() { # Update presence expire time EPOCH_EXPIRE_TIME=$((CURRENT_TIME_EPOCH + PRESENCE_DETECTION_TTL)) - log_debug "VIN $VIN $MATCH update presence expire time to $EPOCH_EXPIRE_TIME" + log_debug "vin:$VIN ble_ln:$BLE_LN update presence expire time to $EPOCH_EXPIRE_TIME" PRESENCE_EXPIRE_TIME_LIST=$(replace_value_at_position "$PRESENCE_EXPIRE_TIME_LIST" \ $position $EPOCH_EXPIRE_TIME) # END if MATCH else - log_debug "VIN $VIN $TYPE $MATCH presence not detected" + log_debug "vin:$VIN ble_ln:$BLE_LN match:$MATCH presence not detected" if [ $CURRENT_TIME_EPOCH -ge $PRESENCE_EXPIRE_TIME ]; then - log_info "VIN $VIN $TYPE $MATCH presence has expired, setting presence OFF" + log_info "vin:$VIN ble_ln:$BLE_LN presence has expired, setting presence OFF" set +e MQTT_OUT=$(eval $MOSQUITTO_PUB_BASE --nodelay -t "$MQTT_TOPIC" -m OFF 2>&1) EXIT_STATUS=$? @@ -74,7 +87,7 @@ check_presence() { return log_debug "mqtt topic $MQTT_TOPIC succesfully updated to OFF" else - log_info "VIN $VIN $TYPE $MATCH presence not expired" + log_info "vin:$VIN ble_ln:$BLE_LN presence not expired" fi # END if expired time fi # END if ! MATCH } @@ -85,9 +98,26 @@ bluetoothctl_read() { # Read BLE data from bluetoothctl or an input file if [ -z $BLECTL_FILE_INPUT ]; then log_debug "Launching bluetoothctl to check for BLE presence" - BLECTL_TIMEOUT=11 set +e - BLTCTL_OUT=$(bluetoothctl --timeout $BLECTL_TIMEOUT scan on 2>&1 | grep -v DEL) + BLTCTL_OUT=$({ + if [ $BLTCTL_COMMAND_DEVICES == "true" ]; then + bltctlCommands="power on,devices,scan on" + else + bltctlCommands="power on,scan on" + fi + IFS=',' + for bltctlCommand in $bltctlCommands; do + echo "$bltctlCommand" + sleep 0.2 + done + + # scan for 10 seconds (Tesla adverstisement each ~9s) + sleep 10 + + echo "scan off" + echo "power off" + echo "exit" + } | bluetoothctl) set -e else # Read from file, great for testing w/ no Bluetooth adapter @@ -119,6 +149,7 @@ listen_to_ble() { while :; do bluetoothctl_read + BLTCTL_COMMAND_DEVICES=false for position in $(seq $n_vins); do set -- $BLE_LN_LIST BLE_LN=$(eval "echo \$${position}") @@ -132,8 +163,18 @@ listen_to_ble() { MQTT_TOPIC="tesla_ble/$VIN/binary_sensor/presence" # Check the presence using both MAC Addr and BLE Local Name - log_debug "$(echo "$BLTCTL_OUT" | grep -E "($BLE_MAC|$BLE_LN)")" - check_presence "BLE MAC & LN" "($BLE_MAC|$BLE_LN)" + log_debug "BLTCTL_OUT:$(echo "$BLTCTL_OUT" | grep -E "($BLE_MAC|$BLE_LN)")" + macAddr=$(check_presence $BLE_LN $BLE_MAC) + + # Add the MAC address to BLE_MAC_LIST if it's not already present at the position + if [ "$macAddr" != "$BLE_MAC" ]; then + eval "BLE_MAC_LIST=\$(echo \$BLE_MAC_LIST | awk '{\$${position}=\"$macAddr\"; print}')" + log_debug "listen_to_ble; BLE_MAC_LIST:$BLE_MAC_LIST" + [ ! -f $KEYS_DIR/${VIN}_macaddr ] && echo $macAddr >$KEYS_DIR/${VIN}_macaddr + fi + + # If a MAC addr is unknown, request "bltctl devices" + [ $macAddr == "FF:FF:FF:FF:FF:FF" ] && BLTCTL_COMMAND_DEVICES=true done sleep $PRESENCE_DETECTION_LOOP_DELAY @@ -151,16 +192,14 @@ scanBLEforMACaddr() { # quite old, but has the principles for auto populating the BLE MAC Address with only the VIN vin=$1 - mac_regex='([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' - ble_ln=$(vinToBLEln $vin) log_info "Looking for vin:$vin in the BLE cache that matches ble_ln:$ble_ln" - if ! bltctl_out=$(bluetoothctl --timeout 2 devices | grep $ble_ln | grep -Eo $mac_regex); then + if ! bltctl_out=$(bluetoothctl --timeout 2 devices | grep $ble_ln | grep -Eo $MAC_REGEX); then log_notice "Couldn't find a match in the cache for ble_ln:$ble_ln for vin:$vin" # Look for a BLE adverstisement matching ble_ln log_notice "Scanning (10 seconds) for BLE advertisement that matches ble_ln:$ble_ln vin:$vin" - if ! bltctl_out=$(bluetoothctl --timeout 10 scan on | grep $ble_ln | grep -Eo $mac_regex); then + if ! bltctl_out=$(bluetoothctl --timeout 10 scan on | grep $ble_ln | grep -Eo $MAC_REGEX); then log_notice "Couldn't find a BLE advertisement for ble_ln:$ble_ln vin:$vin" return 1 fi diff --git a/version.sh b/version.sh index ab2edc4..8d70fd6 100644 --- a/version.sh +++ b/version.sh @@ -2,4 +2,4 @@ # # shellcheck shell=dash # -export SW_VERSION=0.1.1 +export SW_VERSION=0.2.0