Coverage for src / bluetooth_sig / gatt / characteristics / unknown.py: 82%
22 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"""Unknown characteristic implementation for non-SIG characteristics."""
3from __future__ import annotations
5from typing import Any
7from ...types import CharacteristicInfo
8from ..context import CharacteristicContext
9from .base import BaseCharacteristic
12class UnknownCharacteristic(BaseCharacteristic[bytes]):
13 """Generic characteristic implementation for unknown/non-SIG characteristics.
15 This class provides basic functionality for characteristics that are not
16 defined in the Bluetooth SIG specification. It stores raw data without
17 attempting to parse it into structured types.
18 """
20 # NOTE: Exempt from registry validation — UnknownCharacteristic has no fixed UUID
21 _is_base_class = True
23 _UNKNOWN_PREFIX = "Unknown: "
25 def __init__(
26 self,
27 info: CharacteristicInfo,
28 ) -> None:
29 """Initialize an unknown characteristic.
31 The name is normalised to ``"Unknown: <description>"`` format.
32 If no name is provided, the UUID short form is used as the
33 description.
35 Args:
36 info: CharacteristicInfo object with UUID, name, unit, python_type
38 Raises:
39 ValueError: If UUID is invalid
41 """
42 name = info.name.strip() if info.name else ""
43 if not name:
44 name = f"{self._UNKNOWN_PREFIX}{info.uuid.short_form}"
45 elif not name.startswith(self._UNKNOWN_PREFIX):
46 name = f"{self._UNKNOWN_PREFIX}{name}"
48 info = CharacteristicInfo(
49 uuid=info.uuid,
50 name=name,
51 unit=info.unit or "",
52 python_type=info.python_type,
53 )
55 super().__init__(info=info)
57 def _decode_value(
58 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
59 ) -> bytes: # Context type varies
60 """Return raw bytes for unknown characteristics.
62 Args:
63 data: Raw bytes from the characteristic read
64 ctx: Optional context (ignored)
65 validate: Whether to validate ranges (default True)
67 Returns:
68 Raw bytes as-is
70 """
71 return bytes(data)
73 def _encode_value(self, data: Any) -> bytearray: # noqa: ANN401 # Accepts bytes-like objects
74 """Encode data to bytes for unknown characteristics.
76 Args:
77 data: Data to encode (must be bytes or bytearray)
79 Returns:
80 Encoded bytes
82 Raises:
83 ValueError: If data is not bytes/bytearray
85 """
86 if isinstance(data, (bytes, bytearray)):
87 return bytearray(data)
88 raise ValueError(f"Unknown characteristics require bytes data, got {type(data)}")