# Lecteur de badge comme clavier BT



# Principe

La saisie des numéros longs est fastidieuse : codes barres, numéros de cartes étudiants, etc. doivent pouvoir être "scannés" rapidement pour remplir des formulaires.

Pour les codes barres, la solution est connue et commerciale : il s'agit de "douchettes" laser, comme par exemple la série Honeywell 1470 :

[![sps-ppr-1470g-barcode-scanner-5.webp](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/scaled-1680-/sps-ppr-1470g-barcode-scanner-5.webp)](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/sps-ppr-1470g-barcode-scanner-5.webp)

L'appareil est reconnu comme un clavier par l'ordinateur auquel il est connecté. Ainsi, appuyer sur la gachette revient à saisir au clavier les numéros inscrits sur le code barre ou le QR code.

L'idée est de faire la même chose avec un M5Stack équipé d'un lecteur RFID pour saisir les numéros de carte étudiant.

On pourrait alternativement imprimer des codes barres à coller sur les cartes étudiant.

<p class="callout warning">Cette approche est très différente de celle adoptée dans les autres chapitres du projet. Ici, Timetonic ou Fabtrack n'ont pas d'interaction avec le M5 Stack. La douchette ou le lecteur RFID sont -au fond- le prolongement de la main de l'utilisateur qui saisit le code. Dans les autres chapitres, le M5 Stack équipé du lecteur utilise l'API de Timetonic pour déclencher des actions. C'est radicalement différent (et plus complexe).</p>

# Bibliothèques utilisées

### Emuler un clavier

Pour pouvoir interagir avec un maximum de dispositifs d'interrogation de Timetonic/Fabtrack, que ce soient des ordinateurs fixes ou des iPads mobiles dans l'espace, le scanner de cartes est sans fil et se connecte en bluetooth BLE.

Une bibliothèque qui permet cela pour les plateformes à base d'ESP32 est disponible[ ici](https://github.com/T-vK/ESP32-BLE-Keyboard). ([archive](https://wiki.fablab.sorbonne-universite.fr/BookStack/books/mise-en-place-dautomatisations-au-fablab/page/lecture-de-carte-rfid))

