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
M5libdéclare des méthodes virtuelles pures (virtual ... = 0;) commeuploadlogetchangestatus. 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,
uploadlogsans 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
-
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()etchangestatus().
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 :
| Classe | Hérite de | Spécificités |
|---|---|---|
accueil |
M5lib |
Méthodes supplémentaires : entree(), sortie(), regcard().Menu de motifs de visite. |
servante |
M5lib |
Gère la traçabilité des servantes utilisées. |
machine |
M5lib |
Pour l'enregistrement d’utilisation de machines. |
ordinateur |
M5lib |
Associe cartes/scans à une session ordinateur précise. |
materiel |
M5lib |
Permet le prêt/retour d’outils ou matériels via borrow(). |
Chaque classe surcharge au moins :
-
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 renvoie200) servant potentiellement à signaler un changement d’état matériel (ex : verrouillage machine, etc.).
3. Composants globaux manipulés
-
Périphériques :
-
MFRC522 mfrc522: pour la lecture RFID classique (Mifare). -
Unit_UHF_RFID uhf: pour les lectures UHF/EPC.
-
-
API & 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().
-
Résumé Visuel Simplifié
+---------------------------+
| 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()
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
| Fonction | Rôle |
|---|---|
setupstd() |
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. |
reducejson(String json) |
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) |
scancard() |
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. |
scanuhf(String* urfid) |
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. |
showchoice(String choices[]) |
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. |
virtual int uploadlog(String card, String action, String other) = 0 |
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é). |
virtual int changestatus() = 0 |
Méthode virtuelle pure pour changer le statut d'emprunt/de présence (obsolète pour le moment car remplacé par automatisation TimeTonic). |
getuser(String* user) |
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]. |
borrow() |
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...). |
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.
| Fonction | Rôle |
|---|---|
int uploadlog(...) override |
Upload des logs d’accueil à l’API avec les bons id (table, champs...). |
int changestatus() override |
Change le statut d’accueil (placeholder : actuellement valeur fixe pour compatibilité). |
void entree() |
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) |
void sortie() |
Gère la sortie d’un utilisateur (avec getuser) et log cet évènement (avec uploadlog). |
void regcard() |
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 <-> 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. |
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.
| Fonction | Rôle |
|---|---|
int uploadlog(...) override |
Upload des logs liés à l’utilisation d’une servante (carte, action, ""). L'argument other ne sert pas pour les servantes. |
int changestatus() override |
Change le statut de la servante (obsolète, pour compatibilité). |
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.
| Fonction | Rôle |
|---|---|
int uploadlog(...) override |
Upload logs liés à l’utilisation d’une machine (carte utilisateur, action). |
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.
| Fonction | Rôle |
|---|---|
int uploadlog(...) override |
Upload logs spécifiques à l’usage d’un ordinateur (par exemple : session ouverte/fermée). |
Attributs spécifiques
- WIP
e. Classe : materiel
Gère les cycles d’emprunt et de retour d’outillage ou matériel divers.
| Fonction | Rôle |
|---|---|
int uploadlog(...) override |
Upload logs liés à l’utilisation (emprunt/retour) de matériels. |
Attributs spécifiques
- WIP
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
showchoice : UI de sélection de choix multiples (anciennement dans M5lib), retourne la String du choix sélectionnétitre : affichage de texte en gros centré (taille 4, 13 charactères maximum avant dépassement de l'écran)soustitre : affichage de texte en moyen centré (taille 3, 17 charactères maximum)corps : affichage de texte en petit centré (taille 2, 26 charactères maximum)feedback : vibration pour retour utilisateur, à appeler à chaque fois qu'un bouton est pressé