Aquaboun's /// gestion d'aquarium recifal

Bonjour a tous, un long moment que je ne suis pas passer par ici (j'y arrive tout seul hihihi), non en faite je manque cruellement de temp … Je rénove ma maison de A a Z alors sa prend beaucoup de temps, de place …

J'essai de temps en temps d'avancer un peu sur le code, le graphisme et le PCB. C'est justement ce dernier que je partage avec vous aujourd'hui.

Les plus grosse modification sont sur les connectiques. J'au utiliser des connexion ne nécessitant pas a se que je soude mes câble moi même. Donc du din5, rca, jack, sub d et rj45 Il inclus également la possibilité d'installer 3 modules atlas scientifique et les led on été déporter vers l'extérieur pour être visible. Pas de gros changement pour le reste a par de l'optimisation.

Voila le résultat :

|375x500 |281x500 |281x500 |281x500

répartition du brassage avec sélection du type de pompe |281x500 |281x500 |281x500 |281x500 |281x500 |281x500

Salut !

vous êtes devenu un pro, plus besoin de bons points :)

bravo.

Merci mais j'ai eu de bon professeur :wink:

:-[ :D

bonjour a tous,

j’espère que tout le monde va bien en ces temps bien difficile.

un utilisateur a travailler sur une nouvelle fonction que j’ai tout de suite trouvé sympa, la lecture des évènements directement sur l’écran de l’aquabouns.

il ma transmis le bout de code en question mais :

utilisation de “string” pour récupérer les données.
ne peut on pas lire une ligne spécifique ? (ex : lire tout les données de la ligne 53)

Voici son code :

if (myFile) {
  n=0;
  n1=1;
    while ((myFile.available())&&(n1==1)) {
      n++;
      buffersd2 = myFile.readStringUntil('\n');
      char buffersd1[buffersd2.length()+1];
      buffersd2.toCharArray(buffersd1,buffersd2.length()+1);
      switch (n) {
      case 1:
        valeursd00.setText(buffersd1);
        break;
      case 2:
        valeursd01.setText(buffersd1);
        break;
      case 3:
        valeursd02.setText(buffersd1);
        break;
      case 4:
        valeursd03.setText(buffersd1);
        break;
      case 5:
        valeursd04.setText(buffersd1);
        break;
      case 6:
        valeursd05.setText(buffersd1);
        break;
      case 7:
        valeursd06.setText(buffersd1);
        break;
      case 8:
        valeursd07.setText(buffersd1);
        break;
      case 9:
        valeursd08.setText(buffersd1);
       break;
      case 10:
        valeursd09.setText(buffersd1);
        break;
      case 11:
        valeursd10.setText(buffersd1);
        break;
      case 12:
        valeursd11.setText(buffersd1);
        break;
      case 13:
        valeursd12.setText(buffersd1);
        break;
      case 14:
        valeursd13.setText(buffersd1);
        break;
      case 15:
        valeursd14.setText(buffersd1);
        break;
      case 16:
        valeursd15.setText(buffersd1);
        break;
      case 17:
        valeursd16.setText(buffersd1);
        break;
      case 18:
        valeursd17.setText(buffersd1);
        break;
      case 19:
        valeursd18.setText(buffersd1);
        break;
      case 20:
        n=0;
        valeursd19.setText(buffersd1);
        n1=2;
        break;
      }
   }  
  } else {    
   DPRINTF("error opening test.txt");  
  }
  DPRINTF("page sd");  DPRINTLN(); // debug
}

qu’en pensez vous ?

Salut !! ça faisait longtemps !

Oui on peut faire mieux et se passer des Strings!

C'est sur un écran Nextion et vous avez 20 champs de texte valeursd0 à valeursd19 que vous remplissez avec 20 lignes du fichier, c'est ça ?

Comment est défini la variable buffersd1 ? (on dirait un tableau de caractère)

ca fait pas si longtemps :wink: mais ca fais plaisir de voir que je te manque 8)

oui c’est bien ca, sur 18 lignes après réorganisations.

et voici les déclarations dans la librairie :

uint16_t NexText::getText(char *buffer, uint16_t len)
{
    String cmd;
    cmd += "get ";
    cmd += getObjName();
    cmd += ".txt";
    sendCommand(cmd.c_str());
    return recvRetString(buffer,len);
}

bool NexText::setText(const char *buffer)
{
    String cmd;
    cmd += getObjName();
    cmd += ".txt=\"";
    cmd += buffer;
    cmd += "\"";
    sendCommand(cmd.c_str());
    return recvRetCommandFinished();    
}

