bluetooth — Bluetooth bas niveau

Ce module fournit une interface vers le contrôleur Bluetooth embarqué. Il prend en charge le Bluetooth Low Energy (BLE) dans les rôles Central, Peripheral, Broadcaster et Observer, ainsi que les serveurs et clients GATT et les canaux L2CAP orientés connexion. Un même appareil peut fonctionner simultanément dans plusieurs rôles. L’appairage et la liaison (bonding) sont également pris en charge.

Cette API est conçue pour correspondre au protocole Bluetooth bas niveau et fournir des briques de base pour des abstractions de plus haut niveau, telles que des types d’appareils spécifiques.

Astuce

Pour la plupart des applications, préférez la bibliothèque de plus haut niveau aioble, qui fournit un enrobage basé sur asyncio autour de ce module. Voir aioble — BLE asynchrone.

class BLE

class bluetooth.BLE

Renvoie l’objet BLE singleton.

Configuration

active(active: bool | None = None, /) bool

Modifie éventuellement l’état actif de la radio BLE, et renvoie l’état courant.

La radio doit être activée avant d’utiliser toute autre méthode de cette classe.

config(param: str, /) Any
config(*, **kwargs: Any) None

Lit ou définit des valeurs de configuration de l’interface BLE. Pour lire une valeur, le nom du paramètre doit être indiqué entre guillemets sous forme de chaîne, et un seul paramètre est interrogé à la fois. Pour définir des valeurs, utilisez la syntaxe par mots-clés ; un ou plusieurs paramètres peuvent être définis à la fois.

Les valeurs actuellement prises en charge sont :

  • 'mac' : L’adresse actuellement utilisée, selon le mode d’adresse en cours. Ceci renvoie un tuple (addr_type, addr).

    Voir gap_scan pour des détails sur le type d’adresse.

    Ceci ne peut être interrogé que lorsque l’interface est actuellement active.

  • 'addr_mode' : Définit le mode d’adresse. Les valeurs sont :

    Valeur

    Nom

    Comportement

    0x00

    PUBLIC

    Utiliser l’adresse publique du contrôleur.

    0x01

    RANDOM

    Utiliser une adresse statique générée.

    0x02

    RPA

    Utiliser des adresses privées résolvables.

    0x03

    NRPA

    Utiliser des adresses privées non résolvables.

    Par défaut, l’interface utilisera une adresse PUBLIC si elle est disponible, sinon elle utilisera une adresse RANDOM.

  • 'gap_name' : Lit/définit le nom d’appareil GAP utilisé par le service Generic Access (UUID 0x1800), caractéristique Device Name (UUID 0x2a00). Ceci peut être défini à tout moment et modifié plusieurs fois.

  • 'rxbuf' : Lit/définit la taille en octets du tampon interne utilisé pour stocker les événements entrants. Ce tampon est global à l’ensemble du pilote BLE et gère donc les données entrantes de tous les événements, y compris toutes les caractéristiques. L’augmenter permet une meilleure gestion des données entrantes en rafale (par exemple les résultats de scan) et la possibilité de recevoir des valeurs de caractéristiques plus grandes.

  • 'mtu' : Lit/définit le MTU qui sera utilisé lors d’un échange de MTU ATT. Le MTU résultant sera le minimum entre celui-ci et le MTU de l’appareil distant. L’échange de MTU ATT ne se produit pas automatiquement (à moins que l’appareil distant ne l’initie), et doit être déclenché manuellement avec gattc_exchange_mtu. Utilisez l’événement _IRQ_MTU_EXCHANGED pour découvrir le MTU d’une connexion donnée.

  • 'bond' : Définit si la liaison (bonding) sera activée pendant l’appairage. Lorsqu’elle est activée, les demandes d’appairage positionnent le drapeau « bond » et les clés sont stockées par les deux appareils.

  • 'mitm' : Définit si la protection contre les attaques MITM est requise pour l’appairage.

  • 'io' : Définit les capacités d’entrée/sortie de cet appareil.

    Les options disponibles sont :

    Constante

    Valeur

    Capacité

    _IO_CAPABILITY_DISPLAY_ONLY

    0

    Affichage uniquement

    _IO_CAPABILITY_DISPLAY_YESNO

    1

    Affichage avec saisie oui/non

    _IO_CAPABILITY_KEYBOARD_ONLY

    2

    Clavier uniquement

    _IO_CAPABILITY_NO_INPUT_OUTPUT

    3

    Aucune entrée ni sortie

    _IO_CAPABILITY_KEYBOARD_DISPLAY

    4

    Clavier et affichage

  • 'le_secure' : Définit si l’appairage « LE Secure » est requis. La valeur par défaut est false (c.-à-d. autoriser l’appairage « Legacy Pairing »).

