Coverage for src / bluetooth_sig / types / bss.py: 100%
25 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
1"""Types for the Binary Sensor Service (BSS).
3References:
4 Bluetooth SIG Binary Sensor Service 1.0, Sections 3.1.1.1 and 4.2.1
5"""
7from __future__ import annotations
9from enum import IntEnum
11import msgspec
14class BSSMessageID(IntEnum):
15 """BSS Message IDs as per BSS v1.0 Table 4.3."""
17 GET_SENSOR_STATUS_COMMAND = 0x00
18 GET_SENSOR_STATUS_RESPONSE = 0x01
19 SETTING_SENSOR_COMMAND = 0x02
20 SETTING_SENSOR_RESPONSE = 0x03
21 SENSOR_STATUS_EVENT = 0x04
24class SplitHeader(msgspec.Struct, frozen=True, kw_only=True):
25 """BSS Split Header as per BSS v1.0 Table 3.3.
27 Bit layout (uint8):
28 Bit 0: Execute Flag (1 = final/non-split, 0 = split packet)
29 Bits 1-5: Sequence Number (0-31)
30 Bit 6: RFU
31 Bit 7: Source Flag (0 = client→server, 1 = server→client)
33 Attributes:
34 execute_flag: True if this is the final (or only) packet.
35 sequence_number: Sequence order of split packets (0-31).
36 source_flag: True if direction is server→client.
38 """
40 execute_flag: bool
41 sequence_number: int
42 source_flag: bool
44 _EXECUTE_FLAG_MASK = 0x01
45 _SEQUENCE_NUMBER_MASK = 0x1F
46 _SEQUENCE_NUMBER_SHIFT = 1
47 _SOURCE_FLAG_MASK = 0x80
48 _SOURCE_FLAG_SHIFT = 7
50 @staticmethod
51 def from_byte(value: int) -> SplitHeader:
52 """Parse a Split Header from a raw uint8."""
53 return SplitHeader(
54 execute_flag=bool(value & SplitHeader._EXECUTE_FLAG_MASK),
55 sequence_number=(value >> SplitHeader._SEQUENCE_NUMBER_SHIFT) & SplitHeader._SEQUENCE_NUMBER_MASK,
56 source_flag=bool(value & SplitHeader._SOURCE_FLAG_MASK),
57 )
59 def to_byte(self) -> int:
60 """Encode the Split Header to a raw uint8."""
61 if not 0 <= self.sequence_number <= self._SEQUENCE_NUMBER_MASK:
62 raise ValueError(
63 f"sequence_number must be in range 0-{self._SEQUENCE_NUMBER_MASK}, got {self.sequence_number}"
64 )
66 return (
67 (int(self.execute_flag) & self._EXECUTE_FLAG_MASK)
68 | ((self.sequence_number & self._SEQUENCE_NUMBER_MASK) << self._SEQUENCE_NUMBER_SHIFT)
69 | (int(self.source_flag) << self._SOURCE_FLAG_SHIFT)
70 )