Add BLE GATT Device Name probing and WiFi+BLE arrival correlation
ble_alerter.py: probe Apple BLE devices via GATT characteristic 0x2A00 to discover device names (iPhone, Apple TV, etc). Names persist to ble_names.json with last_seen timestamps. GATT_PROBE=1 enables active probing; without it, Apple device last_seen timestamps still tracked. net_alerter.py: on WiFi device arrival, read ble_names.json and log any Apple BLE devices seen within the last 60s as correlation candidates. Gives operator visibility into which BLE MACs co-arrived with a WiFi device. Shared state file: /opt/net_alerter/ble_names.json
This commit is contained in:
@@ -30,6 +30,8 @@ from pathlib import Path
|
||||
LOG_FILE = "/opt/net_alerter/net_alerter.log"
|
||||
OUI_DB_PATH = "/opt/net_alerter/oui.db"
|
||||
ENV_PATH = Path(os.getenv("NET_ALERTER_ENV", "/opt/net_alerter/.env"))
|
||||
BLE_NAMES_FILE = Path("/opt/net_alerter/ble_names.json")
|
||||
BLE_CORRELATION_WINDOW = 60 # seconds — how far back to look for nearby BLE devices
|
||||
|
||||
known_devices = {} # {mac: {ip, hostname, vendor, first_seen, last_seen, infrastructure (opt)}}
|
||||
known_lock = threading.Lock()
|
||||
@@ -984,6 +986,25 @@ def update_occupancy_state() -> None:
|
||||
_update_occupancy_state_unlocked()
|
||||
|
||||
|
||||
def _log_ble_correlation(wifi_mac: str) -> None:
|
||||
"""Log nearby Apple BLE devices seen within BLE_CORRELATION_WINDOW seconds of a WiFi arrival."""
|
||||
try:
|
||||
if not BLE_NAMES_FILE.exists():
|
||||
return
|
||||
data = json.loads(BLE_NAMES_FILE.read_text())
|
||||
now = time.time()
|
||||
nearby = []
|
||||
for ble_mac, entry in data.items():
|
||||
age = now - entry.get("last_seen", 0)
|
||||
if age <= BLE_CORRELATION_WINDOW:
|
||||
name = entry.get("name", "")
|
||||
nearby.append(f"{ble_mac}" + (f" ({name})" if name else ""))
|
||||
if nearby:
|
||||
logging.info(f"[BLE-CORR] WiFi arrival {wifi_mac} — nearby Apple BLE: {', '.join(nearby)}")
|
||||
except Exception as e:
|
||||
logging.debug(f"BLE correlation read failed: {e}")
|
||||
|
||||
|
||||
def on_arrival(mac: str, ip: str, hostname: str = "") -> None:
|
||||
"""Handle device arrival."""
|
||||
# Infrastructure IPs never trigger alerts
|
||||
@@ -1101,6 +1122,7 @@ def on_arrival(mac: str, ip: str, hostname: str = "") -> None:
|
||||
msg = format_arrival(resolved_hostname, resolved_ip, resolved_vendor or "unknown", mac)
|
||||
logging.info(msg)
|
||||
send_alert(msg)
|
||||
_log_ble_correlation(mac)
|
||||
update_occupancy_state()
|
||||
|
||||
t = threading.Timer(2.0, _send_arrival_alert)
|
||||
|
||||
Reference in New Issue
Block a user