diff --git a/files/hostapd.user b/files/hostapd.user new file mode 100644 index 0000000..9d58efa --- /dev/null +++ b/files/hostapd.user @@ -0,0 +1,140 @@ +#!/bin/sh +# hostapd_cli passes arguments as: +# $1 = global +# $2 = IFNAME= +# $3 = <3> +# $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 \ No newline at end of file