Coverage for src / bluetooth_sig / gatt / characteristics / object_type.py: 97%
32 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"""Object Type characteristic implementation."""
3from __future__ import annotations
5from ..context import CharacteristicContext
6from .base import BaseCharacteristic
7from .utils import DataParser
9_UUID_16BIT_BYTES = 2
10_UUID_128BIT_BYTES = 16
11_UUID_16BIT_HEX_CHARS = 4
12_UUID_128BIT_HEX_CHARS = 32
15class ObjectTypeCharacteristic(BaseCharacteristic[str]):
16 """Object Type characteristic (0x2ABF).
18 org.bluetooth.characteristic.object_type
20 A GATT UUID identifying the type of an object in the Object Transfer
21 Service (OTS). May be a 16-bit (2 bytes) or 128-bit (16 bytes) UUID.
22 """
24 min_length: int = 2
25 max_length: int = 16
27 def _decode_value(self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True) -> str:
28 """Parse object type UUID.
30 Args:
31 data: Raw bytes (2 or 16 bytes).
32 ctx: Optional CharacteristicContext.
33 validate: Whether to validate ranges (default True).
35 Returns:
36 UUID as uppercase hex string (e.g. "2AC3" or full 128-bit).
38 """
39 if len(data) == _UUID_16BIT_BYTES:
40 raw = DataParser.parse_int16(data, 0, signed=False)
41 return f"{raw:04X}"
43 # 128-bit UUID: formatted as standard UUID string
44 # Bytes are little-endian, standard UUID format is big-endian groups
45 parts = [
46 data[3::-1].hex(), # time_low (4 bytes, reversed)
47 data[5:3:-1].hex(), # time_mid (2 bytes, reversed)
48 data[7:5:-1].hex(), # time_hi_and_version (2 bytes, reversed)
49 data[8:10].hex(), # clock_seq (2 bytes, big-endian)
50 data[10:16].hex(), # node (6 bytes, big-endian)
51 ]
52 return "-".join(parts).upper()
54 def _encode_value(self, data: str) -> bytearray:
55 """Encode object type UUID to bytes.
57 Args:
58 data: UUID as hex string (4 chars for 16-bit, or
59 standard UUID format for 128-bit).
61 Returns:
62 Encoded bytes (2 or 16 bytes).
64 """
65 clean = data.replace("-", "").replace(" ", "").upper()
67 if len(clean) == _UUID_16BIT_HEX_CHARS:
68 # 16-bit UUID
69 value = int(clean, 16)
70 return DataParser.encode_int16(value, signed=False)
72 if len(clean) == _UUID_128BIT_HEX_CHARS:
73 # 128-bit UUID: reverse byte order for BLE little-endian groups
74 raw = bytes.fromhex(clean)
75 result = bytearray()
76 result.extend(raw[0:4][::-1]) # time_low reversed
77 result.extend(raw[4:6][::-1]) # time_mid reversed
78 result.extend(raw[6:8][::-1]) # time_hi_and_version reversed
79 result.extend(raw[8:10]) # clock_seq big-endian
80 result.extend(raw[10:16]) # node big-endian
81 return result
83 raise ValueError(f"UUID must be 4 hex chars (16-bit) or 32 hex chars (128-bit), got {len(clean)} chars")