Gestion des événements

irq(handler: Callable[[int, Tuple], Any | None], /) None

Enregistre une fonction de rappel pour les événements de la pile BLE. Le handler prend deux arguments, event (qui sera l’un des codes ci-dessous) et data (qui est un tuple de valeurs spécifique à l’événement).

Note : Pour optimiser et éviter les allocations inutiles, les entrées addr, adv_data, char_data, notify_data et uuid des tuples sont des instances memoryview en lecture seule pointant vers le tampon circulaire interne de bluetooth, et ne sont valides que pendant l’invocation de la fonction de gestion d’IRQ. Si votre programme a besoin de conserver l’une de ces valeurs pour y accéder après le retour du gestionnaire d’IRQ (par exemple en la stockant dans une instance de classe ou une variable globale), il doit en faire une copie, soit avec bytes() soit avec bluetooth.UUID(), comme ceci

connected_addr = bytes(addr)  # equivalently: adv_data, char_data, or notify_data
matched_uuid = bluetooth.UUID(uuid)

Par exemple, le gestionnaire d’IRQ d’un résultat de scan peut inspecter adv_data pour décider s’il s’agit du bon appareil, et ne copier l’adresse à utiliser ailleurs dans le programme qu’à ce moment-là. Et pour afficher des données depuis le gestionnaire d’IRQ, print(bytes(addr)) sera nécessaire.

Un gestionnaire opère généralement une distribution selon le code d’événement et déballe le tuple de charge utile spécifique à l’événement

def bt_irq(event, data):
    if event == _IRQ_CENTRAL_CONNECT:
        conn_handle, addr_type, addr = data
        ...
    elif event == _IRQ_SCAN_RESULT:
        addr_type, addr, adv_type, rssi, adv_data = data
        ...

Chaque code d’événement, la charge utile qu’il fournit et une courte description sont listés ci-dessous. Pour les événements dont le champ status est mentionné, status vaut 0 en cas de succès et une valeur non nulle spécifique à l’implémentation en cas d’échec.

Constante

Valeur

Événement

Tuple de charge utile

_IRQ_CENTRAL_CONNECT

1

Un central s’est connecté à ce périphérique.

(conn_handle, addr_type, addr)

_IRQ_CENTRAL_DISCONNECT

2

Un central s’est déconnecté de ce périphérique.

(conn_handle, addr_type, addr)

_IRQ_GATTS_WRITE

3

Un client connecté a écrit dans une caractéristique ou un descripteur local. Utilisez gatts_read pour récupérer la nouvelle valeur.

(conn_handle, attr_handle)

_IRQ_GATTS_READ_REQUEST

4

Un client connecté a émis une lecture. Renvoyez un code d’erreur non nul du tableau ci-dessous pour refuser la lecture, ou 0 / None pour l’accepter.

(conn_handle, attr_handle)

_IRQ_SCAN_RESULT

5

Un seul paquet d’annonce a été reçu pendant un scan actif.

(addr_type, addr, adv_type, rssi, adv_data)

_IRQ_SCAN_DONE

6

Le scan en cours s’est terminé, soit parce que la durée configurée s’est écoulée, soit parce que gap_scan(None) a été appelé.

()

_IRQ_PERIPHERAL_CONNECT

7

Un gap_connect émis précédemment a réussi.

(conn_handle, addr_type, addr)

_IRQ_PERIPHERAL_DISCONNECT

8

Un périphérique connecté s’est déconnecté.

(conn_handle, addr_type, addr)

_IRQ_GATTC_SERVICE_RESULT

9

Un service a été trouvé par gattc_discover_services.

(conn_handle, start_handle, end_handle, uuid)

_IRQ_GATTC_SERVICE_DONE

10

La découverte des services est terminée.

(conn_handle, status)

_IRQ_GATTC_CHARACTERISTIC_RESULT

11

Une caractéristique a été trouvée par gattc_discover_characteristics.

(conn_handle, end_handle, value_handle, properties, uuid)

_IRQ_GATTC_CHARACTERISTIC_DONE

12

La découverte des caractéristiques est terminée.

(conn_handle, status)

_IRQ_GATTC_DESCRIPTOR_RESULT

13

Un descripteur a été trouvé par gattc_discover_descriptors.

