Coverage for src / bluetooth_sig / types / peripheral_types.py: 100%
40 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"""Data structures for BLE peripheral/GATT server definitions.
3This module provides the data structures used to define GATT services
4and characteristics for peripheral devices. These are used by
5PeripheralManagerProtocol implementations.
7Analogous to device_types.py and connected.py structures on the client side.
8"""
10from __future__ import annotations
12from collections.abc import Callable
13from dataclasses import dataclass, field
14from typing import Any
16from bluetooth_sig.gatt.characteristics.base import BaseCharacteristic
17from bluetooth_sig.types.gatt_enums import GattProperty
18from bluetooth_sig.types.uuid import BluetoothUUID
21@dataclass
22class CharacteristicDefinition:
23 """Definition for a GATT characteristic to be hosted on a peripheral.
25 This bridges bluetooth-sig characteristic classes with the peripheral backend.
26 Use `from_characteristic()` to create from a BaseCharacteristic instance.
28 Attributes:
29 uuid: The UUID of the characteristic (16-bit short or 128-bit full).
30 properties: GATT properties (read, write, notify, indicate, etc.).
31 initial_value: Initial value to serve when clients read the characteristic.
32 readable: Whether clients can read this characteristic.
33 writable: Whether clients can write to this characteristic.
34 on_read: Optional callback to dynamically generate value on read requests.
35 on_write: Optional callback when clients write to this characteristic.
37 """
39 uuid: BluetoothUUID
40 """The UUID of the characteristic (16-bit short or 128-bit full)."""
42 properties: GattProperty
43 """GATT properties (read, write, notify, indicate, etc.)."""
45 initial_value: bytearray = field(default_factory=bytearray)
46 """Initial value to serve when clients read the characteristic."""
48 readable: bool = True
49 """Whether clients can read this characteristic."""
51 writable: bool = False
52 """Whether clients can write to this characteristic."""
54 on_read: Callable[[], bytearray] | None = None
55 """Optional callback to dynamically generate value on read requests."""
57 on_write: Callable[[bytearray], None] | None = None
58 """Optional callback when clients write to this characteristic."""
60 @classmethod
61 def from_characteristic(
62 cls,
63 characteristic: BaseCharacteristic[Any],
64 value: Any, # noqa: ANN401
65 *,
66 properties: GattProperty | None = None,
67 on_read: Callable[[], bytearray] | None = None,
68 on_write: Callable[[bytearray], None] | None = None,
69 ) -> CharacteristicDefinition:
70 """Create a CharacteristicDefinition from a bluetooth-sig characteristic.
72 This uses the characteristic's `build_value()` method to encode the
73 initial value, demonstrating the library's encoding capabilities.
75 Args:
76 characteristic: The bluetooth-sig characteristic class instance
77 value: The Python value to encode as the initial characteristic value
78 properties: GATT properties. If None, defaults to READ + NOTIFY.
79 on_read: Optional callback for dynamic value generation
80 on_write: Optional callback for write handling
82 Returns:
83 CharacteristicDefinition ready for use with PeripheralManagerProtocol
85 Example::
86 >>> from bluetooth_sig.gatt.characteristics import BatteryLevelCharacteristic
87 >>> char = BatteryLevelCharacteristic()
88 >>> defn = CharacteristicDefinition.from_characteristic(char, 85)
89 >>> defn.initial_value
90 bytearray(b'U') # 85 encoded as single byte
92 """
93 # Encode the value using the characteristic's build_value method
94 encoded = characteristic.build_value(value)
96 # Default properties: readable + notify
97 if properties is None:
98 properties = GattProperty.READ | GattProperty.NOTIFY
100 # Determine read/write from properties
101 readable = bool(properties & GattProperty.READ)
102 writable = bool(properties & (GattProperty.WRITE | GattProperty.WRITE_WITHOUT_RESPONSE))
104 return cls(
105 uuid=BluetoothUUID(str(characteristic.uuid)),
106 properties=properties,
107 initial_value=encoded,
108 readable=readable,
109 writable=writable,
110 on_read=on_read,
111 on_write=on_write,
112 )
115@dataclass
116class ServiceDefinition:
117 """Definition for a GATT service to be hosted on a peripheral.
119 Attributes:
120 uuid: The UUID of the service (16-bit short or 128-bit full).
121 characteristics: List of characteristics in this service.
122 primary: Whether this is a primary service (vs secondary/included).
124 """
126 uuid: BluetoothUUID
127 """The UUID of the service (16-bit short or 128-bit full)."""
129 characteristics: list[CharacteristicDefinition] = field(default_factory=list)
130 """List of characteristics in this service."""
132 primary: bool = True
133 """Whether this is a primary service (vs secondary/included)."""
136__all__ = [
137 "CharacteristicDefinition",
138 "ServiceDefinition",
139]