Coverage for src / bluetooth_sig / gatt / characteristics / esl_address.py: 100%
22 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"""ESL Address characteristic implementation.
3Per ESL Service v1.0 §3.1.1, the ESL Address is a 16-bit value:
4 - Bits 0-7: ESL_ID (8-bit, range 0x00-0xFE; 0xFF = Broadcast Address)
5 - Bits 8-14: Group_ID (7-bit, range 0-127)
6 - Bit 15: RFU (Reserved for Future Use)
7"""
9from __future__ import annotations
11import msgspec
13from ...types.gatt_enums import CharacteristicRole
14from ..context import CharacteristicContext
15from .base import BaseCharacteristic
16from .utils import DataParser
18ESL_ID_MASK = 0x00FF
19GROUP_ID_MASK = 0x7F00
20GROUP_ID_SHIFT = 8
23class ESLAddressData(msgspec.Struct, frozen=True, kw_only=True):
24 """Parsed ESL Address fields.
26 Attributes:
27 esl_id: ESL identifier (bits 0-7, range 0x00-0xFF).
28 group_id: Group identifier (bits 8-14, range 0-127).
29 """
31 esl_id: int
32 group_id: int
35class ESLAddressCharacteristic(BaseCharacteristic[ESLAddressData]):
36 """ESL Address characteristic (0x2BF6).
38 org.bluetooth.characteristic.esl_address
40 A 16-bit ESL address where bits 0-7 are the ESL ID, bits 8-14 are
41 the Group ID, and bit 15 is reserved for future use (RFU).
42 """
44 _manual_role = CharacteristicRole.INFO
45 expected_length: int = 2
46 min_length: int = 2
48 def _decode_value(
49 self,
50 data: bytearray,
51 ctx: CharacteristicContext | None = None,
52 *,
53 validate: bool = True,
54 ) -> ESLAddressData:
55 """Parse ESL address into ESL_ID and Group_ID fields.
57 Args:
58 data: Raw bytes (2 bytes, little-endian uint16).
59 ctx: Optional CharacteristicContext.
60 validate: Whether to validate ranges (default True).
62 Returns:
63 ESLAddressData with esl_id and group_id.
65 """
66 raw = DataParser.parse_int16(data, 0, signed=False)
67 return ESLAddressData(
68 esl_id=raw & ESL_ID_MASK,
69 group_id=(raw & GROUP_ID_MASK) >> GROUP_ID_SHIFT,
70 )
72 def _encode_value(self, data: ESLAddressData) -> bytearray:
73 """Encode ESL address fields to bytes.
75 Args:
76 data: ESLAddressData with esl_id and group_id.
78 Returns:
79 Encoded bytes (2 bytes, little-endian uint16).
81 """
82 raw = (data.esl_id & ESL_ID_MASK) | ((data.group_id << GROUP_ID_SHIFT) & GROUP_ID_MASK)
83 return DataParser.encode_int16(raw, signed=False)