(conn_handle, dsc_handle, uuid)

_IRQ_GATTC_DESCRIPTOR_DONE

14

La découverte des descripteurs est terminée.

(conn_handle, status)

_IRQ_GATTC_READ_RESULT

15

Un gattc_read émis précédemment a renvoyé des données.

(conn_handle, value_handle, char_data)

_IRQ_GATTC_READ_DONE

16

Un gattc_read émis précédemment est terminé.

(conn_handle, value_handle, status)

_IRQ_GATTC_WRITE_DONE

17

Un gattc_write émis précédemment a été acquitté.

(conn_handle, value_handle, status)

_IRQ_GATTC_NOTIFY

18

Un serveur distant a envoyé une notification (non acquittée).

(conn_handle, value_handle, notify_data)

_IRQ_GATTC_INDICATE

19

Un serveur distant a envoyé une indication (acquittée).

(conn_handle, value_handle, notify_data)

_IRQ_GATTS_INDICATE_DONE

20

Une indication envoyée précédemment a été acquittée par le client (ou a expiré).

(conn_handle, value_handle, status)

_IRQ_MTU_EXCHANGED

21

Un échange de MTU ATT s’est terminé (initié par l’un ou l’autre côté).

(conn_handle, mtu)

_IRQ_L2CAP_ACCEPT

22

Un appareil distant a demandé une connexion L2CAP sur un PSM sur lequel cet appareil est à l’écoute. Renvoyez un entier non nul pour rejeter, ou 0 / None pour accepter.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_CONNECT

23

Un canal L2CAP est maintenant établi, soit en acceptant une demande entrante, soit en menant à bien un l2cap_connect sortant.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_DISCONNECT

24

Un canal L2CAP a été déconnecté. status vaut 0 pour une déconnexion propre, ou une valeur non nulle si une tentative de connexion sortante a échoué.

(conn_handle, cid, psm, status)

_IRQ_L2CAP_RECV

25

Des données sont arrivées sur un canal L2CAP. Appelez l2cap_recvinto pour les lire.

(conn_handle, cid)

_IRQ_L2CAP_SEND_READY

26

Un l2cap_send précédent qui avait renvoyé False s’est vidé et le canal est de nouveau prêt. Un status non nul signifie que le tampon d’émission a débordé et que l’application doit renvoyer les données.

(conn_handle, cid, status)

_IRQ_CONNECTION_UPDATE

27

L’appareil distant a mis à jour les paramètres de connexion (intervalle, latence, délai de supervision).

(conn_handle, conn_interval, conn_latency, supervision_timeout, status)

_IRQ_ENCRYPTION_UPDATE

28

L’état de chiffrement d’une connexion a changé, généralement après la fin d’un appairage ou d’une liaison.

(conn_handle, encrypted, authenticated, bonded, key_size)

_IRQ_GET_SECRET

29

La pile demande un secret de liaison stocké. Si key vaut None, renvoyez la index-ième valeur stockée de sec_type ; sinon renvoyez la valeur associée au couple (sec_type, key) donné. Renvoyez None si rien n’est stocké.

(sec_type, index, key)

_IRQ_SET_SECRET

30

La pile demande à l’application de persister un secret de liaison. Renvoyez True une fois stocké.

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

Une action de clé d’accès (passkey) est requise dans le cadre de l’appairage. Répondez en utilisant gap_passkey ; voir le tableau des actions de clé d’accès ci-dessous pour les actions possibles.

(conn_handle, action, passkey)

Pour l’événement _IRQ_GATTS_READ_REQUEST, les codes de retour disponibles sont :

Constante

Valeur

Signification

_GATTS_NO_ERROR

0x00

Accepter la lecture.

_GATTS_ERROR_READ_NOT_PERMITTED

0x02

Lecture non autorisée.

_GATTS_ERROR_WRITE_NOT_PERMITTED

0x03

Écriture non autorisée.

_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION

0x05

Le client n’est pas authentifié.

_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION

0x08

Le client n’est pas autorisé.

_GATTS_ERROR_INSUFFICIENT_ENCRYPTION

0x0f

Le lien n’est pas chiffré.

Pour l’événement _IRQ_PASSKEY_ACTION, les actions disponibles sont :

Constante

Valeur

Signification

_PASSKEY_ACTION_NONE

0

Aucune action requise.

_PASSKEY_ACTION_INPUT

2

Inviter l’utilisateur à saisir la clé d’accès affichée sur l’appareil distant.

_PASSKEY_ACTION_DISPLAY

