_bleio – Bluetooth Low Energy (BLE) communication — Adafruit CircuitPython 1 documentation (original) (raw)

The _bleio module provides necessary low-level functionality for communicating using Bluetooth Low Energy (BLE). The ‘_’ prefix indicates this module is meant for internal use by libraries but not by the end user. Its API may change incompatibly between minor versions of CircuitPython. Please use theadafruit_bleCircuitPython library instead, which builds on _bleio, and provides higher-level convenience functionality, including predefined beacons, clients, servers.

Note

_bleio uses native BLE capability on boards that support it, including Nordic nRF, Espressif (except ESP32-S2 and ESP32-P4), and SiLabs. On other boards, _bleio, if present, supports BLE using an AirLift co-processor. Pico W boards do not support BLE using the on-board CYW43 co-processor, but do support using an external AirLift.

Available on these boards

_bleio.adapter_: Adapter_

BLE Adapter used to manage device discovery and connections. This object is the sole instance of _bleio.Adapter.

exception _bleio.BluetoothError

Bases: Exception

Catchall exception for Bluetooth related errors.

Initialize self. See help(type(self)) for accurate signature.

exception _bleio.RoleError

Bases: BluetoothError

Raised when a resource is used as the mismatched role. For example, if a local CCCD is attempted to be set but they can only be set when remote.

Initialize self. See help(type(self)) for accurate signature.

exception _bleio.SecurityError

Bases: BluetoothError

Raised when a security related error occurs.

Initialize self. See help(type(self)) for accurate signature.

_bleio.set_adapter(adapter: Adapter | None) → None

Set the adapter to use for BLE, such as when using an HCI adapter. Raises NotImplementedError when the adapter is a singleton and cannot be set.

class _bleio.Adapter(*, uart: busio.UART, rts: digitalio.DigitalInOut, cts: digitalio.DigitalInOut)

The BLE Adapter object manages the discovery and connection to other nearby Bluetooth Low Energy devices. This part of the Bluetooth Low Energy Specification is known as Generic Access Profile (GAP).

Discovery of other devices happens during a scanning process that listens for small packets of information, known as advertisements, that are broadcast unencrypted. The advertising packets have two different uses. The first is to broadcast a small piece of data to anyone who cares and and nothing more. These are known as beacons. The second class of advertisement is to promote additional functionality available after the devices establish a connection. For example, a BLE heart rate monitor would advertise that it provides the standard BLE Heart Rate Service.

The Adapter can do both parts of this process: it can scan for other device advertisements and it can advertise its own data. Furthermore, Adapters can accept incoming connections and also initiate connections.

On boards that do not have native BLE, you can use an HCI co-processor. Pass the uart and pins used to communicate with the co-processor, such as an Adafruit AirLift. The co-processor must have been reset and put into BLE mode beforehand by the appropriate pin manipulation. The uart, rts, and cts objects are used to communicate with the HCI co-processor in HCI mode. The Adapter object is enabled during this call.

After instantiating an Adapter, call _bleio.set_adapter() to set _bleio.adapter

On boards with native BLE, you cannot create an instance of _bleio.Adapter; this constructor will raise NotImplementedError. Use _bleio.adapter to access the sole instance already available.

enabled_: bool_

State of the BLE adapter.

address_: Address_

MAC address of the BLE adapter.

name_: str_

name of the BLE adapter used once connected. The name is “CIRCUITPY” + the last four hex digits of adapter.address, to make it easy to distinguish multiple CircuitPython boards.

start_advertising(data: circuitpython_typing.ReadableBuffer, *, scan_response: circuitpython_typing.ReadableBuffer | None = None, connectable: bool = True, anonymous: bool = False, timeout: int = 0, interval: float = 0.1, tx_power: int = 0, directed_to: Address | None = None) → None

Starts advertising until stop_advertising is called or if connectable, another device connects to us.

Warning

If data is longer than 31 bytes, then this will automatically advertise as an extended advertisement that older BLE 4.x clients won’t be able to scan for.

Note

If you set anonymous=True, then a timeout must be specified. If no timeout is specified, then the maximum allowed timeout will be selected automatically.

Parameters:

stop_advertising() → None

Stop sending advertising packets.

start_scan(prefixes: circuitpython_typing.ReadableBuffer = b'', *, buffer_size: int = 512, extended: bool = False, timeout: float | None = None, interval: float = 0.1, window: float = 0.1, minimum_rssi: int = -80, active: bool = True) → Iterable[ScanEntry]

Starts a BLE scan and returns an iterator of results. Advertisements and scan responses are filtered and returned separately.

Parameters:

Returns:

an iterable of _bleio.ScanEntry objects

Return type:

iterable

stop_scan() → None

Stop the current scan.

advertising_: bool_