J’ai bosser dessus toute la journée et j’ai réussi a l’intégrer dans la fonction qui lis la carte sd :

/* lis sur la carte SD */
boolean lisSurSd(const char * nomDuFichierTxt, char *donneeLueSurSD, size_t indexEcritureMAX) {
 boolean lectureOK = false; // retourne l'etat de lecture
 uint8_t i = zero;
 uint8_t ligneNextion = 0;
 uint16_t rechercheLigne = 0;
 DPRINTF("Ouverture de : "); DPRINTLN(nomDuFichierTxt);//debug
 myFile = SD.open(nomDuFichierTxt, O_READ); // ouvre le fichier
 if (myFile) {
   donneeLueSurSD[0] = '\0'; // on initialise la chaine à vide
   while (myFile.available()) { // on lit l'intégralité du fichier, à concurrence de l'espace dispo dans notre buffer
     if (i < indexEcritureMAX) {
       donneeLueSurSD[i] = myFile.read(); // lit le fichier
       i++;
       if (pageActuelNextion == sd) {
         if (donneeLueSurSD[i - 1] == '\n') {
           donneeLueSurSD[i] = '\0';  // il n'y a plus rien à lire dans le fichier, on termine
           i = 0;
           DPRINTF("ligne nextion :"); DPRINT(ligneNextion); DPRINTF(" / ligne actuel :"); DPRINT(ligneActuel); DPRINTF(" / rechercheligne :"); DPRINT(rechercheLigne); DPRINTLN();
           if (rechercheLigne == ligneActuel) {
             ligneActuel++;
             switch (ligneNextion) {
               case 1:
                 valeursd00.setText(donneeLueSurSD);
                 break;
               case 2:
                 valeursd01.setText(donneeLueSurSD);
                 break;
               case 3:
                 valeursd02.setText(donneeLueSurSD);
                 break;
               case 4:
                 valeursd03.setText(donneeLueSurSD);
                 break;
               case 5:
                 valeursd04.setText(donneeLueSurSD);
                 break;
               case 6:
                 valeursd05.setText(donneeLueSurSD);
                 break;
               case 7:
                 valeursd06.setText(donneeLueSurSD);
                 break;
               case 8:
                 valeursd07.setText(donneeLueSurSD);
                 break;
               case 9:
                 valeursd08.setText(donneeLueSurSD);
                 break;
               case 10:
                 valeursd09.setText(donneeLueSurSD);
                 break;
               case 11:
                 valeursd10.setText(donneeLueSurSD);
                 break;
               case 12:
                 valeursd11.setText(donneeLueSurSD);
                 break;
               case 13:
                 valeursd12.setText(donneeLueSurSD);
                 break;
               case 14:
                 valeursd13.setText(donneeLueSurSD);
                 break;
               case 15:
                 valeursd14.setText(donneeLueSurSD);
                 break;
               case 16:
                 valeursd15.setText(donneeLueSurSD);
                 break;
               case 17:
                 valeursd16.setText(donneeLueSurSD);
                 break;
               case 18:
                 valeursd17.setText(donneeLueSurSD);
                 break;
             }
             if (ligneNextion >= nbr2Lignes) {
               donneeLueSurSD[i] = '\0'; // ajoute caractere de fin
               lectureOK = true; // la lecture c'est bien passé
               myFile.close(); // ferme le fichier
               break;
             }
             ligneNextion++;
           }
           rechercheLigne++;
         }
       }
     }
     else {
       donneeLueSurSD[indexEcritureMAX] = '\0'; // ajoute caractere de fin
       break;
     }
   }
   donneeLueSurSD[i] = '\0';  // il n'y a plus rien à lire dans le fichier, on termine
   lectureOK = true; // la lecture c'est bien passé
   myFile.close(); // ferme le fichier
   effaceBufferTexte(); // efface le buffer
   strncpy_P (bufferTexte, texteNextionImportationDe, maxbufferTexte); // recupere "char" en memoire flash et le copie
   bufferTexte[maxbufferTexte] = '\0'; // ajoute le caractere de fin
   if (strlen(bufferTexte) + strlen(nomDuFichierTxt) < maxbufferTexte) {
     strcat(bufferTexte, nomDuFichierTxt); // ajoute a la chaine de caractere
     if (strlen(bufferTexte) + strlen(nomDuFichierTxt) < maxbufferTexte) {
       strcat(bufferTexte, ", OK"); // ajoute a la chaine de caractere
       if (pageActuelNextion == demarrage) { // si l'ecran est sur la page de demarrage
         texte4.Set_font_color_pco(vert); // texte couleur vert
         texte4.setText(bufferTexte);// envoi char a l'ecran nextion// envoi char a l'ecran nextion
         DDELAY(mille);
       }
       else {
         effaceBufferTexte();
         strncpy_P (bufferTexte, texteNextionPasDeFichier, maxbufferTexte); // recupere "char" en memoire flash et le copie
         bufferTexte[maxbufferTexte] = '\0'; // ajoute le caractere de fin
         strcat(bufferTexte, nomDuFichierTxt); // ajoute a la chaine de caractere
         if (pageActuelNextion == demarrage) { // si l'ecran est sur la page de demarrage
           texte4.Set_font_color_pco(rouge); // text couleur rouge
           texte4.setText(bufferTexte);// envoi char a l'ecran nextion// envoi char a l'ecran nextion
         }
         DPRINT(bufferTexte); DPRINTLN(); // debug
         DDELAY(mille);
       }
       DPRINT(bufferTexte); DPRINTLN(); // debug
     }
     else {
       DPRINTF("probleme de place memoire dans lisSurSd niveau 2");  DPRINTLN(); // debug
     }
   }
   else {
     DPRINTF("probleme de place memoire dans lisSurSd niveau 1");  DPRINTLN(); // debug
   }
 }
 else {
   myFile = SD.open(nomDuFichierTxt, O_WRITE | O_CREAT | O_AT_END);
   myFile.close(); // ferme le fichier
 }
 return lectureOK;
}

