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

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.

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).


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. (archive)

BleKeyboard.cpp

BleKeyboard.h

La disposition du clavier qui est émulée est celle du clavier QWERTY-US exclusivement ! 

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

Reste à faire : 

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.

MFRC522_I2C.h

MFRC522_I2C.cpp

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 :

BleKeyboardExemple.ino


#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;
            }
        }
  }
}