Le BLE simplement avec la carte Adafruit Feather nRF52840 Sense

Dans cet article, je vais décrire comment faire un montage utilisant le protocole Bluetooth Low Energy (BLE) très simplement.
Je me suis inspiré du livre « Bluetooth Low Energy Projets pour Arduino, Raspberry Pi et smartphones » (traduit en Français) et disponible chez Dunod :
https://www.dunod.com/sciences-techniques/bluetooth-low-energy-projets-pour-arduino-raspberry-pi-et-smartphones
Copyright 2016 Alasdair Allan et Don Coleman, Dunod 978-2-10-076085-5

Ce livre propose de réaliser plusieurs montages pour se familiariser avec le protocole BLE. Le premier montage est un « commutateur d’éclairage intelligent » mais le module BLE utilisé dans le livre n’est plus commercialisé. https://www.adafruit.com/product/1697
C’est le grand problème de ce livre dont la publication date de 2017. Une éternité dans le domaine de l’électronique, l’IoT, les objets connectés, etc..
Donc je propose ici d’utiliser la carte Adafruit Feather nrf52840 Sense. Elle embarque le nRF52840 de chez Nordic Semiconductors. Un chip très populaire actuellement.
https://www.adafruit.com/product/4516
Vous pouvez aussi prendre l’Adafruit Feather nRF5240 Express :
https://www.adafruit.com/product/4062 C’est presque la même chose, la seule différence est que la « Sense » intègre des capteurs qui permettrons de faire d’autres montages rapidement sans rajouter d’autre module.

1. Installer l’IDE Arduino

La procédure se trouve sur le site Adafruit en Anglais : https://learn.adafruit.com/adafruit-feather-sense
Installer Arduino IDE (Au minimum la version 1.8.6)
Ensuite il faut rajouter la prise en charge de la carte Feather.
Aller dans « Préférences » et ajouter dans « URL de gestionnaire de cartes supplémentaires » https://www.adafruit.com/package_adafruit_index.json

Redémarrer Arduino IDE.
Dans « Boards Manager » rechercher Adafruit nRF52.

Le packet Adafruit nRF52 va s’afficher, cliquer sur « Installer ». Quand le package est installé, aller dans le menu « Outils » « Type de carte » et sélectionner la carte « Adafruit Bluefruit nRF52840 Feather Bluefruit Sense »

Installer le driver Adafruit pour Windows (uniquement si la carte n’est pas détectée au branchement sur le port USB) https://learn.adafruit.com/adafruit-arduino-ide-setup/windows-driver-installation%C2%A0

2. Exécuter son premier sketch

Depuis l’IDE Arduino, aller dans « File » puis « Examples » « 01.Basics » puis « Blink »
C’est le sketch (programme) de base en Arduino.
Il fait juste clignoter une LED présente sur la carte.
Dans le menu « sketch » cliquer sur «  Upload » Le sketch va être compilé et transféré sur la carte.
Puis la LED rouge sur la carte va clignoter.

3. Faire clignoter une LED externe

Nous allons maintenant faire un montage avec une LED comme si c’était une ampoule.
Prendre une LED et une résistance d’environ 100 Ω.
Attention : dans le livre, la résistance est de 220 Ω car la carte est sur 5V, alors que la Feather est sur 3,3V. Relier la patte 3V de la carte à la barre d’alimentation positive de la plaque. Idem pour la patte GND à la barre négative commune. Relier la résistance 100Ω à la patte 5 de la carte, puis à la patte la plus longue de la LED. Relier l’autre patte de la LED à la masse (GND).

Montage carte Feather avec LED

Modifier le sketch « Blink » pour utiliser la sortie 5 :

#define LED_PIN 5
void setup() {
  pinMode(LED_PIN, OUTPUT);
}
void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);
  delay(1000);
}

4. Ajouter un bouton-poussoir

Rajouter un bouton sur la carte d’expérimentation. Brancher l’une des pattes à la broche 6 de la carte, puis l’autre au +3V. Rajouter une résistance de rappel de 10k Ω depuis la broche 6 pour éviter des faux appuis. Voir la page 30 figure 3.7 du livre pour le schéma du montage.

