Files
intercept/utils/bluetooth/constants.py
Smittix 99d52eafe7 chore: Bump version to v2.18.0
Bluetooth enhancements (service data inspector, appearance codes, MAC
cluster tracking, behavioral flags, IRK badges, distance estimation),
ACARS SoapySDR multi-backend support, dump1090 stale process cleanup,
GPS error state, and proximity radar/signal card UI improvements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 15:12:10 +00: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)