3

Afficher une clé d’accès à 6 chiffres que l’appareil distant doit saisir.

_PASSKEY_ACTION_NUMERIC_COMPARISON

4

Confirmer que la clé d’accès correspond à celle affichée sur l’appareil distant.

Afin d’économiser de l’espace dans le micrologiciel, ces constantes ne sont pas incluses dans le module bluetooth. Ajoutez celles dont vous avez besoin, à partir des listes ci-dessus, à votre programme.

Rôle Broadcaster (annonceur)

gap_advertise(interval_us: int | None, adv_data: bytes | None = None, *, resp_data: bytes | None = None, connectable: bool = True) None

Démarre l’annonce à l’intervalle spécifié (en microsecondes). Cet intervalle sera arrondi à l’inférieur au multiple de 625 us le plus proche. Pour arrêter l’annonce, définissez interval_us à None.

adv_data et resp_data peuvent être de tout type implémentant le protocole tampon (par exemple bytes, bytearray, str). adv_data est inclus dans toutes les diffusions, et resp_data est envoyé en réponse à un scan actif.

Note : si adv_data (ou resp_data) vaut None, alors les données passées à l’appel précédent de gap_advertise seront réutilisées. Cela permet à un broadcaster de reprendre l’annonce avec simplement gap_advertise(interval_us). Pour effacer la charge utile d’annonce, passez un bytes vide, c.-à-d. b''.

Rôle Observer (scanner)

gap_scan(duration_ms: int | None, interval_us: int = 1280000, window_us: int = 11250, active: bool = False, /) None

Exécute une opération de scan d’une durée spécifiée (en millisecondes).

Pour scanner indéfiniment, définissez duration_ms à 0.

Pour arrêter le scan, définissez duration_ms à None.

Utilisez interval_us et window_us pour configurer éventuellement le rapport cyclique. Le scanner s’exécutera pendant window_us microsecondes toutes les interval_us microsecondes, pour un total de duration_ms millisecondes. L’intervalle et la fenêtre par défaut sont respectivement de 1,28 seconde et 11,25 millisecondes (scan en arrière-plan).

Pour chaque résultat de scan, l’événement _IRQ_SCAN_RESULT sera levé, avec les données d’événement (addr_type, addr, adv_type, rssi, adv_data).

Les valeurs de addr_type indiquent des adresses publiques ou aléatoires :

Valeur

Nom

Signification

0x00

PUBLIC

Adresse d’appareil publique.

0x01

RANDOM

Adresse aléatoire (statique, RPA ou NRPA ; le type est encodé dans l’adresse elle-même).

Les valeurs de adv_type correspondent à la spécification Bluetooth :

Valeur

Nom

Signification

0x00

ADV_IND

Annonce non dirigée connectable et scannable.

0x01

ADV_DIRECT_IND

Annonce dirigée connectable.

0x02

ADV_SCAN_IND

Annonce non dirigée scannable.

0x03

ADV_NONCONN_IND

Annonce non dirigée non connectable.

0x04

SCAN_RSP

Réponse de scan.

active peut être défini à True si vous souhaitez recevoir les réponses de scan dans les résultats.

Lorsque le scan est arrêté (soit parce que la durée est écoulée, soit parce qu’il est explicitement arrêté), l’événement _IRQ_SCAN_DONE sera levé.

Rôle Central

Un appareil central peut se connecter aux périphériques qu’il a découverts à l’aide du rôle observer (voir gap_scan) ou dont l’adresse est connue.

gap_connect(addr_type: int | None, addr: bytes | None = None, scan_duration_ms: int = 2000, min_conn_interval_us: int | None = None, max_conn_interval_us: int | None = None, /) None

Se connecter à un périphérique.

Voir gap_scan pour des détails sur les types d’adresses.

Pour annuler prématurément une tentative de connexion en cours, appelez gap_connect(None).

En cas de succès, l’événement _IRQ_PERIPHERAL_CONNECT sera levé. En cas d’annulation d’une tentative de connexion, l’événement _IRQ_PERIPHERAL_DISCONNECT sera levé.

L’appareil attendra jusqu’à scan_duration_ms pour recevoir une charge utile d’annonce de l’appareil.

L’intervalle de connexion peut être configuré en microsecondes en utilisant l’un de min_conn_interval_us et max_conn_interval_us, ou les deux. Sinon, un intervalle par défaut sera choisi, généralement entre 30000 et 50000 microsecondes. Un intervalle plus court augmentera le débit, au détriment de la consommation d’énergie.

