# Mise en place d'automatisations au fablab

# Présentation et mise en place de l'environnement de développement

présentation des objectifs et desccription des librairies, initialisation de TimeTonic et mise en place de l'environnement de développement

# Objectifs

Dans le cadre de l’amélioration des processus au sein du fablab, un projet d’automatisation a été initié afin de moderniser et de simplifier la gestion des accès et des ressources. Ce projet s’articule autour de plusieurs objectifs principaux :

**Automatisation de l’enregistrement via la carte étudiante**  
L’un des axes majeurs du projet consiste à automatiser l’enregistrement des utilisateurs grâce à leur carte étudiante. Cette solution vise à remplacer les méthodes manuelles d’identification par un système de scan rapide et sécurisé, facilitant ainsi l’accès au fablab tout en renforçant la traçabilité des entrées.

**Création d’une base de données centralisée et complète**  
Le projet prévoit la mise en place d’une base de données exhaustive sur Timetonic. Celle-ci regroupera l’ensemble des enregistrements, des emprunts de matériel et des utilisations de machines. L’objectif est de disposer d’un historique fiable et consultable, permettant d’optimiser la gestion des équipements et d’assurer un suivi précis des activités.

**Refonte du mode de gestion des emprunts et des utilisations**  
Le fonctionnement des emprunts et de l’utilisation des machines sera entièrement revu. Désormais, toutes les opérations passeront par le scan de la carte étudiante, supprimant la nécessité de solliciter les emplois étudiants pour valider les demandes. Ce nouveau mode opératoire vise à fluidifier les procédures, à réduire les délais et à responsabiliser les utilisateurs.

En résumé, ce projet d’automatisation s’inscrit dans une démarche d’innovation et d’efficacité, en s’appuyant sur des technologies modernes pour améliorer l’expérience des usagers et la gestion quotidienne du fablab.

# Présentation de TimeTonic

**TimeTonic** est une plateforme collaborative no-code, conçue pour centraliser, organiser et automatiser la gestion de données, de projets et de processus métier. Flexible et visuelle, elle s’adresse aussi bien aux petites équipes qu’aux grandes entreprises, permettant de créer rapidement des applications métiers personnalisées sans compétences en programmation<span class="whitespace-nowrap">.</span>

## Fonctionnalités principales

- **Organisation visuelle et collaborative** : TimeTonic propose des espaces de travail (« books ») où l’on peut structurer ses données sous forme de tableaux intelligents (Smart-tables®), aussi flexibles qu’un tableur mais aussi puissants qu’une base de données relationnelle. Chaque espace peut être personnalisé, partagé et enrichi de commentaires, fichiers, dates, couleurs, etc.
- **Multiples vues** : Il est possible de passer d’une vue tableau à une vue Kanban, calendrier ou Gantt en un clic, pour s’adapter à chaque besoin métier<span class="whitespace-nowrap">.</span>
- **Gestion documentaire et communication** : Chaque espace dispose de sa propre messagerie, d’une adresse email dédiée et permet de centraliser fichiers, notes et discussions, facilitant la collaboration en temps réel<span class="whitespace-nowrap">.</span>
- **Historique et traçabilité** : Toutes les modifications sont historisées, assurant une parfaite traçabilité des actions<span class="whitespace-nowrap">.</span>

## Avantages de TimeTonic

- **Flexibilité extrême** : La plateforme s’adapte à tous les métiers et à toutes les tailles d’organisation. Elle permet de créer des workflows sur-mesure, d’ajouter des champs, des règles d’automatisation et de personnaliser l’interface selon les besoins<span class="whitespace-nowrap">.</span>
- **Simplicité d’utilisation** : Aussi simple à prendre en main qu’un tableur ou des post-its, mais aussi puissante qu’une solution professionnelle avancée<span class="whitespace-nowrap">.</span>
- **Collaboration en temps réel** : Les équipes travaillent dans un espace commun, partagent des informations instantanément et évitent la dispersion des données (emails, fichiers, etc.)<span class="whitespace-nowrap">.</span>
- **Sécurité** : TimeTonic est certifié SecNumCloud et ISO 27001, garantissant la sécurité des données<span class="whitespace-nowrap">.</span>

## Automatisation des processus

TimeTonic intègre un moteur d’automatisation puissant permettant de déclencher des actions dès qu’un événement se produit dans la base de données :

- **Automatisations natives** : Modification automatique de champs, envoi d’emails (avec ou sans pièce jointe), création de nouveaux enregistrements, génération de fichiers ICS (calendrier), etc.
- **Automatisations avancées avec IA** : Il est possible d’intégrer des automatisations utilisant l’intelligence artificielle, par exemple pour générer des suggestions, résumer des rapports, reformater des données ou traduire automatiquement du contenu. Ces automatisations se configurent en quelques étapes et s’intègrent directement dans les workflows existants<span class="whitespace-nowrap">.</span>
- **Formules et règles personnalisées** : Comme dans un tableur, il est possible de créer des formules pour automatiser des calculs ou des mises à jour de données<span class="whitespace-nowrap">.</span>

## Communication et intégration avec d’autres outils (API)

TimeTonic propose une API complète, permettant d’intégrer la plateforme à d’autres applications ou systèmes d’information :

- **API REST** : L’API permet de lire, modifier, créer et supprimer des données dans les tables de TimeTonic, facilitant l’intégration avec des logiciels tiers, des sites web ou des applications mobiles<span class="whitespace-nowrap">.</span>
- **Automatisation inter-applications** : Grâce à des plateformes comme Pipedream, TimeTonic peut être connecté à des outils comme Slack, Gmail, Shopify, Google Sheets, etc. Il devient alors possible de synchroniser des données, déclencher des actions automatiques (création de tâches, alertes, notifications, etc.) ou maintenir une cohérence temps réel entre différents systèmes<span class="whitespace-nowrap">.</span>
- **Cas d’usage concrets** :
    
    
    - Création automatique de tâches à partir de ventes réalisées sur un site e-commerce.
    - Synchronisation des notifications avec Slack pour informer l’équipe en temps réel.
    - Gestion automatisée des stocks avec alertes email dès qu’un seuil est franchi<span class="whitespace-nowrap">.</span>

---

**En résumé**, TimeTonic se distingue par sa capacité à centraliser l’information, à automatiser les tâches répétitives et à communiquer facilement avec l’ensemble de l’écosystème numérique de l’entreprise. C’est un véritable atelier numérique collaboratif, personnalisable et évolutif, qui permet de gagner en efficacité, en transparence et en réactivité

# Présentation M5Stack

Dans le cadre de ce projet, nous utilisons la plateforme de développement **M5Stack**, et plus précisément le module **M5Stack Basic** associé à un **module RFID I2C**. Cette combinaison permet de réaliser rapidement des prototypes embarquant des fonctionnalités de lecture de badges RFID. M5Stack reprend tous les codes de développement d'Arduino, comme son language (C++), et est notamment compatible avec une grande partie de ses librairies.

## 1. La plateforme M5Stack

La **M5Stack** est une solution de développement modulaire dédiée à l’IoT (Internet of Things). Elle se distingue par sa facilité d’utilisation, son aspect compact et sa capacité à empiler différents modules pour ajouter des fonctionnalités selon les besoins du projet.

**Principaux atouts :**

- **Modularité** : modules et unités empilables, connectables sans soudure.
- **Compatibilité logicielle** : support de la programmation graphique (UIFlow), Arduino, MicroPython, ESP-IDF.
- **Connectivité** : Wi-Fi et Bluetooth grâce au microcontrôleur ESP32.
- **Écosystème riche** : de nombreux modules (capteurs, actionneurs, interfaces, etc.) sont disponibles.

## 2. Le M5Stack Basic

Le **M5Stack Basic** est le modèle d’entrée de gamme de la série. Il est particulièrement adapté à l’apprentissage, au prototypage rapide et au développement de solutions embarquées.

**Caractéristiques principales :**

- **Microcontrôleur** : ESP32 (dual-core, 240 MHz)
- **Écran** : TFT couleur 2,0" (320x240 px)
- **Connectivité** : Wi-Fi, Bluetooth
- **Stockage** : slot microSD
- **Contrôles** : 3 boutons utilisateur, haut-parleur intégré
- **Batterie** : LiPo 110 mAh rechargeable
- **Extension** : ports Grove (I2C/UART), connecteur M-BUS, broches GPIO accessibles
- **Boîtier** : plastique industriel compact et robuste

