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 à :


3. Lecture du UID

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


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

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 :

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 status dans 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_u et u_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 : 

Par exemple :

&fieldIds = [7457220, 7457221]

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

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 :

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_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 :
{
	"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

  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.


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


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.