Rôle Peripheral

Un appareil périphérique est censé envoyer des annonces connectables (voir gap_advertise). Il agira généralement comme un serveur GATT, après avoir d’abord enregistré des services et des caractéristiques à l’aide de gatts_register_services.

Lorsqu’un central se connecte, l’événement _IRQ_CENTRAL_CONNECT sera levé.

Rôles Central et Peripheral

gap_disconnect(conn_handle: int, /) bool

Déconnecte le handle de connexion spécifié. Il peut s’agir soit d’un central qui s’est connecté à cet appareil (s’il agit comme un périphérique), soit d’un périphérique auquel cet appareil s’était connecté précédemment (s’il agit comme un central).

En cas de succès, l’événement _IRQ_PERIPHERAL_DISCONNECT ou _IRQ_CENTRAL_DISCONNECT sera levé.

Renvoie False si le handle de connexion n’était pas connecté, et True sinon.

Serveur GATT

Un serveur GATT dispose d’un ensemble de services enregistrés. Chaque service peut contenir des caractéristiques, qui possèdent chacune une valeur. Les caractéristiques peuvent aussi contenir des descripteurs, qui possèdent eux-mêmes des valeurs.

Ces valeurs sont stockées localement et sont accessibles via leur « value handle » généré lors de l’enregistrement du service. Elles peuvent également être lues ou écrites par un appareil client distant. De plus, un serveur peut « notifier » une caractéristique à un client connecté via un handle de connexion.

Un appareil, qu’il soit dans le rôle central ou périphérique, peut fonctionner comme un serveur GATT ; cependant, dans la plupart des cas, il sera plus courant qu’un appareil périphérique agisse comme serveur.

Les caractéristiques et les descripteurs ont une taille maximale par défaut de 20 octets (le MTU ATT par défaut de 23 octets moins un en-tête ATT de 3 octets ; un MTU négocié plus grand n’élève pas à lui seul cette limite). Tout ce qui y est écrit par un client sera tronqué à cette longueur. Toutefois, toute écriture locale augmentera la taille maximale ; donc, si vous voulez autoriser des écritures plus grandes d’un client vers une caractéristique donnée, utilisez gatts_write après l’enregistrement, par exemple gatts_write(char_handle, bytes(100)).

gatts_register_services(services_definition: Sequence[Sequence], /) Sequence[Sequence[int]]

Configure le serveur avec les services spécifiés, en remplaçant tous les services existants.

services_definition est une liste de services, où chaque service est un tuple à deux éléments contenant un UUID et une liste de caractéristiques.

Chaque caractéristique est un tuple à deux ou trois éléments contenant un UUID, une valeur flags, et éventuellement une liste de descripteurs.

Chaque descripteur est un tuple à deux éléments contenant un UUID et une valeur flags.

Les flags sont une combinaison par OU bit à bit des drapeaux définis ci-dessous. Ils définissent à la fois le comportement de la caractéristique (ou du descripteur) ainsi que les exigences de sécurité et de confidentialité.

La valeur de retour est une liste (un élément par service) de tuples (chaque élément est un value handle). Les handles de caractéristiques et de descripteurs sont aplatis dans le même tuple, dans l’ordre où ils sont définis.

L’exemple suivant enregistre deux services (Heart Rate et Nordic UART)

bt = bluetooth.BLE()
bt.active(True)

# Heart Rate service: one Heart Rate Measurement characteristic.
HR_SERVICE = (
    bluetooth.UUID(0x180D),
    (
        (bluetooth.UUID(0x2A37),
         bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY),
    ),
)

# Nordic UART service: a TX characteristic the client subscribes
# to for notifications, and an RX characteristic it writes to.
UART_SERVICE = (
    bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E'),
    (
        (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'),
         bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY),
        (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'),
         bluetooth.FLAG_WRITE),
    ),
)

((hr,), (tx, rx)) = bt.gatts_register_services(
    (HR_SERVICE, UART_SERVICE),
)

Les trois value handles (hr, tx, rx) peuvent être utilisés avec gatts_read, gatts_write, gatts_notify et gatts_indicate.

Note : L’annonce doit être arrêtée avant d’enregistrer des services.

Les drapeaux disponibles pour les caractéristiques et les descripteurs sont :

Constante

Valeur

Signification

_FLAG_BROADCAST

0x0001

La caractéristique peut être diffusée.

_FLAG_READ

0x0002

Le client peut lire la valeur.

_FLAG_WRITE_NO_RESPONSE