Le M5Stack Basic est donc une base idéale pour développer des applications connectées et interactives.

## 3. Le module RFID I2C (MFRC522)

Pour ajouter la fonctionnalité de lecture de badges RFID, nous utilisons un module RFID basé sur la puce **MFRC522**, qui communique avec le M5Stack via le protocole **I2C**.

**Caractéristiques du module RFID :**

- **Lecture/écriture** de tags RFID/Mifare à 13,56 MHz
- **Interface** : I2C (adresse 0x28)
- **Connexion** : via port Grove du M5Stack
- **Applications** : contrôle d’accès, pointage, gestion de stock, etc.

**Intégration :**

- Le module RFID se branche simplement sur le port Grove du M5Stack Basic, ce qui permet une installation rapide et sans soudure.

---

Cette combinaison d’outils permet de disposer d’une plateforme puissante, flexible et facile à mettre en œuvre pour des projets impliquant la lecture de badges RFID et le développement de solutions IoT.

# Mise en place de plateformeIO

## Présentation de PlatformIO

**PlatformIO** est un environnement de développement intégré (IDE) moderne et multiplateforme, spécifiquement conçu pour le développement de logiciels embarqués. Il permet de programmer une grande variété de microcontrôleurs et de cartes, en offrant une gestion avancée des bibliothèques, de la compilation et du déploiement, tout en restant open source et sans verrouillage propriétaire<span class="whitespace-nowrap">.</span>

## Avantages de PlatformIO

- **Support multi-plateformes** : fonctionne sous Windows, macOS, Linux.
- **Gestion centralisée des dépendances** : les bibliothèques nécessaires sont automatiquement installées et mises à jour.
- **Automatisation** : compilation, upload, gestion du port série et tâches personnalisées intégrées.
- **Flexibilité** : compatible avec de nombreux frameworks (Arduino, ESP-IDF, etc.) et microcontrôleurs.
- **Débogage et analyse avancés** : outils de test, d’analyse de code et de gestion de projet professionnels<span class="whitespace-nowrap">.</span>

## Intégration dans Visual Studio Code (VS Code)

PlatformIO s’intègre parfaitement à **Visual Studio Code** (VS Code), l’éditeur de code de Microsoft. L’extension PlatformIO IDE pour VS Code transforme ce dernier en un environnement puissant pour le développement embarqué<span class="whitespace-nowrap">.</span>

## Installation de PlatformIO dans VS Code

1. **Installer VS Code** : Téléchargez et installez Visual Studio Code depuis le site officiel.
2. **Installer l’extension PlatformIO IDE** :
    
    
    - Ouvrez VS Code.
    - Allez dans l’onglet Extensions (Ctrl+Shift+X).
    - Recherchez “PlatformIO IDE” et cliquez sur “Installer”<span class="whitespace-nowrap">.</span>
3. **Redémarrer VS Code** si nécessaire pour activer l’extension.

Une fois installée, l’icône PlatformIO apparaît dans la barre latérale de VS Code, donnant accès à toutes les fonctionnalités de gestion de projets, compilation, upload et monitoring série<span class="whitespace-nowrap">.</span>

## Configuration pour développer sur M5Stack Basic

Le **M5Stack Basic** repose sur un microcontrôleur ESP32. Pour le programmer avec PlatformIO, il suffit de créer un nouveau projet en sélectionnant la carte appropriée et d’ajouter les bibliothèques nécessaires<span class="whitespace-nowrap">.</span>

## Étapes de configuration

1. **Créer un nouveau projet PlatformIO** :
    
    
    - Cliquez sur l’icône PlatformIO dans VS Code.
    - Sélectionnez “New Project”.
    - Donnez un nom au projet (ici FabLab stage).
    - Choisissez la carte : recherchez et sélectionnez `M5Stack Core ESP32` (ID : `m5stack-core-esp32`).
    - Sélectionnez le framework souhaité (Arduino ou ESP-IDF, par exemple).
    - Validez pour créer le projet.
2. **Configurer le fichier platformio.ini** :  
    Le fichier `platformio.ini` est alor configuré automatiquementet contient normalement :
    
    <div class="w-full md:max-w-[90vw]"><div class="codeWrapper text-textMainDark selection:!text-superDark selection:bg-superDuper/10 bg-offset dark:bg-offsetDark my-md relative flex flex-col rounded font-mono text-sm font-thin"><div class="translate-y-xs -translate-x-xs bottom-xl mb-xl sticky top-0 flex h-0 items-start justify-end"></div><div class="-mt-xl"><div class="pr-lg">`[env:m5stack-core-esp32]platform = espressif32board = m5stack-core-esp32framework = arduino`</div></div></div></div>Vous pouvez personnaliser d’autres options (fréquence CPU, protocole d’upload, etc.) selon vos besoins<span class="whitespace-nowrap">. Les bibliothèques ajoutées au porjet via plateformeIO seront automattiquement ajoutées au fichier platformio.ini.</span>
3. **Développer et téléverser votre code** :
    
    
    - Écrivez votre code dans le dossier `src`.
    - Utilisez les boutons “Build” (Ctrl+Alt+B) et “Upload” (Ctrl+Alt+U) de PlatformIO pour compiler et téléverser le programme sur le M5Stack Basic<span class="whitespace-nowrap">.</span>
    - Le moniteur série intégré permet de visualiser les messages envoyés par la carte.

---

**En résumé**, PlatformIO, intégré à VS Code, offre un environnement moderne, puissant et flexible pour développer sur M5Stack Basic. Il facilite la gestion des bibliothèques, la compilation, l’upload et le monitoring, tout en permettant une personnalisation avancée et une grande évolutivité pour tous vos projets embarqués.

# Présentation des librairies utilisées

## **M5Unified**

La librairie **M5Unified** est le cœur du développement sur les appareils M5Stack. Elle offre une interface unifiée pour contrôler la majorité des composants matériels intégrés aux modules M5Stack, comme l’écran LCD, les boutons, le haut-parleur, le microphone, etc. Grâce à cette abstraction, le même code peut fonctionner sur différents modèles de M5Stack sans modification majeure. M5Unified est compatible avec les plateformes Arduino et ESP-IDF, ce qui facilite le développement et améliore la portabilité du code<span class="whitespace-nowrap">.</span>

## **Wire**

La librairie **Wire** permet la communication via le bus I2C, un protocole de communication série très utilisé pour connecter des capteurs et modules externes à une carte microcontrôleur. Elle sert notamment à dialoguer avec des périphériques comme le lecteur RFID ou d’autres capteurs branchés sur le port Grove du M5Stack<span class="whitespace-nowrap">.</span>

## **WiFi**

La librairie **WiFi** permet de connecter l’ESP32 (présent dans le M5Stack Basic) à un réseau sans fil. Elle offre des fonctions pour scanner les réseaux disponibles, se connecter à un point d’accès, gérer les événements Wi-Fi et obtenir une adresse IP. Elle est essentielle pour tout projet nécessitant une communication réseau, comme l’envoi ou la réception de données sur Internet<span class="whitespace-nowrap">.</span>

## **HTTPClient**

**HTTPClient** est une librairie qui facilite la réalisation de requêtes HTTP (GET, POST, etc.) depuis l’ESP32. Elle permet d’interagir facilement avec des serveurs web ou des API (comme ici celui de TimeTonic), d’envoyer des données ou de récupérer des informations à distance. Cette librairie est souvent utilisée en complément de WiFi pour des applications IoT connectées<span class="whitespace-nowrap">.</span>

## **MFRC522\_I2C**

