Files
intercept/utils/bluetooth/constants.py
T
James Smith 96172ca593 style: apply ruff-format to entire codebase
First-time run of ruff-format via pre-commit hook normalises quote
style, trailing commas, and whitespace across 188 Python files.
No logic changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-05 14:48:11 +01:00

338 lines
10 KiB
Python

"""
Bluetooth-specific constants for the unified scanner.
"""
from __future__ import annotations
# =============================================================================
# SCANNER SETTINGS
# =============================================================================
# Default scan duration in seconds
DEFAULT_SCAN_DURATION = 10
# Maximum concurrent observations per device before pruning
MAX_RSSI_SAMPLES = 300
# Device expiration time (seconds since last seen)
DEVICE_STALE_TIMEOUT = 300 # 5 minutes
# Observation history retention (seconds)
OBSERVATION_HISTORY_RETENTION = 3600 # 1 hour
# =============================================================================
# RSSI THRESHOLDS FOR RANGE BANDS
# =============================================================================
# RSSI ranges for distance estimation (dBm)
RSSI_VERY_CLOSE = -40 # >= -40 dBm
RSSI_CLOSE = -55 # -40 to -55 dBm
RSSI_NEARBY = -70 # -55 to -70 dBm
RSSI_FAR = -85 # -70 to -85 dBm
# Minimum confidence levels for each range band
CONFIDENCE_VERY_CLOSE = 0.7
CONFIDENCE_CLOSE = 0.6
CONFIDENCE_NEARBY = 0.5
CONFIDENCE_FAR = 0.4
# =============================================================================
# HEURISTIC THRESHOLDS
# =============================================================================
# Persistent detection: minimum seen count in analysis window
PERSISTENT_MIN_SEEN_COUNT = 10
PERSISTENT_WINDOW_SECONDS = 300 # 5 minutes
# Beacon-like detection: maximum advertisement interval variance (ratio)
BEACON_INTERVAL_MAX_VARIANCE = 0.10 # 10%
# Strong + Stable detection thresholds
STRONG_RSSI_THRESHOLD = -50 # dBm
STABLE_VARIANCE_THRESHOLD = 5 # dBm variance
# New device window (seconds since baseline set)
NEW_DEVICE_WINDOW = 60
# =============================================================================
# DBUS SETTINGS (BlueZ)
# =============================================================================
# BlueZ DBus service names
BLUEZ_SERVICE = "org.bluez"
BLUEZ_ADAPTER_INTERFACE = "org.bluez.Adapter1"
BLUEZ_DEVICE_INTERFACE = "org.bluez.Device1"
DBUS_PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties"
DBUS_OBJECT_MANAGER_INTERFACE = "org.freedesktop.DBus.ObjectManager"
# DBus paths
BLUEZ_PATH = "/org/bluez"
# Discovery filter settings
DISCOVERY_FILTER_TRANSPORT = "auto" # 'bredr', 'le', or 'auto'
DISCOVERY_FILTER_RSSI = -100 # Minimum RSSI for discovery
DISCOVERY_FILTER_DUPLICATE_DATA = True
# =============================================================================
# FALLBACK SCANNER SETTINGS
# =============================================================================
# bleak scan timeout
BLEAK_SCAN_TIMEOUT = 10.0
# hcitool command timeout
HCITOOL_TIMEOUT = 15.0
# bluetoothctl command timeout
BLUETOOTHCTL_TIMEOUT = 10.0
# btmgmt command timeout
BTMGMT_TIMEOUT = 10.0
# Generic subprocess timeout (short operations)
SUBPROCESS_TIMEOUT_SHORT = 5.0
# =============================================================================
# ADDRESS TYPE CLASSIFICATIONS
# =============================================================================
ADDRESS_TYPE_PUBLIC = "public"
ADDRESS_TYPE_RANDOM = "random"
ADDRESS_TYPE_RANDOM_STATIC = "random_static"
ADDRESS_TYPE_RPA = "rpa" # Resolvable Private Address
ADDRESS_TYPE_NRPA = "nrpa" # Non-Resolvable Private Address
ADDRESS_TYPE_UUID = "uuid" # CoreBluetooth platform UUID (macOS, no real MAC available)
# =============================================================================
# PROTOCOL TYPES
# =============================================================================
PROTOCOL_BLE = "ble"
PROTOCOL_CLASSIC = "classic"
PROTOCOL_AUTO = "auto"
# =============================================================================
# RANGE BAND NAMES
# =============================================================================
RANGE_VERY_CLOSE = "very_close"
RANGE_CLOSE = "close"
RANGE_NEARBY = "nearby"
RANGE_FAR = "far"
RANGE_UNKNOWN = "unknown"
# =============================================================================
# PROXIMITY BANDS (new visualization system)
# =============================================================================
PROXIMITY_IMMEDIATE = "immediate" # < 1m
PROXIMITY_NEAR = "near" # 1-3m
PROXIMITY_FAR = "far" # 3-10m
PROXIMITY_UNKNOWN = "unknown"
# RSSI thresholds for proximity band classification (dBm)
PROXIMITY_RSSI_IMMEDIATE = -40 # >= -40 dBm -> immediate
PROXIMITY_RSSI_NEAR = -55 # >= -55 dBm -> near
PROXIMITY_RSSI_FAR = -75 # >= -75 dBm -> far
# =============================================================================
# DISTANCE ESTIMATION SETTINGS
# =============================================================================
# Path-loss exponent for indoor environments (typical range: 2-4)
DISTANCE_PATH_LOSS_EXPONENT = 2.5
# Reference RSSI at 1 meter (typical BLE value)
DISTANCE_RSSI_AT_1M = -59
# EMA smoothing alpha (higher = more responsive, lower = smoother)
DISTANCE_EMA_ALPHA = 0.3
# Variance thresholds for confidence scoring (dBm^2)
DISTANCE_LOW_VARIANCE = 25.0 # High confidence
DISTANCE_HIGH_VARIANCE = 100.0 # Low confidence
# =============================================================================
# RING BUFFER SETTINGS
# =============================================================================
# Observation retention period (minutes)
RING_BUFFER_RETENTION_MINUTES = 30
# Minimum interval between observations per device (seconds)
RING_BUFFER_MIN_INTERVAL_SECONDS = 2.0
# Maximum observations stored per device
RING_BUFFER_MAX_OBSERVATIONS = 1000
# =============================================================================
# HEATMAP SETTINGS
# =============================================================================
# Default time window for heatmap (minutes)
HEATMAP_DEFAULT_WINDOW_MINUTES = 10
# Default bucket size for downsampling (seconds)
HEATMAP_DEFAULT_BUCKET_SECONDS = 10
# Maximum devices to show in heatmap
HEATMAP_MAX_DEVICES = 50
# =============================================================================
# COMMON MANUFACTURER IDS (OUI -> Name mapping for common vendors)
# =============================================================================
MANUFACTURER_NAMES = {
0x004C: "Apple, Inc.",
0x0006: "Microsoft",
0x000F: "Broadcom",
0x0075: "Samsung Electronics",
0x00E0: "Google",
0x0157: "Xiaomi",
0x0310: "Bose Corporation",
0x0059: "Nordic Semiconductor",
0x0046: "Sony Corporation",
0x0002: "Intel Corporation",
0x0087: "Garmin International",
0x00D2: "Fitbit",
0x0154: "Huawei Technologies",
0x038F: "Tile, Inc.",
0x0301: "Jabra",
0x01DA: "Anker Innovations",
}
# =============================================================================
# BLUETOOTH CLASS OF DEVICE DECODING
# =============================================================================
# Major device classes (bits 12-8 of CoD)
MAJOR_DEVICE_CLASSES = {
0x00: "Miscellaneous",
0x01: "Computer",
0x02: "Phone",
0x03: "LAN/Network Access Point",
0x04: "Audio/Video",
0x05: "Peripheral",
0x06: "Imaging",
0x07: "Wearable",
0x08: "Toy",
0x09: "Health",
0x1F: "Uncategorized",
}
# Minor device classes for Audio/Video (0x04)
MINOR_AUDIO_VIDEO = {
0x00: "Uncategorized",
0x01: "Wearable Headset",
0x02: "Hands-free Device",
0x04: "Microphone",
0x05: "Loudspeaker",
0x06: "Headphones",
0x07: "Portable Audio",
0x08: "Car Audio",
0x09: "Set-top Box",
0x0A: "HiFi Audio Device",
0x0B: "VCR",
0x0C: "Video Camera",
0x0D: "Camcorder",
0x0E: "Video Monitor",
0x0F: "Video Display and Loudspeaker",
0x10: "Video Conferencing",
0x12: "Gaming/Toy",
}
# Minor device classes for Phone (0x02)
MINOR_PHONE = {
0x00: "Uncategorized",
0x01: "Cellular",
0x02: "Cordless",
0x03: "Smartphone",
0x04: "Wired Modem",
0x05: "ISDN Access Point",
}
# Minor device classes for Computer (0x01)
MINOR_COMPUTER = {
0x00: "Uncategorized",
0x01: "Desktop Workstation",
0x02: "Server-class Computer",
0x03: "Laptop",
0x04: "Handheld PC/PDA",
0x05: "Palm-size PC/PDA",
0x06: "Wearable Computer",
0x07: "Tablet",
}
# Minor device classes for Peripheral (0x05)
MINOR_PERIPHERAL = {
0x00: "Not Keyboard/Pointing Device",
0x01: "Keyboard",
0x02: "Pointing Device",
0x03: "Combo Keyboard/Pointing Device",
}
# Minor device classes for Wearable (0x07)
MINOR_WEARABLE = {
0x01: "Wristwatch",
0x02: "Pager",
0x03: "Jacket",
0x04: "Helmet",
0x05: "Glasses",
}
# =============================================================================
# BLE APPEARANCE CODES (GAP Appearance values)
# =============================================================================
BLE_APPEARANCE_NAMES: dict[int, str] = {
0: "Unknown",
64: "Phone",
128: "Computer",
192: "Watch",
193: "Sports Watch",
256: "Clock",
320: "Display",
384: "Remote Control",
448: "Eye Glasses",
512: "Tag",
576: "Keyring",
640: "Media Player",
704: "Barcode Scanner",
768: "Thermometer",
832: "Heart Rate Sensor",
896: "Blood Pressure",
960: "HID",
961: "Keyboard",
962: "Mouse",
963: "Joystick",
964: "Gamepad",
965: "Digitizer Tablet",
966: "Card Reader",
967: "Digital Pen",
968: "Barcode Scanner (HID)",
1024: "Glucose Monitor",
1088: "Running Speed Sensor",
1152: "Cycling",
1216: "Control Device",
1280: "Network Device",
1344: "Sensor",
1408: "Light Fixture",
1472: "Fan",
1536: "HVAC",
1600: "Access Control",
1664: "Motorized Device",
1728: "Power Device",
1792: "Light Source",
3136: "Pulse Oximeter",
3200: "Weight Scale",
3264: "Personal Mobility",
5184: "Outdoor Sports Activity",
}
def get_appearance_name(code: int | None) -> str | None:
"""Look up a human-readable name for a BLE appearance code."""
if code is None:
return None
return BLE_APPEARANCE_NAMES.get(code)