0x0004

Le client peut écrire sans attendre de réponse.

_FLAG_WRITE

0x0008

Le client peut écrire avec une réponse acquittée.

_FLAG_NOTIFY

0x0010

Le serveur peut envoyer des notifications (non acquittées).

_FLAG_INDICATE

0x0020

Le serveur peut envoyer des indications (acquittées).

_FLAG_AUTHENTICATED_SIGNED_WRITE

0x0040

Le client peut émettre des écritures signées.

_FLAG_AUX_WRITE

0x0100

Propriétés étendues : les écritures en file d’attente/fiables sont autorisées.

_FLAG_READ_ENCRYPTED

0x0200

La lecture nécessite un lien chiffré.

_FLAG_READ_AUTHENTICATED

0x0400

La lecture nécessite un lien authentifié (protégé contre les attaques MITM).

_FLAG_READ_AUTHORIZED

0x0800

La lecture nécessite une autorisation au niveau de l’application.

_FLAG_WRITE_ENCRYPTED

0x1000

L’écriture nécessite un lien chiffré.

_FLAG_WRITE_AUTHENTICATED

0x2000

L’écriture nécessite un lien authentifié (protégé contre les attaques MITM).

_FLAG_WRITE_AUTHORIZED

0x4000

L’écriture nécessite une autorisation au niveau de l’application.

Comme pour les constantes d’événements ci-dessus, ces drapeaux ne sont pas fournis par le module bluetooth ; copiez ceux dont vous avez besoin dans votre programme.

gatts_read(value_handle: int, /) bytes

Lit la valeur locale de ce handle (qui a été écrite soit par gatts_write, soit par un client distant).

gatts_write(value_handle: int, data: bytes, send_update: bool = False, /) None

Écrit la valeur locale de ce handle, qui peut être lue par un client.

Si send_update vaut True, alors tous les clients abonnés seront notifiés (ou recevront une indication, selon ce à quoi ils sont abonnés et selon les opérations prises en charge par la caractéristique) de cette écriture.

gatts_notify(conn_handle: int, value_handle: int, data: bytes | None = None, /) None

Envoie une demande de notification à un client connecté.

Si data vaut None (par défaut), alors la valeur locale courante (telle que définie avec gatts_write) sera envoyée.

Sinon, si data n’est pas None, alors cette valeur est envoyée au client dans le cadre de la notification. La valeur locale ne sera pas modifiée.

Note : La notification sera envoyée quel que soit l’état d’abonnement du client à cette caractéristique.

gatts_indicate(conn_handle: int, value_handle: int, data: bytes | None = None, /) None

Envoie une demande d’indication à un client connecté.

Si data vaut None (par défaut), alors la valeur locale courante (telle que définie avec gatts_write) sera envoyée.

Sinon, si data n’est pas None, alors cette valeur est envoyée au client dans le cadre de l’indication. La valeur locale ne sera pas modifiée.

Lors de l’acquittement (ou de l’échec, par exemple un délai dépassé), l’événement _IRQ_GATTS_INDICATE_DONE sera levé.

Note : L’indication sera envoyée quel que soit l’état d’abonnement du client à cette caractéristique.

gatts_set_buffer(value_handle: int, len: int, append: bool = False, /) None

Définit la taille du tampon interne d’une valeur en octets. Ceci limitera la plus grande écriture pouvant être reçue. La valeur par défaut est de 20 octets (MTU ATT par défaut de 23 moins l’en-tête ATT de 3 octets).

Définir append à True fera en sorte que toutes les écritures distantes s’ajoutent à la valeur courante, plutôt que de la remplacer. Au plus len octets peuvent être mis en tampon de cette manière. Lorsque vous utilisez gatts_read, la valeur sera effacée après lecture. Cette fonctionnalité est utile pour implémenter quelque chose comme le Nordic UART Service.

Client GATT

Un client GATT peut découvrir et lire/écrire des caractéristiques sur un serveur GATT distant.

Il est plus courant qu’un appareil en rôle central agisse comme le client GATT ; cependant, il est aussi possible qu’un périphérique agisse comme client afin de découvrir des informations sur le central qui s’y est connecté (par exemple pour lire le nom de l’appareil depuis le service Device Information).

gattc_discover_services(conn_handle: int, uuid: UUID | None = None, /) None

Interroge un serveur connecté pour obtenir ses services.

Spécifiez éventuellement un uuid de service pour n’interroger que ce service.