Montage carte Feather avec LED et bouton poussoir

Le sketch Arduino est le suivant :

#define LED_PIN 5
#define BUTTON_PIN 6
int val;
void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);

}
void loop() {
  val = digitalRead(BUTTON_PIN);
  if (val == HIGH) {
    digitalWrite(LED_PIN, HIGH);
  }
   if (val == LOW) {
    digitalWrite(LED_PIN, LOW);
  }
}

Amélioration avec un Anti-Rebond logiciel.

#define LED_PIN 5
#define BUTTON_PIN 6
int currentState;
int debounceState;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);

}

void loop() {
  currentState = digitalRead(BUTTON_PIN);
  delay(10) ;
  debounceState = digitalRead(BUTTON_PIN);

  if (currentState == debounceState) {
   if (currentState == HIGH) {
     digitalWrite(LED_PIN, HIGH);
   }
   if (currentState == LOW) {
     digitalWrite(LED_PIN, LOW);
   }
  }
}

Pour finir, nous allons rajouter la prise en charge du BLE. Le but est de pouvoir lire le status de la LED depuis un smartphone connecté en BLE à la carte, mais aussi de pouvoir allumer la LED à distance. La carte Adafruit Feather nRF52840 Sense intègre déjà un module BLE, il n’y a donc pas de modification du montage à faire.
Le sketch ci-dessous est basé sur celui du livre Exemple 3.1 page 39. Il reprend exactement le même fonctionnement mais a été adapté pour la carte Feather :

#include <bluefruit.h> ❶

#define LED_PIN 5
#define BUTTON_PIN 6

int currentState;
int debounceState;
int switchState = 0;   
int ledState = 0;

BLEService    lightswitch = BLEService(0xFF10); ❷

BLECharacteristic switchCharacteristic = BLECharacteristic(0xFF11);  ❸
BLECharacteristic stateCharacteristic = BLECharacteristic(0xFF12);

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);
  Bluefruit.begin();
  Bluefruit.setName("Light Switch"); ❹
  lightswitch.begin();
  
  switchCharacteristic.setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE); ❺
  switchCharacteristic.setPermission(SECMODE_OPEN, SECMODE_OPEN);
  switchCharacteristic.setFixedLen(1);
  switchCharacteristic.setUserDescriptor("Switch");
  switchCharacteristic.begin();
 
  stateCharacteristic.setProperties(CHR_PROPS_NOTIFY);
  stateCharacteristic.setFixedLen(1);
  stateCharacteristic.setUserDescriptor("State");
  stateCharacteristic.begin(); 
  
  startAdv(); 
  Serial.println("Smart Light Switch");
}

void startAdv(void) ❻
{
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addService(lightswitch);
  Bluefruit.Advertising.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds  
}

void loop() {
  
  currentState = digitalRead(BUTTON_PIN);
  delay(10);
  debounceState = digitalRead(BUTTON_PIN);
  

  if( currentState == debounceState  ) { 
    if ( currentState != switchState ) { 

      if ( currentState == LOW ) { 
        // Button just released
        
      } else { 
        Serial.print(F("Button event: "));
        if ( ledState == 0 ) {
          stateCharacteristic.notify8(1); ❼
          switchCharacteristic.write8(1);
          digitalWrite(LED_PIN, HIGH);
          ledState = 1;
           Serial.println(F("light on"));
       } else {
          stateCharacteristic.notify8(0); ❽
          switchCharacteristic.write8(0);
          digitalWrite(LED_PIN, LOW);
          ledState = 0;
           Serial.println(F("light off"));
       }
      }
      switchState = currentState;
    }
  
  }
}

❶ Inclusion de la librairie Arduino Bluefruit
❷ Création du service avec l’UUID 0xFF10
❸ Création des caractéristiques
❹ Définition du nom du périphérique BLE qui sera affiché sur le smartphone
❺ Définition des propriétés des caractéristiques
❻ Définition de la configuration pour l’ « Advertising ». C’est un élément essentiel du BLE. Le code a été repris de la documentation de la librairie Bluefruit. https://learn.adafruit.com/adafruit-feather-sense/bleadvertising
❼ Bascule les valeurs de switch et state à 1 lors d’un appui sur le bouton-poussoir
❽ Bascule les valeurs de switch et state à 0 lors d’un autre appui

