Coverage for src / bluetooth_sig / advertising / state.py: 100%
18 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-18 11:17 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-18 11:17 +0000
1"""Typed state classes for payload interpretation.
3State management is the caller's responsibility (connection manager, device tracker).
4The interpreter receives state, uses it, and returns updated values.
5The caller decides when/how to persist.
7Based on Bluetooth SIG Core Specification Supplement for advertising data patterns
8and real-world implementations (BTHome, Xiaomi MiBeacon, RuuviTag).
9"""
11from __future__ import annotations
13import msgspec
16class EncryptionState(msgspec.Struct, kw_only=True, frozen=False):
17 """Encryption-related state for a device.
19 Caller is responsible for persisting and updating this state.
20 Interpreter reads current values and returns new values.
22 Attributes:
23 bindkey: 16-byte AES-CCM key for decryption (pre-shared).
24 bindkey_verified: Whether bindkey has successfully decrypted a payload.
25 encryption_counter: Monotonically increasing counter for replay protection.
26 BTHome/Xiaomi use 4-byte counter in advertisement payload.
27 decryption_failed: Whether last decryption attempt failed.
29 """
31 bindkey: bytes | None = None
32 bindkey_verified: bool = False
33 encryption_counter: int = 0
34 decryption_failed: bool = False
37class PacketState(msgspec.Struct, kw_only=True, frozen=False):
38 """Packet tracking state for duplicate/replay detection.
40 Caller is responsible for persisting and updating this state.
42 Attributes:
43 packet_id: Last seen packet ID (for BTHome v2 duplicate filtering).
44 last_seen_timestamp: Timestamp of last valid advertisement (Unix epoch seconds).
45 last_service_data_hash: Hash of last service data payload (for same-payload detection).
47 """
49 packet_id: int | None = None
50 last_seen_timestamp: float = 0.0
51 last_service_data_hash: int | None = None
54class DeviceAdvertisingState(msgspec.Struct, kw_only=True, frozen=False):
55 """Complete advertising state for a device.
57 Managed by caller (connection manager, device tracker).
58 Passed to interpreter; interpreter updates state directly.
60 Attributes:
61 address: Device MAC address or platform identifier.
62 encryption: Encryption-related state.
63 packets: Packet tracking state.
64 device_type: Detected device type from payload (e.g., "BTHome sensor").
65 protocol_version: Detected protocol version (e.g., "v2", "MiBeacon v5").
66 is_sleepy_device: Whether device uses irregular advertising intervals.
68 """
70 address: str = ""
71 encryption: EncryptionState = msgspec.field(default_factory=EncryptionState)
72 packets: PacketState = msgspec.field(default_factory=PacketState)
73 device_type: str | None = None
74 protocol_version: str | None = None
75 is_sleepy_device: bool = False