True when the adapter is currently advertising. (read-only)

connected_: bool_

True when the adapter is connected to another device regardless of who initiated the connection. (read-only)

connections_: Tuple[Connection]_

Tuple of active connections including those initiated through_bleio.Adapter.connect(). (read-only)

connect(address: Address, *, timeout: float) → Connection

Attempts a connection to the device with the given address.

Parameters:

erase_bonding() → None

Erase all bonding information stored in flash memory.

class _bleio.Address(address: circuitpython_typing.ReadableBuffer, address_type: int)

Encapsulates the address of a BLE device.

Create a new Address object encapsulating the address value. The value itself can be one of:

Parameters:

address_bytes_: bytes_

The bytes that make up the device address (read-only).

Note that the bytes object returned is in little-endian order: The least significant byte is address_bytes[0]. So the address will appear to be reversed if you print the raw bytes object. If you print or use str() on the Attribute object itself, the address will be printed in the expected order. For example:

import _bleio _bleio.adapter.address

_bleio.adapter.address.address_bytes b'5\xa8\xed\xf5\x1d\xc8'

type_: int_

The address type (read-only).

One of the integer values: PUBLIC, RANDOM_STATIC, RANDOM_PRIVATE_RESOLVABLE, or RANDOM_PRIVATE_NON_RESOLVABLE.

__eq__(other: object) → bool

Two Address objects are equal if their addresses and address types are equal.

__hash__() → int

Returns a hash for the Address data.

PUBLIC_: int_

A publicly known address, with a company ID (high 24 bits)and company-assigned part (low 24 bits).

RANDOM_STATIC_: int_

A randomly generated address that does not change often. It may never change or may change after a power cycle.

RANDOM_PRIVATE_RESOLVABLE_: int_

An address that is usable when the peer knows the other device’s secret Identity Resolving Key (IRK).

RANDOM_PRIVATE_NON_RESOLVABLE_: int_

A randomly generated address that changes on every connection.

class _bleio.Attribute

Definitions associated with all BLE attributes: characteristics, descriptors, etc.

Attribute is, notionally, a superclass ofCharacteristic and Descriptor, but is not defined as a Python superclass of those classes.

You cannot create an instance of Attribute.

NO_ACCESS_: int_

security mode: access not allowed

OPEN_: int_

security_mode: no security (link is not encrypted)

ENCRYPT_NO_MITM_: int_

security_mode: unauthenticated encryption, without man-in-the-middle protection

ENCRYPT_WITH_MITM_: int_

security_mode: authenticated encryption, with man-in-the-middle protection

LESC_ENCRYPT_WITH_MITM_: int_

security_mode: LESC encryption, with man-in-the-middle protection

SIGNED_NO_MITM_: int_

security_mode: unauthenticated data signing, without man-in-the-middle protection

SIGNED_WITH_MITM_: int_

security_mode: authenticated data signing, without man-in-the-middle protection

class _bleio.Characteristic

Stores information about a BLE service characteristic and allows reading and writing of the characteristic’s value.

There is no regular constructor for a Characteristic. A new local Characteristic can be created and attached to a Service by calling add_to_service(). Remote Characteristic objects are created by Connection.discover_remote_services()as part of remote Services.

classmethod add_to_service(service: Service, uuid: UUID, *, properties: int = 0, read_perm: int = Attribute.OPEN, write_perm: int = Attribute.OPEN, max_length: int = 20, fixed_length: bool = False, initial_value: circuitpython_typing.ReadableBuffer | None = None, user_description: str | None = None) → Characteristic

Create a new Characteristic object, and add it to this Service.

Parameters:

Returns:

the new Characteristic.

deinit() → None

Deinitialises the Characteristic and releases any hardware resources for reuse.

properties_: int_

An int bitmask representing which properties are set, specified as bitwise or’ing of of these possible values.BROADCAST, INDICATE, NOTIFY, READ, WRITE, WRITE_NO_RESPONSE.

uuid_: UUID | None_

The UUID of this characteristic. (read-only)

Will be None if the 128-bit UUID for this characteristic is not known.

value_: bytearray_

The value of this characteristic.

max_length_: int_

The max length of this characteristic.

descriptors_: Descriptor_

A tuple of Descriptor objects related to this characteristic. (read-only)

service_: Service_

The Service this Characteristic is a part of.

set_cccd(*, notify: bool = False, indicate: bool = False) → None

Set the remote characteristic’s CCCD to enable or disable notification and indication.

Parameters:

BROADCAST_: int_

property: allowed in advertising packets

INDICATE_: int_

property: server will indicate to the client when the value is set and wait for a response

NOTIFY_: int_

property: server will notify the client when the value is set

READ_: int_

property: clients may read this characteristic

WRITE_: int_