[BleKeyboard.cpp](https://wiki.fablab.sorbonne-universite.fr/BookStack/attachments/1548)

[BleKeyboard.h](https://wiki.fablab.sorbonne-universite.fr/BookStack/attachments/1549)

<p class="callout danger">La disposition du clavier qui est émulée est celle du clavier QWERTY-US exclusivement ! </p>

Il faut donc que ce soit le clavier choisi dans l'environnement/OS. Sinon, le résultat peut être surprenant.

Accesoirement, on constate que le clavier bluetooth, même lorsqu'aucune carte n'est transmise, cause des frappes malignes. L'ajout d'un appel à la fonction `releaseAll` semble résourdre le problème. C'est un point à éclaircir.

Testé totalement sur macOS.

Sous Windows, le périphérique bluetooth est reconnu, se connecte, transmets correctement nom et niveau de charge batterie, mais aucune donnée ne semble transmise : dans le menu "bluetooth et autres appareils", il n'apparaît pas dans la section claviers/souris mais dans "autres appareils" :

[![Capture d’écran 2025-07-22 132736.png](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/scaled-1680-/capture-decran-2025-07-22-132736.png)](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/capture-decran-2025-07-22-132736.png)

<p class="callout warning">Reste à faire : </p>

- tester sous Linux (le PC de l'entrée)
- tester avec les iPad.

### Lire les cartes RFID

Pour lire les cartes, on utilise la même bibliothèque ce celle déjà employée par Mathieu de Rooster, [qui explique son fonctionnement ici.](https://wiki.fablab.sorbonne-universite.fr/BookStack/books/mise-en-place-dautomatisations-au-fablab/page/lecture-de-carte-rfid)

[MFRC522\_I2C.h](https://wiki.fablab.sorbonne-universite.fr/BookStack/attachments/1550)

[MFRC522\_I2C.cpp](https://wiki.fablab.sorbonne-universite.fr/BookStack/attachments/1551)

# Implémentation

Le code ci-dessous permet, en utilisant les bibliothèques précédentes, d'émuler un clavier bluetooth pour envoyer les caractères lus sur une carte RFID.

Le programme comporte :

- une fonction qui permet de transmettre également la valeur du niveau de charge de la batterie (comme le fait tout périphérique bluetooth)
- un contrôle de longueur de la chaîne lue et convertie avant son envoie par la fonction `print`, et la prise en charge d'une erreur si la longueur n'est pas exactement celle attendue pour les cartes Izly et cartes d'étudiants.
- un forçage de la fonction `releaseAll` après chaque transmission pour éviter les caractères surnuméraires.
- on a ajouté des signaux sonores pour confirmer la lecture

[BleKeyboardExemple.ino](https://wiki.fablab.sorbonne-universite.fr/BookStack/attachments/1553)

```c++

#include <M5Unified.h>
#include "BleKeyboard.h"
#include "MFRC522_I2C.h"

BleKeyboard bleKeyboard("M5CardReader", "M5Stack", 100);
MFRC522 mfrc522(0x28);

void setup() {
  M5.begin();
  Wire.begin();
  Serial.begin(115200);
  bleKeyboard.begin();
  M5.Lcd.println("M5Stack BLE Keyboard");
  mfrc522.PCD_Init();
  M5.Display.setTextSize(2);
  M5.Display.setFont(&fonts::efontCN_12);
  M5.Speaker.begin();
  M5.Speaker.setVolume(50);
}

void loop() {
  M5.update();
  String uid = "";
  M5.Lcd.clear();

  M5.Display.setTextDatum(MC_DATUM);
  M5.Display.setTextSize(3);
  M5.Display.drawString("Présentez", 160, 100);
  M5.Display.drawString("votre carte", 160, 140);

  while (1) {
        M5.Display.setTextSize(1);
        float batLevel = M5.Power.getBatteryLevel();
        M5.Display.drawString("Batterie : " + String(batLevel), 160, 40);
        bleKeyboard.setBatteryLevel(M5.Power.getBatteryLevel());
        if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
            for (byte i = 0; i < mfrc522.uid.size; i++) {
                if (mfrc522.uid.uidByte[i] < 0x10) {
                  uid += "0";
                }
                uid += String(mfrc522.uid.uidByte[i], HEX);
                if (i < mfrc522.uid.size - 1) {
                  uid += ":";
                }
            }
            M5.Lcd.clear();
            int L = uid.length();
            if (L == 20) { 
              M5.Display.setTextSize(3);
              M5.Display.drawString("Carte scannée", 160, 120);
              M5.Speaker.tone(440, 250);  // Frequence Hz, duree ms
              M5.delay(100);
              M5.Speaker.tone(880, 250); 
              //M5.Display.drawString(uid, 160, 120);
              int L = uid.length();
              //M5.Display.drawString(String(L), 160, 160);
              String uidDeb = "";
              String uidFin = "";
              for (int j = 0; j < 10 ; j++) {
                uidDeb += uid[j];
                uidFin += uid[j+10];
              } 
              //M5.Display.drawString(uidDeb, 160, 200);
              //M5.Display.drawString(uidFin, 160, 240);
              bleKeyboard.print(uidDeb);
              M5.delay(100);
              bleKeyboard.print(uidFin);
              M5.delay(2000);
              bleKeyboard.releaseAll();
              break;
            }
            else {
              M5.Display.setTextSize(3);
              M5.Display.drawString("Erreur de lecture", 160, 80);
              M5.Display.drawString("Réessayez svp", 160, 120);
              M5.Speaker.tone(440, 250);  // Frequence Hz, duree ms
              M5.delay(100);
              M5.Speaker.tone(220, 250); 
              M5.delay(2000);
              bleKeyboard.releaseAll();
              break;
            }
        }
  }
}


```