src.bluetooth_sig.device.peripheral¶
Peripheral manager protocol for BLE GATT server adapters.
Defines an async abstract base class that peripheral adapter implementations (bless, bluez_peripheral, etc.) must inherit from to create BLE GATT servers that broadcast services and characteristics.
This is the server-side counterpart to ClientManagerProtocol. Where clients connect TO devices and READ/PARSE data, peripherals ARE devices that ENCODE and BROADCAST data for others to read.
Adapters must provide async implementations of all abstract methods below.
- TODO: PeripheralDevice exists in peripheral_device.py with core functionality.
Remaining gaps to address (see ROADMAP.md Workstream F): - Subscription management (on_subscribe/on_unsubscribe, subscribed_clients tracking) - Client event callbacks (on_client_connected/on_client_disconnected) - Read/write request handling (typed on_read_request/on_write_request) - Descriptor hosting (CCCD, User Description, Presentation Format)
Classes¶
Name | Description |
|---|---|
Abstract base class for BLE peripheral/GATT server implementations. |
Module Contents¶
- class src.bluetooth_sig.device.peripheral.PeripheralManagerProtocol(name: str)¶
Bases:
abc.ABCAbstract base class for BLE peripheral/GATT server implementations.
This protocol defines the interface for creating BLE peripherals that broadcast services and characteristics. Implementations wrap backend libraries like bless, bluez_peripheral, etc.
Uses a fluent builder pattern for advertisement configuration - call configuration methods before start() to customise advertising.
The workflow is: 1. Create peripheral manager with a device name 2. Configure advertising (optional): with_manufacturer_data(), with_tx_power(), etc. 3. Add services and characteristics (using CharacteristicDefinition) 4. Start advertising 5. Update characteristic values as needed 6. Stop when done
- Example::
>>> from bluetooth_sig.gatt.characteristics import BatteryLevelCharacteristic >>> from bluetooth_sig.gatt.services import BatteryService >>> from bluetooth_sig.types.company import ManufacturerData >>> >>> # Create peripheral with fluent configuration >>> peripheral = SomePeripheralManager("My Sensor") >>> peripheral.with_tx_power(-10).with_connectable(True) >>> >>> # Define a service with battery level >>> char = BatteryLevelCharacteristic() >>> char_def = CharacteristicDefinition.from_characteristic(char, 85) >>> >>> service = ServiceDefinition( ... uuid=BatteryService.get_class_uuid(), ... characteristics=[char_def], ... ) >>> >>> await peripheral.add_service(service) >>> await peripheral.start() >>> >>> # Later, update the battery level >>> await peripheral.update_characteristic("2A19", char.build_value(75))
- async add_service(service: bluetooth_sig.types.peripheral_types.ServiceDefinition) None¶
Add a GATT service to the peripheral.
Services must be added before calling start(). Each service contains one or more characteristics that clients can interact with.
- Parameters:
service – The service definition to add
- Raises:
RuntimeError – If called after start()
- get_characteristic_definition(char_uuid: str | bluetooth_sig.types.uuid.BluetoothUUID) bluetooth_sig.types.peripheral_types.CharacteristicDefinition | None¶
Get the characteristic definition by UUID.
- Parameters:
char_uuid – UUID of the characteristic.
- Returns:
CharacteristicDefinition if found, None otherwise.
- abstractmethod get_characteristic_value(char_uuid: str | bluetooth_sig.types.uuid.BluetoothUUID) bytearray¶
- Async:
Get the current value of a characteristic.
- Parameters:
char_uuid – UUID of the characteristic
- Returns:
The current encoded value
- Raises:
KeyError – If characteristic UUID not found
- set_read_callback(char_uuid: str | bluetooth_sig.types.uuid.BluetoothUUID, callback: collections.abc.Callable[[], bytearray]) None¶
Set a callback for dynamic read value generation.
When a client reads the characteristic, this callback will be invoked to generate the current value instead of returning the stored value.
- Parameters:
char_uuid – UUID of the characteristic
callback – Function that returns the encoded value to serve
- Raises:
KeyError – If characteristic UUID not found
- set_write_callback(char_uuid: str | bluetooth_sig.types.uuid.BluetoothUUID, callback: collections.abc.Callable[[bytearray], None]) None¶
Set a callback for handling client writes.
When a client writes to the characteristic, this callback will be invoked with the written data.
- Parameters:
char_uuid – UUID of the characteristic
callback – Function called with the written data
- Raises:
KeyError – If characteristic UUID not found
- abstractmethod start() None¶
- Async:
Start advertising and accepting connections.
Backend implementations must: 1. Create the platform-specific GATT server 2. Register all services and characteristics from self._services 3. Configure advertisement data from self._manufacturer_data, etc. 4. Begin advertising
- Raises:
RuntimeError – If no services have been added
- abstractmethod update_characteristic(char_uuid: str | bluetooth_sig.types.uuid.BluetoothUUID, value: bytearray, *, notify: bool = True) None¶
- Async:
Update a characteristic’s value.
This sets the new value that will be returned when clients read the characteristic. If notify=True and the characteristic supports notifications, subscribed clients will be notified of the change.
- Parameters:
char_uuid – UUID of the characteristic to update
value – New encoded value (use characteristic.build_value() to encode)
notify – If True, notify subscribed clients of the change
- Raises:
KeyError – If characteristic UUID not found
RuntimeError – If peripheral not started
- with_connectable(connectable: bool) Self¶
Set whether the peripheral accepts connections.
- Parameters:
connectable – True to accept connections (default), False for broadcast only.
- Returns:
Self for method chaining.
- Raises:
RuntimeError – If called after start().
- with_discoverable(discoverable: bool) Self¶
Set whether the peripheral is discoverable.
- Parameters:
discoverable – True to be discoverable (default), False otherwise.
- Returns:
Self for method chaining.
- Raises:
RuntimeError – If called after start().
- with_manufacturer_data(manufacturer_data: bluetooth_sig.types.company.ManufacturerData) Self¶
Set manufacturer-specific advertising data.
- Parameters:
manufacturer_data – ManufacturerData instance from the types module.
- Returns:
Self for method chaining.
- Raises:
RuntimeError – If called after start().
- Example::
>>> from bluetooth_sig.types.company import ManufacturerData >>> mfr = ManufacturerData.from_id_and_payload(0x004C, b"\x02\x15...") >>> peripheral.with_manufacturer_data(mfr)
- with_manufacturer_id(company_id: int | bluetooth_sig.types.company.CompanyIdentifier, payload: bytes) Self¶
Set manufacturer data from company ID and payload.
- Parameters:
company_id – Bluetooth SIG company identifier (e.g., 0x004C for Apple) or CompanyIdentifier instance.
payload – Manufacturer-specific payload bytes.
- Returns:
Self for method chaining.
- Raises:
RuntimeError – If called after start().
- Example::
>>> peripheral.with_manufacturer_id(0x004C, b"\x02\x15...")
- with_service_data(service_uuid: bluetooth_sig.types.uuid.BluetoothUUID, data: bytes) Self¶
Add service data to advertisement.
- Parameters:
service_uuid – BluetoothUUID of the service.
data – Service-specific data bytes.
- Returns:
Self for method chaining.
- Raises:
RuntimeError – If called after start().
- Example::
>>> from bluetooth_sig.gatt.services import BatteryService >>> peripheral.with_service_data( ... BatteryService.get_class_uuid(), ... b"\x50", # 80% battery ... )
- with_tx_power(power_dbm: int) Self¶
Set TX power level for advertising.
- Parameters:
power_dbm – Transmission power in dBm (-127 to +127).
- Returns:
Self for method chaining.
- Raises:
RuntimeError – If called after start().
- property connected_clients: int¶
- Abstractmethod:
Get the number of currently connected clients.
- Returns:
Number of connected BLE centrals
- Raises:
NotImplementedError – If backend doesn’t track connections
- property is_advertising: bool¶
- Abstractmethod:
Check if the peripheral is currently advertising.
- Returns:
True if advertising, False otherwise
- property is_connectable_config: bool¶
Get the connectable configuration.
- Returns:
True if peripheral is configured to accept connections.
- property is_discoverable_config: bool¶
Get the discoverable configuration.
- Returns:
True if peripheral is configured to be discoverable.
- property manufacturer_data: bluetooth_sig.types.company.ManufacturerData | None¶
Get the configured manufacturer data.
- Returns:
ManufacturerData if configured, None otherwise.
- property name: str¶
Get the advertised device name.
- Returns:
The device name as it appears to BLE scanners
- property service_data: dict[bluetooth_sig.types.uuid.BluetoothUUID, bytes]¶
Get the configured service data.
- Returns:
Dictionary mapping service UUIDs to data bytes.
- property services: list[bluetooth_sig.types.peripheral_types.ServiceDefinition]¶
Get the list of registered services.
- Returns:
List of ServiceDefinition objects added to this peripheral.