Go Down

Topic: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL (Read 112900 times) previous topic - next topic

J-M-L

#1125
Jun 07, 2019, 12:46 pm Last Edit: Jun 07, 2019, 12:47 pm by J-M-L
Merci
Je vous ai sorti du binaire en échange :)

Pour analyser la date et calculer des différences puisque vous utilisez si je le souviens bien une DS3231 et la librairie RTCLib vous pouvez créer un objet DateTime à partir de l'heure unix et ensuite faire des operation de soustraction entre deux dates pour obtenir un objet de Time TimeSpan que vous pouvez interroger sur le nombre de minutes etc
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

djbouns

Merci
Je vous ai sorti du binaire en échange :)

Pour analyser la date et calculer des différences puisque vous utilisez si je le souviens bien une DS3231 et la librairie RTCLib vous pouvez créer un objet DateTime à partir de l'heure unix et ensuite faire des operation de soustraction entre deux dates pour obtenir un objet de Time TimeSpan que vous pouvez interroger sur le nombre de minutes etc
oui c'est se que je pensait faire. faudra que je creuse timespan pour comprendre.

J'ai inclus la lecture  et écriture binaire dans l'aquabouns et en voulant commencer l'analyse de la date puis le graphique je me suis aperçu d'un "problème"
l'écriture sur SD se fait a la suite, du coup, la dernière prise de mesure est a la fin.
Quand on lit, on lit du début a la fin donc la première lecture est la mesure la plus ancienne.
Quand on dessine le graphique, on envoie une donné qui est décalé d'un cran vers la droite par la deuxième et ainsi de suite (on le vois bien sur la vidéo que j'ai mis avant)
donc tout serait inversé.
Et d'après se que j'ai chercher, il n'y a pas de lecture a l'envers.
Il n'est pas non plus possible d'écrire au début du fichier en décalant la suite.
Mais il y a peut être encore un truc au font du chapeau ?

Encore une chose qui me taraude,
Quand on lit Sd, on lit par vague d'octets correspondant a la taille de la structure.
Mais je me dit, a aucun moment on contrôle que l'on est bien en train de lire calqué sur la vague.
imaginons que pendant l'écriture en binaire sur SD il y a un problème (coupure électrique ou autre)
on va se retrouvé a lire complètement en décalé.
Je ne sait pas si j'ai été claire.





J-M-L

Si si on peut lire le fichier « à l'envers » en utilisant seek() pour se positionner au bon octet

En pratique si tout se passe bien la taille T de votre fichier est un multiple de la taille d'un enregistrement S et  N = T/S sera le nombre d'enregistrements Dans le fichier. Si vous voulez vous positionner au début de l'enregistrement index (commençant à zéro) il suffit de faire un seek à la position indexS

Un seek à 0 vous met au début du fichier,  un seek à la position T vous met en fin de fichier prêt à rajouter quelque chose si le fichier est aussi ouvert en écriture.

Donc pour lire à l'envers il faut calculer N et pour lire le dernier enregistrement vous faites un seek vers (N-1)*S, puis vous lisez les octets et envoyez à l'écran, ensuite vous faites un seek vers (N-2)*S, puis vous lisez les octets et envoyez à l'écran,  ensuite vous faites un seek vers (N-3)*S, puis vous lisez les octets et envoyez à l'écran etc... je pense que vous voyez quel boucle/indice utiliser pour lire les 672 derniers enregistrements :)

 
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

djbouns

arfff pffff j'en est marre de pas y penser lol

et comment être sur que l'on est bien positionner a la lecture bien en face de l'écriture ?

J-M-L

Faut faire confiance aux maths :)
Sinon vous pouvez mettre un mot magique en début de structure genre un uint32_t qui vaut 0xDEADBEEF et donc si vous n'êtes pas positionné sur un « bœuf mort » quand vous lisez vous savez que vous avez un soucis dans le code.. bon ça prend un peu de place sur la carte SD mais vu que maintenant elles font des gigas c'est pas un souci

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

djbouns

j'ai mis tout ca en forme dans l'aquabouns puis travailler le graph ca donne ca :

pour vérifier l'enregistrement j'ai repris le meme que pour l'eeprom
Code: [Select]
const uint32_t motClef = 0xBEEFDEAD;