Pour chaque service découvert, l’événement _IRQ_GATTC_SERVICE_RESULT sera levé, suivi de _IRQ_GATTC_SERVICE_DONE à la fin.

gattc_discover_characteristics(conn_handle: int, start_handle: int, end_handle: int, uuid: UUID | None = None, /) None

Interroge un serveur connecté pour obtenir les caractéristiques dans la plage spécifiée.

Spécifiez éventuellement un uuid de caractéristique pour n’interroger que cette caractéristique.

Passer start_handle=1 et end_handle=0xffff couvre toute la plage de handles d’attributs GATT, de sorte que cette combinaison parcourt en pratique tous les services de l’appareil distant.

Pour chaque caractéristique découverte, l’événement _IRQ_GATTC_CHARACTERISTIC_RESULT sera levé, suivi de _IRQ_GATTC_CHARACTERISTIC_DONE à la fin.

gattc_discover_descriptors(conn_handle: int, start_handle: int, end_handle: int, /) None

Interroge un serveur connecté pour obtenir les descripteurs dans la plage spécifiée.

Pour chaque descripteur découvert, l’événement _IRQ_GATTC_DESCRIPTOR_RESULT sera levé, suivi de _IRQ_GATTC_DESCRIPTOR_DONE à la fin.

gattc_read(conn_handle: int, value_handle: int, /) None

Émet une lecture distante vers un serveur connecté pour le handle de caractéristique ou de descripteur spécifié.

Lorsqu’une valeur est disponible, l’événement _IRQ_GATTC_READ_RESULT sera levé, suivi de _IRQ_GATTC_READ_DONE à la fin.

gattc_write(conn_handle: int, value_handle: int, data: bytes, mode: int = 0, /) None

Émet une écriture distante vers un serveur connecté pour le handle de caractéristique ou de descripteur spécifié.

L’argument mode spécifie le comportement d’écriture, les valeurs actuellement prises en charge étant :

  • mode=0 (par défaut) est une écriture sans réponse : l’écriture sera envoyée au serveur distant, mais aucune confirmation ne sera renvoyée, et aucun événement ne sera levé.

  • mode=1 est une écriture avec réponse : il est demandé au serveur distant d’envoyer une réponse/un acquittement indiquant qu’il a reçu les données.

Si une réponse est reçue du serveur distant, l’événement _IRQ_GATTC_WRITE_DONE sera levé.

gattc_exchange_mtu(conn_handle: int, /) None

Initie un échange de MTU avec un serveur connecté, en utilisant le MTU préféré défini via BLE.config(mtu=value).

L’événement _IRQ_MTU_EXCHANGED sera levé lorsque l’échange de MTU se terminera.

L’échange de MTU est généralement initié par le central ; NimBLE prend en charge les deux rôles.

Canaux L2CAP orientés connexion

Cette fonctionnalité permet un échange de données de type socket entre deux appareils BLE. Une fois les appareils connectés via GAP, l’un ou l’autre peut se mettre à l’écoute de l’autre pour qu’il se connecte sur un PSM numérique (Protocol/Service Multiplexer).

Un seul canal L2CAP peut être actif à la fois (c.-à-d. que vous ne pouvez pas vous connecter pendant que vous êtes à l’écoute).

Les canaux L2CAP actifs sont identifiés par le handle de connexion sur lequel ils ont été établis et par un CID (channel ID).

Les canaux orientés connexion disposent d’un contrôle de flux intégré basé sur des crédits. Contrairement à ATT, où les appareils négocient un MTU partagé, l’appareil à l’écoute et l’appareil qui se connecte définissent chacun un MTU indépendant qui limite la quantité maximale de données en attente que l’appareil distant peut envoyer avant qu’elles ne soient entièrement consommées dans l2cap_recvinto.

l2cap_listen(psm: int, mtu: int, /) None

Commence à écouter les demandes entrantes de canal L2CAP sur le psm spécifié, avec le MTU local défini à mtu.

Lorsqu’un appareil distant initie une connexion, l’événement _IRQ_L2CAP_ACCEPT sera levé, ce qui donne au serveur à l’écoute la possibilité de rejeter la connexion entrante (en renvoyant un entier non nul).

Une fois la connexion acceptée, l’événement _IRQ_L2CAP_CONNECT sera levé, permettant au serveur d’obtenir le channel ID (CID) ainsi que les MTU local et distant.

Note : Il n’est actuellement pas possible d’arrêter l’écoute.

l2cap_connect(conn_handle: int, psm: int, mtu: int, /) None

Se connecte à un pair à l’écoute sur le psm spécifié, avec le MTU local défini à mtu.

