Le bluetooth est un système de communication sans fil. La norme 1.0 a été définie en 1999. Les normes et spécifications ont été définies par le BSIG (Bluetooth Special Interest group) dont les membres étaient (certains n'existent plus) :
De nombreux appareils intègrent le système bluetooth
Une interface bluetooth utilise une adresse souvent nommée bdaddr composée de 6 octets et présenté sous la forme de 6 valeurs hexadécimales séparées par le symbole :.
La réglementation de la puissance d’émission permet une portée maximale de 100m. Dans cet intervalle de distance, il existe 3 classes bluetooth :
Classe | Puissance | Distance | |
---|---|---|---|
1 | 100mW | 20dBm | 100m |
2 | 2.5mW | 4dBm | 20m |
3 | 1mW | 0dBm | 10m |
Un profile est une implémentation d'un protocole pour fournir un service particulier, on trouve par exemple :
Un seul maître établit la communication avec les esclaves.
C'est le maître qui autorise l'esclave à transmettre ses données.
Un maître peut gérer plusieurs esclaves accessibles par radio. On a ainsi une organisation en pico-réseau qui contient un seul maître. Dans un pico-réseau, le maître synchronise tous les esclaves afin d'éviter les perturbations et il n'y a pas de connexion entre esclaves. Un maître ne peut pas être le maître de plusieurs pico-réseaux.
Un appareil qui cherche (inquiry) l'ensemble des appareils accessibles (portée radio), émet des paquets de données à intervalles réguliers. Les appareils qui reçoivent ces données répondent en transmettant les informations d'identification comme leur adresse bdaddr, ces informations permettent à l'émetteur d'établir une connexion.
La connexion entre appareils est une suite d'échanges de données.
Il est possible d'interconnecter plusieurs pico-réseaux avec un seul maître par pico-réseau, pour cela il y a plusieurs possibilités.
Le maître d'un pico-réseaux est l'esclave d'un autre pico-réseau.
Sur la figure, le maître du premier pico-réseau (bleu) est l'esclave du deuxième pico-réseau (rouge).
Chaque maître synchronise son pico-réseau de manière indépendante. Les pico-réseaux se partagent la même zone radio, ce qui crée des perturbations et fait baisser le débit.
Les pico-réseaux se partagent le même esclave.
Le problème de perturbation existe toujours dans cette configuration mais peut être atténué par la distance entre les maîtres qui est plus importante.
Sous linux les librairies et outils sont regroupés dans les paquetages bluetooth et bluez, avec en plus, des paquetages graphiques inclus dans les différents gestionnaire de fenêtres.
Ces paquetages fournissent des commandes dont :
La programmation en C utilise la librairie bluez qui permettent de créer des applications qui utilisent les couches l2cap et rfcomm. Il ne faut pas oublier d'inclure les paquetages dev et ajouter la librairie bluetooth à l'édition de liens (-lbluetooth).
Le scan utilise les fonctions C hci qui sont :
fdhci=hci_open_dev(hcidev)
qui ouvre le socket hci correspondant à l'interface de numéro hcidev, cette fonction retourne l'identifiant de l'interface fdhci.hci_inquiry(hcidev,longueur,nbrep,octets,adr_infos,options)
cherche les appareils bluetooth accessibles avec hcidev qui est le numéro de l'interface bluetooth, longueur qui représente le temps de scan en multiple de 1.28s, nbrep qui correspond aux maximum de réponses, octets qui est un tableau d'octets (non documenté), adr_infos qui est l'adresse d'un pointeur vers une structure de type inquiry_info et options qui vaut en général 0 (très peu documenté). Cette fonction retourne le nombre de réponses obtenues.hci_read_remote_name(fdhci,bdaddr,taille,nom,timeout)
qui effectue une demande de nom pour une adresse bdaddr fournie. fdhci est l'identifiant retourné par hci_open_dev
, bdaddr (structure qui contient un tableau de 6 octets) adresse qui est un champ de la structure adr_infos, taille qui est la longueur maximale du nom, nom qui contient le nom, timeout qui est le temps maximum accordé à la requête.close(fdhci)
ferme l'interface hci.
#include <stdio.h>
#include <stdlib.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <unistd.h>
int main(int argc, char **argv) {
int hci_dev, fdhci , nbrep;
inquiry_info *info = NULL;
bdaddr_t bdaddr;
hci_dev = 0;
char nom[128] = "";
fdhci = hci_open_dev(hci_dev);
if (fdhci < 0) {
perror("opening socket");
return EXIT_FAILURE;
}
nbrep = hci_inquiry (hci_dev, 8, 255, NULL, &info, 0);
for (int i=0 ; i<nbrep ; i+=1 ) {
baswap (&bdaddr, &(info+i)->bdaddr);
int nomexiste = hci_read_remote_name(fdhci,&(info+i)->bdaddr,sizeof(nom),nom,0);
if (nomexiste < 0) {
strcpy(nom,"inconnu");
}
printf ("\t%s %s\n", batostr(&bdaddr),nom) ;
}
free (info);
close(fdhci);
return EXIT_SUCCESS;
}
inquiry_info
est un pointeur vers une structure qui contient, entre autres, l'adresse de l'appareil détecté.
hci_dev vaut 0 car l'ordinateur ne possède qu'une interface bluetooth.
longueur vaut 8 pour obtenir un temps de 8*1.28=10.24s et nbrep=255 ce qui correspond au temps précédent.
En cas d'erreur avec hci_open_dev
, on affiche le code d'erreur et termine le programme.
hci_inquiry
effectue le scan et retourne un tableau dynamique de structures inquiry_info
qu'il ne faudra pas oublier de libérer à la fin du programme. Cette fonction retourne le nombre de réponses obtenues.
baswap
modifie ou non l'ordre des octets en fonction du type de machine. Cela permet d'obtenir les octets dans le bon ordre quelque soit la machine.
batostr
convertit l'adresse qui est un tableau d'octets en une chaîne de caractères
La programmation en python utilise également la librairie bluez.
Il faut importer la librairie bluetooth, les fonctions pour scanner les appareils accessibles sont :
bluetooth.discover_devices
qui retourne une liste d'adresses des appareils accessiblesbluetooth.lookup_name(bdaddr)
qui retourne le nom correspondant à l'adresse bdaddr
import bluetooth
def main(args):
appareils = bluetooth.discover_devices()
for bdaddr in appareils :
nom = bluetooth.lookup_name(bdaddr)
print(f"{bdaddr} : {nom}")
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
appareils est une liste d'adresses sous la forme de chaînes de caractères.
Le BLE (Bluetooth Low Energy) est une version allégée du bluetooth afin de minimiser la consommation d'énergie, cette version est surtout implémentée sur les systèmes embarqués et objets connectés.
Le BLE est apparu en 2010 avec la version 4.0 de bluetooth.
Comme le bluetooth standard un composant BLE est identifié par une adresse bdaddr exprimée sur 6 octets
Les identifiants utilisés dans les services et caractéristiques sont normalisés et associés à des fonctionnalités précises. Les protocoles sont désignés par des UUID 16 bits. Les services et caractéristiques le sont pas des UUID 128 bits. l'ensemble de ces valeurs est parfaitement décrit dans les spécifications bluetooth. Il est également possible d'obtenir un UUID 128 bits en ligne.
Le système est composé d'un système central et de périphériques
Le serveur est installé sur un système embarqué connecté et le client peut être une application smartphone comme par exemple : BLE scanner disponible sur Android et sur Apple (non testé) ou encore la commande bluetootctl sous linux:
scan on
pour démarrer la découverte des périphériques bluetoothscan off
pour arrêter la découverte des périphériques bluetoothconnect bdaddr
pour se connecter au périphérique bluetooth concernégat.list-attributes bdaddr
pour obtenir la liste des services et caractéristiquesgat.select-attribute UUID
pour accéder à une caractéristique d'identifiant UUIDgat.read
pour obtenir la valeur de la caractéristique d'identifiant UUIDgat.write valeur
pour envoyer une nouvelle valeur à la caractéristique d'identifiant UUIDdisconnect
pour se déconnecterquit
pour quitter bluetoothctlIl est vivement conseillé de se reporter à la programmation de la carte MKR1010.
On utilise la librairie Arduino BLE.
La réalisation d'un serveur GATT fait appel aux méthodes de l'objet BLE
ainsi que les classes BLEService
, BLEByteCharacteristic
et BLEDescriptor
.
Lors de l'initialisation :
BLE.begin()
initialise l'interface bluetoothBLE.setLocalName(chaine)
définit le nom de l'applicationBLE.setDeviceName(chaine)
définit le nom de la carteBLE.setAppearance
définit le code d'identification de l' applicationBLE.setAdvertisedService(objetBLEService)
définit le service utiliséBLE.addService(objetBLEService)
ajoute le service à l'interface après avoir configuré l'objet BLEService :
ObjetBLEByteCharacteristic.addDescriptor(objetBLEDescriptor)
ajoute un objet descriptor à la caractéristiqueobjetBLEService.addCharacteristic(BLEByteCharacteristic)
ajoute l'objet caractéristique au serviceObjetBLEByteCharacteristic.writeValue(valeur)
initialise, si cela est nécessaire, le contenu de la caractéristiqueBLE.advertise()
démarre la publication du serviceDans la boucle de surveillance des connexions clientes :
BLE.central()
fournit un objet BLEDevice
qui correspond au client connecté.objetBLEDevice.connected()
est vrai si un client s'est connecté.objetBLEDevice.address()
contient l'adresse du clientBLEByteCharacteristic.written()
vaut vrai si une valeur a été reçueBLEByteCharacteristic.value()
contient la valeur
#include <ArduinoBLE.h>
BLEService ledService("f29b181c-9a04-4f7f-8dc7-df499f6602ad");
BLEByteCharacteristic switchCharacteristic("6ffa8a48-32ce-4a87-92f5-07977fd3ebbe", BLERead | BLEWrite);
BLEDescriptor ledCharacteristic("6a610785-5620-4219-a209-77006a3f082f", "commande led type texte : 0 ou 1");
void setup() {
Serial.begin(9600);
while (!Serial);
pinMode(LED_BUILTIN, OUTPUT);
if (!BLE.begin()) {
Serial.println("Initialisation BLE ERREUR");
while (1);
}
Serial.println("Initialisation BLE OK");
String adresse = BLE.address();
Serial.print("adresse ");
Serial.println(adresse);
BLE.setLocalName("LED");
BLE.setDeviceName("MKR1010");
BLE.setAppearance(0x0785);
BLE.setAdvertisedService(ledService);
switchCharacteristic.addDescriptor(ledCharacteristic);
ledService.addCharacteristic(switchCharacteristic);
BLE.addService(ledService);
Serial.println("initialise service 0");
switchCharacteristic.writeValue(0);
BLE.advertise();
Serial.println("Prêt");
}
void loop() {
BLEDevice central = BLE.central();
if (central) {
Serial.print("Client connecté : ");
Serial.println(central.address());
while (central.connected()) {
if (switchCharacteristic.written()) {
if (switchCharacteristic.value()=='1') {
Serial.println("LED on");
digitalWrite(LED_BUILTIN, HIGH);
}
else {
Serial.println(F("LED off"));
digitalWrite(LED_BUILTIN, LOW);
}
}
}
Serial.print(F("Client déconnecté "));
Serial.println(central.address());
}
}
Exemple de commandes après avoir lancé la commande bluetoothctl
[bluetooth]# scan on Discovery started [NEW] Device XX:XX:XX:XX:XX:XX ... [bluetooth]# scan off Discovery stopped [bluetooth]# gat.list-attributes XX:XX:XX:XX:XX:XX Characteristic (Handle XXXXXX) .............................................. 6ffa8a48-32ce-4a87-92f5-07977fd3ebbe Vendor specific [bluetooth]# gat.select-attribute 6ffa8a48-32ce-4a87-92f5-07977fd3ebbe [MKR1010:/xxxxxxxxxxxxxxx]# gat.read Attempting to read ................................................................ [CHG] Attribute ................................................................... Value: 30 0 30 [MKR1010:/xxxxxxxxxxxxxxx]# gat.write 0x31 Attempting to write ................................................................ [MKR1010:/xxxxxxxxxxxxxxx]# gat.write 0x30 Attempting to write ................................................................ [MKR1010:/xxxxxxxxxxxxxxx]#disconnect Attempting to disconnect from A4:CF:12:8A:A6:4A [CHG] Device XX:XX:XX:XX:XX:XX ServicesResolved: no Successful disconnected [CHG] Device XX:XX:XX:XX:XX:XX Connected: no [bluetooth]#quit
Dans la liste des attributs, on cherche l'UUID qui correspond à celui qui est défini dans le programme arduino soit :
Il est vivement conseillé de se reporter à la programmation de la carte picow.
On trouve difficilement de la documentation sur la programmation en C de bluetooth sur raspberry picow. Les codes qui suivent sont inspirés des exemples picow/bt de l'ensemble des exemples.
cyw43_arch_init()
initialise la puce wifi/bluetooth CYW43439l2cap_init()
initialise la couche l2capsm_init()
initialise la couche de sécuritéatt_server_init(profile_data, att_read_callback, att_write_callback);
initialise le serveur GATT, profile_data est une structure de données définie dans un fichier .h créé lors de la compilation à partir d'un fichier .gatt, ce dernier est un fichier csv qui contient la liste des services et caractéristiques, att_read_callback est une fonction callback qui est appelée lors d'une demande de lecture du client, att_write_callback est une fonction callback qui est appelée lors d'une demande d'écriture du client.att_server_register_packet_handler(packet_handler)
ajoute la fonction callback (packet_handler) de gestion des évènementshci_power_control(HCI_POWER_ON)
active la puce bluetooth.Il n'y a pas besoin de surveiller les demandes des clients bluetooth dans la boucle principale, tout est assuré par les fonctions callback.
Dans la fonction callback packet_handler, il faut publier les services avec les fonctions
gap_advertisements_set_data(taille,adv_datas)
avec adv_datas qui est un tableau d'octets dont le contenu respecte un format particulier :
taille_champ,identifiant_champ,donnees,taille_champ,identifiant_champ,donnees,...avec taille_champ : octet qui contient le nombre d'octets des données + 1, identitfiant_champ : octet qui contient le type des données qui suivent et enfin donnees qui est une suite d'octets qui contiennent les données correspondantes à l'identifiant.
gap_advertisements_enable(1)
activation de la publication des servicesDéclaration des fonctions serveur
#ifndef __SERVER_H
#define __SERVER_H
extern uint8_t const profile_data[];
void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);
#endif
La structure de données adv_data contient les données de publication sous la forme d'un tableau d'octets.
Toutes ces fonctions définies dans le fichier h sont des callback appelées sur des évènements de connexion, déconnexion, lecture d'une caractéristique, écriture d'une caractéristique, ou d'autres évènements.
La fonction packet_handler traite l'initialisation en effectuant la publication des services, et affichant un message de déconnexion.
La fonction read_callback effectue la lecture de l'état de la led et la transmet au client.
La fonction write_callback lit la valeur reçue et affecte cette valeur à la led.
Les fonctions print_buffer et commandeLED sont des fonctions privées uniquement utilisées par les fonctions callback
Définitions des services et caractéristiques picow_ble_led.gatt
PRIMARY_SERVICE, GAP_SERVICE CHARACTERISTIC, GAP_DEVICE_NAME, READ, "picow_temp" PRIMARY_SERVICE, GATT_SERVICE CHARACTERISTIC, GATT_DATABASE_HASH, READ, PRIMARY_SERVICE, f29b181c-9a04-4f7f-8dc7-df499f6602ad CHARACTERISTIC, 6ffa8a48-32ce-4a87-92f5-07977fd3ebbe, READ | WRITE | DYNAMIC,
C'est un fichier au format CSV qui contient la description des services et caractéristiques. On a choisi les mêmes UID que ceux utilisés par le programme Arduino précédent.
Ce fichier gatt permettra de créer le fichier de définitions du même nom picow_ble_led.h
#include <stdio.h>
#include "pico/cyw43_arch.h"
#include "btstack.h"
#include "picow_ble_led.h"
#include "server.h"
#define APP_AD_FLAGS 0x06
static uint8_t adv_data[] = {
0x02, BLUETOOTH_DATA_TYPE_FLAGS, APP_AD_FLAGS,
0x08, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'P', 'i', 'c', 'o', 'L' , 'E' , 'D' ,
0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, 0x1a, 0x18,
};
static const uint8_t adv_data_len = sizeof(adv_data);
static uint8_t etatLed = 0;
void print_buffer(uint8_t *octets,uint16_t taille) {
for(int i=0;i<taille;i+=1) {
printf("%02x ",octets[i]);
}
printf("\n");
}
void commandeLED(uint8_t caractere) {
if (caractere == '1') {
etatLed = 1 ;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, etatLed);
}
else {
etatLed = 0 ;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, etatLed);
}
}
void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
bd_addr_t local_addr;
if (packet_type != HCI_EVENT_PACKET) return;
uint8_t event_type = hci_event_packet_get_type(packet);
switch(event_type){
case BTSTACK_EVENT_STATE:
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
gap_local_bd_addr(local_addr);
printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr));
gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
gap_advertisements_enable(1);
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
printf("HCI_EVENT_DISCONNECTION_COMPLETE\n");
break;
default:
break;
}
}
uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size) {
printf("att_read_callback\n");
if (att_handle == ATT_CHARACTERISTIC_6ffa8a48_32ce_4a87_92f5_07977fd3ebbe_01_VALUE_HANDLE){
uint8_t chled[1] ;
chled[0] = etatLed + '0' ;
printf("etat led %c\n",chled[0]);
return att_read_callback_handle_blob(chled, 1, offset, buffer, buffer_size);
}
return 0;
}
int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) {
printf("att_write_callback\n");
if (att_handle == ATT_CHARACTERISTIC_6ffa8a48_32ce_4a87_92f5_07977fd3ebbe_01_VALUE_HANDLE){
print_buffer(buffer,buffer_size);
commandeLED(buffer[0]);
}
return 0;
}
Contenu du fichier CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
project(picow_ble_led C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(PICO_BOARD pico_w)
pico_sdk_init()
add_executable(picow_ble_led
picow_ble_led.c server.c
)
pico_enable_stdio_usb(picow_ble_led 1)
pico_enable_stdio_uart(picow_ble_led 1)
pico_add_extra_outputs(picow_ble_led)
target_link_libraries(picow_ble_led
pico_stdlib
pico_btstack_ble
pico_btstack_cyw43
pico_cyw43_arch_none
)
target_include_directories(picow_ble_led PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
pico_btstack_make_gatt_header(picow_ble_led PRIVATE "${CMAKE_CURRENT_LIST_DIR}/picow_ble_led.gatt")
pico_add_extra_outputs(picow_ble_led)
Contenu du programme de test
#include "btstack.h"
#include "pico/cyw43_arch.h"
#include "pico/btstack_cyw43.h"
#include "pico/stdlib.h"
#include "server.h"
static btstack_packet_callback_registration_t hci_event_callback_registration;
int main() {
stdio_init_all();
while (!stdio_usb_connected());
if (cyw43_arch_init()) {
printf("initialisation cyw43_arch erreur\n");
return -1;
}
l2cap_init();
sm_init();
att_server_init(profile_data, att_read_callback, att_write_callback);
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
att_server_register_packet_handler(packet_handler);
hci_power_control(HCI_POWER_ON);
while(true) {
sleep_ms(1000);
}
return 0;
}
Pour tester ce serveur on utilise les mêmes clients que ceux utilisés pour la version arduino.
On utilise la librairie bluetooth qui inclut la classe BLE qui permet de gérer la communication bluetooth et de créer, par exemple, un serveur GATT.
Lors de l'initialisation :
objetble = bluetooth.BLE()
: créattion de l'objet BLEobjetble.active(True)
active le circuit bluetooth(addr_type,addr)=objetble.config('mac')
retourne l'adresse bluetooth de la carte ainsi que le type d'adresse.objetble.irq(traiteirq)
installe la fonction callback traiteirq qui sera appelée lors la connexion, déconnexion, l'envoi de données par le client (cas du serveur).( ( handle_led ,) , ) = objetble.gatts_register_services(SERVICES)
qui enregistre les services et caractéristiques avec SERVICES qui est une liste composée de :
bluetooth.UUID
suivi d'une liste de caractéristiques composée de l'UID ainsi que des modes d'accès (bluetooth.FLAG_READ et/ou bluetooth.FLAG_WRITE )ble.gap_advertise(intervalle,adv_data=advertise_datas,connectable=True)
qui publie les services au rythme de intervalle en microsecondes, adv_data est un tableau d'octets qui contient l'identifiant de l'application, connectable autorise ou non au client de se connecter.Dans la boucle de surveillance qui est synchronisée aux évènements dépendant du client (callbak irq)
valeurs=objetble.gatts_read(handle_led)
retourne une liste des valeurs transmises par le clientobjetble.gatts_write(handle_led,valeur)
écrit une valeur dans la caractéristique.
from micropython import const
import struct
from machine import Pin
import bluetooth
import time
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_ADV_TYPE_NAME = const(0x09)
BLE_SERVICE_UUID = bluetooth.UUID('f29b181c-9a04-4f7f-8dc7-df499f6602ad')
BLE_LED_UUID = ( bluetooth.UUID('6ffa8a48-32ce-4a87-92f5-07977fd3ebbe') , bluetooth.FLAG_WRITE | bluetooth.FLAG_READ)
SERVICES = ( ( BLE_SERVICE_UUID, ( BLE_LED_UUID ,) , ) , )
def clevaleurtooctets(cle,valeur):
paire=bytearray()
paire = struct.pack("BB", len(valeur) + 1, cle) + valeur
return paire
def printaddr(addr):
taille=len(addr)
for i in range(taille-1):
octet=addr[i]
print(f"{octet:02x}",end=':')
octet=addr[taille-1]
print(f"{octet:02x}")
estconnecte=False
conn_handle=0
ecriture=False
def traiteirq(event, data):
global estconnecte
global ecriture
global conn_handle
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, addr_type, addr = data
print(f"connecté (handle={conn_handle})", end=": ")
printaddr(addr)
estconnecte=True
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, addr_type, addr = data
print("déconnecté")
estconnecte=False
elif event == _IRQ_GATTS_WRITE:
conn_handle, attr_handle = data
print(f"écriture client (handle={attr_handle})")
ecriture=True
advertise_datas=bytearray()
led = Pin("LED", Pin.OUT)
led.off()
ble = bluetooth.BLE()
led.off()
ble.active(True)
(addr_type,addr)=ble.config('mac')
printaddr(addr)
ble.irq(traiteirq)
( ( handle_led ,) , ) = ble.gatts_register_services(SERVICES)
advertise_datas = clevaleurtooctets(_ADV_TYPE_NAME,"picoled")
ble.gap_advertise(1000,adv_data=advertise_datas,connectable=True)
ble.gatts_write(handle_led,"0")
while True:
if estconnecte :
if ecriture :
valeurs=ble.gatts_read(handle_led)
ecriture=False
if (len(valeurs)>0):
commande=valeurs[0]
if (commande == ord('1')):
led.on()
else:
led.off()
time.sleep(0.5)
bluetooth.UUID(chaine)
crée l'objet UUID qui sera intégré aux services et caractéristiques.
Une caractéristique est une liste composée d'un UID retourné par bluetooth.UUID(chaine)
, suivi d'indicateur de lecture et/ou écriture.
Chaque service est une liste composée d'un UID de service et de listes de caractéristiques.
L'ensemble des services enregistrés est également une liste de services
Le type adv_data est un tableau d'octets qui peut être créé avec la méthode pack
d'un objet struct
.
La méthode read
retourne une liste de valeurs, dans notre cas il s'agit d'un seul octet qui correspond au code ascii du caractère 0 ou 1