:mod:`_bleio`
=============
.. py:module:: _bleio
.. autoapi-nested-parse::
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 the
`adafruit_ble `_
CircuitPython library instead, which builds on `_bleio`, and
provides higher-level convenience functionality, including predefined beacons, clients,
servers.
.. attribute:: adapter
BLE Adapter used to manage device discovery and connections.
This object is the sole instance of `_bleio.Adapter`.
.. py:class:: BluetoothError(Exception: Any)
.. py:class:: ConnectionError(BluetoothError: Any)
.. py:class:: RoleError(BluetoothError: Any)
.. py:class:: SecurityError(BluetoothError: Any)
.. py:class:: Adapter
BLE adapter
The Adapter 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 keyboard may advertise that it can provide key information, but not what the key info is.
The built-in BLE 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.
.. attribute:: enabled
:annotation: :Any
State of the BLE adapter.
.. attribute:: address
:annotation: :Any
MAC address of the BLE adapter. (read-only)
.. attribute:: name
:annotation: :Any
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.
.. attribute:: advertising
:annotation: :Any
True when the adapter is currently advertising. (read-only)
.. attribute:: connected
:annotation: :Any
True when the adapter is connected to another device regardless of who initiated the
connection. (read-only)
.. attribute:: connections
:annotation: :Any
Tuple of active connections including those initiated through
:py:meth:`_bleio.Adapter.connect`. (read-only)
.. method:: start_advertising(self, data: buf, *, scan_response: buf = None, connectable: bool = True, anonymous: bool = False, timeout: int = 0, interval: float = 0.1)
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.
:param buf data: advertising data packet bytes
:param buf scan_response: scan response data packet bytes. ``None`` if no scan response is needed.
:param bool connectable: If `True` then other devices are allowed to connect to this peripheral.
:param bool anonymous: If `True` then this device's MAC address is randomized before advertising.
:param int timeout: If set, we will only advertise for this many seconds.
:param float interval: advertising interval, in seconds
.. method:: stop_advertising(self)
Stop sending advertising packets.
.. method:: start_scan(self, prefixes: sequence = b'', *, buffer_size: int = 512, extended: bool = False, timeout: float = None, interval: float = 0.1, window: float = 0.1, minimum_rssi: int = -80, active: bool = True)
Starts a BLE scan and returns an iterator of results. Advertisements and scan responses are
filtered and returned separately.
:param sequence prefixes: Sequence of byte string prefixes to filter advertising packets
with. A packet without an advertising structure that matches one of the prefixes is
ignored. Format is one byte for length (n) and n bytes of prefix and can be repeated.
:param int buffer_size: the maximum number of advertising bytes to buffer.
:param bool extended: When True, support extended advertising packets. Increasing buffer_size is recommended when this is set.
:param float timeout: the scan timeout in seconds. If None, will scan until `stop_scan` is called.
:param float interval: the interval (in seconds) between the start of two consecutive scan windows
Must be in the range 0.0025 - 40.959375 seconds.
:param float window: the duration (in seconds) to scan a single BLE channel.
window must be <= interval.
:param int minimum_rssi: the minimum rssi of entries to return.
:param bool active: retrieve scan responses for scannable advertisements.
:returns: an iterable of `_bleio.ScanEntry` objects
:rtype: iterable
.. method:: stop_scan(self)
Stop the current scan.
.. method:: connect(self, address: Address, *, timeout: float / int)
Attempts a connection to the device with the given address.
:param Address address: The address of the peripheral to connect to
:param float/int timeout: Try to connect for timeout seconds.
.. method:: erase_bonding(self)
Erase all bonding information stored in flash memory.
.. py:class:: Address(address: buf, address_type: Any)
Encapsulates the address of a BLE device.
.. attribute:: address_bytes
:annotation: :Any
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 :py:class:`~_bleio.Attribute` object itself, the address will be printed
in the expected order. For example:
.. code-block:: pycon
>>> import _bleio
>>> _bleio.adapter.address
>>> _bleio.adapter.address.address_bytes
b'5\\xa8\\xed\\xf5\\x1d\\xc8'
.. attribute:: type
:annotation: :Any
The address type (read-only).
One of the integer values: `PUBLIC`, `RANDOM_STATIC`, `RANDOM_PRIVATE_RESOLVABLE`,
or `RANDOM_PRIVATE_NON_RESOLVABLE`.
.. attribute:: PUBLIC
:annotation: :Any
A publicly known address, with a company ID (high 24 bits)and company-assigned part (low 24 bits).
.. attribute:: RANDOM_STATIC
:annotation: :Any
A randomly generated address that does not change often. It may never change or may change after
a power cycle.
.. attribute:: RANDOM_PRIVATE_RESOLVABLE
:annotation: :Any
An address that is usable when the peer knows the other device's secret Identity Resolving Key (IRK).
.. attribute:: RANDOM_PRIVATE_NON_RESOLVABLE
:annotation: :Any
A randomly generated address that changes on every connection.
.. method:: __eq__(self, other: Any)
Two Address objects are equal if their addresses and address types are equal.
.. method:: __hash__(self)
Returns a hash for the Address data.
.. py:class:: Attribute
Definitions associated with all BLE attributes: characteristics, descriptors, etc.
:py:class:`~_bleio.Attribute` is, notionally, a superclass of
:py:class:`~Characteristic` and :py:class:`~Descriptor`,
but is not defined as a Python superclass of those classes.
.. attribute:: NO_ACCESS
:annotation: :Any
security mode: access not allowed
.. attribute:: OPEN
:annotation: :Any
security_mode: no security (link is not encrypted)
.. attribute:: ENCRYPT_NO_MITM
:annotation: :Any
security_mode: unauthenticated encryption, without man-in-the-middle protection
.. attribute:: ENCRYPT_WITH_MITM
:annotation: :Any
security_mode: authenticated encryption, with man-in-the-middle protection
.. attribute:: LESC_ENCRYPT_WITH_MITM
:annotation: :Any
security_mode: LESC encryption, with man-in-the-middle protection
.. attribute:: SIGNED_NO_MITM
:annotation: :Any
security_mode: unauthenticated data signing, without man-in-the-middle protection
.. attribute:: SIGNED_WITH_MITM
:annotation: :Any
security_mode: authenticated data signing, without man-in-the-middle protection
.. py:class:: Characteristic
Stores information about a BLE service characteristic and allows reading
and writing of the characteristic's value.
.. attribute:: properties
:annotation: :Any
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`.
.. attribute:: uuid
:annotation: :Any
The UUID of this characteristic. (read-only)
Will be ``None`` if the 128-bit UUID for this characteristic is not known.
.. attribute:: value
:annotation: :Any
The value of this characteristic.
.. attribute:: descriptors
:annotation: :Any
A tuple of :py:class:`Descriptor` that describe this characteristic. (read-only)
.. attribute:: service
:annotation: :Any
The Service this Characteristic is a part of.
.. attribute:: BROADCAST
:annotation: :Any
property: allowed in advertising packets
.. attribute:: INDICATE
:annotation: :Any
property: server will indicate to the client when the value is set and wait for a response
.. attribute:: NOTIFY
:annotation: :Any
property: server will notify the client when the value is set
.. attribute:: READ
:annotation: :Any
property: clients may read this characteristic
.. attribute:: WRITE
:annotation: :Any
property: clients may write this characteristic; a response will be sent back
.. attribute:: WRITE_NO_RESPONSE
:annotation: :Any
property: clients may write this characteristic; no response will be sent back
.. method:: add_to_service(self, 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: buf = None)
Create a new Characteristic object, and add it to this Service.
:param Service service: The service that will provide this characteristic
:param UUID uuid: The uuid of the characteristic
:param int properties: The properties of the characteristic,
specified as a bitmask of these values bitwise-or'd together:
`BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`.
:param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which
security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`,
`Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`,
`Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`.
:param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which
security mode is required. Values allowed are the same as ``read_perm``.
:param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is
is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum
number of data bytes that fit in a single BLE 4.x ATT packet.
:param bool fixed_length: True if the characteristic value is of fixed length.
:param buf initial_value: The initial value for this characteristic. If not given, will be
filled with zeros.
:return: the new Characteristic.
.. method:: set_cccd(self, *, notify: bool = False, indicate: float = False)
Set the remote characteristic's CCCD to enable or disable notification and indication.
:param bool notify: True if Characteristic should receive notifications of remote writes
:param float indicate: True if Characteristic should receive indications of remote writes
.. py:class:: CharacteristicBuffer(characteristic: Characteristic, *, timeout: int = 1, buffer_size: int = 64)
Accumulates a Characteristic's incoming values in a FIFO buffer.
.. attribute:: in_waiting
:annotation: :Any
The number of bytes in the input buffer, available to be read
.. method:: read(self, nbytes: Any = 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.
:return: Data read
:rtype: bytes or None
.. method:: readinto(self, buf: Any)
Read bytes into the ``buf``. Read at most ``len(buf)`` bytes.
:return: number of bytes read and stored into ``buf``
:rtype: int or None (on a non-blocking error)
.. method:: readline(self)
Read a line, ending in a newline character.
:return: the line read
:rtype: int or None
.. method:: reset_input_buffer(self)
Discard any unread characters in the input buffer.
.. method:: deinit(self)
Disable permanently.
.. py:class:: 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)
.. attribute:: connected
:annotation: :Any
True if connected to the remote peer.
.. attribute:: paired
:annotation: :Any
True if paired to the remote peer.
.. attribute:: connection_interval
:annotation: :Any
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 and
`connection_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.
.. attribute:: attribute
:annotation: :Any
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.
.. method:: pair(self, *, bond: Any = True)
Pair to the peer to improve security.
.. method:: discover_remote_services(self, service_uuids_whitelist: iterable = None)
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.
:param iterable service_uuids_whitelist:
an iterable of :py:class:~`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 :py:class:~`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.)
:return: A tuple of `_bleio.Service` objects provided by the remote peripheral.
.. py:class:: Descriptor
Stores information about a BLE descriptor.
Descriptors are attached to BLE characteristics and provide contextual
information about the characteristic.
.. attribute:: uuid
:annotation: :Any
The descriptor uuid. (read-only)
.. attribute:: characteristic
:annotation: :Any
The Characteristic this Descriptor is a part of.
.. attribute:: value
:annotation: :Any
The value of this descriptor.
.. py:class:: PacketBuffer(characteristic: Characteristic, *, buffer_size: int)
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_length`
and `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.
.. attribute:: packet_size
:annotation: :int
`packet_size` is the same as `incoming_packet_length`.
The name `packet_size` is deprecated and
will be removed in CircuitPython 6.0.0.
.. attribute:: incoming_packet_length
:annotation: :Any
Maximum length in bytes of a packet we are reading.
.. attribute:: outgoing_packet_length
:annotation: :int
Maximum length in bytes of a packet we are writing.
.. method:: readinto(self, buf: Any)
Reads a single BLE packet into the ``buf``. Raises an exception if the next packet is longer
than the given buffer. Use `packet_size` to read the maximum length of a single packet.
:return: number of bytes read and stored into ``buf``
:rtype: int
.. method:: write(self, data: Any, *, header: Any = None)
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.
:return: number of bytes written. May include header bytes when packet is empty.
:rtype: int
.. method:: deinit(self)
Disable permanently.
.. py:class:: 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.
.. attribute:: address
:annotation: :Any
The address of the device (read-only), of type `_bleio.Address`.
.. attribute:: advertisement_bytes
:annotation: :Any
All the advertisement data present in the packet, returned as a ``bytes`` object. (read-only)
.. attribute:: rssi
:annotation: :Any
The signal strength of the device at the time of the scan, in integer dBm. (read-only)
.. attribute:: connectable
:annotation: :Any
True if the device can be connected to. (read-only)
.. attribute:: scan_response
:annotation: :Any
True if the entry was a scan response. (read-only)
.. method:: matches(self, prefixes: Any, *, all: Any = True)
Returns True if the ScanEntry matches all prefixes when ``all`` is True. This is stricter
than the scan filtering which accepts any advertisements that match any of the prefixes
where all is False.
.. py:class:: ScanResults
Iterates over advertising data received while scanning. This object is always created
by a `_bleio.Adapter`: it has no user-visible constructor.
.. method:: __iter__(self)
Returns itself since it is the iterator.
.. method:: __next__(self)
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.
.. py:class:: Service(uuid: UUID, *, secondary: bool = False)
Stores information about a BLE service and its characteristics.
.. attribute:: characteristics
:annotation: :Any
A tuple of :py:class:`Characteristic` designating the characteristics that are offered by
this service. (read-only)
.. attribute:: remote
:annotation: :Any
True if this is a service provided by a remote device. (read-only)
.. attribute:: secondary
:annotation: :Any
True if this is a secondary service. (read-only)
.. attribute:: uuid
:annotation: :Any
The UUID of this service. (read-only)
Will be ``None`` if the 128-bit UUID for this service is not known.
.. py:class:: UUID(value: Any)
A 16-bit or 128-bit UUID. Can be used for services, characteristics, descriptors and more.
.. attribute:: uuid16
:annotation: :Any
The 16-bit part of the UUID. (read-only)
:type: int
.. attribute:: uuid128
:annotation: :Any
The 128-bit value of the UUID
Raises AttributeError if this is a 16-bit UUID. (read-only)
:type: bytes
.. attribute:: size
:annotation: :Any
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
.. method:: pack_into(self, buffer: Any, offset: Any = 0)
Packs the UUID into the given buffer at the given offset.
.. method:: __eq__(self, other: Any)
Two UUID objects are equal if their values match and they are both 128-bit or both 16-bit.