Une fois le code téléversé, vous devriez pouvoir allumer et éteindre la LED comme avant avec le bouton-poussoir mais en plus vous pouvez afficher le status sur un smartphone.
Sur Iphone vous pouvez utilisez l’application LightBlue. Au lancement, l’application scanne les périphériques BLE à proximité. Le périphérique « Light Switch » devrait apparaitre dans la liste. En cliquant dessus, la connexion est établie et les deux caractéristiques « Switch » et « State » vont apparaître.

Pour le moment, il est possible de lire le status de la LED mais pas de changer l’état depuis le smartphone. Pour faire cela, il faut rajouter un gestionnaire d’événements (ou handler).
Rajouter la ligne suivante juste après switchCharacteristic.begin();

switchCharacteristic.setWriteCallback(switchCharacteristicWritten);

Puis à la fin du sketch rajouter :

void switchCharacteristicWritten(uint16_t conn_hdl, BLECharacteristic* chr, uint8_t* data, uint16_t len) {
  (void) conn_hdl;
  (void) chr;
  (void) len; // len should be 1
  
  Serial.print(F("Characteristic event: "));
  if (data[0]) {
    Serial.println(F("light on"));
    digitalWrite(LED_PIN, HIGH);
    ledState = 1;
    stateCharacteristic.notify8(1); 
    
  } else {
    Serial.println(F("light off"));
    digitalWrite(LED_PIN, LOW);
    ledState = 0;
    stateCharacteristic.notify8(0);   
    
  }
}

Voilà maintenant, dans l’application LightBlue, cliquez sur la caractéristique Switch, puis sur « Write new value », entrez la valeur « 01 », puis cliquez sur Done, la LED va s’allumer, ou entrez la valeur « 00 », la LED va s’éteindre.
Le programme complet est disponible en téléchargement ici :
https://1drv.ms/u/s!AnDlERvozWJSiH0mic39i0BAGQDF?e=QXrVsk

Découverte du protocole Bluetooth Low Energy (BLE) par la pratique

Le but de cet article est d’analyser le protocole sans fil BLE à l’aide d’un capteur de température Xiaomi Mi Home et d’une application pour smartphone puis d’un dongle USB. L’objectif étant d’arriver à récupérer des informations du capteur sans passer par l’application officielle Xiaomi.

1. Matériel nécessaire

Tout d’abord, il faut acheter au minimum dongle USB avec le composant CC2540 et avec un câble de programmation :
L’original du fabricant TI à la référence CC2540EMK-USB, mais il en existe des similaires sur des sites comme Amazon, AliExpress
https://www.amazon.fr/AILOVA-D%C3%A9bogage-dInterface-Broche1Mbps-Renifleur/dp/B07Y858TDF/
https://fr.aliexpress.com/item/1005001847937687.html

Ensuite, un programmateur CC DEBUG :
https://www.amazon.fr/gp/product/B07FP5XHPM
et le capteur Xiaomi Mi Temperature and Humidity Monitor 2
Modèle : LYWSD03MMC
Il est compatible Bluetooth Low Energy BLE 4.2
on peut le trouver chez Boulanger ou sur sur AliExpress pour moins de 10€

Il n’est pas nécessaire d’avoir une passerelle Xiaomi, le capteur peut se connecter directement à un smartphone.

2. Test avec l’application nRF Connect

Télécharger l’application nRF Connect sur un smartphone Android ou Apple

Mettre le capteur de température à proximité du smartphone et lancer un scan.

Vous allez voir apparaître une ligne avec « LYWSD03MMC ». Avec l’application, on peut se connecter au capteur et lire plusieurs informations.

2. Lecture des paquets avec le dongle USB CC2540 de TI

