Récupération de donnée après coupure réseau.

Bonjour,
je réalise un projet avec une multitude de capteur. Toutes les données de ces capteurs (valeur numérique) sont envoyées sur une base de donnée MYSQL et enregistrer sur une carte SD. Le problème est que le réseau internet se coupe assez régulièrement (au moins une fois par mois) et que lorsqu'il se coupe les données n'arrivent plus sur ma BDD. J'aimerais que quand le réseau se relance, toutes les données non envoyées soient envoyées. Savez-vous si cela est possible et comment je pourrais faire?
J'ai pensé mettre un ID (incrémentation d'une variable) associé à chaque prise de mesure et que quand il y ai une coupure, l'ID sois mémorisé. Lorsque le réseau se relancerai l'Arduino enverrait les données entre la ID mémorisé et l'ID actuel en allant lire cela dans la carte SD.

Mon autre idée est que quand le réseau se coupe, j'envoie les données dans un autre fichier sur la carte SD (il enverrait les données sur 2 fichiers différents sur la carte SD) et que quand le réseau se relance, il envoie toutes les données du 2e fichier et puis supprime ce qu'il contient pour qu'il soit opérationnelle pour la prochaine coupure.
Si vous n'avez pas assez d'informations n'hésitez pas à me demander.
Merci d'avance.

Savez vous détecter précisément une coupure dans votre code ?

Oui, avant d'envoyer les données de mes capteurs je fais un

if (client.connect("X.X.X.X",80))
{
envoi des donées.....
}
else{
Serial.println("Problème connexion")
}

Et dés que le réseau se coupe je reçois bien l'indication problème de connexion.

OK - Mais si le réseau plante pendant l’émission ?

Si vous avez une carte SD en local elle peut effectivement servir de zone tampon et vous écrivez dans un fichier tant que vous n’arrivez pas à envoyer. Quand le réseau revient, vous testez si ce fichier existe et si oui vous l’envoyez puis envoyez votre dernière lecture et supprimez le fichier... ça marchera si Murphy ne s’en mêle pas mais vous aurez un jour un soucis de plantage pendant l’emission Et là plus possible de savoir ce qui a été envoyé ou pas...

Souvent on traite cela effectivement avec un identifiant unique d’entegistrment Qui permet au serveur de ne pas stocker deux fois la même donnée et un ack (message retour du serveur) disant que la transaction s’est bien passée (le serveur faisant ou pas un roll back si vous voulez de l’atomicité de la transaction)