property: clients may write this characteristic; a response will be sent back

WRITE_NO_RESPONSE_: int_

property: clients may write this characteristic; no response will be sent back

class _bleio.CharacteristicBuffer(characteristic: Characteristic, *, timeout: float = 1.0, buffer_size: int = 64)

Accumulates a Characteristic’s incoming values in a FIFO buffer.

Monitor the given Characteristic. Each time a new value is written to the Characteristic add the newly-written bytes to a FIFO buffer.

Parameters:

read(nbytes: int | None = None) → bytes | None

Read characters. If nbytes is specified then read at most that many bytes. Otherwise, read everything that arrives until the connection times out. Providing the number of bytes expected is highly recommended because it will be faster.

Returns:

Data read

Return type:

bytes or None

readinto(buf: circuitpython_typing.WriteableBuffer, nbytes: int | None = None) → int | None

Read bytes into the buf. Read at most len(buf) bytes.

You may reduce this maximum read using the nbytes argument.

Returns:

number of bytes read and stored into buf

Return type:

int or None (on a non-blocking error)

readline() → bytes

Read a line, ending in a newline character.

Returns:

the line read

Return type:

int or None

in_waiting_: int_

The number of bytes in the input buffer, available to be read

reset_input_buffer() → None

Discard any unread characters in the input buffer.

deinit() → None

Disable permanently.

class _bleio.Connection

A BLE connection to another device. Used to discover and interact with services on the other device.

Usage:

import _bleio

my_entry = None for entry in _bleio.adapter.scan(2.5): if entry.name is not None and entry.name == 'InterestingPeripheral': my_entry = entry break

if not my_entry: raise Exception("'InterestingPeripheral' not found")

connection = _bleio.adapter.connect(my_entry.address, timeout=10)

Connections cannot be made directly. Instead, to initiate a connection use Adapter.connect. Connections may also be made when another device initiates a connection. To use a Connection created by a peer, read the Adapter.connections property.

disconnect() → None

Disconnects from the remote peripheral. Does nothing if already disconnected.

pair(*, bond: bool = True) → None

Pair to the peer to improve security.

Limitation: Currently bond``must be ``True: bonding always occurs.

discover_remote_services(service_uuids_whitelist: Iterable[UUID] | None = None) → Tuple[Service, Ellipsis]

Do BLE discovery for all services or for the given service UUIDS, to find their handles and characteristics, and return the discovered services.Connection.connected must be True.

Parameters:

service_uuids_whitelist (iterable) –

an iterable of UUID objects for the services provided by the peripheral that you want to use.

The peripheral may provide more services, but services not listed are ignored and will not be returned.

If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow.

If the service UUID is 128-bit, or its characteristic UUID’s are 128-bit, you you must have already created a UUID object for that UUID in order for the service or characteristic to be discovered. Creating the UUID causes the UUID to be registered for use. (This restriction may be lifted in the future.)

Returns:

A tuple of _bleio.Service objects provided by the remote peripheral.

connected_: bool_

True if connected to the remote peer.

paired_: bool_

True if paired to the remote peer.

connection_interval_: float_

Time between transmissions in milliseconds. Will be multiple of 1.25ms. Lower numbers increase speed and decrease latency but increase power consumption.

When setting connection_interval, the peer may reject the new interval andconnection_interval will then remain the same.

Apple has additional guidelines that dictate should be a multiple of 15ms except if HID is available. When HID is available Apple devices may accept 11.25ms intervals.

max_packet_length_: int_

The maximum number of data bytes that can be sent in a single transmission, not including overhead bytes.

This is the maximum number of bytes that can be sent in a notification, which must be sent in a single packet. But for a regular characteristic read or write, may be sent in multiple packets, so this limit does not apply.

class _bleio.Descriptor

Stores information about a BLE descriptor.

Descriptors are attached to BLE characteristics and provide contextual information about the characteristic.

There is no regular constructor for a Descriptor. A new local Descriptor can be created and attached to a Characteristic by calling add_to_characteristic(). Remote Descriptor objects are created by Connection.discover_remote_services()as part of remote Characteristics in the remote Services that are discovered.

classmethod add_to_characteristic(characteristic: Characteristic, uuid: UUID, *, read_perm: int = Attribute.OPEN, write_perm: int = Attribute.OPEN, max_length: int = 20, fixed_length: bool = False, initial_value: circuitpython_typing.ReadableBuffer = b'') → Descriptor

Create a new Descriptor object, and add it to this Service.

Parameters:

Returns:

the new Descriptor.

uuid_: UUID_

The descriptor uuid. (read-only)

characteristic_: Characteristic_

The Characteristic this Descriptor is a part of.

value_: bytearray_

The value of this descriptor.