En cas de connexion réussie, l’événement _IRQ_L2CAP_CONNECT sera levé, permettant au client d’obtenir le CID ainsi que les MTU local et distant (du pair).

Une connexion infructueuse lèvera l’événement _IRQ_L2CAP_DISCONNECT avec un statut non nul.

l2cap_disconnect(conn_handle: int, cid: int, /) None

Déconnecte un canal L2CAP actif avec les conn_handle et cid spécifiés.

l2cap_send(conn_handle: int, cid: int, buf: bytes, /) bool

Envoie le buf spécifié (qui doit prendre en charge le protocole tampon) sur le canal L2CAP identifié par conn_handle et cid.

Le tampon doit satisfaire les deux limites : il ne doit pas dépasser le MTU distant (du pair), et il ne doit pas dépasser le double du MTU local.

Ceci renverra False si le canal est désormais « bloqué » (stalled), ce qui signifie que l2cap_send ne doit pas être rappelé tant que l’événement _IRQ_L2CAP_SEND_READY n’a pas été reçu (ce qui se produira lorsque l’appareil distant accordera davantage de crédits, généralement après avoir reçu et traité les données).

l2cap_recvinto(conn_handle: int, cid: int, buf: Any | None, /) int

Reçoit des données depuis les conn_handle et cid spécifiés dans le buf fourni (qui doit prendre en charge le protocole tampon, par exemple bytearray ou memoryview).

Renvoie le nombre d’octets lus sur le canal.

Si buf vaut None, alors renvoie le nombre d’octets disponibles.

Note : Après réception de l’événement _IRQ_L2CAP_RECV, l’application doit continuer d’appeler l2cap_recvinto jusqu’à ce qu’il n’y ait plus d’octets disponibles dans le tampon de réception (généralement jusqu’à la taille du MTU distant (du pair)).

Tant que le tampon de réception n’est pas vide, l’appareil distant ne se verra pas accorder davantage de crédits de canal et ne pourra plus envoyer de données.

Appairage et liaison (bonding)

L’appairage permet de chiffrer et d’authentifier une connexion via un échange de secrets (avec une protection MITM optionnelle par authentification par clé d’accès).

La liaison (bonding) est le processus consistant à stocker ces secrets dans un stockage non volatile. Une fois liés, un appareil est capable de résoudre une adresse privée résolvable (RPA) d’un autre appareil à partir de la clé de résolution d’identité (IRK) stockée. Pour prendre en charge la liaison, une application doit implémenter les événements _IRQ_GET_SECRET et _IRQ_SET_SECRET.

gap_pair(conn_handle: int, /) None

Initie l’appairage avec l’appareil distant.

Avant d’appeler ceci, assurez-vous que les options de configuration io, mitm, le_secure et bond sont définies (via config).

En cas d’appairage réussi, l’événement _IRQ_ENCRYPTION_UPDATE sera levé.

gap_passkey(conn_handle: int, action: int, passkey: int, /) None

Répond à un événement _IRQ_PASSKEY_ACTION pour les conn_handle et action spécifiés. La signification de passkey dépend de action (qui dépend à son tour de la capacité d’entrée/sortie configurée) :

Action

Réponse passkey requise

_PASSKEY_ACTION_INPUT

La clé d’accès que l’utilisateur lit sur l’appareil distant.

_PASSKEY_ACTION_DISPLAY

Une clé d’accès aléatoire à 6 chiffres générée localement et présentée à l’utilisateur.

_PASSKEY_ACTION_NUMERIC_COMPARISON

1 pour accepter la clé d’accès affichée dans l’événement _IRQ_PASSKEY_ACTION, ou 0 pour annuler l’appairage.

class UUID

class bluetooth.UUID(value: int | bytes | str, /)

Crée une instance UUID avec la value spécifiée. Le Bluetooth utilise trois largeurs d’UUID ; UUID accepte chacune d’entre elles :

Largeur d’UUID

Types de value acceptés

Exemple

16 bits

int ou un tampon de 2 octets (petit-boutiste)

UUID(0x2908) ou UUID(b'\x08\x29')

32 bits

tampon de 4 octets (petit-boutiste)

UUID(b'\x08\x29\x00\x00')

128 bits

tampon de 16 octets ou chaîne avec tirets

UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')

Les UUID 16 et 32 bits sont généralement des identifiants alloués par le SIG (voir les numéros assignés Bluetooth) ; les UUID 128 bits sont normalement définis par le fournisseur.