Merci de votre réponse. Si le réseau se coupe pendant l'émission ce n'est pas très grave. Les données ne seront pas envoyer 1x (si je perd un cycle de donnée c'est tolérable) et au prochain cycle l'Arduino verra qu'il n'est plus connecté et écrira dans le fichier tampon. Je vais essayer comme cela alors.
Merci beaucoup

Ok - à condition que votre erreur de transmission ne plante pas votre arduino (blocage?) —> reprise après panne important à prévoir si vous dépendez d’un ID il faut pouvoir le sauver en cas de reboot

Non l'erreur de transmission ne plante pas l'arduino.

J'arrive a détecter une panne, stocker les infos dans un fichier "tempon.txt" quand le réseau se coupe, ensuite le lire lorsque le réseau est récupérer mais je ne sais pas comment je pourrais envoyer 10 informations à la fois sur internet alors que le fichier en contient 1000 par exemple. Vous auriez une idée?

Pour être plus clair, c'est savoir séparer l'envoi des données. Tout les X octets envoyer sur internet puis continue dans le fichier et renvoyer X octets etc

Sans avoir une idée de l'architecture c'est difficile à dire.

L'ARDUINO s'adresse t'il à un serveur HTTP ou directement au serveur MySQL ?

Vous répétez simplement 10 fois ce que vous faites pour un envoi, comme si vous veniez de faire une acquisition...

Je passe par un script PHP.
Je récupère les données comme ceci sur la carte SD

 else{
      fichierTempon=SD.open("tempon.txt", FILE_WRITE);
    Serial.println("Probleme de connexion");
    tempon=1;
        for(i=0; i<nbPesons;i++)
      {
        output=pesonsx[j][i].get_units();
        if(output<0)
        {
          output=0;
        }
        
        fichierTempon.print("balance_num");
        fichierTempon.print("=");
        fichierTempon.print(j);
        fichierTempon.print("&peson");
        fichierTempon.print(i);
        fichierTempon.print("=");
        fichierTempon.print(output);
        total+=output;
        }
    fichierTempon.print("&total=");
    fichierTempon.print(total);
    fichierTempon.println();
    total=0;
    fichierTempon.close();
    return;
    }

Et mon envoi habituel lorsque je récupère des données ce passe comme ceci

        client.print( "GET /test2_DIEU/test.php?");
        for(i=0; i<nbPesons;i++)
      {
        output=pesonsx[j][i].get_units();
        if(output<0)
        {
          output=0;
        }
        
        client.print("balance_num");
        
        client.print("=");
        client.print(j);
        client.print("&peson");
        client.print(i);
        client.print("=");
        client.print(output);
        total+=output;
        }
    client.print("&total=");
    client.print(total);
    total=0;
    client.println( " HTTP/1.1");
    client.println( "Host: 139.165.152.138" );
    client.println( "Content-Type: application/x-www-form-urlencoded" );
    client.println( "Connection: close" );
    client.println();
    client.println();
    client.stop();

Pour l’envoi habituel c’est assez facile parce que je récupère quelque données puis j’envoie mais ici j’ai toutes les données et je dois les séquencées et c’est la que je ne voix pas comment faire.

J-M-L je n’ai pas compris.
Merci de votre aide.

Envoie tout simplement une requête par ligne présente dans le fichier.
Tu as juste à lire le fichier ligne par ligne et ajouter chaque ligne à l'URL, puisque les lignes dans le fichier ont déjà le bon format :

"balance_num=X&pesonY=Z&total=T\n"

Remarque : tu ouvres le fichier en écriture, mais sans positionner l'index à la fin (append).

Comment je peux faire une lecture ligne par ligne?

C’est surement pour ça que chaque fois que je relance le programme je dois retirer et puis remettre la carde SD. Je vais regarder comment je peux faire ca.
Merci

Je regarde les exemples d'écriture sur la carte SD et je vois nul part qu'il faut mettre l'index a la fin. L'index est mit pas défaut a la fin puisque quand j'écris les données viennent se mettre chaque fois à la suite non?
Encore merci :slight_smile:

Utilisez la librairie SdFat elle est plus robuste et il existe diffrents modes que vous pouvez combinez avec un OU logique pour dire comment ouvrir le fichier (lecture seule, ajout, etc)

#define O_RDONLY  0X00  ///< Open for reading only.
#define O_WRONLY  0X01  ///< Open for writing only.
#define O_RDWR    0X02  ///< Open for reading and writing.
#define O_AT_END  0X04  ///< Open at EOF.
#define O_APPEND  0X08  ///< Set append mode.
#define O_CREAT   0x10  ///< Create file if it does not exist.
#define O_TRUNC   0x20  ///< Truncate file to zero length.
#define O_EXCL    0x40  ///< Fail if the file exists.

Par exemple vous pouvez dire  if (file.open(name, O_WRITE | O_CREAT | O_TRUNC)) {....

Je vais regarder à ça merci.

Comment je peux faire une lecture ligne par ligne?

Avec SD library : String s = readStringUntil('\n');

Mais cela crée une String, assez déconseillé si l'on veut éviter la fragmentation de la mémoire.
Mais tout dépend de l'ARDUINO. Tu ne nous dis pas de quelle carte il s'agit, ni quelle interface tu utilises (Ethernet, WIFI).
Avec une MEGA cela peut se tenter.

Sinon lire le fichier caractère par caractère dans un buffer suffisamment grand. Quand le caractère lu est '\r' ou '\n' terminer le buffer pr '\0' et envoyer la requête.

Avec SDFat il y a une méthode fgets() et un exemple d'utilisation.

Deuxième bonne raison d'utiliser SDFat plutôt que SD.

Je viens de réussir a le faire la bibliothèque SD en utilisant readStringUntil().
Je possède un shield ethernet et c'est un arduino Mega donc je pense que ca devrait être bon. Je vais regarder quand même SDFat.

Avez-vous déjà eu comme problème que a chaque démarrage de programme (quand je le relance) je dois retirer et ensuite remettre la carte SD, sinon elle ne veut pas s'ouvrir quand je fait ceci if(!SD.begin(4)). Lorsque je la retire et remet ça va tout seul. Je ferme bien à chaque fois le fichier quand j'ai fini de l'utiliser.

Donc le support SD est celui du shield Ethernet ?

Initialise-tu l'Ethernet avant la SD ?
C'est normalement ce qu'il faut faire.