pour ecrire en binaire :
Code: [Select]
/* ecrit sur la carte SD en binnaire les donner pour le graphique */
void stockMesuresEnBinaire() {
  DateTime now = rtc.now(); // recupere la date et heure
  stockMesuresDansSD.enregistrement.horodatage = now.unixtime(); // stock date et heure en binaire
  stockMesuresDansSD.enregistrement.clef = motClef ; // clef pour controler que l'on lit bien en face
  stockMesuresDansSD.enregistrement.mesuresT = random (2600, 2650); // copie la temperature du bac
  stockMesuresDansSD.enregistrement.mesuresPh = random (780, 820); // copie le Ph du bac
  //DPRINTF("stockMesuresDansSD.horodatage : "); DPRINTLN(stockMesuresDansSD.enregistrement.horodatage);
  // DPRINTF("stockMesuresDansSD.mesuresT : "); DPRINTLN(stockMesuresDansSD.enregistrement.mesuresT);
  //DPRINTF("stockMesuresDansSD.mesuresPh : "); DPRINTLN(stockMesuresDansSD.enregistrement.mesuresPh);
  myFile = SD.open(mesuresEnBinaire, O_WRITE | O_CREAT | O_AT_END); // ouvre le fichier
  DPRINTF("Ouverture du fichier : "); DPRINTLN(mesuresEnBinaire); // debug
  if (myFile) {
    myFile.write(&stockMesuresDansSD, sizeof(stockMesuresDansSD)); // ecrit dans le fichier
    DPRINTF("Ecrit les mesures sur la carte SD"); DPRINTLN(); // debug
  } else {
    DPRINTF("Erreur d'écriture dans le fichier "); DPRINTLN(); // debug
  }
  myFile.close(); // ferme le fichier
}


vous remarquerez que les donner sont générer aléatoirement par un random pour les test




puis pour lire / analyser :
Code: [Select]
/* lit sur la carte SD les données binnaire pour le graphique */
void lisMesuresEnBinaire() {
  boolean dateDerniereMesure = false;
  uint16_t nbr2MesuresPourLeGraphique = (576 + (variable.Heure * 4) + (variable.minut / 15)) ; // 96 pixels = 1 jours /// 6 jours = 576 pixel + 4 pixels par heure du jour J + 1 pixel toute les 15 min du jour J
  myFile = SD.open(mesuresEnBinaire, O_READ); // ouvre le fichier
  if (myFile) { // fichier ouvert
    uint8_t i = 0; // index pour lire
    uint8_t indexErreur = 0; // index pour decaler la lecture si erreur/clef non conforme
    uint16_t indexMesure = 1; // index des mesures
    uint16_t nbr2MesureMax = (myFile.fileSize() / sizeof(stockDansSD_t)) + indexMesure; // stock le nombre de mesure maximum qu'il y a sur la carte sd
    uint16_t quinzeMinutes = 900; // en secondes
    DateTime now = rtc.now(); // recupere la date et heure actuel
    uint32_t tempsEntreLesMesures = now.unixtime();
    DPRINTF("taille du fichier mesuresEnBinaire : "); DPRINTLN(myFile.fileSize()); // debug
    while (indexMesure < nbr2MesuresPourLeGraphique) { // on boucle autent de fois qu'il faut de pixel pour le graphique
      if (indexMesure >= nbr2MesureMax) {
        graphique(zero, zero); // lance la fonction
        indexMesure++;
        DPRINTF("pas assez de mesures a lire"); DPRINTF("indexmesure : "); DPRINT(indexMesure); DPRINTF(" nbr2MesureMax : "); DPRINT(nbr2MesureMax); DPRINTLN(); // debug
      }
      else {
        DPRINTF("emplacement : "); DPRINTLN((myFile.fileSize() - (indexErreur + (sizeof(stockDansSD_t)*indexMesure)))); // debug
        myFile.seek(myFile.fileSize() - (indexErreur + (sizeof(stockDansSD_t)*indexMesure))); // on se place dans le fichier
        while (i < sizeof(stockDansSD_t)) { // on lit une vague correspondant a la taille de stockDansSD_t
          stockMesuresDansSD.lesOctetsAssocies[i] = myFile.read(); // lit le fichier
          i++; // incremente l'index
        }
        i = zero; // remet l'index a zero pour la prochaine lecture
        DPRINTF("clef : "); DPRINTLN(stockMesuresDansSD.enregistrement.clef); // debug
        if (stockMesuresDansSD.enregistrement.clef == motClef) { // si la clef lu correspond a la clef de controle
          if (dateDerniereMesure == false) { // pour lire la date une fois
            DateTime dateDesMesures = stockMesuresDansSD.enregistrement.horodatage; // convertie l'unixtime en date
            DPRINTF("date : ");  DPRINT(dateDesMesures.day()); DPRINTF("/"); DPRINT(dateDesMesures.month()); DPRINTF("/"); DPRINTLN(dateDesMesures.year()); // debug
            dateDerniereMesure = true; // pour lire la date une fois
          }
          if (tempsEntreLesMesures - quinzeMinutes < stockMesuresDansSD.enregistrement.horodatage) {
            graphique(stockMesuresDansSD.enregistrement.mesuresT, stockMesuresDansSD.enregistrement.mesuresPh); // lance la fonction
            DPRINTF("heure : "); DPRINT(stockMesuresDansSD.enregistrement.horodatage / 3600 % 24); DPRINTF("h"); DPRINT(stockMesuresDansSD.enregistrement.horodatage / 60 % 60); // debug
            DPRINTF(" et "); DPRINT(stockMesuresDansSD.enregistrement.horodatage % 60); DPRINTF(" secondes"); // debug
            DPRINTF("mesuresT : "); DPRINT(stockMesuresDansSD.enregistrement.mesuresT); // debug
            DPRINTF(" et mesuresPh : "); DPRINTLN(stockMesuresDansSD.enregistrement.mesuresPh); // debug
            indexMesure++; // increment l'index des mesures
          }
          else {
            graphique(zero, zero); // lance la fonction
            nbr2MesuresPourLeGraphique--; // on decremente le nbr de mesure pour le graph puisque on a dessiner un pixel sans incrementer l'index
            DPRINTF("trou dans la chronologie des mesures"); DPRINTLN(); // debug
          }
          tempsEntreLesMesures = tempsEntreLesMesures - quinzeMinutes;
          DPRINTF("tempsEntreLesMesures : "); DPRINT(tempsEntreLesMesures); DPRINTLN(); // debug
          DPRINTF("stockMesuresDansSD.enregistrement.horodatage : "); DPRINT(stockMesuresDansSD.enregistrement.horodatage); DPRINTLN(); // debug
        }
        else {
          DPRINTLN("erreur dans la lecture binaire des mesures"); // debug
          indexErreur++; // increment l'index des erreurs
        }
      }
      wdt_reset(); // indique que le loop est OK, pas de bug, remise a zero du compteur "reboot" du watchdog car la lecture de toute les mesure pourait depasser le timer du watchdog
    }
    DPRINTF("taille : "); DPRINTLN(sizeof(stockDansSD_t)); // debug
    myFile.close(); // ferme le fichier
  }
  else { // erreur a l'ouverture du fichier
    DPRINTLN("Erreur a l'ouverture du fichier mesuresEnBinaire"); // debug
  }
}


