Files
openwrt-ha-presence/files/hostapd.user
T
2026-10-12 11:47:21 +03:00

140 lines
4.6 KiB
Bash

#!/bin/sh
# hostapd_cli passes arguments as:
# $1 = global
# $2 = IFNAME=<interface>
# $3 = <3><event>
# $4 = MAC address
MAC="$4"
[ -z "$MAC" ] && exit 0
EVENT=$(echo "$3" | sed 's/^<[0-9]*>//')
MAC_LOWER=$(echo "$MAC" | tr 'A-Z' 'a-z')
STATES_DIR="/tmp/mqtt_ha_states"
mkdir -p "$STATES_DIR"
MQTT_HOST=$(uci get openwrt_ha.main.host)
MQTT_PORT=$(uci get openwrt_ha.main.port)
MQTT_USER=$(uci get openwrt_ha.main.user)
MQTT_PASS=$(uci get openwrt_ha.main.pass)
BASE_TOPIC=$(uci get openwrt_ha.main.base_topic 2>/dev/null || echo "openwrt")
if [ "$EVENT" = "AP-STA-CONNECTED" ]; then
NEW_STATE="home"
elif [ "$EVENT" = "AP-STA-DISCONNECTED" ]; then
NEW_STATE="not_home"
else
exit 0
fi
echo "$NEW_STATE" > "${STATES_DIR}/${MAC_LOWER}"
find_device_by_mac() {
local search_mac="$1"
local i=1
while true; do
device_name="device${i}"
if ! uci -q get openwrt_ha.${device_name}.name >/dev/null 2>&1; then
break
fi
device_macs=$(uci get openwrt_ha.${device_name}.macs)
for mac in $device_macs; do
mac_lower=$(echo "$mac" | tr 'A-Z' 'a-z')
if [ "$mac_lower" = "$search_mac" ]; then
echo "$i"
return 0
fi
done
i=$((i + 1))
done
return 1
}
DEVICE_NUM=$(find_device_by_mac "$MAC_LOWER")
[ -z "$DEVICE_NUM" ] && exit 0
DEVICE_NAME="device${DEVICE_NUM}"
DEVICE_NAME_TEXT=$(uci get openwrt_ha.${DEVICE_NAME}.name)
DEVICE_MACS=$(uci get openwrt_ha.${DEVICE_NAME}.macs)
DEVICE_TYPE=$(uci -q get openwrt_ha.${DEVICE_NAME}.type)
DEVICE_DELAY=$(uci -q get openwrt_ha.${DEVICE_NAME}.delay)
[ -z "$DEVICE_TYPE" ] && DEVICE_TYPE="tracker"
[ -z "$DEVICE_DELAY" ] && DEVICE_DELAY="0"
if [ "$EVENT" = "AP-STA-CONNECTED" ]; then
logger -t "wifi_tracker" "${DEVICE_NAME_TEXT} (${MAC_LOWER}) connected"
elif [ "$EVENT" = "AP-STA-DISCONNECTED" ]; then
logger -t "wifi_tracker" "${DEVICE_NAME_TEXT} (${MAC_LOWER}) disconnected"
fi
get_aggregated_state() {
local state="not_home"
for mac in $DEVICE_MACS; do
mac_lower=$(echo "$mac" | tr 'A-Z' 'a-z')
local mac_state_file="${STATES_DIR}/${mac_lower}"
if [ -f "$mac_state_file" ]; then
if [ "$(cat "$mac_state_file")" = "home" ]; then
state="home"
break
fi
fi
done
echo "$state"
}
convert_state() {
local state="$1"
local type="$2"
if [ "$type" = "alarm" ]; then
[ "$state" = "home" ] && echo "online" || echo "offline"
else
echo "$state"
fi
}
if [ "$DEVICE_TYPE" = "alarm" ]; then
TOPIC="${BASE_TOPIC}/alarm/device_${DEVICE_NUM}/state"
else
TOPIC="${BASE_TOPIC}/device_tracker/device_${DEVICE_NUM}/state"
fi
STATE_FILE="${STATES_DIR}/grace_${DEVICE_NUM}"
if [ "$EVENT" = "AP-STA-CONNECTED" ]; then
rm -f "$STATE_FILE" 2>/dev/null
CURRENT_STATE=$(get_aggregated_state)
MQTT_PAYLOAD=$(convert_state "$CURRENT_STATE" "$DEVICE_TYPE")
mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$TOPIC" -m "$MQTT_PAYLOAD" -r
logger -t "wifi_tracker" "${DEVICE_NAME_TEXT} -> HA: ${MQTT_PAYLOAD}"
fi
if [ "$EVENT" = "AP-STA-DISCONNECTED" ]; then
CURRENT_STATE=$(get_aggregated_state)
if [ "$CURRENT_STATE" = "home" ]; then
rm -f "$STATE_FILE" 2>/dev/null
logger -t "wifi_tracker" "${DEVICE_NAME_TEXT} -> HA: ${CURRENT_STATE} (another MAC active)"
else
if [ "$DEVICE_DELAY" = "0" ]; then
MQTT_PAYLOAD=$(convert_state "not_home" "$DEVICE_TYPE")
mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$TOPIC" -m "$MQTT_PAYLOAD" -r
logger -t "wifi_tracker" "${DEVICE_NAME_TEXT} -> HA: ${MQTT_PAYLOAD}"
else
echo "pending" > "$STATE_FILE"
(
sleep "$DEVICE_DELAY"
if [ -f "$STATE_FILE" ]; then
FINAL_STATE=$(get_aggregated_state)
if [ "$FINAL_STATE" = "not_home" ]; then
MQTT_PAYLOAD=$(convert_state "not_home" "$DEVICE_TYPE")
mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$TOPIC" -m "$MQTT_PAYLOAD" -r
logger -t "wifi_tracker" "${DEVICE_NAME_TEXT} -> HA: ${MQTT_PAYLOAD} (after ${DEVICE_DELAY}s delay)"
else
logger -t "wifi_tracker" "${DEVICE_NAME_TEXT} -> HA: cancelled (device reconnected)"
fi
rm -f "$STATE_FILE" 2>/dev/null
fi
) &
fi
fi
fi