src.bluetooth_sig.advertising.base¶
Base classes for advertising data interpreters.
Advertising data interpretation follows a two-layer architecture:
PDU Parsing (AdvertisingPDUParser): Raw bytes → AD structures - Extracts manufacturer_data, service_data, flags, local_name, etc. - Framework-agnostic, works with raw BLE PDU bytes
Payload Interpretation (PayloadInterpreter): AD structures → typed results - Interprets vendor-specific protocols (BTHome, Xiaomi, RuuviTag, etc.) - Returns strongly-typed sensor data (temperature, humidity, etc.) - State managed externally by caller; interpreter updates state directly - Errors are raised as exceptions (consistent with GATT characteristic parsing)
- Error Handling:
Interpreters raise exceptions for error conditions instead of returning status codes. This is consistent with GATT characteristic parsing.
- Exceptions:
EncryptionRequiredError: Payload encrypted, no bindkey available DecryptionFailedError: Decryption failed (wrong key or corrupt data) ReplayDetectedError: Counter not increasing (potential replay attack) DuplicatePacketError: Same packet_id as previous AdvertisingParseError: General parse failure UnsupportedVersionError: Unknown protocol version
Attributes¶
Name | Description |
|---|---|
Classes¶
Name | Description |
|---|---|
Complete advertising data from a BLE advertisement packet. |
|
Primary data source for interpreter routing. |
|
Interpreter metadata for routing and identification. |
|
Base class for payload interpretation (service data + manufacturer data). |
Module Contents¶
- class src.bluetooth_sig.advertising.base.AdvertisingData¶
Bases:
msgspec.StructComplete advertising data from a BLE advertisement packet.
Encapsulates all extracted AD structures from a BLE PDU. Interpreters access only the fields they need.
- manufacturer_data¶
Company ID → ManufacturerData mapping. Each entry contains resolved company info and payload bytes.
- service_data¶
Service UUID → payload bytes mapping.
- local_name¶
Device local name (may contain protocol info).
- rssi¶
Signal strength in dBm.
- timestamp¶
Advertisement timestamp (Unix epoch seconds).
- manufacturer_data: dict[int, bluetooth_sig.types.company.ManufacturerData]¶
- service_data: dict[bluetooth_sig.types.uuid.BluetoothUUID, bytes]¶
- class src.bluetooth_sig.advertising.base.DataSource(*args, **kwds)¶
Bases:
enum.EnumPrimary data source for interpreter routing.
- LOCAL_NAME = 'local_name'¶
- MANUFACTURER = 'manufacturer'¶
- SERVICE = 'service'¶
- class src.bluetooth_sig.advertising.base.InterpreterInfo¶
Bases:
msgspec.StructInterpreter metadata for routing and identification.
- company_id¶
Bluetooth SIG company ID for manufacturer data routing.
- service_uuid¶
Service UUID for service data routing.
- name¶
Human-readable interpreter name.
- data_source¶
Primary data source for fast routing.
- data_source: DataSource¶
- service_uuid: bluetooth_sig.types.uuid.BluetoothUUID | None = None¶
- class src.bluetooth_sig.advertising.base.PayloadInterpreter(mac_address: str)¶
-
Base class for payload interpretation (service data + manufacturer data).
Interprets raw bytes from BLE advertisements into typed domain objects. State is managed externally by the caller - interpreter receives state and updates it directly. Errors are raised as exceptions.
- Encryption Flow (following BTHome/Xiaomi patterns):
Check if payload is encrypted (flag byte in payload header)
If encrypted, check state.encryption.bindkey
If no bindkey, raise EncryptionRequiredError
Extract counter from payload, compare to state.encryption.encryption_counter
If counter <= old counter, raise ReplayDetectedError
Attempt decryption with AES-CCM
If decryption fails, raise DecryptionFailedError
Parse decrypted payload
Update state.encryption.encryption_counter directly
Return parsed data
Example:
class BTHomeInterpreter(PayloadInterpreter[BTHomeData]): _info = InterpreterInfo( service_uuid=BluetoothUUID("0000fcd2-0000-1000-8000-00805f9b34fb"), name="BTHome", data_source=DataSource.SERVICE, ) @classmethod def supports(cls, advertising_data): return "0000fcd2-0000-1000-8000-00805f9b34fb" in advertising_data.service_data def interpret(self, advertising_data, state): # Parse BTHome service data # Update state.encryption.encryption_counter if encrypted # Raise exceptions on error # Return BTHomeData on success ...
- abstractmethod interpret(advertising_data: AdvertisingData, state: bluetooth_sig.advertising.state.DeviceAdvertisingState) T¶
Interpret payload bytes and return typed result.
Updates state directly (state is mutable). Raises exceptions for errors.
- Parameters:
advertising_data – Complete advertising data from BLE packet.
state – Current device advertising state (caller-managed, mutable).
- Returns:
Parsed data of type T.
- Raises:
EncryptionRequiredError – Payload encrypted, no bindkey available.
DecryptionFailedError – Decryption failed.
ReplayDetectedError – Encryption counter not increasing.
DuplicatePacketError – Same packet_id as previous.
AdvertisingParseError – General parse failure.
UnsupportedVersionError – Unknown protocol version.
- classmethod supports(advertising_data: AdvertisingData) bool¶
- Abstractmethod:
Check if this interpreter handles the advertisement.
Called by registry for fast routing. Should be a quick check based on company_id, service_uuid, or local_name pattern.
- Parameters:
advertising_data – Complete advertising data from BLE packet.
- Returns:
True if this interpreter can handle the advertisement.
- property info: InterpreterInfo¶
Interpreter metadata.
- src.bluetooth_sig.advertising.base.T¶