Installer le logiciel SmartRF Flash programmer de Texas Instruments. Ne pas utiliser la version V2 qui n’est pas compatible avec le CC DEBUGGER. Par exemple la version 1.12.8 du 31 Mai 2016.
Le logiciel est gratuit, mais il faut avoir un compte TI pour le télécharger.
https://www.ti.com/tool/FLASH-PROGRAMMER
Ensuite, il faut installer le driver pour le CC DEBUGGER :
https://www.ti.com/lit/zip/swrc212
Après avoir installé le driver, connecter le CC DEBUGGER au PC. Vérifier que le debugger est bien reconnu en ouvrant le « Gestionnaire de Périphériques » de Windows. Le debugger devrait apparaitre comme un « Cebal controlled device »

Vérification du driver du CC DEBUGGER

Si le driver, n’est pas installé correctement, vous pouvez installer le driver manuellement.
Télécharger et installer le logiciel PACKET-SNIFFER :
https://www.ti.com/tool/PACKET-SNIFFER
(Ne pas utiliser SmartRF Packet Sniffer 2, il n’est pas compatible avec le CC2540) prendre par exemple la version v2.18.1 du 30 Juin 2014)
Récupérer le fichier C:\Program Files (x86)\Texas Instruments\SmartRF Tools\Packet Sniffer\bin\general\firmware\sniffer_fw_cc2540_usb.hex

3. Connecter le CC DEBUGGER

Brancher le CC DEBUGGER à un port USB du PC puis au dongle CC2540 qui lui même doit être connecté à un autre port USB du PC, comme sur la figure ci-dessous :

Branchements

Appuyer sur le bouton RESET du CC DEBUGGER, la LED devrait s’allumer en vert.

4.Programmation

Exécuter le logiciel Flash Programmer, dans la section Flash image, sélectionnez le fichier sniffer_fw_cc2540_usb.hex
Cliquer sur « Perform actions »

TI Flash Programmer

4. Lecture des trames

Exécuter le logiciel SmartRF Packet Sniffer, sélectionner le protocole « Bluetooth Low Energy » et cliquer sur « Start »

Logicel TI SmartRF Packet Sniffer

Vérifier que le dongle est bien reconnu et cliquer sur le bouton « Play » :

SmartRF Packet Sniffer démarrage

Les premières trames devraient apparaître. Il peut y en avoir beacoup car il y a de plus en plus d’émetteur Bluetooth autour de nous !
Mettre le capteur proche du dongle et observer la valeur RSSI. C’est la puissance du signal reçue. La valeur la plus élevée sera probablement celle du capteur.
Ici on voit -34dBm. Noter la valeur AdvA qui est l’adresse du capteur. Ici 0xA4C1388F4833

Affichage des trames BLE

Maintenant, on va filtrer les trames.
Dans le menu « Display filter », sélectionner le « Field Name » = ADV_IND AdvA et appuyer sur le bouton « First », puis entrer l’adresse AdvA récupéré plus haut dans le champ « Filter condition » : AA1=0xA4C1388F4833, cliquer sur Add, puis « Apply filter ».

Filtrage les trames BLE

On va chercher à retrouver le nom du capteur.
On peut constater que toutes les trames ADV_IND sont identiques, c’est des trames d' »ADVERTISEMENT ». Les données sont dans AdvData, mais on ne trouve pas le nom du capteur.
Donc cela doit être dans une autre trame. En effet, il est possible d’envoyer une trame ADV_SCAN_REQ et le capteur répondra par une trame ADV_SCAN_RSP on va donc rechercher ces trames.
Dans le menu « Display filter », sélectionner « Field Name » = « ADV_SCANRSP AdvA »
Cliquer sur le bouton « First », puis entrer l’adresse AdvA récupéré plus haut dans le champ « Filter condition » : AA5=0xA4C1388F4833
Cliquer sur Add, puis sur Apply filter.
Au bout d’un certain temps une trame va apparaitre :

Trame ADV_SCANRSP

Dans cette trame, on peut analyser les données « ScanRspData » et observer que le code hexadécimal convertit en caractères ASCII correspond bien au nom du capteur :

4C5957534430334D4D43
LYWSD03MMC
Décodage nom du capteur en ASCII

Dans un autre article, on apprendra à décoder les trames BLE et voir si il est possible de décoder les données de température et d’humidité du capteur.