> détecte les vides dans l'écriture ecris une mesure nul puis décale de 15 min ect ...
> décale d'un octect la lecture si on tombe pas sur le motClef

sa fait 24h que ca tourne, ca a l'air ok.
https://www.youtube.com/watch?v=u7Rk8nRQq9k

J-M-L

Très bien :)

Notez que maintenant que vous avez compris pour les octets vous n'avez pas vraiment besoin de l'union pour lire les octets de la structure les uns après les autres, la fonction read() sait fait comme la fonction write() et supporte la formefile.read(buf, len) donc vous pouvez lui passer l'adresse de votre buffer et sa taille et ça lit tout d'un coup :)

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

djbouns

oula :/
sa voudrait dire faire un truc comme sa :
Code: [Select]
stockDansSD_t = myFile.read((myFile.fileSize() - (indexErreur + (sizeof(stockDansSD_t)*indexMesure))),sizeof(stockDansSD_t));

J-M-L

#1133
Jun 18, 2019, 11:31 pm Last Edit: Jun 18, 2019, 11:33 pm by J-M-L
Euh presque - un truc du genre :)

Il faut faire un seek au bon endroit et ensuite read(adresse_buffer, nombre_octets)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

djbouns


J-M-L

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

djbouns


djbouns

#1137
Jul 12, 2019, 11:24 am Last Edit: Jul 13, 2019, 08:23 am by djbouns
Cc,

très très  pris par le taf en se moment …

:smiley-confuse:

je continu les évolutions quand je peux et je me suis pencher sur le problème des module PH analogique, peu fiable a moyen / long therme.
j'en est pourtant testé de diffèrent model plus ou moins chère avec le même résultat au bout de quelque semaine / mois, des dérives importante.

j'ai donc commander un  module EZO PH de chez atlas.
les premier test son très concluant ! une précision incomparable !
ces module fonction via port série ou i2c.
mes test on été faire en port série car j'ai lu qu'en i2c il fallait mettre un filtre pour avoir des donné "propre"
j'ai testé avec la librairie SoftwareSerial mais les pin  utilisable sont limité et beaucoup de personne dise que ces la pire des librairie de port série virtuel
apres recherhce j'en est trouvé 2 autres, mieux "noté" :
AltSoftSerial
NeoSWSerial

quelle serait la meilleur alternative ?

ps : autre avantage des module ezo de chez Atlas, sur le même format il ont un module REDOX et CONDUCTIVITE.
l'idée est de prévoir 3 emplacements pour module et de laisser libre chois avant téléversement sur les module utilisé, exemple :
1 PH bac, 1 PH RAC , 1 REDOOX
ou
1 PH bac, 1 REDOX, 1 CONDUCTIVITE
et bien sur les 3 mesures des modules visualisable sur un graphique :)






J-M-L

Vous n'avez plus de port série matériel sur le MEGA?
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

djbouns

Vous n'avez plus de port série matériel sur le MEGA?
et non puisque j'ai l'écran, le sim800l et le d1mini

Go Up