La librairie **MFRC522\_I2C** permet de piloter un module lecteur RFID MFRC522 via le protocole I2C. Elle simplifie la lecture et l’écriture de badges RFID/Mifare en fournissant des fonctions haut niveau pour détecter, lire et écrire sur les cartes. Cette librairie est compatible avec Arduino et ESP32, et nécessite de spécifier l’adresse I2C du module et la broche de reset<span class="whitespace-nowrap">. Attention toutefois, un certain nombre de librairies porte ce nom et seule celle disponible sur le [GitHub de M5Stack](https://github.com/m5stack/M5StickC/tree/master/examples/Unit/RFID) fonctionne avec leur capteur RFID.</span>

## **ArduinoJson**

**ArduinoJson** est une librairie puissante et optimisée pour la manipulation de données JSON sur microcontrôleurs. Elle permet de sérialiser (convertir des objets en texte JSON) et de désérialiser (analyser du texte JSON pour en extraire des données) facilement, ce qui est très utile pour échanger des données structurées avec des serveurs web ou des API (cellui de TimeTonic utilise principalement des objets JSON pour recevoir/envoyer des données). Elle gère les objets, les tableaux, les filtres et l’optimisation mémoire, ce qui la rend idéale pour les projets embarqués<span class="whitespace-nowrap">.</span>

---

## Résumé des rôles

<div class="group relative" id="bkmrk-librairie-r%C3%B4le-princ"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain dark:border-borderMainDark my-[1em] w-full table-auto border"><thead class="bg-offset dark:bg-offsetDark"><tr><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Librairie</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Rôle principal</th></tr></thead><tbody><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">M5Unified</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Contrôle du matériel M5Stack (écran, boutons, haut-parleur, etc.)</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Wire</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Communication I2C avec les modules externes</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">WiFi</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Connexion réseau sans fil et gestion des événements Wi-Fi</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">HTTPClient</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Envoi et réception de requêtes HTTP vers/depuis des serveurs web</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">MFRC522\_I2C</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Lecture/écriture de badges RFID via le module MFRC522 en I2C</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">ArduinoJson</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Manipulation et traitement de données JSON (sérialisation/désérialisation)</td></tr></tbody></table>

</div><div class="px-two bg-background border-border shadow-subtle pointer-coarse:opacity-100 right-xs absolute bottom-0 flex gap-2 rounded-lg border py-px opacity-0 transition-opacity group-hover:opacity-100"><div><div class="flex items-center min-w-0 font-medium gap-1 justify-center"><div class="flex shrink-0 items-center justify-center size-3.5"><svg class="tabler-icon tabler-icon-download " fill="none" height="14" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.7142857142857142" viewbox="0 0 24 24" width="14" xmlns="http://www.w3.org/2000/svg"></svg>  
</div></div></div></div></div>---

L’utilisation combinée de ces librairies permet de gérer efficacement le matériel, de communiquer avec des serveurs distants et de traiter des données structurées, couvrant ainsi l’ensemble des besoins fonctionnels du projet.

# Premier prototype et preuve de concept

mise en place d'un exemple simple permettant la lecture de cartes RFID et la communication entre le M5Stack et l'API de TimeTonic.

# Lecture de carte RFID

## 1. Connexion matérielle

Le module RFID MFRC522 se connecte au port GROVE A du M5Stack Basic, qui correspond aux broches I2C (SDA sur GPIO21, SCL sur GPIO22). L’adresse I2C par défaut du module est 0x28<span class="whitespace-nowrap">.</span>

---

## 2. Initialisation logicielle

Il faut utiliser la bibliothèque **MFRC522\_I2C** pour piloter le lecteur RFID, ainsi que les bibliothèques **Wire** (I2C) et **M5Unified** (pour gérer l’écran et l’initialisation du M5Stack).

L’initialisation consiste à :

- Démarrer le M5Stack (`M5.begin()`).
- Initialiser le bus I2C (`Wire.begin()`).
- Initialiser le module RFID (`mfrc522.PCD_Init()`).

---

## 3. Lecture du UID

Dans la boucle principale du programme, il s’agit de :

- Vérifier la présence d’une nouvelle carte avec `mfrc522.PICC_IsNewCardPresent()`.
- Lire la carte avec `mfrc522.PICC_ReadCardSerial()`.
- Si une carte est détectée, parcourir le tableau `mfrc522.uid.uidByte[]` qui contient le UID, et l’afficher sur l’écran du M5Stack ou sur le port série<span class="whitespace-nowrap">.</span>

---

## 4. Fonction de conversation hexadécimale

Le capteur RFID renvoie les données lues de la carte dans un tableau sous forme de bits bruts. Il faut donc convertir ces données en une chaine de charactères hexadécimaux :

```c++
String uidhex(MFRC522 &rfid){
    String uidStr;
    for (byte i = 0; i < rfid.uid.size; i++) {
        if (rfid.uid.uidByte[i] < 0x10) uidStr += "0";
        uidStr += String(rfid.uid.uidByte[i], HEX);
        if (i < rfid.uid.size - 1) uidStr += ":";
    }
    return uidStr;
}
```

Ce code renvoie une chaine de charactères contenant le numéro de série de la carte lue au format standard, c'est à dire : XX:XX:XX:XX ... où X est un caractère hexadécimal.

## 5. Exemple de code

```c++
#include <M5Unified.h>
#include <Wire.h>
#include "MFRC522_I2C.h"

MFRC522 mfrc522(0x28);  // Adresse I2C du module RFID

void setup() {
    M5.begin();
    Wire.begin();
    mfrc522.PCD_Init();
    M5.Display.setTextSize(2);
    M5.Display.println("Presentez une carte");
}

void loop() {
    if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
        String uid = uidhex(mfrc522);
        M5.Display.print("UID : ");
        M5.Display.println("uid");)
    }
    M5.delay(2000);
    M5.Display.fillRect(0, 60, 320, 240, BLACK);
}
```

Ce code affiche le UID de chaque carte RFID présentée devant le lecteur sur l’écran du M5Stack<span class="whitespace-nowrap">.</span>

---

## 5. Résumé du fonctionnement

- Branchez le module RFID sur le port GROVE A du M5Stack.
- Chargez le code exemple sur le M5Stack.
- Approchez une carte RFID ou un appareil NFC du lecteur.
- Le UID de la carte s’affiche instantanément à l’écran.

Cette méthode est fiable pour des applications telles que le contrôle d’accès, la gestion de présence ou l’inventaire.

# Communication avec l'API de TimeTonic

Pour permettre au M5Stack de communiquer avec l’API de TimeTonic, il faut exploiter les capacités réseau du M5Stack (via l’ESP32), utiliser les librairies WiFi et HTTPClient, et structurer les requêtes selon les spécifications de l’API TimeTonic.

<div class="relative" id="bkmrk-"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">---

</div></div>## 1. Préparer l’accès à l’API TimeTonic

L’API TimeTonic permet d’accéder, de lire et de modifier les données de vos espaces de travail à distance<span class="whitespace-nowrap">.</span> Pour chaque requête, il est nécessaire de transmettre un **sesskey** (clé d’API/session), associé à votre compte utilisateur. Cette clé s’obtient via l’interface TimeTonic et doit être gardée confidentielle (elle ne sera donc publiée ici, si vous copiez l'exemple de code, pensez bien à mettre la votre).

Il est aussi important de repérer dès maintenant où trouver les différents codes permettant d'identifier les books, tables, lignes et colonnes dans TimeTonic :

Book ID : nom de l'espace de travail (attention, si celui-ci a été renommé, il gardera son 1er nom en ID, en cas de doute vérifier dans les paramètres du book dans la catégorie workspace informations).

Table ID : code à 6 chiffres accessible en cliquant sur les 3 points verticaux à droite de la fenêtre lorsque vous visualiser la table, puis en cliquant sur organize fields. L'ID sera entre parenthèse en haut de la fenêtre qui apparait.

Field ID : code à 6 chiffres accessible dans la même fenêtre que pour Table ID, sous la catégorie éponyme.

Row ID : correspond simplement au numéro de la ligne. Lorsqu'on voudra en créer une nouvelle en fin de tableau, on utilisera le code `tmpNEW_ROW`.

<div class="relative" id="bkmrk--1"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">---

</div></div>## 2. Interaction avec l'API

Lors du développement, il existe plusieurs manière d'interagir avec l'API de TimeTonic :

- Sur le site de TimeTonic : chaque modification de vue, de champ etc... est en fait une requête d'API faite de manière transparente.
- Avec l'outil Postman : cet outil permet de construire des requêtes et de voir en direct la réponse du serveur. C'est l'outil privilégié pour tester et construire des requêtes complexes avant de les implémenter dans le code. Il permet aussi de diagnostiquer et résoudre les problèmes lorsqu'on ne récupère pas les données désirées.
- Dans le code du M5 : avec la librairie HTTPClient, et une requête POST passée sous forme de String. Attention, il est nécessaire de formatter la requête correctement pour qu'elle soit interprêtée comme il faut (avec notamment des \\" pour qu'ils n'interagissent pas avec les bornes de la String).

## 2. Exemple de requête : getAllBooks

La méthode **getAllBooks** permet de récupérer la liste de tous les « books » (espaces de travail) auxquels l’utilisateur a accès. Pour connaitre l'étendu des possibilité de l'API de TimeTonic, je vous renvois vers [la documentation de celui-ci](https://timetonic.com/live/apidoc/#api). La requête doit être envoyée en POST à l’URL suivante :

`https://timetonic.com/live/api.php`

Les paramètres à inclure sont :

<div class="relative" id="bkmrk-version-%3A-version-de"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- `version` : version de l’API (ex : "6.20b") (optionnel)
- `req` : "getAllBooks"
- `o_u` : identifiant utilisateur (doit correspondre à celui du sesskey)
- `u_c` : identifiant utilisateur (idem)
- `sesskey` : votre clé d’API/session, qui peut être créée dans les paramètres de votre compte TimeTonic

</div></div><div class="relative" id="bkmrk--2"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">---

</div></div>## 3. Implémentation sur M5Stack (Arduino)

Voici comment structurer le code avec les librairies **WiFi**, **HTTPClient** et **ArduinoJson** :

```
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid = "fablabstaff";
const char* password = "xxxxxxxxx"; //Pensez à remplacer le SSID et le mot de passe par vos paramètres WiFi

HTTPClient http;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connecte au WiFi");

  http.begin("https://timetonic.com/live/api.php");
  String postData = "req=getAllBooks"
                    "&o_u=USER"// Remplacez bien USER par votre nom d'utilisateur TimeTonic
                    "&u_c=USER"
                    "&sesskey=xxxxxxxxxxxxxxxxxxxxxxxxxx"; // Remplacez par votre sesskey
  int httpResponseCode = http.POST(postData);

  if (httpResponseCode > 0) {
    String reponse = http.getString();
    Serial.println("Réponse API :");
    Serial.println(reponse);

    // Traitement JSON (exemple)
    DynamicJsonDocument doc(4096);
    deserializeJson(doc, reponse);
    if (doc["status"] == "ok") {
      JsonArray books = doc["allBooks"];
      for (JsonObject book : books) {
        Serial.println(book["b_c"].as<String>()); // Affiche le code du book
      }
    }
  }
  else {
    Serial.print("Erreur HTTP : ");
    Serial.println(httpResponseCode);
  }
  http.end();
}


void loop() {
  // Rien ici pour cet exemple
}
```

Ce code permet de récupérer les informatiosn de tous les espaces de travail présents dans un compte TimeTonic.

## 4. Points importants

<div class="relative" id="bkmrk-connexion-s%C3%A9curis%C3%A9e-"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- **Connexion sécurisée** : L’API TimeTonic nécessite une connexion HTTPS, ce qui est supporté par l’ESP32.
- **Format POST** : Les paramètres doivent être envoyés en POST, au format `application/x-www-form-urlencoded`[<span class="relative select-none align-middle -top-px font-sans text-base text-textMain dark:text-textMainDark selection:bg-super/50 selection:text-textMain dark:selection:bg-superDuper/10 dark:selection:text-superDark"><span class="hover:bg-super dark:hover:bg-superDark dark:hover:text-backgroundDark min-w-[1rem] cursor-pointer rounded-[0.3125rem] text-center align-middle font-mono text-[0.6rem] tabular-nums hover:text-white py-[0.1875rem] px-[0.3rem] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-offsetPlus dark:bg-offsetPlusDark">2</span></span>](https://support.timetonic.com/hc/en-001/articles/4402552696210-PHP-example-for-getAllBooks)<span class="whitespace-nowrap">[<span class="relative select-none align-middle -top-px font-sans text-base text-textMain dark:text-textMainDark selection:bg-super/50 selection:text-textMain dark:selection:bg-superDuper/10 dark:selection:text-superDark"><span class="hover:bg-super dark:hover:bg-superDark dark:hover:text-backgroundDark min-w-[1rem] cursor-pointer rounded-[0.3125rem] text-center align-middle font-mono text-[0.6rem] tabular-nums hover:text-white py-[0.1875rem] px-[0.3rem] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-offsetPlus dark:bg-offsetPlusDark">3</span></span>](https://timetonic.com/live/api.php?doc).</span>
- **Traitement de la réponse** : La réponse de l’API est en JSON, d’où l’utilisation de la librairie ArduinoJson pour extraire les informations utiles.
- **Gestion des erreurs** : Toujours vérifier le code de retour HTTP et le champ `status` dans la réponse JSON.

---

</div></div>## 5. Résumé

Pour communiquer avec l’API de TimeTonic depuis un M5Stack, il faut :

<div class="relative" id="bkmrk-se-connecter-au-wifi"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- Se connecter au WiFi,
- Construire une requête POST avec les bons paramètres,
- Envoyer la requête à l’API,
- Traiter la réponse JSON pour exploiter les données reçues.

</div></div>Ce principe peut être adapté à toutes les autres méthodes de l’API TimeTonic, en changeant simplement le paramètre `req` et les paramètres associés.

# Lecture et écriture sur TimeTonic

Maintenant que nous pouvons communiquer avec l'API TimeTonic via le M5Stack, il faut savoir utiliser les principales requêtes permettant de lire, créer et modifier les données contenues dans un book (espace de travail). Voici les étapes principales, avec le détail des fonctions API à utiliser et des exemples de structure de requête.

<div class="relative" id="bkmrk-"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">---

</div></div>## 1. Lire les données d’une smart table

Pour récupérer le contenu d’une smart table, il faut utiliser la requête **getTableValues**. Cette requête retourne les lignes (rows) et les valeurs des champs (fields) d’une table donnée.

**Paramètres nécessaires :**

<div class="relative" id="bkmrk-version-%3A-version-de"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- `req` : "getTableValues"
- `o_u` et `u_c` : identifiants utilisateur
- `sesskey` : clé de session API
- `b_c` : code du book (carnet)
- `catCode` : code de la table (catégorie)

</div></div>**Exemple de requête POST :**

> <span style="background-color: rgb(248, 248, 248); font-family: 'Lucida Console', 'DejaVu Sans Mono', 'Ubuntu Mono', Monaco, monospace; font-size: 0.84em; white-space-collapse: preserve;">req=getTableValues&amp;o\_u=USER\_ID&amp;u\_c=USER\_ID&amp;sesskey=SESSION\_KEY&amp;b\_c=BOOK\_CODE&amp;catCode=TABLE\_CODE</span>

En version formatée pour le code C précédemment utilisé :

```
"req=getTableValues"
"&b_c=BOOK_CODE"
"&catCode=TABLE_CODE"
"&o_u=USER_ID"
"&u_c=USER_ID"
"&sesskey=SESSION_KEY"
```

La réponse contiendra un tableau JSON avec toutes les lignes et les valeurs des champs pour chaque ligne<span class="whitespace-nowrap">. Pour pouvoir exploiter ces données dans le code C, il faut utiliser un parseur, qui permet d'identifier et d'isoler chaque donnée lue.</span>

<div class="relative" id="bkmrk--2"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">---

</div></div>## 2. Filtrage des données lues

Pour ne pas récupérer toutes les données de la table à chaque requête, on peut utiliser deux arguments dans celle-ci :

- `fieldIds` : permet de sélectionner les champs que l'on veut récupérer, sous forme d'un tableau JSON

Par exemple :

```
&fieldIds = [7457220, 7457221]
```

Où 7457220 et 7457221 sont les IDs des champs que je veux récupérer.

- `filterRowIds` : permet de sélectionner les lignes que l'on veut récupérer, ou bien au moyen d'une vue déjà existante dans la table, ou via une vue temporaire créée sous la forme d'un objet JSON.

Par exemple :

```
&filterRowIds={"applyViewFilters": 1181354}
```

Où 1181354 est l'ID de la vue que je souhaite utiliser. Pour récupérer cet ID, il faut **inspecter** la page lorsque vous êtes sur la vue qui vous intéresse, puis cliquer sur l'onglet "**network**". Dans les filtres en haut, sélectionner "**Fetch/XHR**" puis rafraichisser la page. Dans les fichiers qui se chargent alors, sélectionner **newDashboard?getUtilisateur** et défiler jusqu'à la section **Request Headers**. Dans celle-ci, trouvez la ligne **Referer**, elle contient en regard un lien terminant par /view/*Un numéro*. Ce numéro est l'ID de votre vue.

**ATTENTION** : le view ID peut maintenant être directement récupéré dans l'URL de la page : sélectionnez la vue souhaitée puis copiez le numéro après /view/ , il 'sagit du viewId.

Pour construire une vue avec un objet JSON, la manoeuvre est beaucoup plus compliquée : il faut remplacer l'ID de vue par un objet JSON avec une syntaxe particulière :

- `operator` : correspond à l'opérateur logique entre les différents filtres (voir les possibilitées dans la [documentation TimeTonic](https://support.timetonic.com/hc/fr/articles/4402560207378-Obtenir-les-donn%C3%A9es-filtr%C3%A9es-d-une-table-filterRowIds))
- `id` : numéro arbitraire à donner à la vue (doit être unique), s'il s'agit d'une vue temporaire, utiliser "tmpId"
- `field_id` : ID du champ dans lequel on veut faire le filtrage
- predicate : opérateur logique du filtre (voir les possibilités dans la documentatio de TimeTonic)
- `operand` : corps du filtre (l'élément contre lequel seront comparées les valeurs)

Voici un exemple d'objet JSON à mettre après `"applyViewFilters":` :

```
{
    "filterGroup": {
        "operator": "and",
        "id": "tmpId",
        "filters": [
            {
                "field_id": 7457220,
                "json": {
                    "predicate": "contains",
                    "operand": "ABC"
                }
            },
            {
                "field_id": 7457221,
                "json": {
                    "predicate": "is",
                    "operand": "abc"
                }
            }
        ]
    }
}
```

NB : `"filterGroup"` (nom de l'objet JSON), `"filters"` (tableau JSON contenant les différents filtres) et `"json"`(objet JSON contenant les arguments de filtrage) sont des éléments statiques mais nécessaires de la syntaxe. toute erreur dans la syntaxe entrainera une réponse valide mais ne contenant aucune donnée de la table interrogée (`"rowInfosLength": 0` dans la réponse).

---

## 3. Écrire des données dans une smart table

L’ajout ou la modification de données dans une smart table se fait avec la requête **createOrUpdateTableRow**. Pour modifier une ligne, il suffit d’indiquer l’identifiant de la ligne (`rowId=ROW_ID_EXISTANT`ou `rowId=tmpNEW_ROW`) et de fournir les nouveaux champs à modifier dans `fieldValues`.

**Paramètres nécessaires :**

<div class="relative" id="bkmrk-req-%3A-%22createorupdat"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- `req` : "createOrUpdateTableRow"
- `o_u` et `u_c` : identifiants utilisateur
- `sesskey` : clé de session API
- `b_c` : code du book (carnet)
- `catCode` : code de la table (catégorie)
- `fieldValues` : données à écrire. celles-ci doivent être sous la forme d'un objet JSON avec la syntaxe suivante :

</div></div>```
{
	"field ID": "Value",
	"field ID 2": "Value 2",
	"field ID 3": "Value 3"
	}
```

**Exemple de requête POST:**

> <span style="background-color: rgb(248, 248, 248); font-family: 'Lucida Console', 'DejaVu Sans Mono', 'Ubuntu Mono', Monaco, monospace; font-size: 0.84em; white-space-collapse: preserve;">req=createOrUpdateTableRow&amp;o\_u=USER\_ID&amp;u\_c=USER\_ID&amp;sesskey=SESSION\_KEY&amp;b\_c=BOOK\_CODE&amp;catCode=TABLE\_CODE&amp;rowId=ROW\_ID\_EXISTANT&amp;fieldValues={"FIELD\_ID1":"NouvelleValeur"}</span>

En version formatée pour le code C (bien noter les antislashs avant les guillemets contenus dans fieldValues : ils permettent de les considérer comme des caractères normaux sans interférer avec les balises de Strings):

```
"req=createOrUpdateTableRow"
"&o_u=USER_ID"
"&u_c=USER_ID"
"&sesskey=SESSION_KEY"
"&b_c=BOOK_CODE"
"&catCode=TABLE_CODE"
"&rowId=ROW_ID"
"&fieldValues={\"FIELD_ID\":\"NouvelleValeur\"}"
```

Seuls les champs à modifier doivent être précisés dans `fieldValues`<span class="whitespace-nowrap">.</span>

<div class="relative" id="bkmrk--4"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">---

</div></div>## 4. Récupérer les identifiants nécessaires

Si les données que vous lisez/écrivez sont toujours au même endroit, vous pouvez manuellement regarder les IDs de chaque champ et les copier dans votre code. Cependant, si vous voulez écrire des données à des endroits dépendant de certains champs/valeurs, vous pouvez obtenir les IDs pertinents via les requêtes **getAllBooks** (pour les books) et **getBookTables** (pour les tables et champs)<span class="whitespace-nowrap">. </span>Avant de pouvoir lire ou écrire, il est indispensable de connaître :

<div class="relative" id="bkmrk-le-code-du-book-%28b_c"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- Le code du book (`b_c`)
- Le code de la table (`catCode`)
- Les identifiants des champs (`fieldID1`, `fieldID2`, etc.)
- L’identifiant de la ligne, si modification (`rowId`)

</div></div><div class="relative" id="bkmrk--5"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">---

</div></div>## 5. Résumé des étapes

<div class="relative" id="bkmrk-authentification-%3A-o"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">1. **Authentification** : Obtenir un `sesskey` via l’API.
2. **Lister les tables** : Utiliser `getAllBooks` puis `getBookTables` pour identifier le book et la table cible si nécessaire.
3. **Lire des données** : Utiliser `getTableValues` pour obtenir les lignes et champs.
4. **Écrire des données** : Utiliser `createOrUpdateTableRow` avec `rowId=tmpNEW_ROW` si vous voulez créer une nouvelle ligne.

---

</div></div>## 6. Bonnes pratiques

<div class="relative" id="bkmrk-utiliser-syst%C3%A9matiqu"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- Utiliser systématiquement la méthode POST pour transmettre les paramètres.
- Manipuler les objets JSON avec soin pour le paramètre `fieldValues`, et utiliser un parseur pour pouvoir utiliser les données lues.
- Toujours vérifier le champ `status` dans la réponse de l’API pour s’assurer du succès de l’opération (le code de succès 200 indique simplement que la requête est parvenue à l'API, pas nécessairement qu'elle a été correctement exécutée).

---

</div></div>En résumé, la lecture et l’écriture dans une smart table TimeTonic via l’API sont simples, mais nécessites une grande attention aux détails : il faut bien identifier les bons paramètres (book, table, champs), utiliser les requêtes appropriées, et les structurer correctement afin de traiter ou d'envoyer les données correctement<span class="whitespace-nowrap">.</span>

# Création d'une bibliothèque uniformisée : M5lib

Conception et codage d'une bibliothèque commune à tous les M5Stack déployés dans le FabLab afin de rendre le déploiement, la maintenance et l'évolution plus simples et efficaces. Du fait sa relative complexité, il n'est pas garanti qu'elle fonctionne sur les M5Stack Core 1 (elle est optimisée pour les Core 2).

# Présentation

## Présentation Générale

La bibliothèque **M5lib** vise à uniformiser la gestion d’une flotte de M5 Core2 au sein d’un FabLab, facilitant le déploiement, l’évolution et la maintenance. Sa structure repose sur des concepts avancés de programmation orientée objet : **factory design pattern** et **polymorphisme**.

## Factory Design Pattern dans M5lib

#### Structure de Base

- La classe **M5lib** est la classe de base commune à tous les types d’appareils M5 (accueil, servante, machine, ordinateur, matériel), définissant l’interface et le comportement standard minimal.
- Plusieurs classes dérivées spécialisent ce comportement pour chaque type de M5 : `accueil`, `servante`, `machine`, `ordinateur`, `materiel`, chacune héritant de M5lib.

#### Objectif du Pattern

Le **factory design pattern** permet d’instancier dynamiquement le bon type d’objet dérivé (`accueil`, `servante`, etc.) en fonction du contexte (par exemple, d’un paramètre de configuration ou d’une saisie utilisateur), tout en manipulant leur interface commune à travers des pointeurs ou références de type M5lib. Dans ce cas, cela veut dire que la déclaration du type d'objet dérivé dans le firmware du M5 permet automatiquement et de manière transparente d'adapter toutes les fonctions nécessaires au comportement de ce type de M5 (requêtes d'API, type d'emprunt...).

#### Avantages

- Centralisation de la logique d’instanciation : éviter la duplication de code lors de la création de nouveaux modules.
- **Extensibilité et maintenance** : ajouter un nouveau “type” d’objet devient trivial (ajout d’une seule classe dérivée et adaptation de la factory).

## Polymorphisme dans M5lib

#### Implémentation

- La classe `M5lib` déclare des méthodes virtuelles pures (`virtual ... = 0;`) comme `uploadlog` et `changestatus`. Ces fonctions ne sont alors pas appelables dans M5lib et n'existent pas en tant que tel tant que le type de M5 n'a pas été déterminé.
- Chaque classe dérivée (*accueil*, *servante*, etc.) implémente ces méthodes selon les besoins spécifiques de son rôle (par exemple, signature différente, formats d’upload différents…). Ainsi, pour un même appel de fonction, le comportement s'adapte parfaitement au cas d'utilisation du type de M5 concerné.

#### Usage

- Grâce au polymorphisme, le reste du programme peut manipuler les objets à travers des pointeurs de type M5lib et appeler, par exemple, `uploadlog` sans connaître la classe exacte : c’est la bonne implémentation qui sera automatiquement utilisée à l’exécution.
- Cela permet d’écrire du code générique, réutilisable, et facile à maintenir. De plus, si par la suite un nouveau cas d'utilisation est identifié comme nécessitant la création d'un nouveau type de M5, il ne faudra ajouter dans le code que les définitions de comportement spécifique à ce type, rendant l'évolutivité beaucoup plus simple.

## Limites et inconvénients

Cette flexibilité du code ne vient pas sans compromis :

- Au cours du développement, il est apparu que la bibliothèque devenait trop grosse pour être déployée sur des M5Stack Core, et afin résoudre ces limitations matérielles, la bibliothèque a été optimisée pour fonctionner sur des M5Stack Core2 (qui possèdent plus de RAM et de stockage interne).
- La logique de polymorphisme et de type abstrait implique que chaque appareil embarque toutes les méthodes de toutes les classes, y compris de celles dont il n'a pas besoin. Cela ne pose pour le moment pas de problème, mais si la bibliothèque est amenée à grandir encore plus, une optimisation de ce côté pourrait s'avérer nécessaire. Son implémentation n'est pas compliquer : il suffit de rajouter des macros avant la définition de chaque classe afin de n'inclure que le code nécessaire, mais cela implique de définir le type de M5 à la compilation, rendant le déploiement plus technique et le code moins flexible.

# Structure

## Dépendances

La librairie fait appel à de nombreuses librairies :

- M5Unified : bibliothèque standard utilisée pour contrôler et interagir avec les M5
- M5GFX : bibliothèque graphique (normalement standard) permettant d'utiliser des fonctions d'affichage avancées afin de créer une UI
- UNIT\_RFID\_UHF : bibliothèque officielle de M5Stack afin de gérer le module RFID UHF
- MFRC522\_I2C : bibliothèque officielle de M5Stack fin de gérer le module RFID (attention, il existe plusieurs versions de cette bilbiothèque et seule celle disponible sur le GitHub de M5Stack fonctionne)
- Wifi : bibliothèque standard permettant de contrôler la connexion WLAN du M5
- HTTPClient : bibliothèque permettant de faire des requêtes HTTP, notamment à l'API TimeTonic
- ArduinoJson : parseur JSON optimisé pour les ESP32, permet de manipulé les objets JSON retourné par l'API de TimeTonic
- Wire : bibliothèque standard permettant d'initialiser et de contrôler la connexion I2C du M5

## Structure de code

La bibliothèque **M5lib** est conçue pour uniformiser le comportement de plusieurs dispositifs **M5Stack Core2** dans l'environnement du FabLab, chacun jouant un rôle défini (accueil, servante, machine, etc.). Elle repose sur une architecture orientée objet claire et modulaire, facilitant l’évolution, la maintenance et l'intégration au back-end (TimeTonic).

## Structure de la Bibliothèque **M5lib**

#### 1. **Classe de base abstraite : `M5lib`**

<div class="relative" id="bkmrk-repr%C3%A9sente-l%E2%80%99interfa"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- Représente l’**interface** commune à tous les types de M5.
- Contient les méthodes de base utilisées par tous les modules : lecture de carte RFID (`scancard`), scan UHF (`scanuhf`), interaction utilisateur (`showchoice`, `getuser`), etc.
- Déclare des **méthodes virtuelles pures** (polymorphisme) à implémenter dans les classes dérivées : `uploadlog()` et `changestatus()`.

</div></div><div class="relative" id="bkmrk-"></div>#### 2. **Classes dérivées spécialisées**

Chaque type de M5 (défini dans `M5type`) possède une classe dédiée, dérivée de `M5lib` :

<div class="relative" id="bkmrk-classe-h%C3%A9rite-de-sp%C3%A9"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="group relative"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain my-[1em] w-full table-auto border"><thead class="bg-offset"><tr><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Classe</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Hérite de</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Spécificités</th></tr></thead><tbody><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`accueil`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`M5lib`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Méthodes supplémentaires : `entree()`, `sortie()`, `regcard()`.  
Menu de motifs de visite.</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`servante`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`M5lib`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Gère la traçabilité des servantes utilisées.</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`machine`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`M5lib`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Pour l'enregistrement d’utilisation de machines.</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`ordinateur`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`M5lib`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Associe cartes/scans à une session ordinateur précise.</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`materiel`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`M5lib`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Permet le prêt/retour d’outils ou matériels via `borrow()`.</td></tr></tbody></table>

</div></div></div></div>Chaque classe surcharge au moins :

<div class="relative" id="bkmrk-uploadlog%3A-envoie-le"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- `uploadlog`: envoie les journaux d’usage à l’API TimeTonic avec une structure propre (identifiants de champs différents selon le type).
- `changestatus`: placeholder actuel (pour la plupart renvoie `200`) servant potentiellement à signaler un changement d’état matériel (ex : verrouillage machine, etc.).

</div></div>#### 3. **Composants globaux manipulés**

<div class="relative" id="bkmrk-p%C3%A9riph%C3%A9riques-%3A-mfrc"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]">- **Périphériques** :
    
    
    - `MFRC522 mfrc522` : pour la lecture RFID classique (Mifare).
    - `Unit_UHF_RFID uhf` : pour les lectures UHF/EPC.
- **API &amp; Données** :
    
    
    - `HTTPClient http` : communication HTTP avec TimeTonic.
    - `JsonDocument doc` : stockage de la réponse JSON.
- **Accès réseau** :
    
    
    - Configuration du Wi-Fi intégrée dans `setupstd()`.

</div></div><div class="relative" id="bkmrk--1"></div>## Résumé Visuel Simplifié

```txt
        +---------------------------+
        |           M5lib          |  <--- classe abstraite
        +---------------------------+
    /        |        |       |         \
   /         |        |       |          \
accueil   servante  machine ordinateur  materiel  <--- classes concrètes

Toutes implémentent :
    + uploadlog()
    + changestatus()

Chaque classe possède des méthodes propres, par exemple :
accueil fournit aussi :
    + entree()
    + sortie()
    + regcard()

```

<div class="relative" id="bkmrk--2"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="w-full md:max-w-[90vw]"><div class="codeWrapper text-textMainDark selection:text-super selection:bg-super/10 bg-offset my-md relative flex flex-col rounded font-mono text-sm font-thin"><div class="translate-y-xs -translate-x-xs bottom-xl mb-xl sticky top-0 flex h-0 items-start justify-end"><div class="flex items-center min-w-0 font-medium gap-1.5 justify-center"></div></div></div></div></div></div>Une **évolution fluide** : il suffit d’ajouter une nouvelle classe dérivée et d’enrichir la factory pour intégrer un nouveau comportement ou un nouveau rôle matériel dans le système du FabLab.

# Structure détaillées

## 1. **Classe Abstraite : `M5lib`**

Classe de base commune à tous les types de M5. Elle définit les fonctionnalités fondamentales.

#### Fonctions membres

<div class="relative" id="bkmrk-fonction-r%C3%B4le-setups"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="group relative"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain my-[1em] w-full table-auto border" style="width: 100%; height: 535px;"><thead class="bg-offset"><tr style="height: 29.7969px;"><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top" style="width: 28.8034%; height: 29.7969px;">Fonction</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top" style="width: 71.1966%; height: 29.7969px;">Rôle</th></tr></thead><tbody><tr style="height: 46.5938px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 46.5938px;">`setupstd()`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 46.5938px;">Effectue l'initialisation matérielle commune : écran, Wi-Fi, RFID, UHF. Attention : la fonction est lboquante tant que le M5 n'est pas connecté au réseau prédéfinit.</td></tr><tr style="height: 63.3906px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 63.3906px;">`reducejson(String json)`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 63.3906px;">Réduit et structure le JSON de réponse de l’API TimeTonic pour simplifier l’accès aux champs utiles. Ne garde que le contenu de "fields" (endroit où est stocké entre autres les données demandées) et "rowInfos" (qui contient notamment le rowId des informations demandées)</td></tr><tr style="height: 46.5938px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 46.5938px;">`scancard()`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 46.5938px;">Scanne une carte RFID classique, retourne l’UID du tag sous forme de String. Contient une UI intégrée. Attention : la fonction est bloquante tant qu'elle n'a pas lu une carte.</td></tr><tr style="height: 63.3906px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 63.3906px;">`scanuhf(String* urfid)`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 63.3906px;">Scanne les tags RFID UHF via le module UHF externe, remplit le tableau passé en paramètre avec les EPC lues (max 200 EPC, ce qui est le max supporté par le module RFID UHF). Fonction actuellement inutilisée dans le code.</td></tr><tr style="height: 63.3906px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 63.3906px;">`showchoice(String choices[])`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 63.3906px;">Affiche sur l’écran un menu de sélection contenant les String du tableau passé en paramètre : l’utilisateur peut naviguer puis valider un choix(jusqu’à 9 options), qui est retourné sous forme de String.</td></tr><tr style="height: 81.4375px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 81.4375px;">`virtual int uploadlog(String card, String action, String other) = 0`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 81.4375px;">Méthode virtuelle pure pour uploader un log dans la table correspondante au type de M5. Prend en paramètre une carte lue, l'action effectuée par l'utilisateur et un agument optionnel (au choix, le motif de la visite, l'ordinateur ou l'outil emprunté).</td></tr><tr style="height: 47.2188px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 47.2188px;">`virtual int changestatus() = 0`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 47.2188px;">Méthode virtuelle pure pour changer le statut d'emprunt/de présence (obsolète pour le moment car remplacé par automatisation TimeTonic).</td></tr><tr style="height: 46.5938px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 46.5938px;">`getuser(String* user)`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 46.5938px;">Lance un scan RFID (avec scancard() ), puis interroge l’API TimeTonic pour récupérer le nom, prénom, et rowId de l'utilisateur scanné. Peuple ensuite le tableau passé en paramètre : \[nom, prénom, tag RFID, rowId\].</td></tr><tr style="height: 46.5938px;"><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 28.8034%; height: 46.5938px;">`borrow()`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border" style="width: 71.1966%; height: 46.5938px;">Gère tout le cycle d’emprunt et retour d’un matériel/machine/ordinateur : identification (avec un appel getuser() ), log (avec un appel uploadlog() ), et contrôle utilisateur (gestion par l'utilisateur de la durée de son emprunt, avec à nouveau un scan de carte et un upload de log à la fin de l'emprunt. Boucles if/else à chaque étape du cycle pour gérer chaque type d'erreur (API, utilisateur inconnu, etc...).</td></tr></tbody></table>

</div></div></div></div>##### Attributs

- `user[4]` : tableau de String contenant toutes les informations d'un utilisateur : \[nom, prénom, tag RFID, rowId\].
- `urfid[200]` : tableau de String pouvant contenir jusqu'à 200 EPC.
- `sesskey` : permet de modifier simplement et directement la clé d'API pour toutes les requêtes de la bibliothèques (en cas d'expiration par exemple)

## 2. **Classes Dérivées**

Chaque classe dérivée apporte des fonctionnalités propres à chaque typologie de M5 dans le FabLab.

#### a. **Classe : `accueil`**

Ajoute des méthodes spécifiques à la gestion d’accueil.

<div class="relative" id="bkmrk-fonction-r%C3%B4le-int-up"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="group relative"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain my-[1em] w-full table-auto border"><thead class="bg-offset"><tr><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Fonction</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Rôle</th></tr></thead><tbody><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`int uploadlog(...) override`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Upload des logs d’accueil à l’API avec les bons id (table, champs...).</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`int changestatus() override`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Change le statut d’accueil (placeholder : actuellement valeur fixe pour compatibilité).</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`void entree()`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Gère la procédure d’entrée : identification (avec getuser), choix du motif de visite (avec showchoice), upload du log d’arrivée (avec uploadlog)</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`void sortie()`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Gère la sortie d’un utilisateur (avec getuser) et log cet évènement (avec uploadlog).</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`void regcard()`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Enregistre une nouvelle carte RFID (avec un scancard puis une requete d'API spécifique) pour un utilisateur après inscription sur Timetonic (liaison rangée TimeTonic &lt;-&gt; badge RFID). La requête d'API récupère la dernière rangée créée avec une vue filtrée (vue chronologique dans TimeTonic), il faut donc faire l'association de carte immédiatement après l'inscription.</td></tr></tbody></table>

</div></div></div></div>##### Attributs spécifiques

`String motifs[9]`: Liste des motifs de visite disponibles à la sélection (préremplie pour plus de simplicité).`String name` : nom du M5, permet de définir l'action d'accueil effectuée : entrée, sortie ou 1ère inscription.

#### b. **Classe : `servante`**

Pour la traçabilité de l’usage des servantes.

<div class="relative" id="bkmrk-fonction-r%C3%B4le-int-up-1"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="group relative"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain my-[1em] w-full table-auto border"><thead class="bg-offset"><tr><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Fonction</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Rôle</th></tr></thead><tbody><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`int uploadlog(...) override`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Upload des logs liés à l’utilisation d’une servante (carte, action, ""). L'argument other ne sert pas pour les servantes.</td></tr><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`int changestatus() override`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Change le statut de la servante (obsolète, pour compatibilité).</td></tr></tbody></table>

</div></div></div></div>##### Attributs spécifiques

- `String rowid`: id de la rangée de cette servante dans la table Servantes du book Inventaire dans TimeTonic (unique à chaque servante, et donc chaque appareil, voir table d'équivalence dans la doc privée).
- `String name` : nom du M5, permet de définir la servante concernée dans les logs.

#### c. **Classe : `machine`**

Gère l’utilisation des machines/outils fixes.

<div class="relative" id="bkmrk-fonction-r%C3%B4le-int-up-2"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="group relative"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain my-[1em] w-full table-auto border"><thead class="bg-offset"><tr><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Fonction</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Rôle</th></tr></thead><tbody><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`int uploadlog(...) override`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Upload logs liés à l’utilisation d’une machine (carte utilisateur, action).</td></tr></tbody></table>

</div></div></div></div>##### Attributs spécifiques

- `String rowid`: id de la rangée de cette machine dans la table Machines du book Inventaire dans TimeTonic (unique à chaque machinr, et donc chaque appareil, voir table d'équivalence dans la doc privée).
- `String name` : nom du M5, permet de définir la machine concernée dans les logs.

#### d. **Classe : `ordinateur`**

Gère le suivi de l'emprunt des ordinateurs portables.

<div class="relative" id="bkmrk-fonction-r%C3%B4le-int-up-3"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="group relative"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain my-[1em] w-full table-auto border"><thead class="bg-offset"><tr><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Fonction</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Rôle</th></tr></thead><tbody><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`int uploadlog(...) override`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Upload logs spécifiques à l’usage d’un ordinateur (par exemple : session ouverte/fermée).</td></tr></tbody></table>

</div></div></div></div>##### Attributs spécifiques

- <span style="font-family: Lucida Console, DejaVu Sans Mono, Ubuntu Mono, Monaco, monospace;"><span style="font-size: 11.76px; white-space-collapse: preserve; background-color: rgb(180, 215, 255);">WIP</span></span>

#### e. **Classe : `materiel`**

Gère les cycles d’emprunt et de retour d’outillage ou matériel divers.

<div class="relative" id="bkmrk-fonction-r%C3%B4le-int-up-4"><div class="prose text-pretty dark:prose-invert inline leading-normal break-words min-w-0 [word-break:break-word]"><div class="group relative"><div class="w-full overflow-x-auto md:max-w-[90vw] border-borderMain/50 ring-borderMain/50 divide-borderMain/50 dark:divide-borderMainDark/50 dark:ring-borderMainDark/50 dark:border-borderMainDark/50 bg-transparent"><table class="border-borderMain my-[1em] w-full table-auto border"><thead class="bg-offset"><tr><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Fonction</th><th class="border-borderMain px-sm py-sm dark:border-borderMainDark break-normal border text-left align-top">Rôle</th></tr></thead><tbody><tr><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">`int uploadlog(...) override`</td><td class="border-borderMain px-sm dark:border-borderMainDark min-w-[48px] break-normal border">Upload logs liés à l’utilisation (emprunt/retour) de matériels.</td></tr></tbody></table>

</div></div></div></div>##### Attributs spécifiques

- <span style="font-family: Lucida Console, DejaVu Sans Mono, Ubuntu Mono, Monaco, monospace;"><span style="font-size: 11.76px; white-space-collapse: preserve; background-color: rgb(180, 215, 255);">WIP</span></span>

## 3. **Utilisation de méthodes virtual / override**

Les méthodes `uploadlog` et `changestatus` sont définies comme `virtual` dans la base, et nécessaires à la personnalisation du comportement selon chaque situation FabLab : chaque classe dérivée implémente les appels API avec les bons identifiants et formats de données.

Avec cette structure, chaque fonction de **M5lib** remplit un rôle précis dans la gestion, la traçabilité, l’ajout de dispositifs et l’intégration back-end dans l’écosystème du FabLab.

# UI

Afin de simplifier, d'uniformiser et de clarifier l'affichage de texte et de l'interface dans le M5, Une classe UI a été créé. Elle permet de simplifier l'implémentation de l'interface utilisateur dans toutes les fonctions interagissant avec celui-ci.

## Structure

#### Méthodes

<div id="bkmrk-showchoice-%3A-ui-de-s"><div>`showchoice` : UI de sélection de choix multiples (anciennement dans M5lib), retourne la String du choix sélectionné</div><div>`titre` : affichage de texte en gros centré (taille 4, 13 charactères maximum avant dépassement de l'écran)</div><div>`soustitre` : affichage de texte en moyen centré (taille 3, 17 charactères maximum)</div><div>`corps` : affichage de texte en petit centré (taille 2, 26 charactères maximum)</div><div>`feedback` : vibration pour retour utilisateur, à appeler à chaque fois qu'un bouton est pressé</div></div>

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


```

# Réflexions sur l'ergonomie de UI



# Etat des lieux

Aujourd'hui, les informations liées à l'accueil et les emprunts sont enregistrées dans un logiciel développé en interne, FabTrack, accessible uniquement aux emplois-étudiants, avec une interface web accessible via deux PC Linux :

[![IMG_3841.png](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/scaled-1680-/img-3841.png)](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/img-3841.png)[![IMG_3846.png](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/scaled-1680-/img-3846.png)](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/img-3846.png)

Les enregistrements des participants à des ateliers spécifiques fait appel à des formulaires web de style Google Form/Framaform. Enfin, les données liées à l'usage des machines ne sont pas collectées, et seules les informations de maintenance sont notées, sur papier :

[![IMG_3842.png](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/scaled-1680-/img-3842.png)](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/img-3842.png)[![IMG_3844.png](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/scaled-1680-/img-3844.png)](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-07/img-3844.png)

Les objectifs de l'introduction de Timetonic et de la transformation sont multiples :

1. centraliser les informations,
2. unifier la façon de les saisir les informations, pour fiabiliser la collecte.
3. alléger la charge de travail des emplois étudiants et personnels,
4. permettre l'extension de la collecte d'information à d'autres situations

# Possibilités techniques

Le point d'entrée des utilisateurs (contributeurs) doit être leur identification (simple, sans authentification). Pour cela, il existe plusieurs possibilités :

- remplir ("à la main") un formulaire avec nom et prénom, ou avec un numéro d'identifiant ;
- badger avec une carte RFID, comme la carte étudiant et/ou la carte de restaurant pour les personnels ;
- badger avec un QR code

L'interface sur laquelle se poursuite la saisie peut être :

- un poste fixe, avec écran + clavier ou un écran tactile seul.
- un téléphone mobile

Toutes les combinaisons ne sont pas possible, ni cohérentes : par exemple, le téléphone peut scanner un QR code, mais on ne peut pas équiper tout le monde de lecteur de badge RFID.

On peut donc envisager essentiellement trois combinaisons :

- poste fixe (avec écran tactile ou clavier) + lecteur badge RFID
- (QR codes affichés + QR code individuel sur la carte) + smartphone pour accéder aux formulaires
- si le lecteur de badge RFID est à base de M5 Stack, une solutions mixte consiste à scanner le badge, puis afficher des QR codes personnalisés, mais cela devient complexe et peu pratique.

Côté imprimantes, l'ajout d'un SBC doté d'Octoprint pour récupérer les informations de l'impression est envisagé. Rien n'empêche d'y connecter un lecteur RFID et un verrou électronique. Le processus devient alors : l'utilisateur entre dans la pièce, prépare son fichier sur le PC local, utilise la clé USB locale, déverrouille l'imprimante avec son badge RFID, branche la clé USB, lance l'impression, puis attend et enfin referme la porte.

Cahier des charges du SBC :

- 2 port USB ou 1 port USB + port I2C pour connecter le lecteur de badge RFID
- 1 port ethernet

Nicolas suggère le [LicheeRV Nano de Sipeed](https://wiki.sipeed.com/hardware/en/lichee/RV_Nano/1_intro.html). Mais on trouve aussi le [RTF5350 chez Olimex,](https://www.olimex.com/Products/OLinuXino/RT5350F/RT5350F-OLinuXino-EVB/open-source-hardware) directement doté de relais pour la commande des verrous.

# Lecteur NFC ACR122U



# Mise en oeuvre lecteur NFC

Le lecteur se connecte en USB au PC de l'accueil, sous Linux.

Il est nécessaire d'installer les paquets lib-nfc6 et lib-nfc-dev, lib-nfc-bin, ydotool.

Il faut élargir les droits sur /dev/uinput +r pour que ydotool puisse y accéder.

Le script suivant permet d'obtenir un comportement adéquat ressemblant à un clavier :

```bash
#/bin/env bash

STRING=""
OLDSTRING=""

while true ; do 

STRING=$(/usr/bin/nfc-list |grep UID |awk '{ print $3,":",$4,":",$5,":",$6,":",$7,":",$8,":",$9 }'|sed 's/ //g' |sed 's/;/:/g' )

[[ $STRING != $OLDSTRING ]] && (gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us+alt-intl')]" ; ydotool type $STRING < /dev/null > /dev/null 2> /dev/null; gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'fr+latin9'), ('xkb', 'us+alt-intl')]" )
OLDSTRING=$STRING
done

```

ydotool s'attend à un clavier US, d'où la nécessité de jouer avec gsettings.

Le script est appelé au démarrage via l'application de réglage des préférences gnome-session-properties :

[![image.png](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-10/scaled-1680-/Frvimage.png)](https://wiki.fablab.sorbonne-universite.fr/BookStack/uploads/images/gallery/2025-10/Frvimage.png)

Malgré le #/bin/env bash en début de script, il est nécessaire d'indiquer /bin/bash /home/fablabuser/run-nfc-scan

# Compléments : API, webhooks, PWA



# Webhooks

Les webhooks sont un mécanisme complémentaire de l'API pour interagir avec les applications/services en ligne. Timetonic en particulier peut "écouter" les webhooks pour réagir lors d'appels.

Une bonne introduction est disponible sur [Webhook.net](https://webhook.net) ([archive](https://web.archive.org/web/20260320160309/https://webhook.net/))

Pour intégrer des appels webhooks dans une page web, avec des scripts, la démarche et des exemples sont présentés [ici](https://docs.talemate.co/dev-portal/latest/tutorials/webhook-buttons.html) dans un contexte de pilotage d'un robot via une page web ([archive](https://web.archive.org/web/20260320160230/https://docs.talemate.co/dev-portal/latest/tutorials/webhook-buttons.html)).

Outils pour tester les requêtes et apprendre :

- [https://pie.dev](https://pie.dev) et sa version CLI : [httpie](https://httpie.io/)
- [Postman](https://www.postman.com)
- ou tout simplement la commande curl.

Concernant l'usage de curl, il existe d'ailleurs un site web [curlconverter](https://wiki.fablab.sorbonne-universite.fr/BookStack/curlconverter.com) qui traduit une syntaxe curl vers d'autres langages (C, python, javascript et de nombreux autres)

[Quelques bonne pratiques (y compris sécurité) pour la programmation avec des webhooks.](https://hookdeck.com/blog/webhooks-at-scale)