en faite je compte les saut de ligne pour pouvoir "naviger d’une page a une autre :
si je click bas je prend la suite de la dernier ligne lu
Si je click haut je soustrait 38 a la ligne actuel, je compte les saut de ligne est quand je suis a l’identique j’affiche les 18 lignes suivante.

mais plus on descend et plus c’est long (le temps de recompter les saut de ligne depuis le début)
d’un autre cote je me dit que ce n’est pas une fonction principal et qu’il ne faut peut être pas monter une usine a gaz.

je post une vidéo bientot

OK !

vous pourriez mettre les objets valeursd0... valeursd17 dans un tableau et éviter le gros switch case en faisanttableauValeursd[ligneNextion-1].setText(donneeLueSurSD);

Pour booster un peu la navigation, il faudrait se souvenir de là où vous vous êtes arrêté dans le fichier ('position') et faire un 'seek' à l'octet d'après la prochaine fois que vous venez (une variable static dans la fonction qui s'en souvient et vous mettez un paramètre bool optionnel à la fonction qui dit si vous voulez commencer au début du log ou là où vous vous êtes arrêté la fois d'avant

void afficher18Lignes(bool commenceAuDebut = true)
{
  static uint32_t teteDeLecture = 0; // 0 début du fichier
  if (commenceAuDebut) {
    teteDeLecture = 0;
  } 

  myFile = SD.open(nomDuFichierTxt, O_READ); // ouvre le fichier 
  if (myFile) {
    myFile.seekSet(teteDeLecture); // seekSet pour la bibliothèque SDFat
  
   ... ici le code pour lire 

   if (on est arrivé en fin de fichier) teteDeLecture = 0; // si on a atteint la fin du fichier lors du parcours
   else teteDeLecture = myFile.curPosition()+1; // sinon l'octet suivant 

   myFile.close(); // ferme le fichier
 }
 ...
}

j'avais pensé au seek le problème c'est que si je me replace a l'endroit X, pour aller en avant, ok, mais pour retour en arrière ? vu que je compte en nombre de ligne et pas en octet vu que chaque ligne a un nombre diffèrent de caractère.

https://www.youtube.com/watch?v=_5F8M0iIcM4

et pour le tableau j’avais déjà tenter avec d’autre mais j’ai coincé surement a cause des declaration :
ex :

NexText valeursd17 = NexText(13, 20, "t17");

Salut
Il y a plusieurs techniques pour résoudre cela

La première et la plus simple c’est d’optimiser la lecture dans Un sens avec le seek car c’est l’usage principal sans doute et tant pis pour l’autre sens ( si j’étais vous je commencerais par afficher la Fin du LOG puisque c’est sans doute ce qu’on veut voir en premier si on le regarde et optimiser la marche arrière)

La seconde option c’est conserver une liste de positions. Quand vous êtes sur cette page d’affichage du log vous ouvrez le fichier, le lisez et bâtissez un tableau avec N positions en mémoire, par exemple exemple les 10 dernières pages. Si vous restez dans ces pages alors ça va vite sinon vous retombez sur une lecture séquentielle - donc c’est un peu comme le premier cas sauf que vous avez N positions au lieu d’une seule

Une autre option est ce qu’on appelle le pre-fetch. Vous affichez une page et pendant que l’utilisateur lit au lieu d’attendre sans rien faire un click vous allez déjà chercher les autres positions pour aller dans l’autre sens. Comme ça lors du click vous avez déjà fait un bout du boulot. Le challenge sur un arduino c’est que ça peut bloquer la loop d’attente d’évènements assez longtemps

Une autre approche est d’optimiser le fichier pour cela. Comme il y a de l’espace sur la carte SD, mettre que des lignes de X caractères en replissant avec des espaces si besoin. Comme ça on peut faire des maths pour calculer la position.

il y a la possibilité de réserver un bloc en binaire au début du fichier log pour 1000 positions par exemple (4000 octets) plus le premier octet vous dit combien de postions sont Occupées. Vous écrivez en binaire les positions quand vous générez le log. L’inconvénient c’est que le fichier n’est plus tout en ASCII

Une Variante est d’avoir un fichier ami qui contient ces positions. Vous le gênerez au moment de l’écriture du LOG. Ce fichier sera petit et si vous stockez en binaire dedans les positions (4 octets) c’est facile de faire un seek pour trouver quelle est la position De la page P. En gros c’est un fichier d’index.

Si la fonction log est importante C’est cette dernière approche qui sera la plus efficace sans doute.

djbouns: et pour le tableau j'avais déjà tenter avec d'autre mais j'ai coincé surement a cause des declaration : ex :

NexText valeursd17 = NexText(13, 20, "t17");

Oui mais une fois qu’ils sont tous déclarés vous pourriez faire un

 NexText* tableau[] = {&valeursd0, &valeursd1, ...};

ca mange 18 pointeurs de sram mais ça permet d’optimiser plein de code plus tard sans doute.

commencer par la fin du fichier j'ai fait des recherches et j'ai pas trouvé. j'ai essayer d'écrire dans le fichier en faisant "a la ligne" puis revenir a 0 pour écrire mais sa ne fonctionne pas.(de façon a faire descendre se qui était précédemment écrit et d'écrire sur la nouvelle première ligne vierge)

Cette fonction n'est pas essentiel mais peut être pratique. Ce qui me semble le plus simple est de fixer un nombre de caractère par ligne et après faire des math.

J-M-L: Oui mais une fois qu’ils sont tous déclarés vous pourriez faire un

 NexText* tableau[] = {&valeursd0, &valeursd1, ...};

ca mange 18 pointeurs de sram mais ça permet d’optimiser plein de code plus tard sans doute.

Ok je vais tenter ca

j'ai fait

NexText*tableauLigneAffichageSd[] = {&valeursd00,&valeursd01,&valeursd02,&valeursd03,&valeursd04,&valeursd05,&valeursd06,&valeursd07,
&valeursd08,&valeursd09,&valeursd10,&valeursd11,&valeursd12,&valeursd13,&valeursd14,&valeursd15,&valeursd16,&valeursd17};

puis

tableauLigneAffichageSd[ligneNextion-1].setText(donneeLueSurSD);

et j'ai

request for member 'setText' in 'tableauLigneAffichageSd[(((int)ligneNextion) + -1)]', which is of pointer type 'NexText*' (maybe you meant to use '->' ?)

on a mis des pointeurs dans le tableau pas les objets directement, donc il faut mettre

tableauLigneAffichageSd[ligneNextion-1][color=red]->[/color]setText(donneeLueSurSD);

YEs, merci

et pour le ficher sd, comment faire soit pour lire a l'envers soit pour ecrir en haut a chaque ajout ?

et pour le ficher sd, comment faire soit pour lire a l’envers soit pour ecrir en haut a chaque ajout ?

On ne peut pas écrire en haut à chaque ajout, on écrit toujours à la fin.

Tenez voici un bout de code de démo qui prend la technique du fichier d’index pour lire à l’envers.

(.ino attaché en PJ)

Il y a des constantes importantes pour la gestion des Index ou de l’affichage

const uint8_t nombreDeLignesAffichage = 10; // le nombre de ligne dans une page d'affichage
const uint8_t tailleMaxLigne = 80; // le nombre max de caractère dans une ligne de la page

L’idée est un affichage du fichier de log par ‘pages’ donc il faut connaître la taille d’une page. ici je dis qu’une page c’est 10 lignes.
Ensuite j’ai décidé de forcer un buffer de taille fixe par ligne pour l’affichage (pas forcément dans le log) est ici c’est 80.

Au début dans le setup il faut appeler prepareFichiersLog("bla bla bla en tête", booléen).
Si le booléen est vrai, on détruit les fichiers de logs s’ils existaient. (donc attention !)
Si le booléen est faux et que les 2 fichiers existent déjà, on ne fait rien, mais si un des deux fichier n’est pas là alors on détruit celui qui existe (attention donc!) et on prépare un fichier d’index avec juste 0x00000000 dedans puisque que ce sera le début de la première page du fichier de log et enfin on écrit l’en tête du fichier de log avec “bla bla bla en tête”

Une fois cela fait, il y a une fonction logMessage("ce que l'on veut mettre dans le log") qui écrit dans le fichier de log et qui se charge de maintenir le fichier d’index pour vous. c’est ce qu’il faut utiliser dans le programme à chaque log. Attention il ne faut pas de saut de ligne au sein du message (il faut donc avoir bâti dans un cString ce que l’on veut écrire).

Dans ce fichier d’exemple, j’ai rajouté à la fin de prepareFichiersLog() un petit bout de code pour remplir mon fichier de log avec plus de 2000 lignes pour la démo

 // ici on triche et on pré-rempli le fichier, à enlever bien sûr
  char message[100]; // un buffer assez grand pour notre message
  for (int i = 1; i < 2023; i++) { // 24 pages de 10, la dernière n'ayant que 7 lignes (ligne d'en tête dans le fichier de log)
    sprintf(message, "%03d\tles valeurs sont A0=%d et A1=%d\t{%ld}", i, analogRead(A0), analogRead(A1), random(-32000, 32000));
    logMessage(message);
  }
  Serial.println("Fichier de log de démo créé avec 2023 lignes");

cette création prend un peu de temps bien sûr car je voulais un fichier de log assez important.

Voilà. La loop est toute simple, elle attend un caractère sur la console série à 115200 bauds. tapez ‘d’ pour lire la page de début, ‘f’ pour lire la page de fin, ‘+’ ou ‘s’ pour lire la page suivante et ‘-’ ou ‘p’ pour lire la page précédente.

Le fichier de log s’appelle “log.txt” et celui d’index associé est “_log.txt”

je vous laisse essayer (ne prenez pas votre carte SD de votre système, je ne veux pas être responsable de son effacement :slight_smile: )

Vous verrez que c’est assez rapide d’accéder à la dernière page (‘f’) et de remonter (’-’) malgré le fait que l’on ait plus de 2000 lignes dans le fichier

essayez de faire ‘f----++±—’ par exemple et vous verrez que ça speed pas mal :slight_smile:

On pourrait envisager facilement un petit bout de code à exécuter une fois séparément qui lit votre fichier de log existant et construit l’index de façon à ce que vous puissiez intégrer la nouvelle fonctionnalité sans avoir à détruire le log existant.

SD_LogAndScroll.ino (8.86 KB)

bonjour,

je retravaille depuis peu sur le projet. Je reprend donc la partie affichage des erreur. J'ai voulu faire par moi même :stuck_out_tongue:

tout les messages écrit avait la même taille (100 caractères) je me plaçait au dernier caractere du fichier je remontait de 100 pour lire une ligne et l’afficher puis remontait de 100 ect ...

La première page (18 lignes) etait ok mais des que je voulait changer de page rien n'allait alors que j'utilisait toujours le même principe. De plus, avec cette méthode aucune vérification pour savoir si l'emplacement était ok par exemple si l'arduino reboot au milieu d'une écriture tout la lecture est ensuite décalé ...

Je me suis donc mis sur le code joint par JML Le principe est compris mais le code est un peu dur a déchiffrer et donc a l'adapter ...

J'aurais besoin de quelque info pour être sur :

chaque ligne écrit doit être précéder de chiffre ? Pour écrire le message je lance la fonction avec mon char* >>> logMessage(bufferTexte);, j'ai bon ? Le fichier index ne s'enrichi que lorsque ont a atteint le nombre de ligne indiquer ? >>> si oui, je pense que mon problème vient de la puisque J'ecrit ligne par ligne cela veut dire que temps que je n'ai pas écrit assez de ligne elle ne sont pas indexer ?