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.
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.
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 :
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
#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.
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.
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. 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.
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. La requête doit être envoyée en POST à l’URL suivante :
https://timetonic.com/live/api.php
Les paramètres à inclure sont :
-
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
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
-
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-urlencoded23. -
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
statusdans la réponse JSON.
5. Résumé
Pour communiquer avec l’API de TimeTonic depuis un M5Stack, il faut :
-
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.
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.
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 :
-
req: "getTableValues" -
o_uetu_c: identifiants utilisateur -
sesskey: clé de session API -
b_c: code du book (carnet) -
catCode: code de la table (catégorie)
Exemple de requête POST :
req=getTableValues&o_u=USER_ID&u_c=USER_ID&sesskey=SESSION_KEY&b_c=BOOK_CODE&catCode=TABLE_CODE
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. 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.
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)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_EXISTANTou rowId=tmpNEW_ROW) et de fournir les nouveaux champs à modifier dans fieldValues.
Paramètres nécessaires :
-
req: "createOrUpdateTableRow" -
o_uetu_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 :
{
"field ID": "Value",
"field ID 2": "Value 2",
"field ID 3": "Value 3"
}
Exemple de requête POST:
req=createOrUpdateTableRow&o_u=USER_ID&u_c=USER_ID&sesskey=SESSION_KEY&b_c=BOOK_CODE&catCode=TABLE_CODE&rowId=ROW_ID_EXISTANT&fieldValues={"FIELD_ID1":"NouvelleValeur"}
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.
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). Avant de pouvoir lire ou écrire, il est indispensable de connaître :
-
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)
5. Résumé des étapes
-
Authentification : Obtenir un
sesskeyvia l’API. -
Lister les tables : Utiliser
getAllBookspuisgetBookTablespour identifier le book et la table cible si nécessaire. -
Lire des données : Utiliser
getTableValuespour obtenir les lignes et champs. -
Écrire des données : Utiliser
createOrUpdateTableRowavecrowId=tmpNEW_ROWsi vous voulez créer une nouvelle ligne.
6. Bonnes pratiques
-
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
statusdans 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).
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.