class _bleio.PacketBuffer(characteristic: Characteristic, *, buffer_size: int, max_packet_size: int | None = None)

Accumulates a Characteristic’s incoming packets in a FIFO buffer and facilitates packet aware outgoing writes. A packet’s size is either the characteristic length or the maximum transmission unit (MTU) minus overhead, whichever is smaller. The MTU can change so check incoming_packet_lengthand outgoing_packet_length before creating a buffer to store data.

When we’re the server, we ignore all connections besides the first to subscribe to notifications.

Parameters:

readinto(buf: circuitpython_typing.WriteableBuffer) → int

Reads a single BLE packet into the buf. Raises an exception if the next packet is longer than the given buffer. Use incoming_packet_length to read the maximum length of a single packet.

Returns:

number of bytes read and stored into buf

Return type:

int

write(data: circuitpython_typing.ReadableBuffer, *, header: bytes | None = None) → int

Writes all bytes from data into the same outgoing packet. The bytes from header are included before data when the pending packet is currently empty.

This does not block until the data is sent. It only blocks until the data is pending.

Returns:

number of bytes written. May include header bytes when packet is empty.

Return type:

int

deinit() → None

Disable permanently.

incoming_packet_length_: int_

Maximum length in bytes of a packet we are reading.

outgoing_packet_length_: int_

Maximum length in bytes of a packet we are writing.

class _bleio.ScanEntry

Encapsulates information about a device that was received during scanning. It can be advertisement or scan response data. This object may only be created by a _bleio.ScanResults: it has no user-visible constructor.

Cannot be instantiated directly. Use _bleio.Adapter.start_scan.

matches(prefixes: circuitpython_typing.ReadableBuffer, *, match_all: bool = True) → bool

Returns True if the ScanEntry matches all prefixes when match_all is True. This is stricter than the scan filtering which accepts any advertisements that match any of the prefixes where match_all is False.

address_: Address_

The address of the device (read-only), of type _bleio.Address.

advertisement_bytes_: bytes_

All the advertisement data present in the packet, returned as a bytes object. (read-only)

The signal strength of the device at the time of the scan, in integer dBm. (read-only)

connectable_: bool_

True if the device can be connected to. (read-only)

scan_response_: bool_

True if the entry was a scan response. (read-only)

class _bleio.ScanResults

Iterates over advertising data received while scanning. This object is always created by a _bleio.Adapter: it has no user-visible constructor.

Cannot be instantiated directly. Use _bleio.Adapter.start_scan.

__iter__() → Iterator[ScanEntry]

Returns itself since it is the iterator.

__next__() → ScanEntry

Returns the next _bleio.ScanEntry. Blocks if none have been received and scanning is still active. Raises StopIteration if scanning is finished and no other results are available.

class _bleio.Service(uuid: UUID, *, secondary: bool = False)

Stores information about a BLE service and its characteristics.

Create a new Service identified by the specified UUID. It can be accessed by all connections. This is known as a Service server. Client Service objects are created viaConnection.discover_remote_services.

To mark the Service as secondary, pass True as secondary.

Parameters:

Returns:

the new Service

deinit() → None

Disable and deinitialise the Service.

characteristics_: Tuple[Characteristic, Ellipsis]_

A tuple of Characteristic designating the characteristics that are offered by this service. (read-only)

remote_: bool_

True if this is a service provided by a remote device. (read-only)

secondary_: bool_

True if this is a secondary service. (read-only)

uuid_: UUID | None_

The UUID of this service. (read-only)

Will be None if the 128-bit UUID for this service is not known.

class _bleio.UUID(value: int | circuitpython_typing.ReadableBuffer | str)

A 16-bit or 128-bit UUID. Can be used for services, characteristics, descriptors and more.

Create a new UUID or UUID object encapsulating the uuid value. The value can be one of:

Creating a 128-bit UUID registers the UUID with the onboard BLE software, and provides a temporary 16-bit UUID that can be used in place of the full 128-bit UUID.

Parameters:

value (int, ReadableBuffer or str) – The uuid value to encapsulate

uuid16_: int_

The 16-bit part of the UUID. (read-only)

Type:

int

uuid128_: bytes_

The 128-bit value of the UUID Raises AttributeError if this is a 16-bit UUID. (read-only)

Type:

bytes

size_: int_

128 if this UUID represents a 128-bit vendor-specific UUID. 16 if this UUID represents a 16-bit Bluetooth SIG assigned UUID. (read-only) 32-bit UUIDs are not currently supported.

Type:

int

pack_into(buffer: circuitpython_typing.WriteableBuffer, offset: int = 0) → None

Packs the UUID into the given buffer at the given offset.

__eq__(other: object) → bool

Two UUID objects are equal if their values match and they are both 128-bit or both 16-bit.