Arduino Forum

International => Français => Topic started by: djbouns on Oct 08, 2017, 09:48 am

Title: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 08, 2017, 09:48 am
Je vient vers vous pour exposer mon projet et peut être recevoir votre aide.

Ma passion a moi , ce n'est pas l'arduino.
Je suis aquariophile depuis tout petit et tournée depuis 6 ans vers le récifal.
Cette passion, tout comme vous, je la partage sur un forum (récifal France) et a chaque étape/projet que j'ai réalisé, j'en est profité pour partager la réalisation avec les autres membres.
Mon bac actuel :
http://www.recifal-france.fr/400l-de-djbouns-t22449.html

Un des premier projet arduin :
http://www.recifal-france.fr/boitier-balling-maison-de-80-t13110.html

Et mon dernier avec le montage d'un ackduino :
Peut etre avez vous déjà entendu parler de l'ackduino ? si non, pour faire cours, c'est un programme sur arduino afin de gérer tout les éléments essentiel d'un bac récifal
http://www.recifal-france.fr/montage-d-un-ackduino-de-a-a-z-t23888.html?hilit=ackduino#p413808

Comme vous, je prend du temps pour partager et aider les autre dans le domaine que je "maîtrise"
Je me suis lancé dans l'arduino a cause du prix de ma passion, les appareil du commerce son hors de prix (exemple, l'aquatronica de base a 750€ http://www.aqua-store.fr/automatisation-aquarium/4717-aquatronica-touch-controller-kit-basic.html)
jetait donc content d'avoir réalisé pour ~80€ des pompe de dosage, car a cette époque le premier prix était dans les 250€ et la distribution de produit en récifal était vraiment la base.
J'etait encore plus content de le partagé et de voir d'autre passionné enthousiasmé (qui devait être dans la situation budgétaire)

Mon projet en cours est en remplacement de cette ackduino (ackduino a été crée par plusieurs personne qui on chacune ajouté leur touche au fur et a mesure puis "abandonné" par les createur au depent d'un projet sur raspbery.
A moyen terme, j'ai personnellement eu le droit a des bug régulier puis a un débordement du bac + une pompe bloqué en marche a vide = cramé + disjoncté ...) bref ...
Dans le but de d'avoir un outil plus fiable pour nos bac, je me suis donc lancé dans ce projet.
(depuis juin).

Je pense avoir bien avancé seul dans un premier temps coté programme :
Levée couchée soleil
Puissance brassage
Oscillateur
Distribution nourriture
Affichage sur écran 3.2 (volonté du non tactil)
Divers alarme et securité

Mais aussi coté hardware avec le dessin et création d'un circuit imprimé (première fois pour moi), le but étant de n'avoir qu'a brancher sonde et autres ... la simplicité pour tous !

C'est sur les fonctionne plus complexe du programme que j'arrive sur le forum arduino.com ...
Je vient tout juste d'intégré dans le programme la gestion des SMS en cas de dépassement température ou de coupure edf.
Oufff :)

Mais voila ...
Je coince sur la partie WEB qui doit avoir pour but de voir les paramètres actuel du bac mais également de pouvoir faire les réglages des paramètres.
j'en apprend tout les jours avec l'arduino mais cette fonction nécessite un niveau de compétence qui me dépasse malgré mon implication. https://forum.arduino.cc/index.php?topic=502206.0


Je cherche a être épauler afin de finir ce dernier chapitre et finaliser tout ça, je pourrait ensuite, a mon tour, partager et apporté mon aide dans mon domaine, sur le forum recifal france (je ne manquerait pas de préciser les personne aillant participé)

Je comprendrait tout a fait que cela n'intéresse pas puisque il n'y a pas d'intérêt pour vous dans tout ça (a par si vous êtes aquariophile également :)).

Ci joint les fichier du projet :
https://www.petit-fichier.fr/2017/10/07/aquabouns/

Toute petite pierre a l'édifice est bien venu :)

Quoi qu'il en soit , je vous remercie d'avoir pris le temps de me lire jusque la.

Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 09:59 am
Les premiers question me viennent de JML :

pourquoi vous obstiner à travailler au niveau de la commande AT et ne pas utiliser des libraries et mon petit hack PROGMEM pour balancer les réponses?
Tout simplement parce que malgré des heures de recherche sur le net, toute bibliothèque trouvé utilise des pin digital via SoftwareSerial Library au lieu des pin RX/TX

pourquoi un esp-01 en mode série? plutôt que des puces plus puissantes genre un wemos D1 mini pro par exemple qui va embarquer la couche wifi directement?
J'essaie de prendre des composant pour les quelle je pense (ou pansait pour celui ci) maîtrisé leur utilisation seul, le plus simplement possible (pour moi simplicité = fiabilité) faire embarqué la couche wifi me semble être compliqué a faire vu mon niveau

est-ce un arduino dédié à l'interface web parlant à d'autres arduino pour collecter les données à représenter où est-ce un seul arduino pilotant tout été devant aussi fournir une interface web? Quels so les éléments connectés et que font-ils
Oui, un arduino seul, toujours pour des raison de codage. ces donc ce seul arduino qui collecte et envoie les info sur la page web.
Je détaillerais tout les éléments connecté dans le post suivant.

Aussi Quelles sont les raisons qu'on président aux choix des composants ou de l'usage direct des commandes AT etc - y-a-t-il une flexibilité sur ce point là? Il doit y avoir à peine 1 ou 2 euros d'ecart Entre un ESP-01et un ESP-12 ou ESP-32 (ESP-8266EX) du Wemos
Il n'y a aucun blocage pour changer de composant si celui ci utilise un port RX/TX. Le circuit imprimé étant deja fait, il serait préférable que les composant changer, quel qu'il soit, puisse se brancher a dans l'emplacement prévu. J'étudierais dans le cas contraire si il y a vraiment un grand bénéfice a changer le CI pour ce composant. 
Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 10:13 am
En détails, voici les composants relié au CI :

1 sonde lm35 pour prise de température de la rampe d'éclairage

1 buzzer pour l'alarme

1 sonde ds18b20 pour température du bac

4 sortie pour le PWM de l'éclairage, driver meanwell
(http://i65.tinypic.com/14eaxkg.jpg)
(http://i63.tinypic.com/33y430y.jpg)
(http://i67.tinypic.com/axffom.jpg)
(http://i68.tinypic.com/14t1snl.jpg)


3 sortie pour le PWM des oscillateur, futaba s3003
(http://neo3plus.com/279-large_default/oscillateurs-de-pompes-osci.jpg)


3 sortie Pour le PWM des pompe de brassage ( jebao rw15) il faut ajouter une petite carte a l'interieur du boitier afin de le relier a l'arduino :
(http://www.aquastyleonline.com/product_images/uploaded_images/rw-2.jpg)
(https://farm3.staticflickr.com/2943/15137331898_b8bb076902_z.jpg)
(https://farm4.staticflickr.com/3904/15137202409_377e6d12c9_z.jpg)


sda/scl pour ds1307

rx/tx1 pour gsm sim900

rx/tx2 pour esp-01

7 sorties A pour boutons via C.I additionnel (5 utilisés pour le moment donc 1 pour la coupure EDF)

8 sorties A pour relais (commutable car certain relais seront utilisé sans l'arduino si besoin) Les relais sont dans le tableau électrique afin qu'il n'y est JAMAIS de 220v hors du tableau (et des prise :) :) :) )
(http://www.conrad.fr/medias/global/ce/3000_3999/3800/3800/3804/1217711_BB_00_FB.EPS_1000.jpg)


1 sortie A pour sonde PH

sorties de 22 a 54 pour hx8357c (écran + sd) (avec se que j'ai trouvé sur le net les sortie 42+43+44+45+46+47+49 ne serait pas utilisé)
(https://img.banggood.com/thumb/water/oaupload/banggood/images/64/6C/6f365674-fd09-4db6-988e-90d1c1dc1721.png)
(https://img.banggood.com/thumb/water/upload/2014/01/SKU193219-4.jpg)
Il seras déporté de 10/15 cm via un nappe.


Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 10:24 am
Le détails des fonctions déjà codé:

l'éclairage, levée et couché progressif en fonctionne d'un horaire de début et de fin, chaque canal et décalé d'un temps donné. niveau maximum réglable

Brassage, associé au levée couché du soleil avec un minimum et maximum réglable.

Oscillateur, angle mini et maxi pour chaque oscillateur avec un temps de mouvement réglable (mais identique pour les 3).

température rampe, déclenchement des ventilateur en cas de dépassement de la température maximum réglée

température bac, déclenchement des ventilateur en cas de dépassement de la température maximum réglée puis alarme, envoie sms, coupure chauffage en cas de dépassement d'une température critique.

GSM, pour envoie de toute anomalie + coupure edf (relais situé dans le tableau électrique et alimenté en continu (relais fermé = bouton non appuyé) qui fait un retour sur un pin bouton de l'arduino, si bouton appuyé (relais ouvert = plus alimenté = bouton appuyé) envoyé d'un SMS (l'arduino est alimenté par une batterie de secours en 5v)

Wifi, pour visualisé les paramètre du bac a tout moment et aussi une partie "réglage" des paramètre

PH, mesure le PH (simplement :) ) mais possibilité par la suite de l'associer a un relais pour gestion d'un RAC par exemple (Réacteur A Calcaire, c'est un tube remplis d'aragonite  dans le quelle une faible partie de l'eau de l'aquarium passe, on y injecte du CO2 afin de descendre le PH se qui dissous l'aragonite, l'eau qui en sort est donc chargé en calcium en KH et compense la consommation des coraux, le CO2 est régulé par un PH-mètre réglé a un PH précis qui active un électrovanne)
(http://www.neo3plus.com/img/cms/info%20recifale/PERIPHERIQUESRAC.jpg)

écran  pour afficher les paramètre ( a voir si possibilité de mise en veille )

Fonction tempête, met le brassage au max durant un laps de temps paramétrable.

Nourrissage, 1 fonction automatique a heure fixe qui actionne un relais qui active un distributeur et baisse/coupure brassage / pompe remonté ... 2eme fonction manuel pour couper les pompe via un bouton durant un laps de temps paramétrable pour nourrire manuellement (cube de congelé par exemple)









Title: Re: aquaboun's
Post by: J-M-L on Oct 08, 2017, 02:10 pm
pourquoi vous obstiner à travailler au niveau de la commande AT et ne pas utiliser des libraries et mon petit hack PROGMEM pour balancer les réponses?
Tout simplement parce que malgré des heures de recherche sur le net, toute bibliothèque trouvé utilise des pin digital via SoftwareSerial Library au lieu des pin RX/TX
avez vous regardé cette librairie (https://github.com/bportaluri/WiFiEsp).

Si vous regardez le code d'un des exemple fourni (WebServer.ino) (https://github.com/bportaluri/WiFiEsp/blob/master/examples/WebServer/WebServer.ino), vous verrez qu'il commence comme ceci:

Code: [Select]
#include "WiFiEsp.h"
// Emulate Serial1 on pins 6/7 if not present
#ifndef HAVE_HWSERIAL1
#include "SoftwareSerial.h"
SoftwareSerial Serial1(6, 7); // RX, TX
#endif


Le code teste (avec le #ifndef HAVE_HWSERIAL1) si la carte Arduino sur laquelle on est a un port Serial1 en matériel et si oui c'est ce qui sera utilisé pour piloter les commandes AT de l'ESP, sinon il instancie une connexion SoftwareSerial qu'il appelle Serial1  et dans le setup il initialise la configuration en passant le port Série sur lequel il travaillera

Code: [Select]
  // initialize ESP module
  WiFi.init(&Serial1);


si j'ai un peu de temps dans l'après midi je vous poste un petit exemple

Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 03:20 pm
si j'ai un peu de temps dans l'après midi je vous poste un petit exemple


Inutile, c'est effectivement la seul que j'ai trouvé et en parallèle de mon code utilisant AT, j'ai travaillé dessus.
Il fonctionne mais j'ai le problème d'affichage, mot par mot dans la page web, suite au conseil sur un autre poste, j'ai essayer de stocker sur carte SD et c'est pire, il doit encore y avoir une histoire de mémoire la dedans ... et c'est ce qui complique tout pour moi.
je retrouve le code ou j'en était et vous poste.
Title: Re: aquaboun's
Post by: J-M-L on Oct 08, 2017, 03:26 pm
Inutile, c'est effectivement la seul que j'ai trouvé et en parallèle de mon code utilisant AT, j'ai travaillé dessus.
Il fonctionne mais j'ai le problème d'affichage, mot par mot dans la page web, suite au conseil sur un autre poste
Oui mais comme vous utilisez une librairie qui gère le stockage en mémoire FLASH, ça ne va pas manger toute votre RAM et il n'y a pas besoin de la classe String. ça a l'avantage de simplifier l'insertion de valeur dynamique dans la page aux bons endroits sans avoir à analyser la ligne et gérer un truc un peu compliqué d'accès aux variables comme j'avais fait avec le tableau de variables dans l'autre post (en trouvant des lignes contenant juste $$$)

essayez ce code par exemple (esp-01 connecté sur Serial2)

si vous tapez l'URL - http://192.168.1.28 chez moi - ça vous dit bonjour et affiche des infos dynamiques
si vous tapez http://192.168.1.28/admin  ça vous affiche une autre page et si vous tapez http://192.168.1.28/AutreChose  alors vous aurez une page d'erreur




Code: [Select]
/* exemple d'utilisation de la librairie "WiFiEsp.h"  // https://github.com/bportaluri/WiFiEsp */

#include "WiFiEsp.h"  // https://github.com/bportaluri/WiFiEsp

#define ESPSEPRIAL Serial2
const byte hardRestPIN = 7; // la pin de l'arduino connectée au reset du module

char ssid[]       = "*****"; // Nom du réseau (SSID). Mériterait d'être const mais warning à la compilation car librairie mal pensée sur ce point
char modDePasse[] = "*****"; // mot de passe du réseau. (pourrait être const char *)
int status = WL_IDLE_STATUS; // l'état de la radio

const uint16_t HTTPPort = 80;
WiFiEspServer server(HTTPPort);   // serveur sur le port 80

const byte maxHTTPLine = 100;
char httpLine[maxHTTPLine + 1]; // +1 pour avoir la place du '\0'

const byte maxURL = 20;
char urlRequest[maxURL + 1]; // +1 pour avoir la place du '\0'


// **************************************************
// LA GESTION DU WEB
// **************************************************


void envoyerPageWeb(WiFiEspClient &client, const char * urlRequest)
{
  // On envoie un en tête de réponse HTTP standard
  client.print(
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Connection: close\r\n" // la connexion sera close par le navigateur à la fin de la réponse
    "\r\n");                // une ligne vide marque la fin du header HTTP
  client.print(F("<!DOCTYPE HTML>\r\n"));
  client.print(F("<html><head>\r\n"));
  client.print(F("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n"));
  client.print(F("<title>AQUABOUN</title>\r\n"));

  if (!strcmp(urlRequest, "/")) {   // on vérifie quelle page est demandée
    // On envoie la page web
    static int reqCount = 0;
    client.print(F("<style type=\"text/css\">\r\n"));
    client.print(F("body {background-color: #00979c}\r\n")); // couleur arduino
    client.print(F("</style></head>\r\n"));
    client.print(F("<body>\r\n"));
    client.print(F("<h1>Salut djbouns !</h1>\r\n"));
    client.print(F("Nb de demandes ="));
    client.print(++reqCount);
    client.print(F("<br>\r\n"));
    client.print(F("Valeur lue sur A0: "));
    client.print(analogRead(0));
    client.print(F("<br>\r\n"));
    client.print(F("</body>"));
  } else if (!strcmp(urlRequest, "/admin")) {  // on vérifie quelle page est demandée
    // On envoie la page web d'admin
    client.print(F("<title>ADMIN</title>\r\n"));
    client.print(F("<style type=\"text/css\">\r\n"));
    client.print(F("body {background-color: #89C8F3}\r\n")); // bleu clair
    client.print(F("</style></head>\r\n"));
    client.print(F("<body>\r\n"));
    client.print(F("<h1>Salut djbouns !</h1>\r\n"));
    client.print(F("Page d'administration<br>\r\n"));
    client.print(F("</body>"));
  } else {
    // On envoie la page web d'erreyr
    client.print(F("<title>ADMIN</title>\r\n"));
    client.print(F("<style type=\"text/css\">\r\n"));
    client.print(F("body {background-color: #FF0000}\r\n")); // rouge
    client.print(F("</style></head>\r\n"));
    client.print(F("<body>\r\n"));
    client.print(F("<h1>ERREUR</h1>\r\n"));
    client.print(F("</body>"));
  }

  client.print(F("</html>\r\n"));

  // un peu d'attente pour que le module ESP ait fini de tout envoyer
  delay(10);
}

// **************************************************

void printHTTPServerInfo()
{
  IPAddress ip = WiFi.localIP();
  Serial.print(F("Site web http://")); Serial.print(ip);
  if (HTTPPort != 80) {
    Serial.print(F(":"));
    Serial.print(HTTPPort);
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);     // pour le debug

  //reset du esp-01
  pinMode(hardRestPIN, OUTPUT);
  digitalWrite(hardRestPIN, LOW);
  delay(100);
  digitalWrite(hardRestPIN, HIGH);
  delay(1000); // on attend le reboot

  ESPSEPRIAL.begin(115200);    // l'ESP-01 a été pré-configuré à 115200 bauds
  WiFi.init(&ESPSEPRIAL);      // initialisation de la librairie et du module ESP

  // on vérifie l'état
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println(F("Composant wifi ne répond pas"));
    while (true); // on meurt ici
  }

  // on essaye de se connecter au réseau
  while ( status != WL_CONNECTED) {
    Serial.print(F("."));
    status = WiFi.begin(ssid, modDePasse);
  }
  Serial.println();
  printHTTPServerInfo();

  // démarre le serveur web sur le port HTTPPort
  server.begin();
}



void loop() {
  WiFiEspClient client;
  boolean currentLineIsBlank = true;
  byte indexMessage = 0;
  char * ptrGET, *ptrEspace;

  // on attend de recevoir une connexion
  if (client = server.available()) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        switch (c) {
          case '\r': // on l'ignore
            break;

          case '\n':
            httpLine[indexMessage] = '\0'; // on termine la ligne correctement (c-string)
            indexMessage = 0; // on se reprépre pour la prochaine ligne
            currentLineIsBlank = true;
            if (ptrGET = strstr(httpLine, "GET")) {
              // c'est la requête GET, la ligne continent "GET /URL HTTP/1.1", on extrait l'URL
              ptrEspace = strstr(ptrGET + 4, " ");
              *ptrEspace = '\0';
              strncpy(urlRequest, ptrGET + 4, maxURL);
              urlRequest[maxURL] = '\0'; // par précaution si URL trop longue
            }
            break;

          default:
            currentLineIsBlank = false;
            if (indexMessage <= maxHTTPLine - 1) {
              httpLine[indexMessage++] =  c; // sinon on ignore le reste de la ligne
            }
            break;
        }

        if (c == '\n' && currentLineIsBlank) { // une requête HTTP se termine par une ligne vide
          envoyerPageWeb(client, urlRequest);
          break;
        }
      }
    }
    client.stop(); // termine la connexion
  }
}
Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 03:34 pm
voila
Code: [Select]
#include "WiFiEsp.h"

WiFiEspServer server(80);

char ssid[] = "***";            // your network SSID (name)
char pass[] = "***";       // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status




void setup() {
  Serial.begin(115200);
Serial2.begin(115200);
WiFi.init(&Serial2);
  if (WiFi.status() == WL_NO_SHIELD) {
    while (true);
  }
  while ( status != WL_CONNECTED) {
    status = WiFi.begin(ssid, pass);
  }
  server.begin();

}

void loop() {
WiFiEspClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n' && currentLineIsBlank) {





client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println("<title>AQUABOUN'S</title>");
client.println("<style>body{background-color: LightBlue ;color: MediumBlue ;font-family: Comic Sans MS;font-size: 35px;}");
client.println("h1{color: MediumBlue ;text-align: center;font-family: Comic Sans MS;font-size: 100px; text-shadow: 5px 4px DodgerBlue ;border: 2px solid red;}");
client.println("h2{color: MediumBlue ;text-align: center;font-family: Comic Sans MS;font-size: 60px; text-shadow: 3px 2px DodgerBlue ;}");
client.println(".button {display: inline-block;padding: 5px 40px;font-size: 25px;cursor: pointer;text-align: center;background-color:mediumBlue;color: white;border-radius:20px;}");
client.println(".button:active {background-color: Blue;}");
client.println(".button2 {background-color:FireBrick;display: inline-block;padding: 5px 40px;font-size: 25px;cursor: pointer;text-align: center;color: white;border-radius:20px;}");
client.println(".button2:active {background-color:red;}");
client.println("</style>");
client.println("</head>");
client.println("<body>");
client.println("<h1>AQUABOUN'S</h1>");
client.println("<br />");
client.println( "<FONT size= 35px>");
client.println( "<text-align: left>");
client.println("<p>Heure : ");
client.println( "<FONT color= red>");

client.println( "<FONT color= MediumBlue >");
client.println( "H");
client.println( "<FONT color= red>");
client.println( "0");
client.println( "<FONT color= MediumBlue >");
client.println( " ");
client.println( "<FONT size= 3px>");
client.println( "<FONT color= red>");

client.println( "<FONT color= MediumBlue >");
client.println( "s");
client.println("<br />");
client.println( "<FONT size= 35px>");
client.println("<p>Temperature aquarium : ");
client.println( "<FONT color= red>");

client.println("&deg");
client.println("<br />");
client.println( "<FONT color= MediumBlue >");
client.println("<p>Temperature rampe : ");
client.println( "<FONT color= red>");

client.println("&deg");
client.println("<br />");
client.println( "<FONT color= MediumBlue >");
client.println("<p>PH: ");
client.println( "<FONT color= red>");
client.println( "sonde ph non instalee");
client.println("<br />");
client.println("<br />");
client.println("<FONT color= MediumBlue >");
client.println("<p>puissance blanc : ");
client.println("<FONT color= red>");

client.println("%  ");
client.println("<br />");
client.println("<button class=button>-</button>");
client.println("<button class=button>+</button>");
client.println("<button class=button2>Valider</button></p>");
client.println("<FONT color= MediumBlue >");
client.println("<p>puissance bleu : ");
client.println("<FONT color= red>");

client.println("%  ");
client.println("<br />");
client.println("<button class=button>-</button>");
client.println("<button class=button>+</button>");
client.println("<button class=button2>Valider</button></p>");




         break;
        }
        if (c == '\n') {
      
         currentLineIsBlank = true;
        }
        else if (c != '\r') {
    
          currentLineIsBlank = false;
        }
   }
}

    delay(10);


    client.stop();
    }
  }

  


Chez moi 24 seconde par avoir la page afficher entièrement
Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 03:37 pm
Code: [Select]
/* exemple d'utilisation de la librairie "WiFiEsp.h"  // https://github.com/bportaluri/WiFiEsp */

#include "WiFiEsp.h"  // https://github.com/bportaluri/WiFiEsp

#define ESPSEPRIAL Serial2
const byte hardRestPIN = 7; // la pin de l'arduino connectée au reset du module

char ssid[]       = "ddd";   // Nom du réseau (SSID)
char modDePasse[] = "ddd";        // mot de passe du réseau
int status = WL_IDLE_STATUS;              // l'état de la radio

const uint16_t HTTPPort = 80;
WiFiEspServer server(HTTPPort);   // serveur sur le port 80

const byte maxHTTPLine = 100;
char httpLine[maxHTTPLine + 1]; // +1 pour avoir la place du '\0'

const byte maxURL = 20;
char urlRequest[maxURL + 1]; // +1 pour avoir la place du '\0'


// **************************************************
// LA GESTION DU WEB
// **************************************************


void envoyerPageWeb(WiFiEspClient &client, const char * urlRequestL)
{
  // On envoie un en tête de réponse HTTP standard
  client.print(
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Connection: close\r\n" // la connexion sera close par le navigateur à la fin de la réponse
    "\r\n");                // une ligne vide marque la fin du header HTTP
  client.print(F("<!DOCTYPE HTML>\r\n"));
  client.print(F("<html><head>\r\n"));
  client.print(F("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n"));
  client.print(F("<title>AQUABOUN</title>\r\n"));

  if (!strcmp(urlRequest, "/")) {   // on vérifie quelle page est demandée
    // On envoie la page web
    static int reqCount = 0;
    client.print(F("<style type=\"text/css\">\r\n"));
    client.print(F("body {background-color: #00979c}\r\n")); // couleur arduino
    client.print(F("</style></head>\r\n"));
    client.print(F("<body>\r\n"));
    client.print(F("<h1>Salut djbouns !</h1>\r\n"));
    client.print(F("Nb de demandes ="));
    client.print(++reqCount);
    client.print(F("<br>\r\n"));
    client.print(F("Valeur lue sur A0: "));
    client.print(analogRead(0));
    client.print(F("<br>\r\n"));
    client.print(F("</body>"));
  } else if (!strcmp(urlRequest, "/admin")) {  // on vérifie quelle page est demandée
    // On envoie la page web d'admin
    client.print(F("<title>ADMIN</title>\r\n"));
    client.print(F("<style type=\"text/css\">\r\n"));
    client.print(F("body {background-color: #89C8F3}\r\n")); // bleu clair
    client.print(F("</style></head>\r\n"));
    client.print(F("<body>\r\n"));
    client.print(F("<h1>Salut djbouns !</h1>\r\n"));
    client.print(F("Page d'administration<br>\r\n"));
    client.print(F("</body>"));
  } else {
    // On envoie la page web d'erreyr
    client.print(F("<title>ADMIN</title>\r\n"));
    client.print(F("<style type=\"text/css\">\r\n"));
    client.print(F("body {background-color: #FF0000}\r\n")); // rouge
    client.print(F("</style></head>\r\n"));
    client.print(F("<body>\r\n"));
    client.print(F("<h1>ERREUR</h1>\r\n"));
    client.print(F("</body>"));
  }

  client.print(F("</html>\r\n"));

  // un peu d'attente pour que le module ESP ait fini de tout envoyer
  delay(10);
}

// **************************************************

void printHTTPServerInfo()
{
  IPAddress ip = WiFi.localIP();
  Serial.print(F("Site web http://")); Serial.print(ip);
  if (HTTPPort != 80) {
    Serial.print(F(":"));
    Serial.print(HTTPPort);
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);     // pour le debug

  //reset du esp-01
  pinMode(hardRestPIN, OUTPUT);
  digitalWrite(hardRestPIN, LOW);
  delay(100);
  digitalWrite(hardRestPIN, HIGH);
  delay(1000); // on attend le reboot

  ESPSEPRIAL.begin(115200);    // l'ESP-01 a été pré-configuré à 115200 bauds
  WiFi.init(&ESPSEPRIAL);      // initialisation de la librairie et du module ESP

  // on vérifie l'état
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println(F("Composant wifi ne répond pas"));
    while (true); // on meurt ici
  }

  // on essaye de se connecter au réseau
  while ( status != WL_CONNECTED) {
    Serial.print(F("."));
    status = WiFi.begin(ssid, modDePasse);
  }
  Serial.println();
  printHTTPServerInfo();

  // démarre le serveur web sur le port HTTPPort
  server.begin();
}



void loop() {
  WiFiEspClient client;
  boolean currentLineIsBlank = true;
  byte indexMessage = 0;
  char * ptrGET, *ptrEspace;

  // on attend de recevoir une connexion
  if (client = server.available()) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        switch (c) {
          case '\r': // on l'ignore
            break;

          case '\n':
            httpLine[indexMessage] = '\0'; // on termine la ligne correctement (c-string)
            indexMessage = 0; // on se reprépre pour la prochaine ligne
            currentLineIsBlank = true;
            if (ptrGET = strstr(httpLine, "GET")) {
              // c'est la requête GET, la ligne continent "GET /URL HTTP/1.1", on extrait l'URL
              ptrEspace = strstr(ptrGET + 4, " ");
              *ptrEspace = '\0';
              strncpy(urlRequest, ptrGET + 4, maxURL);
              urlRequest[maxURL] = '\0'; // par précaution si URL trop longue
            }
            break;

          default:
            currentLineIsBlank = false;
            if (indexMessage <= maxHTTPLine - 1) {
              httpLine[indexMessage++] =  c; // sinon on ignore le reste de la ligne
            }
            break;
        }

        if (c == '\n' && currentLineIsBlank) { // une requête HTTP se termine par une ligne vide
          envoyerPageWeb(client, urlRequest);
          break;
        }
      }
    }
    client.stop(); // termine la connexion
  }
}

P**** c'est génial ça !!!
Title: Re: aquaboun's
Post by: J-M-L on Oct 08, 2017, 03:39 pm
Vous avez peut-être un soucis WiFi...

Chez moi ça prend environ 1 seconde

et il faudrait - pour ne pas tuer la mémoire vive - changer tous les

client.println("xxxxx");

en

client.println(F("xxxxx"));

histoire de stocker les chaînes en mémoire flash directement et passer le pointeur sur cette mémoire plutôt que de les emmener en mémoire vive
Title: Re: aquaboun's
Post by: J-M-L on Oct 08, 2017, 03:43 pm
P**** c'est génial ça !!!
est-ce que ça répond plus vite ?


et sinon bravo pour tout votre "bricolage" - y'a des heures de boulot !
Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 03:49 pm
est-ce que ça répond plus vite ?


et sinon bravo pour tout votre "bricolage" - y'a des heures de boulot !
Mon exclamation était sur le fait d'avoir 2 page possible, donc une pour le paramétrage qui seras, en quelque sorte, caché.

Et oui ... des heures ... ou plutôt des jour ... quoi qu'on doit être a des semaine maintenant lol car certaine nuit son très courte quand on est dans le codage ... lol

Merci a vous
Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 03:50 pm
Vous avez peut-être un soucis WiFi...

Chez moi ça prend environ 1 seconde

a ... un problème de plus a résoudre alors :(

j'ai mis ma page html dans votre code et ca me fait pareil ... affichage mot par mot
Title: Re: aquaboun's
Post by: J-M-L on Oct 08, 2017, 03:51 pm
vous utilisez quel navigateur?

oui j'imagine effectivement que c'est bcp de temps !!
Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 04:04 pm
google chrome ...
et ...
bon pronostique puisque c'est quasi instantanée dans IE ... !
Title: Re: aquaboun's
Post by: J-M-L on Oct 08, 2017, 04:21 pm
en fait je pense que Chrome va balancer des requêtes supplémentaires pour d'autres choses et que vous retournez votre page plusieurs fois... en générant des erreurs au passage sur requête multiples vers votre ESP



Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 05:24 pm
J'ai testé avec mon téléphone avec l'adresse IP a distance et ça marche, sa s'affiche un peu moins vite que d'autre page internet mais c'est minime.
Je vais donc poursuivre cette voix.
J'ai l'impression que c'est un grand pas en avant
je vous tient au courant

Title: Re: aquaboun's
Post by: djbouns on Oct 08, 2017, 10:29 pm
voila :)

J'suis content.
petite question,je n'ai pas de PIN pour le hardRestPIN = 7
Je peut envoyer un at+rst a la place ?

Je doit a présent affecté les bouton a une fonction et sauvegarder ... connaissez vous un tuto bien fait a lire ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 09, 2017, 09:05 am
Le AT+RST est envoyé sans doute à l'initialisation, donc pas la peine à mon avis (à vérifier dans le code source). le reset hardware est physique, ça veut dire que si pour une raison quelconque l'interpretteur De commandes AT ne répond pas ça force un vrai reset matériel

Pourquoi pas de pin reset? vous n'en n'avez plus de dispo?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 09, 2017, 09:28 am
Pour les pin dispo j'attend de recevoir mon dernier CI pour vérifier que les 7pin mentionné plus haut, normalement pris par l'écran son dispo.
sinon, non plus de dispo :/

Pour le reset physique ... j'utilise un adaptateur
https://www.banggood.com/fr/ESP8266-Serial-Wi-Fi-Wireless-ESP-01-Adapter-Module-3_3V-5V-Compatible-For-Arduino-p-1047322.html?currency=EUR&createTmp=1&cur_warehouse=CN&utm_source=googleshopping&utm_medium=cpc_elc&utm_content=zouzou&utm_campaign=pla-fr-dp-pc-esp8266&gclid=Cj0KCQjwvOzOBRDGARIsAICjxocU1pYs2MQt0wWKD_YvmnoJLf-TenFfjPvpPwyeZG_8_Djn__ABLoMaAqhtEALw_wcB (https://www.banggood.com/fr/ESP8266-Serial-Wi-Fi-Wireless-ESP-01-Adapter-Module-3_3V-5V-Compatible-For-Arduino-p-1047322.html?currency=EUR&createTmp=1&cur_warehouse=CN&utm_source=googleshopping&utm_medium=cpc_elc&utm_content=zouzou&utm_campaign=pla-fr-dp-pc-esp8266&gclid=Cj0KCQjwvOzOBRDGARIsAICjxocU1pYs2MQt0wWKD_YvmnoJLf-TenFfjPvpPwyeZG_8_Djn__ABLoMaAqhtEALw_wcB)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 09, 2017, 09:49 am
Ah c'est un adaptateur qui n'expose pas toutes les pins... il en existe d'autres qui sont plus complets

 
(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=229108)


(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=229106)


mais vous pouvez toujours attaquer directement la pin RST du ESP-01 (avec un pont diviseur de tension pour passer en 3.3V)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 09, 2017, 10:27 am
Je vais faire plus simple, je vais souder le pin reset dans l'autre sens pour qu'il ne soit pas sur l'adaptateur :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 09, 2017, 11:28 pm
pin rst Ok,
Bon je lit des poste sur le net mais affecter les boutons a des fonction (et je ne parle pas de la sauvegarde) a l'air hard core et ça m'inquiète beaucoup ... surtout que je ne trouve rien de tres bien expliquer, enfin, surtout compréhensible pour moi :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 10, 2017, 01:55 am
bon 4h a lire tout se que je trouve en cherchant "arduino html bouton" et rien de concluant.
La plus par des exemple trouvé me font par exemple "http://192.*****/mavariable=1" et donc page d'erreur.

Je doit a présent affecté les bouton a une fonction et sauvegarder ... connaissez vous un tuto bien fait a lire ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 10, 2017, 05:53 am
Si vous regardez mon tuto sur le shield ethernet (http://forum.arduino.cc/index.php?topic=460333.0) vous verrez comment je propose une approche relativement simple pour cela et le code HTML de base pour un bouton.

L'idée c'est que la page principale soit générée par http://adresse.ip et les boutons dans le code html sont définis et appellent le site principal mais avec une url différente
http://adresse.ip/param<ici des paramètres>

Vous avez vu ci dessus que l'on est capable de savoir quelle resource est demandée (/ pour la page principale, /admin pour la page d'admin) et là il faut soit que chaque bouton ait son url, soit aller un cran plus loin et passer des paramètres  que votre fonction va analyser pour déterminer quoi faire

Vous verrez que cette approche simple a été reprise  dans cet exemple (http://forum.arduino.cc/index.php?topic=493039.msg3363944#msg3363944) (serveur interactif de relais qui peut supporter jusqu ' a 2000 relais commandé par internet) qui au final n'est pas loin de ce que vous faites

Après on peut faire plus compliqué avec de l'ajax, des requêtes de type POST etc, mais je pense que ça va dépasser vos compétences et besoins
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 10, 2017, 08:59 am
Merci, je lit et essai de comprendre et d'adapter et je revient ... dans une semaine :) :) :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 10, 2017, 11:01 pm
alors, le code avec les relais ne me correspond pas trop puisque il ne fait que duplique une même fonction ON/OFF selon une suite de déterminé de boutonx=PINx ect...
j'ai compris le principe du bouton qui complète l'url.
Le code du tuto correspondrait a mes besoin puisque il ajoute ou diminue des valeurs mais j'ai un problème de compréhension même si j'ai compris le principe.

J'ai don testé la chose , simpliste, suivante :
Sur ma page principale :
client.print(F("<button onclick=\"location.href='/V=1'\" type='button'>sfgqrg</button>"));
puis
else if (!strcmp(urlRequest, "/V=1")) {
test = test +1;
}
Le positif est que ma variable test est bien modifié a +1
Le problème c'est le retour aussi tôt a la page principal ...
J'ai tenté un return lol sa aurais été trop simple :)

Je continu ma croisade ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 10, 2017, 11:08 pm
Il faut régénérer la page totale
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 10, 2017, 11:10 pm
Il faut régénérer la page totale
on est bien d'accord
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 10, 2017, 11:15 pm
j'ai tenté urlRequest == "/";
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 10, 2017, 11:32 pm
avec ce que j'ai vu sur le net,
client.print("location.href='/'");
devrait marché :(
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 11, 2017, 12:14 am
J'ai trouvé ca qui marche, que je trouve assez simple mais il faut attendre plusieurs seconde entre chaque click sinon sa marche pas :(
une idée pourquoi si long ?

client.println("<button onClick=location.href='./?LED=ON'>ON</button>");

et dans le loop

cadena.concat(c);  

int posicion=cadena.indexOf("LED=");        
          if(cadena.substring(posicion)=="LED=ON")    
         {
test = test +1;                          
         }


Que me conseille tu ? cette méthode est bonne et peut être adapter a tout mes nombreux bouton ou faut il que je creuse sur ton code, il ne me manque que le retour a la page après le clic ... et vu ton niveau, je pencherais pour ton code :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 11, 2017, 10:32 am
la librairie n'est pas top pour plusieurs requêtes trop rapide en provenance du même navigateur et l'ESP-01 a ses propres contraintes aussi de ce côté là - un shield ethernet ou une carte wifi de plus haut niveau est bien utile si vous voulez plus de robustesse .

Sinon vous retombez dans l'usage de la classe String... pas bon...

avec
Code: [Select]
client.println("<button onClick=location.href='./?LED=ON'>ON</button>");

l'URL va être capturée par mon code du post #6 quand la loop appelle la fonction:
envoyerPageWeb(WiFiEspClient &client, const char * urlRequest)

la variable urlRequest vaudra alors "/?LED=ON" vous pouvez regardez dans mon autre tuto comment on analyse proprement cette requête si vous voulez de la dynamité (LED qui peut être autre chose et ON aussi) ou si vous avez peu de boutons faire comme dans mon code ci dessus en comparant la requête reçue avec "/" ou "/admin" --> tester avec "/?LED=ON"

si vous retournez toujours la même page web après modif éventuellement de certains param lors de la requête  il suffit de modifier un peu la fonction pour d'abord tester l'URL et faire les modifs puis ensuite balancer la page

Code: [Select]
void envoyerPageWeb(WiFiEspClient &client, const char * urlRequest)
{
  static int reqCount = 0;

  // ************* ICI TESTER L'URL RECUE POUR DECIDER QUOI FAIRE *************
  if (!strcmp(urlRequest, "/")) {  // page de base
     reqCount = 0; // par exemple une requête sur la home page remet à 0 le compteur du serveur
  } else if (!strcmp(urlRequest, "/?LED=ON")) {  // requête d'un bouton
     reqCount++; // par exemple on modifie une variable utilisée plus tard dans la page
  } else if (!strcmp(urlRequest, "/?LED=OFF")) {  // requête d'un bouton
     reqCount--;  // par exemple on modifie une variable utilisée plus tard dans la page
  }

  // **********************************************************************

  // puis on génère la page qui va bien
  // On envoie un en tête de réponse HTTP standard  client.print(
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Connection: close\r\n" // la connexion sera close par le navigateur à la fin de la réponse
    "\r\n");                // une ligne vide marque la fin du header HTTP
  client.print(F("<!DOCTYPE HTML>\r\n"));
  client.print(F("<html><head>\r\n"));
  client.print(F("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n"));
  client.print(F("<title>AQUABOUN</title>\r\n"));

    // On envoie la page web
  client.print(F("<style type=\"text/css\">\r\n"));
  client.print(F("body {background-color: #00979c}\r\n")); // couleur arduino
  client.print(F("</style></head>\r\n"));
  client.print(F("<body>\r\n"));
  client.print(F("<h1>Salut djbouns !</h1>\r\n"));
  client.print(F("Nb de demandes ="));
  client.print(reqCount);
  client.print(F("<br>\r\n"));
  client.print(F("Valeur lue sur A0: "));
  client.print(analogRead(0));
  client.print(F("<br>\r\n"));
  client.print(F("</body>"));
  client.print(F("</html>\r\n"));

  // un peu d'attente pour que le module ESP ait fini de tout envoyer
  delay(10);
}


pour tester même s'il n'y a pas de boutons dans la page générée, vous pouvez taper directement dans la barre d'adresse du navigateur  http://<ip>/?LED=ON ou http://<ip>/?LED=OFF et vous allez voir la variable s'incrémenter ou se décrémenter

OK ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: MicroQuettas on Oct 11, 2017, 03:47 pm
Bonjour à toutes et à tous,

Ayant un peu galéré sur le sujet avant d'arriver à quelque chose de cohérent et qui marche, je me permets d'intervenir sur la façon de faire générer une requête à un navigateur...

Regardons cela sur un exemple, une page et la requête que le navigateur génère quand on clique sur un bouton après avoir rempli les champs de saisie. Le code complet de la page est en PJ.

La requête est une GET, la plus employée, qui ressemble à cela, aux variations de navigateur près:

Code: [Select]

GET /BTS10.htm?T80=admin&T81=pass&N01=01 HTTP/1.1
Host: 192.168.1.236
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.236/BTS10.htm?T80=&T81=&N01=01
Connection: keep-alive
Upgrade-Insecure-Requests: 1


Cette requête demande une ressource (URI) dont l'identification complète est :
192.168.1.236/BTS10.htm?T80=admin&T81=pass&N01=01
Il y a 3 parties:


Comment mettre ce qu'il faut dans une page html pour que le navigateur génère une requête bien propre ?

Regardons cela sur l'exemple :

Le site : sauf si on veut en changer, il n'y a rien à mettre. Par défaut, le navigateur reste sur le site où il est,

La page : elle se précise dans la balise ouvrante <form action='BTS10.htm'> qui ouvre un formulaire. S'il n'y en a qu'une appelez la "index.htm" comme tout le monde,

Les infos passées à la page sont générées par chacune des commandes sur le formulaire : boutons, entrées, sélecteurs, etc. Cette partie peut être vide, par ex. pour la requête initiale sur un serveur,
Ici, deux boîtes de texte et un bouton.
Pour chaque commande, le même format au retour: "name=value"

Voyons comment décrire cela en html pour la première boîte de texte :
<input name='T80' type='text' size='30'  maxlength='20' style='font-size: 12pt'>

Un champ "name", mais pas de "value", car le champ s'affiche vide avant la saisie. Si j'avais voulu mettre une valeur par défaut, j'aurais ajouté : value='defaut', écrit ici sans l'accent.
Il s'agit d'une saisie de texte type='text' et le reste sont des formatages.

A l'exécution, j'ai tapé "admin" que l'on retrouve au retour dans le champ "T80=admin".

La boîte de texte T2 est identique, sauf qu'il s'agit d'un mot de passe :
<input name='T81' type='password' size='30'  maxlength='20' style='font-size: 12pt'>
Ayant saisi "pass", elle retourne T81=pass.

Maintenant, le bouton :
<button name='N01' type='submit' value ='01'><p class='Bt1'>Valider</p></button>

Les champs importants sont le "name" et la "value" que l'on retrouve au retour dans la requête : "N01=01".

Comment cela marche t'il ?

Rien de plus simple : lorsqu'on clique un bouton, le navigateur collecte toutes les "values" des boîtes d'entrée et termine par celle du bouton cliqué (il ne peut y en avoir qu'un).
Il met le tout à la file, les entrées étant séparées par "&" et l'on obtient :
"T80=admin&T81=pass&N01=01" placé, dans une requête GET, après la page séparé par un "?", sur la première ligne, après le GET et un blanc, soit :
/BTS10.htm?T80=admin&T81=pass&N01=01

Le "/" indique le page demandée est sur la racine du site.

Le traitement de la requête reçue comprend deux étapes :


Il y a plein de bibliothèques et de routines (dont celles de J-M-L) qui font cela, mais il faut d'abord avoir le bon code html pour générer une requête correcte.

Dans votre cas, vous utilisez le "onClick=selection.href="...". C'est du Javascript. Ca a marché dans votre exemple, mais cela n'est pas fait pour cela. Réservez le pour changer de site, pas pour passer des infos à votre serveur.

Voila, j'espère que cela va vous aider. Le fichier joint est le code html de la page exemple. Vous pouvez l'ouvrir avec votre navigateur. En cliquant sur un bouton, le navigateur générera une erreur, mais il affichera la page et le "tail"  de sa requête (en tout cas Firefox le fait).

Je vous invite à bidouiller le code de la page, en regardant en direct sur votre navigateur ce qu'il fait. C'est super pour mettre au point une page.

Pour le détail du html, format, commandes, accents, couleurs, etc, un site un peu ancien mais très complet, avec plein d'exemples, même si la navigation y est un peu touffue:
http://www.info.univ-angers.fr/~gh/selfhtml_fr/ (http://www.info.univ-angers.fr/~gh/selfhtml_fr/)

Bon courage, ce n'est pas simple au début, mais une fois que l'on a quelque chose qui marche, cela fait plaisir. On perfectionne ensuite au fur et à mesure.

Enfin, il y a de multiples façons de faire, à chacun la sienne...

A+

MicroQuettas


(*) Les puristes auraient utilisé une requête POST pour ce cas. Ils ont raison, mais c'est pour un exemple de la requête GET.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 12, 2017, 12:18 am
l'ESP-01 a ses propres contraintes aussi de ce côté là
une carte wifi de plus haut niveau est bien utile si vous voulez plus de robustesse .
Plusieurs fois ou vous aborder ce sujet/problème.
Que me conseiller vous ? (il doivent etre utiliser via tx/rx)

esp12 (http://www.ebay.fr/itm/ESP8266-ESP12-NodeMcu-Lua-WeMos-D1-Sans-Fil-WiFi-Kit-Developpement-Carte-TE441-/152657664713?hash=item238b1b1ac9:g:X9oAAOSwzhRZjAeD) ?

esp32 (http://www.ebay.fr/itm/ESP32-Genuine-WeMos-LOLIN32-V1-0-0-compatible-with-Arduino-NodeMCU-MicroPython-/272710828821?hash=item3f7ed50315:g:EfgAAOSwPWRZO6fy) ?

Je ne vais pas rester bloquer sur ce projet a cause d'un composant ... j'ai déjà assez avec le code ... :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 12, 2017, 12:33 am
OK ?
J'ai bien compris le principe dont cela doit fonctionner mais je doit continuer a travailler un code a partir de : envoyerPageWeb(WiFiEspClient &client, const char * urlRequest)
ou pas.
Il semblerais que ce ne soit pas adapter a mon utilisation au dire de MicroQuettas.

Pourtant, cela fonctionne mise a par se problème de vitesse avec le bouton qui n'est pas pris en compte.
Sinon, pour contrer cela, il est peut être possible de faire un champs pour saisir directement la valeur voulu et valider, se qui ne ferait qu'une demande ... ??? qu'en penser vous ?


J'arrive vraiment a un problème de compréhension a ce niveau  a cause d'une chose assez simple.
Jusque a présent, mis a par les thermes d'écriture qui m'était inconnu, la saisie des ligne de commande avait une logique et un sens.
Ce qui me bloque dans les exemple ect ... c'est ce genre de chose :
httpLine[indexMessage++] =  c;
(c == '\n' && currentLineIsBlank)
char * ptrGET, *ptrEspace;
Qui n'ons ni queue ni tète pour moi et ce n'est pas faute de lire et relire, de faire des recherche avec l'IDE avec la fonction trouvée pour essayer de comprendre a quoi se rapporte chaque élément.
Je passe ~3h le matin et ~4h la nuit depuis plusieurs jour a vous lire et lire des dizaines de post sur le net.
Ma motivation est vraiment importante mais j'arrive a un point ou je me demande si le poisson n'est pas trop gros et je suis conscient du temps que vous prenez.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 12, 2017, 12:36 am
Bon courage, ce n'est pas simple au début, mais une fois que l'on a quelque chose qui marche, cela fait plaisir. On perfectionne ensuite au fur et à mesure.


Bonjour MicroQuettas

Merci pour ton explication détaillé.
Je vais prendre le temps de tester cette page afin de comprendre les conséquence de chaque Click.



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 12, 2017, 10:26 am
Pour comprendre cette ligne httpLine[indexMessage++] =  c; il faut la décomposer

httpLine est un tableau de caractères d'une certaine taille dans lequel on va ranger les uns après les autres les caractères que l'on reçoit sur la ligne Série.  dans notre cas la variable c. Pour les mettre les uns après les autres il nous faut une variable qui va parcourir le tableau et se souvenir de l'endroit où l'on doit ranger le prochain caractère. J'utilise la variable indexMessage pour cela.

donc pour mettre c dans le tableau à la position indexMessage, on écrirait simplement

httpLine[indexMessage] =  c;
ensuite il faut se souvenir qu'on a rempli cette case et donc passer à la case d'après. Donc après avoir stocké c au bon endroit on devrait faire un un truc du genre indexMessage = indexMessage + 1;

il existe dans le langage C une instruction ++ qui incrémente (ajoute 1 unité) directement une variable.

donc au lieu de faire indexMessage = indexMessage + 1;, je pourrais écrire indexMessage++; et mon code serait

httpLine[indexMessage] =  c;
indexMessage++;

Il faut savoir que l'on peut mettre le ++ avant ou après le nom de la variable et ça ne fait pas tout à fait la même chose:

a = 3;
b = a++; // ici on met a dans b et ensuite on augmente a de 1, donc b vaut 3 et a vaut 4 après exécution
b = ++a; // ici on augmente a de 1 d'abord puis met a dans b ensuite, donc b vaut 4 et a vaut 4 après exécution

En tenant compte de cette information on voit que l'on peut faire donc tout d'un seul coup:

httpLine[indexMessage++] = c;

ça veut dire mettre c dans le tableau httpLine à la position indexMessage, puis ensuite augmenter de 1 indexMessage

OK ?


if (c == '\n' && currentLineIsBlank) ça c'est plutôt simple. l'opérateur && c'est le ET logique (si condition1 est vraie ET condition2 est vraie alors...). Ici on regarde donc si j'ai reçu un retour chariot et que la ligne précédente était vide (une variable que l'on maintient pendant qu'on reçoit les caratères) alors faire quelque chose --> la raison de cela est expliquée dans mon tuto, une requête HTTP se termine par une ligne vide, c'est comme cela que l'on repère la fin de la demande du navigateur.

OK?


char * ptrGET, *ptrEspace; ça déclare simplement 2 pointeurs sur des caractères;
l'objectif du code qui suit est d'extraire du tableau la partie qui concerne l'URL reçue. c'est ce code

Code: [Select]
if (ptrGET = strstr(httpLine, "GET")) {
   // c'est la requête GET, la ligne continent "GET /URL HTTP/1.1", on extrait l'URL
   ptrEspace = strstr(ptrGET + 4, " ");
   *ptrEspace = '\0';
   strncpy(urlRequest, ptrGET + 4, maxURL);
   urlRequest[maxURL] = '\0'; // par précaution si URL trop longue
}



En supposant que la ligne contient bien "GET /ADMIN HTTP/1.1" on veut alors extraire /ADMIN pour s'en souvenir et le passer ensuite à la fonction d'affichage de la page web.

voici ce que fait ce code

(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=229461)



est clair ?


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 12, 2017, 10:42 am
dire oui serait un mensonge.

J'ai compris le principe de ce qui est fait/demander mais c'est l'écriture (surtout si il y a des "raccourci") que je ne fait pas correspondre a l'action.

Il faut que j'y arrive, je vais y passer du temps, je revient vers vous si question précise.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: sachab on Oct 12, 2017, 11:58 am
Bonjour

Sujet très intéressant.

Djbouns, j'ai déjà fait ton arduino balling, et il fonctionne impec, jusqu'à présent aucun bug.
Est il possible d'avoir le code du nouveau projet?

Perso je partirai sur un esp32 (26 Digital IO et 12 Analog input pins)

Si tu veux un esp12, j'en ai 1, je peux te l'envoyer, c'est Kdo!


A+

Sacha
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 12, 2017, 10:44 pm
Bonsoir Sachab,

J'ai utilisé mes pompe de dosage pour le balling plusieurs année sans aucun problème, juste de l'usure et de la corrosion sur les partie "moteur" (a 5€ l'unité, rien d'anormal)

J'espère que ce nouveau projet seras aussi stable et efficace.

J'ai commander un esp32. (3€ plus chere qu'un esp12) je pense le recevoir mardi.

Pour le code il est partager ici dans le but de le faire évoluer et aboutir.
Il n'as volontairement pas été mis pour le moment sur recifal france.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Oct 12, 2017, 11:43 pm
Bonjour

Sujet très intéressant.

Djbouns, j'ai déjà fait ton arduino balling, et il fonctionne impec, jusqu'à présent aucun bug.
Merci  :)

Voir la troisième ligne (http://www.recifal-france.fr/post267136.html#p267136) du code.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:13 am
:) et oui  :smiley-wink:  

(https://image.noelshack.com/fichiers/2017/41/5/1507846247-sans-titre.png)

Je ne suis pas du genre a m'approprier le travaille des autres :)

arfff ... déjà 3 ans et demi ... :smiley-eek-blue:


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:23 am
Bon ...

A part me remémorer de vieux souvenir :) 
 ....

J'ai (enfin) réussi a adapter le code de JML (celui des variables pour led) a ma connexion WIFI.
J'ai donc la page qui s'affiche correctement.
Je me lance dans l'expérience pour remplacer la page d'origine par la mienne avec les bouton correspondant.

1er remarque :
Les boutons sont en "location.href=" tout comme le code que j'ai reussi a faire fonctionner, par contre, le click rapide sur le bouton réagi beaucoup mieux que dans mon code (mais c'est pas encore sa) mais de façon aléatoire, les Click rapide finisse par générer une page "la page ne peut s'afficher". a voir si avec l'esp32 cela seras réduit.

2eme remarque :
Ma page étant assez grande, je doit descendre avec ma roulette de souris pour faire défiler les fonctions.
Des que je clik sur un bouton, je re bascule en haut de la page, se qui oblige a redescendre ... ect ...

Si besoin je mettrait le code, en cours de test, il est pas propre la :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 09:22 am
Problème rencontré a l'adaptation avec mon code pour modifier les variables correspondant aux haure de lever et coucher soleil (pwm led)

Je déclarais ces variable en hhmmss exemple 123000 pour 12h30.
il me parraisait compliquer de pouvoir  modifier cette variable du fait quelle ne peut etre traiter en centiemme puisque il s'agit d'heure.

j'ai donc testé la chose suivante
Code: [Select]
long Hlever = 12;
int Mlever = 34;
long LEVER = ((Hlever*10000)+(Mlever*100)); // heure debut levé

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
Serial.print(Hlever);
Serial.print("H");
Serial.println(Mlever);

}

void loop() {
  // put your main code here, to run repeatedly:


long LEVER = ((Hlever*10000)+(Mlever*100));
Serial.println(LEVER);

Mlever = Mlever +10;
delay (2000);
Serial.print(Hlever);
Serial.print("H");
Serial.println(Mlever);
Mlever = Mlever+10;
delay (2000);
Serial.print(Hlever);
Serial.print("H");
Serial.println(Mlever);
Mlever = Mlever+10;
delay (2000);
if (Mlever>=60){
Mlever = Mlever-60;
Hlever = Hlever+1; 
}
Serial.print(Hlever);
Serial.print("H");
Serial.println(Mlever);
LEVER = ((Hlever*10000)+(Mlever*100));
Serial.println(LEVER);
delay (20000);



}


Y avait il une solution plus simple qui ne me faisait pas modifier mon code d'origine ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 09:27 am
je ne comprends pas la question

(généralement on code l'heure sous forme de secondes depuis le début de la journée 3600 x h + 60 x m + s) comme ça on peut ajouter ou soustraire pour calculer des durées plus simplement que dans l'autre représentation )

il me semble que vous avez une horloge RTC dans votre projet, vous pouvez donc aussi utiliser les classes DateTime et TimeSpan de la RTCLib (https://github.com/adafruit/RTClib) pour représenter le temps de manière compatible avec votre RTC
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 09:33 am
Dans mon code d'origine :

long LEVER = 100000; // heure debut levé

Pour :

if ((time >= LEVER) && (time < finLEVER)){


Maintenant que je veut modifier cette variable par le click d'un bouton, si :
variable = 125500  donc 12h50
Que le click d'un bouton ajoute 10 minute, je vais me retrouver a 126500 ...
et vu cette long variable il me paraissait compliquer de mettre un condition pour que si les 4 dernier chiffre égal ou au dessus de 6000 sa passe a 0000 et ajoute 10000.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 09:36 am
vous pouvez donc aussi utiliser les classes DateTime et TimeSpan de la RTCLib (https://github.com/adafruit/RTClib) pour représenter le temps de manière compatible avec votre RTC
a ... connait pas ... je vais tout de suite voir sa
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 09:57 am
si au lieu de coder h*1000 + m*100 + s vous tenez compte réellement des secondes et faites h*3600 + m*60 + s le nombre obtenu est moins "compréhensible" pour les humains mais les maths sont ensuite super simples. ajouter 1h 10 minutes et 22 secondes c'est simplement ajouter 1 * 3600 + 10*60 + 22 par exemple

et les tests du genre
Code: [Select]
if ((time >= LEVER) && (time < finLEVER)){vont continuer à fonctionner. Faut juste vous assurer de coder le temps partout pareil.

- dans l'absolu j'utiliserai des unsigned long, le temps c'est positif
- si vous faites des macros, pensez au signe ul au bout des constantes pour forcer l'évaluation non pas en entier mais en unsigned long

Code: [Select]
unsigned long t = 12*3600 + 35*60 + 10; // 12h35 et 10 secondes (pas bon en entier!!!)va bugger car le calcul numérique est effectué en int soit sur 2 octets signés par le pré-processeur et donc il faut l'écrire
Code: [Select]
unsigned long t = 12*3600ul + 35*60 + 10; // 12h35 et 10 secondes pour forcer le calcul en unsigned long

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 10:14 am
Ok cela va fonctionner pour faire varier le programme mais après impossible(difficile) de pouvoir afficher l'heure modifier puisque elle est devenu un nombre du genre 46530 (12h55 30s)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: kamill on Oct 13, 2017, 10:22 am
Bonjour,

Code: [Select]
heure=t/3600;
minute=(t%3600)/60;
seconde=t%60;
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 10:29 am
Non c'est facile - en calcul entier:

(46530 / 3600) = les heures

(46530 / 60) % 60 = les minutes

(46530 % 60) = les secondes

EDIT: grillé par kamill :)

on n'a pas la même formule pour les minutes. le résultat et le même
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 10:35 am
Arf ... sa marche ...
Vous avez réponse a tout ...
C'est agacent :)   :)   :)
Je commence a comprendre ce que ressente mes alternant BTS que j'ai dans mon équipe au boulo ...  :smiley-razz:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 10:36 am
jmet tout sa en forme ... j'ai pris ma journée, j'espère avoir bien avancer ce soir.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 10:43 am
Arf ... sa marche ...
Vous avez réponse a tout ...
C'est agacent :)   :)   :)
Je commence a comprendre ce que ressente mes alternant BTS que j'ai dans mon équipe au boulo ...  :smiley-razz:
:)  :smiley-mr-green:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:01 am
Donc, pour ne pas avoir a modifier tout mon code d'origine if ((time >= LEVER) && (time < finLEVER)){
(car foncion "time" lit hhmmss) et les fonctions j'ai fait ca :
Code: [Select]
unsigned long LEVERV = 36000; // 10h00 00
unsigned long LEVER;



void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);

}

void loop() {

  // put your main code here, to run repeatedly:

LEVERV = LEVERV +40*60 ; // +40 min

LEVER = ((LEVERV/3600*10000ul)+(((LEVERV%3600)/60)*100ul)+(LEVERV%60));
Serial.print(LEVER);
Serial.println();
delay (5000);
}



Si sa vous paret correct jme lance dans toute la modif sur mon code principal
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:40 am
et une autre petit question,
Il faut que je fixe des condition pour certaine variable (par exemple pompe a 100% pour ne pas passer a 101%)

Cela pose t'il problème si elle sont juste après l'action du bouton ?

Code: [Select]
case 4:
          puissanceblanc += labelValue;
            if (puissanceblanc >100){
            puissanceblanc = 100;
          }
          else if (puissanceblanc <0){
            puissanceblanc = 0;
          }
          break;
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:52 am
Et encore une :)
Certain bouton doivent modifier des variable de 0.1
Visiblement ça ne marche pas.
du au  " long int labelValue;" ?
J'ai tenté de le remplacer par un double mais sans succès non plus
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 11:52 am
préférez l'utilisation de fonctions plutôt que de coder les trucs en dur partout dans le code.

Code: [Select]
unsigned long LEVERV = 36000ul; // 10 h00 00

void printTime(unsigned long t)
{
  unsigned int h, m, s;

  h = t / 3600;
  m = (t / 60) % 60;
  s = t % 60;
  Serial.print(h);
  Serial.print(F(":"));
  if (m < 10)  Serial.print(F("0"));
  Serial.print(m);
  Serial.print(F(":"));
  if (s < 10)  Serial.print(F("0"));
  Serial.println(s);
}


void setup() {
  Serial.begin(115200);
  printTime(LEVERV);
}

void loop() {
  delay (1000);
  LEVERV +=  40 * 60 ; // +40 min
  printTime(LEVERV);
}


attention bien sûr au débordement, rien dans ce code ne vérifie que vous allez au delà de minuit

Quote
Cela pose t'il problème si elle sont juste après l'action du bouton ?
Non, je ne vois pas pourquoi ce serait un soucis
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 11:54 am
Quote
Certain bouton doivent modifier des variable de 0.1
un long c'est un nombre entier, donc ajouter 0.1 ne change rien...

je suppose que ce n'est pas pour le temps? si quelque chose varie de 0.1 en 0.1 alors il faut stocker cela dans un float ou un double (même représentation sur 4 octets sur un MEGA). Ensuite quand vous afficher la valeur il faut vous assurer de ne pas uniquement représenter la valeur entière.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:55 am
JML, j'ai vu que vous utiliser souvent le void
Quelle différence avec un *****.h ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 11:57 am
void ça veut dire que la fonction en renvoie rien.

un .h c'est souvent quelque chose qui contient une collection de variables et définitions de fonctions ou macros que l'on veut incorporer dans son projet pour que le compilateur sache compiler un fichier donné
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:57 am
J'ai justement changer pour un double
du au  " long int labelValue;" ?
J'ai tenté de le remplacer par un double mais sans succès non plus
Mes variable initial sont bien en float.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:58 am
en renvoie rien.

?  :o
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 12:06 pm
ah vous faites référence au code de mon autre tuto, c'est ça ?

de mémoire je crois que le code lit les valeurs passées dans l'URL avec un atoi() qui convertit un texte ASCII en nombre entier. il ne faut donc pas utiliser cette fonction pour lire un nombre flottant mais atof()


Code: [Select]
float x;
const char * valeurTxt = "123.4";

void setup() {
  Serial.begin(115200);
  x = atof(valeurTxt);
  Serial.println(x, 4);
  
  x += 0.1;
  Serial.println(x, 4);

  x += 0.1;
  Serial.println(x, 4);
}

void loop() {}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:08 pm
ah vous faites référence au code de mon autre tuto, c'est ça ?
euh ... ba oui, vous étes un peu ma base de travaille lol

mon maître  :smiley-wink:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 12:09 pm
Quote
Quote from: J-M-L on Today at 11:57 am
en renvoie rien.
?  :o
une fonction en C ou C++ peut retourner une valeur ou rien du tout. quand elle ne retourne rien, on déclare son type de retour comme étant void

void printTime(unsigned long t) {...} --> la fonction printTime ne renvoie aucune valeur

int ajouter(int a, int b) {return a+b;} --> la fonction ajouter renvoie un entier (la somme des 2 param)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:12 pm
A ...
En gros c'est une fonction, qui non utilisé ne génére rien (je exprime mal)
Dans le cas pressent, se void est une opération mathématique. si elle n'est pas appeler a la suite d'un numérique elle ne génèreras aucune valeur.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:13 pm
je vais finir par avoir une image :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:20 pm
ah vous faites référence au code de mon autre tuto, c'est ça ?

de mémoire je crois que le code lit les valeurs passées dans l'URL avec un atoi()
Je n'ai trouvé aucune ligne "atoi"
Donc je ne sait pas ou remplacer par :
Code: [Select]
float x;
const char * valeurTxt = "123.4";

void setup() {
  Serial.begin(115200);
  x = atof(valeurTxt);
  Serial.println(x, 4);
 
  x += 0.1;
  Serial.println(x, 4);

  x += 0.1;
  Serial.println(x, 4);
}

void loop() {}


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 12:24 pm
Je n'ai trouvé aucune ligne "atoi"
Donc je ne sait pas ou remplacer par :
ah, je devais le faire en long avec atol() au lieu de atoi()

labelValue = atol(item);
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:26 pm
ah, je devais le faire en long avec atol() au lieu de atoi()

labelValue = atol(item);
Bingo !

labelValue = atol(item);

Qui est dans un void parseCommand()
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 12:33 pm
A ...
En gros c'est une fonction, qui non utilisé ne génére rien (je exprime mal)
Dans le cas pressent, ce void est une opération mathématique. si elle n'est pas appeler a la suite d'un numérique elle ne génèreras aucune valeur.
vous voyez ce qu'est une fonction ?

void n'est pas un raccourci de langage pour dire une fonction.

void c'est un mot clé du langage de programmation

Il a différents usages:

- Quand il est utilisé comme type retourné par la fonction, ça veut dire que la fonction ne retourne pas de valeur. void maFonction(int x) {...} est une fonction qui ne retourne aucune valeur et qui prend un paramètre de type entier appelé x dans le corps de la fonction. --> par exemple la fonction pinMode(pin, mode) ne retourne rien

- Quand il est utilisé pour la liste des paramètres d'une fonction, void spécifie que la fonction ne prend aucun paramètre (mais peut être ignoré).  unsigned long maFonction(void) {...} est une fonction qui ne retourne un unsigned long et ne prend aucun param  (on l'écrira souvent void maFonction() {...} tout simplement)--> par exemple la fonction millis()

- Quand il est utilisé dans la déclaration d'un pointeur, void spécifie que le pointeur est « universel »,

void * ptr; // ptr est un pointeur générique qui peut pointer vers tout type de données, le compilateur ne fait aucune vérification de cohérence
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:36 pm
oui, je crois, c'est un peu comme un presse a billet qui attend son papier ... pas de papier, pas de resultat ...

 :smiley-money:  :smiley-money:  :smiley-money:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 12:38 pm
oui, je crois, c'est un peu comme un presse a billet qui attend son papier ... pas de papier, pas de resultat ...

 :smiley-money:  :smiley-money:  :smiley-money:
(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)

vous aurez l'image après 10 bons points :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:39 pm
 :smiley-cry:  :smiley-cry:
c'est le premier de toute ma vie  :smiley-cry:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 12:47 pm
YESSS
Le changement des variables avec décimal = OK

Jcroc un bout et jmi remet

Bonne appétit a vous aussi
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: sachab on Oct 13, 2017, 01:36 pm
Bonjour

Désolé Bricoleau pour avoir attribué ton travail à Djouns.

Dans les 2 cas, merci à vous deux pour ce que vous faites.

A+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 03:26 pm
Sa commence a prendre forme.

Je n'arrive pas a modifier les variable correspondant au horraire.
Exemple bonton ci dessous qui doit diminuer la variable de -600 (10min)
Code: [Select]
client.print(F("<button onclick=\"location.href='/LEVER=-600'\" type='button'class=button>-10</button>&nbsp;"));


Avez vous une idee du pourquoi ?

Les autre fonction fonctionne :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 03:52 pm
je vous ai mis un petit mot perso, lisez le.

ça m'étonnerait que tout fonctionne. Voici vos variables que vous recherchez dans l'URL

Code: [Select]
const char * labelsOfInterest[] = {
  "tempbacvent",          "tempbacmax",     "temprampemax",     "consigneph",
  "puissanceblanc",       "puissancebleu",  "puissancejebao1",  "puissancejebao2",
  "puissancejebao3",      "angle1oscillo1", "angle2oscillo1",   "angle1oscillo2",
  "angle2oscillo2",       "angle1oscillo3", "angle2oscillo3",   "delaisnouritureminute",
  "delaistempetteminute", "nourissage1",    "nourissage2",      "LEVER",
  "COUCHER"
};


l'ordre de déclaration est important puisque labelIndex va nous dire lequel a été trouvé

Cependant dans le switch/case vous faites
Code: [Select]

switch (labelIndex) {

....

        case 15: // W
          LEVER += labelValue;
          break;
        case 16: // W
          COUCHER += labelValue;
          break;
      }



Le soucis est là: LEVER et COUCHER ne sont pas à l'entrée 15 et 16 du tableau labelsOfInterest mais en 19 et 20... faut revoir le switch/case il doit y en avoir d'autres de faux




Vous devriez aussi changer le nom des fonction printTime() car elle n'imprime rien mais plutôt calculent les éléments de temps dans des variables globales (pas top).

Ce serait plus cohérent soit de passer client en paramètre de la fonction et l'écrire
Code: [Select]
void printTime(unsigned long t, WiFiEspClient& client)
{
  h = t / 3600;
  m = (t / 60) % 60;
  s = t % 60;

  client.print(h);
  client.print(F(":"));
  if (m < 10)  client.print(F("0"));
  client.print(m);
}
comme cela ça l'imprime vraiment. vous l'appelez en faisant
Code: [Select]
  printTime(LEVER, client);(et vous enlevez bien sûr le code de la partie appelante qui écrit l'heure)

ou alors appelez la fonction updateHMS() par exemple pour dire qu'elle met simplement à jour les variables globales

Code: [Select]
void updateHMS(unsigned long t)
{
  h = t / 3600;
  m = (t / 60) % 60;
  s = t % 60;
}


la première approche est plus propre et vous n'avez pas vraiment besoin d'avoir h,m, s comme variables globales (à moins que ça ne vous serve ailleurs ? )



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 04:35 pm
Le soucis est là: LEVER et COUCHER ne sont pas à l'entrée 15 et 16 du tableau labelsOfInterest mais en 19 et 20... faut revoir le switch/case il doit y en avoir d'autres de faux
Pfff c'est a force d'y trifouillé ... :(
C'est pourtant si simple bref, c'est corrigé.


Ce serait plus cohérent soit de passer client en paramètre de la fonction et l'écrire
C'est la première chose que j'ai voulu faire mais des que j'ai remplacé Serial par client il me disait, client est pas déclaré ...)
Il me manquait le , WiFiEspClient& client)


Pour h m s en variable global, Il le sont dans mon code global, il recuper l'heure du ds1307.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 05:34 pm
Ma page étant assez grande, je doit descendre avec ma roulette de souris pour faire défiler les fonctions.
Des que je clik sur un bouton, je re bascule en haut de la page, se qui oblige a redescendre ... ect ...
Y a t'il un solution pour rafraîchir en restant a la même hauteur de page ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 05:37 pm
Pfff c'est a force d'y trifouillé ... :(
C'est pourtant si simple bref, c'est corrigé.
une bonne technique pour ne pas vous tromper est d'utiliser une énumération.

une fois votre tableau défini vous copier le contenu, et le collez dans un éditeur de texte et remplacez les guillemets par '_' puis vous vous servez de cela pour faire un enum

Code: [Select]
const char * labelsOfInterest[] = {
  "tempbacvent",          "tempbacmax",     "temprampemax",     "consigneph",
  "puissanceblanc",       "puissancebleu",  "puissancejebao1",  "puissancejebao2",
  "puissancejebao3",      "angle1oscillo1", "angle2oscillo1",   "angle1oscillo2",
  "angle2oscillo2",       "angle1oscillo3", "angle2oscillo3",   "delaisnouritureminute",
  "delaistempetteminute", "nourissage1",    "nourissage2",      "LEVER",  "COUCHER"
};

 

vous aide alors à créer cela:

Code: [Select]
enum : byte {
  _tempbacvent_,          _tempbacmax_,     _temprampemax_,     _consigneph_,
  _puissanceblanc_,       _puissancebleu_,  _puissancejebao1_,  _puissancejebao2_,
  _puissancejebao3_,      _angle1oscillo1_, _angle2oscillo1_,   _angle1oscillo2_,
  _angle2oscillo2_,       _angle1oscillo3_, _angle2oscillo3_,   _delaisnouritureminute_,
  _delaistempetteminute_, _nourissage1_,    _nourissage2_,      _LEVER_,  _COUCHER_
};


ensuite c'est simple au lieu de vous embêter à compter dans quel ordre ils sont vous pouvez faire un switch avec les petits noms car le premier élément d'un enum vaut 0 donc vous avez le bon ordre

Code: [Select]
switch (labelIndex) {
    case _tempbacvent_ :
      break;

    case _tempbacmax_ :
      break;

    case _temprampemax_ :
      break;

    case _consigneph_ :
      break;

    case _puissanceblanc_ :
      break;

    case _puissancebleu_ :
      break;

    case _puissancejebao1_ :
      break;

    case _puissancejebao2_ :
      break;

    case _puissancejebao3_ :
      break;

    case _angle1oscillo1_ :
      break;

    case _angle2oscillo1_ :
      break;

    case _angle1oscillo2_ :
      break;

    case _angle2oscillo2_ :
      break;

    case _angle1oscillo3_ :
      break;

    case _angle2oscillo3_ :
      break;

    case _delaisnouritureminute_ :
      break;

    case _delaistempetteminute_ :
      break;

    case _nourissage1_ :
      break;

    case _nourissage2_ :
      break;

    case _LEVER_ :
      break;

    case _COUCHER_ :
      break;
  }


en plus comme cela c'est bcp plus lisible et vous éviter le problème d'avoir un numéro qui ne correspond pas

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 05:39 pm
Quote
Y a t'il un solution pour rafraîchir en restant a la même hauteur de page ?
pas simplement non... pour le navigateur web vous avez tout rechargé, c'est une nouvelle page...

dans l'absolu il faudrait essayer de travailler la page HTML pour avoir une représentation un peu plus "tableau de bord" comme ça il n'y aurait pas besoin de scroller
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 05:45 pm
une bonne technique pour ne pas vous tromper est d'utiliser une énumération.
effectivement
Mais du coup il n'y a plus :
const char * labelsOfInterest[]

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 07:02 pm
si si il faut les conserver pour que la fonction d'analyse fonctionne
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 08:18 pm
je m'en doutait m'ai c'est la ligne const char * labelsOfInterest[] qui etait devant que je n'arrive pas a re placer ...
avant, non, apres non, sur la meme ligne non ... >:(
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 10:35 pm
vous devez avoir cela:

Code: [Select]
const char * labelsOfInterest[] = {
  "tempbacvent",          "tempbacmax",     "temprampemax",     "consigneph",
  "puissanceblanc",       "puissancebleu",  "puissancejebao1",  "puissancejebao2",
  "puissancejebao3",      "angle1oscillo1", "angle2oscillo1",   "angle1oscillo2",
  "angle2oscillo2",       "angle1oscillo3", "angle2oscillo3",   "delaisnouritureminute",
  "delaistempetteminute", "nourissage1",    "nourissage2",      "LEVER",  "COUCHER"
};

enum : byte {
  _tempbacvent_,          _tempbacmax_,     _temprampemax_,     _consigneph_,
  _puissanceblanc_,       _puissancebleu_,  _puissancejebao1_,  _puissancejebao2_,
  _puissancejebao3_,      _angle1oscillo1_, _angle2oscillo1_,   _angle1oscillo2_,
  _angle2oscillo2_,       _angle1oscillo3_, _angle2oscillo3_,   _delaisnouritureminute_,
  _delaistempetteminute_, _nourissage1_,    _nourissage2_,      _LEVER_,  _COUCHER_
};
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 10:37 pm
a ok le tableau est en plus ...
Je l'avait remplacé ...
Merci

Chui sur la page HTML, sa va tenir sur une page, dans un tableau.
J'ai l'impression que l'affichage est plus long (ou c'est pars que je ne voyant pas la fin de la page avant ?)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 10:48 pm
vous avez sans doute un peu plus de HTML à envoyer... mais ça ne devrait pas être significatif....
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 10:55 pm
en réfléchissant à votre projet je me dis que si j'étais vous (je sais ça complique un peu) je prendrai un Wemos D1 complet ou similaire qui ne servirait qu'à faire l'interface web.

Le Wemos communiquerait par le port série potentiellement avec votre arduino dans un langage de commande que vous pourriez définir (en gros exporter des variables ou les lire). Ce serait bien plus efficace pour la partie web. c'est un puce qui a bcp plus de mémoire dans laquelle vous pourrez stocker votre page web sans soucis (4M bytes de mémoire flash !) -, il tourne à 80MHz au lieu de 16MHz de votre arduino, intègre directement à travers l'API web la communication wifi sans passer par les commandes AT et vous le programmez aussi avec le langage arduino.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:03 pm
J'ai vu cette solution (puisque les esp12 ou esp32 peuve être programmer directement et gère des sortie numérique.
Sa soulagerais l'arduino.
Comme je vous l'ai dit au paravent, les idée ne me manque pas ... c'est les connaissance pour y arrivé qui ne me font pas prendre ce chemin ...

Je reçoit mardi mon esp32 qui, il me semble tourne a 240 MHz en double core, 520 KB SRAM, 16 MB flash.
j'aurais donc la possibilité de faire évoluer mon projet.

De la manière dont vous m'épauler (j'ai un réacteur d'A380 au fion  :smiley-zipper: ) je me dit que tout est possible :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 13, 2017, 11:12 pm
comment comptez vous l'utiliser ?

il n'a pas les commandes AT donc ne va pas fonctionner comme votre ESP-01

y'a des trucs qui existent (https://github.com/espressif/esp32-at) mais ça va vous compliquer la vie
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:21 pm
Pourtant j'ai vu ca :

ici (https://pcbreflux.blogspot.fr/2017/02/esp32-playing-with-esp32-at-commands.html)

et sur le datasheet il y a des pin rx/tx

datasheet (http://espressif.com/en/support/download/documents?keys=&field_type_tid%5B%5D=54)
Photo page 9

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 13, 2017, 11:25 pm
ma page (https://img15.hostingpics.net/pics/746829Sanstitre.png) donne sa.

Vous remarquerez l'arrivé d'un bouton rouge ...
Nous y voici, nous y voila ...

Code: [Select]
        case 23: // W
          valider += labelValue;
          // y faut tout sauvegarder  :)
          // c une histoire d'epprom ...
          // Une gros dossier totalement inconnu :(
          // on va faire dodo et verras sa demain
          // Encore merci JML pour ton aide qui m'as permis de bien bien avancer aujourd'hui.
          valider = 0;
          break;
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 14, 2017, 04:30 am
;)

Pour l'esp il faudra vérifier quand vous le recevez quel OS est installé dessus et mettre si nécessaire celui des commandes AT
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 09:15 am
Ok, pour 3 € de différence avec esp12, vu les performance sur la papier ...
Je croise led doigt pour que tout fonctionne simplement et plus efficacement.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 14, 2017, 10:54 am
Le successeur de l'ESP8266 qui est dans les Wemos mini par exemple est  l'ESP32 qui a été lancé en septembre 2016 - il y a un an environ donc. Au début il était cher mais avec des produits basés sur le module ESP-WROOM-32 (http://www.iotsharing.com/2017/05/introduction-to-esp32.html) c'est devenu compétitif

ils sont livrés généralement avec FreeRTOS nu et vous pouvez installer au dessus une "couche arduino (https://github.com/espressif/arduino-esp32)" - je n'ai jamais essayé d'installer un langage de commande AT

Vous avez pris quoi finalement comme esp32? Le wemos Lolin 32 (https://wiki.wemos.cc/products:lolin32:lolin32) ou une chinoiserie un peu moins connue (https://www.amazon.fr/Hrph-Development-Bluetooth-antenne-Ultra-Low/dp/B0717759B7/ref=sr_1_2) ?  Le Lolin n'a pas vraiment de documentation pour le moment (essayez de cliquer sur les liens (https://wiki.wemos.cc/tutorials:lolin32) pour voir)


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 11:12 am
J'ai pris celui ci (https://www.amazon.fr/gp/product/B06Y6HXXY1/ref=oh_aui_detailpage_o02_s00?ie=UTF8&psc=1)

Je n'est pas trouvé de doc précise non plus pour celui ci mais juste pour la "puce"
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 14, 2017, 12:58 pm
OK faut parler chinois pour celui là. (https://item.taobao.com/item.htm?&id=542459608596) mais il y a un gitHub associé en anglais (https://github.com/SmartArduino/SZDOITWiKi/wiki/ESP8266---ESP32) mentionné dans la doc en chinois - faudra sans doute le flasher avec autre chose que son OS de base...


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 06:30 pm
faudra sans doute le flasher avec autre chose que son OS de base...
Encore une mission ...
J'ai deja un esp12 que je n'arrive pas a uploader le firmeware ...
J'espère que ce seras plus simple.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 14, 2017, 06:42 pm
oui c'est un peu galère, faut prendre le coup :)

perso je suis sur Mac, je le fais par le script python esptool (https://github.com/espressif/esptool) qui supporte aussi des ESP32

- faut s'assurer d'avoir un adaptateur genre FTDI qui sorte bien du 3.3V ou faire les adaptation de tension 5V <-> 3.3V

- faut mettre la puce en mode "flash" donc
                 GPIO 0: LOW
                 GPIO 2: HIGH (3.3V)
                 GPIO 15: LOW
                 alimenté avec une bonne source de courant (pas à travers le FTDI) 3.3V and GND
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 10:17 pm
Oui c'est bien se que je fait, comme sur les post du net ... bref ... j'espere que tout se passeras bien avec l'esp 32 ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 10:40 pm
Je cherche sur le net pour comprendre l'utilisation de l'epprom.
Une chose ma chagrine
Code: [Select]
Syntaxe : EEPROM.write(adresse, valeur)

Adresse : place dans laquelle vous voulez enregistrer la mémoire. Pour l'ATmega168, entre 0 et 511
Valeur : entre 0 et 255


J'ai des variable de avec des nombres de plusieurs milliers ... y a forcement un astuce

Le EEPROM.PUT() ??
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 10:46 pm
sa marche :) :) :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 10:48 pm
J'ai fait un premier code avec
Code: [Select]
#include <EEPROM.h>

/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
int addr = 123;
int val = 456;

void setup() {
EEPROM.put(1, addr);
EEPROM.put(10, val);


Puis un second avec

Code: [Select]
#include <EEPROM.h>

// start reading from the first byte (address 0) of the EEPROM
int addr = 0;
int val = 0;


void setup() {
  // initialize serial and wait for port to open:
  Serial.begin(9600);
EEPROM.get(1, addr);
EEPROM.get(10, val);
}

void loop() {
  // read a byte from the current address of the EEPROM

  Serial.print(addr);
  Serial.println();
  Serial.print(val);
  Serial.println();


Et j'ai bien mes valeur 123 et 456 qui sont afficher sur le moniteur serie
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 10:49 pm
Je suis etoner que sa est ete si simple  ::)
Trop beau pour etre vrai ...  :smiley-roll-sweat:
je vais attendre votre confirmation avant de l'intégrer a mon bouton sauvegarde ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 10:52 pm
Et si vous pouvez me confirmer, l'adresse que je donne a l'epprom doit prendre en compte le nombre de bytes enregistrer avant ? exemple, a l'adresse 10 je stock un int, le prochaine adresse a utiliser est 12 (int = 2 bytes) ?



Avec un peu de chance je vais avoir mon 2eme bon point  :smiley-cool:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 14, 2017, 11:06 pm
Oui tout à fait chaque case contient 1 octet et ça fonctionne tout seul. se souvenir cependant qu'on n'a que 100,000 écritures possibles et donc à utiliser à bon escient, pas dans un boucle qui tourne à fond

Pour savoir de combien d'octets il faut sauter, vous pouvez utiliser sizeof(votreVariable)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 14, 2017, 11:26 pm
HSon // rupture de bon point // HSoff

J'ai l'intention  de mettre EEPROM.get juste après la déclaration de met variable, comme cela, ce sont les dernière variable enregistré qui seront pris en compte.
Le EEPROM.put seras utilisé 1 fois dans le code, lorsque l'on sauvegarde les variable modifier sur la page internet. ( j'ai vu que cette fonction n'enregistrait que si la variable avait été modifier)

De ce fait, il y auras très très peu d'écriture (la lecture ne rentre pas dans l'usure de ce composant si j'ai bien tout lu)

Aller j'inclue tout ça ... Jsuis content, jpensait que c'était une étape galere de OUF ... j'ai presque réussi tout seul :)
Je suis en train de muté en JML ... (peut être pas quand même lol)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 14, 2017, 11:32 pm
Quand on bosse ça se voit :)

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 08:45 am
YESSSS

et de deux lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 09:27 am
:)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 10:45 am
Bon, ça fonctionne ... mis a part au premier démarrage, ça a été galère.
Vu que je demande de lire les variable sur l'epprom et qu'il n'y en a pas au premier démarrage = erreur sur la page et donc même si on sauvegarde, l'epprom sauvegarde les erreur :)
Donc obliger de faire un code sans la partie lecture de l'epprom pour pouvoir sauvegarder et après remettre la lecture et c'est bon ...

Pour les prochaine fois j'ai penser faire un boolean sauvegarder dans l'eeprom pour que si il n'y a pas eu de sauvegarde l'eeprom ne lise pas.

Il y a peut être une solution de prévu ?

 

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 10:52 am
La partie page de commande étant opérationnel, je me retourne vers le code générant 2 page (page "d'accueil" et page "admin") il faut que je combine les deux page ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 10:57 am
Pour traiter le cas de savoir si oui ou non l'EEPROM a été initialiséé généralement on écrit à une adresse connue de l'EEPROM une sorte de message qui a peu de chance d'être là par hasard, sur 4 octets consécutifs par exemple. ça a donné des idées sur l'usage  de codes  rigolos en hexadécimal du genre 0xDEADBEEF (dead beef) ou encore 0x8BADF00D (ate bad food) ou 0xBAADF00D (bad food), 0xBAADCAFE (bad café)

Bref dans le startup() vous allez lire à l'adresse connue, si vous trouvez votre petit message vous savez que les valeurs des paramètres en EEPROM sont bons sinon vous y écrivez des valeurs par défaut raisonnables et le mot clé magique à l'adresse connue
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 11:01 am
Bref dans le startup() vous allez lire à l'adresse connue, si vous trouvez votre petit message vous savez que les valeurs des paramètres en EEPROM sont bons sinon vous y écrivez des valeurs par défaut raisonnables.
Donc cette "phrase" doit être ajouter lorsque je fait une sauvegarde dans l'eeprom avec les autre paramètre sinon je lirait toujours les valeur par default.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 01:03 pm
Voici un bout de code d'exemple

Code: [Select]
#include <EEPROM.h>

const uint32_t motClef = 0xDEADBEEF;
const uint16_t adresseMotClef = 0x00;

const byte tailleMax = 50;

// __attribute__ ((packed)) permet de forcer la conservation de l'ordre des champs
// c'est utile pour éviter que le compilateur mette le bazar quand on en rajoute au fil du temps
struct __attribute__ ((packed)) _paramS {
  int8_t minimumT;          // -128 à 127°
  int8_t maximumT;          // -128 à 127°
  char ville[tailleMax + 1]; // la ville d'installation
} lesParametres;

const uint16_t adresseDesParametres = adresseMotClef + sizeof(motClef);

// *************************

char messageRecu[tailleMax + 1]; // +1 pour stocker un '\0' à la fin de la chaîne
byte index;

boolean recevoirMessage(const char finDeChaine)
{
  boolean fin = false;

  if (Serial.available()) { // si on a au moins un charactère en attente
    int recu = Serial.read(); // -1 si erreur, sinon notre charactère
    if (recu != -1) {
      if (recu == finDeChaine) fin = true;
      else {
        if (recu != '\r') { // on ignore CR
          messageRecu[index++] = (char) recu;
          messageRecu[index] = '\0'; // on marque la fin de chaîne
          if (index >= tailleMax) index = tailleMax - 1; // évite de déborder
        }
      }
    }
  }
  return fin;
}


void printParams()
{
  Serial.println(F("\n************* PARAMS *************"));
  Serial.print(F("Temp min =\t")); Serial.println(lesParametres.minimumT);
  Serial.print(F("Temp max =\t")); Serial.println(lesParametres.maximumT);
  Serial.print(F("Ville    =\t")); Serial.println(lesParametres.ville);
}

void etablirValeursParDefaut()
{
  uint32_t lectureMotClef;
  Serial.print(F("Mot Clef = 0x")); Serial.println(motClef, HEX);
  Serial.print(F("Adresse Mot Clef = 0x")); Serial.println(adresseMotClef, HEX);
  Serial.print(F("Adresse Params = 0x")); Serial.println(adresseDesParametres, HEX);

  EEPROM.get(adresseMotClef, lectureMotClef);
  if (lectureMotClef == motClef) {
    // la mémoire a déjà été initialisée, on peut charger les paramètres
    Serial.println("params en memoire = OK");
    EEPROM.get(adresseDesParametres, lesParametres);
  } else {
    // la mémoire n'avait pas encore été initialisée
    Serial.println("params en memoire = pas OK");
    lesParametres.minimumT = -22;
    lesParametres.maximumT = 44;
    strcpy(lesParametres.ville, "une ville inconnue");
    EEPROM.put(adresseDesParametres, lesParametres);
    EEPROM.put(adresseMotClef, motClef);
  }
  printParams();
}


void setup() {
  Serial.begin(115200);
  Serial.println(F("\n\n-------- DEMO --------\n"));

  etablirValeursParDefaut();

  // pas nécessaire car le compilateur le fait pour nous avec des variables globales
  // juste pour vous rappeller qu'il est bon de définir les bonnes conditions initiales
  index = 0;
  messageRecu[0] = '\0';


  Serial.println(F("\nEntrez le nom de la ville ou reset"));
}

void loop() {
  if (recevoirMessage('\n')) {
    // on a reçu le message met à jour l'EEPROM

    // à titre de démo, si l'entrée contient "reset", on efface le mot clé
    if (!strcmp(messageRecu, "reset")) {
      EEPROM.put(adresseMotClef, 0xABADCAFE); // mauvais mot clé - au reboot les params seront rétablis au défaut
      Serial.println(F("Reset mot clef. rebootez l'Arduino pour voir"));
    } else {
      memset(lesParametres.ville, '\0', tailleMax + 1); // on met tous les octets à 0
      strcpy(lesParametres.ville, messageRecu);         // on stocked le nom de la ville
      EEPROM.put(adresseDesParametres, lesParametres);  // on remet tout en mémoire
      printParams();                                    // on affiche les  params
      // On re-initalise notre buffer
      index = 0;
      messageRecu[0] = '\0';
    }
  }
}


la première fois que vous le lancez vous allez voir cela sur la console (réglée à 115200, avec envoi  de CR/LF)

-------- DEMO --------

Mot Clef = 0xDEADBEEF
Adresse Mot Clef = 0x0
Adresse Params = 0x4
params en memoire = pas OK

************* PARAMS *************
Temp min =   -22
Temp max =   44
Ville    =   une ville inconnue

Entrez le nom de la ville ou reset


le code a detecté que votre carte n'avait pas le bon mot clé (cf la partie en rouge) et a donc mis les paramètres par défaut et établi un environnement correct.

Vous voyez que la ville est inconnue.

Tapez dans la console "Toulouse" par exemple et validez

la console va alors afficher************* PARAMS *************
Temp min =   -22
Temp max =   44
Ville    =   Toulouse


On a changé les paramètres et on le voit. Pour s'assurer que c'est bien en mémoire maintenant, fermez la console série rebootez l'arduino. (ou l'ouverture de la console le reboot)

Vous verrez alors s'afficher
-------- DEMO --------

Mot Clef = 0xDEADBEEF
Adresse Mot Clef = 0x0
Adresse Params = 0x4
params en memoire = OK

************* PARAMS *************
Temp min =   -22
Temp max =   44
Ville    =   Toulouse

Entrez le nom de la ville ou reset


On voit donc que le mot clé a été reconnu et les paramètres bien initialisés non pas aux valeurs par défaut mais avec le contenu de la mémoire (on voit bien qu'il s'est souvenu de Toulouse).


Maintenant tapez reset dans la console et validez.

si vous regardez le code, j'ai fait un petit test quand on reçoit la ligne entrée qui vérifie si c'est ce mot qu'on a tapé et si oui efface le mot clé en mémoire (le remplace par une valeur fausse)

la console va vous dire
Reset mot clef. rebootez l'Arduino pour voir

effacez la console, fermez là. rouvrez là en rebootant votre arduino et là vous verrez que la console affiche
-------- DEMO --------

Mot Clef = 0xDEADBEEF
Adresse Mot Clef = 0x0
Adresse Params = 0x4
params en memoire = pas OK

************* PARAMS *************
Temp min =   -22
Temp max =   44
Ville    =   une ville inconnue

Entrez le nom de la ville ou reset


--> comme le code n'a pas trouvé le mot clé, il a décidé que la mémoire n'était pas bonne et a remis des paramètres par défaut. Toulouse a été effacé.

--> bref ce n'est pas compliqué

Notez au passage:

- le mot clé est rangé en mémoire AVANT les données

- je mets tous mes paramètres globaux que je dois mémoriser dans une structure. ça permet de simplifier fortement l'écriture de la sauvegarde, on écrit directement la structure en EEPROM.

ça va aussi simplifier l'évolution du code pendant qu'on développe et améliore le projet si on a d'autres paramètres à mémoriser

- en utilisant __attribute__ ((packed)) dans la déclaration de la structure, vous évitez les optimisations du compilateur et les champs en mémoire seront bien déclarés dans cet ordre.

--> si vous avez besoin de nouveaux paramètres, mettez les à LA FIN de la structure.

--> Au prochain lancement il y aurait lecture des params existants et du bazar pour les reste. Pour traiter cela généralement on a aussi en EEPROM, comme premier élément des paramètres,  un numéro de version. Au boot, Si vous voyez le motClef, vous savez qu'une partie de la mémoire est déjà initialisé. Vous lisez alors le No de version. Si elle ne correspond pas à la version actuelle de votre logiciel, alors  en fonction de la version vous chargez les paramètres existants, établissez des valeurs par défaut pour les nouveaux et restockez le tout en mettant à jour le numéro de version. --> ça donne un truc d'évolutif.


OK?
 

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 02:39 pm
oui sa marche


Mais je coince pour adapter sur le programme "double page"
si j'ai bien compris c'est if (!strcmp qui lit l'adresse GET
Mais dans le code pour gerer les bouton il est utilisé:
if (!strcmp(labelsOfInterest, item)) {
alors quand dans le code double page il est utilisé :
(!strcmp(urlRequest, "/admin"
il faudrait donc que le :
if (!strcmp(labelsOfInterest, item)) { soi t plutot en :
if (!strcmp "/admin"(labelsOfInterest, item)) {
?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 02:46 pm
strcmp() (http://en.cppreference.com/w/cpp/string/byte/strcmp) est une fonction de la librairie standard qui compare 2 chaînes de caractères (c-strings)

Donc dans un cas on l'utilise pour voir si ce que l'on a reçu c'est «GET »
Si c'est un GET je sais que j'ai derrière une URL que je vais extraire
L'URL elle même va contenir une affectation de variable et donc dans l'autre cas j'utilise strcmp() pour chercher dans le tableau des noms de variables laquelle on a reçu

On pourrait dire que admin est une variable mais si vous la trouvez alors derrière il ne faut pas essayer de lire une valeur
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 02:48 pm
donc je fait

(!strcmp(urlRequest, "/admin" et ajoute ensuite
if (!strcmp(labelsOfInterest, item)) {
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 03:14 pm
c'est bien ça
Par contre les bouton ramène a ip/** au lieu de ip/admin/**
dit rien ... je vais trouver
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 03:17 pm
vous êtes dans l'intégration dans votre gros projet ou toujours dans un "petit" projet à part?

si dans le second cas, pouvez vous poster le code de là où vous en êtes?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 03:19 pm
je suis dans le projet "moyen" lol
J'essais d'adapter le projet "page de programmation" au programme "double page"
Je vous envoie
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 03:20 pm
j'ai trouver pour l'url des bouton mais du coup, plus d'action ...
Je vais trouver ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 04:16 pm
Y doit y avoir des "conflit" car l'url "admin" ne fonctionne pas toujours ...
des fois on reste sur la page principal ou vis versa ...

Pour les boutons, je n'est pas trouvé, je pence que ca tourne autour de ca et qu'il faut ajouter /admin ...
Mais ou ... ?

Code: [Select]
int commandLength = strlen(urlRequest);

  item = strtok(urlRequest, "=");

  while (item) {
    labelFound = false;
    for (int i = 0; i < maxLabelsOfInterest; ++i) {
      if (!strcmp(labelsOfInterest[i], item)) {


...

J'ai quand meme reussi a se que les bouton donne
http://192.168.1.52/admin/nourissage2=600
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 05:22 pm
votre code contient

Code: [Select]
         if (strlen(urlRequest) != 0) parseCommand();{
          // une requête HTTP se termine par une ligne vide
          envoyerPageWeb(client, urlRequest);
          break;
          }


il y a ne paire de {} qui ne sert à rien

Code: [Select]
       if (c == '\n' && currentLineIsBlank) {
          // une requête HTTP se termine par une ligne vide
          if (strlen(urlRequest) != 0) parseCommand();
          envoyerPageWeb(client, urlRequest);
          break;
        }


quand vous arrivez là, on a reçu l'intégralité de la requête HTTP et l'URL est dans la variable urlRequest

Elle peut être / par exemple ou si j'ai bien compris ce que vous voulez faire  /admin/puissanceblanc=-5.

Dans les 2 cas vous appelez parseCommand() qui commence par faire un
Code: [Select]
item = strtok(urlRequest, "=");
 ça initialise item sur le début de urlRequest et remplace le premier "=" trouvé par un caractère nul.

et ensuite dans la boucle while vous faites un test pour comparer avec vos labelsOfInterest
Code: [Select]
     if (!strcmp(labelsOfInterest[i], item)) {


dans le premier cas /, comme il n'y a pas de '='  item est NULL et vous n'analysez rien.

Dans le second cas /admin/puissanceblanc=-5 le '=' est remplacé par un '\0' (on modifie la chaîne urlRequest en utilisant strtok()) et item pointe sur /admin/puissanceblanc --> qui n'est pas un labelsOfInterest et donc vous ne trouvez rien non plus...


--> il faudrait démarrer l'analyse de la chaîne après /admin/ donc tester si l'url commence par /admin/ (avec strncmp par exemple) et si oui commencer le strtok 7 caractères plus loin car il y a 7 caractères dans /admin/
Code: [Select]
  item = strtok(urlRequest+7, "=");
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 09:25 pm
si j'ai bien compris ce que vous voulez faire
Dans un premier temps j'ai adapter un code de façon a avoir une page "d'accueil" et une page "/admin"
Dans un second temps j'ai adapter un code de façon a avoir des boutons fonctionnel sur une page web.
Les bouton de cette page web sont ceux présent sur la page /admin.
A l'heure actuel j'essai donc de combiner ces deux code.
ce qui fait que mes bouton répondant a (exemple) ip/puissanceblanc=-5 doivent a présent être en ip/admin/puissanceblanc=-5
n'ésiter pas a me dire si je ne suis pas claire ou si des détails vous échappés.
tester si l'url commence par /admin/ (avec strncmp par exemple) et si oui commencer le strtok 7 caractères plus loin car il y a 7 caractères dans /admin/
Code: [Select]
  item = strtok(urlRequest+7, "=");
Je me doutait que c'était ici mais je cherchais a ajoute /admin plutôt que de faire +7 ...

J'ai fait ces deux changement, suprimer la paire de {} et modifier en
Code: [Select]
  item = strtok(urlRequest+7, "="); mais toujours pareil, les bouton rafraîchisse la page mais sans changer les variables.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 10:46 pm
Imprimez ce que item vaut dans le while en faisant les test par rapport aux labelsOfInterest
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 11:10 pm
ça me donne ça :
Code: [Select]
[WiFiEsp] New client 0
avant while
puissancebleu

dans while

[WiFiEsp] Disconnecting  0


J'ai donc tout de suite penser a :
Code: [Select]
const byte maxURL = 20;
et je l'ai modifier a 35

et ca donne ca :
Code: [Select]
[WiFiEsp] New client 0
avant while
puissanceblanc

dans while
-5
[WiFiEsp] Disconnecting  0


Donc bien pris en compte mais page blanche.
Mais la variable est bien modifier lorsque je rafraîchi la page.


Es que cette ligne s'arrete au caractère indiquer (/admin) ou analyse tout (/admin/peutimporte) se qui suit d'ou l'erreur ?
Code: [Select]
(!strcmp(urlRequest, "/admin"))
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 15, 2017, 11:12 pm
Ah oui il faut grandement allonger l'url Et la ligne lue, elle a quelle taille dans votre code?

strcmp(urlRequest, "/admin") Compare vraiment les 2 donc pas bon si pas juste /admin

Il faut utiliser comme je l'ai dit plus haut strncmp()

strncmp(urlRequest, "/admin", strlen("/admin"))

Ou si vous voulez compter vous même et économiser de la mémoire  strncmp(urlRequest, "/admin", 6)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 11:26 pm
en ajoutant le ! avant ça fonctionne :)

La plus grosse fait
http://192.168.1.52/admin/delaismouvementoscillo=-1

32 :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 15, 2017, 11:37 pm
J'ai remarque un bug qui n'était pas présent avant la fusion des deux codes.
Lorsque l'on clic sur un bouton, puis un autre, le premier Click sur le second bouton rafraîchi la page mais sans action.
exemple,
1er Click /// je Click "tempbacvent-5", variable modifier, page rafraîchi.
2eme Click /// Je Click ensuite sur tempbacmax+5, variable non modifier, page rafraîchi.
En regardant dans le moniteur, je vois qu'il est affiché :
1er click /// avant while / tempbacvent / dans while / -0.5
2eme Click /// avant while / tempbacvent /dans while /
Il faut attendre min ~3sec entre chaque click


Une idee pourquoi le "item = strtok(urlRequest+7, "=");" ne se met pas a jour du premier coup ?
Du au "hardware" faiblard ?




Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 16, 2017, 06:53 am
repostez votre code, sans cela on je ne peux pas suivre vos modifs.

(je pars en vacances une semaine donc moins présent les jours qui viennent)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 16, 2017, 07:59 am
Voila,

BONNE VACANCE
(http://alterego.ccilvn.be/wp-content/uploads/2015/08/bonnes-vacances.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 18, 2017, 02:10 am
esp32 recu
Bien sur, firmware pas en AT, 4h a essayer de mettre a jour avec le firmware AT ...  :smiley-sleep:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 18, 2017, 10:11 am
Ca y est, firmware AT instalé
Répond bien dans le moniteur
et fonctionnel avec le code.
Aucune amélioration sur la vitesse d'affichage
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 18, 2017, 11:45 pm
et après plusieurs test, pareil pour les boutons ...
On click , ca rafraîchi et seulement 1 fois sur 3 la variable est modifié ...  :smiley-confuse:
Je trouve rien qui pourrait justifier ce bug ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 20, 2017, 12:24 am
En parallèle, j'ai réfléchit a une méthode pour pouvoir indiquer et sauvegarder le ssid et mdp du réseau WIFI.
J'ai donc réalise un code utilisant le sim900 déjà présent pour prévenir des coupure de courant et autre alerte.

Le fonctionnement est simple, envoie d'un sms au sim900 de type, "ssid ***votre ssid***" soit "mdp ***votre mdp***".
il lit le message et ne garde que le ssid ou mot de passe, il vous répond (il répond au numéro du sms reçu) ensuite par sms que c'est OK.
Il ne reste qu'a sauvegarder dans l'epprom ces deux donner une fois reçu.
De cette façon, l'appareil sera totalement autonome une fois le code téléverser une fois.

Mais ...
Et oui, il a toujours un mais avec moi :/
J'ai une question et un probleme.

Mon problème : dans mon code principal, ssid et mdp sont déclarer en temps que char alors que dans ce code il sont en string.
du coup, je n'arrive pas fusionner les deux code.

Ma question : ce code utilise des String, cela pose t'il un gros problème ?

Merci
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 20, 2017, 04:24 pm
Bonjour rapide

si vous pouvez éviter la classe String c'est mieux :)

votre fonction message - vous ne trouvez pas qu'elle ressemble étrangement  à ce que l'on a déjà écrit pour gérer l'attente de la réponse de l'ESP aux commandes AT

--> donc jetez celle ci à la poubelle et adaptez celle que vous avez déjà
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: sachab on Oct 21, 2017, 02:20 pm
Bonjour,

Je ne connais pas ton code, mais si ça peux aider, je tourne depuis 1 an, sans bug, avec un code pour ma rampe led qui a un lever et un couché de soleil sans palier visible. Si ça intéresse je peux le poster.

A+
 
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 21, 2017, 10:29 pm
Merci sachab mais pas de soucis de se coté la.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 21, 2017, 11:22 pm
--> donc jetez celle ci à la poubelle et adaptez celle que vous avez déjà
On a les meme idee, mais une fois bloqué a :
request for member 'concat' in 'reponse', which is of non-class type 'char'
j'en ai conclu que le .concat de reponse.concat ne pouvais rentree dans la class char.

Je vais continuer de regarder ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 22, 2017, 10:57 am
J'ai reçu mon CI définitif (v1.0)

(https://image.noelshack.com/minis/2017/42/7/1508662237-img-20171020-234611.png) (https://www.noelshack.com/2017-42-7-1508662237-img-20171020-234611.jpg)
(https://image.noelshack.com/minis/2017/42/7/1508662235-img-20171020-234549.png) (https://www.noelshack.com/2017-42-7-1508662235-img-20171020-234549.jpg)


donc ... au boulot :)

(https://image.noelshack.com/minis/2017/42/7/1508662229-img-20171021-102400.png) (https://www.noelshack.com/2017-42-7-1508662229-img-20171021-102400.jpg)
(https://image.noelshack.com/minis/2017/42/7/1508662204-img-20171021-102502.png) (https://www.noelshack.com/2017-42-7-1508662204-img-20171021-102502.jpg)
(https://image.noelshack.com/minis/2017/42/7/1508662183-img-20171021-102434.png) (https://www.noelshack.com/2017-42-7-1508662183-img-20171021-102434.jpg)
(https://image.noelshack.com/minis/2017/42/7/1508662194-img-20171021-102424.png) (https://www.noelshack.com/2017-42-7-1508662194-img-20171021-102424.jpg)
(https://image.noelshack.com/minis/2017/42/7/1508662185-img-20171021-102411.png) (https://www.noelshack.com/2017-42-7-1508662185-img-20171021-102411.jpg)
(https://image.noelshack.com/minis/2017/42/7/1508662225-img-20171021-102538.png) (https://www.noelshack.com/2017-42-7-1508662225-img-20171021-102538.jpg)
(https://image.noelshack.com/minis/2017/42/7/1508662155-img-20171022-103803.png) (https://www.noelshack.com/2017-42-7-1508662155-img-20171022-103803.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: jfs59 on Oct 22, 2017, 01:23 pm
bonjour
je m'interroge sur la provenance et le prix du circuit ?

merci
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: sachab on Oct 22, 2017, 02:36 pm
Beau travail Djbouns
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 22, 2017, 02:46 pm
joli poisson !
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 22, 2017, 05:16 pm
bonjour
je m'interroge sur la provenance et le prix du circuit ?

merci
Passer par une petite société.
Livré pour 36.93€
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: ChPr on Oct 22, 2017, 06:25 pm
Sur vos photos, là où les composants sont montés, on ne voit pas de remontée de soudure. Les trous ne sont pas métallisés ?

Cordialement.

Pierre
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 22, 2017, 06:56 pm
Sur vos photos, là où les composants sont montés, on ne voit pas de remontée de soudure. Les trous ne sont pas métallisés ?

Cordialement.

Pierre
non, pas l'utilité puisque le circuit est en simple couche. la couche TOP n'est la qu'en remplacement de la serigraphie
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: ChPr on Oct 22, 2017, 07:19 pm
Vu la teinte du support, j'ai l'impression qu'il est en bakélite et non en verre époxy. Faites attention à l'humidité.

Cordialement.

Pierre
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 22, 2017, 10:52 pm
apres toute cette pares midi, j'en suis arrivé a ca :

Code: [Select]
#define gsm Serial1     // Si utilisation MEGA

char reponse, numeroSMS,SMS[8];
unsigned long t0;

char ssid [] = "ratata";   // Nom du réseau (SSID)
char mdp [] = "prout";


boolean message(char attente, unsigned int timeout, boolean affiche) {
  t0 = millis();
  reponse="";
  while (millis() - t0 < timeout) {
    while(gsm.available()) reponse = gsm.read();
    if (!strcmp(reponse,attente)>0){        // Lit encore 100 ms le port série  
       while(gsm.available()) reponse = gsm.read();
        break;}}
  //if (affiche || !strcmp(reponse,attente)==-1 ) {      
   // Serial.print("Attente = " (attente) " "+ !strcmp(reponse,attente)+" duree ");
   // Serial.print(millis()-t0); Serial.println(" ms");
   // Serial.println(reponse);}
  
  if (!strcmp(reponse,attente)>0) return true;
  else return false;
}


void LireSMS(){
  gsm.println("AT+CMGF=1");  // Mode Texte
  message("OK",1000,0);
  gsm.println("AT+CMGR=1");  // Lit le premier message disponible sur la carte SIM
  message("OK",2000,1);
  // Récupérer N° de telephone emetteur pour lui répondre
  int test= !strcmp(reponse,"+33");
  numeroSMS = strtok(test,test+12);
  Serial.println("SMS recu depuis : " + numeroSMS);
 
  // Analyse du message reçu
  if (!strcmp(reponse,"Ssid")>0){
    int sms = !strcmp(reponse,"Ssid");
    SMS = ("SSID : ") + (strtok(sms+5, "="));
    
    
  }
  else if (!strcmp(reponse,"Mdp")>0){
    int mdp=!strcmp(reponse,"Mdp");  
    SMS = ("Mots de passe : ") + (strtok(mdp+4, "="));
    
  }
  else {
      SMS = "Ordre non compris !";
  }
        
  gsm.println("AT+CMGD=1,4"); // effacer les SMS de la Carte SIM
  message("OK",1000,0);
    
  // Envoyer la confirmation de l'ordre par SMS
  gsm.println("AT+CMGS=\"" numeroSMS "\"");
  message(">",1000,0);
  gsm.println(SMS);
  gsm.write(26); // Caractère de fin 26 <Ctrl-Z>
  message("+CMGS:",10000,1);  
}

void setup() {

  Serial.begin(9600);
  gsm.begin(9600);
  Serial.println("Initialisation...");
  gsm.println("AT");
  while (!message("OK",1000,0)) gsm.println("AT");
  gsm.println("AT+CMGF=1");         // Mode Texte
  message("OK",1000,0);
  gsm.println("AT+CMGD=1,4"); // effacer les SMS en mémoire dans la carte SIM
  message("OK",2000,0);      // car on lit toujours le message N°1 de la carte SIM...
  
}

void loop() {
  if (message("+CMTI:",20000,0)) LireSMS();   // Si nouveau SMS disponible SIM800 envoie +CMTI:
}


et se foutu message qui persite ...
Code: [Select]
exit status 1
invalid operands of types 'const char [8]' and 'char*' to binary 'operator+'
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 22, 2017, 10:56 pm
Êtes vous sur que response doit être un char ? (1 seul caractère?) idem pour numeroSMS
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 22, 2017, 11:29 pm
A la base, numeroSMS et réponse etait en String.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 23, 2017, 12:02 am
donc il comporte plus qu'un caractere :/

il faut que j'utlise atoi ?
un peu comme sa ?
Code: [Select]
char str[20];
   
   strcpy(str, "98993489");
   val = atoi(str);
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 23, 2017, 12:37 am
Oui, il faut assez d'espace pour stocker le texte

Et while(gsm.available()) reponse = gsm.read(); ça ne va pas bien marcher..

Regardez comment on a fait dans l'autre fonction qui écoutait la réponse de l'ESP ou alors relisez mon petit tuto en français (http://forum.arduino.cc/index.php?topic=500683.0)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 23, 2017, 09:32 am
oui j'ai bien compris qu'il faut utiliser c string, c'est ce que j'essaie de faire en remplaçant par strcmp par exemple


donc je remplace
reponse.concat(char(gsm.read()));
par
strcat(reponse,(gsm.read()))

et
reponse.indexOf("+33");
par
strpbrk(reponse,"+33");
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 23, 2017, 09:35 am
Non parce que gsm.read() retourne juste un caractère, pas une chaîne

Regardez le tuto du port série ci-dessus il y a du code
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 23, 2017, 09:39 am
mais donc il faut changer complètement la structure du code actuel, aucun intérêt de travailler a partir de celui la
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 23, 2017, 10:08 am
oui - c'est juste une fonction hein... pas la fin du monde :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 23, 2017, 10:41 am
oui - c'est juste une fonction hein... pas la fin du monde :)
:smiley-yell:
Entre deux tirage de cheveux, ton mess ma bien faire rire  :D  :D  :D
tu a raison il faut relativiser  :smiley-roll:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 23, 2017, 10:44 am
c'est vraiment exactement comme le code de l'ESP. vous envoyez des commandes AT ou +CMTI au GSM au lieu du Wi-Fi et vous attendez une réponse sur la ligne série avec un mot clé
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 02:14 am
c'est vraiment exactement comme le code de l'ESP.
oui et justement toute la partie dont je n'arrive pas a trouver la logique ...
bref, une demi journée, j'arrive déjà a pas avoir d'erreur en compilant
Code: [Select]
#define gsm Serial1
 
void setup()
{
  Serial.begin(9600);
  gsm.begin(9600);
 gsm.println("AT");
 delay (2000);
 gsm.println("AT+CMGF=1");
 delay (2000);
 
}

void loop()
{
  if(gsm.available()) {
    char c = gsm.read();
    if (c != -1) {
      switch (c) {
       
        case '\r':
          break;
        case '\n':       
          break;
       
        default:
        if(strstr (c, "Mdp")){
          Serial.print(F("mdp recu"));}
        else if(strstr (c, "ssid")){
          Serial.print(F("ssid recu"));}
          break;
      }
    }
  }

}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 09:33 am
Dans les chose que je ne comprend pas,
pourquoi juste en ajoutent
Code: [Select]

        default:
         Serial.print((char) c);
       
                    break;


J'ai les question/réponse de
Code: [Select]
gsm.println("AT");
 delay (2000);
 gsm.println("AT+CMGF=1");

alors que sinon, non

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 24, 2017, 09:46 am
parce que le composant est en mode "echo" donc répète la commande qu'il a reçu, puis l'exécute et vous envoie sa réponse
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 09:50 am
A ...

Jsuis en train de tout reprendre le code qui affiche dans le moniteur en char puis en une phrase
http://forum.arduino.cc/index.php?topic=500683.0

j'ai modifier pour que le serial imprime le message recu par sms plutot que celui ecrit dans le moniteur
#define gsm Serial1
gsm.begin(9600);

 while (gsm.available() && messageEnCours) {
    int c = gsm.read();

Mais aucune reaction
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 09:51 am
peut etre pasrque le gsm n'est pas mis en mode texte ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 09:51 am
jessaie ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 24, 2017, 10:14 am
il faut que le GSM soit configuré pour sortir les SMS reçu automatiquement sur son interface série. ça se fait avec des commandes AT
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 10:15 am
oui avec ("AT+CMGR=1")
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 24, 2017, 10:17 am
parfois il faut faire un AT+CMGF=1 avant pour passer en SMS text mode (selon les composants le mode par défaut est SMS PDU mode) --> vérifiable en envoyant AT+CMGF=? et regardant la réponse donnée
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 10:33 am
parfois il faut faire un AT+CMGF=1 avant pour passer en SMS text mode (selon les composants le mode par défaut est SMS PDU mode) --> vérifiable en envoyant AT+CMGF=? et regardant la réponse donnée
il me repond +CMGF: (0,1)
donc je le passe en mode texte sistematiquement avant tout autre demande
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 11:25 am
j'en suis la, dans un premier temps, tout dans le serial, j'envoie mon texte, il me repond (sauf que meme quand j'envoie ssid# il me repond qu'il ne comprend pas mais bon ...)
et des que je bascul sur gsm(serial1) plus rien
Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 50;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

const char marqueurDeFin = '#';

boolean ecouter()
{
  gsm.println("AT+CMGF=1");         // Mode Texte
delay(1000);
  gsm.println("AT+CMGR=1");
delay(2000);
   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;

  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case marqueurDeFin:
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void setup() {
  Serial.begin(9600);
  gsm.begin(9600);
  Serial.println("Initialisation...");
gsm.println("AT");
delay(1000);
gsm.println("AT+CMGF=1");         // Mode Texte
delay(2000);
  gsm.println("AT+CMGD=1,4"); // effacer les SMS en mémoire dans la carte SIM
delay(2000);
  Serial.println("Initialisation terminé");
 
}

void loop() {
  if (! ecouter()) {
    Serial.println(message);
    if (!strcmp(message, "ssid")) {
      Serial.println(F("Ssid recu"));
    }
      else if (!strcmp(message, "mdp")) {
      Serial.println(F("Mdp recu"));
      }
      else {
      Serial.println(F("pardon, pouvez vous repeter ?"));
    }
  }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 24, 2017, 12:32 pm
Vous n'avez pas le bon marqueur de fin, ça devrait être '\n' pas '#'

sinon il ne faut absolument pas mettre
Code: [Select]
  gsm.println("AT+CMGF=1");         // Mode Texte
delay(1000);
  gsm.println("AT+CMGR=1");
delay(2000);
   
dans la fonction ecouter()

on lui dit une fois dans le setup() et ça bascule dans le bon mode, ensuite on écoute.

je crois (de mémoire) qu'il faut faire un AT+CNMI pour router automatiquement les SMS vers le port série et pas les lire un par un depuis la mémoire
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 24, 2017, 09:28 pm
Ok je vais faire la modif du # (je ne m'etait pas atarder cela ne me paraissait pas primordial)

Pour les fonction AT+CMGF=1 et AT+CMGR=1 je les est mis la car en plus d'etre dans le setup (du code en string) il etait de nouveau au moment de lire le sms.

Pour la commande AT je vais voir dans le datasheet.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 25, 2017, 12:06 am
effectivement si j'ai compri les post en anglais que j'ai lu, cnmi pourait envoyer directement le message.

il se compose : AT+CNMI=1,2,0,0,0 <<< c'est dernier corresponde surement a une fonctionne mais se que j'ai trouver pour le moment est en anglais et pas compréhensible pour moi.

En le metant dans le code, "message" ne vaut plus rient (vide) et le moniteur indique +CMTI: "SM",9 se qui correspondrait a l'emplacement du message recu ...

je continu de chercher
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 25, 2017, 12:49 am
fin du 4eme jours ...  :smiley-confuse:
déprimé ou dégoûté ... pourquoi choisir :)

Alors au moins savoir pourquoi passer tout ce temps a faire tout ça (je doit être a ~100h pour le hardware et ~250h de recherche et codage en 4 mois et je commence a avoir ma femme sérieusement sur le dos lol):
Pourquoi tout le monde (oui,oui, puisque des heures sur le net a jamais trouvé des code/projet en AT sans String) utilise la class String puisque elle semble si néfaste a long thermes ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 25, 2017, 12:55 am
je continu de chercher

La meilleur traduction/explication que j'ai trouvé :




Rechercher le CNMI dans les URC

Maintenant, vous recevrez enfin les informations sur un message texte entrant. Il ressemblera à ceci:

+ CMTI: "SM", 1
CMTI signifie qu'il s'agit d'un URC lié à un message texte. SM signifie que le message a été stocké sur la carte SIM. '1' signifie qu'il a été sauvegardé sur le 1er enregistrement du stockage.

Vous avez juste besoin d'analyser cette URC pour obtenir l'index du message dans le stockage. Vous pouvez le faire comme ceci:

int index = arg0.indexOf (",");
String sms_positionInMemory = arg0.substring (index + 1, index + 3);

Maintenant, vous savez où le message est stocké et est capable de le lire Utilisez la commande AT + CMGR . La réponse contiendra le message texte.

Réponse chaîne = atc.send ("AT + CMGR =" + sms_posisionInMemory + "\ r");
Vous avez lu le message!




Donc cette fonction serait pour avoir des info sur le message comme sont emplacement par exemple afin de pouvoir activer une fonction sur un message/emplacement précis.

Donc la fonction pour lire le message est bien AT + CMGR =

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 25, 2017, 03:45 am
Il y a deux approches pour lire les sms.

Par défaut les SMS sont routés vers le stockage SIM et il faut donc écouter si on en a reçu un, si oui aller lire la case où est stocké le sms sur la carte SIM, puis faire le ménage et l'effacer

--> Il faut d'abord dire à votre module que vous êtes intéressé par le routage des événements (URC) de type sms vers le terminal.

ça se fait avec AT+CNMI=2,1 (le 2 pour dire je veux les URC de type SMS et le 1 pour dire je veux les SMS « normaux » (il y a différents types de SMS comme la class3))

- vous écoutez le port série en attente d'un message qui ressemble à + CMTI: "SM", 1
==> c'est un peu comme quand on écoutait le port série de l'esp et que l'on voyait une requête TCP entrante, on analysait alors la requête pour trouver le n° de canal et l'URL et on bâtit la réponse en conséquence. Ici un + CMTI: "SM", 1 nous dit, vous avez un SMS dans la zone de stockage « SM » (la carte sim) à la position 1, donc il faut dans l'absolu reconnaître +CMTI, trouvez la position et aller lire ce qu'il y a de rangé à cette position avec la commande AT+CMGR=1 puis ensuite faut vider la mémoire 1 de la SIM et donc envoyer AT+CMGD=1

Mais vous pouvez aussi passer en mode routage direct des SMS sur le port série avec un AT+CNMI=0,2,0,0,0 (le 2 c'est le champ <mt> de la commande qui dit de router vers le port série.  les messages ne sont pas sauvegardés, il sont perdus si rien ne les lit sur le port série). Ils sont transmis  alors directement sur le port série en notification sous la forme +CMT: "N° de tel",,date heure\r\n et suivi par le contenu du message. donc votre code dans ce cas doit écouter pour trouver le +CMT: et sur la ligne suivante vous aurez le contenu du SMS

J'ai trouvé un document en français qui en parle -> page 24-26 de ce document  (http://thibaut.legaye.free.fr/stock/irist/modemGSM/Aide_AT_V13.pdf)

Donc oui il faut choisir une approche pour la lecture, soit en mémoire avec ensuite effacement, soit juste en écoutant le flux
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 26, 2017, 01:23 am
La méthode lecture direct me parait plus approprié car :
elle ne sauvegarde pas (donc pas d'effacement)
Elle indique le numéro de tel (donc utile puisque il faut répondre a ce même numéro)
et tout cela pourras être fait en indiquant a partir de quelle caractère nous voulons analyser.

Tout parait si simple ... :) au bout du cinquième jour au point mort :/

Je vois sa mais j'ai un problème un peu bloquant ...
tout s'affiche dans le moniteur serie et se répond ... l'echo comme tu dit. mais comment ne plus avoir ca ?


Code: [Select]

pardon, pouvez vous repeter ?
ATAT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
AT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OAT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
AT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
ATAT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
AT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
AAT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
AT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
ATAT+CAT+CMGF=1


pardon, pouvez vous repeter ?
AT+CAT+CMGF=1


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?
AAT+CAT+CMGF=1


pardon, pouvez vous repeter ?


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: sachab on Oct 26, 2017, 10:41 am
Bonjour Djouns,

Ton problème est simple, il te demande juste de répéter. :)  :-[

Non mais blague à part félicitation pour ce post.
Lorsque le code sera fonctionnel, va-tu le proposer au partage, car je pense que beaucoup seraient intéressés?

A+
Sacha
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 26, 2017, 12:00 pm
Lorsque le code sera fonctionnel, va-tu le proposer au partage, car je pense que beaucoup seraient intéressés?

A+
Sacha
C'est le but, couplé au montage hardware afin d'être un appareil complet.
Mais la parti programmation est vraiment très compliquer pour moi et je passe des heure t des jour pour des fonction qui pourtant n'ont pas l'air très compliquer quand on si connait un peu plus.
n'étant qu'épauler que par jml, cela devient compliquer car ni ici ni sur recifal france on ne m'apporte de l'aide a par lui.
Si cela continu, je risque de bâcler cette partie au détriment du bon fonctionnement a long thermes.
c'est dommage. et surtout, il n'y auras pas d'intérêt a partager un projet bâcler pour ensuite avoir des retour néfaste.
Vraiment dommage vu le nombre de personne qui compte sur ce genre de projet (mais qui continu d'utiliser l'ackduino avec les problème qu'on lui connait)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: sachab on Oct 26, 2017, 05:24 pm
J'ai essayé de télécharger les fichiers de ton projet à https://www.petit-fichier.fr/2017/10/07/aquabouns/

mais rien y fait j'ai comodo qui me bloque ce lien avec un Warning: Unsafe Website Blocked!

www.petit-fichier.fr.

Je ne sais pas si mes compétences seront suffisantes, mais en regardant les fichiers, peut être qu'une idée ou suggestion surgira de mon esprit.

Part contre si tu as besoin d'aide sur le circuit imprimé ou l'electronique, j'ai de bonnes bases.

A+

Sacha
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: MicroQuettas on Oct 26, 2017, 06:05 pm
Djbouns,

Dans un projet complexe comme le vôtre, il y a plusieurs façons de faire, qui peuvent toutes marcher. Il vaut mieux qu'une seule personne vous aide plutôt que plusieurs avec chacune son idée sur la question...

Bon courage,

MicroQuettas.

PS : une question si vous avez le temps. Je crois avoir vu sur votre site que vous injectiez du CO2 dans l'aquarium ? Quel est l'effet, pas de l'eau à bulles quand même ? :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 26, 2017, 10:23 pm
J'ai essayé de télécharger les fichiers de ton projet à https://www.petit-fichier.fr/2017/10/07/aquabouns/
mais rien y fait j'ai comodo qui me bloque ce lien avec un Warning: Unsafe Website Blocked!
Je vient de le faire et pas de probleme.
Sa vient soit de ton navigateur soit de ton anti virus.
Sinon, envoie moi ton mail, normalement ca doit passer il fait moins de 10mo

Part contre si tu as besoin d'aide sur le circuit imprimé ou l'electronique, j'ai de bonnes bases.
Oui sa peut mettre utile, au moins pour vérifier que je n'ai pas fait de bêtise lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 26, 2017, 10:32 pm
Pour désactiver l'echo Généralement on envoie ATE0 (et ATE1 pour le remettre)

(suis juste sur mon smartphone donc peut pas trop,aider pour le moment, ce week end je regarderai plus précisément votre soucis)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 26, 2017, 10:48 pm
Djbouns,
Dans un projet complexe comme le vôtre, il y a plusieurs façons de faire, qui peuvent toutes marcher. Il vaut mieux qu'une seule personne vous aide plutôt que plusieurs avec chacune son idée sur la question...
tout a fait d'accord, c'est ce qui c'est passer avec l'ackduino ... un ptit bout de chaqun ... avec chaqun une facon differente de coder ...



PS : une question si vous avez le temps. Je crois avoir vu sur votre site que vous injectiez du CO2 dans l'aquarium ? Quel est l'effet, pas de l'eau à bulles quand même ? :)
vous injectiez du CO2 dans l'aquarium ?
Alors oui et non :)

En eau douce, le CO2 est injecter directement dans le bac pour alimenter en dioxyde de carbone les plantes.
Le problème du CO2 est qu'il acidifie l'eau. Il faut donc le réguler via un ph mètre et une électrovanne.
Les bac d'eau douce on un PH autour de 7.

En eau de mer, c'est different. le CO2 n'est pas injeter dans le bac mais dans un reacteur a calcaire (http://jmsnat.free.fr/site/rac+++.html) qui contient du substrat (le plus souvent de l'aragonite).
Les bac recifal on un PH autour 8.
l'aragonite ce dissout a partir d'un PH inférieur a 7. le but est donc de decendre le PH dans le Reacteur A Calcaire pour dissoudre l'aragonite qui fournira en calcium et KH l'aquarium ( le calcium et le KH  son consommer par les coraux pour construire leur squelette (http://www2.ggl.ulaval.ca/personnel/bourque/s3/3.35b.jpg) et donc "grandire"
Il faut donc bien réglé le RAC et l'apport en CO2 pour ne pas faire chuter le PH de l'aquarium.



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 26, 2017, 10:49 pm
(suis juste sur mon smartphone donc peut pas trop,aider pour le moment, ce week end je regarderai plus précisément votre soucis)
Ok JM, je continu tout de même de regarder, a la recherche du declic lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 27, 2017, 06:26 am
Vous avez quoi comme carte GPRS? (quelle version du jeu de commandes)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 27, 2017, 09:16 am
J'ai une SIM800L :
Code: [Select]
AT+GSV

SIMCOM_Ltd
SIMCOM_SIM800L
Revision:1418B03SIM800L24



Et une SIM900A:

Code: [Select]
AT+GSV

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

Étonnant qu'elle me réponde SIM800A ...


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: sachab on Oct 27, 2017, 10:55 am
J'ai téléchargé ton zip.

Félicitation pour ce codage bien organisé, même moi, je le comprends :)
Je vote pour que J-M-L fasse du récifal.

Je vais commander un écran afin de pouvoir suivre et participer dans la limite de mes compétences à l'avancer du projet.

Voici quelques réflexions, qui, si tu en retiens, risque de t'occuper un peu voir beaucoup.
- Sans parler de l'eau douce, en eau de mer plusieurs variantes existent, le fish only, le récifal, les méthodes balling, jaubert, berlinoise etc.. Afin que l'aquabouns touche le plus d'aquariophile peut être que l'activation/désactivation des options soit possibles.
- Pouvoir modifier toutes les valeurs personnalisables (levé, couché, etc...) sans devoir se connecter, par exemple grace a un encodeur rotatif ou avec un clavier. ma préférence va à l'encoder rotatif qui simplifie grandement les choses.
- Ajouter la gestions de moteurs pour pompes doseuses. Mais pas avec l'algorithme de la méthode balling qui limite l'utilisation, mais en faisant un déclenchement à une heure déterminée, par jour/ semaine, dosage, calibrage, durée etc indépendant pour chaque pompe.
- Pourquoi créer un circuit avec des relais, alors qu'il existe des cartes de relais pour arduino peu chères.
Si tu comptes vraiment créer une carte pour des relais, pourquoi ne pas mettre des relais reed qui sont silencieux et prennent peux de places.

Tes sorties pwm attaquent directement tes alim meenwell drivers intégrés ou des driver mean well style ldd-1000.

Voici mes premières réflexions/ suggections.

A+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 27, 2017, 11:27 pm
- Sans parler de l'eau douce, en eau de mer plusieurs variantes existent, le fish only, le récifal, les méthodes balling, jaubert, berlinoise etc.. Afin que l'aquabouns touche le plus d'aquariophile peut être que l'activation/désactivation des options soit possibles.
C'est un détail qui est surement a ma porté.
Je pencherais sur ce point une fois le code complet.

- Pouvoir modifier toutes les valeurs personnalisables (levé, couché, etc...) sans devoir se connecter, par exemple grace a un encodeur rotatif ou avec un clavier. ma préférence va à l'encoder rotatif qui simplifie grandement les choses.
Ce genre de chose reviendrait a avoir un écran tactile :)
Et en plus, ajouter ce genre de bouton reviendrais a etre obliger d'avoir un ecran. C'est justement le sujet que j'ai lancer ici (http://www.recifal-france.fr/sondage-gestion-d-aquarium-avec-ecran-ou-sans-ecran-t32914.html#p568540) car je penche de plus en plus vert le "sans écran" ... a suivre ...


- Ajouter la gestions de moteurs pour pompes doseuses. Mais pas avec l'algorithme de la méthode balling qui limite l'utilisation, mais en faisant un déclenchement à une heure déterminée, par jour/ semaine, dosage, calibrage, durée etc indépendant pour chaque pompe.
J'ai pas ou peu parlée de mon "cahier des charges" fixer de par mes différente expérience arduino/récifal.
Cette automate ne gère que des appareil "secondaire" si je puits dire ...

Plus précisément, je ne veut pas confier la gestion de la température a l'arduino.(le chauffage est gérer directement par sonde interne a celui ci ou alors par un mh1210 ou équivalent). l'arduino n'as comme fonction que de relever la température et dans le cas ou la température du bac dépasse la limite max, d'ouvrir un relais (relais non alimenté = fermé = ON)

Je ne veut pas gérer l'osmolation par arduino (ceci est gérer de manière mécanique/électronique sur le C.I. sans passer par l'arduino)

Je ne veut pas gérer l'allumage/extinction de l'écumeur par l'arduino (ceci est gérer de manière mécanique/électronique sur le C.I. sans passer par l'arduino)

Je ne veut pas gérer pompe de remonté par arduino (l'arduino n'as comme fonction que de couper la remonté lorsque l'on active le nourrissage manuel (cube congeler par exemple) donc nous somme a coté a ce moment la (relais non alimenté = fermé = pompe ON)


Tout ces points n'ayant comme but qu'il n'y est aucun ( ne jamais dire jamais :)) risque pour le bac en cas de BUG (comme j'ai subit avec l'ackduino, bug quand osmolation allumer = vidage de la réserve = chute salinité = débordement = pompe osmolation cramé = disjonction ... Ou bug quand chauffage éteint ... en pleine hiver ...)
Bref, cela peut avoir une contrainte pour certain (même si je vois pas en quoi) mais au prix de notre bac ...



- Pourquoi créer un circuit avec des relais, alors qu'il existe des cartes de relais pour arduino peu chères.
Si tu comptes vraiment créer une carte pour des relais, pourquoi ne pas mettre des relais reed qui sont silencieux et prennent peux de places.
Si tu regarde bien mon C.I, il ne comporte pas de relais.
Encore un point sur le quelle je ne transigerait pas, PAS DE 220V EN DEHORS DU TABLEAU.
Ces pour cette raison que le circuit est la "a moitier", il suffis de brancher ces sorties dans le tableau a des relais, chez moi des Finder
(http://www.conrad.fr/medias/global/ce/3000_3999/3800/3800/3804/1217711_BB_00_FB.EPS_1000.jpg)

Mais chacun pourras faire comme il le veut niveau montage électrique. si tu regarde bien le C.I il est possible de se bracher sur les sortie des l'arduino correspondante avant de rentrée dans le circuit relais (il suffit de ne pas alimenter en 12v la partie relais)




Tes sorties pwm attaquent directement tes alim meenwell drivers intégrés ou des driver mean well style ldd-1000.
Tout les branchement vu jusque a présent était comme cela. babyfish ou autre egalement, non ?




Afin de pouvoir si retrouver, je te propose que la partie "Hardware" soit discuter/partager sur le poste de mon bac (http://www.recifal-france.fr/400l-de-djbouns-t22449-378.html#p566418) afin de ne pas tout mélanger ici.
J-M-L, tu y est le bienvenu :)  :)  :)




A+
[/quote]
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 28, 2017, 12:58 am
C'est un détail qui est surement a ma porté.
Je pencherais sur ce point une fois le code complet.
fait sur la page WEB (https://img4.hostingpics.net/pics/398636Sanstitre.jpg) :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 28, 2017, 04:46 pm
revenons a nos moutons ...

j'ai fait quelque modif et rechercher la fonction AT+CNMI=0,2,0,0,0.
J'ai bien un retour du numero de tel qui envoyai le sms + date et heure mais pas le sms en lui meme.
pour avoir le sms il faut faire AT+CNMI=2,2,0,0,0.
Donc j'ai bien le SMS qui safiche dans la console mais meme quand le message est Ssid ou Mdp, le serial affiche "pardon, pouvez vous repeter ?"

J'ai bien suprimé l'echo mais j'ai du coup les reponse sans les question lol
Code: [Select]
pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?


pardon, pouvez vous repeter ?
OK

pardon, pouvez vous repeter ?




Le code donne ca ... j'ai l'impression de m'approcher de la fin du tunnel mais y a encore un gros precipisse a franchir lol

Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 50;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'



boolean ecouter()
{   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void setup() {
  Serial.begin(9600);
  gsm.begin(9600);
  Serial.println("Initialisation...");
gsm.println("AT");
delay(1000);


gsm.println("AT+CMGDA=\"DEL READ\"");
delay(1000);

gsm.println("AT+CNMI=2,2,0,0,0");
delay(1000);

gsm.println("AT+CSAS");
delay(1000);

gsm.println("AT+CMGF=1"); // Mode Texte
delay(1000);

Serial.println("Initialisation terminé");
 
}

void loop() {
  if (! ecouter()) {
    Serial.println(message);
    if(!strcmp(message,"Ssid")) {
      Serial.println(F("Ssid recu"));
    }
      else if (!strcmp(message,"Mdp")) {
      Serial.println(F("Mdp recu"));
      }
      else {
      Serial.println(F("pardon, pouvez vous repeter ?"));
    }
  }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 28, 2017, 05:58 pm
J'ai réussi a avoir les réponse correspondante a mes SMS en faisant sa :
Code: [Select]
if(strncmp(message,"Ssid",4)==0) {
     ssid = strtok(message+5, "=");
     Serial.println(ssid);     
     Serial.println(F("Ssid recu"));
    }
      else if (strncmp(message,"Mdp",3)==0) {
     mdp = strtok(message+4, "=");
     Serial.println(mdp);       
      Serial.println(F("Mdp recu"));
      }
      else {
      Serial.println(F("pardon, pouvez vous repeter ?"));


Donc la, il lit le sms, trouve si il s'agit du ssid ou mdp, et "pioche" les caractères correspondant modifi le char ssid ou mdp.

Une bonne avancé

Il me reste a faire pareille avec le numéro de tel pour pouvoir répondre par sms OK
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 28, 2017, 06:50 pm
Bonsoir

je n'ai pas avec moi de quoi tester réellement si ça va fonctionner mais jetez un oeil à un truc comme ça

prévu pour avoir le SIM800 sur Serial1, fonctionnant à 9600 bauds et la console à 115200

comme dans le tuto ESP il y a une fonction gsmPrintlnATCommand() pour envoyer une commande AT, qui attend une réponse passée aussi en paramètre, pendant un certain temps (et qui affiche le contenu de ce que l'on lit si on dit "vrai" en dernier param). l'attente se fait en appelant la fonction waitForString()


il y a une fonction un peu générique getGSMLine() qui va lire le port Série du module pour bâtir une phrase jusqu'à un marqueur


Le code ci dessous est supposé configurer le module GPRS puis détecter ce qui arrive. S'il reconnait une réponse alors il essaye de l'analyser.

j'ai mis un petit bout de code qui permet de taper dans la console série des commandes AT pour voir le résultat, par exemple si vous tapez AT+CSQ alors le code reconnait le début de la réponse +CSQ: xxx,yyy et extrait puis vous affiche xxx et yyy


Code: [Select]
#define gsm Serial1

const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 1000ul;

const byte maxMessageSize = 200;
char GSM_MessageLine[maxMessageSize + 1]; // +1 as we want to be able to store the trailing '\0'

// --------------------------------------
// gsmPrintlnATCommand executes an AT commmand by adding at the end a CR LF
// then it checks if endMarker string is receivedon the GSM Serial port
// for max duration ms returns a boolean stating if the marker was found
// with the verbose option, the output from the GSM is also printed to Serial
// --------------------------------------

boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

// --------------------------------------
// gsmPrintATCommand or gsmpWriteATCommand is used when you don't want to send the CR LF
// at the end of the commmand line; use it to build up a multi part command
// same syntax as print as they are Variadic Macros using print or write
// --------------------------------------
#define gsmPrintATCommand(...) gsm.print(__VA_ARGS__)
#define gsmWriteATCommand(...) gsm.write(__VA_ARGS__)


// --------------------------------------
// read a line from gsm, ignore '\r' and returns true if '\n' is found
// --------------------------------------

boolean getGSMLine()
{
  static byte indexMessage = 0;
  boolean incomingMessage = true;

  while (gsm.available() && incomingMessage) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          GSM_MessageLine[indexMessage] = '\0'; // trailing NULL char for a correct c-string
          indexMessage = 0; // get ready for next time
          incomingMessage = false;
          break;
        case '\r': // don't care about this one
          break;
        default:
          if (indexMessage <= maxMessageSize - 1) GSM_MessageLine[indexMessage++] = (char) c; // else ignore it..
          break;
      }
    }
  }
  return !incomingMessage;
}

// --------------------------------------
// waitForString wait max for duration ms whilst checking if endMarker string is received
// on the GSM Serial port returns a boolean stating if the marker was found
// --------------------------------------

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}


void setup() {
  Serial.begin(115200);
  gsm.begin(9600); // suivant votre config, essayez 9600 19200 38400 57600 74880 115200

  // prévoir éventuellement AT+CPIN=1234 pour rentrer le PIN

  if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }

  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }

  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, false)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }

  /*
    On passe en Message en verbal (ATV1)
      OK          -->   Commande acceptÈe
      RING        -->   Appel entrant
      NO CARRIER  -->   déconnexion par perte de porteuse
      ERROR       -->   Commande non acceptée
      BUSY        -->   Distant occupé
      NO ANSWER   -->   Pas de réponse du distant
  */
  if (!gsmPrintlnATCommand("ATV1", OKString, oneSecond, false)) {
    Serial.print(F("Erreur Message en Verbal"));
    dieHere();
  }

  // exemple pour envoyer des commandes

  if (!gsmPrintlnATCommand("AT+CNMI=0,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }


  Serial.println("Initialisation terminé");
}


void loop()
{
  int r;

  // on lit une commande AT que l'utilisateur tape sur la console série et on l'envoie au gsm
  while (Serial.available()) {
    r = Serial.read();
    if (r != -1) gsm.write((char) r);
  }

  if (getGSMLine()) {
    // ici on peut tester si la réponse est quelque chose d'intéressant

    // ********************************************
    // par exemple analyse de la réponse à AT+CSQ
    if (!strncmp(GSM_MessageLine, "+CSQ:", 5)) { // 5 parce que "+CSQ:" c'est 5 caractères, on compare le début de la chaîne
      int rssi, ber;
      if ( sscanf(GSM_MessageLine, "+CSQ: %d,%d", &rssi, &ber) == 2) {
        Serial.print(F("Qualité de reception = ")); Serial.println(rssi);
        Serial.print(F("Code Erreur = ")); Serial.println(ber);
      }
    }


    // ********************************************
    // TEST RECEPTION D'UN SMS
    // +CMT: "+33620000000",,"01/03/22,16:33:31+00"<CRLF>
    // texte bla bla bla<CRLF>
    //
    else if (!strncmp(GSM_MessageLine, "+CMT:", 5)) {// 5 parce que "+CMT:" c'est 5 caractères, on compare le début de la chaîne
      char phoneNb[30];
      if ( sscanf(GSM_MessageLine, "+CMT: \"%[+0-9]s\"", phoneNb) == 1) {
        Serial.print(F("SMS de = ")); Serial.println(phoneNb);
        while (!getGSMLine()); // on attend le texte du SMS
        Serial.print(F("Message = [")); Serial.print(GSM_MessageLine); Serial.println(F("]"));
      }
    }

    // ********************************************
    // Autres test...
    else if (!strncmp(GSM_MessageLine, "+TOTO:", 6)) {


    } else {
      Serial.print(F("ignore ["));
      Serial.print(GSM_MessageLine);
      Serial.println(F("]"));
    }
  }


}


j'ai utiliser sscanf() pour la démo - mais vaut mieux passer par des fonctions moins gourmandes en mémoire comme vous le faites avec strtok() par exemple

dites moi si ça aide

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 28, 2017, 07:27 pm
Toute la partie initialisation, NICKEL !

Pour le reste, quand je tape +CSQ: xxx,yyy j'ai error.

Pour la fonction strtok j'y suis presque ... j'arrive a récupérer mon numéro (le numéro émetteur du sms) sous la forme +336*********" pour cela je fait tel = strtok(message+8,",") mais il faut que je coupe au " et non pas au ,  mais quand on met tel = strtok(message+8,""") sa marche pas.
Je croit que quand cela seras bon, le code serait fonctionnel (ou presque)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 28, 2017, 08:30 pm
faut taper AT+CSQ dans la console, ça va l'envoyer au module qui doit répondre


Quote
mais quand on met tel = strtok(message+8,""") sa marche pas.
il ne faut pas oublier de mettre un '\' pour que le guillemet soit pris en compte dans une chaîne "\""


essayez ce code pour voir strtok()

Code: [Select]
char reponse1[] = "+CMT: \"+33600123400\",,\"17/10/28,20:50:31+01\"";
char reponse2[] = "+CMT: \"+33600123400\",,\"17/10/28,20:50:31+01\"";
char *ptr;

void setup() {
  int i;

  Serial.begin(115200);

  ptr = strtok(reponse1, ",\"");
  i = 1;
  while (ptr) {
    Serial.print(i++); Serial.print("\t"); Serial.println(ptr);
    ptr = strtok(NULL, ",\"");
  }
 
  Serial.println(F("----------------"));

  ptr = strtok(reponse2, ",/:\"");
  i = 1;
  while (ptr) {
    Serial.print(i++); Serial.print("\t"); Serial.println(ptr);
    ptr = strtok(NULL, ",/:+\"");
  }

}

void loop() {}


suivant les caractères séparateurs que l'on donne on peut couper plus ou moins finement la phrase d'entrée. vous devriez voir cela sur la console

1   +CMT:
2   +33600123400
3   17/10/28
4   20:50:31+01
----------------
1   +CMT
2   
3   33600123400
4   17
5   10
6   28
7   20
8   50
9   31
10  01



ça devrait vous donner des idées :) (un petit coup de strcpy() pour récupérer la chaîne ou un petit coupe de atoi() pour lire un entier (pour le jour et l'heure si vous voulez le détail)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 28, 2017, 10:07 pm
J'ai enfin réussi a récupérer le numéro de tel correctement puis a le remettre comme numéro pour envoyer un sms avec strncmp

Je n'est pas besoin de connaitre la date ni l'heure, le seul but est de récupérer le numéro de tel

du coup j'en suis la

Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;   
char *mdp ;
char *tel;
char *SMS;


const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 3000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
     if (gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, false)) {
     gsm.print("AT+CMGS=");
     gsm.print(tel); 
     gsm.println();
     delay(500); 
     gsm.print(SMS);
     delay(500);
     gsm.print((char)26);
     }
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGDA=\"DEL READ\"", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {



    if (!strncmp(message,"+CMT:",5)){
      Serial.println(message);
     tel = strtok(message+6,(","));
     SMS = "tel recu :";
     Serial.println(SMS);
     envoiesms();
     
     }
     
    else if(strncmp(message,"Ssid",4)==0) {
     ssid = strtok(message+5, "=");
     SMS = "SSID RECU : ",(ssid);
     Serial.println(SMS);
     envoiesms();
     }
    }
     else if (strncmp(message,"Mdp",3)==0) {
     mdp = strtok(message+4, "=");
     SMS = "MDP RECU : ",(mdp);
     Serial.println(SMS);
     envoiesms();
      }

   
     else {
      SMS = "instruction pas comprise";
      Serial.println(SMS);
      envoiesms();
    }
  }


sa marche partiellement ...
Une fois sur deux je reçoit pas de sms mais il y a bien du mouvement dans la console... je comprend pas pourquoi ...

Par contre, si il ny a pas de sms arrivé, le loop ne devrait pas continue non ? il il me lit en boucle les dernier "else" instruction non comprise.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 28, 2017, 10:18 pm
essayez ce code pour voir strtok()
utiliser cela serait peut être mieux entre autre dans le cas d'un numéro de tel ans un format différent (je pense déjà a exporter mdr)

Mais je ne comprend pas comment ensuite récupérer la chaîne numéro 2.

Je continu de chercher mais je ne comprend pas pourquoi sa repond un coup sur deux et pourquoi se loop continuel des lors qu'un sms est recu ...

Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;   
char *mdp ;
char *tel;
char *SMS;


const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 2000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
     
     gsm.print("AT+CMGS=");
     gsm.print(tel); 
     gsm.println();
     delay(500); 
     gsm.print(SMS);
     delay(500);
     gsm.print((char)26);
     
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGD=1,4", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {
    if (!strncmp(message,"+CMT:",5)){
     Serial.println(message);
     tel = strtok(message+6,(","));
     SMS = "sms recu";
     Serial.println(SMS);
     envoiesms();
    }
         
    else if(strncmp(message,"Ssid",4)==0) {
     ssid = strtok(message+5, "=");
     SMS = "SSID RECU : ",(ssid);
     Serial.println(SMS);
     delay(500);
     envoiesms();
     }
   
     else if (strncmp(message,"Mdp",3)==0) {
     mdp = strtok(message+4, "=");
     SMS = "MDP RECU : ",(mdp);
     Serial.println(SMS);
     delay(500);
     envoiesms();
      }
   
     else {
      SMS = "instruction pas comprise";
      Serial.println(SMS);
      delay(500);
      envoiesms();
    }
    gsm.println("AT+CMGD=1,4");
    Serial.println("sms effacer");
    }
  }




Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 28, 2017, 11:21 pm
dans votre vrai code il ne faudra pas mettre de
Code: [Select]
void dieHere()
{
  while (true);
}
il faudra gérer quand un truc ne fonctionne pas (reset / rebooter le composant / désactiver la fonction)

Code: [Select]
const uint32_t oneSecond = 3000ul; --> changez le nom de la variable si ce n'est plus une seconde...
Code: [Select]
const uint32_t attente3s = 3000ul;par exemple


dans la fonction boolean ecouter() vous devriez tester si vous avez reçu '\r' et ne pas l'ajouter au message car il ne sert à rien
Code: [Select]
boolean ecouter()
{
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        case '\r': // on laisse tomber le <CR>
          break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}



ce bout de code (vous pourriez utiliser les macros que j'avais proposé)
Code: [Select]
void envoiesms() {
  if (gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, false)) {
     gsm.print("AT+CMGS=");
     gsm.print(tel); 
     gsm.println();
    delay(500);
    gsm.print(SMS);
    delay(500);
    gsm.print((char)26);
  }
}
vous pouvez simplifier le début en
Code: [Select]
    gsm.print("AT+CMGS=");
    gsm.println(tel);
et virer le gsm.println();

il n'y a pas besoin d'attendre 1/2 secondes avant d'envoyer le caractère de fin de SMS    gsm.print((char)26); - vous pouvez virer le delay(500);







char *SMS;
...
      SMS = "SSID RECU : ", (ssid);
...
    SMS = "MDP RECU : ", (mdp);
ça ne va pas faire ce que vous voulez

vous devriez déclarer SMS comme un tableau de caractère suffisamment long pour votre message le plus long et faire un strcpy() et un strcat() pour rajouter des trucs dans la chaîne (en fait comme quand vous envoyez le SMS vous ne passez pas dans la boucle d'attente de message, vous pouvez sans doute utiliser temporairement ce tableau pour ne pas trop manger de mémoire


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 08:47 am
dans votre vrai code il ne faudra pas mettre de
Code: [Select]
void dieHere()
{
  while (true);
}

il faudra gérer quand un truc ne fonctionne pas (reset / rebooter le composant / désactiver la fonction)
J'y avait penser mais cela ne me paraissait pas prioritaire, je pense utiliser la fonction RESET


Code: [Select]
const uint32_t oneSecond = 3000ul;
 --> changez le nom de la variable si ce n'est plus une seconde...
Code: [Select]
const uint32_t attente3s = 3000ul;
par exemple
oui sa fait partie des chose que je trifouille lors de mes test sans remettre après

dans la fonction boolean ecouter() vous devriez tester si vous avez reçu '\r' et ne pas l'ajouter au message car il ne sert à rien
Code: [Select]
boolean ecouter()
{
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        case '\r': // on laisse tomber le <CR>
          break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

ok je vait voir



ce bout de code (vous pourriez utiliser les macros que j'avais proposé)
Code: [Select]
void envoiesms() {
  if (gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, false)) {
     gsm.print("AT+CMGS=");
     gsm.print(tel);  
     gsm.println();
    delay(500);
    gsm.print(SMS);
    delay(500);
    gsm.print((char)26);
  }
}

 vous pouvez simplifier le début en
Code: [Select]
  gsm.print("AT+CMGS=");
    gsm.println(tel);

et virer le gsm.println();

il n'y a pas besoin d'attendre 1/2 secondes avant d'envoyer le caractère de fin de SMS gsm.print((char)26); - vous pouvez virer le delay(500);
Oui sa fait encore partie des chose je je n'est pas remis en place







char *SMS;
...
      SMS = "SSID RECU : ", (ssid);
...
    SMS = "MDP RECU : ", (mdp);
ça ne va pas faire ce que vous voulez

vous devriez déclarer SMS comme un tableau de caractère suffisamment long pour votre message le plus long et faire un strcpy() et un strcat() pour rajouter des trucs dans la chaîne (en fait comme quand vous envoyez le SMS vous ne passez pas dans la boucle d'attente de message, vous pouvez sans doute utiliser temporairement ce tableau pour ne pas trop manger de mémoire
oui, ca ne fait pas se que je veut lol
faire un tableau ... oula ... faut je retourne voir http://www.cplusplus.com
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 29, 2017, 09:16 am
Code: [Select]
char SMS[160]; // tableau de caractères, réserve 160 cases mémoires (octets)
...
strcpy(SMS, "SSID="); // écrit SSID= au début du tableau suivi du '\0'
strcat(SMS, ssid); // rajoute ssid à la suite, si ssid est bien une chaîne de caractères


Mais ce que je disais c'est au lieu de recréer encore un buffer pour SMS, utilisez celui déjà existant pour la réception sur le port série
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 09:23 am
donc :

Code: [Select]
 SMS = "SSID RECU : ";
     strncat(SMS,ssid,50);

au lieu de ca
Code: [Select]
SMS = "SSID RECU : ", (ssid);

Ça fonctionne sans que j'ai utilisé de tableau (chose que je ne maîtrise pas vraiment, même si j'ai compris le principe d'index :) )

Cela pose t'il problème de faire comme ça ?


dans la fonction boolean ecouter() vous devriez tester si vous avez reçu '\r' et ne pas l'ajouter au message car il ne sert à rien
Je ne vois pas ou je l'ai ajouter au message ... ni dans se que je tape sur mon tel :) :) :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 09:27 am
Code: [Select]
char SMS[160]; // tableau de caractères, réserve 160 cases mémoires (octets)
...
strcpy(SMS, "SSID="); // écrit SSID= au début du tableau suivi du '\0'
strcat(SMS, ssid); // rajoute ssid à la suite, si ssid est bien une chaîne de caractères


Mais ce que je disais c'est au lieu de recréer encore un buffer pour SMS, utilisez celui déjà existant pour la réception sur le port série
Ce qui veut dire qu'a chaque fois qu'il est lu strcpy(SMS,"fff") la tableau "sms"est effacer et recommence a zero ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 09:31 am
j'ai toujours le loop qui envoie message recu des qu'il a recu un sms
ne tient pas compte de se message, j'ai trouvé
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 29, 2017, 10:37 am
écrire cela n'est pas bon
Code: [Select]
char * SMS;
...
SMS = "SSID RECU : ";
strncat(SMS,ssid,50);


ce qu'il se passe c'est que SMS est un pointeur générique vers la mémoire. mais il n'y a aucune case allouée pour stocker du contenu, vous dites simplement que SMS est variable pour stocker l'adresse d'une zone en mémoire qui va contenir des caractères.

Quand vous effectuez SMS = "SSID RECU : "; vous dites au compilateur stocke en mémoire quelque part la chaîne "SSID RECU : " et initialise le pointeur SMS comme pointant sur le premier caractère. ça c'est bon. Mais vous n'avez réservé aucune case mémoire supplémentaire, il se peut qu'il y ait d'autres variables de votre programme en mémoire juste après les cases réservées pour "SSID RECU : ". Donc quand vous faites ensuite strncat(SMS,ssid,50); vous allez écraser ce qu'il y a en mémoire juste après la fin de la chaîne de caractère et ça va mettre le souc dans votre code et c'est super dur ensuite à débugger

--> principe: quand on veut écrire une chaîne de caractère en mémoire, il faut réserver un certain nombre de cases mémoires (octets) pour écrire dedans tout ce que l'on veut - SANS DEBORDER. pour cela on crée un tableau
Code: [Select]
char SMS[160]; // tableau de caractères, réserve 160 cases mémoires (octets)
 et on peut ranger dans le tableau les caractères les uns après les autres pour faire sa phrase. attention en C et C++ une chaîne de caractère bien formée se termine par le caractère null '\0' donc il faut toujours prévoir une case pour ce caractère même si on ne le voit pas. Par exemple
Code: [Select]
char toto[] = "bonjour";
va réserver dans le tableau toto 7 octets pour les lettres plus un octet pour le null à la fin, donc c'est un tableau de 8 caractères

OK ?

Quote
Ce qui veut dire qu'a chaque fois qu'il est lu strcpy(SMS,"fff") la tableau "sms"est effacer et recommence a zero ?
oui strcpy() commence à stocker au niveau du pointeur et rajoutera le '\0' à la fin tout seul. quand vous faites ensuite strcat() la fonction cherche où est le '\0', et écrit le texte en commençant par la case contenant le '\0' et remet un '\0' tout à la fin

(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=231464)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 10:44 am
Ok jean marc,
J'avais fais cette modif et j'ai commencer a avoir les problème  ci dessous, du coup j'ai trifouillé :(
Je refait les modif, je vois et jvous dis.

Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;  
char *mdp ;
char *tel;
char *SMS;


const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 2000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{  
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
         // case '\r':
         // break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
    
     Serial.print("AT+CMGS=");
     Serial.println(tel);  
     delay(500);  
     Serial.print(SMS);
     Serial.print((char)26);
     if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("erreur effacement"));
    }
     Serial.println("sms effacer");
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {
Serial.println(message);
    
    if (!strncmp(message,"+CMT:",5)){
     tel = strtok(message+6,(","));
     //Serial.println(tel);
     SMS = "sms recu";
     //Serial.println(SMS);
     }
          
    else if(strncmp(message,"Ssid",4)==0) {
     ssid = strtok(message+5, "=");
     SMS = "SSID RECU : ";
     strncat(SMS,ssid,50);
     //Serial.println(SMS);
     delay(500);
     envoiesms();
     }
    
     else if (strncmp(message,"Mdp",3)==0) {
     mdp = strtok(message+4, "=");
     SMS = "SSID RECU : ";
     strncat(SMS,mdp,50);
     //Serial.println(SMS);
     delay(500);
     envoiesms();
      }
  
     else {
      //SMS = "?";
      //Serial.println(SMS);
      //delay(500);
      envoiesms();
    }
    
  }  
    
  }


et voila ce que j'ai dans le moniteur

Code: [Select]
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK

OK

OK

OK
Initialisation terminé


AT+CMGS=
+CMT: "+33********","","17/10/29,10:30:20+04"
Ssid hfgjh

OK
sms effacer


Alors que je devrais avoir :

Code: [Select]
AT+CMGS="+33********"
SSID RECU : hfgjh

OK
sms effacer


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 10:50 am
J'ai remis comme tu me l'avais conseillé

Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;   
char *mdp ;
char *tel;
char SMS[100];


const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 2000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
          //case '\r':
          //break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
     
     Serial.print("AT+CMGS=");
     Serial.println(tel); 
     delay(500); 
     Serial.print(SMS);
     Serial.print((char)26);
     if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("erreur effacement"));
    }
     Serial.println("sms effacer");
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {
    if (!strncmp(message,"+CMT:",5)){
     tel = strtok(message+6,(","));
     //Serial.println(tel);
     strcpy(SMS, "sms recu");
     //Serial.println(SMS);
     }
         
    else if(strncmp(message,"Ssid",4)==0) {
     ssid = strtok(message+5, "=");
     strcpy(SMS, "SSID recu :");
     strncat(SMS,ssid,50);
     //Serial.println(SMS);
     delay(500);
     envoiesms();
     }
   
     else if (strncmp(message,"Mdp",3)==0) {
     mdp = strtok(message+4, "=");
     strcpy (SMS, "Mdp recu :");
     strncat(SMS,mdp,50);
     //Serial.println(SMS);
     delay(500);
     envoiesms();
      }
   
     else {
      strcpy (SMS, "Instructions non comprise");
      //Serial.println(SMS);
      //delay(500);
      envoiesms();
    }
   
  } 
   
  }


Et quand j'envoie sms j'ai sa :

Code: [Select]
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK

OK

OK

OK
Initialisation terminé
AT+CMGS=
Instructions non comprise+CMT: "+336*******","","17/10/29,10:46:13+04"
Ssid hfgjh

OK
sms effacer


Il ne lit plus la ligne +CMT et du coup lit le sms, trouve Ssid et envoie le sms, bien sur le numero de tel n'est pas enregistré du coup ...

Je n'arrive pas a comprendre pourquoi la ligne + cmt apparaît après ... et se cumul a Instructions non comprise

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 29, 2017, 11:12 am
si vous voulez conserver en mémoire le No de tel il ne faut pas un pointeur dans la ligne qui sert à la réception, car au prochain tour c'est effacé. il faut que vous déclariez aussi tel comme un tableau dans lequel vous dupliquez les données

regardez cet exemple:

Code: [Select]
char reponse[] = "+CMT: \"+33600123400\",,\"17/10/28,20:50:31+01\"";

char *ptr;
const byte maxTelSize = 30;
char tel[maxTelSize + 1]; // +1 pour le caractère nul en fin de chaîne

void setup() {
  int i;

  Serial.begin(115200);

  tel[0] = '\0'; // initalise à vide

  if (!strncmp(reponse, "+CMT: ", 6)) {
    ptr = strtok(reponse, ",\"");  // met un '\0' sur le premier guillemet et ptr pointe sur +CMT:
    ptr = strtok(NULL, ",\"");     // met un '\0' sur le second guillemet et ptr pointe sur +33600123400
    if (ptr) {
      strncpy(tel, ptr, maxTelSize);
      tel[maxTelSize] = '\0'; // juste au cas où le N° de tel était trop long, la fonction strncpy ne met pas le null en fin de chaîne
      Serial.print("J'ai le No de tel suivant: [");
      Serial.print(tel);
      Serial.println("]");
    }
  } else {
    Serial.println("ce n'est pas une commande +CMT");
  }
}

void loop() {}


ça va afficher

J'ai le No de tel suivant: [+33600123400]
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 11:44 am
oui ton code affiche bien le numéro
Et une fois dans mon code, même chose qu'avant ...
Code: [Select]
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK

OK

OK

OK
Initialisation terminé
AT+CMGS=
Instructions non comprise+CMT: "+336*******","","17/10/29,11:43:57+04"
Ssid hfgjh

OK
sms effacer


Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;   
char *mdp ;
char SMS[100];
char *ptr;
const byte maxTelSize = 30;
char tel[maxTelSize + 1]; // +1 pour le caractère nul en fin de chaîne



const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 2000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
          //case '\r':
          //break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
     
     Serial.print("AT+CMGS=");
     Serial.println(tel); 
     delay(500); 
     Serial.print(SMS);
     Serial.print((char)26);
     if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("erreur effacement"));
    }
     Serial.println("sms effacer");
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {

if (!strncmp(message, "+CMT: ", 6)) {
    ptr = strtok(message, ",\"");  // met un '\0' sur le premier guillemenet et ptr pointe sur "+CMT: "
    ptr = strtok(NULL, ",\"");      // met un '\0' sur le second guillemenet et ptr pointe sur "+33600123400"
    if (ptr) {
      strncpy(tel, ptr, maxTelSize);
      tel[maxTelSize] = '\0'; // juste au cas où le N° de tel était trop long, la fonction strncpy ne met pas le null en fin de chaîne
    }
}
   
    /*if (!strncmp(message,"+CMT:",5)){
     tel = strtok(message+6,(","));
     //Serial.println(tel);
     strcpy(SMS, "sms recu");
     //Serial.println(SMS);
     }*/
         
    else if(strncmp(message,"Ssid",4)==0) {
     ssid = strtok(message+5, "=");
     strcpy(SMS, "SSID recu :");
     strncat(SMS,ssid,50);
     //Serial.println(SMS);
     delay(500);
     envoiesms();
     }
   
     else if (strncmp(message,"Mdp",3)==0) {
     mdp = strtok(message+4, "=");
     strcpy (SMS, "Mdp recu :");
     strncat(SMS,mdp,50);
     //Serial.println(SMS);
     delay(500);
     envoiesms();
      }
   
     else {
      strcpy (SMS, "Instructions non comprise");
      //Serial.println(SMS);
      //delay(500);
      envoiesms();
    }
   
  } 
   
  }
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 02:13 pm
en retirant la fin du code (ou l'on cherche si ssid ou mds) le numero de tel est bien lu ... mais me repond par sms recu (puis vide) au lieu de sms recu : "le sms recu."

Y a un truc pas claire la dedant

Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;   
char *mdp ;
char SMS[100];
char *ptr;
const byte maxTelSize = 30;
char tel[maxTelSize + 1]; // +1 pour le caractère nul en fin de chaîne



const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 2000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
          //case '\r':
          //break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
     
     gsm.print("AT+CMGS=\"");
     gsm.print(tel);
     gsm.println("\"");   
     delay(5000); 
     gsm.println(SMS);
     gsm.println((char)26);
     gsm.println();
     delay(1000);
     if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("erreur effacement"));
    }
     else Serial.println("sms effacer");
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {

if (!strncmp(message, "+CMT:", 5)) {
    ptr = strtok(message, ",\"");  // met un '\0' sur le premier guillemenet et ptr pointe sur "+CMT: "
    ptr = strtok(NULL, ",\"");      // met un '\0' sur le second guillemenet et ptr pointe sur "+33600123400"
    if (ptr) {
      strncpy(tel, ptr, maxTelSize);
      tel[maxTelSize] = '\0'; // juste au cas où le N° de tel était trop long, la fonction strncpy ne met pas le null en fin de chaîne
    }
    envoiesms();
}
     strcpy(SMS, "sms recu :");
     strncat(SMS,message,50);

  }}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 29, 2017, 02:14 pm
 :smiley-sad:  :smiley-sad:  :smiley-sad:
Chui a bout  :'(
Sa fait 10 jours chui la dessus
Sa marche a moitié après sa marche plus du tout.
et rebelote :(
(https://s-i.huffpost.com/gen/4393678/images/n-THE-MATRIX-628x314.jpg)








Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 30, 2017, 12:03 am
en retirant la fin du code (ou l'on cherche si ssid ou mds) le numero de tel est bien lu ... mais me repond par sms recu (puis vide) au lieu de sms recu : "le sms recu."

Y a un truc pas claire la dedant

Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;   
char *mdp ;
char SMS[100];
char *ptr;
const byte maxTelSize = 30;
char tel[maxTelSize + 1]; // +1 pour le caractère nul en fin de chaîne



const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 2000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{   
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
          //case '\r':
          //break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
     
     gsm.print("AT+CMGS=\"");
     gsm.print(tel);
     gsm.println("\"");   
     delay(5000); 
     gsm.println(SMS);
     gsm.println((char)26);
     gsm.println();
     delay(1000);
     if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("erreur effacement"));
    }
     else Serial.println("sms effacer");
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {

if (!strncmp(message, "+CMT:", 5)) {
    ptr = strtok(message, ",\"");  // met un '\0' sur le premier guillemenet et ptr pointe sur "+CMT: "
    ptr = strtok(NULL, ",\"");      // met un '\0' sur le second guillemenet et ptr pointe sur "+33600123400"
    if (ptr) {
      strncpy(tel, ptr, maxTelSize);
      tel[maxTelSize] = '\0'; // juste au cas où le N° de tel était trop long, la fonction strncpy ne met pas le null en fin de chaîne
    }
    envoiesms();
}
     strcpy(SMS, "sms recu :");
     strncat(SMS,message,50);

  }}

Vous appelez envoiesms() avant de mettre me message dans la variable SMS
Code: [Select]
tel[maxTelSize] = '\0'; // juste au cas où le N° de tel était trop long, la fonction strncpy ne met pas le null en fin de chaîne
    }
    envoiesms(); // envoi du message
}
     strcpy(SMS, "sms recu :"); // pourquoi c'est faut ensuite?
     strncat(SMS,message,50);
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 30, 2017, 10:01 am
Je vois plus rien a force de tout essayer  :(  et jpasse pour un ksoss en plus  :smiley-confuse:

donc une fois remis dans l'ordre, en ne laissant que la condition
Code: [Select]
if (!strncmp(message, "+CMT:", 5)) {
le code donne ça  :
Code: [Select]
#define gsm Serial1


const byte tailleMessageMax = 200;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'

char *ssid ;  
char *mdp ;
char SMS[100];
char *ptr;
const byte maxTelSize = 30;
char tel[maxTelSize + 1]; // +1 pour le caractère nul en fin de chaîne



const char * ATString = "AT";
const char * OKString = "\r\nOK\r\n";

const uint32_t oneSecond = 2000ul;


boolean gsmPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}

boolean ecouter()
{  
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;
  while (gsm.available() && messageEnCours) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
          //case '\r':
          //break;
        default:
          if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          break;
      }
    }
  }
  return messageEnCours;
}

void envoiesms(){
    
     gsm.print("AT+CMGS=\"");
     gsm.print(tel);
     gsm.println("\"");  
     delay(5000);  
     gsm.print(SMS);
     gsm.println((char)26);
     delay(1000);
     if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("erreur effacement"));    
    }
     else Serial.println("sms effacer");
}


void setup() {
Serial.begin(115200);
gsm.begin(9600);
if (gsmPrintlnATCommand(ATString, OKString, oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+GSV", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("ATE0", OKString, oneSecond, true)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CMGD=4", OKString, oneSecond, true)) {
    Serial.print(F("Erreur delete message"));
    dieHere();
  }
  if (!gsmPrintlnATCommand("AT+CNMI=2,2,0,0,0", OKString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
  }
if (!gsmPrintlnATCommand("AT+CSAS", OKString, oneSecond, true)) {
    Serial.print(F("Error Save"));
  }
if (!gsmPrintlnATCommand("AT+CMGF=1", OKString, oneSecond, true)) {
    Serial.print(F("Error mode texte"));
  }
    Serial.println("Initialisation terminé");
}

void loop() {
  if (! ecouter()) {

if (!strncmp(message, "+CMT:", 5)) {
    ptr = strtok(message, ",\"");  // met un '\0' sur le premier guillemenet et ptr pointe sur "+CMT: "
    ptr = strtok(NULL, ",\"");      // met un '\0' sur le second guillemenet et ptr pointe sur "+33600123400"
    if (ptr) {
      strncpy(tel, ptr, maxTelSize);
      tel[maxTelSize] = '\0'; // juste au cas où le N° de tel était trop long, la fonction strncpy ne met pas le null en fin de chaîne
    }
     strcpy(SMS, "sms recu du :");
     strncat(SMS,tel,100);
     envoiesms();      
}
     /*else if(strncmp(message,"Ssid",4)==0) {
     ssid = strtok(message+5, "=");
     strcpy(SMS, "SSID recu :");
     strncat(SMS,ssid,50);
     envoiesms();
     }
    
     else if (strncmp(message,"Mdp",3)==0) {
     mdp = strtok(message+4, "=");
     strcpy (SMS, "Mdp recu :");
     strncat(SMS,mdp,50);
     envoiesms();
      }
  
     else {
      strcpy (SMS, "Instructions non comprise");
      envoiesms();
    }*/
  }
}


dans le serial :
Code: [Select]
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK

OK

OK

OK
Initialisation terminé
Azerty

>
> erreur effacement



(l'erreur d'effacement est du au fait d'être en "AT+CNMI=2,2,0,0,0" ? pas d'enregistrement mémoire donc rien a effacer = erreur ?)

et par sms je reçoit :
Code: [Select]
sms recu du :+3365******
Donc tout est OK (a par l'effacement.)


Des que je remet juste la condition:
Code: [Select]
else {
      strcpy (SMS, "Instructions non comprise");
      envoiesms();
    }


envoie du même sms (azerty)

Dans la console :
Code: [Select]
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK

OK

OK

OK
Initialisation terminé
+CMT: "+3365*****","","17/10/30,09:59:46+04"
Azerty

ERROR
OK
sms effacer


Et rien par sms




Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 30, 2017, 10:10 am
par contre, si je met toute les condition sauf "else" j'ai bien un retour par sms du ssid ou mdp recu (et rien des que les message commence apr autre chose que ssid ou mdp)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Oct 30, 2017, 11:12 am
J'essaye de jeter un œil en fin d'après midi je serai devant un ordi. Je bouge bcp, donc la majorité de mes posts sont faits depuis un smartphone ou une tablette - peux pas trop tester, c'est donc souvent du code "à l'aveugle" que je vous propose
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Oct 30, 2017, 11:36 am
Pas de problème jm, on a une vie a coté :) c'est déjà sympa de me suivre comme ça.
Quand jsuis bloqué, jcontinu de travaillé sur les chose plus simple dans le code principal / html ou sur le hardware
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 03, 2017, 10:33 am
J'ai intégré la parti web a mon code principal.
Pas de problème a la compilation.
Mais une fois televersé, rien ne se lance.
J'ai placé des "Serial.print"  a différent endroit pour voir ou était le problème et même pas uns ligne sur le moniteur ... donc j'en déduit un bug total :(

Trop lourd ?

J'ai commander une DUE, ça me permettra de pouvoir comparer les performance.
Si c'est concluant, je continurais la dessus mais je serait obliger de modifier le hardware ne serait ce que pour les pwm 3v3>>>5v

Pour esp dédié web, la partie échange avec l'arduino me parait compliqué. j'ai déjà assez de mal comme cela.


Pour récapituler l'avancement du projet :

>>>Code principal ok sans wifi et gsm
>>>Wifi seul presque ok (reste un problème de lenteur de réponse des bouton (~3 seconde avant de pouvoir re clicker pour qu'il soit pris en compte))
>>>Gsm seul presque ok ( reste un problème avec la ligne "else" correspondant a envoyer un message quand la commende n'est pas comprise)
>>>Hardware opperationel (mais déjà plein de modif dans ma tète pour la v2 surtout si utilisation d'une DUE)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 03, 2017, 10:38 pm
Vous pouvez faire un récapitulatif complet du cahier des charges?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 04, 2017, 01:07 am
Vous pouvez faire un récapitulatif complet du cahier des charges?
Sans prendre en compte les difficulté de codage :
gestion eclarage
gestion brassage + oscillo
Gestion alimentation
gestion température
page web visualisation des paramètre actuel / page web administrateur,paramétrage.
gsm pour alerte
Fonction supplémentairement suite échange/demande d'autre aquariophile :
écran tactile pour visu + paramétrage
osmolation
pompe de dosage.

Coté hardware:
220v exclusivement dans le tableau
Pas de restriction sur les composants, mega/due, esp01/esp12/esp32, écran 3.2"/5"/7"
CI "de base" + modul additionnel (le ph, écran,pompe doseuse doivent etre "plug and play" de t'elle sorte que chacun puisse adapter et faire évoluer l'automate en fonction de ces besoin/budget)

Le montage actuel:

fabrication CI ~45€ (~10€ si fait maison)
Divers fourniture/connecteur/résistance ect ... ~15€
écran 3.2 ~12€
wifi esp01 ~5€
sim800 ~15€
modul ph + sonde ~15€
arduino mega ~10€
Sonde température 5€
relais finder ~7€ pièce (actuellement 4)
soit ~115€ si CI maison

Pompe de dosage ~10€ piece
écrans 7" tactil en spi, il tourne ~50€ (permet de libérer des pin sur l'arduino)
Pour "la total écran 7" + 4 pompe dosage + ph bac+rac = 208€ si CI maison ou 243€  si fait faire.
Soit 3 ou 4 fois moins chère que les automate du commerce.







Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 04, 2017, 07:31 am
La « gestion » des différents éléments ça veut dire juste pilotage d'un relai ON/OFF ? Ou plus finement chaque composant ?

Le pilotage c'est quoi? une liste (éditable?) de moment de la journée où on passe de OFF à ON puis de ON à OFF ?


Sinon ce n'est pas une super pratique d'organiser le code comme cela
Code: [Select]
void loop(){
#include"heure_temp_ph.h"
#include"eclairage.h"
#include"oscillo.h"
#include"jebao.h"
#include "alimentation.h"
#include "edf.h"
#include "action_temperature.h"
#include"affichage.h"
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 04, 2017, 04:28 pm
Non, la gestion comporte un code bien précis pour chaque fonction.
Pwm pour éclairage, pompe brassage ...
Fonction millis pour déplacement des oscillo
Il y a quelque fonction simple on / off celon plusieurs critère ... nourrissage, tempête ...

Le pilotage serait de mettre via un bouton (web?) la fonction en on ou off
Exemple, j'ai un automate sans écran, mettre écran "off" et que le code "oublie" cette partie du code. avec un bouton et une fonction if ca m'as l'aire assez simple.
Meme chose pour les pompe doseuse, pompe ON on lit l'ensemble de la fonction associé.

Pour l'organisation du code, moins pratique mais plus simple a comprendre et a retrouvé ces petit (pour moi en tout cas)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 04, 2017, 06:41 pm
Bonsoir

bon j'ai enfin eu un peu de temps chez moi donc j'ai repris mon SIM800L avec ma carte SIM de test

(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=232224)


J'alimente correctement la carte par une alimentation séparée (5V 1.5A fonctionne pour moi) , je joins le GND Arduino à mon alim externe et je connecte le Rx du module SIM800L au Tx de Serial3 de mon MEGA ainsi que le Tx du module SIM800L au Rx de Serial3 de mon MEGA.

Ce module se charge des correspondances de tension donc pas besoin d'adapter à 3.3V


Je charge le code suivant dans mon arduino MEGA
Code: [Select]
#define gsm Serial3

const char * _SSID = "monSSID";
const char * _PWD = "motDePasse";

const byte ctrlZ = 0x1A;
const char * ctrlZString = "\x1A";
const char * escapeString = "\x1B";

const char * ATString = "AT";
const char * OKShortString = "OK";
const char * OKLongString = "\r\nOK\r\n";

const uint32_t oneSecond = 1000ul;

const byte maxMessageSize = 200;
char GSM_MessageLine[maxMessageSize + 1]; // +1 pour le '\0' à la fin de la c-string

// --------------------------------------
// gsmPrintlnAndWaitATCommand executes an AT commmand by adding at the end a CR LF
// then it checks if endMarker string is receivedon the GSM Serial port
// for max duration ms returns a boolean stating if the marker was found
// with the verbose option, the output from the GSM is also printed to Serial
// --------------------------------------

boolean gsmPrintlnAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean gsmPrintAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.print(command);
  return waitForString(endMarker, duration, verbose);
}

// --------------------------------------
// gsmPrintATCommand or gsmpWriteATCommand is used when you don't want to send the CR LF
// at the end of the commmand line; use it to build up a multi part command
// same syntax as print as they are Variadic Macros using print or write
// --------------------------------------
#define gsmPrintATCommand(...)    gsm.print(__VA_ARGS__)
#define gsmPrintlnATCommand(...)  gsm.println(__VA_ARGS__)
#define gsmWriteATCommand(...)    gsm.write(__VA_ARGS__)


// --------------------------------------
// read a line from gsm, ignore '\r' and returns true if '\n' is found
// --------------------------------------

boolean getGSMLine()
{
  static byte indexMessage = 0;
  boolean incomingMessage = true;

  while (gsm.available() && incomingMessage) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          GSM_MessageLine[indexMessage] = '\0'; // trailing NULL char for a correct c-string
          indexMessage = 0; // get ready for next time
          incomingMessage = false;
          break;
        case '\r': // don't care about this one
          break;
        default:
          if (indexMessage <= maxMessageSize - 1) GSM_MessageLine[indexMessage++] = (char) c; // else ignore it..
          break;
      }
    }
  }
  return !incomingMessage;
}

// --------------------------------------
// waitForString wait max for duration ms whilst checking if endMarker string is received
// on the GSM Serial port returns a boolean stating if the marker was found
// --------------------------------------

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}


void setup() {
  Serial.begin(115200);
  gsm.begin(9600); // suivant votre config, essayez 9600 19200 38400 57600 74880 115200

  // prévoir éventuellement AT+CPIN="1234" pour rentrer le PIN

  if (gsmPrintlnAndWaitATCommand(ATString, OKLongString, 5 * oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("AT+GSV", OKLongString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATE0", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATV1", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Message en Verbal"));
    dieHere();
  }

  // on passe en les SMS en mode texte
  if (!gsmPrintlnAndWaitATCommand("AT+CMGF=1", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CMGF"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }


  // on passe en mode routage des SMS vers le terminal
  if (!gsmPrintlnAndWaitATCommand("AT+CNMI=1,2,0,0,0", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }

  Serial.println("Initialisation terminé");
}

boolean sendSMS(const char * noDeTel, const char * messageAEnvoyer)
{
  boolean SMSenvoye = false;
  gsmPrintATCommand("AT+CMGS=\"");
  gsmPrintATCommand(noDeTel);

  if (gsmPrintlnAndWaitATCommand("\"", ">", oneSecond, false)) {
    gsmPrintlnATCommand(messageAEnvoyer);
    SMSenvoye = gsmPrintlnAndWaitATCommand(ctrlZString, OKShortString, 5 * oneSecond, false);
  } else {
    gsmPrintlnATCommand(escapeString);
  }
  return SMSenvoye;
}

void loop()
{
  if (getGSMLine()) {
    // ********************************************
    // TEST RECEPTION D'UN SMS
    // +CMT: "+33620000000",,"01/03/22,16:33:31+00"<CRLF>
    // texte bla bla bla<CRLF>
    // ********************************************
    if (!strncmp(GSM_MessageLine, "+CMT:", 5)) {// 5 parce que "+CMT:" c'est 5 caractères, on compare le début de la chaîne
      const byte maxDigitsPhoneNb = 30;
      char phoneNb[maxDigitsPhoneNb + 1];
      char *ptr = strtok(GSM_MessageLine, "\"");
      if (ptr) {
        ptr =  strtok(NULL, "\"");
        strncpy(phoneNb, ptr, maxDigitsPhoneNb);
        phoneNb[maxDigitsPhoneNb] = '\0';

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("SMS de = ")); Serial.println(phoneNb);
        // ***

        while (!getGSMLine()); // on attend le texte du SMS

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("Message = [")); Serial.print(GSM_MessageLine); Serial.println(F("]"));
        // ***

        if (!strncmp(GSM_MessageLine, "CONFIG", 6)) { // 6 parce que 6 caractères dans le mot "CONFIG"
          // on a rerçu un SMS nous demandant la config, on construit la réponse
          strcpy(GSM_MessageLine, "La config est la suivante:\r\nSSID = ");
          strcat(GSM_MessageLine, _SSID);
          strcat(GSM_MessageLine, "\r\nMot de Passe = ");
          strcat(GSM_MessageLine, _PWD);
          sendSMS(phoneNb, GSM_MessageLine);
        } else {
          sendSMS(phoneNb, "Pas compris");
        }
      }
    }
  }
}


le lance, la console me dit
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800L
Revision:1418B02SIM800L24

OK

OK

OK
Initialisation terminé


J'envoie depuis mon iPhone un SMS au module dans lequel j'écris "Coucou", la console série me dit

SMS de = +336xxxxxxxx
Message = [Coucou]


et je reçois en retour sur mon iPhone un SMS en provenance de ma carte qui me dit
Pas Compris

J'envoie un nouveau SMS au module dans lequel j'écris "CONFIG" (en majuscules, sans les guillemets), la console série me dit

SMS de = +336xxxxxxxx
Message = [CONFIG]


et je reçois en retour sur mon iPhone un SMS en provenance de ma carte qui me dit
La config est la suivante:
nSSID = monSSID
Mot de Passe = motDePasse



si j'envoie d'autres SMS ça fonctionne sans soucis - mais le seul SMS compris c'est CONFIG


testez si ça fonctionne pour vous

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 04, 2017, 09:58 pm
oui, tout fonctionne

Code: [Select]
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK
Initialisation termin⸮
SMS de = +336****
Message = [Coucou]
SMS de = +336****
Message = [CONFIG]
SMS de = +336****
Message = [Test autre message]



et j'ai bien recu:

Pas Compris
puis
La config est la suivante:
nSSID = monSSID
Mot de Passe = motDePasse
puis
Pas Compris
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 04, 2017, 10:06 pm
Si je compare ce code a celui que testai précédemment ce qui me saute au yeux est cette ligne
Code: [Select]
while (!getGSMLine()); // on attend le texte du SMS
Qui, suite a ligne "+cmt, atend la réception du message pour lancer la suite d'analyse via la commande strncmp
Alors que dans le code precedent, le message était analysé avec tout les condition d'affilé que ce soit pour les message +cmt ou pour le sms recu.
C'est bien ca ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 04, 2017, 11:29 pm
Le +CMT est sur une ligne et le SMS derrière (d'ailleurs je me rends compte que ça ne fonctionne pas si le sms est sur plusieurs lignes, en fait faudrait lire jusqu'au marqueur de fin de sms)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 05, 2017, 02:38 pm
Les sms envoyer seront de format "Ssid monssid" ou "Mdp monmdp" donc il ne seront pas sur plusieurs lignes (sauf si chaque ligne est limité en caractère?)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 05, 2017, 03:21 pm
Pour recuperer le ssid recu j'ai donc
Modifier const char * _SSID = "monSSID" en char * _SSID (meme declaration que la page web)


 Puis utiliser la même formule que dans le code précédent et que dans la page web a savoir
Code: [Select]
_SSID = strtok(GSM_MessageLine+5,"=");
Qui devrait faire correspondre _SSID a la suite de caractère situer a partir du caractère 6 inclu.
Exemple sms envoyer "Ssid pourtest", ssid = pourtest

Au lieu de ça, j'ai un reboot du modul :(
Code: [Select]
GPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK
Initialisation terminé
SMS de = +336*****
MessageGPRS Modem OK

SIMCOM_Ltd
SIMCOM_SIM800A
Revision:1418B04SIM800A24

OK

OK

OK
Initialisation terminé



attention e suis en serial1 au lieu de 3 comme vous
Code: [Select]
#define gsm Serial1

char * _SSID;
char * _PWD;

const byte ctrlZ = 0x1A;
const char * ctrlZString = "\x1A";
const char * escapeString = "\x1B";

const char * ATString = "AT";
const char * OKShortString = "OK";
const char * OKLongString = "\r\nOK\r\n";

const uint32_t oneSecond = 1000ul;

const byte maxMessageSize = 200;
char GSM_MessageLine[maxMessageSize + 1]; // +1 pour le '\0' à la fin de la c-string

// --------------------------------------
// gsmPrintlnAndWaitATCommand executes an AT commmand by adding at the end a CR LF
// then it checks if endMarker string is receivedon the GSM Serial port
// for max duration ms returns a boolean stating if the marker was found
// with the verbose option, the output from the GSM is also printed to Serial
// --------------------------------------

boolean gsmPrintlnAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean gsmPrintAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.print(command);
  return waitForString(endMarker, duration, verbose);
}

// --------------------------------------
// gsmPrintATCommand or gsmpWriteATCommand is used when you don't want to send the CR LF
// at the end of the commmand line; use it to build up a multi part command
// same syntax as print as they are Variadic Macros using print or write
// --------------------------------------
#define gsmPrintATCommand(...)    gsm.print(__VA_ARGS__)
#define gsmPrintlnATCommand(...)  gsm.println(__VA_ARGS__)
#define gsmWriteATCommand(...)    gsm.write(__VA_ARGS__)


// --------------------------------------
// read a line from gsm, ignore '\r' and returns true if '\n' is found
// --------------------------------------

boolean getGSMLine()
{
  static byte indexMessage = 0;
  boolean incomingMessage = true;

  while (gsm.available() && incomingMessage) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          GSM_MessageLine[indexMessage] = '\0'; // trailing NULL char for a correct c-string
          indexMessage = 0; // get ready for next time
          incomingMessage = false;
          break;
        case '\r': // don't care about this one
          break;
        default:
          if (indexMessage <= maxMessageSize - 1) GSM_MessageLine[indexMessage++] = (char) c; // else ignore it..
          break;
      }
    }
  }
  return !incomingMessage;
}

// --------------------------------------
// waitForString wait max for duration ms whilst checking if endMarker string is received
// on the GSM Serial port returns a boolean stating if the marker was found
// --------------------------------------

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}


void setup() {

_SSID = "monSSID";
_PWD = "motDePasse";

  Serial.begin(115200);
  gsm.begin(9600); // suivant votre config, essayez 9600 19200 38400 57600 74880 115200

  // prévoir éventuellement AT+CPIN="1234" pour rentrer le PIN

  if (gsmPrintlnAndWaitATCommand(ATString, OKLongString, 5 * oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("AT+GSV", OKLongString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATE0", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATV1", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Message en Verbal"));
    dieHere();
  }

  // on passe en les SMS en mode texte
  if (!gsmPrintlnAndWaitATCommand("AT+CMGF=1", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CMGF"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }


  // on passe en mode routage des SMS vers le terminal
  if (!gsmPrintlnAndWaitATCommand("AT+CNMI=1,2,0,0,0", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }

  Serial.println("Initialisation terminé");
}

boolean sendSMS(const char * noDeTel, const char * messageAEnvoyer)
{
  boolean SMSenvoye = false;
  gsmPrintATCommand("AT+CMGS=\"");
  gsmPrintATCommand(noDeTel);

  if (gsmPrintlnAndWaitATCommand("\"", ">", oneSecond, false)) {
    gsmPrintlnATCommand(messageAEnvoyer);
    SMSenvoye = gsmPrintlnAndWaitATCommand(ctrlZString, OKShortString, 5 * oneSecond, false);
  } else {
    gsmPrintlnATCommand(escapeString);
  }
  return SMSenvoye;
}

void loop()
{
  if (getGSMLine()) {
    // ********************************************
    // TEST RECEPTION D'UN SMS
    // +CMT: "+33620000000",,"01/03/22,16:33:31+00"<CRLF>
    // texte bla bla bla<CRLF>
    // ********************************************
    if (!strncmp(GSM_MessageLine, "+CMT:", 5)) {// 5 parce que "+CMT:" c'est 5 caractères, on compare le début de la chaîne
      const byte maxDigitsPhoneNb = 30;
      char phoneNb[maxDigitsPhoneNb + 1];
      char *ptr = strtok(GSM_MessageLine, "\"");
      if (ptr) {
        ptr =  strtok(NULL, "\"");
        strncpy(phoneNb, ptr, maxDigitsPhoneNb);
        phoneNb[maxDigitsPhoneNb] = '\0';

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("SMS de = ")); Serial.println(phoneNb);
        // ***

        while (!getGSMLine()); // on attend le texte du SMS

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("Message = [")); Serial.print(GSM_MessageLine); Serial.println(F("]"));
        // ***

        if (!strncmp(GSM_MessageLine, "Ssid", 4)) { // 6 parce que 6 caractères dans le mot "CONFIG"
          // on a rerçu un SMS nous demandant la config, on construit la réponse
          _SSID = strtok(GSM_MessageLine+5,"=");
          strcpy(GSM_MessageLine, "La config est la suivante:\r\nSSID = ");
          strcat(GSM_MessageLine, _SSID);
          sendSMS(phoneNb, GSM_MessageLine);
        } else {
          sendSMS(phoneNb, "Pas compris");
        }
      }
    }
  }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 05, 2017, 04:23 pm
faire ça ce n'est pas top
Code: [Select]
  _SSID = "monSSID";
  _PWD = "motDePasse";

quel est l'objectif ? soit vous voulez un tableau de caractères, soit un pointeur, mais faire pointer votre pointeur sur une chaîne constante va faire aboyer le compilo....

Qu'est-ce que vous envoyez comme SMS? un truc du genre Ssid=coucou ?
en supposant que ce soit cela et donc qu'on ait ça dans GSM_MessageLine

quand vous faites
Code: [Select]
if (!strncmp(GSM_MessageLine, "Ssid", 4))ça compare les 4 caractères du début de GSM_MessageLine avec Ssid --> ici c'est bon donc on rentre dans le if

vous exécutez alors:
Code: [Select]
          _SSID = strtok(GSM_MessageLine+5,"=");qui a pour effet de remplacer le prochain = par un caractère null '\0' et de faire pointer votre variable _SSID au milieu du buffer GSM_MessageLine (une c-string qui contient donc plus que " coucou". (et éventuellement tout ce qui avait aussi derrière coucou)

Notez que c'est aussi simple d'écrire _SSID = GSM_MessageLine+6;...

ensuite vous faites
Code: [Select]
          strcpy(GSM_MessageLine, "La config est la suivante:\r\nSSID = ");
          strcat(GSM_MessageLine, _SSID);


et c'est là le drame :)

votre premier strcpy écrase GSM_MessageLine avec la chaîne "La config est la suivante:\r\nSSID = " et votre pointeur _SSID pointe toujours au milieu de cette chaîne qui vient d'être écrasée... et faire un strcat() avec des éléments se chevauchant c'est pas une bonne idée. (cf la doc de strcat()  (http://en.cppreference.com/w/cpp/string/byte/strcat)--> The behavior is undefined if the strings overlap.


c'est pour cela que si vous regardez mon code où j'extrais le N° de tel de l'appelant, j'ai un petit buffer local dans lequel je copie depuis  GSM_MessageLine le numéro de téléphone pour les mettre au chaud ailleurs --> faut faire pareil

essayez avec ce bout de code (je suis sur mon tel, donc peut pas tester)

Code: [Select]
        if (!strncmp(GSM_MessageLine, "Ssid", 4)) { // 4 parce que 4 caractères dans le mot "Ssid"
          // on a rerçu un SMS nous demandant la config, on construit la réponse
          const byte maxSSID = 30;// prévoir la bonne longueur
          char copieDuSSID[maxSSID+1];
          _SSID = strchr(GSM_MessageLine + 5, "="); // Notez que c'est aussi simple d'écrire _SSID = GSM_MessageLine+6;...
          strncpy(copieDuSSID, _SSID,maxSSID);
          copieDuSSID[maxSSID] = '\0';
          strcpy(GSM_MessageLine, "La config est la suivante:\r\nSSID = ");
          strcat(GSM_MessageLine, copieDuSSID);
          sendSMS(phoneNb, GSM_MessageLine);
        } else {
          sendSMS(phoneNb, "Pas compris");
        }
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 05, 2017, 04:42 pm
Je ne voyait  pas sa comme sa ...
une fois _SSID = je pensait que la valeur était enregistrer dans _SSID et donc que la chaîne GSM_MessageLine pouvait être modifier sans que cela affecte _SSID

Code: [Select]
  _SSID = "monSSID";
  _PWD = "motDePasse";

etait la pour le test puisque dans le code final il ne seras pas present vu qu'il sera definit par le ssid ou mds recu par sms.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 05, 2017, 04:43 pm
Donc dans le serial le sms est bien lu mais la réponse recu par sms est toujours la même quelque soit le sms envoyer commencant pas ssid
Code: [Select]
La config est la suivante : SSID = d
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 07, 2017, 11:20 am
Bon, matinée passé sur l'aquabouns bien sur mais pas sur le code ...
Voici un détail de les composant utilisé et de toute les fonctionnalités prévu de l'aquaboun's
N'hésité pas a me dire si certain point ne vous semble pas clair.

Fichier trop gros pour etre joint ici
aquaboun's.doc (https://www.partage-fichiers.com/upload/ks5nt5qf/)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 09, 2017, 10:14 am
Et oui je suis toujours la :)
Et plutôt avec du positif :)
J'ai reçu il y a 3 jours mon d1 pro
J'ai donc passé 3 soirée a adapter le code web pour le téléverser directement dans le d1.
Se matin, ça y est !!!
C'est fonctionnel :)
Mais avec un petit lot de problème quand même

Pour le positif :


Pour le negatif :


Le voici ci joint
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 09, 2017, 10:29 am
un peu occupé en ce moment m'ai hier soir j'ai pondu un bout de code pour vous montrer comment échanger des données entre le MEGA et le D1 mini par serial pour séparer la partie web de la partie contrôle. je suis en vadrouille donc je n'ai pas testé le code, dès que je peux valider que ce que j'ai écrit tourne je vous le posterai.

dans: tempsprecedent1 = millis - 10000; --> il ne vous manque pas des parenthèses pour millis() (écrit comme cela, millis et l'adresse mémoire de la fonction donc le compilateur n'est pas content)

Pour la perf d'affichage malheureusement on reste dans des perf de petits ordinateurs - faudrait optimiser la page web, utiliser potentiellement de la compression et le SPIFFS pour les partie statique etc...

ensuite il y a à tester des trucs un peu plus avancés comme un client.setNoDelay(1); (une fois que vous avez fait WiFiClient client = server.available(); par exemple - et si vous avez des données en fichier SPIFFS, un client.write(webFile); devrait booster un max
   
faudra que je creuse un peu
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 09, 2017, 10:44 am
un peu occupé en ce moment m'ai hier soir j'ai pondu un bout de code pour vous montrer comment échanger des données entre le MEGA et le D1 mini par serial pour séparer la partie web de la partie contrôle. je suis en vadrouille donc je n'ai pas testé le code, dès que je peux valider que ce que j'ai écrit tourne je vous le posterai.
(http://idata.over-blog.com/4/18/49/01/GIFS/genial.gif)


dans: tempsprecedent1 = millis - 10000; --> il ne vous manque pas des parenthèses pour millis() (écrit comme cela, millis et l'adresse mémoire de la fonction donc le compilateur n'est pas content)
Pfff effectivement, toujours ces petit detail ...
Mais pourquoi il n'y avait pas d'erreur de compilation quand envoyer dans l'arduino ?

Pour la perf d'affichage malheureusement on reste dans des perf de petits ordinateurs - faudrait optimiser la page web, utiliser potentiellement de la compression pour les partie statique etc...
J'adhererai a cette théorie si l'esp-01 relié a l'arduino était aussi long ou plus long mais il met ~2 seconde a m'afficher cette page, le d1 en "direct" devrait être plus performant et non l'inverse.
A moins qu'il me manque une explication  :smiley-confuse:

Pour mon petit .doc, si vous l'avez vu, tout est assez claire ? faut il plus d'info ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 09, 2017, 11:23 am
Pour la compression mon html a l'air pas mal puisque les outils de compression indique
Taux de compression: 99%
8 985 octets avant
8 865 octets apres
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 09, 2017, 11:26 am
SPIFFS

Oula ... ca a l'air une usine a gaz  :o
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 09, 2017, 01:35 pm
Pour la compression mon html a l'air pas mal puisque les outils de compression indique
Taux de compression: 99%
8 985 octets avant
8 865 octets apres
Euh je ne suis pas sûr de quels outils vous parlez là...  si vous gzip-ez votre HTML vous verrez qu'il devient bcp bcp plus petit - le texte se comprimant bien

Ensuite il faudrait essayer de pousser des lignes plus longues dans le client.print (ce qui ne pose pas de soucis de RAM grâce au fait qu'on lit directement en progmem) - à cause des ACK mais faut que je regarde plus précisément
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 09, 2017, 11:22 pm
Euh je ne suis pas sûr de quels outils vous parlez là...  si vous gzip-ez votre HTML vous verrez qu'il devient bcp bcp plus petit - le texte se comprimant bien
j'ai chercher sur le net a compresser ma page html.
je suis tombé sur different logitiel dont Absolute HTML Compressor

Je pense comprendre que vous parliez de ça (https://www.alsacreations.com/article/lire/914-compression-pages-html-css-gzip-deflate.html) mais pour mettre tout ça dans le code ... il faut que j'devienne insomniaque lol

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 11, 2017, 09:48 am
Bonjour - finalement je n'ai pas pu m'approcher des mes arduino dans la semaine, je teste dans l'après midi le bout de code Arduino <<-- SERIAL -->> Wemos D1 et vous poste l'exemple d'échange de données

le gzip c'est pratique avec des pages statiques mais comme vous avez beaucoup de dynamique ça ne va pas aider bcp. il faudra optimiser les ACK de la communication wifi je ferai 2 ou 3 tests
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 11, 2017, 10:38 am
Pour l'ACK,
Au vu de la description trouvé ici (http://searchnetworking.techtarget.com/definition/ACK)
cela rejoindrais l'idée que j'avais sur ce qui se passe dans le serial lorsque je demande la page :
Code: [Select]
WiFi connected
Server started
192.168.1.54
conected
conected
conected
conected
conected
conected
conected
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
conected
available
n

Donc je mettait dit que cela devait être long a cause de ca.
c'est bien lié a l'ACK ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 11, 2017, 09:55 pm
En creusant un peu ce sera difficile de contourner simplement l'ACK

Il faudra donc passer à l'étape suivante - un petit coup d'AJAX sans doute - faut que je trouve le temps de faire un petit tuto
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 11, 2017, 10:57 pm
un petit coup d'AJAX sans doute - faut que je trouve le temps de faire un petit tuto
Laisse tombé, y a ma femme pour ça !
(https://img.coopathome.ch/produkte/880_880/RGB/3181694_001.jpg?_=1473689089446)
(https://st2.depositphotos.com/1007989/5894/i/950/depositphotos_58949549-stock-photo-smiley-using-a-duster.jpg)

plus sérieusement, si je comprend bien l'ajax permettrais de mettre a jour les variable sur la page web sans avoir besoin de la recharger ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 12, 2017, 08:06 am
Pas très galant tout cela ...

Oui avec AJAX la page statique pourrait venir du SPIFFS (un système de fichier simple sur l'ESP) et cette page mettrait à jour des sous parties par une approche AJAX. comme on envoie moins de données c'est plus efficace malgré les ACK et c'est plus joli à l'oeil Car on ne recharge pas toute la page
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 12, 2017, 08:38 pm
petit début de tuto  (http://forum.arduino.cc/index.php?topic=511147.0)posté pour la partie SPIFFS

le reste quand j'ai un peu plus de temps....
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 14, 2017, 10:55 am
Comme conseiller j'ai installer la bibliothèque FSBrowserNG et tout celle associées.
Cloner manuellement l'esp8266
Et j'ai fini par réussir a compiler sans erreur.

J'ai donc voulu televerser le code exemple Userconfigexemple.

Et j'arrive toujours a ce message:


Code: [Select]
Archiving built core (caching) in: C:\Users\djbouns\AppData\Local\Temp\arduino_cache_384035\core\core_esp8266com_esp8266_d1_mini_lite_CpuFrequency_80,FlashSize_1M0,LwIPVariant_open,Debug_Disabled,DebugLevel_None____,UploadSpeed_115200_59f27b87b1649ba33697614d4ec8334b.a
Le croquis utilise 367911 octets (35%) de l'espace de stockage de programmes. Le maximum est de 1023984 octets.
Les variables globales utilisent 40820 octets (49%) de mémoire dynamique, ce qui laisse 41100 octets pour les variables locales. Le maximum est de 81920 octets.
java.io.IOException: Cannot run program "C:\Program Files (x86)\Arduino\hardware\esp8266com\esp8266/tools/esptool/esptool.exe": CreateProcess error=2, Le fichier spécifié est introuvable
 at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
 at processing.app.helpers.ProcessUtils.exec(ProcessUtils.java:26)
 at cc.arduino.packages.Uploader.executeUploadCommand(Uploader.java:129)
 at cc.arduino.packages.uploaders.SerialUploader.uploadUsingPreferences(SerialUploader.java:207)
 at cc.arduino.UploaderUtils.upload(UploaderUtils.java:78)
 at processing.app.SketchController.upload(SketchController.java:713)
 at processing.app.SketchController.exportApplet(SketchController.java:686)
 at processing.app.Editor$DefaultExportHandler.run(Editor.java:2168)
 at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: CreateProcess error=2, Le fichier spécifié est introuvable
 at java.lang.ProcessImpl.create(Native Method)
 at java.lang.ProcessImpl.<init>(ProcessImpl.java:386)
 at java.lang.ProcessImpl.start(ProcessImpl.java:137)
 at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
 ... 8 more
Une erreur est survenue lors du transfert du croquis



Code: [Select]
C:\Program Files (x86)\Arduino\hardware\esp8266com\esp8266/tools/esptool/esptool.exe
Le fichier spécifié est introuvable

 
esptool.exe est bien a cette emplacement.

Une idée ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 16, 2017, 09:24 am
J'ai intégré la parti web a mon code principal.
Pas de problème a la compilation.
Mais une fois televersé, rien ne se lance.
J'ai placé des "Serial.print"  a différent endroit pour voir ou était le problème et même pas uns ligne sur le moniteur ... donc j'en déduit un bug total :(
Depuis ce jour la  , impossible de refaire fonctionné mon code, même en retirant toute la partie web ...
Ça va passer par la fenêtre ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 16, 2017, 09:28 am
il faut peut-être revenir à la version précédente de la librairie pour votre code?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 16, 2017, 10:24 am
il faut peut-être revenir à la version précédente de la librairie pour votre code?
Je n'ai pas changer de librairie ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 17, 2017, 06:59 am
Depuis ce jour la  , impossible de refaire fonctionné mon code, même en retirant toute la partie web ...
Ça va passer par la fenêtre ...
Avec vos #include de code source c'est quasiment impossible de comprendre la structure de la loop, le chevauchement possible de variables et l'allocation mémoire....

Peut être débordez vous la mémoire au run time ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 17, 2017, 10:13 am
Il faut que que cree tout ces fonction en VOID et que je les laisses en une page ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 17, 2017, 10:48 am
l'idéal serait de définir "proprement" ce que doit faire la loop() sous forme sans doute d'une machine à état pour chacun des sous systèmes.

Chaque appel dans la loop() doit être non bloquant et rapide.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 17, 2017, 11:48 am
l'idéal serait de définir "proprement" ce que doit faire la loop() sous forme sans doute d'une machine à état pour chacun des sous systèmes.

Chaque appel dans la loop() doit être non bloquant et rapide.
Je ne comprend pas du tout comment mettre cela en forme de cette façon.

A tu un exemple sous cette forme que je vois stp ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 17, 2017, 12:01 pm
cf mon tuto éventuellement (http://forum.arduino.cc/index.php?topic=470879.0)

La loop() écoute les différents événements possibles et agit en conséquence. Il y a une variable globale (ou plusieurs si plusieurs sous systèmes) qui vont aider à savoir là où on en est dans les différents traitements.

c'est pour cela que je vous demandais le cahier des charges. il y a un bon début de boulot dans ce que vous avez partagé, mais il manque la "logique" (ce qu'il faut faire) pour chaque sous système . Quelles décisions doivent être prises par l'Arduino et en fonction de quoi
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 17, 2017, 11:16 pm
Comme très souvent je comprend le principe ... Ya qu'a ... lol
la plus part des fonctions sont generé en fonction de l'heure.
exemple, de 10h a 12h lever soleil
de 12h a 20h soleil zenith
20h a 22h coucher soleil
de 22h a 10h eteint

Le code donne ca:
Code: [Select]
if ((time >= LEVERbleu1) && (time < finLEVERbleu1)){
  pwmbleu1 = map(time, LEVERbleu1, finLEVERbleu1, 0, puissancebleu);
  analogWrite (bleu1, pwmbleu1);
  }
else if ((time >= COUCHERbleu1) && (time < finCOUCHERbleu1)){ 
  pwmbleu1 = map(time, COUCHERbleu1, finCOUCHERbleu1, puissancebleu, 0);
  analogWrite (bleu1, pwmbleu1);
  }   
else if ((time >= finLEVERbleu1 ) && (time < COUCHERbleu1)) {
  pwmbleu1 = puissancebleu;
  analogWrite(bleu1, puissancebleu);
  }
else {
  pwmbleu1 = 0;
  analogWrite(bleu1, 0);


Dans le loop il faut donc mettre la lecture de l'heure.
Dans le setup, associé chaque créneau horaire a une fonction
Déclarer chaque fonction en VOID

c'est ca ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 18, 2017, 12:30 pm
J'ai vu d'autre exemple (mais pas d'exemple avec des condition comme moi) sur le net et si je les adaptes j'arrive a :

Code: [Select]
void debutleverblanc1 {
  if ((Time >= debut_LEVER_blanc1) && (Time < fin_LEVER_blanc1)){
  pwm_blanc1 = map(Time, debut_LEVER_blanc1, fin_LEVER_blanc1, 0, puissance_blanc);
  analogWrite (pinOUT_blanc1, pwm_blanc1);
  }
}

void debutcoucherblanc1{
if ((Time >= debut_COUCHER_blanc1) && (Time < fin_COUCHER_blanc1)){  
  pwm_blanc1 = map(Time, debut_COUCHER_blanc1, fin_COUCHER_blanc1, puissance_blanc, 0);
  analogWrite (pinOUT_blanc1, pwm_blanc1);
  }
}
  
void finleverblanc1 {
  if ((Time >= fin_LEVER_blanc1 ) && (Time < debut_COUCHER_blanc1)) {
  pwm_blanc1 = puissance_blanc;
  analogWrite(pinOUT_blanc1, puissance_blanc);
  }
}


Mais pour le else  ?
Code: [Select]
else {
  pwm_blanc1 = 0;
  analogWrite(pinOUT_blanc1, 0);
}

Si je le met dans un void il ne feras pas le lien avec les if dans les void précédent ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 19, 2017, 10:46 am
Donc dans le serial le sms est bien lu mais la réponse recu par sms est toujours la même quelque soit le sms envoyer commencant pas ssid
Code: [Select]
La config est la suivante : SSID = d

Je me suis re penché sur la partie SMS.
Je suis arrivé a avoir une réponse correcte a mes demandes.

Voyer vous des incohérences ? si non, je l'inclus dans mon code principale
Code: [Select]
#define gsm Serial1

char * _SSID ;
char * _MDP ;

const byte ctrlZ = 0x1A;
const char * ctrlZString = "\x1A";
const char * escapeString = "\x1B";

const char * ATString = "AT";
const char * OKShortString = "OK";
const char * OKLongString = "\r\nOK\r\n";

const byte max_SSID = 50;// prévoir la bonne longueur
char copie_SSID[max_SSID+1];
const byte max_MDP = 50;// prévoir la bonne longueur
char copie_MDP[max_MDP+1];

         
const uint32_t oneSecond = 1000ul;

const byte maxMessageSize = 200;
char GSM_MessageLine[maxMessageSize + 1]; // +1 pour le '\0' à la fin de la c-string

// --------------------------------------
// gsmPrintlnAndWaitATCommand executes an AT commmand by adding at the end a CR LF
// then it checks if endMarker string is receivedon the GSM Serial port
// for max duration ms returns a boolean stating if the marker was found
// with the verbose option, the output from the GSM is also printed to Serial
// --------------------------------------

boolean gsmPrintlnAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean gsmPrintAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.print(command);
  return waitForString(endMarker, duration, verbose);
}

// --------------------------------------
// gsmPrintATCommand or gsmpWriteATCommand is used when you don't want to send the CR LF
// at the end of the commmand line; use it to build up a multi part command
// same syntax as print as they are Variadic Macros using print or write
// --------------------------------------
#define gsmPrintATCommand(...)    gsm.print(__VA_ARGS__)
#define gsmPrintlnATCommand(...)  gsm.println(__VA_ARGS__)
#define gsmWriteATCommand(...)    gsm.write(__VA_ARGS__)


// --------------------------------------
// read a line from gsm, ignore '\r' and returns true if '\n' is found
// --------------------------------------

boolean getGSMLine()
{
  static byte indexMessage = 0;
  boolean incomingMessage = true;

  while (gsm.available() && incomingMessage) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          GSM_MessageLine[indexMessage] = '\0'; // trailing NULL char for a correct c-string
          indexMessage = 0; // get ready for next time
          incomingMessage = false;
          break;
        case '\r': // don't care about this one
          break;
        default:
          if (indexMessage <= maxMessageSize - 1) GSM_MessageLine[indexMessage++] = (char) c; // else ignore it..
          break;
      }
    }
  }
  return !incomingMessage;
}

// --------------------------------------
// waitForString wait max for duration ms whilst checking if endMarker string is received
// on the GSM Serial port returns a boolean stating if the marker was found
// --------------------------------------

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}


void setup() {
  Serial.begin(115200);
  gsm.begin(9600); // suivant votre config, essayez 9600 19200 38400 57600 74880 115200

  // prévoir éventuellement AT+CPIN="1234" pour rentrer le PIN

  if (gsmPrintlnAndWaitATCommand(ATString, OKLongString, 5 * oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("AT+GSV", OKLongString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATE0", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATV1", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Message en Verbal"));
    dieHere();
  }

  // on passe en les SMS en mode texte
  if (!gsmPrintlnAndWaitATCommand("AT+CMGF=1", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CMGF"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }


  // on passe en mode routage des SMS vers le terminal
  if (!gsmPrintlnAndWaitATCommand("AT+CNMI=1,2,0,0,0", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }

  Serial.println("Initialisation terminé");
}

boolean sendSMS(const char * noDeTel, const char * messageAEnvoyer)
{
  boolean SMSenvoye = false;
  gsmPrintATCommand("AT+CMGS=\"");
  gsmPrintATCommand(noDeTel);

  if (gsmPrintlnAndWaitATCommand("\"", ">", oneSecond, false)) {
    gsmPrintlnATCommand(messageAEnvoyer);
    SMSenvoye = gsmPrintlnAndWaitATCommand(ctrlZString, OKShortString, 5 * oneSecond, false);
  } else {
    gsmPrintlnATCommand(escapeString);
  }
  return SMSenvoye;
}

void loop()
{
  if (getGSMLine()) {
    // ********************************************
    // TEST RECEPTION D'UN SMS
    // +CMT: "+33620000000",,"01/03/22,16:33:31+00"<CRLF>
    // texte bla bla bla<CRLF>
    // ********************************************
    if (!strncmp(GSM_MessageLine, "+CMT:", 5)) {// 5 parce que "+CMT:" c'est 5 caractères, on compare le début de la chaîne
      const byte maxDigitsPhoneNb = 30;
      char phoneNb[maxDigitsPhoneNb + 1];
      char *ptr = strtok(GSM_MessageLine, "\"");
      if (ptr) {
        ptr =  strtok(NULL, "\"");
        strncpy(phoneNb, ptr, maxDigitsPhoneNb);
        phoneNb[maxDigitsPhoneNb] = '\0';

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("SMS de = ")); Serial.println(phoneNb);
        // ***

        while (!getGSMLine()); // on attend le texte du SMS

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("Message = [")); Serial.print(GSM_MessageLine); Serial.println(F("]"));
        // ***

        if (!strncmp(GSM_MessageLine, "CONFIG", 6)) { // 6 parce que 6 caractères dans le mot "CONFIG"
          // on a rerçu un SMS nous demandant la config, on construit la réponse
          strcpy(GSM_MessageLine, "La config est la suivante:\r\nSSID = ");
          strcat(GSM_MessageLine, _SSID);
          strcat(GSM_MessageLine, "\r\nMot de Passe = ");
          strcat(GSM_MessageLine, _MDP);
          sendSMS(phoneNb, GSM_MessageLine);
        }
        else if (!strncmp(GSM_MessageLine, "Ssid", 4)) { // 6 parce que 6 caractères dans le mot "CONFIG"
          _SSID = GSM_MessageLine + 5; // Notez que c'est aussi simple d'écrire _SSID = GSM_MessageLine+6;...
          strncpy(copie_SSID, _SSID,max_SSID);
          copie_SSID[max_SSID] = '\0';
          _SSID = copie_SSID;
          strcpy(GSM_MessageLine, "nouveau SSID recu = ");
          strcat(GSM_MessageLine, _SSID);
          sendSMS(phoneNb, GSM_MessageLine);
        }
        else if (!strncmp(GSM_MessageLine, "Mdp", 3)) { // 6 parce que 6 caractères dans le mot "CONFIG"
          _MDP = GSM_MessageLine + 4; // Notez que c'est aussi simple d'écrire _SSID = GSM_MessageLine+6;...
          strncpy(copie_MDP, _MDP,max_MDP);
          copie_MDP[max_MDP] = '\0';
          _MDP = copie_MDP;
          strcpy(GSM_MessageLine, "nouveau MDP recu = ");
          strcat(GSM_MessageLine, _MDP);
          sendSMS(phoneNb, GSM_MessageLine);
        }         
        else {
          sendSMS(phoneNb, "Pas compris");
        }
      }
    }
  }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 19, 2017, 12:34 pm
* A mon avis ici c'est pas _SSID qu'il faut mais copie_SSID et idem pour _MDP il faut prendre copie_MDP à condition bien sûr de les avoir extraits auparavant
Code: [Select]
strcat(GSM_MessageLine, _SSID);
...
strcat(GSM_MessageLine, _MDP);


* Le code suppose que votre SMS ne contienne pas plusieurs lignes - mais ça peut être une convention.

* C'est mieux quand les commentaires correspondent au code :)
Code: [Select]
else if (!strncmp(GSM_MessageLine, "Ssid", 4)) { // 6 parce que 6 caractères dans le mot "CONFIG".
..
else if (!strncmp(GSM_MessageLine, "Mdp", 3)) { // 6 parce que 6 caractères dans le mot "CONFIG"
passez aussi éventuellement  tous les commentaires en français, ce sera utile pour les non anglophones

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 19, 2017, 02:41 pm
* A mon avis ici c'est pas _SSID qu'il faut mais copie_SSID et idem pour _MDP il faut prendre copie_MDP à condition bien sûr de les avoir extraits auparavant
Code: [Select]
strcat(GSM_MessageLine, _SSID);
...
strcat(GSM_MessageLine, _MDP);
Au début le code était comme vous dite mais du coup le contenu n'était pas enregistré dans  _SSID
C'est pour cela qua j'ai fait
Code: [Select]
_SSID = copie_SSID;


* Le code suppose que votre SMS ne contienne pas plusieurs lignes - mais ça peut être une convention.
Les MDP reseau peuvent être assez long.
j'ai testé des sms avec "MDP 20caracterre espace 5 caractères espace 20 caractères" soit 51 caractères et tout ces bien passé. Quand j'ai ensuite envoyer CONFIG, j'ai bien reçu tout le MDP soit 47 caractères.
Donc pour moi c'est OK (a voir dans le code principal + wifi)

* C'est mieux quand les commentaires correspondent au code :)
Code: [Select]
else if (!strncmp(GSM_MessageLine, "Ssid", 4)) { // 6 parce que 6 caractères dans le mot "CONFIG".
..
else if (!strncmp(GSM_MessageLine, "Mdp", 3)) { // 6 parce que 6 caractères dans le mot "CONFIG"

passez aussi éventuellement  tous les commentaires en français, ce sera utile pour les non anglophones
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 19, 2017, 02:41 pm
Code: [Select]
#define gsm Serial1

char * _SSID ;
char * _MDP ;

const byte ctrlZ = 0x1A;
const char * ctrlZString = "\x1A";
const char * escapeString = "\x1B";

const char * ATString = "AT";
const char * OKShortString = "OK";
const char * OKLongString = "\r\nOK\r\n";

const byte max_SSID = 50;// prévoir la bonne longueur
char copie_SSID[max_SSID+1];
const byte max_MDP = 50;// prévoir la bonne longueur
char copie_MDP[max_MDP+1];

         
const uint32_t oneSecond = 1000ul;

const byte maxMessageSize = 200;
char GSM_MessageLine[maxMessageSize + 1]; // +1 pour le '\0' à la fin de la c-string

// --------------------------------------
//GsmPrintlnAndWaitATCommand exécute une commmand AT en ajoutant à la fin CR LF
//alors, il vérifie si endMarker est recu sur le Port série GSM
//pour la durée Max , boolean si le marqueur a été trouvé
//avec l'option verbeuse, les info du GSM sont imprimées dans le serial

// --------------------------------------

boolean gsmPrintlnAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.println(command);
  return waitForString(endMarker, duration, verbose);
}

boolean gsmPrintAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose)
{
  gsm.print(command);
  return waitForString(endMarker, duration, verbose);
}

// --------------------------------------
//GsmPrintATCommand ou gsmpWriteATCommand est utilisé quand vous ne voulez pas envoyer à CR LF
//à la fin de la ligne de commmand; utilisez il développer une partie multi commande
//la même syntaxe est imprimé comme ils sont des Macros Variadic utilisant imprimé ou écrivent
// --------------------------------------

#define gsmPrintATCommand(...)    gsm.print(__VA_ARGS__)
#define gsmPrintlnATCommand(...)  gsm.println(__VA_ARGS__)
#define gsmWriteATCommand(...)    gsm.write(__VA_ARGS__)


// --------------------------------------
// Lise une ligne de gsm, ignorez '\r ' et des retours vrais si '\n ' est trouvé
// --------------------------------------

boolean getGSMLine()
{
  static byte indexMessage = 0;
  boolean incomingMessage = true;

  while (gsm.available() && incomingMessage) {
    int c = gsm.read();
    if (c != -1) {
      switch (c) {
        case '\n':
          GSM_MessageLine[indexMessage] = '\0'; // a la fin character NULL pour c-string correct
          indexMessage = 0; // pret pour la suite
          incomingMessage = false;
          break;
        case '\r': // n'est pas pris en compte
          break;
        default:
          if (indexMessage <= maxMessageSize - 1) GSM_MessageLine[indexMessage++] = (char) c; // sinon ignoré
          break;
      }
    }
  }
  return !incomingMessage;
}

// --------------------------------------
// WaitForString attend la duree Max ms en vérifiant si endMarker est reçue
// Sur le Port série GSM rend une déclaration boolean si le marqueur a été trouvé
// --------------------------------------

boolean waitForString(const char * endMarker, unsigned long duration, boolean verbose)
{
  int localBufferSize = strlen(endMarker);
  char localBuffer[localBufferSize];
  int index = 0;
  boolean endMarkerFound = false;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // effacer buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (gsm.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) gsm.read();
      if (verbose) Serial.print((char) localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}

void dieHere()
{
  while (true);
}


void setup() {
  Serial.begin(115200);
  gsm.begin(9600); // suivant votre config, essayez 9600 19200 38400 57600 74880 115200

  // prévoir éventuellement AT+CPIN="1234" pour rentrer le PIN

  if (gsmPrintlnAndWaitATCommand(ATString, OKLongString, 5 * oneSecond, false)) {
    Serial.println(F("GPRS Modem OK"));
  } else {
    Serial.println(F("Erreur GPRS Modem"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("AT+GSV", OKLongString, oneSecond, true)) {
    Serial.print(F("Erreur Version"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATE0", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Echo off"));
    dieHere();
  }

  if (!gsmPrintlnAndWaitATCommand("ATV1", OKLongString, oneSecond, false)) {
    Serial.print(F("Erreur Message en Verbal"));
    dieHere();
  }

  // on passe en les SMS en mode texte
  if (!gsmPrintlnAndWaitATCommand("AT+CMGF=1", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CMGF"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }


  // on passe en mode routage des SMS vers le terminal
  if (!gsmPrintlnAndWaitATCommand("AT+CNMI=1,2,0,0,0", OKLongString, oneSecond, true)) {
    Serial.print(F("Error AT+CNMI"));
    // dieHere(); // on ne meurt pas ici mais AT+CNMI non configurgé
  }

  Serial.println("Initialisation terminé");
}

boolean sendSMS(const char * noDeTel, const char * messageAEnvoyer)
{
  boolean SMSenvoye = false;
  gsmPrintATCommand("AT+CMGS=\"");
  gsmPrintATCommand(noDeTel);

  if (gsmPrintlnAndWaitATCommand("\"", ">", oneSecond, false)) {
    gsmPrintlnATCommand(messageAEnvoyer);
    SMSenvoye = gsmPrintlnAndWaitATCommand(ctrlZString, OKShortString, 5 * oneSecond, false);
  } else {
    gsmPrintlnATCommand(escapeString);
  }
  return SMSenvoye;
}

void loop()
{
  if (getGSMLine()) {
    // ********************************************
    // TEST RECEPTION D'UN SMS
    // +CMT: "+33620000000",,"01/03/22,16:33:31+00"<CRLF>
    // texte bla bla bla<CRLF>
    // ********************************************
    if (!strncmp(GSM_MessageLine, "+CMT:", 5)) {// 5 parce que "+CMT:" c'est 5 caractères, on compare le début de la chaîne
      const byte maxDigitsPhoneNb = 30;
      char phoneNb[maxDigitsPhoneNb + 1];
      char *ptr = strtok(GSM_MessageLine, "\"");
      if (ptr) {
        ptr =  strtok(NULL, "\"");
        strncpy(phoneNb, ptr, maxDigitsPhoneNb);
        phoneNb[maxDigitsPhoneNb] = '\0';

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("SMS de = ")); Serial.println(phoneNb);
        // ***

        while (!getGSMLine()); // on attend le texte du SMS

        // *** DEBUG *** POUR VOIR CE QU'IL SE PASSE
        Serial.print(F("Message = [")); Serial.print(GSM_MessageLine); Serial.println(F("]"));
        // ***

        if (!strncmp(GSM_MessageLine, "CONFIG", 6)) { // 6 parce que 6 caractères dans le mot "CONFIG"
          // on a reçu un SMS nous demandant la config, on construit la réponse
          strcpy(GSM_MessageLine, "La config est la suivante:\r\nSSID = ");
          strcat(GSM_MessageLine, _SSID);
          strcat(GSM_MessageLine, "\r\nMot de Passe = ");
          strcat(GSM_MessageLine, _MDP);
          sendSMS(phoneNb, GSM_MessageLine);
        }
        else if (!strncmp(GSM_MessageLine, "Ssid", 4)) { // 4 parce que 4 caractères dans le mot "Ssid"
          // on a reçu un SMS nous indiquant un nouveau Ssid, on construit la réponse
          _SSID = GSM_MessageLine + 5; // on extrait le Ssid du message
          strncpy(copie_SSID, _SSID,max_SSID);
          copie_SSID[max_SSID] = '\0';
          _SSID = copie_SSID;
          strcpy(GSM_MessageLine, "nouveau SSID recu = ");
          strcat(GSM_MessageLine, _SSID);
          sendSMS(phoneNb, GSM_MessageLine);
        }
        else if (!strncmp(GSM_MessageLine, "Mdp", 3)) { // 3 parce que 3 caractères dans le mot "Mdp"
           // on a reçu un SMS nous indiquant un nouveau Mdp, on construit la réponse
          _MDP = GSM_MessageLine + 4; // on extrait le Mdp du message
          strncpy(copie_MDP, _MDP,max_MDP);
          copie_MDP[max_MDP] = '\0';
          _MDP = copie_MDP;
          strcpy(GSM_MessageLine, "nouveau MDP recu = ");
          strcat(GSM_MessageLine, _MDP);
          sendSMS(phoneNb, GSM_MessageLine);
        }         
        else {
          sendSMS(phoneNb, "Instruction non comprise");
        }
      }
    }
  }
}


 :)

J'ai fait au mieux pour la traduction
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 19, 2017, 03:22 pm
Ah oui j'avais raté le _SSID = copie_SSID; donc ça va (vous auriez pu directement utiliser copie_SSID)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 19, 2017, 03:43 pm
Ah oui j'avais raté le _SSID = copie_SSID; donc ça va (vous auriez pu directement utiliser copie_SSID)


Dans la partir wifi le ssid et mdp sont déclare en char *
J'ai donc fait comme ca pour que la "fusion" des code ne pause pas de problème.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 19, 2017, 04:04 pm
Comme très souvent je comprend le principe ... Ya qu'a ... lol
la plus part des fonctions sont generé en fonction de l'heure.
exemple, de 10h a 12h lever soleil
de 12h a 20h soleil zenith
20h a 22h coucher soleil
de 22h a 10h eteint

Le code donne ca:
Code: [Select]
if ((time >= LEVERbleu1) && (time < finLEVERbleu1)){
  pwmbleu1 = map(time, LEVERbleu1, finLEVERbleu1, 0, puissancebleu);
  analogWrite (bleu1, pwmbleu1);
  }
else if ((time >= COUCHERbleu1) && (time < finCOUCHERbleu1)){ 
  pwmbleu1 = map(time, COUCHERbleu1, finCOUCHERbleu1, puissancebleu, 0);
  analogWrite (bleu1, pwmbleu1);
  }   
else if ((time >= finLEVERbleu1 ) && (time < COUCHERbleu1)) {
  pwmbleu1 = puissancebleu;
  analogWrite(bleu1, puissancebleu);
  }
else {
  pwmbleu1 = 0;
  analogWrite(bleu1, 0);


Dans le loop il faut donc mettre la lecture de l'heure.
Dans le setup, associé chaque créneau horaire a une fonction
Déclarer chaque fonction en VOID

c'est ca ?
Et pour organiser mon code ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 23, 2017, 09:38 am
J'ai cree des void pour chaque fonction "complète"
sa compile en fonctionne et j'ai remarqué une difference :
avant :
Code: [Select]
Le croquis utilise 13600 octets (5%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 1288 octets (15%) de mémoire dynamique, ce qui laisse 6904 octets pour les variables locales. Le maximum est de 8192 octets.


apres:
Code: [Select]
Le croquis utilise 13464 octets (5%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 746 octets (9%) de mémoire dynamique, ce qui laisse 7446 octets pour les variables locales. Le maximum est de 8192 octets.


Cela fait partie du but recherché ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 23, 2017, 10:54 am
Non le  but est vraiment de structurer correctement la boucle. si la mémoire allouée baisse, vérifier exactement ce que vous avez fait au niveau des variables globales - votre #include précédent mettait tout dans la boucle principale, en vrac

Petit point (amical) sur le vocabulaire un void ne veut rien dire dans votre contexte, on appelle cela une fonction. void c'est juste le type retourné par la fonction  - c'est à dire "rien" :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 23, 2017, 11:10 am
Ok pour void les fonctions  :)

Voila le code modifié,
C'est plus clair ou il y a encore des choses a modifier ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 23, 2017, 11:49 am
Je suis depuis quelle jours sur l'écriture et lecture de la carte SD
Dans un premier temps pour y stocker mon Ssid et Mdp mais par la suite pouvoir stocker mes mesure et y accéder via internet (bref, on en est pas la :) )

Je suis donc arrivé au code ci dessous
Code: [Select]
#include <SPI.h>
#include <SD.h>

File myFile;
char * ssid;
char lecture[50];

int i=0 ;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(53)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("ssid.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to ssid.txt...");
    myFile.seek(0);
    myFile.println("t'en a pas marre d'ecrire des conneries ?");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening ssid.txt");
  }

  // re-open the file for reading:
  myFile = SD.open("ssid.txt");
  if (myFile) {
    Serial.println("ssid.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()>0){
      lecture[i] = myFile.read();
      i++;
       
    }


   
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
      ssid = lecture;
      Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
      Serial.print(ssid);
      Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
 
}

void loop() {
  // nothing happens after setup
}


et je pense avoir enfin de compris (je crois) le fonctionnement de "i"
Dans le cas présent on lis octet par octet le texte du fichier sd.
Le premier caractère est stocker dans "lecture [1]" le second dans "lecture[2]" ...
et donc au final lecture = caractère 1+2 ...
Si c'est ça, j'ai mis le temps ... :) mieux vos tard que jamais :)

Y a t'il des erreur/amélioration a faire sur ce code ?




Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 23, 2017, 12:21 pm
Quote
et je pense avoir enfin de compris (je crois) le fonctionnement de "i"
Dans le cas présent on lis octet par octet le texte du fichier sd.
Le premier caractère est stocker dans "lecture [1]" le second dans "lecture[2]" ...
et donc au final lecture = caractère 1+2 ...
Si c'est ça, j'ai mis le temps ... :) mieux vos tard que jamais :)
Bravo :)

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)

Je vous recommande d'utiliser SDFat (https://github.com/greiman/SdFat) au lieu de SD. C'est du même auteur que celle qui est dans l'IDE mais elle est plus avancée, plus robuste.


Pour
Code: [Select]
  Serial.begin(9600);prenez l'habitude plutôt de travailler à 115200 ou 74880 (pour les ESP souvent leur configuration par défaut)

Pour
Code: [Select]
  if (!SD.begin(53)) {éviter de coder en dur 53. ce que vous passez en paramètre c'est la broche matérielle SS (broche 10 sur la plupart des cartes Arduino et 53 sur la Mega) et donc puisque vous utilisez la vraie, autant utiliser son petit nom
Code: [Select]
  if (!SD.begin(SS)) { ce qui fait que le code est plus portable (va fonctionner aussi sur UNO).

Quand vous faites cela
Code: [Select]
    // read from the file until there's nothing else in it:
    while (myFile.available() > 0) {
      lecture[i] = myFile.read();
      i++;
    }
il serait bon de tester que vous ne dépassez pas la taille du tableau lecture sinon ça va mettre la pagaille dans la mémoire.

sinon ça devrait être bon (j'ai pas testé - juste lu le code)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 23, 2017, 01:07 pm
Ok pour void les fonctions  :)

Voila le code modifié,
C'est plus clair ou il y a encore des choses a modifier ?

je tâcherai de trouver un peu plus de temps pour regarder cela - mais c'est bcp de code donc....

j'ai déjà noté un bug

Code: [Select]
int duree_nourissage = 20; // durée du nourissage minute/ pompe de brassage au minimum
...
  if (millis() - temps_precedent_nourissage <= (duree_nourissage * 60000)) {


comme duree_nourissage est un entier, l'expression duree_nourissage * 60000 va être effectuée en entier et ça va faire un overflow il faut écrire duree_nourissage * 60000ul

Je vous conseille de déclarer tout ce qui touche au temps en unsigned long et de ne pas avoir de valeurs qui trainent dans le code comme 60000 mais de les déclarer avec un joli nom au début du code (ou dans un .h que vous importez) du genre
Code: [Select]
const unsigned long uneMinute = 60000ul; // 60 secondes en millisecondesle code de votre test devient ensuite

Code: [Select]
  if (millis() - temps_precedent_nourissage <= (duree_nourissage * uneMinute)) { ce qui est déjà un peu plus lisible, mais j'irai un cran plus loin et je définirais duree_nourissage directement en ms comme ça le code se lit partout plus simplement (et petite prime la durée du nourissage peut être maintenant gérée plus finement comme 1 min 30 par exemple)
Code: [Select]
unsigned long duree_nourissage = 20 * uneMinute; // durée du nourissage minute/ pompe de brassage au minimum
...
if (millis() - temps_precedent_nourissage <= duree_nourissage) {


--> à changer partout, par exemple ici aussi vous avez le même soucis
Code: [Select]
  else if (millis() - temps_precedent_tempette <= (duree_tempette * 60000)) {


Pour la gestion du temps vous avez déclaré en variables globales
Code: [Select]
unsigned long temps_precedent_oscillo, temps_precedent_nourissage, temps_precedent_tempette;
, comme je pense qu'elles ne servent pas ailleurs que dans les fonctions associées, pour simplicité de lecture il vaut mieux les déclarer (bien sûr en static pour que la valeur ne soit pas perdue en sortie de fonction) chacune directement dans la fonction adéquate

Code: [Select]
    else if (brassage1_ON == 1) { // si brassage1 ON
...
    else if (brassage1_ON == 2) { // si brassage1 PWM


au lieu d'utiliser 1, 2 qui sont des valeurs qu'on ne comprend pas, créez un enum pour avoir des petits noms sympas
Code: [Select]
enum modeBrassage_t : byte {brassageArret=0, brassageActif=1, brassagePWM=2}; // valeurs données pour l'exemple, ce seraient les valeurs par défaut car un enum compte depuis 0
modeBrassage_t brassage1_ON = brassagePWM, brassage2_ON = brassagePWM, brassage3_ON = brassagePWM;

...

else if (brassage1_ON == brassageActif) { // si brassage1 ON
...
    else if (brassage1_ON == brassagePWM { // si brassage1 PWM

C'est quand même plus lisible, non?


Pourquoi aller lentement sur la console Série?
Code: [Select]
  Serial.begin(9600);


Les boutons ne sont pas en INPUT_PULLUP? vous avez une résistance externe?
Code: [Select]
  pinMode(pinIN_bouton_alimentation, INPUT);
  pinMode(pinIN_bouton_tempete, INPUT);


Je vois que vous utilisez toujours un DS1307, mon conseil serait de passer sur un DS3231 pour la stabilité

appuyez sur ctrl-T dans l'IDE, vous verrez que votre indentation deviendra toute suite plus jolie

un bon début en tout cas :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 23, 2017, 11:02 pm
Bravo :)

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)
:)  :)  :) ca fait 3  ;D  ;D  ;D

Quand vous faites cela
Code: [Select]
   // read from the file until there's nothing else in it:
    while (myFile.available() > 0) {
      lecture[i] = myFile.read();
      i++;
    }

il serait bon de tester que vous ne dépassez pas la taille du tableau lecture sinon ça va mettre la pagaille dans la mémoire.
Je m'était posé la question justement ... sans trop savoir comment je pouvais verifier ca ...   :smiley-confuse:

Avec
Code: [Select]
lectureMAX strlen(myFile.read())
Puis
Code: [Select]
if (lectureMAX>50){
lecture[i] = myFile.read();
      i++;
}


 ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 23, 2017, 11:03 pm
Pour la réponse sur mon code principal, j'ai pris ma journée demain pour bosser la dessus  :D  :D
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 23, 2017, 11:14 pm
à quel index du tableau sauvez vous le caractère lu? comment peut on savoir si on a débordé du tableau (combien de cases a-t-on?)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 23, 2017, 11:30 pm
à quel index du tableau sauvez vous le caractère lu? comment peut on savoir si on a débordé du tableau (combien de cases a-t-on?)
au caractère 0.
Lecture a été déclaré char lecture [50], d'ou if (lectureMAX>50)
mais peut être que if (lectureMAX>lecture) serait mieux
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 12:56 am
J'essaye à nouveau:
Code: [Select]
lecture[i] = myFile.read();à quel index écrit-on le caractère lu?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 08:40 am
lecture  ::)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 09:20 am
lecture  ::)
je vais enlever le bon point... :) que vous aviez eu quand vous aviez expliqué
Quote
Le premier caractère est stocké dans "lecture [1]" le second dans "lecture[2]" ...
L'index c'est le N° de la case (l'adresse de l'octet en mémoire depuis le début du tableau pour faire simple dans notre cas avec des caractères) dans laquelle on va stocker le caractère.... donc c'est la variable i qui indique cela... lecture c'est le nom du tableau (et accessoirement un pointeur sur la première case du tableau). Quand vous avez déclaré
Code: [Select]
char lecture[50]; vous créez un tableau qui peut contenir 50 caractères. Les indices commencent à 0 et donc le dernier endroit de stockage autorisé dans ce tableau est à l'index 49.

Je reviens donc à ma question: que devez vous tester quand vous écrivez
Code: [Select]
lecture[i] = myFile.read(); pour vous assurer de ne pas écrire dans une case non autorisée ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 09:41 am
J'ai bien compris  le "i"
Me retire pas mon point  :(
 8)

C'est la tournure de la question  :P

Code: [Select]
strcmp (à quel index écrit-on le caractère lu?, que devez vous testez quand vous écrivez)

 :smiley-twist:


Il ne faut pas que "i" dépasse 49.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:00 am
J'ai bien compris  le "i"
Me retire pas mon point  :(
 8)
donné c'est donné, reprendre c'est voler :)

C'est la tournure de la question  :P
Code: [Select]
strcmp (à quel index écrit-on le caractère lu?, que devez vous testez quand vous écrivez)
 :smiley-twist:
je n'ai jamais parlé de strcmp()... c'est vous... non il n'y a pas besoin de strcmp() et surtout pas si vous n'avez pas mis un caractère nul à la fin de la chaîne...


Il ne faut pas que "i" dépasse 49.
ben voilà - donc quel est le bout de code en C qui dirait
si i est inférieur ou égal à 49 alors ajouter l'élément lu dans le tableau puis augmenter i ??
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:07 am
Code: [Select]

const byte lectureMAX = 49;
char lecture (lectureMAX+1);

while (myFile.available() > 0) {
      if (i=<lectureMAX){
      lecture[i] = myFile.read();
      i++;
      }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:09 am
char lecture (lectureMAX+1); euh.... :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:10 am
c du chipotage la  :P
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:10 am
Code: [Select]
const byte lectureMAX = 49;
char lecture [lectureMAX+1];

while (myFile.available() > 0) {
      if (i=<lectureMAX){
      lecture[i] = myFile.read();
      i++;
      }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:11 am
=< .. euh... :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:11 am
ouai, c'est comme droite et gauche ... j'inverse tout le temps  :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:12 am
Code: [Select]
const byte lectureMAX = 49;
char lecture [lectureMAX+1];

while (myFile.available() > 0) {
      if (i<=lectureMAX){
      lecture[i] = myFile.read();
      i++;
      }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:13 am
ouai, c'est comme droite et gauche ... j'inverse tout le temps  :smiley-confuse:
c'est comme en français on dit "inférieur ou égal" donc on écrit < puis =

sinon une fois que le tableau est plein, que pensez vous que votre while va faire puisqu'on n'a pas lu le caractère suivant? (indice - penser à l'instruction break)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:14 am
il va tourné en rond ...
Longtemps ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:15 am
Code: [Select]
const byte lectureMAX = 49;
char lecture [lectureMAX+1];

while (myFile.available() > 0) {
      if (i<=lectureMAX){
      lecture[i] = myFile.read();
      i++;
      }
 break

}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:32 am
euh... :)

(regardez bien où vous l'avez placé)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:32 am
Petite question sur la fonction millis().

Que se passe t il quand millis() devient un numérique trop grand (plus grand que unsigned long ?) ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:33 am
euh... :)

(regardez bien où vous l'avez placé)
Je l'ai modifier 3 fois ... falais bien que ce ne soit pas au bonne endroit.
J'hesitait entre le mettre dans le if ou dans while ...

Donc dans le if
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:35 am
Petite question sur la fonction millis().

Que se passe t il quand millis() devient un numérique trop grand (plus grand que unsigned long ?) ?
il retourne à 0 (il faut quand même plus de 54 jours)

mais si vous avez bien écrit (comme vous le faites) des if (millis() - lastMoment >= duree) {...} alors c'est tout à fait fonctionnel même si millis() est revenu à zéro car au contraire de l'addition, la soustraction en unsigned va faire que cela va fonctionner



Je l'ai modifier 3 fois ... falais bien que ce ne soit pas au bonne endroit.
J'hesitait entre le mettre dans le if ou dans while ...

Donc dans le if
Non :)

s'il y a de la place vous voulez continuez à lire, pas vous arrêter de lire. c'est quand il n'y a plus de place que vous voulez interrompre le while... donc il faut un .... au if
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:39 am
Code: [Select]
const byte lectureMAX = 49;
char lecture [lectureMAX+1];

while (myFile.available() > 0) {
      if (i<=lectureMAX){
      lecture[i] = myFile.read();
      i++;
      }
      else {
      break;
      }
}


Arf ... avoir un code qui fonctionne (a première vu) et toute ces petite chose qui finiront pas générer des BUG ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:40 am
il retourne à 0 (il faut quand même plus de 54 jours)
Ta été calculer ça ...  :-X  :D
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:42 am
modeBrassage_t brassage1_ON = brassagePWM, brassage2_ON = brassagePWM, brassage3_ON = brassagePWM;
Cette ligne ne serre qu'a passer en pwm au démarrage ?
Si oui, elle fonctionnerais egalement comme ca :
Code: [Select]
modeBrassage_t brassage1_ON = 2, brassage2_ON = 2, brassage3_ON = 2;
 
? c'est pour le stockage dans l'eeprom que je pence a ça.

Mais vu que chaque pompe peut etre reglé individuelement, il faut que je fasse :
Code: [Select]
enum modeBrassage1 : byte {brassage1Arret, brassage1Actif, brassage1PWM};
enum modeBrassage2 : byte {brassage2Arret, brassage2Actif, brassage2PWM};
enum modeBrassage3 : byte {brassage3Arret, brassage3Actif, brassage3PWM};


Sinon quand je vais modifier la valeur de modeBrassage toute les pompes seront affecté ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:59 am
Ta été calculer ça ...  :-X  :D
je m'en souviens - il suffit de regarder ce que font 4 294 967 295 millisecondes :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:01 am
je m'en souviens - il suffit de regarder ce que font 4 294 967 295 millisecondes :)


49,71026961805556 jours

Oula ... il sont ou les 54 jours ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:02 am
ça c'est pour définir des constantes - c'est mieux que vos 1, 2 ...
Code: [Select]
enum modeBrassage : byte {brassageArret, brassageActif, brassagePWM};

ensuite vous pouvez dire

Code: [Select]
modeBrassage1 = brassageArret; // cette pompe est à l'arrêt
modeBrassage2 = brassageActif; // cette pompe est à fond
modeBrassage3 = brassagePWM; // cette pompe est en PWM


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:02 am
49,71026961805556 jours

Oula ... il sont ou les 54 jours ?
euh - oui c'est p't'être bien 49 et quelques et pas 54 d'ailleurs... comme quoi la mémoire :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:04 am
Quote from: J-M-L link=msg=3498716 date=1511517721
ensuite vous pouvez dire

[code
modeBrassage1 = brassageArret; // cette pompe est à l'arrêt
modeBrassage2 = brassageActif; // cette pompe est à fond
modeBrassage3 = brassagePWM; // cette pompe est en PWM[/code]


a et enfaite pour modifier le principe reste le même, si j'envoie 2 a brassage2 il interprete 2 comme brassagePWM
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:14 am
ah et en fait pour modifier le principe reste le même, si j'envoie 2 a brassage2 il interprete 2 comme brassagePWM
oui (à condition qu'ils soient définis dans le bon ordre - le premier dans la liste vaut 0, le second vaut 1, etc - sauf si vous leur donnez des valeurs) mais l'idée est vraiment d'arrêter d'utiliser des nombres magiques que personne ne comprend et plutôt des constantes avec un joli nom que tout le monde peut comprendre (ou vous dans 1 an quand vous reviendrez relire le code)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:18 am
mais je pense a la page web, les bouton incrémente +1 a modeBrassage
pour ensuite faire brassage1 = modebrassage ?
Et la je ne comprend pas comment brassage2 et 3 ne vont pas passer dans le meme mode

il faut donc bien que je fasse
Code: [Select]
enum modeBrassage1 : byte {brassage1Arret, brassage1Actif, brassage1PWM};
enum modeBrassage2 : byte {brassage2Arret, brassage2Actif, brassage2PWM};
enum modeBrassage3 : byte {brassage3Arret, brassage3Actif, brassage3PWM};
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:26 am
Non.
Code: [Select]
enum modeBrassage1 : byte {brassage1Arret, brassage1Actif, brassage1PWM};
enum modeBrassage2 : byte {brassage2Arret, brassage2Actif, brassage2PWM};
enum modeBrassage3 : byte {brassage3Arret, brassage3Actif, brassage3PWM};


vous n'avez pas défini 3 fois la valeur '1' ou '2'....  vous définissez juste un petit nom générique. ensuite vos variables prennent une de ces valeurs.

faire cela:
Code: [Select]
modeBrassage1 = brassageArret; // cette pompe est à l'arrêt
modeBrassage2 = brassageActif; // cette pompe est à fond
modeBrassage3 = brassagePWM; // cette pompe est en PWM

c'est comme faire
Code: [Select]
modeBrassage1 = 0; // cette pompe est à l'arrêt
modeBrassage2 = 1; // cette pompe est à fond
modeBrassage3 = 2; // cette pompe est en PWM

mais c'est plus lisible.


(si j'ai bien compris il y a 3 pompes de brassage hein?)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:35 am
oui ok mais a quoi j'incrémente mon +1 des bouton web ?
je doit faire
Code: [Select]

enum modeBrassage : byte {brassageArret, brassageActif, brassagePWM};
int brassage1_ON = brassagePWM, brassage2_ON = brassagePWM, brassage3_ON = brassagePWM;

Et par exemple le bouton incrémente -1 a brassage1_ON qui devient a lors brassage1_ON = brassage actif ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:48 am
Code: [Select]
 else if (millis() - temps_precedent_tempette <= (duree_tempette * 60000)) {

Ok, c'est vrai que c'est mieux :)

mais j'irai un cran plus loin et je définirais duree_nourissage directement en ms comme ça le code se lit partout plus simplement
Puisque ce temps  est paramétrable via web, je serait obliger de faire la division donc un calcul dans les 2 cas. Il me parait plus simple ( a lire) de déclarer duree_nourissage en minute et que l'Arduino face le calcule plutôt que déclarer en millis et faire le calcul.

Pour la gestion du temps vous avez déclaré en variables globales
Code: [Select]
unsigned long temps_precedent_oscillo, temps_precedent_nourissage, temps_precedent_tempette;

, comme je pense qu'elles ne servent pas ailleurs que dans les fonctions associées
Pour temps_precedent_oscillo, Ok, utilisé dans une seule fonction.
J'ai fait :
Code: [Select]
void OSCILLO() {
  static unsigned long temps_precedent_oscillo;


Pour les 2 autres, elles sont utilisées dans plusieurs fonction (dans bouton pour les faire =millis() puis dans leur fonction respective, if (temps_precedent *** <= ****)

Pourquoi aller lentement sur la console Série?
Code: [Select]
 Serial.begin(9600);

Hey man … (https://www.youtube.com/watch?v=dCW4EJUS5is&list=RDdCW4EJUS5is&t=10).on n'est pas pressé …


:) :) :)

Ça change quoi d'aller plus vite ?

Les boutons ne sont pas en INPUT_PULLUP? vous avez une résistance externe?
Code: [Select]
 pinMode(pinIN_bouton_alimentation, INPUT);
  pinMode(pinIN_bouton_tempete, INPUT);

Oui j'ai mis une résistance mais si je peut la retirer …

Je vois que vous utilisez toujours un DS1307, mon conseil serait de passer sur un DS3231 pour la stabilité
Non, non, je suis sur un ds3231 mais la bibliothèque fonctionne également.

Appuyez sur ctrl-T dans l'IDE, vous verrez que votre indentation deviendra toute suite plus jolie
Magie …

Un bon début en tout cas :)
Heu … Hin … je … je … heu …
Comment ça « début » … ???
J'y suis depuis juin  :o
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:50 am
oui ok mais a quoi j'incrémente mon +1 des bouton web ?
je doit faire
Code: [Select]

enum modeBrassage : byte {brassageArret, brassageActif, brassagePWM};
int brassage1_ON = brassagePWM, brassage2_ON = brassagePWM, brassage3_ON = brassagePWM;

Et par exemple le bouton incrémente -1 a brassage1_ON qui devient a lors brassage1_ON = brassage actif ?
d'une part définir les variables sous le type byte pour être cohérent et économiser 3 octets :-)

Quand vous faites
Code: [Select]
enum modeBrassage : byte {brassageArret, brassageActif, brassagePWM};

modeBrassage devient le nom d'un "type" comme "byte" ou "int" donc ensuite il faut dire
Code: [Select]
modeBrassage brassage1_ON = brassagePWM, brassage2_ON = brassagePWM, brassage3_ON = brassagePWM;

pour ce qui est d'ajouter ou enlever 1, ça fonctionne toujours puisque les "petits noms" ont pris des valeurs séquentielles en comptant depuis 0.

Pour être propre généralement on rajoutera à la fin du enum une valeur "finale" qui marque la fin de la liste des modes possibles
Code: [Select]
enum modeBrassage : byte {brassageArret, brassageActif, brassagePWM, finDeListe};


et ensuite quand on clique pour passer au mode suivant vous testez si le mode courant est == à finDeListe si oui vous passez à 0 ou brassageArret et pour les autres c'est OK d'ajouter 1.


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 12:13 pm
Quote
Non, non, je suis sur un ds3231 mais la bibliothèque fonctionne également.
--> utiliser l'objet approprié alors le 3231 pas le 1307 (il y en a plusieurs dans la librairie)

Quote
Oui j'ai mis une résistance mais si je peut la retirer …
les INPUT_PULLUP activent une résistance interne sur la pin... donc vous connectez
Pin Arduino <--> bouton <--> GND
et la pin est HIGH quand le bouton n'est pas actif et devient LOW quand active

Quote
Ça change quoi d'aller plus vite ?
votre loop() fait plein de choses et sera un peu lente et vous utilisez plein de port séries. Un buffer série ne contient que 64 octets, si les données arrivent plus vite que vous ne les lisez vous allez perdre des données. Si vous écrivez en sortie Série et que le buffer est plein (ie vous envoyez bcp de données) alors le Serial.print() ou le Serial.write() deviennent bloquant - un peu comme si vous aviez un delay(), donc plus vite les octets quittent votre arduino, plus vite votre arduino va passer à la suite du code



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 12:20 pm
--> utiliser l'objet approprié alors le 3231 pas le 1307 (il y en a plusieurs dans la librairie)
Il n'y a que le commentaire que je n'ai pas changer car j'ai bien
Code: [Select]
// **************************************** horloge
RTC_DS3231 rtc;
unsigned long Time, H;
unsigned int M, S;



les INPUT_PULLUP activent une résistance interne sur la pin... donc vous connectez
Pin Arduino <--> bouton <--> GND
et la pin est HIGH quand le bouton n'est pas actif et devient LOW quand active
Je met ca de coté car la majorité des retour de futur utilisateur que j'ai eu veut un écran tactil ...


votre loop() fait plein de choses et sera un peu lente et vous utilisez plein de port séries. Un buffer série ne contient que 64 octets, si les données arrivent plus vite que vous ne les lisez vous allez perdre des données. Si vous écrivez en sortie Série et que le buffer est plein (ie vous envoyez bcp de données) alors le Serial.print() ou le Serial.write() deviennent bloquant - un peu comme si vous aviez un delay(), donc plus vite les octets quittent votre arduino, plus vite votre arduino va passer à la suite du code
A oui, je comprend ...
Mais du coup cela explique peut être le problème avec le code GSM une fois qu'il est inclue dans le code principal ...
Le gsm est en 9600 et 1 fois sur deux les sms ne sont pas reçu ou plutôt traité entièrement (le numéro de tel mais pas le message lui même) et du coup rien n'est pris en compte ...

C'est plausible ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 12:23 pm
bonne ap
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 02:08 pm
Quote
Puisque ce temps  est paramétrable via web, je serait obliger de faire la division donc un calcul dans les 2 cas. Il me parait plus simple ( a lire) de déclarer duree_nourissage en minute et que l'Arduino face le calcule plutôt que déclarer en millis et faire le calcul.
ce que vous présentez à l'utilisateur n'est pas forcément la valeur interne... une multiplication c'est pas la fin du monde :)


Quote
Mais du coup cela explique peut être le problème avec le code GSM une fois qu'il est inclue dans le code principal ...
Le gsm est en 9600 et 1 fois sur deux les sms ne sont pas reçu ou plutôt traité entièrement (le numéro de tel mais pas le message lui même) et du coup rien n'est pris en compte ...
c'est possible - le GSM envoie plus de 64 octets entre l'en tête et le contenu du SMS - si vous ne le lisez pas assez vite alors vos allez perdre des données du début

c'est aussi pour cela que je disais qu'il faut bien structurer la loop() et pas tout balancer à la suite de manière à ce que les fonctions stratégiques ne soient pas privées longtemps de travailler.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 03:12 pm
Il faut peut être mieux ne pas faire de multiplication a répétition dans le loop et faire une division 1 fois lorsque l'on demande la page internet ...
Dit comme sa, sa change tout :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 03:25 pm
ca donne ca avec toute les petite modif
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 04:19 pm
J'ai instaler sdfat
Code: [Select]
#include <SPI.h>
#include <SDFat.h>

File myFile;
char * ssid;
char lecture[50];

int i=0 ;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(53)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("ssid.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to ssid.txt...");
    myFile.seek(0);
    myFile.println("t'en a pas marre d'ecrire des conneries ?");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening ssid.txt");
  }

  // re-open the file for reading:
  myFile = SD.open("ssid.txt");
  if (myFile) {
    Serial.println("ssid.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()>0){
      lecture.indexOf(i, myFile.read());
      i++; 
    }


   
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
ssid = lecture;
      Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
      Serial.print(ssid);
      Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
 
}

void loop() {
  // nothing happens after setup
}



Sa fonctionne mais des que le texte ecrit dans le fichier txt est plus court il reste le précédent ...
Il faut ecrire du "vide" jusque a arriver a 49 caractère ? ou y a une autre méthode ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 04:41 pm
Il faut peut être mieux ne pas faire de multiplication a répétition dans le loop et faire une division 1 fois lorsque l'on demande la page internet ...
Dit comme sa, sa change tout :)


Sur le même principe cela veut dire qu'il faut que je fasse pareil pour tout mes % passer en pwm avec * 2.55 ?
Mais ca va pas etre galère a modifier après car pour modifier de 1 il faudra ajouté un décimal 2.55
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 05:22 pm
vous êtes sûr qu'il compile votre code ?

c'est quoi ce délire? :)
Code: [Select]
lecture.indexOf(i, myFile.read());

encore la vitesse de tortue :)
Code: [Select]
  Serial.begin(9600);

ça ne sert à rien sur un Mega de faire cela:
Code: [Select]
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 05:25 pm
Quote
Il faut ecrire du "vide" jusque a arriver a 49 caractère ? ou y a une autre méthode ?
Pour faire une chaine de caractère avec un tableau de caractère (ce qu'on appelle une c-string, on en a déjà parlé) il doit se termine par un caractère nul '\0''

ensuite je ne sais pas où vous voyez des choses qui trainent? dans le ficher? sur un LCD? 
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:27 pm
vous êtes sûr qu'il compile votre code ?

c'est quoi ce délire? :)
Code: [Select]
lecture.indexOf(i, myFile.read());
Arf laisse tomber ... c'est ca davoir plusieurs fenetre ouverte avec des vieux nanare .... pffff


encore la vitesse de tortue :)
Code: [Select]
 Serial.begin(9600);
 
Rien ne sert de courire (mais je voudrait pas dire, tout les exmple de code fournie avec les biblioteque son comme ca)

ça ne sert à rien sur un Mega de faire cela:
Code: [Select]
 while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

Msieu Msieu, c'est pas moi ... c'est dans l'exemple ...


Bon le bon code :

Code: [Select]
#include <SPI.h>
#include "SdFat.h"
SdFat SD;

#define SD_CS_PIN SS
File myFile;

char * ssid;
const byte lectureMAX = 49;
char lecture [lectureMAX+1];
int i=0 ;

void setup() {
  Serial.begin(9600);

  Serial.print("Initializing SD card...");

  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("ssid.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to ssid.txt...");
    myFile.seek(0);
    myFile.println("bon ... tu va fonctionner !!!?");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening ssid.txt");
  }

  // re-open the file for reading:
  myFile = SD.open("ssid.txt");
  if (myFile) {
    Serial.println("ssid.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available() > 0) {
      if (i<=lectureMAX){
      lecture[i] = myFile.read();
      i++;
      }
      else {
      break;
      }
}
 
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  ssid = lecture;
      Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
      Serial.print(ssid);
      Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  
}

void loop() {
  // nothing happens after setup
}



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 05:29 pm
Quote
tout les exmple de code fournie avec les biblioteque son comme ca
oui parce qu'il datent d'un temps où l'arduino de base ne savait pas faire mieux sans se mélanger les pinceaux...


sinon une fois lu le contenu du fichier, si vous mettiez un '\0' à la fin du tableau ce serait mieux ... (attention de ne pas déborder)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:32 pm
Pour faire une chaine de caractère avec un tableau de caractère (ce qu'on appelle une c-string, on en a déjà parlé) il doit se termine par un caractère nul '\0''

ensuite je ne sais pas où vous voyez des choses qui trainent? dans le ficher? sur un LCD? 
Oui sur le fichier de la sd

au debut j'ai ecrit du text du genre "je raconte n'importe quoi"
et ensuite "je suis bo"
et je me suis retrouvé avec (en lecture) "je suis bo n'importe quoi"
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:32 pm
c'est un  exemple  :smiley-grin:  :smiley-grin:  :smiley-grin:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 05:37 pm
Quote
et je me suis retrouvé avec (en lecture) "je suis bo n'importe quoi"
la vérité sort de la bouche des arduinos :)

deux soucis

1/ vous vous positionnez dans le fichier au début (avec le myFile.seek(0);) et donc les caractères que vous écrivez viennent remplacer les caractères à cet endroit. Mais si le texte est plus court que l'ancien, votre fichier va conserver les anciens caractères. --> si vous voulez effacer le contenu alors le plus simple c'est de détruire le fichier s'il existe déjà et d'en créer un nouveau

2/ quand vous relisez le contenu du fichier vous ne mettez pas de caractère nul en fin de tableau. il faut le faire sinon le prochain print va imprimer jusqu'à ce qu'il trouve ce 0... si ça se trouve bcp plus loin en mêmoire que vous 50 octets même
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:39 pm
pour le caractere 0
c'est bon ?
 
Code: [Select]
    myFile.println("bon ... tu va fonctionner !!!?");
    myFile.println("\0")
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:43 pm
puis
Code: [Select]
else {
      lecture[i] = "\0";
      break;
      }
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:50 pm
Et j'ai ajouté avant d'ecrire
Code: [Select]
SD.remove ("ssid.txt");
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:50 pm
mais du coup j'ai un saut de ligne maintenant
Code: [Select]
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
bon ... tu va fonctionner !!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


avant
Code: [Select]
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
bon ... tu va fonctionner !!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 05:53 pm
la vérité sort de la bouche des arduinos :)
c'est pas gentil gentil
chui beau goss !

(http://scrat.hellocoton.fr/img/classic/la-tele-des-inconnus-emission-inedite-ce-soir-sur-d8-17164240.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 06:14 pm
Non ce n'est pas bon...

myFile.println("\0")

des guillemets c'est pour une chaîne de caractère, de apostrophes c'est pour un caractère. c'est pas pour rien que j'ai écrit '\0', pas "\0". (même si ici ça ne change rien mais une bonne habitude à prendre, ne pas confondre 1 caractère et une chaine d'un seul caractère)

votre bug c'est le ln
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 06:16 pm
effectivement ca marche :/
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 06:18 pm
 a ouai ...
J'ai déjà du mal avec des truc qui saute au yeux mais si maintenant faut voir la différence ente " et ' ...
je vais devoir ouvrir grand les  :o
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 06:18 pm
effectivement ca marche :/
surprise :)


pour les " ou ' c'est important de bien faire la différence. un c'est un char *, l'autre un char
Code: [Select]
const char toto = 'x'; // c'est bon
const char toto = "x"; // c'est pas bon, une chaîne se terminant par un \0 il faudrait 2 caractères
const char * toto = "x"; // c'est bon


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 06:20 pm
ba du coup cette partie est Ok, y  plus qu'a attendre de l'intégrer avec le gsm
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 08:14 pm
Je me suis basé au code du gsm pour copier le ssid une fois extrait du fichier txt.
J'ai donc fait
Code: [Select]
strncpy(ssid, lecture,lectureMAX);
et bien sur sa marche pas, rien ne se passe...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 08:21 pm
a oui, c'est pas l'histoire que ssid fix un pointeur dans lecture et que lecture varie du cout sa pointe plus sur ce que l'on veut ?
 
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 08:32 pm
c'etait ca ... c'est bon
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:27 pm
Bon en plus de tout ca, j'ai fait pas mal de petite modif dans le code principal dont de nouvelle fonction :

l'osmolation, qui n'était pas prévu au programme, mais vu la demande ...
Code: [Select]
void OSMOLATION() {
  boolean compteur_osmolation = true;
  unsigned long temps_precedent_osmolation;
  unsigned long temps_attente_osmolation;
  if (pinIN_floteur_osmolation == LOW) { // si floteur en position basse
    if (compteur_osmolation == true) {  
    temps_precedent_osmolation = millis(); // activation de la duree d'osmolation
      compteur_osmolation = !compteur_osmolation;
    }
    if (osmolation_ON <= compteur_MAX_osmolation) { //si compteur MAX pas atteind
    if (millis() - temps_precedent_osmolation >= duree_osmolation_millis) { // osmolation si duree d'osmolation non depassé
        digitalWrite(pinOUT_relais_osmolation, HIGH); // relais osmolateur ON
        temps_attente_osmolation = millis(); // activation de la duree d'attente apres osmolation
      }
      else if (millis() - temps_attente_osmolation >= duree_osmolation_millis) { // attente si duree attente non depassé
        digitalWrite(pinOUT_relais_osmolation, LOW); // relais osmolateur OFF
      }
      else { // quand duree osmolation + duree atteinte
        compteur_MAX_osmolation++; // +1 au compteur d'osmolation
        compteur_osmolation = !compteur_osmolation;
      }
    }
    else { // quand compteur MAX atteind
      digitalWrite(pinOUT_relais_osmolation, LOW);
      // alerte
    }
  }
  else { // quand floteur en position haute
    osmolation_ON = 0;
  }
}


Et un mode tempête aléatoire :

Code: [Select]
void TEMPETTE_ALEATOIR(){
  if (tempette_du_jour == true){
  H_tempette_aleatoir = random(fin_LEVER_blanc2, debut_COUCHER_blanc1);
  duree_tempette_aleatoir = random((millis()+30000), (millis()+duree_tempette_millis));
  tempette_du_jour = !tempette_du_jour;
}
  if (H_tempette_aleatoir == Time){
  temps_precedent_tempette_aleatoir = millis();
}
}
************
if (millis() - temps_precedent_tempette_aleatoir <= duree_tempette_aleatoir) {
    pwm_jebao1,pwm_jebao2,pwm_jebao3 = puissance_tempette;
    analogWrite(pinOUT_jebao1, pwm_jebao1);
    analogWrite(pinOUT_jebao2, pwm_jebao2);
    analogWrite(pinOUT_jebao3, pwm_jebao3);
  }
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:47 pm
Sans doute un bug ici et une petite simplification
if (digitalRead(pinIN_floteur_osmolation) == LOW) { // si floteur en position basse
    if (compteur_osmolation == true) { 
      temps_precedent_osmolation = millis(); // activation de la duree d'osmolation
       compteur_osmolation = false;
    }


(Et un booléen c'est rarement un compteur :) autant appeler compteur_osmolation avec un autre nom )


Ps: on écrit tempête et aléatoire :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 10:54 pm
a oui, c'est pas l'histoire que ssid fix un pointeur dans lecture et que lecture varie du cout sa pointe plus sur ce que l'on veut ?
Non c'est qu'il n'y a pas de cases mémoires associées à SSID ! Vous ne pouvez pas faire un strcpy() dedans... (attention quand on fait un strncpy() il faut mettre à la main un zéro dans la dernière case au cas où)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 10:56 pm
Les bouton et flotteur son relier au pin analogique.

Avant j'aurais écrit "autant écrire compteur_osmolation = false;" mais ça, c'était avant ...
Y a t'il une raison a passer par l'un plutot que l'autre ? peut être pars-qu'avant j'ai utilisé "compteur_osmolation == true"

Je ne vois pas comment l'appeler ce boolean ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:00 pm
Non c'est qu'il n'y a pas de cases mémoires associées à SSID ! Vous ne pouvez pas faire un strcpy() dedans... (attention quand on fait un strncpy() il faut mettre à la main un zéro dans la dernière case au cas où)
Non c'est qu'il n'y a pas de cases mémoires associées à SSID !  ??? je ne comprend pas, je n'est rien vu de différent par rapport au code gsm.
A part que char * ssid est vide avant d'être dans strcpy. c'est ça ?

Pour le '\0' je l'avais bien mis. :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:19 pm
Pour le strncpy(ssid, lecture,lectureMAX);

char * ssid; ça veut dire réserver de la place pour un pointeur (2 octets, une adresse) vers quelque part sur la mémoire, qui s'appelle ssid. mais ça ne réserve aucun espace mémoire.

char lecture[50]; ça veut dire réserver 50 cases mémoires pour y mettre des caractères, l'adresse de la première case étant connue sous le nom de lecture

Quand vous faites le strncpy(ssid, lecture,lectureMAX); vous prenez au plus lectureMAX caractères qui sont rangés consécutivement à partir de l'adresse mémoire  lecture (en s'arretant au premier 0 rencontré) et vous les dupliquez (copiez) les uns derrières les autres à partir de l'adresse pointée par ssid. Comme vous n'avez pas réservé de cases pour cette copie vous allez faire n'importe quoi (et si ssid pointe au milieu de lecture alors la fonction strcpy() est interdite)

OK?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:23 pm
Les bouton et flotteur son relier au pin analogique.

Avant j'aurais écrit "autant écrire compteur_osmolation = false;" mais ça, c'était avant ...
Y a t'il une raison a passer par l'un plutot que l'autre ? peut être pars-qu'avant j'ai utilisé "compteur_osmolation == true"
Pas compris la question ou l'explication.


Pour le nom du booléen, un truc du genre declencherOsmolation par exemple

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:35 pm
OK?
Ok mais quel est l'intérêt dans mon cas d'avoir ce pointeur autent directement avoir char ssid [50] ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:38 pm
C'est votre idée :)

Dans le code gsm on avait d'ailleurs fait un tableau pour l'extraire et le copier...

Un pointeur c'est juste si vous n'avez pas besoin de le conserver
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:38 pm
et donc j'aurais :

Code: [Select]

strncpy(_SSID, GSM_MessageLine + 5,max_SSID);
_SSID[max_SSID] = '\0';


au lieu de
Code: [Select]
SSID = GSM_MessageLine + 5; // on extrait le Ssid du message
strncpy(copie_SSID, _SSID,max_SSID);
copie_SSID[max_SSID] = '\0';
_SSID = copie_SSID;
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:40 pm
C'est votre idée :)
Oula ...
Faut pas hésiter a sortir le smiley fouet quand c'est comme ca ...
Jcrois que c'est bon après et jcontinu tete baissé ...
et puis 3 semaine apres je comprend plus  :smiley-roll-sweat:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:43 pm
Pfff effectivement c'est tellement plus simple !!!

Bref, c'est corrigé ...

Code: [Select]
    strncpy(mdp, lecture, maxMdp);
    mdp[maxMdp] = '\0'


ta vu le ptit '\0'

 :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 24, 2017, 11:53 pm
Bon Zou ...
O dodo
Un grand merci Jean Marc pour ton aide encore aujourd'hui ...  :smiley-wink:
ça avance bien  :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 24, 2017, 11:56 pm
Pfff effectivement c'est tellement plus simple !!!

Bref, c'est corrigé ...

Code: [Select]
    strncpy(mdp, lecture, maxMdp);
    mdp[maxMdp] = '\0'


ta vu le ptit '\0'

 :)
J'ai vu :)

Attention il faut que mdp ait été déclaré avec maxMdp+1 cases réservées

Bonne nuit!
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 25, 2017, 12:01 am
Attention il faut que mdp ait été déclaré avec maxMdp+1 cases réservées
Code: [Select]
// **************************************** wifi
const byte maxSsid = 40;// prévoir la bonne longueur
char ssid[maxSsid + 1];
const byte maxMdp = 40;// prévoir la bonne longueur
char mdp[maxMdp + 1];


 :smiley-cool:  :smiley-cool:  :smiley-cool:  :smiley-grin:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 25, 2017, 12:06 am
Cool
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 25, 2017, 09:37 am
Pour revenir sur le problème de lecture de sms.
Quelle solution faut-il envisager ?
Car même si le code est organiser la quantité d'information a traiter dans la boucle est la même ? (et va continuer a s'agrandir)
Ya t'il un code pour prioriser certaine fonction ?
Ou peut être faudra t'il que la fonction GSM soit répété a différent moment dans la boucle ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 25, 2017, 09:57 am
la première chose à faire c'est de faire un timing des fonctions, quand elles tournent. Si vous voyez des fonctions trop longues il faut les découper en petits bouts pour que seulement une étape soit fait à chaque tour de boucle et pour les très longues (genre le web) il faut soit envisager de l'accélérer (cf mon tuto,sur SPIFFS) et les déporter sur un second arduino éventuellement (j'ai toujours le code dont je vous avais parlé mais pas eu le temps de le nettoyer)

Comme vous utilisez millis() pour décider quand elles doivent s'executer - assurez vous que les tempos soient telles que elles ne se déclenchent pas toute dans la même loop()

La plupart du temps ça devrait aller sans trop d'effort, mais si vous avez une fonction critique alors envisager de l'appeler entre 2 autres fonctions c'est possible aussi - du genre
Code: [Select]
fonction1();
testSMS();
fonction2();
testSMS();
fonction3();
testSMS();
fonction4();
testSMS();
si vraiment c'est nécessaire
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 25, 2017, 11:24 am
Pour le timing,
il s'agit de faire en sorte que la boucle génère t'elle fonction, puis au tour suivant une autre et ainsi de suite (et les fonction importante en continu)
Ou alors de dire pendant 500millis t'elle fonction puis la suivante ( et toujours les fonction importante en continu ?

Pour le tuto spiffs j'ai commencer mais pas encore mis a fond dessus (je me met a jour sur le "simple" de façon a n'avoir qu'a l'ajouter ensuite)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 25, 2017, 11:28 am
Quote
Ou alors de dire pendant 500millis t'elle fonction puis la suivante ( et toujours les fonction importante en continu ?
non 500ms c'est bcp trop pour une seule fonction

idéalement (si vous voulez que des boutons répondent par exemple) pas plus de quelques ms (moins de 5/10). En 10ms votre méga fait 160,000 instructions de base... c'est quand même pas mal de calculs
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 25, 2017, 11:43 am
non 500ms c'est bcp trop pour une seule fonction

idéalement (si vous voulez que des boutons répondent par exemple) pas plus de quelques ms (moins de 5/10). En 10ms votre méga fait 160,000 instructions de base... c'est quand même pas mal de calculs
Petit test réalisé ... En 10 seconde, avec le code actuel (qui est loin d'être complet) :

arduino mega chinois (72 boucles soit 7.2 a la seconde soit 138.8 millis la boucle)
Arduino mega wemos d1 (102 boucles soit 10.2 a la seconde soit 98 millis la boucle)

Apres, je pourrait analysé le temps de boucle de chaque fonction ...

Mais y a t'il plus d'interet a se quelle boucle pendant un certain temps (et donc faire surement plusieurs loop) plutôt que de leur donner un ordre (1 loop puis suivante ) ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 25, 2017, 11:49 am
et par exemple faire un truc du genre :

Code: [Select]
loop :

// fonction continu
wifi
gsm
affichage
bouton

// fonction tour a tour
fonction=1
eclairage

fonction=2
brassage

fonction=3
oscillo

fonction++
if fonction=4
fonction=1



C'est juste pour montrer l'exemple, me dit pas qu'il manque des parenthèse et des point virgules :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 26, 2017, 11:15 am
Les petit test continu ...
Avec la mesure fonction par fonction du temps de boucle :
Code: [Select]
TIME(); // max 5 millis
OSMOLATION();// max 4 millis
ECLAIRAGE();//max 6 millis
NOURISSAGE();// max 5 millis
VENTILATION();// max 5 millis
BRASSAGE();// max 6 millis
BOUTON();// max 5 millis
TEMPERATURE();//100 millis
ALARME(); // max 5 millis
PH(); // 5 millis


Si je tiens pas le problème la ...

La fonction en question :
Code: [Select]
void TEMPERATURE() {
  // **************************************** recuperation temperature ds18b20
  sensors.requestTemperatures();
  temp_bac = sensors.getTempCByIndex(wire_bac);
  temp_rampe = sensors.getTempCByIndex(wire_rampe);
}


Vu le peut d'écriture qu'elle contient ... je ne vois pas ou j'ai pu me gourer  :smiley-confuse:


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 26, 2017, 12:42 pm
Apres quelque recherche sur le net ce temps est plutôt bon :/
il est annoncé selon la résolution entre 100ms et 750ms !

a contrario, je suis surpris que toutes les autre fonctions ne prenne que 5/6ms max.

Donc pour le moment, la fonction qui seras sortie de chaque loop est la température.

Je vais remettre la fonction SMS dans le code principale en désactivant la température pour voir si le problème est réglé.


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 26, 2017, 01:53 pm
La température il faut la lire en asynchrone. Cf mon petit projet de gestion de T° et humidité dans les projets finis

Vous lancez une mesure puis vous revenez plus tard lire le résultat
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 26, 2017, 03:54 pm
visiblement cela consiste a ajouter
Code: [Select]
 sensors.setWaitForConversion(false); // on travaillera en asynchrone, on n'attend pas les lectures
  sensors.requestTemperatures(); // on lance une demande de lecture qui sera prête plus tard


Si c'est bien le cas, j'en arrive a un maximum de 29millis par loop sur la fonction.


Code: [Select]
boucle éffectuée : 68 fois soit : 29 millis par boucle
23.00
23.50
boucle éffectuée : 69 fois soit : 29 millis par boucle
23.00
23.50
boucle éffectuée : 70 fois soit : 28 millis par boucle
23.00
23.50
boucle éffectuée : 71 fois soit : 29 millis par boucle
23.00
23.50
boucle éffectuée : 72 fois soit : 29 millis par boucle
23.00
23.50
boucle éffectuée : 73 fois soit : 27 millis par boucle
23.00
23.50
boucle éffectuée : 74 fois soit : 29 millis par boucle
23.00
23.50
boucle éffectuée : 75 fois soit : 29 millis par boucle
23.00
23.50
boucle éffectuée : 76 fois soit : 28 millis par boucle
23.00
23.50
boucle éffectuée : 77 fois soit : 29 millis par boucle


et donc, toujours si j'ai bien compris, le serial.print de la température afficher juste après la demande correspond surement au température relever il y a quelle loop (puisque pas encore mis a jour)?

ps : il ne fait pas chaud chez moi, cela a du a la résistance 4k7 ... il m'on envoyer des 4k6  >:(
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 26, 2017, 06:14 pm
Pour pouvoir envoyer mes températures lors des alertes SMS j'i fait ca :
Code: [Select]
strcpy(GSM_Message, "!!! ALERT TEMPERATURE !!!");
  dtostrf (temp_bac,5,1, buffer);
  strcat(GSM_Message, buffer);
  envoyerSMS(numero2tel, GSM_Message);
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 26, 2017, 06:23 pm
avec
Code: [Select]
buffer[maxMessageSize] = '\0'; ça éviteras de se faire tirer les oreille  :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 26, 2017, 11:47 pm
if (compteur_osmolation == true) {
Le fait de ne mettre aucune info veut forcement dire qu'on parle de lui en "VRAI" ?

Ps: on écrit tempête et aléatoire :)
C'est fait :smiley-confuse:


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 27, 2017, 05:03 am
Le fait de ne mettre aucune info veut forcement dire qu'on parle de lui en "VRAI" ?
Oui quand on écrit  if (expression) {...} le compilateur calcule la valeur logique (vrai ou faux) de l'expression et si c'est vrai exécute ce qui suit

L' expression ne peut pas être void, et la règle en C ou C++ c'est que si l'espression N'est pas de type logique alors une valeur nulle veut dire faux et toute valeur non nulle veut dire vrai
(par exemple
Code: [Select]
File monFichier = SD.open("Toto.txt");
if (monFichier) {...}
ne veut pas dire si monFichier est vrai, car son type est File pas boolean ça veut dire si monFichier nest pas le pointeur NULL, if (monFichier != NULL) {...}  )

Dans notre cas votre compteur_osmolation est un booléen donc déjà directement une valeur logique - pas la peine de lui dire si (vrai == vrai) alors {...} on peut juste dire si (vrai) {...}

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Nov 27, 2017, 05:13 am
avec
Code: [Select]
buffer[maxMessageSize] = '\0'; ça éviteras de se faire tirer les oreille  :smiley-confuse:
Mais avec dtostrf() il n'y a pas besoin, il met toujours le '\0' pour vous dans tous les cas - donc ça ne sert absolument à rien, autant l'enlever :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 27, 2017, 09:26 am
Mais avec dtostrf() il n'y a pas besoin, il met toujours le '\0' pour vous dans tous les cas - donc ça ne sert absolument à rien, autant l'enlever :)
Pfff,

J'ai chercher sur le net avant parce que j'ai vu que certaine fonction l'ajoutait automatiquement et d'autre non, pour celle ci, j'ai pas trouvé donc par Default je me suis dit ... plutôt que de me faire taper sur les doigts ... et comme par hasard  ...  :smiley-confuse:

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 27, 2017, 11:29 am
y a t'il une solution pour envoyer par SMS le signe dégrée ?
J'ai testé pas mal de truc (°, 0xB0, 248) sans succès, certain dise que ce n'est pas possible donc il mette un C après la température
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 27, 2017, 11:40 am
Qu'est ce que tu pense de l'utilisation d'un arduino DUE ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 29, 2017, 10:07 am
Je me suis encore mis dans une belle galère ...   :smiley-confuse:
J'ai reçu mon écran ER-TFTM070-5
Selon se que j'avais lu et compris, il suffisant de brancher l'écran avec 5 fils :
RST, SCLK, SDI, SDO, SCS
et le vdd et gnd
Visiblement non ...
Et ce que j'ai du mal a comprendre c'est que quand je branche juste le vcc et gnd l'écran ne s'allume pas.
Normal ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Nov 29, 2017, 11:28 am
https://www.buydisplay.com/download/manual/ER-TFTM070-5_Datasheet.pdf

Boun's si cela peut aider.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 29, 2017, 12:08 pm
Merci Breisleach mais je l'ai déjà lus et relus
J'ai ouvert un post sur le sujet
https://forum.arduino.cc/index.php?topic=514417.new#new


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: patoune08 on Nov 30, 2017, 12:40 pm
Bonjour,

J'ai lu les 25 pages avec intérêt et je précise que je suis plus que débutant mais j'apprends (ou j'essaie).

Serait il possible d'avoir le programme en entier pour que je puisses essayer de l'adapter à un aquarium d'eau douce (2000L).

En tout cas très beau travail.

Merci d'avance


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Nov 30, 2017, 11:03 pm
Bonsoir Patoune,

Il ne me parait pas judicieux de partager un code en cour de développement, qui n'as même pas été testé.
Par contre, tu peut partager tes besoins afin de voir si il peuvent être inclue dans le projet.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: patoune08 on Dec 01, 2017, 01:09 am
Bonsoir,

Pour l'eau douce le besoin est beaucoup plus simple : éclairage progressif, 2 pompes de brassage, nourrissage, 1 sonde de température (+ chauffage), 1 capteur de niveau - 1 pompe et une électrovanne pour le changement d'eau.

C'est très simple quand on connait mais quand on est novice c'est une autre histoire.

Pour l'instant je recherche à faire fonctionner sur un écran tactile de 3,2", pour ce qui est de l'interface web et les sms je verrais après, je préfère y aller étape par étape.
 
J'ai essayé Sebduino et Akduino mais il y a des erreurs lors de la compilation et comme je ne m'y connait pas assez je n'arrive pas à les faire fonctionner.

Si le début de ton programme est déjà fait je peux essayer de l'adapter et le tester. Ce qui ferait 2 versions (eau de mer et eau douce).

Pour info je n'ai jamais trouvé d'automate diy pour l'eau douce.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 01, 2017, 09:12 am
comme je te l'ai dit même si le début est écrit il n'as jamais été testé, il comporte a coup sur des erreur d'écriture et donc des bug.
Patience ...

ps1 :l'ackduino est a téléverser a partir de codeblocks et non pas de l'ide arduino. compile et téléversement fonctionne correctement dans codeblocks  :smiley-wink:

ps2 : l'ackduino est le dernier nom du projet "sebduino" et l'ackduino 1.25 "idefixes" est la derniere version de l'ackduino améliorés par idefixes, elle prend en charge les pompes jebao pour le brassage.

ps3: regarde mon post complet sur le montage de l'ackduino  (http://www.recifal-france.fr/montage-d-un-ackduino-de-a-a-z-t23888.html?hilit=montage%20ackduino)et aussi le post pour toute les question sur l'ackduino (http://www.recifal-france.fr/question-sur-le-montage-d-un-ackduino-de-a-a-z-t23890.html?hilit=montage%20ackduino) et n'hesite pas a poster tes question la bas en cas de soucis
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: patoune08 on Dec 01, 2017, 11:22 pm
Merci,

ça y est j'ai réussi à faire fonctionner les sondes de températures et les relais, je vais passer à l'éclairage

Je ne comprends pas le fonctionnement des alarmes, je verrais plus tard.

Je vais essayer de l'adapter à mon usage (eau douce).
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 02, 2017, 06:40 pm
Petit question bête :smiley-confuse:
quand l'arduino n'est pas connecté a l'ordi, fait il tout de même les opération Serial.print ou il les zap ?
Je pe pose la question car pour debugger c'est pratique mais si une fois le code en route l'arduino travaille pour rien c'est bête ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 03, 2017, 07:58 pm
J'ai commencer a regarder comment faire un graphique pour avoir la température sur 24h.
J'ai fini par faire fonctionné une page :
Code: [Select]
<!DOCTYPE html>

<html>
<head>
<style>#graphe{border:1px solid;background-color:#FFFFFF}</style>
<script>
// fonction pour dessiner
function draw(f,f1) {
  // Largeur et hauteur en pixels
  var W=1000, H=W/2.4
  var sc=W/24;
  var canvas = document.getElementById("graphe");
  canvas.width=W; canvas.height=H;
  var ctx = canvas.getContext("2d");

// nb de pixels pour une unité
ctx.strokeStyle = "green";
ctx.moveTo(0,H/2);
ctx.lineTo(W,H/2);
ctx.stroke();
  // tracé du quadrillage
  ctx.strokeStyle = "#666";
  ctx.beginPath();
  ctx.lineWidth=0.5;
  for(var i=0; i<=H/sc; i++) { // lignes horizontales
    ctx.moveTo(0, H-sc*i)
    ctx.lineTo(W, H-sc*i)
  } 
  for(var i=0; i<=W/sc; i++) { // lignes verticales
    ctx.moveTo(sc*i,H-0)
    ctx.lineTo(sc*i, H-H)
  }
  ctx.stroke();
 
  // tracé de la fonction
  var x;
  with(Math) {
    ctx.strokeStyle = "#ff0000";
    ctx.lineWidth=1.5;
    ctx.beginPath();   
    for(x=-W/(2*sc); x<=W/(2*sc); x+=1/sc) {
      ctx.moveTo(0, H/2)
      ctx.lineTo(sc, 50)
      ctx.lineTo(sc*2, 30)
      ctx.lineTo(sc*3, 100)
      ctx.lineTo(sc*4, 100)
      ctx.lineTo(sc*5, 50)
      ctx.lineTo(sc*6, 30)
      ctx.lineTo(sc*7, 100)
      ctx.lineTo(sc*8, 100)
      ctx.lineTo(sc*9, 30)
      ctx.lineTo(sc*10, 100)
      ctx.lineTo(sc*11, 100)
      ctx.lineTo(sc*12, 50)
      ctx.lineTo(sc*13, 30)
      ctx.lineTo(sc*14, 100)
      ctx.lineTo(sc*15, 100)
      ctx.lineTo(sc*16, 50)
      ctx.lineTo(sc*17, 30)
      ctx.lineTo(sc*18, 100)
      ctx.lineTo(sc*19, 100)
      ctx.lineTo(sc*20, 30)
      ctx.lineTo(sc*21, 100)
      ctx.lineTo(sc*22, 100)
      ctx.lineTo(sc*23, 50)
      ctx.lineTo(sc*24, 30)     
    }   
  }   
  ctx.stroke(); 
}
function tracer()
{
draw(0,0);
}
</script>
</head>
<body onload="tracer();afficher()">
<p><canvas id="graphe"></canvas></p>
</body>
</html>


Je l'ai donc mis dans un code arduino :
Code: [Select]
client.print(F("<style>#graphe{border:1px solid;background-color:#FFFFFF}</style><script>\r\n"));
// fonction pour dessiner
client.print(F("function draw(f, f1){ var W = 1000, H = W / 2.4;var sc = W / 24; var canvas = document.getElementById(graphe);canvas.width = W; canvas.height = H; var ctx = canvas.getContext(2d)\r\n"));
// nb de pixels pour une unité
client.print(F("ctx.strokeStyle = green; ctx.moveTo(0, H / 2);ctx.lineTo(W, H / 2);ctx.stroke()\r\n"));
// tracé du quadrillage
client.print(F("ctx.strokeStyle = #666;ctx.beginPath();ctx.lineWidth = 0.5;for (var i = 0; i <= H / sc; i++){ctx.moveTo(0, H - sc * i) ctx.lineTo(W, H - sc * i)}\r\n"));
client.print(F(" for (var i = 0; i <= W / sc; i++) {ctx.moveTo(sc * i, H - 0)ctx.lineTo(sc * i, H - H)}ctx.stroke(); \r\n"));
// tracé de la fonction
client.print(F(" var x;with(Math) {ctx.strokeStyle = #ff0000;ctx.lineWidth = 1.5;ctx.beginPath(); \r\n"));
client.print(F("for (x = -W / (2 * sc); x <= W / (2 * sc); x += 1 / sc) {ctx.moveTo(0, H / 2) \r\n"));
client.print(F("ctx.lineTo(sc, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 2, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 3, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 4, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 5, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 6, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 7, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 8, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 9, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 10, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 11, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 12, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 13, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 14, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 15, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 16, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 17, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 18, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 19, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 20, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 21, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 22, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 23, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 24, 30)}}\r\n"));
client.print(F("ctx.stroke()}function tracer(){draw(0, 0)}< / script >< / head > \r\n"));
client.print(F(" < body onload = tracer(); afficher() ><p><canvas id = graphe> < / canvas > < / p >< / body > \r\n"));


Et la page reste blanche.

 
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 03, 2017, 09:30 pm
Petit question bête :smiley-confuse:
quand l'arduino n'est pas connecté a l'ordi, fait il tout de même les opération Serial.print ou il les zap ?
Je pe pose la question car pour debugger c'est pratique mais si une fois le code en route l'arduino travaille pour rien c'est bête ...
il les exécute effectivement.

On peut créer des macros pour les traces debug qui gèrent les impressions sous différentes formes et on recompile en mode non débug pour la version finale

par exemple un truc du genre
Code: [Select]

#define DEBUG // à commenter pour enlever les traces


#ifdef DEBUG
#define DPRINTF(s)   {Serial.print(F(s));}
#define DPRINTFV(s,v)  {Serial.print(F(s)); Serial.print(v);}
#define DPRINTFX(s,v) {Serial.print(F(s)); Serial.print(F("0x")); Serial.print(v, HEX);}
#define DPRINT(x)  {Serial.print(x);}
#define DPRINTLN(x)  {Serial.println(x);}
#else
#define DPRINTF(s)
#define DPRINTFV(s,v)
#define DPRINTFX(s,v)
#define DPRINT(x)
#define DPRINTLN(x)
#endif


et dans le code vous n'utilisez plus Serial.print(F("problème memoire")); mais vous faites un DPRINTS("problème memoire"); par exemple. Quand vous recompilez en élevant la ligne déclarant DEBUG pour la version finale alors tous les DPRINT ne génère plus de code et le compilateur ne génère rien - donc ça libère de la mémoire



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 03, 2017, 09:34 pm
J'ai commencer a regarder comment faire un graphique pour avoir la température sur 24h.
J'ai fini par faire fonctionné une page :
...
Je l'ai donc mis dans un code arduino :
.....

Et la page reste blanche.

--> vous avez traduit ça

<body onload="tracer();afficher()">
<p><canvas id="graphe"></canvas></p>


comme cela:

client.print(F(" < body onload = tracer(); afficher() ><p><canvas id = graphe> < / canvas > < / p >< / body > \r\n"));

manquerait pas des trucs?  (attention aux espaces aussi genre < / canvas > ou < / p >)

vous n'avez pas étudié mon début de tuto sur SPIFFS et AJAX? l'interface serait drôlement plus rapide et pas de réaffichage
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 03, 2017, 10:06 pm
vous n'avez pas étudié mon début de tuto sur SPIFFS et AJAX? l'interface serait drôlement plus rapide et pas de réaffichage
Non pas mi dessus car pas trop de temps ces dernier jour (1h par ci par la) et sa a l'air d'être une gros morceaux, j'attend d'être bien poser pour revenir sur la partie ESP.
(du coup je bidouille un peu, je met mon code au propre, j'essaie de comprendre cette écran de malheur ...)
Mais effectivement, si cette partie grignote sur l'écriture de la page, attend mettre ça de coté.

J'ai retiré les " car il y a erreur de compilation sinon et lorsque on fait \" c'est page blanche egalement.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 03, 2017, 10:27 pm
les guillemets ne sont pas là pour décorer et les tags doivent être bien écrits </canvas> pas avec des espaces


Si vous prenez votre code HTML certes il affiche quelque chose en le chargeant en tant que fichier, mais si vous allez dans la console web  (Chrome ou Safari on cette fonction) je vois une erreur ReferenceError: Can't find variable: afficher
onload -- toto.html:77


donc votre fichier d'origine n'est pas correct - même si quelque chose s'affiche

Depuis votre arduino - connectez vous, puis dans le menu du navigateur passez en mode développement, regardez le code HTML reçu et comparez le à celui que vous avez écrit à la main. Sont-ils identiques à 100% ? --> si ce n'est pas le cas, modifiez la partie Arduino pour en tenir compte
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 03, 2017, 11:56 pm
passez en mode développement
8)
Ça m'as pris 2h mais c'est pratique,
Maintenant ca fonctionne et plus d'erreur en prime :)

Code: [Select]
client.print(F("<style>#graphe{border:1px solid;background-color:#FFFFFF}</style><script>\r\n"));
// fonction pour dessiner
client.print(F("function draw(f, f1){var W = 1000, H = W/2.4;var sc = W/24; var canvas = document.getElementById(\"graphe\");\r\n"));
client.print(F("canvas.width = W; canvas.height = H; var ctx = canvas.getContext(\"2d\");\r\n"));
// nb de pixels pour une unité
client.print(F("ctx.strokeStyle = \"green\"; ctx.moveTo(0, H/2);ctx.lineTo(W, H/2); ctx.stroke();\r\n"));
// tracé du quadrillage
client.print(F("ctx.strokeStyle = \"#666\";ctx.beginPath();ctx.lineWidth = 0.5;for (var i = 0; i <= (H/sc); i++){ctx.moveTo(0, H - sc * i);ctx.lineTo(W, H - sc * i)}\r\n"));
client.print(F(" for (var i = 0; i <= (W/sc); i++) {ctx.moveTo(sc * i, H - 0);ctx.lineTo(sc * i, H - H)}ctx.stroke(); \r\n"));
// tracé de la fonction
client.print(F(" var x; with(Math){ctx.strokeStyle = \"#ff0000\" ;ctx.lineWidth = 1.5;ctx.beginPath(); \r\n"));
client.print(F("for (x = -W / (2 * sc); x <= W / (2 * sc); x += 1 / sc) {ctx.moveTo(0, H / 2) \r\n"));
client.print(F("ctx.lineTo(sc, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 2, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 3, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 4, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 5, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 6, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 7, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 8, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 9, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 10, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 11, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 12, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 13, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 14, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 15, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 16, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 17, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 18, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 19, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 20, 30)\r\n"));
client.print(F("ctx.lineTo(sc * 21, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 22, 100)\r\n"));
client.print(F("ctx.lineTo(sc * 23, 50)\r\n"));
client.print(F("ctx.lineTo(sc * 24, 30)}}\r\n"));
client.print(F("ctx.stroke();}function tracer(){draw(0, 0);}</script></head>\r\n"));
client.print(F("<body onload =\"tracer()\"><p><canvas id =\"graphe\"></canvas></p></body>\r\n"));
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 04, 2017, 04:42 am
 Cool
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 04, 2017, 08:46 am
oui sauf que (a quand ce jour ou il n'y aurais plus de, sauf, mais ...)
Sur internet exploreur, cela n'est pas pris en charge (d'après se que j'ai pu lire) et que su chrome il y a toujours se problème de lenteur déjà rencontré avec la page "normal".
Je met ca de coté jusqu'à pouvoir me pencher sur la partie wifi.
Peut être vendredi si j'ai ma journée
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 04, 2017, 09:35 am
La lenteur ne sera traitée que par le passage en SPIFFS et AJAX...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 05, 2017, 12:05 am
J'ai trouvé un graphique plus adapté, plus jolie, regroupant tout les relevé de paramètre en même temps et fonctionnant sous IE :)

Code: [Select]
<!DOCTYPE HTML>
<html lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>[...]</title>
<style type="text/css">
</style>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
 google.load("visualization", "1", {packages:["corechart"]});
 google.setOnLoadCallback(drawChart);
 function drawChart() {
 var data = new google.visualization.DataTable();
 data.addColumn('string', 'Q(m3/h)');
 data.addColumn('number', 'T du BAC');
 data.addColumn('number', 'T de la rampe');
 data.addColumn('number', 'PH BAC');
 data.addColumn('number', 'PH RAC');
 data.addRow([ "0",  9.0, 11.5, 13.5, 14.5]);
 data.addRow([ "1",  8.5, 11.0, 13.0, 14.5]);
 data.addRow([ "2",  7.8,  9.5, 12.5, 14.0]);
 data.addRow([ "3",  6.5,  9.0, 11.5, 13.5]);
 data.addRow([ "4",  5.2,  8.0, 11.0, 12.5]);
 data.addRow([ "5", null,  6.0,  9.0, 11.0]);
 data.addRow([ "6", null,  4.0,  7.5,  9.0]);
 data.addRow([ "7", null, null, 5.75,  7.5]);
 data.addRow([ "8", null, null, null,  6.0]);
 data.addRow([ "9", null, null, null, null]);
    data.addRow([ "10",  9.0, 11.5, 13.5, 14.5]);
 data.addRow([ "11",  8.5, 11.0, 13.0, 14.5]);
 data.addRow([ "12",  7.8,  9.5, 12.5, 14.0]);
 data.addRow([ "13",  6.5,  9.0, 11.5, 13.5]);
 data.addRow([ "14",  5.2,  8.0, 11.0, 12.5]);
 data.addRow(["15", 5,  6.0,  9.0, 11.0]);
 data.addRow(["16", 6,  4.0,  7.5,  9.0]);
 data.addRow(["17", 8, null, 5.75,  7.5]);
 data.addRow(["18", 12, null, null,  6.0]);
 data.addRow(["19", 15, null, null, null]);
    data.addRow(["20", 7,  6.0,  9.0, 11.0]);
 data.addRow(["21", 9,  4.0,  7.5,  9.0]);
 data.addRow(["22", 22, null, 5.75,  7.5]);
 data.addRow(["23", 15, null, null,  6.0]);
 data.addRow(["24", 19, null, null, null]);
 
 var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
 chart.draw(data, { width: 1920, height: 1080, title: 'Relever les paramètres',
    hAxis: {title: 'Heure',   minValue: 0, maxValue: 24, textStyle:{ fontSize : 12}},
    vAxis: {title: 'Temperature', minValue: 0, maxValue: 45, textStyle:{ fontSize : 12}, gridlines:{ color: '#aaa', count: 50}},
 });
}
</script>
</head>
<body>
<div id="chart_div">&nbsp;</div>
</body>
</html>



la page s'affiche.
Dans chrome j'ai une "erreur orange" mais je ne comprend pas ce que je doit faire :
Code: [Select]
jsapi: 22 Un script inter-bloqueur, intersite (c'est-à-dire différent eTLD + 1), https://www.google.com/uds/?file=visualization&v=1&packages=corechart, est appelé via document.write. La demande de réseau pour ce script PEUT être bloquée par le navigateur dans ce chargement de page ou dans un futur chargement de page en raison d'une mauvaise connectivité réseau. S'il est bloqué dans cette page, il sera confirmé dans un message de console ultérieur. Voir https://www.chromestatus.com/feature/5718547946799104 pour plus de détails.
google.loader.f @ jsapi: 22



Coté arduino,
je cherche a "transformer" les lignes
Code: [Select]
data.addRow([ "13",  6.5,  9.0, 11.5, 13.5]);
 le but étant de na pas avoir a tout numéroter :
exemple,
si i=1:
colonne 1h les valeur temp_bac"i", temp_rampe"i",ph_BAC"i" et ph_RAC"i" seront lu.
puis i++
donc i=2:
colonne 2h les valeur temp_bac"i", temp_rampe"i",ph_BAC"i" et ph_RAC"i" seront lu.
puis i++
ect ...

J'ai testé pas mal de truc mais je me demande si cela est possible car dans les code que j'ai déjà vu, cette méthode sert pour "affecter" les caractere dans une chaîne char (dsl si ces mal exprimé)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 05, 2017, 09:43 am
 :D  :D  :D
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 05, 2017, 10:15 am
J'ai trouvé  8)
j'ai fait le test sur 24 secondes (plutôt qu'attendre 24h  :smiley-razz: )

j'ai fait
Code: [Select]
float temp_bac_graph[25],temp_rampe_graph[25],ph_BAC_graph[25],ph_RAC_graph[25];

////////////////////////////////////////////////////////////////////////////////////////////

void GRAPHIQUE(){
i=S;
if ((i<25)&&(testgraph==0)){
temp_bac_graph[i]=temp_bac;
temp_rampe_graph[i] = temp_rampe;
ph_BAC_graph[i] = ph_BAC;
ph_RAC_graph[i] =ph_RAC;
Serial.println(i);
}
}

//////////////////////////////////////////////////////////////////////////////////

i=0;
while (i<25){

client.print(F("data.addRow([\""));client.print(i);client.print(F("\",\r\n"));client.print(temp_bac_graph[i]);client.print(F(","));client.print(temp_rampe_graph[i]);
client.print(F(","));client.print(ph_BAC_graph[i]);client.print(F(","));client.print(ph_RAC_graph[i]);client.print(F("]);\r\n"));
i++;
}




j'ai mis mon doigt sur la sonde "température bac" pour faire varier la T

TinDinnnnn: (https://img15.hostingpics.net/pics/456139Sanstitre.jpg)



Ps: j'ai pris 5% de mémoire dynamique avec cette fonction.
Du au float ? (25 float de chaque variable (4) de 4 octets = 400 octets ?)
Code: [Select]
Les variables globales utilisent 5332 octets (65%) de mémoire dynamique, ce qui laisse 2860 octets pour les variables locales. Le maximum est de 8192 octets.
400 fait bien 4.88% de 8192 donc je pense que ces ça...
Donc, il faut trouver une solution pour stocker sur SD je suppose ..
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 05, 2017, 11:28 pm
pas envie de coder ce soir alors je lit "juste" le tuto sur l'esp.
la première partie pour mettre en mémoire la page html ma l'air accessible.
après ça se complique avec ajax
xml je patauge
et quand je vois que le nombre de page que tu a encore réservé  :smiley-confuse:  :smiley-confuse:  :smiley-confuse:

Tu a du voir de quoi jetait capable jusque a présent.
Je me demande vraiment si j'ai le niveau pour me lancer la dedans et ne pas finir bloqué ...

Il faut également penser que d'autre utilisateur devrons faire certaine de ces manipulations pour pouvoir utiliser l'aquabouns et certains on pas/peu de connaissance dans l'arduino.
Si mon projet ne peut être monté et utilisé par peu de monde, il perd tout intérêt pour la majorité des aquariophiles.

Qu'en pence tu ? dois je revoir mes ambitions a la baisse ou foncer ? jusque ou aller pour rester accessible a la majorité ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 06, 2017, 12:07 am
Oui c'est un bon point - le soucis étant que la performance ne va pas être bonne en HTML, peut être il faut se concentrer sur la solution avec l'ecran TFT
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 06, 2017, 09:13 am
l'ecran TFT
J'ai aussi réfléchit a cette solution et n'avoir que la visualisation des paramètre sur la page web, via le graphique  (quand on est en vacance par exemple) sans avoir la page de paramétrage, qui est très long des que l'on touche au bouton.

reste le problème de l'écran ...

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 06, 2017, 09:19 am
Oui c'est un bon point
J'en est gagné un de plus ?  :smiley-wink:  ;D
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 06, 2017, 09:22 am
Si ce n'est pas indiscret, tu travaille dans quoi ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 06, 2017, 10:15 am
J'en est gagné un de plus ?  :smiley-wink:  ;D
Pour l'humour ? Non ça ne compte pas :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Dec 06, 2017, 01:15 pm
Boun's, J-M-L bonjour.

Boun's tu n'as peu l'image du ' Bon Point'

Et je vous suis toujours en apprenant tranquillement.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 06, 2017, 06:47 pm
Pour l'humour ?
Celui ci te reviens :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 06, 2017, 11:10 pm
a tu un ecran sur arduino a me conseiller ? un capacitif avec une connection a peu de fils (l'idéal est de pourvoir le deporter via un RJ45) ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 07, 2017, 09:40 am
Le seul que j'ai c'est le 2.8 TFT Touch Shield for Arduino w/Capacitive Touch (https://www.adafruit.com/product/1947) de Adafruit mais il est assez petit avec 240x320 pixels  (devrait suffire cependant pour vos besoins si vous bossez un l'interface graphique (je ne pense pas que vous ayez vraiment besoin de 7 pouces!)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 07, 2017, 12:13 pm
Le seul que j'ai c'est le 2.8 TFT Touch Shield for Arduino w/Capacitive Touch (https://www.adafruit.com/product/1947) de Adafruit mais il est assez petit avec 240x320 pixels  (devrait suffire cependant pour vos besoins si vous bossez un l'interface graphique (je ne pense pas que vous ayez vraiment besoin de 7 pouces!)
Les futures utilisateur souhaite un écran plus grand, pas forcement 7" mais l'avantage est que les 5" et 7" avait la même puce et même résolution donc chacun pouvais mettre l'écran de la taille souhaité.
5" me semblais être un bon compromis taille/prix
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 08, 2017, 12:07 am
mes recherche mon fait tomber plusieurs fois sur des écran "nextion" que j'ai zaper a chaque fois.
Mais faute de trouver réellement se que je cherche, connection avec peu de fils et sans shield, tactil capacitif ... j'ai fini par y regarder de plus pret.

Il communique avec l'arduino via le tx / rx (donc, que 4 fils :) )
si j'ai bien compris, toute la video est geré par l'ecran lui meme en telechargent directement dans l'ecran les page que l'on cree avec leur logitiel (https://nextion.itead.cc/editor_guide/), pratique puisque plus besoin de téléverser a chaque modif pour voir le rendu ...
Donc l'arduino est un peu libéré ( et également de la bibliothèque assez lourde associé)

J'ai trouvé 2 video ou l'on voit la réactivité de l'ecran.
video 1 (https://www.youtube.com/watch?v=eDn7LFyoEm8)
video 2 (https://www.youtube.com/watch?v=hKt1MmYD0-Q)

Autre point simpa :
en résolution 800*480 il est dispo en 5" et 7" (https://nextion.itead.cc/shop-nextion/)
et pourquoi pas faire aussi des page  en 480 * 320 pour ceux qui voudrait un écran plus petit (3.5") ?

dispo en version avec boitier (https://www.itead.cc/nextion-nx8048k070-011r-011c.html) ce qui est vraiment un plus pour l'intégrer a nos aquariums

Bref ... trop beau sur le papier pour être vrai ...

Qu'en penser vous ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 08, 2017, 08:57 am
et j'ai meme trouvé un exemple pour un aquarium (https://www.itead.cc/blog/nextion-tutorial-based-on-nextion-arduino-library) :)
en tout cas je trouve l'interface graphique vraiment sympa (incomparable avec se que j'avais pu faire cette été sur mon 480*320)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 08, 2017, 09:20 am
Oui nextion c'est cool et performant -  mais c'est assez cher aussi et ils n'ont qu'un soft pour PC.. moi je suis Mac ou Linux alors je ne les aime pas :)

Ils ont une librairie arduino qui facilite la communication
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 08, 2017, 09:31 am
Oui nextion c'est cool et performant -  mais c'est assez cher aussi et ils n'ont qu'un soft pour PC.. moi je suis Mac ou Linux alors je ne les aime pas :)
C'est vrai que c'est un peu plus chère, en comparaison, les 7" sont au alentour de 50€ et la, le moins chère que j'ai trouvé c'est 80€ ...
Pour les 5" 45€ contre 70€ ...
Pour les 3.5# ~15€ contre 20€ donc sur petite taille peu de différence

oui, embêtant pour leur application ...
D'un autre coté, une fois l'interface graphique réalisé et mis sur SD cela n'as plus d'importance.

d'un point de vu global,
branchement (moins de 8 fils pour fonctionner)
performance
Facilité de programmation/échange avec l'arduino
qualité/prix
Je doit oublier cette piste (pour la quelle ?)?
ou cela est un bon compromis
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 08, 2017, 09:37 am
C'est un  bon compromis - avec des jolis graphiques et c'est un peu comme AJAX et la page web, vous ne balancez que les données il se charge de peindre l'ecran Comme il faut donc c'est rapide

Juste avis perso - je boycotte les sociétés qui n'ont pas compris que de plus en plus de monde utilise un Mac ou Linux (ou le cloud); c'est pour moi un signe de manque de vision et d'adaptation au changement. Donc des has-been... ce qui m'intéresse c'est le progrès, l'innovation.. ils ne vivent pas avec leur temps et donc leurs clients un jour vont se retrouver dépassés aussi
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 08, 2017, 09:41 am
C'est un  bon compromis - avec des jolis graphiques et c'est un peu comme AJAX et la page web, vous ne balancez que les données il se charge de peindre l'ecran Comme il faut donc c'est rapide

Juste avis perso - je boycotte les sociétés qui n'ont pas compris que de plus en plus de monde utilise un Mac ou Linux (ou le cloud); c'est pour moi un signe de manque de vision et d'adaptation au changement. Donc des has-been... ce qui m'intéresse c'est le progrès, l'innovation.. ils ne vivent pas avec leur temps
oula ... faut que je passe sous mac ... j'ai pas envie que mon fils pence que je suis un vieux des années 80 ...  ;D  ;D  ;D

Du coup, ca veut dire que tu ne pouras pas m'aider sur cette partie la ...  :smiley-roll-blue:  :smiley-roll-sweat:

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 08, 2017, 01:04 pm
Non pas vraiment pour aider - cels dit comme je suis curieux j'ai regardé comment ça marche et lu quelques tutos et lu le code des librairies en diagonale - c'est assez simple à comprendre
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 08, 2017, 01:18 pm
Sinon pour le « faut que je passe sous mac » --> pas forcément (même si ça vous changerait la vie en mieux à mon avis même s'il vous faudrait une période d'adaptation  :) )

Mais mon commentaire C'est plus pour les fabricants de solutions - je suis pour que les individus eux restent libres de leur choix bien sûr
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 08, 2017, 05:32 pm
Non pas vraiment pour aider - cels dit comme je suis curieux j'ai regardé comment ça marche et lu quelques tutos et lu le code des librairies en diagonale - c'est assez simple à comprendre
Je me lens dans le vide alors ...
Je part sur le 3.5" dans un premier temps histoire de dompter la bete.
Si tout est Ok je prendrais un 7" comme ça je pourrait proposer 2 définition et 3 taille d'écran
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 08, 2017, 05:34 pm
ça vous changerait la vie en mieux
Je suis sur de ca mais se qui me bloque c'est la partie hardware qui ne peut pas être monter maison, pas evolutif, cout plus élevé ...
Je me trompe peut être ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 12, 2017, 12:06 am
Bonsoir,

j'avance peu en se moment, faute de temps.
Je continu a mettre en forme.
J'en arrive a un code assez long, difficile de si retrouver ... (dans toute les fonctions, mais le loop est beaucoup plus claire)
J'ai pour le moment inclue le wifi pour les test.
Le gsm est opérationnel.

il y a peut être autre chose a faire pour rendre tout cela plus claire et lisible ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 12, 2017, 12:25 pm
dans l'absolu il faudrait un fichier .cpp et un fichier .h par grands modules (les fonctions dans la loop()).

Dans le .h vous déclarez la fonction principale qui est appelée dans la loop(), tout le reste qui lui est spécifique est dans le .cpp qui inclus le .h

le .ino inclurait aussi tous ces .h

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 13, 2017, 12:10 am
j'ai suivi ce tuto (http://eskimon.fr/1803-arduino-mini-tuto-organisez-votre-code-en-fichiers) que plusieurs personne recommande sur les forums

J'ai donc eclairage.h :
Code: [Select]
ECLAIRAGE();

et eclairage.cpp:
Code: [Select]
void ECLAIRAGE(){
  // **************************************** bleu 1
  if (eclairageBleu1 == eclairageArret) {
    pwm_bleu1 = 0;
    analogWrite(pinOUT_bleu1, 0);
  }
  else if (eclairageBleu1 == eclairageActif) {
    pwm_bleu1 = puissance_bleu;
    analogWrite(pinOUT_bleu1, puissance_bleu);
  }
  else if (eclairageBleu1 == eclairagePWM) {
    if ((Time >= debut_LEVER_bleu1) && (Time < fin_LEVER_bleu1)) {
      pwm_bleu1 = map(Time, debut_LEVER_bleu1, fin_LEVER_bleu1, 0, puissance_bleu);
      analogWrite (pinOUT_bleu1, pwm_bleu1);
    }
    else if ((Time >= debut_COUCHER_bleu1) && (Time < fin_COUCHER_bleu1)) {
      pwm_bleu1 = map(Time, debut_COUCHER_bleu1, fin_COUCHER_bleu1, puissance_bleu, 0);
      analogWrite (pinOUT_bleu1, pwm_bleu1);
    }
    else if ((Time >= fin_LEVER_bleu1 ) && (Time < debut_COUCHER_bleu1)) {
      pwm_bleu1 = puissance_bleu;
      analogWrite(pinOUT_bleu1, puissance_bleu);
    }
    else {
      pwm_bleu1 = 0;
      analogWrite(pinOUT_bleu1, 0);
    }
  }

  // **************************************** bleu 2
  if (eclairageBleu2 == eclairageArret) {
    pwm_bleu2 = 0;
    analogWrite(pinOUT_bleu2, 0);
  }
  else if (eclairageBleu2 == eclairageActif) {
    pwm_bleu2 = puissance_bleu;
    analogWrite(pinOUT_bleu2, puissance_bleu);
  }
  else if (eclairageBleu2 == eclairagePWM) {
    if ((Time >= debut_LEVER_bleu2) && (Time < fin_LEVER_bleu2)) {
      pwm_bleu2 = map(Time, debut_LEVER_bleu2, fin_LEVER_bleu2, 0, puissance_bleu);
      analogWrite (pinOUT_bleu2, pwm_bleu2);
    }
    else if ((Time >= debut_COUCHER_bleu2) && (Time < fin_COUCHER_bleu2)) {
      pwm_bleu2 = map(Time, debut_COUCHER_bleu2, fin_COUCHER_bleu2, puissance_bleu, 0);
      analogWrite (pinOUT_bleu2, pwm_bleu2);
    }
    else if ((Time >= fin_LEVER_bleu2 ) && (Time < debut_COUCHER_bleu2)) {
      pwm_bleu2 = puissance_bleu;
      analogWrite(pinOUT_bleu2, puissance_bleu);
    }
    else {
      pwm_bleu2 = 0;
      analogWrite(pinOUT_bleu2, 0);
    }
  }

  /////////////////////////////////////// *** blanc *** ///////////////////////////////////////
  // **************************************** blanc 1
  if (eclairageBlanc1 == eclairageArret) {
    pwm_blanc1 = 0;
    analogWrite(pinOUT_blanc1, 0);
  }
  else if (eclairageBlanc1 == eclairageActif) {
    pwm_blanc1 = puissance_blanc;
    analogWrite(pinOUT_blanc1, puissance_blanc);
  }
  else if (eclairageBlanc1 == eclairagePWM) {
    if ((Time >= debut_LEVER_blanc1) && (Time < fin_LEVER_blanc1)) {
      pwm_blanc1 = map(Time, debut_LEVER_blanc1, fin_LEVER_blanc1, 0, puissance_blanc);
      analogWrite (pinOUT_blanc1, pwm_blanc1);
    }
    else if ((Time >= debut_COUCHER_blanc1) && (Time < fin_COUCHER_blanc1)) {
      pwm_blanc1 = map(Time, debut_COUCHER_blanc1, fin_COUCHER_blanc1, puissance_blanc, 0);
      analogWrite (pinOUT_blanc1, pwm_blanc1);
    }
    else if ((Time >= fin_LEVER_blanc1 ) && (Time < debut_COUCHER_blanc1)) {
      pwm_blanc1 = puissance_blanc;
      analogWrite(pinOUT_blanc1, puissance_blanc);
    }
    else {
      pwm_blanc1 = 0;
      analogWrite(pinOUT_blanc1, 0);
    }
  }

  // **************************************** blanc 2
  if (eclairageBlanc2 == eclairageArret) {
    pwm_blanc2 = 0;
    analogWrite(pinOUT_blanc2, 0);
  }
  else if (eclairageBlanc2 == eclairageActif) {
    pwm_blanc2 = puissance_blanc;
    analogWrite(pinOUT_blanc2, puissance_blanc);
  }
  else if (eclairageBlanc2 == eclairagePWM) {
    if ((Time >= debut_LEVER_blanc2) && (Time < fin_LEVER_blanc2)) {
      pwm_blanc2 = map(Time, debut_LEVER_blanc2, fin_LEVER_blanc2, 0, puissance_blanc);
      analogWrite (pinOUT_blanc2, pwm_blanc2);
    }
    else if ((Time >= debut_COUCHER_blanc2) && (Time < fin_COUCHER_blanc2)) {
      pwm_blanc2 = map(Time, debut_COUCHER_blanc2, fin_COUCHER_blanc2, puissance_blanc, 0);
      analogWrite (pinOUT_blanc2, pwm_blanc2);
    }
    else if ((Time >= fin_LEVER_blanc2 ) && (Time < debut_COUCHER_blanc2)) {
      pwm_blanc2 = puissance_blanc;
      analogWrite(pinOUT_blanc2, puissance_blanc);
    }
    else {
      pwm_blanc2 = 0;
      analogWrite(pinOUT_blanc2, 0);
    }
  }

}


et ajouter #include "eclairage.h" dans "l'en tete" de mon fichier .ino


et a la compile j'ai
Code: [Select]
exit status 1
expected constructor, destructor, or type conversion before ';' token

sur mon fichier eclairage.h

Pourtant j'ai bien suivi le tuto, et je l'ai refait 3 fois ...



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 13, 2017, 07:26 am
Dans le .h mettez
Code: [Select]

#ifndef  _eclairage_h_
#define _eclairage_h_
extern void ECLAIRAGE();
#endif


ça dit qu'il va exister quelque part une fonction du nom ECLAIRAGE qui ne prend aucun param et qui ne retourne rien. le .cpp va lui importer le .h et définir cette fonction. Votre .ino lui va aussi prendre le .h

Pour éviter de déclarer 2 fois des mêmes choses on utilise la ruse du #ifndef
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 13, 2017, 11:33 pm
les declaration t'elle que
Code: [Select]
int puissance_bleu = 255 ;
qui sont utilisé pour cette fonction mais egalement dans d'autre doivent etre declaré dans le .cpp ou dans le ino ?

Quand je les met dans le ino j'ai erreur dans .cpp et quand elle sont dans le .cpp elle sont non déclarer dans le ino ...

Y a encore une ruse...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 14, 2017, 07:01 am
Ce sont des éléments globaux - donc un .h genre varglobales.h qui les déclare comme étant extern que vous importez partout où au moins une des variable, constante, type, enum, ... doit être connu

et vous les définissez (allouez la mémoire et la valeur de départ) dans un des fichiers .cpp, le plus pertinent

Mettre aussi la « ruse » du ifndef dans ce. h aussi

Code: [Select]
#ifndef  _varglobales_h_
#define _varglobales_h_
extern int puissance_bleu;
// ....
#endif
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 14, 2017, 09:07 am
Ce sont des éléments globaux - donc un .h genre varglobales.h qui les déclare comme étant extern que vous importez partout où au moins une des variable, constante, type, enum, ... doit être connu

et vous les définissez (allouez la mémoire et la valeur de départ) dans un des fichiers .cpp, le plus pertinent
si je comprend bien, actuelement j'ai
Code: [Select]
unsigned long debut_LEVER_bleu1 = LEVER;

Je fait un header (j'ai revisé lol) avec
Code: [Select]
unsigned long debut_LEVER_bleu1;

et dans le Cplusplus le plus concerné je fait
Code: [Select]
debut_LEVER_bleu1 = LEVER;

Pour le #ifndef, extern, #endif je regarde pour trouver un post qui m'explique le pourquoi et ce que c'est.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 14, 2017, 09:26 am
Oui pour le mot header, non pour la forme car il faut utiliser extern

Une variable est définie par plusieurs choses: son petit nom pour l'utiliser dans le code, son type (le nombre d'octets alloués), son adresse mémoire (l'adresse du premier octet) et le contenu de ces adresses mémoire.

En gros On parlera de déclaration quand il s'agit du nom et du type et de définition quand il s'agit du tout - du type, du nom, de l'adresse mémoire (et du contenu éventuellement).

En faisant
Code: [Select]
int toto=8;on déclare et définit en même temps la variable,c'est à dire qu'on fait tout d'un coup: on dit que le type est int, que le petit nom c'est toto, et en l'écrivant comme cela quand le compilateur voit ça il réserve de la mémoire (ici 2 octets) à un endroit particulier. Et accessoirement il met dans les bits de 2 octets la représentation en binaire de la valeur 8.

Quand on fabrique un projet qui comporte plusieurs fichiers il y a plusieurs étapes. La première consiste à compiler chaque fichier indépendamment puis ensuite à tout mettre ensemble et résoudre à ce moment là les dernières choses inconnues - on appelle cela la phase de « link » en anglais.

Pour compiler un bout de code où on parlerait de toto, il suffit de savoir que toto est un entier sur 2 octets. C'est Seulement à la phase de link qu'il faudra enfin savoir où il est exactement en mémoire.

Le mot clé extern permet de séparer les deux opérations.
Code: [Select]
extern int toto; dit au compilateur "il va y avoir quelque part une variable de type int qui s'appelera toto. Ne te soucie pas pour le moment d'où elle est en mémoire, je te le dirais plus tard, à l'extérieur de ce fichier (d'où le extern) ».bien sûr il faudra s'assurer que quelque part ailleurs vous ayez bien la définition

Donc quand vous voulez utiliser une variable dans différents fichiers, il y en a un qui contient la vraie définition (et donc effectue l'allocation de la mémoire) et tous les autres ne doivent avoir que la déclaration (juste qu'est-ce que c'est que ce nom représente).

Si vous n' avez qu'une variable vous pouvez mettre
Code: [Select]
extern int toto;dans tous les fichiers. C'est simple. Mais si vous en avez beaucoup ça fait lourd de mettre toutes ces déclarations dans chaque fichier et Donc souvent on fait un .h qui ne fait que déclarer toutes les variables partagées avec extern et ensuite tous les fichiers de code (.cpp ou .ino) qui ont besoin de les connaître, importent ce .h ce qui permet au compilateur de connaître le type des variables et leurs noms. Un des fichiers - peu importe lequel mais souvent celui qui est pertinent pour cette variable ou le corps principal -  va avoir la vraie définition et lors de la phase de link tout au bout du processus de fabrication du programme exécutable, le linker retrouve ses petits et remplace les adresses inconnues par la vraie adresse mémoire à lire ou écrire

OK?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 14, 2017, 09:42 am
J'ai bien compris le principe, l'explication est très clair  :smiley-wink:
effectivement ça compile :)
Mais du coup, ça fait un paquet de ligne en plus ...



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 21, 2017, 12:51 am
bonsoir,

Discret en se moment ... beaucoup de taf avec les fete qui approche donc bon ... je boss beaucoup moins sur le projet que j'en est envie mais bon ...

J'ai reçu mon écran nextion 3.5.
Ca a l'air vraiment super, tu branche, et quasi instantanément tu a un menu demo.
tres belle affichage.
J'ai donc commencer a utilise le logitiel NEXTION EDITOR pour faire des tests.
Et comme d'habitude ... sa a merdé ...
J'ai donc chercher a comprendre ...
Et j'ai fini par trouver ...

Ces écran son commercialiser sous 2 référence différente pour chaque ecran.
exemple pour le 3.5
NX4832T035_011R et TJC4832T035_011R
La version NX (nextion) est faite pour le marché international tandis que la version TJC est réservé au marché chinois. (et je pense que l'on peut dire que ce sont des copie tout simplement!)
Certain vendeur n'hesite pas a vendre ces ecran TJC en indiquant NEXTION ...
Vous vous douter bien quelle version des deux j'ai reçu ...  :smiley-confuse:  :smiley-confuse:
Si cette "difference" ne posait pas probleme ...

MAIS

Le logiciel NEXTION EDITOR a décider de ne prendre en charge que les ecran NX ...
Pour les ecran TJC il faut utiliser USART HMI ... qui est en chinois !!!
Bien sur, impossible d'importer un fichier fait dans nextion editor dans usart hmi ...


Décidément ... compliqué avec les écrans ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 21, 2017, 05:55 am
Les joies des chinoiseries...courage !
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 24, 2017, 09:18 am
Code: [Select]
0110001001101111011011100110101001101111011101010111001000101100000010100110001001101111011011100110111001100101001000000110011001100101011101000110010100100000011001000110010100100000011011100110111101100101011011000010000001100001001000000111010001101111011101010111001100101110000010100110000100101011






si besoin ... (http://www.supportduweb.com/convertisseur-textes-binaire-code-ascii-numerique-ordinateur-secret-encoder-text-binary-chiffrer.html)




 :smiley-wink:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 27, 2017, 11:47 pm
bonsoir,

Apres l'électronique et le codage ... il faut se mettre au graphisme ...Tout aussi compliqué sans maîtrise des logiciel mais sa commence a être sympa
(https://img15.hostingpics.net/pics/665438Sanstitre.png)
Y manque que les variable :)

Un fois l'affichage terminer je passerait au codage écran puis arduino.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 28, 2017, 09:32 am
Wow c'est Disney land :)

Bravo et bonnes fêtes
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 28, 2017, 09:45 am
(http://cleopatre22.e-monsite.com/medias/ecard/bonne-fete-6-1.gif)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 29, 2017, 11:29 am
En retard de 4 jours ...

Mais il est quand même passé ...

Le papa noel  lol

Et visiblement, il y avait beaucoup de lutin en CP ou maladie ...
:)


(http://i64.tinypic.com/68dk4n.jpg)

Ça va être bien pratique pour l'aquaboun's ... boitier, support sonde ect ...





Et 6h15 plus tard

(http://i65.tinypic.com/29eo04.jpg)


Y a plus qu'a tout réglé et lancer la première impression :) :) :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 29, 2017, 11:35 am
Il y en a qui sont gâtés :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Dec 29, 2017, 02:22 pm
Boun's bonjour.

Super page d'accueil et joli graphisme, donc en un mot ' beau boulot'.

Je rejoins J-M-L ' y en as qui sont vernis'.

Allez zou bonne fête et à l'année prochaine.

Pascal.
 
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hazerty565 on Dec 29, 2017, 03:28 pm
djbouns dis moi on tu as acheter ton imprimante 3D? quel prix?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 29, 2017, 04:02 pm
merci

Je l'ai commander sur gearbest.
pour 170€

Par contre il faut prendre en compte 3 points importants :

1 mois 1/2 de délais de livraison
Risque de dédouanement ( donc 20% + 25€ de frais)
Arrive démonté ( j'ai passé 6h15 non stop ! et c'est juste pour le montage ... je suis depuis plusieurs heure sur le réglage et test ...) je ne suis pas un pro mais je ne crois pas être novice non plus donc ATTENTION ne vous lancer pas a l'aveugle.

PS: et ne pas oublier qu'il a fallu être sage toute l'année lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 01:47 am
La page de paramétrage

(https://img15.hostingpics.net/pics/911337Sanstitre.png)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 31, 2017, 01:56 am
Je vois que vous maîtriser la chose !

C'est peut être juste mon goût perso mais je trouve que c'est chargé et difficile à lire. Le dessin du fond devrait être plus en filigrane pour améliorer les contrastes, les champs texte un fond blanc et texte noir c'est plus lisible et visible etc...

En ergonomie des interfaces utilisateurs, moins c'est plus ! Faites simple, une seule police de caractères, les couleurs doivent être porteuse de sens, ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 03:10 pm
Je vois que vous maîtriser la chose !
lol oula ... se n'est que le visuel ... je vais m'amuser avec le codage je pense ...


Pour le fond blanc sous le texte sa fait dégueu (je trouve)
j'ai donc mis le texte en blanc et suis revenu sur le fond original (donc assez sombre)
J'ai changer la couleur des boutons en faisant un degradé d'un coté pour le - et de l'autre pour le + (pas fait encore l'écriture dans les boutons)

(https://img15.hostingpics.net/pics/592540Sanstitre.png)

Pour info, si vous ouvrez l'image dans une nouvelle page ou a partir du lien (https://img15.hostingpics.net/pics/592540Sanstitre.png), l'image sera taille "pixel" réel (800*480), donc plus pratique de se rendre compte


Qu'en pense tu ?

et vous , hazerty565, Breisleach (en temps que futur utilisateur ? lol)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 31, 2017, 03:20 pm
Les labels en blanc c'est déjà plus lisible - ensuite je ne comprends pas bien ce qui va aller dans toutes ces cases où vous avez des 5 et comment l'utilisateur va interagir
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 03:49 pm
ensuite je ne comprends pas bien ce qui va aller dans toutes ces cases où vous avez des 5 et comment l'utilisateur va interagir
Les "5" sont provisoire, je n'ai pas encore rentrée les valeur de chaque bouton.
Ces boutons, par un appuie tactile modifierons la variable qui seras entre les 2 boutons, même implantation que sur la page web (et modifieras en même temps la variable dans l'arduino)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: ChPr on Dec 31, 2017, 03:54 pm
Vous ne disposez pas de caractères accentués pour votre afficheur ?

Dernière info en bas à droite : Mouvement de 1° des oscillateurs toutes les :

Bonnes fêtes de fin d'année à vous ... et à toutes et à tous.

Pierre
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 31, 2017, 03:55 pm
ah OK

Pourquoi ne pas dessiner des beaux boutons avec d'un côté un "-" et de l'autre un "+" et la valeur entre les 2?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 05:28 pm
chaque bouton ne modifie pas la variable du même nombre
certain 0.1 d'autre 1 ou encore 5 ...

J'ai mis les valeur dans les boutons :
(https://img15.hostingpics.net/pics/933665Sanstitre.png)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 05:57 pm
Petite question sur les ssid et mdp wifi (je suis sur le clavier tactile)

Est il impératif d'avoir minuscule/majuscule ou les ssid et mdp sont bien reconnu quand même ?
Y a t'il des caractere spéciaux dedans ? sinon, cela m'évite un paquet de touche a faire.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 31, 2017, 06:03 pm
Tous les  caractères sont reconnus...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 06:05 pm
Vous ne disposez pas de caractères accentués pour votre afficheur ?

Dernière info en bas à droite : Mouvement de 1° des oscillateurs toutes les :

Bonnes fêtes de fin d'année à vous ... et à toutes et à tous.

Pierre
Les % fonctionnes
Les ° non ...

L'orthographe c pas mon truc  :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 06:06 pm
Tous les  caractères sont reconnus...
a ...

arff ...

 :smiley-sweat:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: ChPr on Dec 31, 2017, 06:36 pm
... L'orthographe c pas mon truc  :smiley-confuse:
Moi non plus, mais j'essaie d'y faire attention.

Au-delà de ça, vous réalisez un matériel dont plusieurs personnes pourraient s'inspirer ou le reproduire. C'est quand même plus sympa si l'IHM est correcte et n'a pas l'air de venir d'une traduction douteuse d'un truc venant d'on ne sait où.

Cordialement.

Pierre
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 31, 2017, 06:54 pm
#djbouns - de mémoire je crois que j'avias Lu que Nextion supportait de nombreux ISO8859 et pour le français c'est le 1 (il manque de mémoire le E dans l'O = œ) ou le 15  (ajoute le symbole € et le œ) qui va bien.

regardez la doc comment sélectionner le Charest et ensuite il suffit d'envoyer ces caractères, ils tiennent sur 1 octet, la partie ASCII est la même et il y a d'autres caractères dans la partie haute y compris toutes les lettres accentuées
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Dec 31, 2017, 07:10 pm
#djbouns
Ludovic   ;)


je suppose que tu parle de ça :
(https://img15.hostingpics.net/pics/980681Sanstitre.png)


Je suis rester sur celui par défaut, ascii, car je ne comprend pas se qu'il me veut lol
Donc il suffit que je sélectionne la deuxième ligne pour avoir les caractere spéciaux.


Je testerais sa en 2018 car je doit y allée ...  :smiley-razz:


Alors avec un peu d'avance ...


(https://t3.ftcdn.net/jpg/01/81/59/40/240_F_181594048_s1q9Tw1OFLiTTdsY4rZfhWLmqpd8lkLU.jpg)


Passer un bon réveillons, et profité bien, mais pas trop lol  :smiley-mr-green:

Et un grand Merci pour toutes l'aide que vous m'apportez.

Et ...
a l'année prochaine lol (https://www.youtube.com/watch?v=EsCZ4ciTZEk)

;)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Dec 31, 2017, 07:19 pm
Bonne fête de fin d'année, joyeux réveillon, ne mangez pas les poissons de l'aquarium :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 01, 2018, 11:00 am
ne mangez pas les poissons de l'aquarium :)
:smiley-confuse:  :smiley-confuse:  :smiley-confuse:  trop tard  :smiley-confuse:  :smiley-confuse:  :smiley-confuse:

(https://img15.hostingpics.net/pics/694232Sanstitre.png)

:smiley-lol:  :smiley-lol:  :smiley-lol:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 01, 2018, 11:14 am
J'ai pris le 8859-1 et les ° se "transforme" en ?
Et les ? reste bien en ?

mais je vient de voir que ça le fait directement dans le logiciel, avant même d'être affecté a un type de police :/
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 01, 2018, 02:22 pm
un petit aperçu (https://www.youtube.com/watch?v=tDnYKmtVGOA&feature=youtu.be) des pages réalisé et de la navigation
Le clavier est presque fini

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 01, 2018, 06:05 pm
normalement le lien fonctionne maintenant
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 03, 2018, 04:01 am
qu'en pensez vous ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Jan 03, 2018, 08:23 am
Boun's bonjour et tous mes vœux pour toi et ta familles.

Joli et simple de compréhension je trouve... Beau travail et hâte de continuer à apprendre en vous lisant.
¨
Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 03, 2018, 09:17 am
Salut

Bravo pour le boulot - surtout le clavier qui a du demander pas mal de temps. Une petite modification peut-être pour la partie Wifi: généralement en interface utilisateur on choisit d'abord le champ à modifier puis on tape le texte à côté plutôt que le contraire (ou taper dans le vide et affecter le résultat)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 03, 2018, 11:30 am
Bravo pour le boulot
Arfff ... en 2018 juste le droit a un bravo ... meme plus de bon point  :smiley-confuse:
;D  ;D  ;D

le clavier qui a du demander pas mal de temps
au que oui ...


généralement on choisit d'abord le champ à modifier puis on tape le texte à côté
par ici (https://youtu.be/whxgeA2ulRg)

Je n'ai fait que la première ligne du clavier, je ferait le reste cette nuit.
C'est bon comme ca ou autre chose a modifier avant de programmer toutes les touches ?


J'ai également ajouter "un petit détail" lorsque l'on clique sur enregistrer car le retour a la page précédente me paraissait trop violent et pouvait laisser penser qu'il y avait un bug et/ou que la sauvegarde n'avait pas ete faite. j'ai donc ajouter un petit barre de progression ne laissant plus planer de doute.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 03, 2018, 11:31 am
Boun's bonjour et tous mes vœux pour toi et ta familles.
Meilleur voeux a vous aussi
La santé et plein de bonne chose
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 03, 2018, 03:36 pm
Arfff ... en 2018 juste le droit a un bravo ... meme plus de bon point  :smiley-confuse:
;D  ;D  ;D
au que oui ...


par ici (https://youtu.be/whxgeA2ulRg)

Je n'ai fait que la première ligne du clavier, je ferait le reste cette nuit.
C'est bon comme ca ou autre chose a modifier avant de programmer toutes les touches ?


J'ai également ajouter "un petit détail" lorsque l'on clique sur enregistrer car le retour a la page précédente me paraissait trop violent et pouvait laisser penser qu'il y avait un bug et/ou que la sauvegarde n'avait pas ete faite. j'ai donc ajouter un petit barre de progression ne laissant plus planer de doute.
c'est cool :)

idéalement si vous pouviez avoir une sorte de champs de texte visualisé par un rectangle blanc à côté du SSID ou PWD ce serait l'idéal car on est habitué à reconnaitre ce genre de champs et donc à cliquer dessus pour le remplir
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 03, 2018, 11:21 pm
La question est dans la video (https://youtu.be/QBEYbumuhbs)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 04, 2018, 12:17 pm
?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 04, 2018, 12:50 pm
Oui c'est bon :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 07, 2018, 12:26 am
Bonsoir,

Petit vidéo video (https://youtu.be/K03WqXwqaAs) des mouvement thermomètre, j'ai également ajouter les champs variable.

C'était assez compliquer puisque le NEXTION ne prend que les chiffres entier, Donc les faire bouger a partir de température en décimal ... (les variable devront être x10 en sortant de l'arduino, le point des centième est incruster sur l'image de fond, meme chose pour les PH) et que les barres d'avancement ne peuvent pas être paramétré avec une valeurs basse et haute, elle son forcement de 0 a 100.
Ce n'est pas parfait mais je trouve les mouvement correcte.
Le thermo de rampe va de 20 a 65
Celui de l'aqua de 22 a 28.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 08, 2018, 12:29 am
J'ai avancé sur les variable du paramétrage avec un peu de code

///HS-in///
Le codage sur le nextion est assez simple et intuitif puisque il nous propose les possibilité au fur et a mesure de la ligne de code un peu comme la saisie intuitive de google.
Je suis vraiment agréablement surpris par le logiciel nextion, j'espère que le codage pour les échanges arduino/nextion seras aussi "facile"
///HS-out///

Des limite ont été mise pour tout les paramètres dont certains en relation entre eux.
Exemple, la limite PH bas ne peut pas être supérieur a la limite PH haut, ect ...

J'ai passé un peu de temps sur l'affichage OFF des oscillateur et tempête car, tout comme les affichage testé sur arduino, la  dernière image par dessus reste affiché si elle n'est pas recouvert. j'ai donc triché en élargissant les champs texte et sur les moment de rafraîchissement de l'écran.
De cette façon, visuellement on ne se rend compte de rien.

https://youtu.be/2MjN8nAFbJs (https://youtu.be/2MjN8nAFbJs)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 13, 2018, 10:37 pm
Et me revoila :) :) :)

Je suis depuis 2 jours sur la partie échange d'information entre l'écran et l'arduino.
J'ai naviguer sur le net, énormément de post en anglais, mais j'ai fini par trouver par ou commencer.
(je suis même tomber sur un le forum un post de juillet ou participe j.m)

Et donc, qui dit reprendre le codage dit rencontrer de nouveau problème :)

J'ai fait un petit code "test" pour comprendre les inter action entre les deux composant
Dans un premier temps, j'envoie des info de l'arduino a l'ecran.

Un champs texte initialement remplie par "abcd" est rempli par "azerty"
Un champs numérique initialement remplie par "1234" est rempli par now.second d'un RTC, ce champs ce mais bien a jour, sans saccade, c'est TOP :)

Code: [Select]

#include <Wire.h>
#include "RTClib.h"

#include "NexText.h"
#include "NexVariable.h"

RTC_DS3231 rtc;


NexText t0 = NexText(0, 1, "t0");
NexVariable n0 = NexVariable(0, 2, "n0");

void setup () {


Serial1.begin(9600);
Serial.begin(9600);

  delay(3000); // wait for console opening

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
}

void loop () {
DateTime now = rtc.now();
t0.setText("yes");
n0.setValue(now.second());
}


Par contre, dans le moniteur serie j'ai
Code: [Select]
recvRetCommandFinished err
recvRetCommandFinished err

Qui apparaît, un après l'envoie du champs texte et l'autre du numérique
J'ai chercher et ce problème arrive a beaucoup de monde mais sur tout les post, aucune solution( et en plus toujours en anglais donc je comprend pas tout des fois)
Il serait du au fait que l'écran ne renvoie pas un retour "OK" en quelque sort.
Mais pourquoi ...

ps : l'arduino arrive bien a lire les variable pressentes sur l'écran
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 16, 2018, 12:09 am
Personne ?

En plus je vient de voir que le forum nextion est fermé ... : /
Je trouve des code d'exemple mais pas de tuto adapté a se que j'ai besoin.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 16, 2018, 12:48 am
Désolé mais peux pas vous aider sur ce coup là - je n'ai pas ce genre d'écran
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 16, 2018, 08:42 am
 :smiley-wink: je le savais, on en avait discuté  :)
la poisse il on fermé le forum le 15 novembre  :smiley-confuse:

J'ai 3h devant moi ... il faut que je comprenne les exemple fourni avec la biblioteque
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 16, 2018, 10:24 am
J'ai compris le principe de l'exemple "bouton"
Sur l'ecran, un bouton avec du texte dessus "1"
Dans l'arduino :
Code: [Select]
void b0PopCallback(void *ptr)
{
    uint16_t len;
    uint16_t number;
    NexButton *btn = (NexButton *)ptr;
    dbSerialPrintln("b0PopCallback");
    dbSerialPrint("ptr=");
    dbSerialPrintln((uint32_t)ptr);
    memset(buffer, 0, sizeof(buffer));

    /* Get the text value of button component [the value is string type]. */
    btn->getText(buffer, sizeof(buffer));
    
    number = atoi(buffer);
    number += 1;

    memset(buffer, 0, sizeof(buffer));
    itoa(number, buffer, 10);

    /* Set the text value of button component [the value is string type]. */
    btn->setText(buffer);
}


Chaque click augment de +1 la valeur le texte present sur le bouton.


Si je décode se qui se passe :
Le click sur l'ecran envoie un message "65 00 01 00 FF FF FF " a l'arduino (le "65 00 01 00 FF FF FF " étant surement décodé par la bibliothèque et associé au bon bouton, ce qui déclenche b0PopCallback)
L'arduino lit la valeur "texte" du  bouton en la stock dans un String
"atoi" converti se String en numerique
On ajout +1 a se numerique
"itoa" converti le numerique en String
L'arduino renvoie cette valeur au bouton qui l'affiche.

Je ne croie pas mettre trompé donc cela m'amène a une question ...
En procédant de cette manière, l'arduino est sollicité (j'irais dire, pour rien puisque l'écran lui même est capable de faire cette opération de +1 ou -1)

J'étais parti du principe que :
Quand la page s'ouvre, les valeur son demander a l'arduino.
On modifie tout se que l'on veut
On enregistre ( toute les valeur son envoyer a l'arduino OU, il me parait plus simple que l'arduino les lises)

Je continu sur ma lancer ou adopte leur exemple ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 16, 2018, 11:49 am
Oui le principe du callback de l'écran est bien celui la et si vous pouvez bien interroger chaque élément lors du click sur la sauvegarde des préférences alors les 2 approches sont possibles

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 16, 2018, 11:51 am
mais la quelle te parait la mieux ?
vos mieux laisser l'arduino faire autre chose ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 16, 2018, 12:16 pm
Les interfaces modernes sont souvent en modification directe (ce que vous voyez affiché est la réalité en vigueur tout le temps) sauf dans certains cas où plusieurs paramètre doivent être modifiés d'un coup pour faire quelque chose de cohérent

Je pense que dans votre cas vous êtes plutôt dans la seconde catégorie et qu'il ne sert à rien d'avoir l'arduino Qui doit traiter toutes les valeurs intermédiaires si vous voulez passer un paramètre de 10 à 20, surtout si pour que ce soit cohérent il faut en baisser un autre de 20 à 10 par exemple.

Donc si vous voulez frimer un peu :) - vous allez dire que vous prenez la design pattern MVC (https://fr.m.wikipedia.org/wiki/Modèle-vue-contrôleur) - vous avez une vue et un contrôleur embarqué dans l'ecran (ça reste hors du champs du processeur central) et un seul bouton (sauvegarde des préférences) sert à mettre à jour le modèle.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 16, 2018, 05:11 pm
je frimerais peut être quand tout sera opérationnel lol
Je vais donc continuer sur le principe que j'avais.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 17, 2018, 01:07 am
Avant de continuer a bosser sur le nextion il faut que je mette de l'ordre dans mon code global car c'est un bazars monstre !!!
Je l'avais mis de coté au moment ou je créait de .cpp et .h

j'ai deux chose qui m'interpelle.

Dans un premier temps, j'ai des erreurs a la compile dans le premiere .cpp qu'il croise et il me dit par exemple boolean not declared.
Apres avoir chercher sur le net il faudrait ajouter #include "arduino.h" dans le fichier cpp si j'ai bien compris
https://www.arduino.cc/en/Hacking/LibraryTutorial  (~vers 30% du document)
Une fois fait sa compile
Mais au fichier cpp suivant rebelote.
Se qui veut dire qu'il faut ajouter #include "arduino.h" a chaque fichier cpp ?

Ensuite malgré que mes pin soit déclaré dans le ino, il me dit :
'pinOUT_relais_distributeur_nouriture' was not declared in this scope
ya un truc a faire ou il faut également que je fasse
extern const byte pinOUT_relais_distributeur_nouriture;

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 17, 2018, 01:30 am
Quote
Se qui veut dire qu'il faut ajouter #include "arduino.h" a chaque fichier cpp ?
oui. arduino.h rajoute tous les mots clés liés au monde arduino

Quote
ya un truc a faire ou il faut également que je fasse
extern const byte pinOUT_relais_distributeur_nouriture;
oui idéalement les trucs globaux devraient être dans un .h que vous importez partout, déclarés en extern et définis dans le .ino par exemple (où là où ça fait du sens)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 17, 2018, 09:24 am
oui idéalement les trucs globaux devraient être dans un .h
c'est le cas pour tout les pins il sont dans un #include "pin.h" qui est appelé dans le ino juste apres les biblioteque.

que vous importez partout, déclarés en extern et définis dans le .ino par exemple (où là où ça fait du sens)
la je ne comprend pas.
"que vous importez partout" = #include "pin.h"
"déclarés en extern" ?
Une fois le #include "pin.h" importez dans le fichier.h ca compile car j'ai deja fait
Code: [Select]
extern unsigned long Time, H;
extern unsigned long temps_precedent_nourissage;
extern boolean tempete_ON;
extern int i;
extern float temp_bac_graph[24], temp_rampe_graph[24], ph_BAC_graph[24], ph_RAC_graph[24],temp_bac,temp_rampe,ph_BAC,ph_RAC;

C'est de ca que tu parlais en "extern" ? si oui, c'est OK
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 17, 2018, 12:46 pm
Oui si vous avez besoin de connaître le nom d'une variabke globale dans le fichier toto.cpp alors qu'elle est définie (définir = allouer la mémoire associée) dans le .ino alors l'idéal est d'avoir cette variable en extern dans un global.h et importer ce .h dans le .cpp

global.h
Code: [Select]
extern int v; // déclare que v est de type int, n'alloue pas de mémoire
extern int x; // déclare que x est de type int, n'alloue pas de mémoire


Projet.ino
Code: [Select]
#include "global.h"
int v = 1; // définit v (alloue la mémoire)
....
x = x * v; // le compilateur sait que x existe - ça sera résolu au link
....


Toto.cpp
Code: [Select]
#include "global.h"
int x = 8; // définit x (alloue la mémoire)
....
x = v-1; // le compilateur sait que v existe - ça sera résolu au link
....


Et rajoutez le petit bout de code en début du .h pour éviter d'importer 2 fois de suite le même .h (avec les #ifdef....)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 17, 2018, 01:48 pm
Arfff

j'ai fait l'inverse.
declaration dans global.h
et les extern dans les autre .cpp
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 17, 2018, 02:13 pm
:)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 17, 2018, 06:53 pm
:)
Ca veut dire que c'est pas grave ou je doit tout modifier ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 18, 2018, 03:36 am
Ca veut dire que c'est pas grave ou je doit tout modifier ?
Oui....(tout,modifier)

(i ne devrait sans doute pas être global)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 18, 2018, 03:36 am
Suis sur mon mobile pour quelques jours encore donc peut pas vérifier...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 08:32 am
sa tombe bien, j'ai pris deux jours pour me reposer la tête ... je vais faire ça lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 10:35 am
j'ai fait mon global.h
Code: [Select]
#include <SPI.h>
#include "RTClib.h"
#include "SdFat.h"
#include "WiFiEsp.h"
#include <Servo.h>
#include <DallasTemperature.h>
#include <OneWire.h>

/////////////////////////////////////// *** autres *** ///////////////////////////////////////
extern boolean graph_par_H;
extern unsigned long duree_nourissage_millis;
extern unsigned long heure_nourrissage1;
extern unsigned long heure_nourrissage2;
extern float consigne_ph_RAC;
extern float consigne_ph_BAC;
extern float ph_RAC, ph_BAC;
extern unsigned long temps_precedent_nourissage;
extern unsigned long temps_precedent_tempete;
extern const uint32_t verifeeprom;
extern uint32_t lectureverifeeprom;
extern boolean valider;

/////////////////////////////////////// *** brassage *** ///////////////////////////////////////
extern int pwm_jebao1, pwm_jebao2, pwm_jebao3;
extern int puissance_max_jebao1; //
extern int puissance_max_jebao2;
extern int puissance_max_jebao3;
extern int puissance_min_jebao1;
extern int puissance_min_jebao2;
extern int puissance_min_jebao3;

/////////////////////////////////////// *** eclairage *** ///////////////////////////////////////
extern int pwm_blanc1, pwm_blanc2, pwm_bleu1, pwm_bleu2;
extern int puissance_blanc;
extern int puissance_bleu;
extern unsigned long LEVER;
extern unsigned long COUCHER;
extern unsigned int progression;
extern unsigned long debut_LEVER_bleu1;
extern unsigned long debut_LEVER_bleu2;
extern unsigned long debut_LEVER_blanc1;
extern unsigned long debut_LEVER_blanc2;
// **************************************** fin lever
extern unsigned long fin_LEVER_bleu1;
extern unsigned long fin_LEVER_bleu2 ;
extern unsigned long fin_LEVER_blanc1;
extern unsigned long fin_LEVER_blanc2 ;
// **************************************** debut coucher
extern unsigned long debut_COUCHER_bleu2 ;
extern unsigned long debut_COUCHER_bleu1 ;
extern unsigned long debut_COUCHER_blanc2;
extern unsigned long debut_COUCHER_blanc1 ;
// **************************************** fin coucher
extern unsigned long fin_COUCHER_bleu2;
extern unsigned long fin_COUCHER_bleu1;
extern unsigned long fin_COUCHER_blanc2;
extern unsigned long fin_COUCHER_blanc1;

/////////////////////////////////////// *** temperature *** ///////////////////////////////////////
extern float temp_bac_graph[24], temp_rampe_graph[24], ph_BAC_graph[24], ph_RAC_graph[24];
extern float temp_bac, temp_rampe;
extern float temp_declenchement_vent_bac ; // temperature de declaenchement de la ventilation du bac
extern float temp_alerte_bac ; // temperature de declaenchement de la ventilation du bac
extern float temp_declenchement_vent_rampe;

/////////////////////////////////////// *** gsm *** ///////////////////////////////////////
extern boolean alerte;
const byte maxnumero2tel;
extern char numero2tel [];
extern const char * ATString;
extern const char * OKShortString;
extern const char * OKLongString;
const uint32_t oneSecond ;
extern const byte maxMessageSize;
extern char GSM_Message[];
extern char buffer[];
extern boolean envoyerSMS(const char * noDeTel, const char * messageAEnvoyer);

/////////////////////////////////////// *** horloge *** ///////////////////////////////////////
extern unsigned long Time, H;
extern unsigned int M, S;
extern unsigned long temps_precedent_nourissage, temps_precedent_tempete, temps_precedent_tempete_aleatoire;

/////////////////////////////////////// *** oscillo *** ///////////////////////////////////////
extern int oscillo1_angle1;
extern int oscillo1_angle2;
extern int oscillo2_angle1;
extern int oscillo2_angle2;
extern int oscillo3_angle1;
extern int oscillo3_angle2;
extern unsigned int delais_mouvement_oscillo_millis;
extern int position_oscillo1, position_oscillo2, position_oscillo3;
//extern Servo oscillo1, oscillo2, oscillo3;
extern boolean oscillo1_ON, oscillo2_ON, oscillo3_ON;

/////////////////////////////////////// *** tempete *** ///////////////////////////////////////

extern RTC_DS3231 rtc;
extern OneWire oneWire;
extern DallasTemperature sensors;
extern DeviceAddress sonde_bac, sonde_rampe;
extern boolean adresse_sonde_rampe, adresse_sonde_bac;
extern boolean tempete_ON;
extern unsigned long duree_tempete_millis;
extern int puissance_tempete;
extern unsigned long H_tempete_aleatoire;
extern unsigned long duree_tempete_aleatoire;

/////////////////////////////////////// *** sd *** ///////////////////////////////////////
extern SdFat SD;
extern void recup_para_sd();

/////////////////////////////////////// *** oscillo *** ///////////////////////////////////////
extern Servo oscillo1, oscillo2, oscillo3;
extern int position_oscillo1, position_oscillo2 , position_oscillo3;

/////////////////////////////////////// *** wifi *** ///////////////////////////////////////
extern boolean gsmPrintlnAndWaitATCommand(const char * command, const char * endMarker, unsigned long duration, boolean verbose);
const byte maxSsid, maxMdp;
extern char ssid[], mdp[];
extern int status;
extern void rebootwifi();
extern void printHTTPServerInfo();
const uint16_t HTTPPort;
extern WiFiEspServer server(HTTPPort);

/////////////////////////////////////// *** gestionweb *** ///////////////////////////////////////
extern const byte maxURL;
extern char urlRequest[];
extern const unsigned int maxLabelsOfInterest;
extern const char * labelsOfInterest[];
extern const byte maxHTTPLine;
extern char httpLine[];


j'avais des erreur de compil et j'ai perdu pas mal de temps sur les extern const byte ou uint32_t" mais j'ai trouvé la solution
il suffisait de ne pas mettre "extern" et de supprimer "= *"


par contre j'ai toujours une méga erreur concernant "serveur"
Code: [Select]
sketch\autres.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.9.2/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions

sketch\bassage.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

sketch\eclairage.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

sketch\gestionweb.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

sketch\osmolation.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

sketch\sd.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

sketch\temperature.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

sketch\tempete.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

sketch\wifi.cpp.o (symbol from plugin): In function `server':

(.text+0x0): multiple definition of `server'

sketch\AQUABOUNS_V2_gsm.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Erreur de compilation pour la carte Arduino/Genuino Mega or Mega 2560



Je pense que cela vient de la :
Code: [Select]
const uint16_t HTTPPort;
extern WiFiEspServer server(HTTPPort);


J'ai chercher mais rien trouvé sur le net pour solutionner

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 11:04 am
Suis sur mon mobile pour quelques jours encore donc peut pas vérifier...
j'avais pas vu :/
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 11:39 am
pour pouvoir avancer, j'ai mis dans le setup //server.begin();
comme sa je peut continuer

Je vais avancer sur le communication nextion / arduino
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 18, 2018, 12:06 pm
Votre .h devrait avoir cette structure
Code: [Select]
#ifndef GLOBAL_H_
#define GLOBAL_H_
....
#endif


extern WiFiEspServer server(HTTPPort);
Cette écriture fait plus que définir l'objet server, ça l'instancie (allocation de la mémoire et appel du constructeur)

Essayez juste extern WiFiEspServer server;

Et dans le bon fichier il faudra faire WiFiEspServer server(HTTPPort); pour allouer la mémoire
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 12:10 pm
(https://media.istockphoto.com/vectors/two-thumb-up-emoticon-for-you-design-vector-id464368183?k=6&m=464368183&s=612x612&w=0&h=Ao7Wfu2eeThQVfNMmuFhUIvES_DyuFcA2Tmay_2q3kw=)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 01:14 pm
Pour envoyer les info au nextion :

fonction de base pour envoyer :
Code: [Select]
n0.setValue(valeur);
n0 correspond au nom du destinataire dans le nextion
setvalue correspond a l'ordre d'envoier
(valeur) correspond a la valeur envoyer a n0
l'ecran affichera donc dans le chanps n0 (valeur)

J'ai donc voulu faire
Code: [Select]
void num_send_to_nextion(char *objname, float T) {
  unsigned int numtogo;
  numtogo = T * 10; // le nextion ne gere pas de float donc tout est *10
  (objname).setValue(numtogo);

pour que quand j'appelle :
Code: [Select]
num_send_to_nextion(n0, temp_bac) // temp bac = 26.6
cela envoie
n0.setValue(266);

Mais le compilateur me répond
Code: [Select]

sketch\nextion.cpp: In function 'void num_send_to_nextion(char*, float)':

nextion.cpp:46: error: request for member 'setValue' in 'objname', which is of non-class type 'char*'

   (objname).setValue(numtogo);

             ^

exit status 1
request for member 'setValue' in 'objname', which is of non-class type 'char*'


C'est les déclaration dans la bibliothèque nextion qui me bloque ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 18, 2018, 01:26 pm
Le nom d'un objet est un pointeur en mémoire vers l'objet pas son nom de variable ascii dans votre code... une fois compilé tous les noms disparaissent... donc pas faisable avec une chaîne de caractère comme on peut le faire dans certains langages interprétés

Soit chaque fonction parle spécifiquement à un objet, soit Il faut conserver par exemple un tableau de tous les objets nextion créés et les référencer par leur index dans le tableau
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 01:40 pm
ok ba tempi, je vais pas monter une usine a gaz ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 18, 2018, 02:15 pm
Vous pourriez faire une macro
Code: [Select]
#define SETx10VALUE(x) setValue((int)((x)*10))

Et au lieu d'appeler
Code: [Select]
n0.setValue(valeur);faire
Code: [Select]
n0.SETx10VALUE(valeur);et laisser le préprocesseur bosser pour vous
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 09:21 pm
J'ai tellement de variable a convertir de manière différent que cela ne vos même pas le coup de faire des fonctions.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 18, 2018, 11:46 pm
Ok
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 18, 2018, 11:49 pm
j'ai bien avancé aujourd'hui mais énormément de temps passer a résoudre les problèmes lié a avoir le code étalé dans plusieurs fichiers ...
A chaque ligne nouvellement écrit faut en ajouté partout ...
 :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 12:16 am
Je dirai (sans méchanceté) que c'est un signe d'un code mal « architecturé » - normalement on a des unités de code relativement indépendantes et il n'y a pas besoin de tout déclarer partout

Ce sera pour la prochaine version :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 12:19 am
Ce sera pour la prochaine version :)
https://www.youtube.com/watch?v=pbaXL7UwzQ4 (https://www.youtube.com/watch?v=pbaXL7UwzQ4)
 :o  :smiley-confuse:  :D  :D  :D
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 12:24 am
normalement on a des unités de code relativement indépendantes et il n'y a pas besoin de tout déclarer partout
Je n'ai tout de même pas tout a appeler partout mais comme il y a un fichier.cpp par catégorie (Eclairage, brassage, ect..) et que, par exemple, l'écran doit accéder (pour lire et modifier) a toutes ces catégorie ... donc  :smiley-confuse:  :smiley-confuse:  :smiley-confuse:

Il n'en reste pas moins qu'il y a surement une meilleur architecture a adopter

Je vais encore passer la mâtiné dessus et je donnerais un aperçu du rendu visuel + programme ( la première page de l'affichage commence a afficher et réagir :) je ressent vraiment que ça se concrétise )
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Jan 19, 2018, 09:06 am
Djbouns and J-M-L bonjour.

Je vous suis toujours quoique suivre n'est pas le mot approprié, je suis même perdu mais j'aime suivre le développement de cet automate.

Quel boulot accomplis.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 10:49 am
salut breisleach,
Merci
y en a encore a faire :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 10:53 am
depuis hier je fouille dans la biblioteque nextion pour comprendre et avancé mais y a un truc que je ne trouve pas et comprend pas
le "void*ptr"
Code: [Select]
void t0PopCallback(void *ptr)
{
    dbSerialPrintln("t0PopCallback");
    t0.setText("50");
}


Dans certain exemple fourni par nextion il y a dans le setup :
Code: [Select]
t0.attachPop(t0PopCallback, &t0);
 et dans d'autre
Code: [Select]
t0.attachPop(t0PopCallback);
Cela fonctionne dans les deux cas

J'ai aussi testé de faire
Code: [Select]
t0.setText("50");
en dehors de la fonction est ca fonctionne aussi

donc je ne comprend pas a quoi sert "void*ptr"
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 12:26 pm
À mon avis (c'est typique dans le design des IHM en MVC) la fonction callback (celle que vous attachez au bouton) prend en paramètre un pointeur sur l'objet clické. Si vous n'avez qu'un seul bouton ou un callback pour chaque bouton ça ne sert pas puisque dans la fonction vous savez quel bouton a été clické, mais si vous attachez le même callback à plusieurs éléments alors ça vous permet de savoir lequel a été clické. Le fait que le pointeur ne soit pas typé (utilisation de void * qui veut dire pointeur en mémoire sur n'importe quoi - ça pourrait être un NexButton * ou un NexText *c'est pour permettre d'avoir le même callback pour plusieurs types d'objets)

Il se peut aussi que ce soit pour passer un paramètre lors du callback, éventuellement si c'est configurable lors de la définition du callback

Pour vérifier Dans votre callback faites
Code: [Select]
void t0PopCallback(void *ptr)
{
    if (ptr == (void *) &t0) dbSerialPrintln("OK c'est bien ce que je pensais"); // on vérifie si le pointeur est bien t0
    dbSerialPrintln("t0PopCallback");
    t0.setText("50");
}
Quand vous clickez ça va vérifier que ptr pointe bien en mémoire sur t0

Et éventuellement tester aussi
Code: [Select]
int toto; // variable globale
...
t0.attachPop(t0PopCallback, (void *) &toto);
...

void t0PopCallback(void *ptr)
{
    if (ptr == (void *) &toto) dbSerialPrintln("OK j'ai bien toto en param"); // on vérifie si le pointeur est bien sur notre entier
    dbSerialPrintln("t0PopCallback");
    *((int*) ptr) = 50; // on met 50 dans toto
    t0.setText("50");
}

Si cette approche fonctionne alors ça vous permet de partager le même callback entre plusieurs champs texte par exemple mais chacun piloterait une variable différente en mémoire
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 12:51 pm
sa compile pas
Code: [Select]
invalid cast from type 'NexText' to type 'void*'

J'avais penser que c'etait le bouton que l'on attachait a la fonction mais je comprenait pas pourquoi si on ne l'indiquais pas sa fonctionnais quand meme.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 12:54 pm
Vous avez écrit ça comment?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 12:56 pm
Vous avez écrit ça comment?
Code: [Select]
void t4PopCallback(void *ptr){
if (ptr == (void *) t4){
  dbSerialPrintln("OK c'est bien ce que je pensais"); // on vérifie si le pointeur est bien t0
}
    dbSerialPrintln("t0PopCallback");
    t4.setText("50");
}

 :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 01:01 pm
Ah j'ai merdé évidemment il faut mettre l'adresse de l'objet (void *) &t4 dans le test (je suis sur mon tel donc peux pas tester)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 01:06 pm
Ah j'ai merdé
(https://i.pinimg.com/736x/51/d4/ef/51d4ef870146758ca24c3abe63cf9dc8--emoji-faces-smiley-faces.jpg)



Code: [Select]
OK c'est bien ce que je pensais
t0PopCallback

(http://img109.xooimage.com/files/6/d/9/best20smiley-4642d03.gif)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 01:07 pm
:)

Vous avez essayé avec toto?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 01:08 pm
Vous avez essayé avec toto?
?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 01:09 pm
Relisez le message de la page précédente j'étais en train de l'éditer quand vous faisiez le test
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 01:13 pm
sa marche pas avec toto
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 01:17 pm
Ok - dommage :(

Donc c'est juste le caller qui est passé en paramètre sans doute
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 01:52 pm
Ok - dommage :(
si tu le dit  :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 19, 2018, 03:48 pm
Code: [Select]
enum modeBrassage : byte {brassageArret, brassageActif, brassagePWM, retourBrassageArret};
modeBrassage brassage1_ON = brassagePWM, brassage2_ON = brassagePWM, brassage3_ON = brassagePWM;


Je n'arrive pas a declarer cette enum dans mon global en extern
j'ai besoinde
 brassageArret, brassageActif, brassagePWM, retourBrassageArret
et
brassage1_ON

Sur le net il dise que "enum" est un "int" mais j'ai
Code: [Select]
'brassageArret' redeclared as different kind of symbol
a la compil
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 19, 2018, 04:05 pm
Enum par défaut est un int sauf si vous lui préciser d'utiliser un byte...

enum modeBrassage : byte {brassageArret, brassageActif, ....

Mais à mon avis ça ne vient pas du type byte ou int.

dans cette déclaration modeBrassage est un type il faut donc que les variables qui vont prendre ces valeurs nommées soient de type  modeBrassage pas int ni byte



Un enum ne se déclare pas en externe, ce ne sont pas des valables donc vous mettez juste l'enum Dans le .h global
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 20, 2018, 12:45 am
(http://www.camping-vacaf.fr/wp-content/uploads/2015/07/Danse-des-pouces.gif)

Les ligne "enum" transféré dans global et "extern modeBrassage" egalement dans le global
Tout est Ok
Il est trop tard pour faire une vidéo de l'écran comme promis  :smiley-confuse: mais la page d'accueil est presque fini et fonctionnel (tout les bouton son rattacher dans l'arduino et son couplé a leur fonction et toute les variables son bien envoyer par l'arduino et reçu/affiché par l'écran)

Il faudra, quand tout le code sera fini avec l'écran, vraiment se pencher sur le loop car l'envoie/réception de donné avec l'écran prend un certain temps (~1/3 de seconde juste pour la MAJ des info température, éclairage, brassage ect ...) et les bouton de l'écran ne réagisse plus pendant se temps la ...

J'ai passer une bonne partie de ces deux jour a remettre de l'ordre dans le code.
Tout n'est pas fini, il manque encore des commentaire et de la mise en forme mais j'espère que ces compréhensible.

Je peut pas bosser sur le code se week end mais je garde un oeil sur le forum, a l'affût de vos commentaire.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 20, 2018, 11:01 am
Je suis en vadrouille donc prut pas voir le code. Vous devriez penser à faire un github :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 20, 2018, 11:00 pm
Je suis en vadrouille donc prut pas voir le code. Vous devriez penser à faire un github :)
c'est prevu, d'ailleurs sur la page info l'adresse est deja indiqué mais je le ferait quand le code seras ok.  Le code reste dispo avec mon message precedent et moi aussi jsui en vadrouille donc jboss pa dessu. Kan tu poura,  si yu peut mdire ske ten pense a+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Jan 23, 2018, 06:02 pm
Boun's.

Je n'y connais pas grand chose, bon je fais des nano pour les température et humidité plus quelques petits montage sur Tft, mais avoir vu d'autre prog un peu fouilli, je trouve le tien lisible et compréhensif même pour un néophyte que je suis.

Je viens de demander un devis pour un 550 litres surverse centrale ( mais vraiment central) je vais donc le réceptionner, le mettre à vieillir et voir si tu pourras m'aider à mettre ton prog en place, si tu es d'accord car développer ce que tu as faits me semble être un but que je ne saurais atteindre.

Au fait que des coraux mous il seras.

En attente de te lire et continuer à suivre cette belle aventure.

Bonne soirée à toi.

Pascal.

J-M-L bonsoir idem pour toi une bonne soirée.


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 23, 2018, 07:00 pm
je trouve le tien lisible et compréhensif même pour un néophyte que je suis.
Je trouvais mon code précédent compréhensif aussi mais la priorité est de faire les choses dans les règles.
J'espère avoir atteint se but.
J'attends la validation de l'expert ;) quand il pourras regarder
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 25, 2018, 10:32 am
Cc,

J'ai reussi a faire une focntion pour dessiner les courbes.
La dificulté etait dans le fait que le nextion dessin les courbe par pixel, on ne peut pas Ecrire un point au milieu par exemple.
Si le tableau fait 800 pixels de large alors il faut envoyer 400 pixels pour que la courbe arrive a la moitié du tableau ...
Il m'as fallu faire des calcules pour que tout tombe juste en ayant 48 valeur (pour la courbe 24h) ou 84 (pour la courbe 7 jours)
j'ai donc fait ca (pour celle de 24h)
Code: [Select]
void courbe_24h_T(int T_precedent, int T_suivant) { // dessine la courbe temperature sur 24h (boucle de 15 pixels, a lancer 48 fois pour graph complet ******************
  int val_courbe = T_precedent;
  int i = 0;
  DPRINTLN("envoie 15 pixels au graph temperature sur 24h");
  while (i < 15) { // boucle 15 fois
    val_courbe = val_courbe + ((T_suivant - T_precedent) / 15); // ajoute a la valeur precedent la diference entre les 2 mesures divisé en 15
    int pixel_courbe = map(val_courbe, 2400, 2800, 0, 157);
    s0.addValue(0, (pixel_courbe)); // envoie 1 pixels
    i++;


il suffit ensuite de lancer cette fonction 48 fois avec les températures relever entre 0h et 23h30

j'en arrive donc au stockage et récupérations des températures.
pour les utiliser il faut qu'elle soit en "int"
J'imaginais utiliser la carte SD mais cela signifie qu'il faudra lire les info TXT puis chercher dedans chaque donnée, l'extraire pour lancer la fonction et faire cela 48 fois ...
c'est l'usine a gaz ...

Y a une autre solution ?


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 27, 2018, 12:13 pm
Salut

posé à un endroit avec un mon mac connecté correctement à internet :)

J'ai jeté un oeil au code  quelques commentaires / critiques constructives:




appuyez sur ctrl-t dans chacun des fichiers pour qu'ils soent correctement indentés. Virez les lignes vides superflues.

Une convention de programmation est que les noms en majuscules soient plutôt réservés pour les constantes ou les éléments d'un enum (constants aussi) --> Je changerai donc le nom de vos fonctions globales pour suivre le camelCase par exemple ALERTE_TEMPERATURE() devient alerteTemperature() et idem pour tout le reste du code.. je sais c'est du boulot.... :)

tous les noms de vos NexVariable n0  n1 etc sont peu parlants.... si n4 est l'affichage % brassage 3 pourquoi ne pas appeler la variable brassage3PerCent ou nexionBrassage3PerCent ou nxBrassage3PerCent.. idem pour les p, b, t g et j et va0. la longueur d'un nom de variable est viré à la compilation donc ça ne prend pas plus de place et le code ensuite est plus lisible / compréhensible quand on y revient 1 an plus tard ou que quelqu'un se penche dessus.




ça je vous ai déjà dit que ce n'est pas une bonne pratique :)
Code: [Select]

void setup() {
#include "setup.h"
}


Un .h c'est un en-tête, on y déclare des variables importe d'autres header etc mais on ne s'en sert pas pour injecter du code. c'est pas beau, c'est pas fait pour cela. et surtout ici vous avez même des #include aussi que vous injectez donc au coeur d'une fonction... ça ne se fait pas du tout!! beurk :)

Si vous voulez que le code du setup soit ailleurs dans un autre fichier, créez un setup.h et un setup.cpp et dans le fichier setup.cpp définissez une fonction void customSetup(). Votre sketch lui va importer setup.h comme un header comme les autres dans lequel la déclaration de void customSetup(); sera effectuée et votre vrai setup sera alors
Code: [Select]

void setup() {
   customSetup();
}

mais je ne suis pas persuadé que ce soit utile, à mon avis vous pouvez mettre directement le code dans le setup()....




idem pour pageweb.h (et les autres codes HTML) et pour être efficace votre page web devrait n'a pas besoin d'être "jolie" en HTML, virez tous les blancs ou  \r\n (mettre juste un espace à la place) en trop et compactez tout ça (par exemple la variable zone_dessin pourrait s'appeler zd uou juste z et graphe pourrait être juste g... on n'écrit pas < / script > mais </script> idem pour < / body >

--> ça sert à rien de transmettre des octets qui ne servent à rien.




dans la loop() vous avez if (millis()-refresh > 10000) { --> le 10000 devrait être un const unsigned long ou un #define dans vos fichiers de param. il faut éviter d'avoir des nombres magiques qui trainent.

idem ailleurs dans le code, j'ai vu un if (temp_rampe > 65) { // variation du thermo temperature rampe --> 65 devrait être une constante déclarée quelque part et pas au milieu du code

quand vous faites un if (temp_bac * 10 > 280) { // variation thermo temperature aquarium autant écrire if (temp_bac  > 28) { et bien sûr le 28 devrait aussi être une constante déclarée (comme vous avez fait pour temp_alerte_bac_haut par exemple )




évitez de dupliquer les calculs
Code: [Select]
void refresh_nextion_ph() {// maj des mesure ph ******************************************************************************************************************
  if (int ph_BAC_nextion = (ph_BAC * 100) < 100) {
    n10.setValue(ph_BAC_nextion); // affiche le ph du bac
  }
  if (int ph_RAC_nextion = (ph_BAC * 100) < 100) {
    n11.setValue(ph_RAC * 100); // affiche le ph du rac
  }
}

--> dans ce code vous calculez 2 fois ph_BAC * 100 et vous créez 2 variables différentes BAC et RAC... il y a sans doute quelque chose de louche sur le second.. ça sent le bug




il y a un fichier qui porte mal son nom --> bassage.cpp manque un r

dans ce fichier il y a la valeur magique 2.55 qui revient hyper souvent.. il faudrait la définir.. et comme vous faites un map juste avant de définir l'analogWrite, vous pourriez même inclure le facteur d'échelle par 2.55 dans la fonction affine map()




const uint16_t HTTPPort = 80; devrait être dans gestionweb.h et pas dans le .cpp




avoir ça quand on fait un petit bout de code de démo c'est OK, mais pas dans un vrai programme en production.
Code: [Select]
void dieHere() {
  while (true);
}

il me semble que ce n'est pas appelé donc ce n'est pas grave, mais autant le virer




 DPRINT (" \" a été envoyer au : ");

--> a été envoyé :)

attention, pas sûr que les accents vont bien sortir..




dans horloge.cpp attention (même si ici ça ne déborde pas car H est déjà un unsigned long ) aux calculs faits en int au lieu de unsigned long

quand on a de grosses constantes il vaut mieux écrire H = (H * 3600ul); pour s'assurer qu'on force le calcul en unsigned long





Sinon c'est quand même déjà bcp mieux que la version 1, ça vaut presqu'un bon point de plus (car il y a des choses que je vous avais déjà dit à corriger :) )

(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=242864)





Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 29, 2018, 09:05 am
Bonjour jm,

content de te revoir, j'espère que ton absence de réseau est du au fait que tu est sous les tropic et non dans la creuse lol.

Je commence les cartons du déménagement donc sa va être compliqué d'etre sur le code les weekend (mais j'en profite le vendredi :) )
Je commence également a me dire que le système ne seras pas opérationnel a temps (pour être installer a la mise en eau du nouveau bac dans ma nouvelle maison), mais bon, ce n'est pas faute d'y passer le maximum de temps.

La partie graphique me prend énormément de temps et allonge le code de manière phénoménale ...
en pièce jointe le travail de cette semaine et ça ne représente que la page d'accueil ...


Je met cette partie en stand bye pour corriger tout se qui ne va pas.

je commence donc la lecture ... et mise en application  :D

appuyez sur ctrl-t dans chacun des fichiers pour qu'ils soent correctement indentés. Virez les lignes vides superflues.
fait  :smiley-cool:


Une convention de programmation est que les noms en majuscules soient plutôt réservés pour les constantes ou les éléments d'un enum (constants aussi) --> Je changerai donc le nom de vos fonctions globales pour suivre le camelCase par exemple ALERTE_TEMPERATURE() devient alerteTemperature() et idem pour tout le reste du code.. je sais c'est du boulot.... :)
Ok pour les majuscule.
Dans ton exemple tu a retirer les "_" , ils sont aussi a retirer?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 29, 2018, 09:28 am
On réserve souvent les _ pour des variables privées / cachées, ou les types genre uint8_t

Maintenant ce ne sont juste que des conventions donc rien d'obligatoire!

Bon courage pour le déménagement

(Dans les montagnes - pas dans les Iles)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 29, 2018, 09:56 am
merci

tous les noms de vos NexVariable n0  n1 etc sont peu parlants.... si n4 est l'affichage % brassage 3 pourquoi ne pas appeler la variable brassage3PerCent ou nexionBrassage3PerCent ou nxBrassage3PerCent.. idem pour les p, b, t g et j et va0. la longueur d'un nom de variable est viré à la compilation donc ça ne prend pas plus de place et le code ensuite est plus lisible / compréhensible quand on y revient 1 an plus tard ou que quelqu'un se penche dessus.
fait  8)



profite bien

(https://aminus3.s3.amazonaws.com/image/g0008/u00007768/i00773393/3a34e194b44522d578420e70d40a5a9a_large.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 29, 2018, 10:03 am
ce ne sont juste que des conventions donc rien d'obligatoire!
Je veut faire ca bien  ;)  donc c'est partie !  :smiley-roll-sweat:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 29, 2018, 06:32 pm
(https://www.aspentimes.com/wp-content/uploads/2017/03/untucked-atw-030917.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 29, 2018, 07:49 pm
 
(https://www.aspentimes.com/wp-content/uploads/2017/03/untucked-atw-030917.jpg)
On peut pas être doué en tout.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 30, 2018, 12:43 am
:)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 30, 2018, 09:09 am
vous pourriez même inclure le facteur d'échelle par 2.55 dans la fonction affine map()
Faire comme ça ?

Code: [Select]
float pourCentEnPwm = 2.55;
pwm_jebao1 = map(Time, debut_LEVER_bleu1, fin_LEVER_blanc2, (puissanceMinBrassage1*pourCentEnPwm), (puissanceMaxBrassage1*pourCentEnPwm));



Le problème en faisant ca c'est qu'ensuite je suis obliger de tout diviser par "pourCentEnPwm" pour pouvoir afficher sur l'écran en %.

Donc si je fait
Code: [Select]
analogWrite (pinOutBleu2, pwmBleu2 * pourCentEnPwm);

c'est bon ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jan 30, 2018, 09:12 pm
OK si c'est utilisé sans le facteur ailleurs alors ça revient plus ou moins au même - éventuellment prendre l'option qui fait l moins de calculs
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 30, 2018, 11:08 pm
OK si c'est utilisé sans le facteur ailleurs alors ça revient plus ou moins au même - éventuellment prendre l'option qui fait l moins de calculs
C'est bien celle ci donc ok merci
Je continu a tout mettre a jour
Effectivement c'est beaucoup de boulot.
C'est le deuxième jours ... :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 30, 2018, 11:33 pm
que penser vous de cette constatation fait en fin de semaine dernière :

J'ai modifier le Nextion pour communiquer avec lui en 115200 au lieu de 9600 par Default.
j'ai fait quelque test et je n'est vu aucune amélioration du temps de réponse ( j'ai envoyer une suite de paramètre dans l'écran qui retournait une valeur dans le serial moniteur)

Normal ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jan 31, 2018, 12:37 am
Une convention de programmation est que les noms en majuscules soient plutôt réservés pour les constantes ou les éléments d'un enum (constants aussi) --> Je changerai donc le nom de vos fonctions globales pour suivre le camelCase par exemple ALERTE_TEMPERATURE() devient alerteTemperature() et idem pour tout le reste du code.. je sais c'est du boulot.... :)
fait

C'était long ...  :smiley-sweat:  :smiley-sweat:  :smiley-sweat:
J'en est profité pour modifier certain nom afin que se soit plus claire
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 01, 2018, 11:26 pm
évitez de dupliquer les calculs
Code: [Select]
void refresh_nextion_ph() {// maj des mesure ph ******************************************************************************************************************
  if (int ph_BAC_nextion = (ph_BAC * 100) < 100) {
    n10.setValue(ph_BAC_nextion); // affiche le ph du bac
  }
  if (int ph_RAC_nextion = (ph_BAC * 100) < 100) {
    n11.setValue(ph_RAC * 100); // affiche le ph du rac
  }
}

--> dans ce code vous calculez 2 fois ph_BAC * 100 et vous créez 2 variables différentes BAC et RAC... il y a sans doute quelque chose de louche sur le second.. ça sent le bug
y voit tout ...

c'est rectifié
Code: [Select]
// ******************************************************************************************************************************************************************
void rafraichirPhBacNextion() {// maj des mesure ph *********************************************************************************************************************
  if (changementPhBac != (phBac * deuxDecimalEnEntier)) {
    changementPhBac = (phBac * deuxDecimalEnEntier);
    if (changementPhBac > 999) {
      changementPhBac = 0;
    }
    affichagephbac.setValue(changementPhBac); // affiche le ph du bac
    DPRINTLN("refresh ph bac");
  }
}
void rafraichirPhRacNextion() {// maj des mesure ph *********************************************************************************************************************
  if (changementPhRac != (phRac * deuxDecimalEnEntier)) {
    changementPhRac = (phRac * deuxDecimalEnEntier);
    if (changementPhRac > 999) {
      changementPhRac = 0;
    }
    affichagephrac.setValue(changementPhRac); // affiche le ph du rac
    DPRINTLN("refresh ph rac");
  }
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 01, 2018, 11:37 pm



const uint16_t HTTPPort = 80; devrait être dans gestionweb.h et pas dans le .cpp



Donc toute les variable utilisé uniquement dans un *.cpp doivent être mis dans le*.h du même nom ?
Si c'est bien ça, j' n'ai pas que celle la a déplacer ...


Pour rester sujet "déclaration", pour optimiser le code il faut que je fasse le maximum de déclaration a intérieur d'une fonction (a condition que la valeur de celle ci ne soit pas nécessaire en dehors de la fonction ou elle est déclaré) ?
Si oui, j'ai encore un coup de balais a passer lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 03, 2018, 03:14 pm
Non pas obligatoirement mais faut garder une cohérence pour le .h

Oui si on n'a besoin d'une variable que dans une seule fonction pas la peine de la mettre globale

Allez pour le boulot fourni :)

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 03, 2018, 09:03 pm
Non pas obligatoirement mais faut garder une cohérence pour le .h
Je ne comprend pas de quelle cohérence tu parle avec l'exemple "const uint16_t HTTPPort = 80; devrait être dans gestionweb.h et pas dans le .cpp"


Oui si on n'a besoin d'une variable que dans une seule fonction pas la peine de la mettre globale

Allez pour le boulot fourni :)

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)
YESsss

Sa fait 3 :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 03, 2018, 11:48 pm
Comme vous avez mis le reste dans le .h, le port pourrait y être aussi - par cohérence. si ça ne sert à personne d'autre alors on peut aussi tout garder dans le .cpp

L'idée du .h c'est pour partager
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 05, 2018, 10:26 am
Ok, faudras que je regarde tout alors.

Pour info, j'ai passer le week end sur un probleme :
la gestion des heures parametrable dans le nextion.
> quand l'heure était en 2 decimal dans le nextion (heure et minute) il n'est pas capable d'ecrire "00" en minute , il ecrit "0"
Il a donc falu trouver une solution ...
J'ai finni par afficher l'heure en texte (les minutes seulement), le nextion convertie le texte en decimal, fait la modif + ou - et convertit decimal en texte.
Il faut ensuite que l'arduino récupère le texte quand on sauvegarde, le transforme en decimal pour fait le calcul pour l'avoir en seconde


Code: [Select]
memset(minuteEnTexteIn, 0, sizeof(minuteEnTexteIn));
  valeurleverSoleilh.getValue(&numberh);// recupere la valeur dans nextion
  valeurleverSoleilm.getText(minuteEnTexteIn, sizeof(minuteEnTexteIn)); // recupere la valeur dans nextion
  DPRINTLN(minuteEnTexteIn);
  horraireEnSeconde(numberh, minuteEnTexteIn); // calcule h*3600+m*60
  leverSoleil = recupHorraireTemporraire;// attribut la valeur nextion dans l'arduino
  EEPROM.put(saveleverSoleil, leverSoleil);// sauvegarde dans l'eeprom la valeur

void horraireEnSeconde(unsigned long h, char m [sizeof(minuteEnTexteIn)]) {
  DPRINTLN("*********************** fonction horraireEnSeconde *************************");
  int M = atoi(m);
  recupHorraireTemporraire = ((h * 3600ul) + (M * 60));
}


Et inversement quand on charge la page pour afficher le paramétrage actuel :
Code: [Select]

secondeEnHorraire(leverSoleil) ;
  valeurleverSoleilh.setValue(numberh);
  valeurleverSoleilm.setText(minuteEnTexteOut);


void secondeEnHorraire(unsigned long t) {
  unsigned long h, m;
  h = t / 3600u;
  m = (t / 60) % 60;
  numberh = h;

  if (m == 0) {
    minuteEnTexteOut[0] = '0';
    minuteEnTexteOut[1] = '0';
    minuteEnTexteOut[2] = '\0';

  }
  else if (m == 5) {
    minuteEnTexteOut[0] = '0';
    minuteEnTexteOut[1] = '5';
    minuteEnTexteOut[2] = '\0';
  }
  else {
    itoa (m, minuteEnTexteOut, 10);
  }
}



Ça fonctionne
j'ai eu l'impression d'avoir un beug a un moment mais pas sur et après plusieurs essai répéter je n'ai rien vu d'anormal.

c'était compliqué...





Dans les exemple nextion les "char" sont declarer comme ca :
Code: [Select]
char exemple [10]= {0};


a quoi sert  "= {0}" ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 05, 2018, 01:04 pm
Quote
a quoi sert  "= {0}" ?
À initialiser le tableau à 0
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 05, 2018, 03:37 pm
Les deux fonctions avec les "numérique" <<<>>> char te semble correcte sinon ?
(j'ai encore du mal avec les "char", peut être subsiste une petite erreur génératrice de bug )
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Feb 07, 2018, 01:36 pm
Bouns bonjour.

Trois joli bon point ou faut-il aussi compter celui sans le coin haut droit ?????

En tout cas tu abat un boulot de fou et en attendant le final haut en couleurs c'est sur, j'applaudi d'avance.

J'ai passer commande d'un bac en 180 x60 x60 et aurais besoin de tes lumières pour la décantes mais c'est hors sujet ici.

J-M-L bonjour.

Allez zou bonne journée à vous deux.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 07, 2018, 08:39 pm
Salut  Pascal,

Merci  ;)

on peut parler de ton bac sur recifal france ou envoie moi un MP

a+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 07, 2018, 08:41 pm
Pour info :
Code: [Select]
Le croquis utilise 53254 octets (20%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 6703 octets (81%) de mémoire dynamique, ce qui laisse 1489 octets pour les variables locales. Le maximum est de 8192 octets.

La mémoire disponible faible, des problèmes de stabilité pourraient survenir.


Le code commence a être très long :) :) :)
quand je retire les serial.print sa redescend a 60%
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 07, 2018, 10:58 pm
J'ai vraiment un problème avec des "const byte" utilisé a plusieurs endroit.(utilisé pour délimité l'écriture d'un "char")
Des que je l'ai mes en extern sur le global.h j'ai une erreur de compil.
Ça fait 2h que je navigue sur le net mais je trouve rien  :smiley-confuse:

comment faire ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Feb 07, 2018, 11:33 pm
Si c'est un truc comme
Code: [Select]
  const byte toto = 12;, toto n'est pas une variable globale. C'est une constante qui disparaît à la compilation.

Le compilateur remplace toto par 12 partout dans le code.

Et tu obtiens exactement le même code compilé que si tu avais mis
Code: [Select]
#define toto 12

Donc pas étonnant que le compilo râle si tu essayes de la déclarer en extern.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 07, 2018, 11:35 pm
content de te revoir bricoleau.

Mais comment faire pour pouvoir utiliser ces constantes dans different *.ccp ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Feb 08, 2018, 01:06 pm
Ben tu le mets dans un fichier header .h

Cela ne devrait pas poser de problème particulier.

Et bien sûr, afin d'éviter tout problème d'inclusions multiples d'un même header dans divers cpp compilés ensemble, le contenu d'un .h doit toujours être de la forme :
Code: [Select]
#ifndef monfichierheader_h
#define monfichierheader_h
...
(contenu utile du header)
...
#endif


Ainsi, quand le compilateur rassemble tous les bouts de code en un seul :
- le premier #include "monfichier.h" va importer le contenu utile du header
- les #include suivants ne vont rien importer car monfichierheader_h aura déjà été défini, donc on n'entre pas dans la clause ifndef

C'est la mécanique standard pour éviter les doublons d'inclusion.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 09, 2018, 12:32 am
arfff, on en revient a se que l'on disait il y a quelque message avec jean marc sur les déclarations a mettre dans le .h
mais du coup j'ai une erreur a la compile
Code: [Select]
'byte' does not name a type

faut ajouter #include "arduino.h" dans chaque .h, c'est normal ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 09, 2018, 04:24 am
Byte est spécifique au monde arduino. Le type à utiliser est uint8_t
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 09, 2018, 08:41 am
Byte est spécifique au monde arduino. Le type à utiliser est uint8_t
ca me donne la meme chose une fois dans le header
Code: [Select]
'uint8_t' does not name a type
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 09, 2018, 09:42 am
Il nya pas un bug avant ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 09, 2018, 10:19 am
le message global
Code: [Select]
In file included from sketch\wifi.cpp:1:0:

wifi.h:3: error: 'uint8_t' does not name a type

 const uint8_t maxSsid = 30;// prévoir la bonne longueur

       ^

wifi.h:4: error: 'uint8_t' does not name a type

 const uint8_t maxMdp = 30;// prévoir la bonne longueur

       ^

wifi.h:5: error: 'uint8_t' does not name a type

 const uint8_t maxURL = 40;

       ^

wifi.cpp:12: error: 'maxURL' was not declared in this scope

 char urlRequest[maxURL + 1]; // +1 pour avoir la place du '\0'

                 ^

wifi.cpp:13: error: 'maxSsid' was not declared in this scope

 char ssid[maxSsid + 1];

           ^

wifi.cpp:14: error: 'maxMdp' was not declared in this scope

 char mdp[maxMdp + 1];

          ^

Plusieurs bibliothèque trouvées pour "DallasTemperature.h"
Utilisé : C:\Users\djbouns\Documents\Arduino\libraries\DallasTemperature
Non utilisé : C:\Program Files (x86)\Arduino\libraries\DallasTemperature
exit status 1
'uint8_t' does not name a type


les erreur precedente me semble nomale puisque "uint8_t" n'est pas connu, le nom de la constante est non déclaré dans le .cpp
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: icare on Feb 09, 2018, 11:16 am
Bonjour,
Met
Code: [Select]
#include <Arduino.h>
dans ton fichier .h
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 09, 2018, 06:19 pm
Bonjour,
Met
Code: [Select]
#include <Arduino.h>
dans ton fichier .h
bONJOUR ICARE,
j'avais remarquer que cela fonctionnait en faisant cela mais ca veut dire qu'il faut le mettre dans chaque header ? apres chaque #define monfichierheader_h pour qu'il ne soit pas charger plusieurs fois ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 09, 2018, 07:40 pm
il n'y a pas de raisons que ça ne fonctionne pas mais  il faut respecter les règles C / C++

sketch principal:
Code: [Select]
#include "glob.h"

void setup() {
  Serial.begin(115200);
  Serial.println(toto);
}

void loop() {}


Header: glob.h
Code: [Select]
#ifndef glob_h
#define glob_h
#include <stdint.h> // http://www.cplusplus.com/reference/cstdint/
extern const uint8_t toto;
#endif


Implémentation: glob.cpp
Code: [Select]
#include "glob.h"
const uint8_t toto = 10;


ça devrait compiler sans warnings et imprimer 10 dans la console.




Quote
j'avais remarquer que cela fonctionnait en faisant cela mais ca veut dire qu'il faut le mettre dans chaque header ? apres chaque #define monfichierheader_h pour qu'il ne soit pas charger plusieurs fois ?
le fichier Arduino.h (https://github.com/arduino/Arduino/blob/3d3bb385ad7575596b07ca20bf55d50a0166a215/hardware/arduino/avr/cores/arduino/Arduino.h#L20-L21) commence lui aussi par
Code: [Select]
#ifndef Arduino_h
#define Arduino_h
donc ne sera pas inclus deux fois quel que soit l'endroit où vous faites l'import



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 10, 2018, 12:11 am
effectivement, en ajoutant #include <stdint.h> dans mon header sa compil sans problème.
J'ai bien la valeur de ma constante  dans le moniteur.
Donc c'est ok :) :) :)

une dernière précision svp,
bricoleau  me disait de déclarer ces constantes dans mon header. (les extern son dans global.h)
jml, dans l'exemple ci dessus, a mis la declaration dans le .cpp et les extern dans le header du .cpp du même nom.
La quelle des deux dois je appliquer ?

mais  il faut respecter les règles C / C++
difficile sans formation :)
D'ailleurs vous pouvez peut être m'aider, j'ai déjà été a deux reprise voir dans des magasin pour trouver un bouquin simple et complet sur l'arduino/c++
a première vu sa ma paru très "pauvre" >>> exemple, l'arduino pour les nul
Ou alors c'était niveau bac ++
Une suggestion sur un ouvrage qui pourrait m'apprendre toute les "réglés" de base sans être nian nian ou hard ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Feb 10, 2018, 07:52 pm
Header: glob.h
Code: [Select]
#ifndef glob_h
#define glob_h
#include <stdint.h> // http://www.cplusplus.com/reference/cstdint/
extern const uint8_t toto;
#endif


Implémentation: glob.cpp
Code: [Select]
#include "glob.h"
const uint8_t toto = 10;

Euh...

Peut-être que coder ainsi est nécessaire avec d'autres compilos que celui de notre IDE Arduino, à moins que ce ne soit une intransigeance des ayatollahs de la syntaxe...  :)

Mais je maintiens : dans le cas d'une constante simple, c'est-à-dire pas un tableau, il n'est pas nécessaire de s'embêter ainsi.

toto n'est pas une variable globale pour laquelle un espace ram est réservé, contenant une valeur fixe, qui justifierait l'emploi du mot clé "extern", ainsi que sa définition dans un fichier cpp.

La pré-compil remplace partout toto par sa valeur littérale.
Le code compilé résultant est le même que si on avait mis un #define toto 10, sauf qu'au passage le compilo a pu contrôler que le type de toto est bien conforme à son usage.

Mettre directement la valeur dans un header ne pose aucun souci avec l'IDE arduino

header constantes.h
Code: [Select]
#ifndef constantes_h
#define constantes_h
#include <arduino.h>

const uint8_t toto = 10;

#endif


et pas besoin d'un fichier cpp associé

Me gourre-je ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 10, 2018, 08:22 pm
@bricoleau --> Mon point était juste de montrer que ça fonctionnait aussi avec des constantes et que l'endroit de définition n'était pas obligatoirement l'endroit de déclaration. ça fonctionne comme le reste, const ou pas const. L'important est que la définition (allocation de la mémoire correspondante) ne doit se faire qu'une seule fois.

Quote
toto n'est pas une variable globale pour laquelle un espace ram est réservé, contenant une valeur fixe, qui justifierait l'emploi du mot clé "extern", ainsi que sa définition dans un fichier cpp.

La pré-compil remplace partout toto par sa valeur littérale.
Le code compilé résultant est le même que si on avait mis un #define toto 10, sauf qu'au passage le compilo a pu contrôler que le type de toto est bien conforme à son usage.
Si si  toto est bien une variable globale avec un espace ram réservé, contenant une valeur fixe. Suivant les architectures cette variable peut-être placée en mémoire en lecture seule par exemple (OS avec des pages protégées par exemple).

Le remplacement d'une constante par sa valeur littérale est un effet d'optimisation du compilateur et non pas du pré-processeur et donc c'est différent d'un #define (même si pour un entier c'est ce que le compilateur va générer). 

Personnellement je déconseille les #define (sauf directives de compilation optionnelle comme dans les fichiers .h) et préfère une bonne définition de const. Le mot clé const à l'origine a été pensé pour vérifier la justesse sémantique du code et ensuite seulement utilisé pour des optimisations  -->  en utilisant un type donné pour le const GCC peut effectuer toutes les vérifications d'usage et vous n'aurez pas d'effets de bords potentiellement liés à une promotion indue.

de même j'utilise des enum plutôt que des define si j'ai plusieurs valeurs

enfin les const peuvent avoir un scope précis que les #define ne permettent pas
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 10, 2018, 08:58 pm
(https://s00.yaplakal.com/pics/pics_original/2/6/9/3918962.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Feb 11, 2018, 12:36 am
Bon bon d'accord

C'est le compilateur avec les paramètres de l'IDE Arduino qui optimise.

N'empêche que j'ai quand même un peu de mal à mettre mes const en extern dans un cpp, vu que cela ne change strictement rien dans l'exécutable televerse dans l'arduino, ni dans leur portée, ni dans les contrôles de typage à la compilation.

À moins d'avoir un bout de code multi plateforme écrit pour la postérité, non exclusivement destiné à Arduino, la nécessité ne me saute pas franchement aux yeux :P
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 11, 2018, 03:31 am
Ça dépend du type de const - c'est vrai pour des petits types genre octets ou 16 bits sur un Arduino traditionnel
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 11, 2018, 09:03 am

donc c'est bon si je laisse comme ça :

gsm.h
Code: [Select]
#ifndef  _gsm_h_
#define _gsm_h_
#include <stdint.h> // http://www.cplusplus.com/reference/cstdint/
const uint8_t maxnumero2tel = 15;
#endif


global.h
Code: [Select]
#ifndef global_h_
#define global_h_
extern const uint8_t maxnumero2tel;
#endif


affichage.cpp
Code: [Select]
#include "global.h"

*****
  strncpy(numero2tel, bufferTexte, maxnumero2tel);
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 11, 2018, 11:33 am
Pourquoi deux .h ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 11, 2018, 12:58 pm
Pourquoi deux .h ?
eux ...
Il y a mon global.h qui contient toute mes variables en "extern" qui est appeler dans tout les .cpp nécessaire.
et il y a toute les "famile", gsm, wifi, affichage, etc qui on 1 header et 1 cpp.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 11, 2018, 02:47 pm
OK

oui
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 11, 2018, 04:16 pm
ouf lol

J'ai peut de temps en se moment entre le taf (interdiction de circuler), mon déménagement qui approche (les carton et le déménagement de l'aqua) mais je bidouille quand même un peu.
La page de paramétrage est Ok donc les 2 plus grosse page (menu + paramètre)
J'ai jouté 2 pages, une pour modifier l'heure de l'horloge et 1 pour tout le paramétrage du brassage + oscillo)
donc sa avance doucement.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 11, 2018, 04:16 pm
D'ailleurs vous pouvez peut être m'aider, j'ai déjà été a deux reprise voir dans des magasin pour trouver un bouquin simple et complet sur l'arduino/c++
a première vu sa ma paru très "pauvre" >>> exemple, l'arduino pour les nul
Ou alors c'était niveau bac ++
Une suggestion sur un ouvrage qui pourrait m'apprendre toute les "réglés" de base sans être nian nian ou hard ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Feb 11, 2018, 04:31 pm
Bouns bonjour.

Je te rejoint en ce qui concerne les livres traitant de l'arduino et de la programmation, ne lisant pas l'anglais couramment surtout en termes techniques le choix en langue de notre beau pays est des plus restreint, pour la compréhension des écrits.

Sinon réfection faite, tu as raison mon idée de décante en plein milieu du bac bof, je voulais au départ faire deux univers bien distinct.

Courage pour toutes les aventures bénéfiques qui arrivent dans ta vie.

Pascal.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 11, 2018, 10:23 pm
J'ai un probleme avec la sauvegarde dans l'eeprom
J'ai chercher a automatisé l'adresse de sauvegarde.
Apres qelque recherche j'ai fait
Code: [Select]

uint16_t adresse = 0;
const uint8_t savepuissanceMaxBrassage1 = adresse;
adresse += sizeof(puissanceMaxBrassage1);
const uint8_t savepuissanceMaxBrassage2 = adresse;
adresse += sizeof(puissanceMaxBrassage2);
const uint8_t savepuissanceMaxBrassage3 = adresse;
adresse += sizeof(puissanceMaxBrassage3);
const uint8_t saveaccalemieNocturne = adresse;
adresse += sizeof(accalmieNocturne);
const uint8_t saveleverSoleil = adresse;
adresse += sizeof(leverSoleil);
const uint8_t savecoucherSoleil = adresse;
adresse += sizeof(coucherSoleil);
const uint8_t savedureelevercoucher = adresse;
adresse += sizeof(dureelevercoucher);
const uint8_t savealertetemperaturebasse = adresse;
adresse += sizeof(alertetemperaturebasse);
const uint8_t savealertetemperaturehaute = adresse;
adresse += sizeof(alertetemperaturehaute);
const uint8_t saveventilationaquarium = adresse;
adresse += sizeof(ventilationaquarium);
const uint8_t saveventilationrampe = adresse;
adresse += sizeof(ventilationrampe);
const uint8_t saveheureNourrissage1 = adresse;
adresse += sizeof(heureNourrissage1);
const uint8_t saveheureNourrissage2 = adresse;
adresse += sizeof(heureNourrissage2);
const uint8_t savedureeNourissageMillis = adresse;
adresse += sizeof(dureeNourissageMillis);
const uint8_t saveconsignePhRac = adresse;
adresse += sizeof(consignePhRac);
const uint8_t savealertephbacbas = adresse;
adresse += sizeof(alertephbacbas);
const uint8_t savealertephbachaut = adresse;
adresse += sizeof(alertephbachaut);
const uint8_t savepuissanceMaxBlanc = adresse;
adresse += sizeof(puissanceMaxBlanc);
const uint8_t savepuissanceMaxBleu = adresse;
adresse += sizeof(puissanceMaxBleu);
const uint8_t saveoscillo1Angle1 = adresse;
adresse += sizeof(oscillo1Angle1);
const uint8_t saveoscillo2Angle1 = adresse;
adresse += sizeof(oscillo2Angle1);
const uint8_t saveoscillo3Angle1 = adresse;
adresse += sizeof(oscillo3Angle1);
const uint8_t saveoscillo1Angle2 = adresse;
adresse += sizeof(oscillo1Angle2);
const uint8_t saveoscillo2Angle2 = adresse;
adresse += sizeof(oscillo2Angle2);
const uint8_t saveoscillo3Angle2 = adresse;
adresse += sizeof(oscillo3Angle2);
const uint8_t savessid = adresse;

qui est mis au debut du setup

puis j'ai une fonction
Code: [Select]
void enregistrerBrassage() {
  DPRINTLN("******************************************************************************************************");
  DPRINTLN("*************************************** sauvegarde brassage ******************************************");
  DPRINTLN("******************************************************************************************************");   
  valeurbrassage1.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage1 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(savepuissanceMaxBrassage1, puissanceMaxBrassage1); // sauvegarde dans l'eeprom la valeur
  valeurbrassage2.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage2 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(savepuissanceMaxBrassage2, puissanceMaxBrassage2); // sauvegarde dans l'eeprom la valeur
  valeurbrassage3.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage3 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(savepuissanceMaxBrassage3, puissanceMaxBrassage3); // sauvegarde dans l'eeprom la valeur
  valeuroscillo1min.getValue(&number); // recupere la valeur dans nextion
  oscillo1Angle1 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(saveoscillo1Angle1, oscillo1Angle1); // sauvegarde dans l'eeprom la valeur
  valeuroscillo2min.getValue(&number); // recupere la valeur dans nextion
  oscillo2Angle1 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(saveoscillo2Angle1, oscillo2Angle1); // sauvegarde dans l'eeprom la valeur
  valeuroscillo3min.getValue(&number); // recupere la valeur dans nextion
  oscillo3Angle1 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(saveoscillo3Angle1, oscillo3Angle1); // sauvegarde dans l'eeprom la valeur
  valeuroscillo1max.getValue(&number); // recupere la valeur dans nextion
  oscillo1Angle2 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(saveoscillo1Angle2, oscillo1Angle2); // sauvegarde dans l'eeprom la valeur
  valeuroscillo2max.getValue(&number); // recupere la valeur dans nextion
  oscillo2Angle2 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(saveoscillo2Angle2, oscillo2Angle2); // sauvegarde dans l'eeprom la valeur
  valeuroscillo3max.getValue(&number); // recupere la valeur dans nextion
  oscillo3Angle2 = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(saveoscillo3Angle2, oscillo3Angle2); // sauvegarde dans l'eeprom la valeur
  valeurdureetempette.getValue(&number); // recupere la valeur dans nextion
  dureeTempeteMillis = (number * minuteEnMillis); // attribut la valeur nextion dans l'arduino
  EEPROM.put(savedureeTempeteMillis, dureeTempeteMillis); // sauvegarde dans l'eeprom la valeur
  valeurtempette.getValue(&number); // recupere la valeur dans nextion
  puissanceTempete = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(savepuissanceTempete, puissanceTempete); // sauvegarde dans l'eeprom la valeur
  valeurmouvementoscillo.getValue(&number); // recupere la valeur dans nextion
  delaisMouvementOscilloMillis = (number * secondeEnMillis); // attribut la valeur nextion dans l'arduino
  EEPROM.put(savedelaisMouvementOscilloMillis, delaisMouvementOscilloMillis); // sauvegarde dans l'eeprom la valeur
  valeuraccalemienocturne.getValue(&number); // recupere la valeur dans nextion
  accalmieNocturne = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(saveaccalmieNocturne, accalmieNocturne); // sauvegarde dans l'eeprom la valeur

qui est dans un *cpp avec d'autre fonction exactement identique a celle ci (pour page parametre, wifi ...)

J'au une erreur de compile que je n'arrive pas a comprendre
Code: [Select]
C:\Users\djbouns\AppData\Local\Temp\ccZqpNL8.ltrans8.ltrans.o: In function `EERef::update(unsigned char)':

ccZqpNL8.ltrans8.o:(.text+0xb74): undefined reference to `savepuissanceMaxBrassage1'

ccZqpNL8.ltrans8.o:(.text+0xb92): undefined reference to `savepuissanceMaxBrassage2'

C:\Users\djbouns\AppData\Local\Temp\ccZqpNL8.ltrans8.ltrans.o: In function `enregistrerBrassage()':

ccZqpNL8.ltrans8.o:(.text+0xbb0): undefined reference to `savepuissanceMaxBrassage3'

ccZqpNL8.ltrans8.o:(.text+0xbce): undefined reference to `saveoscillo1Angle1'

ccZqpNL8.ltrans8.o:(.text+0xbec): undefined reference to `saveoscillo2Angle1'

ccZqpNL8.ltrans8.o:(.text+0xc0a): undefined reference to `saveoscillo3Angle1'

ccZqpNL8.ltrans8.o:(.text+0xc28): undefined reference to `saveoscillo1Angle2'

ccZqpNL8.ltrans8.o:(.text+0xc46): undefined reference to `saveoscillo2Angle2'

ccZqpNL8.ltrans8.o:(.text+0xc64): undefined reference to `saveoscillo3Angle2'

ccZqpNL8.ltrans8.o:(.text+0xca2): undefined reference to `savedureeTempeteMillis'

ccZqpNL8.ltrans8.o:(.text+0xce4): undefined reference to `savepuissanceTempete'

ccZqpNL8.ltrans8.o:(.text+0xd1c): undefined reference to `savedelaisMouvementOscilloMillis'

ccZqpNL8.ltrans8.o:(.text+0xd4e): undefined reference to `saveaccalmieNocturne'


C'est pas claire en plus  :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 12, 2018, 03:21 am
Attention - toutes les adresses de vos saveXXX ne doivent pas être des uint8_t mais des uint16_t


Quote
qui est mis au debut du setup
Vous voulez dire que vos saveXXX ce ne sont pas des constantes globales? Si c'est DANS le code de setup() alors la portée de ces variables est limitée au setup, elles sont inconnues en dehors de la fonction. Ce devrait être des constantes globales (idéalement cette partie de variables de configuration devrait être directement dans une structure que vous écrivez ou lisez d'un coup depuis l'EEPROM - c'est bcp plus simple à gérer (cf quelque part dans notre longue discussion je vous avais montré comment faire avec le mot clé genre 0xDEADBEEF ou 0xBADCAFFE  pour voir si l'EEPROM avait déjà été initialisée)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 12, 2018, 08:39 am
Attention - toutes les adresses de vos saveXXX ne doivent pas être des uint8_t mais des uint16_t
partant de zero, la liste de "save" doit actuellement arriver a ~100 d'ou le fait que j'ai mis uint8_t tout en sachant qu'il faudrait passer en uint16_t sur les save d'après.
tu remarqueras que j'ai bien mis uint16_t adresse = 0;
Apres je supose que c'est pour "harmoniser" qu'il faut pas faire comme j'ai fait ?


Vous voulez dire que vos saveXXX ce ne sont pas des constantes globales? Si c'est DANS le code de setup() alors la portée de ces variables est limitée au setup, elles sont inconnues en dehors de la fonction.
Je n'avait pas reflechit que setup() fonctionnait comme void mafonction().

Les save* était dans le setup au moment de mon message.
Initialement je les avait mis dans mon autres.cpp dans le "rubrique" eeprom et j'avais une erreur, qui m'etait tout aussi incomprehensible puisque je declare bien adresse et il me dit  'adresse' does not name a type
Code: [Select]
autres.cpp:107: error: 'adresse' does not name a type
 adresse += sizeof(puissanceMaxBrassage1);

 ^

autres.cpp:109: error: 'adresse' does not name a type

 adresse += sizeof(puissanceMaxBrassage2);

 ^

autres.cpp:111: error: 'adresse' does not name a type

 adresse += sizeof(puissanceMaxBrassage3);

 ^

autres.cpp:113: error: 'adresse' does not name a type

 adresse += sizeof(accalmieNocturne);

 ^

autres.cpp:115: error: 'adresse' does not name a type

 adresse += sizeof(leverSoleil);

 ^

autres.cpp:117: error: 'adresse' does not name a type

 adresse += sizeof(coucherSoleil);

 ^

autres.cpp:119: error: 'adresse' does not name a type

 adresse += sizeof(dureelevercoucher);

 ^

autres.cpp:121: error: 'adresse' does not name a type

 adresse += sizeof(alertetemperaturebasse);

 ^

autres.cpp:123: error: 'adresse' does not name a type

 adresse += sizeof(alertetemperaturehaute);

 ^

autres.cpp:125: error: 'adresse' does not name a type

 adresse += sizeof(ventilationaquarium);

 ^

autres.cpp:127: error: 'adresse' does not name a type

 adresse += sizeof(ventilationrampe);

 ^

autres.cpp:129: error: 'adresse' does not name a type

 adresse += sizeof(heureNourrissage1);

 ^

autres.cpp:131: error: 'adresse' does not name a type

 adresse += sizeof(heureNourrissage2);

 ^

autres.cpp:133: error: 'adresse' does not name a type

 adresse += sizeof(dureeNourissageMillis);

 ^

autres.cpp:135: error: 'adresse' does not name a type

 adresse += sizeof(consignePhRac);

 ^

autres.cpp:137: error: 'adresse' does not name a type

 adresse += sizeof(alertephbacbas);

 ^

autres.cpp:139: error: 'adresse' does not name a type

 adresse += sizeof(alertephbachaut);

 ^

autres.cpp:141: error: 'adresse' does not name a type

 adresse += sizeof(puissanceMaxBlanc);

 ^

autres.cpp:143: error: 'adresse' does not name a type

 adresse += sizeof(puissanceMaxBleu);

 ^

autres.cpp:145: error: 'adresse' does not name a type

 adresse += sizeof(oscillo1Angle1);

 ^

autres.cpp:147: error: 'adresse' does not name a type

 adresse += sizeof(oscillo2Angle1);

 ^

autres.cpp:149: error: 'adresse' does not name a type

 adresse += sizeof(oscillo3Angle1);

 ^

autres.cpp:151: error: 'adresse' does not name a type

 adresse += sizeof(oscillo1Angle2);

 ^

autres.cpp:153: error: 'adresse' does not name a type

 adresse += sizeof(oscillo2Angle2);

 ^

autres.cpp:155: error: 'adresse' does not name a type

 adresse += sizeof(oscillo3Angle2);

 ^

Plusieurs bibliothèque trouvées pour "DallasTemperature.h"
Utilisé : C:\Users\djbouns\Documents\Arduino\libraries\DallasTemperature
Non utilisé : C:\Program Files (x86)\Arduino\libraries\DallasTemperature
exit status 1
'adresse' does not name a type


Donc forcement j'ai chercher et peut etre fait pire en metant dans setup()  :smiley-confuse:


Ce devrait être des constantes globales (idéalement cette partie de variables de configuration devrait être directement dans une structure que vous écrivez ou lisez d'un coup depuis l'EEPROM - c'est bcp plus simple à gérer  
Je ne suis pas sur de comprendre ...
ecrire les adresses de stockage dans l'eeprom ?


(cf quelque part dans notre longue discussion je vous avais montré comment faire avec le mot clé genre 0xDEADBEEF ou 0xBADCAFFE  pour voir si l'EEPROM avait déjà été initialisée)
je n'ai pas oublier  ;)  mais comme j'avais une erreur, je l'ai mis de coté le temps d'écrire se que je voulait et que sa fonctionne.
J'avais bien prévu de le remettre ensuite, jte jure lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 12, 2018, 08:43 am
En pratique vous n'avez besoin de qu'une seule adresse - celle du début de la zone de stockage. Mettez tous les Paramètres dans une structure (et oui tout le code à modifier :) ) et vous sauver la structure d'un coup - c'est la fonction update qui se chargera de tout bien écrire où il faut  - plus besoin de jongler avec une adresse par paramètre

Regardez mon petit projet de projet fini démo de gestion de Température - c'est comme ça que j'ai fait dans ce code si je me souviens bien
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 12, 2018, 09:35 am
En pratique vous n'avez besoin de qu'une seule adresse - celle du début de la zone de stockage. Mettez tous les Paramètres dans une structure (et oui tout le code à modifier :) ) et vous sauver la structure d'un coup - c'est la fonction update qui se chargera de tout bien écrire où il faut  - plus besoin de jongler avec une adresse par paramètre

Regardez mon petit projet de projet fini démo de gestion de Température - c'est comme ça que j'ai fait dans ce code si je me souviens bien
C'est ca : ?
Code: [Select]
const uint32_t motClef = 0xBEEFDEAD;
const uint16_t adresseMotClef = 0x00;

// __attribute__ ((packed)) permet de forcer la conservation de l'ordre des champs
// c'est utile pour éviter que le compilateur mette le bazar quand on en rajoute au fil du temps
struct __attribute__ ((packed)) _paramS {
  int16_t tempConsigne;
  int16_t humConsigne;
  int16_t ventConsigne;
  byte   vitesseVentilateur; // PWM pour le ventilateur
} lesParametres;

const uint16_t adresseDesParametres = adresseMotClef + sizeof(motClef);


Si oui,
si je comprend bien,
on liste les paramètre a sauvegarder (pour moi les save***)
un petit coup de EEPROM.put(adresseDesParametres, lesParametres);
et ...
c'est tout ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 12, 2018, 09:51 am
oui

bien sûr après partout où vous voulez utilisez les paramètres il faut changer le nom de la variable pour y accéder par la structure

il y a la fonction suivante qui est appelée au démarrage dans le setup()
Code: [Select]
// **********************************************************
void etablirValeursParDefaut()
{
  uint32_t lectureMotClef;
  EEPROM.get(adresseMotClef, lectureMotClef);
  if (lectureMotClef == motClef) {
    // la mémoire a déjà été initialisée, on peut charger les paramètres
    EEPROM.get(adresseDesParametres, lesParametres);
  } else {
    // la mémoire n'avait pas encore été initialisée
    lesParametres.tempConsigne = 20;
    lesParametres.humConsigne = 50;
    lesParametres.ventConsigne = 2; // entre 0 (ventilateur vitess min) et 5 PWM ventilateur à 0xFF)
    lesParametres.vitesseVentilateur = lesParametres.ventConsigne * 51;
    EEPROM.put(adresseDesParametres, lesParametres);
    EEPROM.put(adresseMotClef, motClef);
  }


et quand je veux sauvegarder les paramètres (après une modif) il suffit de faire
Code: [Select]
EEPROM.put(adresseDesParametres, lesParametres);
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 13, 2018, 11:05 am
je suis presque au bout (de la modif :) )
j'ai fait
Code: [Select]
struct __attribute__ ((packed)) _paramS {
  uint8_t puissanceMaxBrassage1;
  uint8_t puissanceMaxBrassage2;
  uint8_t puissanceMaxBrassage3;
  uint8_t oscillo1Angle1 = number;
  uint8_t oscillo2Angle1 = number;
  uint8_t oscillo3Angle1 = number;
  uint8_t oscillo1Angle2 = number;
  uint8_t oscillo2Angle2 = number;
  uint8_t oscillo3Angle2 = number;
  uint32_t dureeTempeteMillis = (number * minuteEnMillis);
  uint8_t puissanceTempete = number;
  uint16_t delaisMouvementOscilloMillis = (number * secondeEnMillis);
  uint8_t  accalmieNocturne = number;
} sauvergarde;

et
Code: [Select]
void enregistrerBrassage() {
  DPRINTLN("******************************************************************************************************");
  DPRINTLN("*************************************** sauvegarde brassage ******************************************");
  DPRINTLN("******************************************************************************************************");
  valeurbrassage1.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage1 = number; // attribut la valeur nextion dans l'arduino
  valeurbrassage2.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage2 = number; // attribut la valeur nextion dans l'arduino
  valeurbrassage3.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage3 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo1min.getValue(&number); // recupere la valeur dans nextion
  oscillo1Angle1 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo2min.getValue(&number); // recupere la valeur dans nextion
  oscillo2Angle1 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo3min.getValue(&number); // recupere la valeur dans nextion
  oscillo3Angle1 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo1max.getValue(&number); // recupere la valeur dans nextion
  oscillo1Angle2 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo2max.getValue(&number); // recupere la valeur dans nextion
  oscillo2Angle2 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo3max.getValue(&number); // recupere la valeur dans nextion
  oscillo3Angle2 = number; // attribut la valeur nextion dans l'arduino
  valeurdureetempette.getValue(&number); // recupere la valeur dans nextion
  dureeTempeteMillis = (number * minuteEnMillis); // attribut la valeur nextion dans l'arduino
  valeurtempette.getValue(&number); // recupere la valeur dans nextion
  puissanceTempete = number; // attribut la valeur nextion dans l'arduino
  valeurmouvementoscillo.getValue(&number); // recupere la valeur dans nextion
  delaisMouvementOscilloMillis = (number * secondeEnMillis); // attribut la valeur nextion dans l'arduino
  valeuraccalemienocturne.getValue(&number); // recupere la valeur dans nextion
  accalmieNocturne = number; // attribut la valeur nextion dans l'arduino
  EEPROM.put(adresseDeSauvegarde, sauvergarde);
  versConfig();
}

et comme d'ab, j'ai une erreur mais la ... je comprend pas le problème de parenthèse.
Code: [Select]
sketch\affichage.cpp: In function 'void enregistrerBrassage()':

affichage.cpp:946: error: expected primary-expression before ')' token

   EEPROM.put(adresseDeSauvegarde, sauvergarde);

                                              ^

Plusieurs bibliothèque trouvées pour "DallasTemperature.h"
Utilisé : C:\Users\djbouns\Documents\Arduino\libraries\DallasTemperature
Non utilisé : C:\Program Files (x86)\Arduino\libraries\DallasTemperature
exit status 1
expected primary-expression before ')' token

Si je fait    EEPROM.put(adresseDeSauvegarde, 123);  ca fonctionne
Le problème est quand il y a sauvegarde.

J'ai bien verifier avec le code source (lcd rtc temp hum vent) et c'est identique
arfff ...   :smiley-sweat:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 13, 2018, 02:34 pm
dans la définition de la struct il ne faut pas mettre de valeurs --> virer tous les = number

Code: [Select]
struct __attribute__ ((packed)) _paramS {
  uint8_t puissanceMaxBrassage1;
  uint8_t puissanceMaxBrassage2;
  uint8_t puissanceMaxBrassage3;
  uint8_t oscillo1Angle1;
  uint8_t oscillo2Angle1;
  uint8_t oscillo3Angle1;
  uint8_t oscillo1Angle2;
  uint8_t oscillo2Angle2;
  uint8_t oscillo3Angle2;
  uint32_t dureeTempeteMillis;
  uint8_t puissanceTempete;
  uint16_t delaisMouvementOscilloMillis;
  uint8_t  accalmieNocturne;
} sauvergarde;


dans la fonction qui va au début du sketch regarder si l'EEPROM est déjà initialisée ou pas:
- si déjà initialisée alors juste charger sauvergarde avec le contenu de l'EEPROM
- si pas initialisée, alors mettre des valeurs par défaut dans sauvergarde et l'écrire en EEPROM avec le mot magique pour la prochaine fois



sinon vous n'avez pas d'autres erreurs avant?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 13, 2018, 03:56 pm
o ....

Laisse tombé ...

Jsuis le nez dessus des heure et jvois rien, sa me dégoute.

heureusement tu vois tout :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 13, 2018, 05:35 pm
c'est le soucis souvent - c'est plus simple pour les autres de repérer des erreurs...

Quand on galère comme ça, le mieux c'est d'aller prendre l'air un peu et de revenir avec un regard frais sur le problème.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 13, 2018, 06:15 pm
C'est pas un temps a prendre l'air, je vais etre malade  :o  :smiley-mr-green:  :)  :)  :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 13, 2018, 06:20 pm
Tu a du remarquer que souvent je post et je supprime quelque heure après pars-que j'ai trouvé tout seul ...
Si sa pouvait etre tout le temps comme sa :)
Bientôt ... lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 13, 2018, 07:55 pm
C'est pas un temps a prendre l'air, je vais etre malade  :o  :smiley-mr-green:  :)  :)  :)
:)

bon ben faut s'occuper de nettoyer l'aquarium alors ou faire le ménage ou un bon repas ! votre femme sera contente :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 13, 2018, 09:21 pm
:)

bon ben faut s'occuper de nettoyer l'aquarium alors ou faire le ménage ou un bon repas ! votre femme sera contente :)
oula ... c'est demain de st valentin ... faut pas deconner lol lol lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 13, 2018, 10:50 pm
sinon vous n'avez pas d'autres erreurs avant?
j'ai bien viré tout les "="
L'erreur est la meme  :smiley-confuse:
Et non, pas d'erreur avant, et pas d'erreur si je retire EEPROM.put(adresseDeSauvegarde, sauvergarde);

Voici toute l'erreur quand je met EEPROM.put(adresseDeSauvegarde, sauvergarde);

Code: [Select]
sketch\affichage.cpp: In function 'void enregistrerBrassage()':
affichage.cpp:946: error: expected primary-expression before ')' token
EEPROM.put(adresseDeSauvegarde, sauvergarde);                                          
exit status 1
expected primary-expression before ')' token
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 14, 2018, 01:25 am
postez le code pour voir comment tout cela est défini...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 14, 2018, 01:51 am
postez le code pour voir comment tout cela est défini...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 14, 2018, 10:26 am
manquent les fichier NexVariable.h etc - donc je ne peux pas tester la compilation

dans la fonction etablirValeursParDefaut() il faut initialiser toutes les valeurs de la structure à une valeur par défaut correcte
Code: [Select]
void etablirValeursParDefaut() {
  uint32_t lectureMotClef;
  EEPROM.get(adresseMotClef, lectureMotClef);
  if (lectureMotClef == motClef) {
    // la mémoire a déjà été initialisée, on peut charger les paramètres
    EEPROM.get(adresseDeSauvegarde, sauvergarde);
  }
  else {
    // la mémoire n'avait pas encore été initialisée
    sauvergarde.puissanceMaxBrassage1;  // CA FAIT QUOIT CA?? FAUT INITIALISER LES VALEURS
    sauvergarde.puissanceMaxBrassage2;  // CA FAIT QUOIT CA?? FAUT INITIALISER LES VALEURS
    sauvergarde.puissanceMaxBrassage3;  // CA FAIT QUOIT CA?? FAUT INITIALISER LES VALEURS
    EEPROM.put(adresseDeSauvegarde, sauvergarde);
    EEPROM.put(adresseMotClef, motClef);
  }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 14, 2018, 10:42 am
la biblioteque est trop grosse mais elle est dispo ICI (https://github.com/itead/ITEADLIB_Arduino_Nextion)


Pour l'initialisation, j'ai fais comme cela car les valeur par Default son déclaré avec la variable et son appelé avant le setup, exemple : (dans brassage.cpp)
Code: [Select]
uint8_t puissanceMaxBrassage1 = 100 ; // puissance jebao rw 15 en %
uint8_t puissanceMaxBrassage2 = 80 ; // puissance jebao rw 8 en %
uint8_t puissanceMaxBrassage3 = 40 ; // puissance jebao rw 8 en %

donc au moment de void etablirValeursParDefaut(), puissanceMaxBrassage* a déjà une valeur.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 14, 2018, 11:24 am
mon point c'est que ce code ne fait rien du tout
Code: [Select]
    sauvergarde.puissanceMaxBrassage1;
    sauvergarde.puissanceMaxBrassage2;
    sauvergarde.puissanceMaxBrassage3;
ce ne serait pas plutôt
Code: [Select]
    sauvergarde.puissanceMaxBrassage1 = puissanceMaxBrassage1;
    sauvergarde.puissanceMaxBrassage2 = puissanceMaxBrassage2;
    sauvergarde.puissanceMaxBrassage3 = puissanceMaxBrassage3;
que vous vouliez écrire? et quid des autres valeurs? la structure n'est pas initialisée?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 14, 2018, 11:42 am
j'arrive à compiler sans erreurs par contre il y a des dizaines de Warnings...

vous devriez activer les "compilation Warnings" au moins au niveau "more" et régler chacun des soucis mentionné. le programme doit compiler sans warnings.

cela dit j'ai ce message:

Sketch uses 54678 bytes (21%) of program storage space. Maximum is 253952 bytes.
Global variables use 7146 bytes (87%) of dynamic memory, leaving 1046 bytes for local variables. Maximum is 8192 bytes.
Low memory available, stability problems may occur.


donc faut faire attention à cette partie et vous assurer que tout vos print de debug soient en F("xxx") par exemple histoire de libérer de la SRAM (vu que vous avez encore plein de place en flash)

qu'est-ce que vous avez comme message à la compilation ??
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 15, 2018, 01:22 am
j'arrive à compiler sans erreurs par contre il y a des dizaines de Warnings...
Je vais me faire engueuler ...
Pour continuer a bosser j'ai commenter la ligne qui pose probleme.
elle est dans affichage.cpp, dans void enregistrerBrassage() {, c'est : EEPROM.put(adresseDeSauvegarde, sauvergarde);

Des qu'il y a cette ligne qui doit sauvegarder les paramettre j'ai cette erreur :
Code: [Select]
sketch\affichage.cpp: In function 'void enregistrerBrassage()':
affichage.cpp:946: error: expected primary-expression before ')' token
EEPROM.put(adresseDeSauvegarde, sauvergarde);
exit status 1
expected primary-expression before ')' token



vous devriez activer les "compilation Warnings" au moins au niveau "more" et régler chacun des soucis mentionné. le programme doit compiler sans warnings.
Je pense avoir trouver comment l'activer et ce n'est pas jolie jolie ...
Je peut meme pas le poster, y fait plus de 9000 lignes  :o
cela dit j'ai ce message:

Sketch uses 54678 bytes (21%) of program storage space. Maximum is 253952 bytes.
Global variables use 7146 bytes (87%) of dynamic memory, leaving 1046 bytes for local variables. Maximum is 8192 bytes.
Low memory available, stability problems may occur.


donc faut faire attention à cette partie et vous assurer que tout vos print de debug soient en F("xxx") par exemple histoire de libérer de la SRAM (vu que vous avez encore plein de place en flash)

qu'est-ce que vous avez comme message à la compilation ??
Ok pour le serial.print(F
Mais le serial.println(F n'existe pas et vu que c'est pas commenté, je ne sait trop a quoi cela correspond
Code: [Select]
#define DEBUG // à commenter pour enleverSoleil les traces


#ifdef DEBUG
#define DPRINTF(s)   {Serial.print(F(s));}
#define DPRINTFV(s,v)  {Serial.print(F(s)); Serial.print(v);}
#define DPRINTFX(s,v) {Serial.print(F(s)); Serial.print(F("0x")); Serial.print(v, HEX);}
#define DPRINT(x)  {Serial.print(x);}
#define DPRINTLN(x)  {Serial.println(x);}
#else
#define DPRINTF(s)
#define DPRINTFV(s,v)
#define DPRINTFX(s,v)
#define DPRINT(x)
#define DPRINTLN(x)
#endif


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 16, 2018, 11:05 am
Pour le bug

changez autres.h comme cela
Code: [Select]
#ifndef  _autres_h_
#define _autres_h_
#include <stdint.h> // http://www.cplusplus.com/reference/cstdint/
const uint32_t motClef = 0xBEEFDEAD;
const int16_t adresseMotClef = 0x00;
const int16_t adresseDeSauvegarde = adresseMotClef + sizeof(motClef);

// __attribute__ ((packed)) permet de forcer la conservation de l'ordre des champs
// c'est utile pour éviter que le compilateur mette le bazar quand on en rajoute au fil du temps
struct __attribute__ ((packed)) paramS_t {
  uint8_t puissanceMaxBrassage1;
  uint8_t puissanceMaxBrassage2;
  uint8_t puissanceMaxBrassage3;
  uint8_t oscillo1Angle1;
  uint8_t oscillo2Angle1;
  uint8_t oscillo3Angle1;
  uint8_t oscillo1Angle2;
  uint8_t oscillo2Angle2;
  uint8_t oscillo3Angle2;
  uint32_t dureeTempeteMillis;
  uint8_t puissanceTempete;
  uint16_t delaisMouvementOscilloMillis;
  uint8_t  accalmieNocturne;
};
extern paramS_t sauvergarde;


void nourissage();
void ph();
void graphique();
void testTempsBoucle();
void etablirValeursParDefaut();

#endif


et dans autres.cpp remplacez la partie EEPROM par
Code: [Select]
// *******************************************************************************************************************************************
// **************************************** eeprom
// *******************************************************************************************************************************************
paramS_t sauvergarde;

void etablirValeursParDefaut() {
  uint32_t lectureMotClef;
  EEPROM.get(adresseMotClef, lectureMotClef);
  if (lectureMotClef == motClef) {
    // la mémoire a déjà été initialisée, on peut charger les paramètres
    EEPROM.get(adresseDeSauvegarde, sauvergarde);
  }
  else {
    // la mémoire n'avait pas encore été initialisée
    sauvergarde.puissanceMaxBrassage1;
    sauvergarde.puissanceMaxBrassage2;
    sauvergarde.puissanceMaxBrassage3;
    EEPROM.put(adresseDeSauvegarde, sauvergarde);
    EEPROM.put(adresseMotClef, motClef);
  }
}



Notez que votre fonction enregistrerBrassage()
Code: [Select]
void enregistrerBrassage() {
  DPRINTLN("******************************************************************************************************");
  DPRINTLN("*************************************** sauvegarde brassage ******************************************");
  DPRINTLN("******************************************************************************************************");
  valeurbrassage1.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage1 = number; // attribut la valeur nextion dans l'arduino
  valeurbrassage2.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage2 = number; // attribut la valeur nextion dans l'arduino
  valeurbrassage3.getValue(&number); // recupere la valeur dans nextion
  puissanceMaxBrassage3 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo1min.getValue(&number); // recupere la valeur dans nextion
  oscillo1Angle1 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo2min.getValue(&number); // recupere la valeur dans nextion
  oscillo2Angle1 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo3min.getValue(&number); // recupere la valeur dans nextion
  oscillo3Angle1 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo1max.getValue(&number); // recupere la valeur dans nextion
  oscillo1Angle2 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo2max.getValue(&number); // recupere la valeur dans nextion
  oscillo2Angle2 = number; // attribut la valeur nextion dans l'arduino
  valeuroscillo3max.getValue(&number); // recupere la valeur dans nextion
  oscillo3Angle2 = number; // attribut la valeur nextion dans l'arduino
  valeurdureetempette.getValue(&number); // recupere la valeur dans nextion
  dureeTempeteMillis = (number * minuteEnMillis); // attribut la valeur nextion dans l'arduino
  valeurtempette.getValue(&number); // recupere la valeur dans nextion
  puissanceTempete = number; // attribut la valeur nextion dans l'arduino
  valeurmouvementoscillo.getValue(&number); // recupere la valeur dans nextion
  delaisMouvementOscilloMillis = (number * secondeEnMillis); // attribut la valeur nextion dans l'arduino
  valeuraccalemienocturne.getValue(&number); // recupere la valeur dans nextion
  accalmieNocturne = number; // attribut la valeur nextion dans l'arduino

 EEPROM.put(adresseDeSauvegarde, sauvergarde);
   
  versConfig();
}
lit bien les data affichées sur le nexion mais ne les stockent pas dans sauvergarde.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 17, 2018, 09:24 am
Yes, merci

Notez que votre fonction enregistrerBrassage()lis bien les data affichées sur le nexion mais ne les stockent pas dans sauvergarde.
Je ne comprend pas ...
Les paramètre son lu dans le nextion puis associé a la variable correspondant dans l'arduino.
a la fin de cela, il y a EEPROM.put(adresseDeSauvegarde, sauvergarde);
qui enregistre toute les variable de la liste struct __attribute__ ((packed)) paramS_t {
non ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 17, 2018, 09:54 am
Yes, merci

Je ne comprend pas ...
Les paramètre son lu dans le nextion puis associé a la variable correspondant dans l'arduino.
a la fin de cela, il y a EEPROM.put(adresseDeSauvegarde, sauvergarde);
qui enregistre toute les variable de la liste struct __attribute__ ((packed)) paramS_t {
non ?
Oui mais il faut que vos variables dans sauvegarde soit mis à jour avec les nouvelles valeurs - en pratique vous ne devriez plus avoir nulle part de variable Arduino à sauver qui ne soit pas membre de sauvegarde. Partout vous devriez avoir sauvegarde.XXX et pas juste XXX. Il faut tout remplacer partout.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 17, 2018, 10:08 am
  :smiley-eek-blue: :'(
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 17, 2018, 10:27 am
et oui ... c'est ce que je disais en #571 (http://forum.arduino.cc/index.php?topic=504431.msg3603814#msg3603814)....

Quote
En pratique vous n'avez besoin de qu'une seule adresse - celle du début de la zone de stockage. Mettez tous les Paramètres dans une structure (et oui tout le code à modifier :) ) et vous sauver la structure d'un coup - c'est la fonction update qui se chargera de tout bien écrire où il faut  - plus besoin de jongler avec une adresse par paramètre
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 17, 2018, 11:05 am
et oui ... c'est ce que je disais en #571 (http://forum.arduino.cc/index.php?topic=504431.msg3603814#msg3603814)....

Faut le temps je comprenne lol
bon ba y a plus qu'as ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 17, 2018, 11:36 am
oui :)

donc plus de puissanceMaxBrassage1 nulle part dans le programme, ça doit être remplacé par sauvegarde.puissanceMaxBrassage1

vous pouvez aussi simplifier - au lieu d'écrire
Code: [Select]
valeurbrassage1.getValue(&number); // recupere la valeur dans nextion
puissanceMaxBrassage1  = number; // attribut la valeur nextion dans l'arduino


vous pouvez mettre la valeur d'un coup au bon endroit en mémoire
Code: [Select]
valeurbrassage1.getValue(&sauvegarde.puissanceMaxBrassage1); // recupere la valeur dans nextion
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 17, 2018, 10:05 pm
J'ai remplacer une premier variable puissanceMaxBrassage1 par sauvegarde.puissanceMaxBrassage1
J'ai des erreur de compile comme quoi sauvegarde n'est pas déclaré.

Cette "écriture" pour la sauvegarde devient compliquer alors que je ne voulait juste simplifier l'indexation
(sans parler que j'ai pas compris le fonctionnement)
il doit sans doute y avoir plus simple sans tout avoir a modifier non ?

En plus, si j'ai une méga liste de warning, il faudrait peut être mieux la résorber avec de continuer ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 18, 2018, 11:16 pm
j'ai passer une bonne partie de la journee a resoudre tout ces Warning.
Je suis content d'en avoir réparé une majorité sans vous embêter :)

Il en reste un peu mais je ne suis pas sur qu'elle vienne de moi.
problème dans la biblioteque EEPROM ?

Code: [Select]
In file included from C:\Users\djbouns\Documents\AQUABOUNS_V2_gsm\AQUABOUNS_V2_gsm.ino:23:0:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:43:30: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

     operator const uint8_t() const       { return **this; }

                              ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:92:26: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

     operator const int() const          { return index; }

                          ^

In file included from C:\Users\djbouns\Documents\AQUABOUNS_V2_gsm\AQUABOUNS_V2_gsm.ino:23:0:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:145:20: warning: 'EEPROM' defined but not used [-Wunused-variable]

 static EEPROMClass EEPROM;

                    ^

In file included from sketch\affichage.cpp:1:0:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:43:30: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

     operator const uint8_t() const       { return **this; }

                              ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:92:26: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

     operator const int() const          { return index; }

                          ^

In file included from sketch\affichage.cpp:1:0:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:145:20: warning: 'EEPROM' defined but not used [-Wunused-variable]

 static EEPROMClass EEPROM;

                    ^

Le croquis utilise 54826 octets (21%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 7050 octets (86%) de mémoire dynamique, ce qui laisse 1142 octets pour les variables locales. Le maximum est de 8192 octets.
La mémoire disponible faible, des problèmes de stabilité pourraient survenir.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 20, 2018, 10:43 am
j'ai mis les serial.print en Flash

j'arrive a :
Code: [Select]

Le croquis utilise 59586 octets (23%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 5311 octets (64%) de mémoire dynamique, ce qui laisse 2881 octets pour les variables locales. Le maximum est de 8192 octets.


et quand je retire le debug je suis a :
Code: [Select]
Le croquis utilise 52066 octets (20%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 5009 octets (61%) de mémoire dynamique, ce qui laisse 3183 octets pour les variables locales. Le maximum est de 8192 octets.



J'ai pas mal chercher sur le net pour l'eeprom et les seul exemple d'indexation "propre" que j'ai trouvé son identique a ton exemple JM donc va falloir vraiment que je revois tout ... une fois de plus :(
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Feb 20, 2018, 02:07 pm
Boun's et tu as même pas eu un bon point de plus pour tout le boulot accomplis ces derniers jours.

C'est pas juste.

J-M-L fais un tit geste.

Courage Boun's.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 21, 2018, 12:07 am
j'ai tout modifier  :smiley-sweat:  :smiley-sleep:

J'ai donc dans "eeprom.h"
Code: [Select]
#ifndef  _eeprom_h_
#define _eeprom_h_
#include <stdint.h> // http://www.cplusplus.com/reference/cstdint/

const uint32_t motClef = 0xBEEFDEAD;
const uint16_t adresseMotClef = 0x00;
const uint16_t adresseDeSauvegarde = adresseMotClef + sizeof(motClef);

// __attribute__ ((packed)) permet de forcer la conservation de l'ordre des champs
// c'est utile pour éviter que le compilateur mette le bazar quand on en rajoute au fil du temps
struct __attribute__ ((packed)) paramS_t {
uint8_t puissanceMaxBrassage1;
uint8_t puissanceMaxBrassage2;
uint8_t puissanceMaxBrassage3;
uint8_t accalmieNocturne;
uint8_t puissanceMaxBlanc;
uint8_t puissanceMaxBleu;
uint32_t leverSoleil;
uint32_t coucherSoleil;
uint16_t dureelevercoucher;
uint8_t oscillo1Angle1;
uint8_t oscillo1Angle2;
uint8_t oscillo2Angle1;
uint8_t oscillo2Angle2;
uint8_t oscillo3Angle1;
uint8_t oscillo3Angle2;
uint16_t delaisMouvementOscilloMillis;
uint16_t dureeOsmolationMillis ;
uint8_t compteurOsmolationMax;
float ventilationaquarium;
float alertetemperaturehaute;
float alertetemperaturebasse;
uint8_t ventilationrampe;
boolean adresseSondeRampe;
boolean adresseSondeBac;
uint32_t dureeTempeteMillis;
uint8_t puissanceTempete;
boolean tempeteAleatoireOn;
boolean tempeteDuJour;
uint32_t dureeNourissageMillis;
uint32_t heureNourrissage1;
uint32_t heureNourrissage2;
boolean nourrissage1ON;
boolean nourrissage2ON;
float consignePhRac;
float alertephbacbas;
float alertephbachaut;


};
extern paramS_t sauvergarde;

#endif



Puis dans eeprom.cpp
Code: [Select]
#include "eeprom.h"
#include <EEPROM.h>


// *******************************************************************************************************************************************
// **************************************** eeprom
// *******************************************************************************************************************************************

paramS_t sauvergarde;

void etablirValeursParDefaut() {
  uint32_t lectureMotClef;
  EEPROM.get(adresseMotClef, lectureMotClef);
  if (lectureMotClef == motClef) {
    // la mémoire a déjà été initialisée, on peut charger les paramètres
    EEPROM.get(adresseDeSauvegarde, sauvergarde);
  }
  else {
    // la mémoire n'avait pas encore été initialisée
sauvegarde.puissanceMaxBrassage1 = 50 ; // puissance jebao rw 15 en %
sauvegarde.puissanceMaxBrassage2 = 50 ; // puissance jebao rw 8 en %
sauvegarde.puissanceMaxBrassage3 = 50 ; // puissance jebao rw 8 en %
sauvegarde.accalmieNocturne = 50; // pourcentage de reduction du brassage la nuit
sauvegarde.puissanceMaxBlanc = 50 ; // puissance blanc en %
sauvegarde.puissanceMaxBleu = 50 ; // puissance bleu en %
sauvegarde.leverSoleil = 36000ul; // heure debut sauvegarde.leverSoleil (h*3600+m*60+s)
sauvegarde.coucherSoleil = 72000ul; // heure fin couché (h*3600+m*60+s)
sauvegarde.dureelevercoucher = 3600u; // temps de levé (h*3600+m*60+s)
sauvegarde.oscillo1Angle1 = 80 ; // angle oscillo entre 0 et 180
sauvegarde.oscillo1Angle2 = 100 ; // angle oscillo entre 0 et 180
sauvegarde.oscillo2Angle1 = 80 ; // angle oscillo entre 0 et 180
sauvegarde.oscillo2Angle2 = 100 ; // angle oscillo entre 0 et 180
sauvegarde.oscillo3Angle1 = 80 ; // angle oscillo entre 0 et 180
sauvegarde.oscillo3Angle2 = 100 ; // angle oscillo entre 0 et 180
sauvegarde.delaisMouvementOscilloMillis = 3000u ; // delais mouvement oscillo en millis
sauvegarde.dureeOsmolationMillis = 5000u; //durée de l'osmolation en millis
sauvegarde.compteurOsmolationMax = 5; // nombre de declanchement de l'osmolation avant alarme
sauvegarde.ventilationaquarium = 27; // temperature de declanchement de la ventilation du bac
sauvegarde.alertetemperaturehaute = 27.5; // temperature de declanchement de la ventilation du bac
sauvegarde.alertetemperaturebasse = 24.8; // temperature de declanchement de la ventilation du bac
sauvegarde.ventilationrampe = 35; //  temperature de declanchement de la ventilation de la rampe
sauvegarde.adresseSondeRampe = 0; // adresse de la sonde de temperature de la rampe
sauvegarde.adresseSondeBac = 1; // adresse de la sonde de temperature du bac
sauvegarde.dureeTempeteMillis = 2000u; // durée tempête millis
sauvegarde.puissanceTempete = 75; // puissance de toutes les pompe jebao en mode tempête en %
sauvegarde.tempeteAleatoireOn = false; // on/off tempette aleatoire
sauvegarde.tempeteDuJour = false; // on/off tempette quotidienne
sauvegarde.dureeNourissageMillis = 300000ul; // durée du nourissage en millis
sauvegarde.heureNourrissage1 = 36000ul; // heure du nourrissage auto 1 (h*3600+m*60+s)
sauvegarde.heureNourrissage2 = 72000ul; // heure du nourissage auto 2 (h*3600+m*60+s)
sauvegarde.nourrissage1ON = true; // on/off nourissage 1
sauvegarde.nourrissage2ON = false;// on/off nourissage 2
sauvegarde.consignePhRac = 6.66; // consigne du ph du RAC
sauvegarde.alertephbacbas = 7.77; // limite PH bas du bac pour alerte
sauvegarde.alertephbachaut = 8.88;; // limite ph haut du bac pour alerte



    EEPROM.put(adresseDeSauvegarde, sauvergarde);
    EEPROM.put(adresseMotClef, motClef);
  }
}



et j'ai modifier toute mes variables a sauvegarder en "sauvegarde.****"

dans mon global.h je les ai donc en
Code: [Select]
extern uint8_t sauvegarde.oscillo1Angle1;
et j'ai cette erreur
Code: [Select]
global.h:126: error: expected initializer before '.' token

 extern uint8_t sauvegarde.oscillo1Angle1;



donc je me suis dit, sauvegarde doit etre devenu un type donc j'ai fait
Code: [Select]
extern sauvegarde.oscillo1Angle1;
et j'ai aussi une erreur
Code: [Select]
exit status 1
'sauvegarde' does not name a type


donc je me retrouve coincé ... encore :(
j'ai plus la niak a force ...
On arrive au bout du 9e mois  :smiley-sad-blue:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 21, 2018, 08:01 am
Suis en déplacement toute la semaine juste sur mon tel et pas bcp de temps avant le week end

Bravo pour le boulot - pour le
Coup du extern il faut définir le type (la structure) dans un .h et en externe dans le .h la variable et importer le .h - c'est ce que j'avais proposé comme modif plus haut
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 21, 2018, 11:56 pm
Yes  :smiley-grin:
a demain  :smiley-sleep:   :smiley-razz:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Feb 22, 2018, 09:44 am
en attendant le week-end pour le boulot fourni :)

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 22, 2018, 10:29 pm
(https://www.theshulergroupllc.com/wp-content/uploads/2017/05/Yeses.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 24, 2018, 11:34 pm
J'ai travailler aujourd'hui sur le démarrage de l'automate.
Il me paraissait important qu'au démarrage l'on sache si tout est OK coté périphérique.
Donc plutôt que d'avoir tout dans le Moniteur série, pourquoi ne pas l'avoir directement sur l'écran :)

Ça donne ça (https://youtu.be/qQ1_k_XEz0U)
(le modul gsm et sd ne sont pas branché actuellement :) )


n'hésiter pas a donner vos avis :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Feb 25, 2018, 11:20 am
la partie eeprom me fou un sacré bazars ...

Je pense avoir compris pourquoi
Mon fichier est comme ca:
Code: [Select]
#include "WiFiEsp.h"
#include <Wire.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include "SdFat.h"
#include "Nextion.h"
#include "RTClib.h"
#include <Servo.h>
#include <EEPROM.h>
#include "pin.h"
// **********************************************************************************************************************************************************************************************
// Declarations des fonctions
// ---------------------------
#include "eeprom.h"
#include "eclairage.h"
#include "autres.h"
#include "gsm.h"
#include "affichage.h"
#include "brassage.h"
#include "horloge.h"
#include "oscillo.h"
#include "osmolation.h"
#include "Sd.h"
#include "temperature.h"
#include "tempete.h"
#include "global.h"
#include "debug.h"
// **********************************************************************************************************************************************************************************************
// Setup
// ---------------------------
void setup() {
etablirValeursParDefaut();


Les valeurs de l'epprom son donc lu des l'entree dans le setup, mais, certain calcule present dans mes fixhier *.h utilise les valeur de l'eeprom.
exemple :
Code: [Select]
uint32_t finleverSoleilBleu1 = (sauvegarde.leverSoleil + sauvegarde.dureelevercoucher);

Je me retrouve donc avec finleverSoleilbleu1 = 0  :(


A part tout déplacer juste après la lecture de l'eeprom, je vois pas comment faire autrement.


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 02, 2018, 10:35 pm
Je commençais a être inquiet de plus voir professeur jean marc
Mais il est bien la lol

Msieu Msieu
Vous pouvez me dire si je doit tout déplacer juste après la lecture de l'eeprom ou si y a une autre solution ?
(je me suis pas reposer en attendant, j'ai quasi finaliser la partie "graphique sur 24h" c'etait pas une mince affaire :)  )
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 03, 2018, 12:25 am
Ben oui... faut déplacer après la lecture des valeurs... :)
L'autre option étant d'utiliser des #define mais comme ça c'est recalculé à chaque fois..
Code: [Select]
#define finleverSoleilBleu1  (sauvegarde.leverSoleil + sauvegarde.dureelevercoucher)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 03, 2018, 09:47 am
 :smiley-confuse:
Entre changer tout les nom puis tout déplacer ...
On va y arrivé  :smiley-cool:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 03, 2018, 10:20 am
Disons que dès que vous avez décidé que ce n'étaient plus des constantes, il n'y a pas de magie, il faut les mettre à jour quand une des valeurs change... le plus simple effectivement est d'avoir tout au même endroit dans le code:

- établissement des valeurs au démarrage qui sont soit des valeurs par défaut si l'EEPROM n'est pas initialisée, soit lecture de l'EEPROM et calcul des valeurs dérivées

- à chaque modification d'une Valeur, sauvegardé en EEPROM et recalculer des valeurs dérivées

ça ne fait que deux fonctions réellement écrire été si dès le début vous avez pris l'approche de la structure pour les paramètres alors le code ne change pas si d'aventure vous devez rajouter des nouveaux param, suffit d'etendre La structure
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 03, 2018, 10:25 pm
C'est bon, j'ai donc ton déplacé dans une fonction majValeursParDefaut() qui met a jour toute les variables calculé a partir des sauvegarde.***

Je continu sur la partie graphique
Comme je vous ai dit, le graph 24h est OK
Voir ici le rendu (https://www.youtube.com/watch?v=c8OHEYpF-_Y&feature=youtu.be), la plus grosse galère a été de faire en sorte que la partie droite du graph soit l'heure du dernier relevé et que le graph parte de la en affichant les bonne heure en dessous (au départ le graph allait de 0h a 24h)

A pressent j'attaque la partie graph sur 7 jours, au départ je voulait stocker les mesure dans une variable par heure donc 168 variables*2(température + ph)soit 1344 octets et 2 problèmes :
1) le fait qu'en cas de redémarrage / coupure de courant toutes les mesure était perdu
2) l'optimisation du code

J'ai donc pensé a mettre tout sa sur SD.
Si je met en place ce que je sait déjà faire, sa va être 1 mesure = 1 fichier, un peut cochon tout ça.
>mettre dans un .csv, et la, je doit encore tout apprendre. j'ai trouvé diffèrent poste qui explique comment écrire dans un .csv mais aucun pour récupérer une donné dans un emplacement précis.

Si vous savez ou je peut trouver un tuto pour faire ca :)

A moins qu'il y est une autre solution que le .csv?




Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Mar 04, 2018, 04:16 pm
Boun's bonjour.

Super boulot que tu as accomplis et très bel écran, en plus deux bon point de plus, tu approche de mes plus vifs applaudissements.

Encore une fois BRAVO.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 04, 2018, 04:48 pm
C'est bon, j'ai donc ton déplacé dans une fonction majValeursParDefaut() qui met a jour toute les variables calculé a partir des sauvegarde.***
(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)


Je continue sur la partie graphique
Comme je vous ai dit, le graphe 24h est OK
Voir ici le rendu (https://www.youtube.com/watch?v=c8OHEYpF-_Y&feature=youtu.be), la plus grosse galère a été de faire en sorte que la partie droite du graphe soit l'heure du dernier relevé et que le graphe parte de là en affichant les bonnes heures en dessous (au départ le graphe allait de 0h a 24h)
(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)

A présent j'attaque la partie graphe sur 7 jours, au départ je voulais stocker les mesures dans une variable par heure donc 168 variables*2(température + ph)soit 1344 octets et 2 problèmes :
1) le fait qu'en cas de redémarrage / coupure de courant toutes les mesure était perdu
2) l'optimisation du code
effectivement 24x7 = 168 valeurs à enregistrer... mais avez vous besoin de les mémoriser sur 4 octets chacune?

--> Quelle est la résolution de votre écran? Si l'amplitude du graphe tient sur 256 points (et vous n'êtes pas au pixel près donc à mon avis même pour 512 ça irait), vous feriez mieux de mémoriser le Y sur un seul octet - ça ramène pour la température et le ph à 2 x 168 octets = 336 octets ==> ça tiendrait en SRAM plus facilement mais en cas de reboot on perd tout l'historique, donc si c'est un soucis alors il faut effectivement penser à stocker cela quelque part.

deux options: utiliser l'EEPROM de votre Arduino mega avec un buffer circulaire: Vous définissez une adresse de départ pour la T°, disons à l'adresse 100 et toutes le heures vous mémorisez dans la case suivante la valeur de la T°. Quand vous êtes arrivé à 168 valeurs enregistrée, celle suivante vient écraser celle qui est en 100 et donc au bout d'un moment pour lire les 168 dernières valeurs, il faut commencer à lire au milieu de la mémoire aller jusqu'au bout puis recommencer au début (c'est pour cela qu'on dit que c'est un buffer circulaire). il faut donc mémoriser quelque part aussi l'adresse du pointeur mémoire de la prochaine écriture et le nombre de valeur valides (avant qu'on en ait écrit 168 éventuellement) --> si vous voulez que ça résiste à un reboot il faut aussi mettre cela en EEPROM. comme vous avez moins de 255 valeurs, ça prend aussi 1 octet pour chacun. et l'octet de "case suivant" sera modifié toutes les heures. Comme l'EEPROM a une durée de vie de 100,000 écritures ça veut dire qu'au bout de 100,000 heures cette case mémoire qui contient l'index  'case suivante' ne sera plus fiable.... Bon, 100,000 heures ça veut dire que votre case mémoire risque de devenir défaillante dans 11 ans... ça laisse le temps de voir venir... dans 10 ans vous pouvez recompiler le programme éventuellement et stocker ce pointeur dans une autre case qui n'a pas encore été utilisée et vous repartez pour 10 ans :)

pour la partie stockage des données, vous allez écraser la valeur que tous les 7 jours donc le reste de la mémoire tient 700,000 jours - quasiment 2000 ans... je pense donc que vous n'avez pas à vous en soucier :)

(notez que vous avez sur un MEGA de quoi stocker sur 4 octets chaque valeur si c'est ce que vous voulez conserver)

L'autre option comme vous le mentionnez c'est une carte SD.

J'ai donc pensé a mettre tout sa sur SD.
Si je met en place ce que je sait déjà faire, sa va être 1 mesure = 1 fichier, un peut cochon tout ça.
>mettre dans un .csv, et la, je doit encore tout apprendre. j'ai trouvé diffèrent poste qui explique comment écrire dans un .csv mais aucun pour récupérer une donné dans un emplacement précis.

Si vous savez ou je peut trouver un tuto pour faire ca :)

A moins qu'il y est une autre solution que le .csv?
Vu que le fichier ne sert qu'à l'affichage, perso je ne m'ennuierai pas avec un format lisible par les humains... et je mettrais les valeurs en binaire directement dans le fichier, les unes à la suite des autres, éventuellement avec une gestion un peu smart des fichiers - par exemple un fichier dont le nom est la date du genre 20180304.dat de 2 x 24 valeurs par jour et pour bâtir le graphe final avec votre RTC vous savez quels sont les noms des 7 derniers fichiers à aller lire et vous importez les valeurs en vous en servez pour l'affichage. si le nom de fichier n'existe pas c'est que les données ne sont pas encore là, et vous mettez des 0 par exemple sur le graphe.

il y a de fortes chances que la carte SD ne dure pas 10 ans - donc il faudra prévoir de la changer à un moment et vous perdrez l'historique ce faisant - mais vous n'avez pas à re-compiler le programme.

Perso je prendrai l'option EEPROM car ce sera plus rapide et moins compliqué à gérer que la carte SD.


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 04, 2018, 05:56 pm
Voici un exemple de code qui gère un buffer circulaire en EEPROM.

le fonctionnement reprend ce que je décris plus haut (avec 5 valeurs au lieu de 168) et comme je ne veux pas attendre toutes les heures pour rajouter une entrée et voir le tableau se remplir, j'ai mis dans la loop un code qui attend que vous tapiez la lettre 's' sur la console série (réglée à 115200 bauds) pour générer un octet aléatoire et aller le ranger en mémoire, puis afficher la liste des valeurs. en envoyant plusieurs  's' vous verrez le tableau se remplir, puis une fois plein se décaler... c'est le principe du buffer circulaire.

Code: [Select]
#include <EEPROM.h>

const byte maxValeurs = 5; // le nombre de valeurs max à sauver en EEPROM
byte indexProchaineValeur = 0;  // un index par rapport à l'adresse de début (ici on stocke des octets)
byte nombreTotalValeurs = 0; // combien de valeurs sont valides dans la mémoire (une fois le tableau rempli elles sont toutes valides)

// GESTION DE L'EEPROM

const uint32_t motClef = 0xBADCAFE; // pour savoir si l'EEPROM a déjà été initialisée

const uint16_t adresseMotClef = 0x100; // on commencera à stocker tout cela à partir de cette adresse en EEPROM
const uint16_t adresseNombreTotalValeurs = adresseMotClef + sizeof(motClef);
const uint16_t adresseProchaineValeur = adresseNombreTotalValeurs + sizeof(nombreTotalValeurs);
const uint16_t adresseBufferCirculaire = adresseProchaineValeur + sizeof(indexProchaineValeur);


void etablirValeursParDefaut()
{
  uint32_t lectureMotClef;
  Serial.print(F("Mot Clef = 0x")); Serial.println(motClef, HEX);
  Serial.print(F("Adresse Mot Clef = 0x")); Serial.println(adresseMotClef, HEX);
  Serial.print(F("Adresse des valeurs = 0x")); Serial.println(adresseBufferCirculaire, HEX);

  EEPROM.get(adresseMotClef, lectureMotClef);
  if (lectureMotClef == motClef) {
    // la mémoire a déjà été initialisée, on peut charger les paramètres
    Serial.println(F("initialisation OK"));
    EEPROM.get(adresseProchaineValeur, indexProchaineValeur);
    EEPROM.get(adresseNombreTotalValeurs, nombreTotalValeurs);
  } else {
    // la mémoire n'avait pas encore été initialisée
    Serial.println(F("params en memoire pas OK"));
    indexProchaineValeur = 0;
    nombreTotalValeurs = 0;
    EEPROM.put(adresseProchaineValeur, indexProchaineValeur);
    EEPROM.put(adresseNombreTotalValeurs, nombreTotalValeurs);
    EEPROM.put(adresseMotClef, motClef);
  }

  Serial.print(F("indexProchaineValeur = ")); Serial.println(indexProchaineValeur);
  Serial.print(F("nombreTotalValeurs = ")); Serial.println(nombreTotalValeurs);

}

void lireBufferCirculaire()
{
  byte n = 1, v;

  if (nombreTotalValeurs == 0) return;

  Serial.println(F("------ LECTURE DU BUFFER CIRCULAIRE ------"));
  // si le buffer est plein on a les plus vieille valeurs entre indexProchaineValeur et la fin du buffer, puis en relisant depuis le début
  // sinon on lit simplement depuis le début

  if (nombreTotalValeurs >= maxValeurs) { // buffer plein
    for (int i = indexProchaineValeur; i < maxValeurs; i++) {
      EEPROM.get(adresseBufferCirculaire + i, v);
      Serial.print(n++); Serial.print(F("\t->\t")); Serial.println(v);
    }
  }

  for (int i = 0; i < indexProchaineValeur; i++) {
    EEPROM.get(adresseBufferCirculaire + i, v);
    Serial.print(n++); Serial.print(F("\t->\t")); Serial.println(v);
  }
  Serial.println(F("-------------------------------------------\n"));

}


void ajouterDansBufferCirculaire(byte v)
{
  Serial.println(F("------ AJOUT DANS BUFFER CIRCULAIRE ------"));
  Serial.print(F("Valeur = ")); Serial.println(v);

  // on range v au bon endroit
  EEPROM.put(adresseBufferCirculaire + indexProchaineValeur, v);

  indexProchaineValeur++;
  if (indexProchaineValeur >= maxValeurs) indexProchaineValeur = 0; // on boucle
  EEPROM.put(adresseProchaineValeur, indexProchaineValeur);

  if (nombreTotalValeurs < maxValeurs) {
    // on met alors à jour le nombre de valeurs correctes ensuite c'est plus la peine
    // le buffer circulaire est plein
    nombreTotalValeurs++;
    EEPROM.put(adresseNombreTotalValeurs, nombreTotalValeurs);
  }
  Serial.println(F("-------------------------------------------\n"));
}


void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(0));
  etablirValeursParDefaut();
}

void loop() {

  // on attend l'envoi d'un 's' pour suivant sur le port série
  if (Serial.available()) {
    int c = Serial.read();
    if ((c != -1) && ((byte) c == 's')) {
      ajouterDansBufferCirculaire((byte) random(0, 256));
      lireBufferCirculaire();
    }
  }
}


en tapant plusieurs fois de suite s voici à quoi la console ressemble


Mot Clef = 0xBADCAFE
Adresse Mot Clef = 0x100
Adresse des valeurs = 0x106
initialisation OK
indexProchaineValeur = 0
nombreTotalValeurs = 0
>>> ici je tape s<<<
------ AJOUT DANS BUFFER CIRCULAIRE ------
Valeur = 120
-------------------------------------------

------ LECTURE DU BUFFER CIRCULAIRE ------
1   ->   120
-------------------------------------------
>>> ici je tape s<<<
------ AJOUT DANS BUFFER CIRCULAIRE ------
Valeur = 131
-------------------------------------------

------ LECTURE DU BUFFER CIRCULAIRE ------
1   ->   120
2   ->   131
-------------------------------------------
>>> ici je tape s<<<
------ AJOUT DANS BUFFER CIRCULAIRE ------
Valeur = 224
-------------------------------------------

------ LECTURE DU BUFFER CIRCULAIRE ------
1   ->   120
2   ->   131
3   ->   224
-------------------------------------------
>>> ici je tape s<<<
------ AJOUT DANS BUFFER CIRCULAIRE ------
Valeur = 161
-------------------------------------------

------ LECTURE DU BUFFER CIRCULAIRE ------
1   ->   120
2   ->   131
3   ->   224
4   ->   161
-------------------------------------------
>>> ici je tape s<<<
------ AJOUT DANS BUFFER CIRCULAIRE ------
Valeur = 130
-------------------------------------------

------ LECTURE DU BUFFER CIRCULAIRE ------
1   ->   120
2   ->   131
3   ->   224
4   ->   161
5   ->   130
-------------------------------------------
>>> ici je tape s<<< MAIS LE BUFFER EST DEJA PLEIN
------ AJOUT DANS BUFFER CIRCULAIRE ------
Valeur = 163
-------------------------------------------

------ LECTURE DU BUFFER CIRCULAIRE ------
1   ->   131
2   ->   224
3   ->   161
4   ->   130
5   ->   163
-------------------------------------------


on voit bien dans le dernier affichage que le buffer s'est rempli et que l'on a décalé les valeurs .on perd le 120 et le 131 qui était en 2 devient la première valeur

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 04, 2018, 07:52 pm
Wahou ...
Toujours aussi Top les réponse :)

J'avais mis de coté la sauvegarde sur eeprom du fait de l'usure mais c'est vrai qu'avec un petit calcul j'aurais pu m'apercevoir que cela était jouable.

Restons donc sur cette option.

En se qui concerne la valeur stocker sur 4 octets :
Je pense que tu parle de mettre sur un octets l'adresse du pixel a dessiner sur le graphique ?
Si c'est bien cela veut dire qu'il faut revoir l'integralité de ma fonction qui dessine les courbe puisque actuelement le PH et Temperature sont stocker sous forme entiere (26.55°=2655 et ph 8.62 = 862)
Puis ensuite la fonction si dessous prend la température avant après et dessine les pixel "manquant" en passant par une fonction MAP qui adapte les mesure (de 2600 a 2800 pour le température) a la taille du graphique (156pixels) :
Code: [Select]
void courbeTemperature9Pixels(int16_t Tprecedent, int16_t Tsuivant) { // dessine la courbe temperature sur 7 jours (boucle de 9 pixels, a lancer 84 fois pour graph complet ****************
  uint16_t val_courbe = Tprecedent;
  uint8_t i = 0;
  float unHuitieme = ((Tsuivant - Tprecedent) / 8.00);
  while (i < 9) { // boucle 9 fois
    val_courbe = val_courbe + (unHuitieme * (i + 1)); // ajoute a la valeur precedent la diference entre les 2 mesures divisé en 9
    if (i == 8) {
      val_courbe =  Tsuivant;
    }
    if (val_courbe < minimumCourbeTemp) {
      val_courbe = minimumCourbeTemp;
    }
    else if (val_courbe > maximumCourbeTemp) {
      val_courbe = maximumCourbeTemp;
    }
    uint8_t pixel_courbe = map(val_courbe, minimumCourbeTemp, maximumCourbeTemp, 0, hauteurEnPixelCourbe);
    variablegraphtemperature7j.addValue(0, (pixel_courbe)); // envoie 1 pixels
    i++;
    delay(10);
  }
  DPRINTF("envoie 9 pixels au graph temperature sur 7 jours"); DPRINTLN();
}


Sincèrement, je suis pas venu vous embeter ici avec la parti graphique parce que je savait que vous pouviez pas tester, mais franchement, j'ai galéré lol
Avec la place dispo dans l'eeprom, je peut stocker mes 1344 octets :/ c'est sur que c'est la simplicité et c'est l'eeprom ne seras pas optimisé mais je ne suis pas coincé de ce coté la contrairement a la mémoire de l'arduino déjà a 76% :(

donc si je pouvais éviter :) mais j'ai peut être oublier de prendre un paramètre en compte ?



Pour l'adressage, si on part du principe que la température lundi 0h est stocker en 1000 par exemple lundi 1h a 1004 lundi 2h a 1008,  ect ...
Pourquoi avoir besoin d'un pointeur a stocker ?
Il ne suffirait pas de lire le jour+heure pour savoir ou écrire ? (exemple mardi 12h = 1144)



ps: merci Breisleach, content que sa plaise.

ps2: on doit y etre au 10 bon point ... J'ai gagné quoi ?  ;D


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 04, 2018, 08:08 pm
Quote
Pour l'adressage, si on part du principe que la température lundi 0h est stocker en 1000 par exemple lundi 1h a 1004 lundi 2h a 1008,  ect ...
Pourquoi avoir besoin d'un pointeur a stocker ?
Il ne suffirait pas de lire le jour+heure pour savoir ou écrire ? (exemple mardi 12h = 1144)
Pour plusieurs raisons - la première étant que   Le calcul de l'adresse ne sera pas simple une fois la semaine remplie, le principe du  circulaire c'est qu'il faut revenir au début :)

Ensuite si vous avez une panne de courant de 2h vous allez vous retrouver avec deux cases non remplies et ça va faire moche sur le graphe - soit vous aurez 0 soit la valeur de 7 jours d'avant qui n'aura pas été écrite. En se souvenant de là où on doit écrire (pas fait dans le code ci dessus) et en fonction du jour vous pouvez savoir (mais c'est des maths un peu compliqués sauf si vous sauvez l'heure de dernière mis à jour aussi en eeprom) qu'il y a eu un problème éventuellement et remplir les cases  avec une valeur par défaut


Quote
ps2: on doit y etre au 10 bon point ... J'ai gagné quoi ?  ;D
De mon temps on gagnait une image :)
(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=247985)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 04, 2018, 08:58 pm
De mon temps on gagnait une image :)
(http://forum.arduino.cc/index.php?action=dlattach;topic=504431.0;attach=247985)
Arfff :( :( :(  
Tout ca pour ca ... :/
lol

De mon temps on gagnait une image :)
De notre temps on est plus iphone ou playstation lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 04, 2018, 09:02 pm
Ensuite si vous avez une panne de courant de 2h vous allez vous retrouver avec deux cases non remplies et ça va faire moche sur le graphe - soit vous aurez 0 soit la valeur de 7 jours d'avant qui n'aura pas été écrite. En se souvenant de là où on doit écrire (pas fait dans le code ci dessus) et en fonction du jour vous pouvez savoir (mais c'est des maths un peu compliqués sauf si vous sauvez l'heure de dernière mis à jour aussi en eeprom) qu'il y a eu un problème éventuellement et remplir les cases  avec une valeur par défaut
Effectivement, l'exemple de code circulaire est très bien mais, outre "c'est des maths un peu compliqués" en cas de coupure, un autre point essentiel me parait compliqué :
Lors de l'affichage du graphique, il faudra, tout comme le graphique 24h que l'heure en bas du graphique coïncide avec les mesure relevé (la dernière mesure devant être a droite avec la date/heure correspondante.
Je ne vois pas comment je pourrait faire vu que la sauvegarde dans l'eeprom se fait sans correspondance avec date/heure
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 04, 2018, 11:21 pm
Oui soit vous afficher sur le graphe les 168 dernières mesures réalisées en croisant les doigts pour qu'il n'y ait pas eu de coupure de plus d'une heure, ou en vous en fichant un peu, ça donne la tendance, soit il faut faire un peu de maths (et conserver quand même en mémoire le dernier index écrit)

Vous devez noter l'heure de démarrage initial de votre système en EEPROM (temps unix sur 4 octets fournis par la RTC) disons que c'est t0. le temps unix (ou posix) est le nombre de secondes écoulées depuis le 1er janvier 1970 00:00:00 UTC jusqu'à l'événement à dater (hors secondes intercalaires).

À l'instant unix t il s'est donc écoulé (t - t0) secondes si vous divisez (division entière) cela par 24x3600ul ça vous donne le nombre de jours et si vous prenez le modulo de ce nombre de jour par 7 ça vous dit à quel jour J (0 à 6) vous en êtes.

vous calculez d'une manière similaire le N° H de l'heure de l'enregistrement de la journée  (je vous laisse réfléchir)

Ensuite le calcul (24 x J + H) vous donne l'index  dans l'EEPROM ou vous devriez écrire. si ce n'est pas la case suivante (attention c'est circulaire) de celle où vous avez écrit la dernière fois alors c'est que vous avez perdu des heures, il faut remplir les cases intermédiaires avec une valeur arbitraire (0 ou maintenir la dernière valeur connue par exemple)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 05, 2018, 03:26 am
Oui soit vous afficher sur le graphe les 168 dernières mesures réalisées en croisant les doigts pour qu'il n'y ait pas eu de coupure de plus d'une heure, ou en vous en fichant un peu, ça donne la tendance, soit il faut faire un peu de maths (et conserver quand même en mémoire le dernier index écrit)
Vous feriez quoi ? ( au vu du nombre de fois ou il va y avoir un reboot / par rapport / difficulté du code a ecrire et la memoire qui va etre utilisé, tout en sachant que cette fonction "graphique" ne me parait pas primordial mais juste "pour info" ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 06, 2018, 04:08 pm
 :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 06, 2018, 10:49 pm
Je me demanderais si c'est bien nécessaire dans un premier temps :)

Est-ce que les 7 derniers jours présentent un intérêt sur la gestion de l'écosystème ou c'est juste comme ça ? Pourquoi 7j et pas 1 mois ou un an ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 06, 2018, 11:17 pm
j'ai envie de dire c'est un +
L'absence de cette fonction est totalement sans incidence sur la gestion du bac.
après c'est utile en cas de problème dans le bac, c'est un premier contrôle, température et ph

Oui, pourquoi pas un ans lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 06, 2018, 11:22 pm
perso si c'était important j'enverrai les données sur un services en ligne et je consulterai par mon iPhone plutôt que d'avoir un écran sur l'unité

Si la consultation à la semaine est vraiment épisodique alors juste écrire sur la carte SD un fichier cvs et le lire et représenter dans Excel si besoin de vérifier l'historique - vous pouvez ainsi stocker des années de données 

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 07, 2018, 08:34 am
L'idée de stocker indéfiniment et voir sur excel me parait un bon compromis, je garderais ainsi que la partie sur 24h "volatile".
faut que je regarde comment ecrire en continu dans un .csv et sans reprendre a zero en cas de coupure.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 07, 2018, 09:11 am
Écrire un csv est trivial

Vous décidez du format d'une ligne; quelles valeurs vous souhaitez écrire - et ensuite c'est juste des print de ces valeurs séparées par des virgules ou des tabulations Et vous finissez par un retour à la ligne "\r\n"

La première écriture pourrait-être des étiquettes pour les colonnes pour que ça fasse joli sous Excel et faciliter les tris par étiquette au lieu de lettre de colonne

Ma recommendation serait de commencer par mettre aussi la date et l'heure sur chaque ligne éventuellement avec aussi l'heure UNIX - ça vous facilitera la vie sous Excel sans écrire de formules pour faire des tris et des graphes

 Il faut bien sûr gérer ça correctement donc vérifier si le fichier existe. Si le fichier n'existait pas alors il faut ouvrir le fichier en vérifiant que ça s'est bien passé et écrire la ligne d'en tête avant la première ligne de données, sinon juste les données à la fin du fichier et une fois la ligne écrite fermer le fichier.

Si vous avez 100 caractères  sur une ligne  - soit 100 octets - vous pouvez stocker plusieurs milliers d'années de données toutes les heures sur une carte SD de 4Go ou 80 ans si vous écrivez toutes les minutes avant que la carte soit pleine (elle plantera avant :) )

Bien sûr il faut utiliser la librairie SDFat et pas la libraire SD standard



 
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 07, 2018, 10:14 pm
Une fois de plus merci jean Marc pour ce retour.
Mon déménagement approche donc carton et tout le reste ...
On range l'électronique  :smiley-confuse:
je doit mettre le projet en Standby :(
Si tout ce passe bien, dans ~10 jours je reprendrait le projet.
Mais ne vous inquiété pas, je vous ferait profité de l'installation du nouvelle Aqua pendant ce lapse de temps  ;)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 07, 2018, 11:24 pm
Bon déménagement !!
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 08, 2018, 02:57 am
merci
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Mar 09, 2018, 01:43 pm
Boun's bonjour.

Ouep bon courage et bon emménagement dans ta futur demeure.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 10, 2018, 08:56 am
Merci
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Mar 17, 2018, 11:56 pm
Bonsoir,

Des petites NEWS :)
Déménagement fini vendredi, c'était compliqué

La fin du 400l (http://www.recifal-france.fr/400l-de-djbouns-t22449-414.html#p598186)

Le début (chaotique) du 430l (http://www.recifal-france.fr/430l-de-djbouns-t34485.html#p597886)

J'esperre reprendre le projet dans moins de 10 jours, si tout va bien ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Mar 18, 2018, 10:16 am
chaotique est un faible mot !!! courage
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Mar 23, 2018, 11:51 am
Boun's, J-M-L bonjour.

Ouep Boun's c'est pas peu dire comme début, la tu manque sérieusement de chance, mais sur que cela vas devenir un beau bocal.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on May 04, 2018, 04:42 pm
Bonjour tout le monde, je passe juste vous faire un petit coucou.
Comme vous l'avez remarquer, 2 mois ou le projet est au point mort.
Dans un premier temps a cause de mon déménagement + nouvelle aquarium qui a pris beaucoup de temps et d'énergie mais a peine fini, j'ai eu un "petit" problème de santé.
J'ai tout le temps que je veux mais je ne suis pas en mesure de rester concentré.
Si tout se passe bien, j'espère que se seras réglé dans ~2 mois.

Le projet aboutira :)

Dsl de vous faire patienté.

a+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: lesept on May 04, 2018, 05:11 pm
Le début (chaotique) du 430l (http://www.recifal-france.fr/430l-de-djbouns-t34485.html#p597886)
et, dans le lien :

Quote
4e bac en 6 ans ...
Et celui la démarre très mal ...
Ça a commencer par un retard de fabrication, du coup j'ai eu le bac mardi soir et il fallait que jeudi soir tout soit transféré.
Quand je pense à tous les étudiants qui passent demander de l'aide pour un seul bac, alors que tu en as déjà 4 !!! (fin mode taquin)

Bon rétablissement et bon courage !
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on May 04, 2018, 05:41 pm
Bon courage !
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jun 28, 2018, 11:14 am
Bonjour a tous,

L'opération est passer mais je doit encore me reposer un bon moment ...

Quand cela le permettait j'ai bosser un peu sur le plus simple, le moins prise de tete, le pcb :)
Je pense être a la version final, encore quelque petite modif et test de composant et sa seras bon.

Dans les grande ligne :


Je vous joint un aperçu du pcb (https://image.noelshack.com/fichiers/2018/26/4/1530176449-pcb.jpg)




Je voudrait aborder un autre aspect de se projet afin d'avoir votre avis ...

J'ai été approcher par le directeur d'une société  (création de pièce en alu ....) passionné de récifal et travaillant sur l'automatisation de l'aquarium (rampe éclairage principalement,  fabrication du dissipateur en aluminium :) et toute la partie électronique.
Son but étant claire pour moi, commercialiser ces créations.
Son intérêt en vers moi et mon projet  me paraissant "bizarre" (je suis un simple amateur comparer a se que j'ai vu de ces réalisations digne d'une société professionnel) je n'est pas donner suite.

Du coup, je me questionne beaucoup sur ce que pourrait faire des personnes de mon projet.
Se l'accaparer ? déposer un "brevet" ? en tirer des bénéfices ?
Cela me perturbe assez, a ne plus savoir comment je doit partager se projet ...


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jun 28, 2018, 10:00 pm
Welcome back!!!

Reposez vous - sans vous poser des questions existentielles sur votre code ! (Sinon rajoutez partout que c'est en GPL V3 dans vos code sources)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jun 29, 2018, 10:20 am
Content de te vous relire JM  :)
être devant un ordi est reposant :)
entre 2 mal de tete je poursuit le pcb et quand j'ai retrouver mes esprits jme met sur la dernière long ligne droite du code ... (la reprise va etre tres difficile :/)
(déjà 1 ans et 2 mois que j'ai démarrer se projet)

Pour le GPL V3, la lecture ma permis d'en comprendre le principe mais je n'ai pas compris se qu'il faut faire pour etre sous cette license, déclaration ? ou juste l'indiquer dedans ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jun 29, 2018, 01:39 pm
Pour le GPL V3, la lecture ma permis d'en comprendre le principe mais je n'ai pas compris se qu'il faut faire pour etre sous cette license, déclaration ? ou juste l'indiquer dedans ?
vous  :)  Tu peux lire ce document (https://www.gnu.org/licenses/gpl-howto.fr.html)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jun 29, 2018, 06:08 pm
 ;) je préfère, depuis le temps que l'on échange  :)


La liste des choses a faire est assez simple a mettre en place.
Il ne semble pas y avoir quoi que se soit a "déposer"
La ou je ne comprend pas, c'est que n'importe qui peut récupérer le code, le modifier (jusque la, OK), enlever les mentions et déposer un "vrai" copyright ?
Cette lecture me donne l'impression que la GPL est basé sur la bonne fois de chacun ...


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jun 30, 2018, 09:07 am
Il suffit de le publier à un endroit public, genre github, ce qui datera la mise à dispo et si le code est piqué par quelqu'un qui ne respecte pas votre license alors vous pourriez l'attaquer. attention ça n'empêche pas d'autres personnes de lancer des produits avec votre code, la communauté libre c'est le partage, mais ça les obligera aussi à publier tout leur code de tout leur produit et donc rester dans l'esprit

En pratique lancer un produit commercial sur du code piqué comme cela plus ou moins au hasard et qui dépend de quelqu'un d'autre pour fixer les bugs est le meilleur moyen de perdre de l'argent
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jun 30, 2018, 11:05 am
ok ...
il y a déjà plusieurs mois que j'ai déjà crée un compte github pour partager l'aquabouns.
Donc tout le monde pourras prendre le code, l'utiliser, le modifier et même vendre un produit commercial le contenant comme source mais il seras dans l'obligation de toujours laisser le code modifier a disposition ...

Sympa cette License de "partage"
Ok, je suis un peu moins inquiet du coup :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jun 30, 2018, 03:31 pm
Oui - il faut juste vous assurer que chaque  fichier  le texte qui va bien en en tete
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Jul 02, 2018, 01:25 pm
Bouns heureux d'avoir de tes nouvelles et d'être de retour sur ton projet.

Bon rétablissement et vas y cool.

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 03, 2018, 02:52 pm
Merci Breisleach

J'ai de la chance, assis sa va alors sa me permet d'avancer et ça m'occupe :)


Je crois me souvenir avoir croiser quelqu'un ici qui avait des connaissance en électronique.
Je rencontre un petit problème avec mon système de "relais alim/batterie" en cas de coupure
Si il est toujours la, qu'il me fasse un petit signe :)  (que j'encombre pas le poste "code" avec l'électronique :) )

J'ai commencer a relire le code (pour re comprendre lol) et j'ai fait quelque bidouille
La page "horloge" est ok (modif et sauvegarde) mise a part le fait des mois en 30/31 jours qui n'est pas pris en compte.
(https://image.noelshack.com/minis/2018/27/2/1530625894-img-20180703-150522.png) (https://www.noelshack.com/2018-27-2-1530625894-img-20180703-150522.jpg)


et puis une petite liste de problème :
sauvegarde ne fonctionne plus (enregistre le premier paramètre sur tout les suivant)(je vais donc relir tout les poste qui en parlais ici pour trouver d'ou vient le problème)

Problème avec les sonde PH, quand l'ecran nextion se met en veille(10min) il y a moins de chute de tension de le CI (4.80v>5v) du coup les resultat des sonde ph varie de 0.5. (je cherche comment faire ...)

Partie graphique, le code étant déjà assez long je met se point de coté mais il y a de forte chance pour que le graphique ne soit visible que par le wifi et non pas via l'écran nextion.

Toute la partie gestion de floteur a ecrire, il y en auras 5: niveau constant, niveau écumeur, sécurité, niveau bas eau osmose, niveau haut godet écumeur)

après ça, il resteras a me remémorer et inclure toute la partie wifi et gsm ...

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 03, 2018, 06:29 pm
Pour le problème de sauvegarde, cela ne vient pas de la partie du code "sauvegarde".

Lorsque je lance la sauvegarde, l'arduino demande la valeur au nextion.
Nextion repond exemple 100 et l'arduino le stock dans un uint8_t number
number a la bonne valeur.
number est ensuite copier : brassage1 = number.
Puis l'arduino lance une deuxième requête et la, la réponse est 100 alors que ce n'est pas la valeur demandé.
Toute les requête suivante obtienne le même resultat.
comme si nextion n'avait pas eu le Temp de répondre ou l'arduino de les lire.
Pourtant le baud rate est a 115200 et pas de problème quand c'est l'arduino qui envoie une variable au nextion ...

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 03, 2018, 07:20 pm
 :( 
Quand l'ecran est brancher directement sur l'arduino ça a l'air OK
Des qu'il est sur le CI sa merde ...
pourtant il n'y a que 54mm de longueur de piste ...
Arff le cuivre ralenti la transmission ?  :smiley-confuse:

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 04, 2018, 11:32 am
ça semble résolu ...
J'ai mis une couche de vernis sur les pistes, pour le moment plus de problème .... ouf ...

Petite video (https://youtu.be/RXGwhhRWrbg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 04, 2018, 05:38 pm
J'ai commencer a bien me remettre dans le code, c'est repartie :)
j'essai au max d'optimiser dans un premier temps car la place manque :/
Et principalement sur la partie affichage mais pas facile avec le nextion.

J'ai pas mal de fonction identique mais avec la bibliothèque nextion et les déclarations je ne trouve pas comment faire.

declaration :
Code: [Select]
NexButton boutonomoinsoscillo1min = NexButton(9, 8, "b31");
NexButton boutonplusoscillo1min = NexButton(9, 11, "b34");


Par exemple j'ai :
Code: [Select]

void boutonoscillo1min(void *ptr) {
  valeuroscillo1min.getValue(&number);
boutonoscillo1();
}
void boutonoscillo1max(void *ptr) {
  valeuroscillo1max.getValue(&number);
  boutonoscillo1();
  }
void boutonoscillo1(){
positionOscillo1 = number;
  oscillo1.write(positionOscillo1);
  affichagedegreoscillo1.setValue(positionOscillo1);
}


et je voudrait plutot faire unpeu comme ca :
Code: [Select]
void boutonoscillo(void *ptr,[b]MonNomDeBoutton[/b]) {
  MonNomDeBoutton.getValue(&number);
positionOscillo1 = number;
  oscillo1.write(positionOscillo1);
  affichagedegreoscillo1.setValue(positionOscillo1);
}


dans la biblioteque il y a :
Code: [Select]
NexVariable::NexVariable(uint8_t pid, uint8_t cid, const char *name)
    :NexTouch(pid, cid, name)
{
}

uint32_t NexVariable::getValue(uint32_t *number)
{
    String cmd = String("get ");
    cmd += getObjName();
    cmd += ".val";
    sendCommand(cmd.c_str());
    return recvRetNumber(number);
}


se qui voudrait dire qu'il prend l'adresse des déclaration et non le nom donné ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 10, 2018, 05:23 pm
Concernant les échanges tx/rx  ecran/arduino.
quand l'écran est en veille, j'ai l'impression que l'arduino n'aime pas et fini par "beuger".
Quand l'arduino envoie des donner, attend t il un retour de l'écran sur la réception de ces donner ? si oui, cela explique un beug de l'arduino ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 10, 2018, 06:57 pm
pour info,

Je cherchait depuis un moment a avoir un resultat stable dans la mesure du PH.
Je n'était pas satisfait des module ph 4502c qui me donnait un ph +/- 0.2
J'ai donc cherche et ce module ne semble qu'être qu'un convertisseur 5v>3.5 pour la sonde puis un amplis

J'ai donc fais le montage suivant avec juste la sonde (plus de module):
arduino 3.3v > résistance ajustable 103 > sonde ph > condensateur ceramique 103 > IN analogique arduino.
puis le code suivant :
Code: [Select]
const byte pinInPhRac = A0;    // Connect the sensor's Po output to analogue pin 0.

// Variables:-
float phRac;
float bas = 9999;
float haut = 0;

uint8_t moyenneGlissante = 0;
boolean moyenneGlissanteON = false;
const byte nbrDeMesure = 20;
uint16_t moyennePhRac[nbrDeMesure];
void setup()
{
  Serial.begin(74880);
}

void loop()
{
  moyennePhRac[moyenneGlissante] = map(analogRead(pinInPhRac), 755, 557, 401, 918);
  moyenneGlissante++;
  if (moyenneGlissante == nbrDeMesure) {
    moyenneGlissanteON = true;
    moyenneGlissante = 0;
  }
  if (moyenneGlissanteON == true) {
    for (int i = 0; i < nbrDeMesure; i++) {
      phRac += moyennePhRac[i];
    }
    phRac = phRac / (nbrDeMesure * 200);
    Serial.print("ph actuel : "); Serial.println(phRac);
    if (phRac < bas) {
      bas = phRac;
    }
    if (phRac > haut)    {
      haut = phRac;
    }
    Serial.print("ph bas: "); Serial.println(bas);
    Serial.print("ph haut: "); Serial.println(haut);
    Serial.println();
  }
}


le meilleur compromis a été avec une moyenne rotative sur 20 mesure, j'arrive a un resultat variant de +/- 0.02
une moyenne rotative sur 10 mesure donnait +/- 0.05
Et pour avoir des mesure +/- 0.01 il fallait monter a 50 mesure.

Ce montage a l'air satisfaisant dotant plus qu'il fait économiser 15€ par module (2 module sur mon projet)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 10, 2018, 10:38 pm
Concernant les échanges tx/rx  ecran/arduino.
quand l'écran est en veille, j'ai l'impression que l'arduino n'aime pas et fini par "beuger".
non ça ne devrait absolument pas jouer (si vous parlez du PC. sur le nextion je ne sais pas)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 10, 2018, 11:32 pm
non je parle bien du nextion.
J'ai mis une veille au bout de 10 min. et l'arduino fini toujours par beuger.
Donc je me demandait  , lorsque il y a des envoie de donner, es que l'arduino envoi bêtement ou es qu'il détecte qu'il n'y a plus de réponse en face et beug.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 11, 2018, 05:18 am
Je ne sais pas - je n'utilise pas ce composant - faudrait regarder si la librairie attend un retour

Il se peut que ça fonctionne tant que le buffer d'entrée du nextion n'est pas plein et ensuite il perd des données et la synchro ne se ferait plus bien  au moment où il se réveille? (Pure hypothèse)

Au lieu de désactiver l'écran si vous aviez une fonction qui le met au noir ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 11, 2018, 10:40 am
j'ai déjà jeter un coup d'œil a la bibliothèque mais je n'est rien trouvé mais je ne suis pas spécialiste :)
Il y a bien une fonction pour le rétroéclairage, le problème qui va se poser est que si l'on"Click" sur l'écran sombre a l'endroit ou il y a un bouton, cela va réveiller l'écran mais aussi actionner la fonction.
Il faudrait peut être basculer sur une page "stand-by", ecran sombre ou la totalité de l'écran est un bouton mais cela veut dire que c'est l'arduino qui doit gérer cela au lieu que se soit l'écran lui même ...
Encore une fonction qui va me prendre énormément de temps  :smiley-confuse: et de mémoire sur l'arduino
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 11, 2018, 11:22 am
Quote
Je ne sais pas - je n'utilise pas ce composant - faudrait regarder si la librairie attend un retour
Oui. Voir la fonction recvRetCommandFinished (https://github.com/itead/ITEADLIB_Arduino_Nextion/blob/master/NexHardware.cpp).
Mais le timeout est court : 100ms.

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 11, 2018, 04:43 pm
Bonjour hbachetti,

Code: [Select]
bool  recvRetCommandFinished ( uint32_t timeout)
{   
    bool ret = false ;
    uint8_t temp [ 4 ] = { 0 };
   
    nexSerial. setTimeout (timeout);
    if ( sizeof (temp)! = nexSerial. readBytes (( char *) temp, sizeof (temp)))
    {
        ret = false ;
    }

    if (temp [ 0 ] == NEX_RET_CMD_FINISHED
        && temp [ 1 ] == 0xFF
        && temp [ 2 ] == 0xFF
        && temp [ 3 ] == 0xFF
        )
    {
        ret = vrai ;
    }


et pour toi cela explique le plantage de l'arduino ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 11, 2018, 10:34 pm
Absolument pas.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 11, 2018, 11:39 pm
ok merci  :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 12, 2018, 02:16 am
Lire ce post sur leur forum (http://support.iteadstudio.com/support/discussions/topics/11000012949) ==> comment est géré l'écran ? en dim ou en sleep et avec quels params?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 12, 2018, 05:04 pm
Merci Jean marc cela rejoint mes précédentes lectures.
J'ai donc :
Crée une page "standby" avec un bouton couvrant toute la surface
Dans la page menu, un timer (1min)
Dans chaque bouton de l'écran menu j'ai ajouter une ligne de commande qui remet le timer a zéro des que le bouton en cliquer et remet le rétroéclairage a son niveau "Default" si ce n'est pas le cas
Si aucune activité au bout d'une minute, le luminosité décent progressivement et quand a zéro, bascule sur la page standby et envoi cette info a l'arduino.
L'arduino stop toute mise a jour car plus sur la page "menu"
Quand on touche l'écran "noir" de la page standby, envoie info a l'arduino qui demande d'afficher la page menu et met tout les champs a jour.
Un fois celle ci charger le nextion remet la luminosité a "Default"

depuis ce matin pas de beug, je laisse tourner pour être sur ...

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 13, 2018, 05:50 am
Cool

Mais il ne semblait - à la lecture de leur doc - que vous n'aviez pas vraiment Besoin de le gérer vous même et que des variables d'environnement permettait de gérer cela
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 13, 2018, 08:18 am
la traduction laisse pensé que oui
Précédament j'avais thsp = 60 + thup = 1
sauf que des que l'écran passe en mode "thsp" l'arduino fini par beuger même ci pour hbachetti cela n'en n'est pas la cause.
pour le mode sleep, il faut le gérer le passage dans se mode manuellement, donc faire un timer ... comme je l'ai fait sauf qu'il est préciser "mais la mise à jour d'autres variables pendant le sommeil peut s'attendre à des problèmes." j'ai déjà assez de problème  :smiley-lol:

Ce que j'ai fait le met pas l'écran en veille mais éteint le rétroéclairage et passe sur une page "bouton" tout en prévenant l'arduino qui stop toute communication.

depuis que ces en place, pas un seul beug  :smiley-cool:


Pour le reste du projet, je voix le bout du tunnel concernant la partie arduino/ecran
Il me reste toute la partie PH que je pensait sur la bonne voix mais qui en faite n'est pas au point.
Le montage plus code est OK pour un PH stable mais dérive des lors que le ph change et le calibrage est impossible. j'attend  quelque composant pour me remette dessus.

hormis ça, il me reste 4 flotteurs a cree/coder puis il faut que j'integre la partie SMS et WIFI que l'on a vu il y a plusiseurs mois.
La partie SMS devrait être la plus simple il faut juste que je me remette dans les "char" (comme ben-hur  :smiley-eek:  :-X )
La partie wifi va demander un gros travaille car il faut déjà intégrer les échanges puis complètement revoir la partie html, un gros morceau  :smiley-confuse:

C'est sur la bonne voix  :smiley-grin:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 13, 2018, 11:03 am
Encore du pain sur la planche mais c'est aussi ça qui est intéressant !!
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 14, 2018, 01:13 am
Encore du pain sur la planche mais c'est aussi ça qui est intéressant !!
:o  :smiley-roll-sweat:
Mais effectivement  ;D  je vais donc avoir besoin d'aide 8)

La partie Sms a bien été intégré en fonctionne
voici le retour du mais
J'ai un problème avec le numéro de téléphone sauvegardé.

a la sauvegarde le numéro est bien enregistré mais dans le fichier il y a un passage a la ligne.
Si je retire manuellement dans le fichier txt ce saut de ligne tout fonctionne.
C'est vraiment ce passage a la ligne qui fou tout en l'air.

J'ai beau chercher, je n'est ajouter aucun passage a la ligne, que un caractere de fin.

La partie recup du nextion
Code: [Select]
void enregistrerTel(void *ptr) {
  uint8_t i = 0;
  effaceBuffer();
  valeurtel.getText(bufferTexte, maxbufferTexte);
  strncpy(numero2tel, bufferTexte, maxnumero2tel);
   numero2tel[maxnumero2tel] = '\0';
  ecritSurSd("numero2tel.txt", numero2tel);


et sauvegarde sur sd
Code: [Select]
void ecritSurSd(char * nomDuFichierTxt, char * donneeAEcrireSurSD) {// *******************************************************************************************************************************************
  SD.remove(nomDuFichierTxt);
  myFile = SD.open(nomDuFichierTxt, FILE_WRITE);
  if (myFile) {
    myFile.println(donneeAEcrireSurSD);
  } else {
    DPRINTF("Erreur d'écriture dans le fichier "); DPRINTLN(nomDuFichierTxt); DPRINTLN();
  }
  myFile.close();
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 14, 2018, 01:13 am
Le retour charriot à la fin dans le fichier provient du
myFile.println(donneeAEcrireSurSD);

Faudrait just faire un print mais dans l'absolu la fonction de lecture ne devrait pas tenir compte de la fin de ligne et juste ignorer tout ce qui n'est pas des chiffres par exemple

Sinon juste par acquis de conscience, vous aviez bien déclaré la taille du buffer comme celà:
char numero2tel[maxnumero2tel+1];
N'est-ce pas ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 14, 2018, 01:15 am
ba oui, comme le serial.println ... pfff
2h de perdu :(
merci
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 14, 2018, 12:08 pm
Sinon juste par acquis de conscience, vous aviez bien déclaré la taille du buffer comme celà:
char numero2tel[maxnumero2tel+1];
N'est-ce pas ?
Code: [Select]
const uint8_t maxnumero2tel = 15;
Code: [Select]
char numero2tel [maxnumero2tel + 1];

:)

C'était bien fait et sa fait parti des choses vérifier 10 fois avant de comprendre le problème.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 14, 2018, 12:18 pm
En général on procède plutôt comme ceci :

Code: [Select]

#define MAXNUMERO2TEL    15
char numero2tel [MAXNUMERO2TEL + 1];


Car dans ce cas, la macro MAXNUMERO2TEL n'occupe aucune place en mémoire.

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 14, 2018, 12:41 pm
C'est valable pour tout les const uint8_t ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 14, 2018, 12:46 pm
En général on procède plutôt comme ceci :
Code: [Select]

#define MAXNUMERO2TEL    15
char numero2tel [MAXNUMERO2TEL + 1];

Car dans ce cas, la macro MAXNUMERO2TEL n'occupe aucune place en mémoire.
En théorie ce que vous dites est correct mais c'est oublier l'étage d'optimisation de code du compilateur. Comme on a pris soin de d'utiliser const le compilateur sait que ça ne va pas changer et n'alloue pas de mémoire et remplace directement par la valeur dans le code généré. (Idéalement il faudrait utiliser  const byte plutôt que int. ça aiderait encore plus le compilateur)

D'autre part quand on fait des define comme cela On laisse moins de chance au compilateur de faire des optimisations car c'est de la substitution de texte et il prend donc en mémoire la place d'un int signé (2 octets sur uno, 4 sur esp par exemple) pour les calculs que le préprocesseur ne sait pas faire (pour le +1 le compilateur ne génère pas de code il sait que c'est 16 le résultat). En utilisant une "variable constante" ça vous donne l'avantage de pouvoir aider le compilateur en typant la constante.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 14, 2018, 12:56 pm
Un const a forcément une adresse en mémoire. Par contre il est plutôt situé dans la zone code.

Sinon, on ne pourrait pas écrire ceci :

Code: [Select]

void loop() {
  // put your main code here, to run repeatedly:
  char s[30];
  const uint8_t maxnumero2tel = 15;
  char numero2tel [maxnumero2tel + 1];
  sprintf(s, "addr=%x val=%d", &maxnumero2tel, maxnumero2tel);
  Serial.println(s);
  delay(1000);
}

// addr=8fb val=15

***** EDIT *****

En déclaration globale, on retrouve son adresse avec avr-objdump :

Code: [Select]

const uint8_t maxnumero2tel = 15;
char numero2tel [maxnumero2tel + 1];
void loop() {
  // put your main code here, to run repeatedly:
  char s[30];
  sprintf(s, "addr=%x val=%d", &maxnumero2tel, maxnumero2tel);
  Serial.println(s);
  delay(1000);
}

// addr=112 val=15

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 14, 2018, 03:26 pm
Un const a forcément une adresse en mémoire. Par contre il est plutôt situé dans la zone code.
@hbachetti - C'est encore bien pensé mais.... en fait ce que vous voyez c'est que si le code ne peut pas être optimisé alors le compilateur va allouer effectivement de la  mémoire.... C'est ce que vous faites ici.

Le compilateur voit que vous avez une référence vers la constante par le biais d'un pointeur et donc qu'il a besoin d'une zone de stockage et à partir de là l'optimiseur de code ne peut plus décider que votre constante ne sert à rien. Il faut comparer ce qui est comparable, Votre programme n'a pas d'équivalent avec un #define.


Prenez un code de blink par exemple:
Code: [Select]
const byte pinNb = 13;

void setup() {
  pinMode(pinNb, OUTPUT);
}

void loop() {
  digitalWrite(pinNb, HIGH);
  delay(1000);
  digitalWrite(pinNb, LOW);
  delay(1000);
}
compilé sur un UNO ça me donne

Sketch uses 928 bytes (2%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.


Maintenant compilez la version avec un #define
Code: [Select]
#define pinNb 13

void setup() {
  pinMode(pinNb, OUTPUT);
}

void loop() {
  digitalWrite(pinNb, HIGH);
  delay(1000);
  digitalWrite(pinNb, LOW);
  delay(1000);
}


et vous verrez à la compilation:

Sketch uses 928 bytes (2%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.


On voit bien qu'à programme équivalent la mémoire programme et SRAM utilisées sont identiques.

de plus si vous effectuez une avr-objdump -S des deux programmes ci dessus et que vous les comparez vous verrez qu'ils sont strictement identiques ==> le compilateur a généré à 100% le même binaire.


En pratique et pour bien faire, le bon usage serait d'utiliser constexpr byte pinNb = 13; (avec un static en plus ou pas) et pas const byte pinNb = 13; mais les vieux usages persistent et les compilateurs étant plutôt doués pour déterminer ce qui est constant et peut être calculé ou optimisé à la compilation, l'adoption de constexpr (qui date de C++11) n'a pas eu vraiment lieu.

La bonne pratique de programmation c'est de fournir un maximum d'information sur vos intentions au compilateur. un #define présente l'inconvénient majeur de simplement offrir de la substitution de texte et ensuite le lancer la compilation, ce qui rend le debug et la compréhension des message d'erreurs compliqués. La notion de const ou constexpr présente l'avantage sémantique d'informer le compilo sur le type attendu et sur votre intention d'invariabilité, donc le compilateur vous avertirait si vous essayez de modifier un contenu qui est supposé être constant.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 14, 2018, 07:09 pm
Il est cependant très habituel en C / C++ de définir la taille d'un tableau par un #define.
Mon expérience des noyaux LINUX et BSD sans doute ...

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 14, 2018, 07:13 pm
Il est cependant très habituel en C / C++ de définir la taille d'un tableau par un #define.
Mon expérience des noyaux LINUX et BSD sans doute ...

@+

oui oui c'est fréquent. Mais c'est moins "informatif" pour le compilateur, donc une moins bonne pratique (qui date du temps où effectivement les optimiseurs ne pouvaient pas virer la variable)


de plus nombreux sont les débutants qui oublient les parenthèses dans les define... par exemple dans ce code on pourrait penser de prime abord que GRAND_BUFFER1 et GRAND_BUFFER2 sont identiques la multiplication étant commutative 2*PETIT_BUFFER_AVEC_NULL ou PETIT_BUFFER_AVEC_NULL*2 devraient être identiques...

Code: [Select]
#define PETIT_BUFFER 10
#define PETIT_BUFFER_AVEC_NULL PETIT_BUFFER+1
#define GRAND_BUFFER1 2*PETIT_BUFFER_AVEC_NULL
#define GRAND_BUFFER2 PETIT_BUFFER_AVEC_NULL*2

void setup() {
  Serial.begin(115200);
  Serial.println(PETIT_BUFFER);
  Serial.println(PETIT_BUFFER_AVEC_NULL);
  Serial.println(GRAND_BUFFER1);
  Serial.println(GRAND_BUFFER2);
}

void loop() {}
et pourtant quand on lance le code on obtient

10
11
21      parce que 2*10+1
12      parce que 10+1*2

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 14, 2018, 07:44 pm
Je veux bien mais pratiquant le C depuis 30 ans je préfère privilégier les habitudes en vigueur dans les mondes que je fréquente habituellement et donc la lisibilité pour les communautés auxquelles j'appartiens, LINUX en particulier.

Bien entendu cela suppose certaines précautions, les parenthèses entre autres, mais cela devient vite un réflexe.
Je suis parfaitement conscient que cela équivaut à un nivellement par le bas, mais on n'a pas toujours un compilateur moderne à notre disposition.

Nous avons aussi l'habitude d'utiliser l'éditeur vi, malgré son âge vénérable, car souvent il est disponible sur des plateformes même très rudimentaires.



@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 14, 2018, 07:50 pm
que de bon souvenirs avec vi :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 14, 2018, 10:59 pm
Je ne participerais pas a ce debat sur les entraille du codage qui me depasse :)

Par contre,
Idéalement il faudrait utiliser  const byte plutôt que int.
uint8_t est definni dans stdint.h et byte dans l'arduino mais tout deux corresponde a un unsigned char.
Donc l'utilisation de l'un ou de l'autre est équivalent sauf que byte évite au compilateur arduino de "modifier" le uint8_t en byte ? si ces ca, cela n'est valable que pour le codage via le compilateur arduino ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 14, 2018, 11:20 pm
uint8_t ça fait partie de la norme depuis C++11 (unsigned integer type with width of exactly 8 bits)

byte c'est un truc arduino pour dire uint8_t.. en gros il traine quelque part dans un des fichiers (https://github.com/esp8266/Arduino/blob/fcf2ac5d3de6c17fe177e16ccd1a2789826c2aa0/cores/esp8266/Arduino.h#L191) (Arduino.h) un truc du genre
Code: [Select]
typedef uint8_t byte;

donc si vous programmez dans l'environnement  arduino vous pouvez utiliser byte sinon le bon usage c'est uint8_t
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 01:41 am
donc si vous programmez dans l'environnement  arduino vous pouvez utiliser byte sinon le bon usage c'est uint8_t
(http://m.memegen.com/yczjym.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 01:42 am
Code: [Select]
typedef uint8_t byte;
on etait pas loin
Code: [Select]
typedef  uint8_t octet;
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 02:20 am
Oh purée...
Oui bon les vous c'est parce que je suis de la vieille école... ça vient tout seul plutôt que le tu...

Sinon j'écris en anglais et j'utilise  "you" et que ça veut dire tu ou vous comme you want
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 02:22 am
on etait pas loin
Code: [Select]
typedef  uint8_t octet;
vous avez une version localisée du langage??? (si (tu|vous) clique(s|z) sur mon lien c'est bien byte)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 09:48 am
o ouai , laisse tomber ... j'ai le traducteur google qui ma traduit la page tout seul.
Quel boules
Sa me paraissait bizarre que t'es pas raison  :smiley-grin:  :smiley-grin:  :smiley-grin:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 01:05 pm
J'ai un beug sur l'extraction de la carte sd alors que tout fonctionnait parfaitement

les declarations:
Code: [Select]
char ssid[maxSsid + 1];
char mdp[maxMdp + 1];
char numero2tel [maxnumero2tel + 1];
const uint8_t maxSsid = 30;
const uint8_t maxMdp = 30;
const uint8_t maxnumero2tel = 15;


l'appel de la fonction:
Code: [Select]
lisSurSd("ssid.txt", ssid);
  lisSurSd("mdp.txt", mdp);
  lisSurSd("numero2tel.txt", numero2tel);


la fonction :
Code: [Select]
void lisSurSd(char * nomDuFichierTxt, char *donneeLueSurSD) {
  const uint8_t lectureMAX = 30;
  char lecture [lectureMAX + 1];
  myFile = SD.open(nomDuFichierTxt);
  DPRINTF("Ouverture de :"); DPRINTLN(nomDuFichierTxt);
  if (myFile) {
    int i = 0;
    while (myFile.available()) {
      if (i <= lectureMAX) {
        lecture[i] = myFile.read();
        i++;
      }
      else {
        lecture[i] = ('\0');
        break;
      }
    }
    strncpy(donneeLueSurSD, lecture, lectureMAX);
    donneeLueSurSD[lectureMAX] = '\0';
  } else {
    DPRINTF("Erreur a l'ouverture du fichier ");
  }
  myFile.close();
}


et le resultat :
Code: [Select]
Extraction des infos presentes dans la carte SD...
Ouverture de :ssid.txt
Le fichier : ssid.txt a bien ete lu =testssid⸮⸮⸮⸮///
Ouverture de :mdp.txt
Le fichier : mdp.txt a bien ete lu =testmdp///
Ouverture de :numero2tel.txt
Le fichier : numero2tel.txt a bien ete lu =0678912345⸮⸮///


Pas de probleme avec testmdp
Mais testssid et 06** son completer par "⸮⸮" jusque a 13 caracteres
Pourquoi ? pourquoi pas testmdp ?

Les fichier sur sd son correct, pas d'espace ni saut de ligne après les caractères.
Je les ai tout de même effacer et recommencer 2 fois, sans changement.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 04:00 pm
ben oui... c'est normal - vous ne mettez pas le '\0' exactement à la fin de ce que vous avez lu quand le fichier contient moins de lectureMAX caractères... (vous en mettez bien un tout à la fin du tableau mais c'est pas suffisant, il faut qu'il soit pile à la fin de ce que vous avez lu)

en plus vous faites un strncpy(donneeLueSurSD, lecture, lectureMAX); sans vous assurer que ça rentre dans le tableau que vous avez reçu en paramètre (par exemple comme maxnumero2tel vaut 15 vous risquez de mettre le bazar dans la mémoire puisque lectureMAX vaut 30...

idéalement il faudrait passer à votre fonction la taille max du tableau et vous pouvez directement écrire dedans au lieu d'avoir un tableau intermédiaire qui prend de la mémoire sur la pile pour rien.

je ne suis pas sur mon mac mais je vais essayer de vous taper du code à tester

notez aussi qu'il vaut mieux pour la lisibilité déclarer les constantes de taille avant de les utiliser pour les tableaux
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 04:05 pm
J'avais effectivement penser a la taille de numero2tel mais vu que le problème sur testssid je me suis dit que cela devait plutôt être un problème avec le caractere de fin. j'étais sur la bonne piste.

Se que je comprend pas du tout ces pourquoi cela a fonctionné correctement depuis des mois (la lecture/écriture fonctionnait parfaitement jusque a il y a deux jour :/)


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 04:08 pm
notez aussi qu'il vaut mieux pour la lisibilité déclarer les constantes de taille avant de les utiliser pour les tableaux
Je n'ai pas fait le copier coller dans le bon sens.
Les const uint8_t se trouve dans mon .h alors que les char sont dans mon .cpp
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 04:22 pm
tenez voici un bout de code à tester je ne suis pas sur mon ordi donc difficile à vérifier, il se peut qu'il y ait des fautes de frappe

déclaration des constantes:
Code: [Select]
const uint8_t maxSsid = 30;
const uint8_t maxMdp = 30;
const uint8_t maxnumero2tel = 15;


déclaration des tableaux
Code: [Select]
char ssid[maxSsid + 1];
char mdp[maxMdp + 1];
char numero2tel [maxnumero2tel + 1];


Lecture des différents fichiers
Code: [Select]
if (lisSurSd("ssid.txt", ssid, sizof(ssid)) == false) {
  // on a un soucis !
}

if (lisSurSd("mdp.txt", mdp, sizof(mdp)) == false) {
  // on a un soucis !
}

if (lisSurSd("numero2tel.txt", numero2tel, sizof(numero2tel)) == false) {
  // on a un soucis !
}



La fonction de lecture
Code: [Select]
boolean lisSurSd(const char * nomDuFichierTxt, char *donneeLueSurSD, size_t NbMaxCaracteres)
{
  size_t indexEcritureMAX = NbMaxCaracteres - 1; // idéalement il faudrait tester si on nous appelle avec  NbMaxCaracteres valant 0 et retourner une erreur dans ce cas là.. ici on sait qu'on ne fait pas de bêtise :)
  boolean lectureOK = false;

  DPRINTF("Ouverture de :"); DPRINTLN(nomDuFichierTxt);
  myFile = SD.open(nomDuFichierTxt);

  if (myFile) {
    size_t i = 0;
    donneeLueSurSD[0] = '\0'; // on initialise la chaîne à 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(); // idéalement il faudrait tester si la lecture s'est bien passée
        i++;
      } else { // il reste des données dans le fichier mais on n'a plus de place
        donneeLueSurSD[indexEcritureMAX] = '\0'; // donc on tronque ici
        break; // et on arrête de lire le fichier
      }
    }
    // il n'y a plus rien à lire dans le fichier
    donneeLueSurSD[i] = '\0';  // on termine la chaîne proprement à cet endroit
    lectureOK = true;
    myFile.close();
  } else {
    DPRINTF("Erreur a l'ouverture du fichier "); DPRINTLN(nomDuFichierTxt);
  }
  return lectureOK;
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 05:10 pm
Sa c'est mis a fonctionner malgré ne rien avoir toucher et les petit carre lu  :smiley-confuse:  :smiley-confuse:  :smiley-confuse:
J'ai tout de même intégrer ton code et effectivement, beaucoup de faute !  :P

je pense que tu voulait sizeof mais même après cette modif j'avait une erreur de compile
J'ai remplacé par size_t
Code: [Select]
if (lisSurSd("ssid.txt", ssid, sizof(ssid)) == false) {
  // on a un soucis !}


Et d'autre petit truc mais c'est OK.
J'avais essayer de récupérer la taille du char de destination mais je ne m'y suis pas pris comme cela.
Et j'ai pas encore assimiler de faire de boolean qui sont des fonctions.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 05:53 pm
euh oui sizof() --> sizeof()
Quote
J'ai remplacé par size_t
je ne sais pas où... size_t c'est un type qui représente une taille

Une fonction peut soit rien retourner, auquel cas on la déclare void, soit elle retourne quelque chose genre un booléen ou un entier ou un pointeur etc... et dans ce cas c'est le type que l'on met devant le nom de la fonction. ici je me suis dit que ce serait bien si l'appelant pouvait savoir si la lecture du fichier s'est bien passée, donc je retourne VRAI si c'est OK et FAUX sinon
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 05:55 pm
ba oui mais non, c'est size_t puisque :
Code: [Select]
boolean lisSurSd(const char * nomDuFichierTxt, char *donneeLueSurSD, size_t NbMaxCaracteres){
sinon:
Code: [Select]
invalid application of 'sizeof' to incomplete type 'char []'
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 05:58 pm
ba oui mais non, c'est size_t puisque :
Code: [Select]
boolean lisSurSd(const char * nomDuFichierTxt, char *donneeLueSurSD, size_t NbMaxCaracteres){
sinon:
Code: [Select]
invalid application of 'sizeof' to incomplete type 'char []'
je ne sais pas à quelle partie du code vous faites référence ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 06:19 pm
dans la fonction boolean il y a "size_t NbMaxCaracteres"
Code: [Select]
boolean lisSurSd(const char * nomDuFichierTxt, char *donneeLueSurSD, size_t NbMaxCaracteres){

donc pour l'appeler il faut:
Code: [Select]
if (lisSurSd("ssid.txt", ssid,  size_t(ssid)) == false) {
  // on a un soucis !
}


et pas
Code: [Select]
if (lisSurSd("mdp.txt", mdp, sizof(mdp)) == false) {
  // on a un soucis !
}


non ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 07:05 pm
Non ;)

size_t (https://en.cppreference.com/w/cpp/types/size_t) c'est un type (en gros un unsigned int). donc dans la définition de la fonction on dit que le type de  NbMaxCaractere représente une taille. et quand vous devez appeler la fonction vous devez donner la taille donc appeler avec
Code: [Select]
lisSurSd("mdp.txt", mdp, sizeof(mdp))
j'avais juste oublié le e dans sizeof
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 07:16 pm
C'est la premiere chose que j'avais faite mais il y a erreur de compil
Code: [Select]

AQUABOUNS_V2_gsm:128: error: invalid application of 'sizeof' to incomplete type 'char []'

   if (lisSurSd("ssid.txt", ssid, sizeof(ssid)) == false) {

                                             ^

AQUABOUNS_V2_gsm:132: error: invalid application of 'sizeof' to incomplete type 'char []'

   if (lisSurSd("mdp.txt", mdp, sizeof(mdp)) == false) {

                                          ^

AQUABOUNS_V2_gsm:136: error: invalid application of 'sizeof' to incomplete type 'char []'

   if (lisSurSd("numero2tel.txt", numero2tel, sizeof(numero2tel)) == false) {
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 07:19 pm
comment les tableaux sont déclarés dans le fichier? si le compilateur à la compilation ne connait pas la taille ça ne fonctionnera pas effectivement. dans ce cas il faudra faire

Code: [Select]
lisSurSd("ssid.txt", ssid, maxSsid + 1) et donner la taille directement

et comme la première chose que je fais dans la fonction c'est -1, autant pas faire le +1 à l'appel et dire que c'est directement le maxCar et enlever le -1 dans la fonction et appeler avec
Code: [Select]
lisSurSd("ssid.txt", ssid, maxSsid)

donc la fonction devient
Code: [Select]
boolean lisSurSd(const char * nomDuFichierTxt, char *donneeLueSurSD, size_t indexEcritureMAX)
{
  boolean lectureOK = false;

  DPRINTF("Ouverture de :"); DPRINTLN(nomDuFichierTxt);
  myFile = SD.open(nomDuFichierTxt);

  if (myFile) {
    size_t i = 0;
    donneeLueSurSD[0] = '\0'; // on initialise la chaîne à 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(); // idéalement il faudrait tester si la lecture s'est bien passée
        i++;
      } else { // il reste des données dans le fichier mais on n'a plus de place
        donneeLueSurSD[indexEcritureMAX] = '\0'; // donc on tronque ici
        break; // et on arrête de lire le fichier
      }
    }
    // il n'y a plus rien à lire dans le fichier
    donneeLueSurSD[i] = '\0';  // on termine la chaîne proprement à cet endroit
    lectureOK = true;
    myFile.close();
  } else {
    DPRINTF("Erreur a l'ouverture du fichier "); DPRINTLN(nomDuFichierTxt);
  }
  return lectureOK;
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 10:50 pm
au oui c'est plus simple et compréhensif comme ça.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 15, 2018, 11:01 pm
Comme je l'ai deja dit, le code devient gros avec beaucoup de fonction.
La fonction qui lit les bouton de l'ecran a besoin d'au moins 2500 "loop"/10 secondes pour que l'écran réponde correctement.
Toute les fonctions d'affiler font 1300 loup/10 secondes.
après différent test J'ai donc fait ceci :
Code: [Select]
lireBoutonsNextion(); //boucle éffectuée : 45633 fois en 10 secondes soit : 0 millis par boucle

  if (roulement <= 3000) {
    rafraichirSiSurMenu();//boucle éffectuée : 57316 fois en 10 secondes soit : 0 millis par boucle
    rafraichirHeureSiSurMenu();// boucle éffectuée : 40595 fois en 10 secondes soit : 0 millis par boucle
    horaire(); //boucle éffectuée : 9372 fois en 10 secondes soit : 0 millis par boucle
    rebootAlarme();//boucle éffectuée : 18753 fois en 10 secondes soit : 0 millis par boucle
    tempeteAleatoireAutomatique();//boucle éffectuée : 9371 fois en 10 secondes soit : 0 millis par boucle
    nourrissage();// boucle éffectuée : 9325 fois en 10 secondes soit : 0 millis par boucle
    eclairage();//boucle éffectuée : 8247 fois en 10 secondes soit : 0 millis par boucle
    brassage();// boucle éffectuée : 8451 fois en 10 secondes soit : 0 millis par boucle
    oscillateur();//boucle éffectuée : 9195 fois en 10 secondes soit : 0 millis par boucle
    ventilation();// boucle éffectuée : 9246 fois en 10 secondes soit : 0 millis par boucle
    ph(); //boucle éffectuée : 7040 fois en 10 secondes soit : 0 millis par boucle
    roulement++;
    if (roulement == 1000) {
      flotteurs();// boucle éffectuée : 1491 fois en 10 secondes soit : 0 millis par boucle
    }
    else if (roulement == 2000) {
      temperature();// boucle éffectuée : 223 fois en 10 secondes soit : 0 millis par boucle
    }
    else if (roulement == 3000) {
      messageAlerteTemperature(); // boucle éffectuée : 4674 fois en 10 secondes soit : 0 millis par boucle
      roulement = 0;
    }
  }

j'arrive a 4663 boucle mais je ne trouve pas cela très propre.
J'ai tester avec des compteur millis mais cela nécessite plusieurs variable uint32_t donc de la place de stockage.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 15, 2018, 11:07 pm
dans l'absolu chaque fonction devrait avoir son propre rythme de mise à jour.. par exemple ça sert sans doute à rien de lire le pH toutes les 15 millisecondes. une fois toutes les 5 minutes par exemple ça devrait être suffisant non?

donc oui il faudrait un uint32_t par fonction clé qui se souviendrait du dernier moment de déclenchement et l'appel à la fonction commencerait par faire un test pour voir si ça fait assez longtemps ou pas qu'on a appelé vraiment la fonction de mesure et si c'est trop récent ne rien faire.

si vous voulez gagner de la place dans vos DPRINT vous pourriez utiliser la macro F() non ? (j'ai vu plus haut que ce n'était pas le cas)  - même si au final (j'espère) la macro quand on compile en mode non debug doit carément virer le texte, au moins pendant que vous testez vous aurez un peu plus de RAM de dispo
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 16, 2018, 12:12 am
Effectivement certaine fonction son moins importante ou ne nécessite pas une réaction instantané.
Je voulait éviter de crée plusieurs variable car je commence vraiment a être bloqué coté mémoire malgré toute les améliorations et changement que j'ai fait.
Le compilateur indique un risque de beug au dela de 75% de mémoire utilisé.
Cette limite est elle vraiement a ne pas depasser ?

Pour le DPRINTF, je ne peut l'utiliser que pour DPRINTF("nananere") et j'utilise DPRINT pour les variables.
quand je désactive debeug je gagne 1%
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 16, 2018, 06:22 am
Quote
Le compilateur indique un risque de beug au dela de 75% de mémoire utilisé.
Cette limite est elle vraiement a ne pas depasser ?
Tout dépend de votre programme et de combien de place vous utilisez dynamiquement (tous ces tableaux temporaires par exemple celui que j'ai viré dans le code ci dessus c'est toujours ça de pris)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 16, 2018, 08:03 am
tous ces tableaux temporaires par exemple celui que j'ai viré dans le code ci dessus c'est toujours ça de pris
:smiley-confuse: j'en est fait a toute les fonction répétitive (brassage 1,2,3, éclairage 1,2,3,4, oscillo 1,2,3, nourrissage 1,2
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 16, 2018, 11:26 am
Tant que ça rentre. ....
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 16, 2018, 11:58 am
Oui lol mais je suis revenu a 80% est reste le wifi et divers petites chose alors vu que l'automate tourneras H24 il ne faut pas que ca beug
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 16, 2018, 12:14 pm
Insérez du code qui vérifie la mémoire restante (https://github.com/McNeight/MemoryFree) et regardez ce que ça donne
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 16, 2018, 03:08 pm
sa indique 1463 libre au lieu des 1524 du compilateur.
Par contre ces fix j'ai déclencher plein de fonction via bouton ou l'écran, envoyer des SMS et toujours 1463.
C'est sensé évoluer avec l'utilisation ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Jul 16, 2018, 03:23 pm
Bonjour

Si tu veilles bien à laisser TOUTES les chaînes de caractère en flash (via progmem), les 8 ko de RAM d'une mega doivent être largement suffisants pour un programme de cette nature.
75% de RAM occupée dès la compil me laisse à penser que la gestion des chaînes est perfectible.
C'est effectivement un peu limite (à voir selon les besoins temporaires de chaque fonction).

Indépendamment de ce point, il faut inclure une gestion du watchdog dans ton automate, si ce n'est pas déjà le cas.
C'est un filet de sécurité contre toutes sortes d'aléa (bug ou autre), qui déclenchera un reboot du système au moindre problème.
Même avec le meilleur programme du monde, cette sécurité est indispensable pour le pilotage d'un aquarium, pour ne prendre aucun risque avec la vie de tes hôtes à écailles ou polypes.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 16, 2018, 03:37 pm
Bonjour bricoleau

concernant la mémoire, je l'ai vu s'envoler lorsque j'ai fait toute les déclarations lier a l'écran.(je ne parle que de la déclaration, exemple pour déclarer l'emplacement d'un bouton ou d'une variable sur l'écran)
Si j'ai bien compris la bibliothèque, tout est en string.
C'est ça qui prend beaucoup de place ?

Pour la gestion des chaines, j'ai fait cela:
Code: [Select]
// **************************************** declarations
uint8_t pwmEclairage[4];
uint32_t debutleverSoleil[4];
uint32_t finleverSoleil[4];
uint32_t debutcoucherSoleil[4];
uint32_t fincoucherSoleil[4];
uint8_t eclairageOnOffPwm[4] {pwm, pwm, pwm, pwm};

void eclairage() { // *******************************************************************************************************************************************
  for (uint8_t numeroEclairage = bleu1; numeroEclairage <= blanc2; numeroEclairage++) {
    if (eclairageOnOffPwm [numeroEclairage] == Arret) {
      pwmEclairage[numeroEclairage] = zero;
      analogWrite(pinOutEclairage[numeroEclairage], zero);
      //DPRINTF("OFF"); DPRINTF("  //  ");DPRINT(Heure);DPRINTF("h");DPRINT(minut);DPRINTLN();
    }
    else if (eclairageOnOffPwm [numeroEclairage] == Actif) {
      pwmEclairage[numeroEclairage] = sauvegarde.puissanceMaxEclairage[numeroEclairage];
      analogWrite(pinOutEclairage[numeroEclairage], sauvegarde.puissanceMaxEclairage[numeroEclairage] * pourCentEnPwm);
      // DPRINTF("ON"); DPRINTF("  //  ");DPRINT(Heure);DPRINTF("h");DPRINT(minut);DPRINTLN();
    }
    else if (eclairageOnOffPwm [numeroEclairage] == pwm) {
      if ((Time >= debutleverSoleil[numeroEclairage]) && (Time < finleverSoleil[numeroEclairage])) {
        pwmEclairage[numeroEclairage] = map(Time, debutleverSoleil[numeroEclairage], finleverSoleil[numeroEclairage], zero, sauvegarde.puissanceMaxEclairage[numeroEclairage]);
        analogWrite (pinOutEclairage[numeroEclairage], pwmEclairage[numeroEclairage] * pourCentEnPwm);
        //DPRINTF("pwm monte");DPRINT(numeroEclairage); DPRINTF("  //  ");DPRINT(Heure);DPRINTF("h");DPRINT(minut);DPRINTLN();
      }
      else if ((Time >= debutcoucherSoleil[numeroEclairage]) && (Time < fincoucherSoleil[numeroEclairage])) {
        pwmEclairage[numeroEclairage] = map(Time, debutcoucherSoleil[numeroEclairage], fincoucherSoleil[numeroEclairage], sauvegarde.puissanceMaxEclairage[numeroEclairage], zero);
        analogWrite (pinOutEclairage[numeroEclairage], pwmEclairage[numeroEclairage] * pourCentEnPwm);
        //DPRINTF("pwm baisse"); DPRINT(numeroEclairage); DPRINTF("  //  ");DPRINT(Heure);DPRINTF("h");DPRINT(minut);DPRINTLN();
      }
      else if ((Time >= finleverSoleil[numeroEclairage] ) && (Time < debutcoucherSoleil[numeroEclairage])) {
        pwmEclairage[numeroEclairage] = sauvegarde.puissanceMaxEclairage[numeroEclairage];
        analogWrite(pinOutEclairage[numeroEclairage], sauvegarde.puissanceMaxEclairage[numeroEclairage] * pourCentEnPwm);
        //DPRINTF("pwm full"); DPRINT(numeroEclairage); DPRINTF("  //  ");DPRINT(Heure);DPRINTF("h");DPRINT(minut);DPRINTLN();
      }
      else {
        pwmEclairage[numeroEclairage] = zero;
        analogWrite(pinOutEclairage[numeroEclairage], zero);
        //DPRINTF("pwm zero");DPRINT(numeroEclairage); DPRINTF("  //  ");DPRINT(Heure);DPRINTF("h");DPRINT(minut);DPRINTLN();
      }
    }
  }
}


Pour se que tu nome "watchdog" j'avait cette idée derrière la tète, plus précisément, j'imaginais que le wemos  d1 mini pro puisse reboot l'arduino si bug et vis versa.
C'est juste que je garde sa pour le fin pour ne pas m'éttaler partout a la fois (j'ai déjà tendance a trop le faire)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Jul 16, 2018, 06:21 pm
Non dans ce bout de code je ne vois rien qui cloche au niveau RAM.
75% occupé à la compil sur une mega, cela veut dire qu'il y a près de 6000 octets réservés en permance, c'est qui est énorme.
Dans ces 6000 octets on trouve :
1) tes variables globales
2) les chaines de caractères utilisées sans progmem <= c'est là qu'est le problème la plupart du temps
3) les variables statiques internes aux bibliothèques utilisées (par ex environ 70 octets pour Serial). La lib du LCD est peut-être très gourmande?

Pour le watchdog, pas besoin d'un wemos, c'est une fonctionnalité intégrée au hardware de l'arduino.
Le principe est tout simple : le watchdog est comme un compte à rebours qui déclenche le reboot lorsqu'il arrive à zéro. Pour éviter le reboot, il faut venir régulièrement le réinitialiser.
Concretement :
1) dans setup() tu actives le watchdog avec une durée (par exemple maximum 8 secondes)
2) dans loop() tu fais un reset systématique du watchdog

ainsi, s'il s'écoule plus de 8 secondes entre deux exécutions de loop(), l'arduino effectue un reboot automatique.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 16, 2018, 07:13 pm
Je suis content de voir que je n'est pas fait d'erreur grossière d'écriture dans mes fonctions :) je devient bon ... ou pas lol

Comment savoir si la bibliothèque de l'écran nextion est gourmande ?
En tout cas un déclaration d'un champs de l'écran c'est 72 octets de stockage et 12 octets de mémoire dynamique.
j'ai 141 déclarations donc 10152 octets de stockage et 1692 de mémoire dynamique juste pour les déclarations.

"Pour 2) les chaines de caractères utilisées sans progmem" il faut que je me renseigne la dessus, je connait pas, comme d'hab :/ je voudrait finir d'inclure les SMS et mes flotteurs avant.

Pour le "watchdog" sa a l'air simple ... unpeu trop d'ailleurs ...



Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 17, 2018, 03:13 am
Pour la mémoire imprimez là en sortie de vos fonctions - ou en début mais juste après la déclaration des variables locales.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 17, 2018, 09:31 am
Pour la mémoire imprimez là en sortie de vos fonctions - ou en début mais juste après la déclaration des variables locales.
Ok je vais faire ca avec un bout de qui garderas en mémoire la plus petite mémoire mesuré
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: bricoleau on Jul 17, 2018, 10:05 am
Le problème, c'est que cela ne prendra pas en compte les allocations de RAM temporaires effectuées par les fonctions des bibliothèques utilisées.
Néanmoins cela donne quand même une indication. Il faudra juste veiller à garder assez de RAM dispo pour ces fonctions de bas niveau.

Il me semble avoir vu des outils plus subtils, qui initialisent le contenu de la RAM disponible avec une valeur spécifique, pour ensuite aller regarder jusqu'où elle a été temporairement utilisée.

Mais bon là vu les symptômes, pas la peine d'investir du temps dans un thermomètre trop sophistiqué.
Il vaut mieux essayer directement de comprendre où sont les 6000 octets de RAM alloués dès le départ.

Pour le watchdog, voici un petit bout de code très démonstratif
Code: [Select]
//Test du watchdog
#include <avr/wdt.h>

void setup() {
  Serial.begin(9600);
  Serial.println("Debut");
 
  //Activation du watchdog
  //15mS     WDTO_15MS
  //30mS     WDTO_30MS
  //60mS     WDTO_60MS
  //120mS    WDTO_120MS
  //250mS    WDTO_250MS
  //500mS    WDTO_500MS
  //1S       WDTO_1S           
  //2S       WDTO_2S
  //4S       WDTO_4S
  //8S       WDTO_8S
  wdt_enable(WDTO_8S);

  //Attention :
  //Certaines cartes sont livrées avec un bootloader qui ne désactive pas le watchdog
  //Résultat : suite au premier reboot, le watchdog peut se redéclencher perpétuellement alors même que l'exécution du bootloader n'est pas terminée
  //Solution : mettre la carte hors puis sous tension pour sortir de la boucle infernale, puis mettre à jour le bootloader de la carte.
}

void loop() {
  wdt_reset(); //instruction à exécuter régulièrement pour éviter le reboot automatique
 
  //reboot déclenché manuellement via le terminal série
  if (Serial.available()) {
    for (int i=0; i<20; i++) {
      Serial.println(i);
      delay(1000);
    }//La boucle dure 20 secondes => trop long pour le watchdog
  }
}
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 19, 2018, 10:21 pm
je me suis fait discret car je me tire les cheveux sur mes mesure PH.
Enfaîte, tout fonctionnais.  
Mais il est ou le problème alors ?  :o
Et bien c'est un problème hardware. Lorsque l'écran est allumer (650mAh), il y a un petit chute de tension sur le PCB 0.15v qui ne pause aucun problème de fonctionnement a quiconque.
ROoo mais il est ou le problème alors ?  :o
Et bien, lorsque l'ecran Nextion passe en veille, hop, la chute de tension disparait ... et hop ... ~+0.30 dans la mesure PH.
Dans un premier temps j'en cru que la variation de tension qui alimente la carte PH était a la base du problème j'ai donc alimenter cette carte avec le 12v via un l78l05.
Malgré la tension constante j'ai retrouver les même variation de mesure.
Donc cette variation doit en faite affecter l'arduino qui du coup fait fluctuer les valeur mesuré.(l'arduino est alimenter en 5v, pas par le Vin)
La solution que j'envisage est donc d'alimente l'écran via le 12v via un TSR 1-2450 comme sa il n'y auras plus de chute de tension sur le 5v.

Pour se qui est de la stabilité des mesures (~0.08 de variation entre les mesure), j'ai testé plusieurs méthode dont certaine utilisant de la mémoire, j'ai fini par opter pour du simple, efficace et peu gourmand.

Le loop lance la fonction PH.
Celle ci mesure un coupe sur deux le PH bac puis PH rac.
je multiplie le resultat précédent par 9 et ajoute la nouvelle mesure.
Puis divise par 10.
Les mesure sont stables et cela ne (devrait pas) pause pas de problème puisque il n'y a pas de gros changement brusque a mesurer.


Code: [Select]
// ****************************************  PH
void ph() {
  // **************************************** recuperation ph
  if (switchPhRacBac == true) {
    recupererPh(pinInPhBac, phBac);
    phBac = moyennePh;
    DPRINTF("ph bac : "); DPRINT(phBac); DPRINTF("  //  "); DPRINT(Heure); DPRINTF("h"); DPRINT(minut); DPRINTLN();
  }
  else if (switchPhRacBac == false) {
    recupererPh(pinInPhRac, phRac);
    phRac = moyennePh;
    DPRINTF("ph rac : "); DPRINT(phRac); DPRINTF("  //  "); DPRINT(Heure); DPRINTF("h"); DPRINT(minut); DPRINTLN();
  }



void recupererPh(const byte pin, float moyennePrecedente) {
  uint16_t mesurePh;
  mesurePh = map(analogRead(pin), 774, 595, 401, 918);
  switchPhRacBac = !switchPhRacBac;
  moyennePh = (mesurePh / 100);
  moyennePh = ((moyennePrecedente * 9) + moyennePh) / 10;
  }






Je fini de faire mes fonction flotteur et les alerte SMS associé.

Apres je me met sur la mémoire (freeMemory) et a chercher se qui me prend autant de place.


(si vous connaissez un forum d'électronique avec des gas aussi sympa qu'ici ça m'intéresse pars que soit personne ne répond soit on se fait mal parlé  :( )
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 20, 2018, 01:28 am
Comment fonctionne la lecture de pH ? C'est sur une pin analogique ? dans ce cas la variation de tension d'entrée de la carte peut jouer sur la référence analogique si vous êtes resté sur le défaut
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 08:35 am
alors la carte est sur pin analogique mais :
Il n'y a aucun datasheet pour cette carte donc difficile de connaitre toute les caractéristiques.  Les composant visible son des amplificateur lm358 et un 4502c.
C'est la première chose que j'ai envisager, que cette chute de tension affecte directement la carte. mais après l'avoir alimenté séparément j'ai constater exactement les même écart donc (je me demande si) l'arduino étant alimenter en 4.80v quand l'écran est allumer, prend pour "référence 5v" 4.8v. (?)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 08:53 am
Salut

Utiliser la référence interne 1.1V de l'ADC peut être une solution. Par contre elle n'est pas très précise, 10% je crois, mais probablement plus stable.
Sinon, une référence externe genre LM4040.

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 09:22 am
Salut hbachetti,

La carte ph retourne ~3.7v (donc y va y avoir un problème si la plage max est 1.1v ?)

Pour le lm4040 si j'ai bien compris c'est pour mettre sur AREF et il faut appeler AR_EXTERNAL
Cette solution semble faisable.

Mais ne faut'il pas éviter cette chute de tension en alimentent l'écran différemment plutôt que remédier au consequance ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 10:13 am
Bien sûr, dans le cas où on utilise la ref interne, il faut diviser la tension mesurée afin qu'elle soi inférieure à 1.1V.
Utiliser un pont diviseur résistif, donc, avec de préférence des résistances à film métallique, pour la stabilité en température.

Quote
Mais ne faut'il pas éviter cette chute de tension en alimentent l'écran différemment plutôt que remédier au consequance ?
Je n'ai pas suivi le sujet depuis le départ, et je ne sais pas d'où sort ton 5V. Est-il stable dans le temps et en fonction de la température ?

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 10:30 am
le pcb est alimenter par une alimentation 5v 3A.
Je n'ai pas remarqué de variation avec la température (a par la chute de tension du a l'écran allumé)  

je me suis fait discret car je me tire les cheveux sur mes mesure PH.
Lorsque l'écran est allumer (650mAh), il y a un petit chute de tension sur le PCB 0.15v qui ne pause aucun problème de fonctionnement a quiconque.
mais lorsque l'ecran Nextion passe en veille, hop, la chute de tension disparait ... et hop ... ~+0.30 dans la mesure PH.
Dans un premier temps j'en cru que la variation de tension qui alimente la carte PH était a la base du problème j'ai donc alimenter cette carte avec le 12v via un l78l05.
Malgré la tension constante j'ai retrouver les même variation de mesure.
Donc cette variation doit en faite affecter l'arduino qui du coup fait fluctuer les valeur mesuré.(l'arduino est alimenter en 5v, pas par le Vin)
La solution que j'envisage est donc d'alimente l'écran via le 12v via un TSR 1-2450 comme sa il n'y auras plus de chute de tension sur le 5v.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 10:32 am
Une alimentation dont tu connais les caractéristiques?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 10:46 am
 :(  a part 5v 5A(rectif 5A pas 3A)
celui ci (https://www.amazon.fr/gp/product/B073RJL3VW/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1)
et pareil pour le 12V 3A je n'en sait pas plus
(mais a mon niveau je ne vois pas se qu'il faudrait savoir  :( )
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 11:00 am
Connaître la stabilité, surtout en température serait un plus.

Tu devrais essayer tout de même de faire la mesure en utilisant la référence interne 1.1V.
Ce n'est pas une grosse modification et cela apportera probablement une meilleure stabilité.
Pense à découpler la référence interne à l'aide d'un condensateur 1µF sur la pin AREF.

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 11:14 am
Tu devrais essayer tout de même de faire la mesure en utilisant la référence interne 1.1V.
Je vais essayer de mieux comprendre avant de tenter ce branchement pars que :
Quote
you must set the analog reference to EXTERNAL before calling analogRead(). Otherwise, you will short together the active reference voltage (internally generated) and the AREF pin, possibly damaging the microcontroller on your Arduino board.
m'inquiète un peu.


j'ai l'impression que toute les pin analogique vont être affecter par cette référence.
Donc les autre pin vont aussi avoir cette référence et ne plus émettre ou recevoir de 5v mais plutôt cette référence ?


Ce n'est pas une grosse modification et cela apportera probablement une meilleure stabilité.
Pense à découpler la référence interne à l'aide d'un condensateur 1µF sur la pin AREF.
tout comme en codage je découvre alors faut le temps que je comprenne (et que j'ai se qui faut sous la main)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 12:51 pm
Quote
you must set the analog reference to EXTERNAL before calling analogRead(). Otherwise, you will short together the active reference voltage (internally generated) and the AREF pin, possibly damaging the microcontroller on your Arduino board.
Si tu utilises la référence interne 1.1V, il faut appeler analogReference(INTERNAL) et non pas analogReference(EXTERNAL).

Quote
j'ai l'impression que toute les pin analogique vont être affecter par cette référence.
Pas forcément.

Code: [Select]

    analogReference(INTERNAL);
    analogRead(A0);
    int sensorValue = analogRead(A0);
    analogReference(DEFAULT);
    analogRead(A1);
    int sensorValue = analogRead(A1);


N'oublie pas qu'à chaque changement d'entrée, il faut faire une lecture à vide afin de stabiliser la charge de la capacité de l'entrée.

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 01:33 pm
Les boutons son fini et les SMS associer aussi
Reste a voir si il y a d'éventuel bug.

Pour la mémoire, j'ai mis freememory dans les fonctions et un fonction qui enregistre la plus faible et plus haute mémoire disponible.

resultat:
Code: [Select]
memoire ici : 1359 // memoire min : 1322 // memoire max : 1359


contrairement a tout se que j'aurais penser c'est la fonction éclairage qui utilise le plus la mémoire.
Mais la variation est tout de même limité, 37 octets.

Donc le "problème" vient d'ailleurs ....




J'essai de comprendre et faire le montage avec la référence intern 1.1v

j'ai pas compris ca :
Code: [Select]
Pense à découpler la référence interne à l'aide d'un condensateur 1µF sur la pin AREF
Je met le condo sur AREF et GND ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 02:26 pm
d'après se que j'ai trouvé sur le net le condo est a mettre entre AREF et GND.(je n'avais qu'un condo 474)

Pour le pont diviseur j'ai fait vcc>r6k8 et gnd r2k2 , la sortie de la carte ph est 3.7v max

J'ai ensuite étalonner la sonde pour arriver a des mesure cohérente.
Je remarque de suite des écarts plus important dans les mesure ~0.15 au lieu de ~0.8 avant.

Je lance les mesure puis branche l'écran (entre mesure 81 et 82) et :

Code: [Select]
mesure n°80
ph actuel : 920.00
ph bas: 909.00
ph haut: 994.00
ph moyen: 950.45

mesure n°81
ph actuel : 915.00
ph bas: 909.00
ph haut: 994.00
ph moyen: 950.01

mesure n°82
ph actuel : 833.00
ph bas: 833.00
ph haut: 994.00
ph moyen: 948.59

mesure n°83
ph actuel : 855.00
ph bas: 833.00
ph haut: 994.00
ph moyen: 947.46


Le problème reste le même et est encore plus accentué puisque j'avais des variation ~0.3 et maintenant ~0.8
Par contre, j'ai appris le pont diviseur  :smiley-grin:  :smiley-cool:

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 03:13 pm
Cela me paraît insensé que la référence interne soit si sensible à une chute de tension d'alimentation.
Je savais qu'elle était imprécise - entre 1V et 1.2V - mais je la croyais stable.
Il faut que je fasse un essai ce soir.

Une solution à base de référence de tension LM4040 ? ou éventuellement TL431.

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 03:19 pm
Personnellement quand je veux de la précision j'utilise ceci :

ADS1115 (https://fr.aliexpress.com/item/16-Bit-IIC-I2C-4-Channel-ADS1115-Module-ADC-with-Pro-Gain-Amplifier-For-Arduino-2V/32639483684.html?spm=a2g0s.9042311.0.0.74816c37ZhTrnP)

Il y a 4 voies analogiques, résolution 16 bits et cela se lit en I2C.

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 03:29 pm
Mais ne crois tu pas que régler le problème de base (séparer l'écran de l'alimentation 5v) serait préférable ?
Parsque si l'ecran ne bouge pas (reste allumer ou eteind) le problème n'est pas présent.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 20, 2018, 03:49 pm
A essayer. Il faut absolument un 5V très stable.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 06:51 pm
ADS1115 (https://fr.aliexpress.com/item/16-Bit-IIC-I2C-4-Channel-ADS1115-Module-ADC-with-Pro-Gain-Amplifier-For-Arduino-2V/32639483684.html?spm=a2g0s.9042311.0.0.74816c37ZhTrnP)
Je vais tenter ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 20, 2018, 10:42 pm
il faut inclure une gestion du watchdog dans ton automate,
J'ai commencer a tester et bien sur je suis tomber sur une carte avec un vieux bootloader.
Heureusement, j'en est d'autre ou ça marche parfaitement.
C'est d'une simplicité ... si tout pouvais être comme sa.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 21, 2018, 11:28 am
J'ai eu une idée (non non peut etre pas de génie  :smiley-evil:),
Le problème avec la carte ph et le pont diviseur ces que la carte ph a une tension qui fluctue ~1v entre ph4 et ph9
Avec le pont diviseur cette tension et INTERNAL1V1 cette variation de tension est diviser par 5.
Cela fait des palier de 0.07ph

Ce matin j'ai donc fait :
analogReference(EXTERNAL); en relient au 3.3v de l'arduino
Fait un pont diviseur "plus faible" de
3.7v a 3.2v

J'ai des palier de ~0.02ph et joint au code le resultat est assez stable.


L'idéal serait d'avoir une référence externe  de 3.7-4v pour ne pas avoir de pont diviseur et avoir l'échelé original de la carte ph.

Et si j'utilisait un L78L5 (via 12v) pour alimenter AREF ? j'aurais une tension stable ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 21, 2018, 12:03 pm
La résistance variable sur la carte ph permet de descendre a 3.05v avec un ph 4.00
La tension diminue lorsque le ph monte donc pas de risque de dépasser 3.3v
du coup pas besoin de pond diviseur
toujours des palier de 0.02ph mais beaucoup plus stable

Par contre, les mesure devienne instable quand l'arduino n'est plus brancher par usb.
Je suppose que cela est du au fait que l'arduino est alimenter par le 5v au lieu du vin ou du jack.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 21, 2018, 01:59 pm
Ton alimentation 5V n'est pas stable.
Effectivement si tu alimentes en 12V sur VIN ou JACK, le régulateur 5V de la carte fournira une tension de meilleure qualité.
Inutile de mettre du 5V sur AREF. Ceci revient au même :
Code: [Select]
   analogReference(DEFAULT);

@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 21, 2018, 04:04 pm
quand je test les mesure ph sans tout le reste du montage pas de problème mais je pense que le fait que l'arduino et tout les élément sur le pcb soit sur la même alimentation génère c'est variation (exemple quand le GSM émet un sms)
le 12v est dédier a la partie relais pour ne pas avoir de parasite c'est pour cette raison que je ne m'en sert pas pour alimenter l'arduino.

Si je prend un petit régulateur 5v>3.3v pour brancher AREF je devrait avoir des mesures stable.



Je commence a remettre les pied dans le html et le wemos d1 mini ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 21, 2018, 11:50 pm
Une référence de tension serait préférable à un régulateur.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 22, 2018, 09:15 am
(http://www.oubouger.fr/_oubouger/static/upload/vig_detail/vig_ev_Pouce.jpg)

c'est fou la variante de composant qu'il peut exister.
On se rend vite compte que c'est un metier :/

j'ai trouver le MCP1541-I/TO qui délivre 4.096v
Il n'y auras plus aucun risque même avec la carte ph au max a 3.7v
Le montage semble identique a un régulateur, Vin gnd Vout, condo avant et après.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 22, 2018, 11:02 am
Vous avez aussi un moteur de recherche sur Texas (http://www.ti.com/power-management/voltage-reference/series-voltage-reference/products.html#p2352max=0.05)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 24, 2018, 07:11 pm
J'ai recu le MCP1541-I/TO qui délivre la tension de référence sur AREF.
Les mesure son stable.
Et quand l'écran passe en veille, les mesure s'affole  :(
J'ai testé d'alimenté les carte ph sur source externe en plus
Meme resultat :(
il me reste a tester avec le ads1115
Et c'est ragent car mis a par cela je pense avoir fini toute la partie fonction et ecran. je laisse tourner pour "découvrir" d'éventuel bug mais rien pour le moment :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 24, 2018, 08:02 pm
Quid des masses - sont elles bien communes?
quand vous dites
Quote
Et quand l'écran passe en veille, les mesure s'affole
--> est-ce que vous voyez cela par programme Arduino ou simplement en branchant  un voltmètre sur la sonde ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 24, 2018, 08:30 pm
alors concernant les masses c'est une grande question a la quelle je n'est pas obtenu de réponse.
A la base, les alimentation 5v et 12v sont séparer pour qu'il n'y est pas de parasite du au relais.
Donc arduino > r220 > pc817 > r1k > uln2803 > diode > relais 12v
Jusque la les masse séparé.
 J'ai fait une carte test avec les masse commune. Je n'est pas vu (visuellement sur ecran et moniteur série) de conséquence de parasite. Par contre, lorsque le 5V est couper et alimenter en 12V , la LED qui indique l'alimentation 5V etait mi allumée ...


Pour les mesures c'est avec le moniteur série.
Mais j'ai également la constatation sur l'écran nextion a sa sortie de veille (quand non brancher en usb pour avoir le moniteur série).

J'ai déjà lors des test précédent brancher le multimètre sur la carte ph sans qu'il y est de fluctuation significative du au passage allumer/veille de l'écran

A quoi pense tu ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 24, 2018, 11:47 pm
J'ai recu le MCP1541-I/TO qui délivre la tension de référence sur AREF.
Les mesure son stable.
Et quand l'écran passe en veille, les mesure s'affole  :(
J'ai testé d'alimenté les carte ph sur source externe en plus
Meme resultat :(
il me reste a tester avec le ads1115
Et c'est ragent car mis a par cela je pense avoir fini toute la partie fonction et ecran. je laisse tourner pour "découvrir" d'éventuel bug mais rien pour le moment :)
J'ai changer d'arduino et de carte ph, refait tout les branchements.
Depuis 30 min j'ai  des resultat stable ...

Dodo pour aujourd'hui.
Demain je laisse tourner pour être sur ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 25, 2018, 06:54 pm
 :D  ;D  sa tourne depuis ce matin.
J'ai juste ajuster la valeur basse ph4.01 et haute ph9.18
quand je mesure une solution 6.86, je trouve 6.87  8)

J'ai donc voulu aller plus loin.(me mettre en temps qu'utilisateur final pour voir si juste en ajustant le potentiomètre de la carte ph on retrouvait bien la bonne valeur haute et basse.)
J'ai changer de sonde PH pour voir.
c'est très long a se stabiliser ( du la résistance variable ?)
j'arrive a bien avoir 4.01 et 9.18 et j'ai 6.85 au lieu de 6.86.

Donc l'on peut dire que ce montage + code est concluant  :smiley-cool:

Merci hbachetti pour tes conseilles pour ce montage.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 25, 2018, 08:15 pm
et pour faciliter tout ça, j'ai ajouter un bouton pour l'étalonnage. (https://www.youtube.com/watch?v=YwYlPJ3uWxg&feature=youtu.be)
Lorsque l'étalonnage est activé, les mesure sont prise a chaque loop et toute les 500 millis l'écran est mise a jour.


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Jul 25, 2018, 08:46 pm
Mais quelle est la conclusion ?
Carte PH défectueuse ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 25, 2018, 09:03 pm
Non pas de carte ph défectueuse.
J'ai retourner le problème dans tout les sens.
Les branchement était bon donc a par un faut contact sur la platine d'essai ou l'un des fils de montage, je vois pas.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 04:39 pm
cc tout lmonde,

Depuis se matin je regarde le fonctionnement de progmem.
J'ai réussi a modifier mes déclarations pour ne pas avoir d'erreur.
La mémoire qui etait utiliser bascule bien sur la mémoire flash

declarations
Code: [Select]
const char alerte[] PROGMEM = "!!! ALERTE !!!";
const byte maxbufferTexte = 30;
char bufferTexte[maxbufferTexte + 1];


puisque lorsque je veut utiliser le char*
Code: [Select]
strncpy_P (bufferTexte,alerte, maxbufferTexte);

Lors de la première utilisation de la fonction tout est ok.
Ensuite, c'est du n'importe quoi :(

Si j'ai bien compris il faut "reconstruire la chaîne" en faisant par exemple
Code: [Select]
for (int i =0; i==maxbufferTexte; i++)


Mais même avec l'aide de ceci (https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#ga963f816fc88a5d8479c285ed4c630229)
Je ne ni arrive pas
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 28, 2018, 05:52 pm
et avec l'aide de ceci (https://www.arduino.cc/reference/en/language/variables/utilities/progmem/) ?


Lors de la première utilisation de la fonction tout est ok.
Ensuite, c'est du n'importe quoi :(
ça veut dire quoi 'ensuite' ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 06:02 pm
ça veut dire quoi 'ensuite' ?
Lorsque la fonction contentent
Code: [Select]
strncpy_P (bufferTexte,alerte, maxbufferTexte);
est re demandé après la première fois.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 06:08 pm
l'exemple arduino est le premier que j'ai lu mais lorsque je test :
Code: [Select]
const PROGMEM  uint16_t charSet[]  = { 65000, 32796, 16843, 10, 11234};

// save some chars
const char signMessage[] PROGMEM  = {"I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt;
int k;    // counter variable
char myChar;


void setup() {
  Serial.begin(74880);
  while (!Serial);  // wait for serial port to connect. Needed for native USB

  // put your setup code here, to run once:
  // read back a 2-byte int
  for (k = 0; k < 5; k++)
  {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // read back a char
  for (k = 0; k < strlen_P(signMessage); k++)
  {
    myChar =  pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:

}


j'ai dans la console
Code: [Select]
65000
32796
16843
10
11234

I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART


Se que je ne comprend pas c'est pourquoi je n'est qu'un ligne "
I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"

alors que je j'ai un serial.print a chaque loop du "K" temps que "K" est inférieur au nombre de caractere de "signMessage"
Code: [Select]
for (k = 0; k < strlen_P(signMessage); k++)
  {
    myChar =  pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 28, 2018, 06:10 pm
il n'y a pas de raison....

essayez de faire tourner cela, vous verrez qu'on peut le copier autant de fois qu'on veut...
Code: [Select]
const char alerte[] PROGMEM = "!!! ALERTE !!!";
const byte maxbufferTexte = 30;
char bufferTexte[maxbufferTexte + 1];

unsigned long n = 0;

void setup() {
  Serial.begin(115200);
}

void loop() {
  strncpy_P (bufferTexte, alerte, maxbufferTexte);
  Serial.print(n++);
  Serial.print(F("\t"));
  Serial.println(bufferTexte);
  delay(100);
}


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 28, 2018, 06:13 pm
j'ai dans la console
Code: [Select]
I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART


Ce que je ne comprend pas c'est pourquoi je n'est qu'un ligne "
I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"

alors que je j'ai un serial.print a chaque loop du "K" temps que "K" est inférieur au nombre de caractere de "signMessage"
Code: [Select]
for (k = 0; k < strlen_P(signMessage); k++)
  {
    myChar =  pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }


euh pas compris... c'est pas dans la loop, c'est dans le setup.. donc fait qu'une seule fois

k parcours la totalité des caractères en mémoire flash dans la chaine signMessage et les imprime un par un...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 06:13 pm
il n'y a pas de raison....

essayez de faire tourner cela, vous verrez qu'on peut le copier autant de fois qu'on veut...
Code: [Select]
const char alerte[] PROGMEM = "!!! ALERTE !!!";
const byte maxbufferTexte = 30;
char bufferTexte[maxbufferTexte + 1];

unsigned long n = 0;

void setup() {
  Serial.begin(115200);
}

void loop() {
  strncpy_P (bufferTexte, alerte, maxbufferTexte);
  Serial.print(n++);
  Serial.print(F("\t"));
  Serial.println(bufferTexte);
  delay(100);
}



effectivement :(
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 06:16 pm
euh pas compris... c'est pas dans la loop, c'est dans le setup.. donc fait qu'une seule fois

k parcours la totalité des caractères en mémoire flash dans la chaine signMessage et les imprime un par un...
ba oui je suis d'accord.
Le fait de voir la phrase s'afficher en en une fois dans le moniteur ma perturbé!
L'arduino est plus rapide que moi :)

oui je parlait de loop mais je parlait fait dans le "for" je ne vois pas comment le nommer autrement.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 28, 2018, 06:30 pm
L'arduino est plus rapide que moi :)
LOL :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 06:36 pm
a ba on se moque maintenant :smiley-razz:  :smiley-evil:  ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 09:06 pm
Il y avait plusieurs fonction qui utilisant ce "char" et ne les aillant pas toute modifier le problème venait de la.
Donc selon la fonction appeler il y avait une erreur au lieu du même message qui avait fonctionné précédemment ... (et non pas la même fonction qui "bugait" après premier utilisation)
Il y a tellement de ligne et de fichier que ça devient compliquer a la moindre modification.
(~3250 lignes dans 15 fichiers sans compter les .h)

Je poursuis le remplacement en progmem ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 28, 2018, 10:47 pm
Ok !
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 28, 2018, 11:42 pm
dsl y a vraiment des fois ou jvous embête pour rien  :smiley-confuse:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 29, 2018, 01:24 am
sa pic les yeux  :o  ...
Mais sa en valait le coup  :smiley-razz:

Mémoire de stockage :
Utilisé avant : 70896 octets, après 71970 octets, delta 1074 octets

Les variables :
Utilisé avant : 6730 octets, après 5360 octets, delta 1370 octets , 65% au lieu de 82%

:smiley-money:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 29, 2018, 07:44 am
Bravo!
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 29, 2018, 04:39 pm
Il y a d'autre variable que je peut mettre en flash ? Les "const ***" ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 30, 2018, 02:47 pm
Depuis hier je commence a mettre a jour tout les commentaires

Certaines informations sont nécessaires pour les futurs utilisateurs afin que le montage + bibliothèque soit en osmose avec le code.

Voici la première page ci jointe.

La mise en page est correcte ? lisible ? compréhensif ?

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Jul 30, 2018, 03:05 pm
Non les variables entières type const byte ou const int etc ne vous prennent sans doute aucune place et sont directement remplacé dans le code à la compilation

Je suis sur l'on iPhone - peux pas lire le .ino facilement
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 30, 2018, 03:14 pm
Non les variables entières type const byte ou const int etc ne vous prennent sans doute aucune place et sont directement remplacé dans le code à la compilation
Ok
Le croquis utilise 59850 octets (23%) de l'espace de stockage de programmes.
Les variables globales utilisent 5263 octets (64%) de mémoire dynamique

Ça parais plus coherent avec la taille du code ou je doit encore chercher du "gras" ?

Je suis sur l'on iPhone - peux pas lire le .ino facilement
J'espère que tu profite du soleil au moins  :smiley-cool:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 31, 2018, 04:43 pm
j'essai de regarder depuis quelque temps le fonctionnement du wemos d1 mini.
J'arrive a téléverser dans le wemos et a accéder a une page web.

Se qu'il faut mettre en place :
Echange entre wemos et l'arduino
Page web dans un fichier html

Pour les échange il faut bien sur coder des deux cotés  :smiley-confuse: sur le net je trouve des post qui code le wemos (pour utilisation seul) mais pas avec des échange rx/tx avec l'arduino.
De même qu'il faudra déclarer les variables coté wemos ( et la je me demande comment faire concorder les variable)

Pour la page web .html, pour ne pas avoir a ajouter un client.print a chaque ligne.
J'ai un souvenir lointain... j'avais tenter de stocker le html sur SD mais le resultat était catastrophique.
Il me semble également me souvenir que l'on avait parler d'une mémoire "caché" sur le wemos qui pouvait contenir cette page ?

En bref j'ai repousser la partie wifi au bout du bout mais nous y voila ... il faut que j'y m'attelle !
Disons que c'est le dernier sprint ... de 5km lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: caps1g3f on Jul 31, 2018, 04:55 pm
Bonjour, je suis le sujet presque depuis le début car il s'avère que j'y trouve des réponses à mes questions sans souvent avoir besoin de les poser...
Désolé si je n'ai pas tout correctement suivi et sans vouloir remettre en cause tout le taf effectué, pourquoi ne pas utiliser que le Wemos ? (nombre de pins dispo  ?) Le wemos (esp8266) est plus puissant et possède plus de mémoire qu'un arduino. Cela permettrai de s'affranchir de la comm Wemos<-> arduino.
Le codage est "globalement" (tout est dans le globalement) identique entre ESP8266 et arduino..

Fin du HS, c'est avec hâte que je suivrais la fin de ce projet, en esperant pouvoir partager le mien dès qu'il seras 'terminé.'
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Jul 31, 2018, 06:20 pm
Bonjour caps1g3f,

Le wemos ne dispose tout simplement pas d'assez de pin :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 01, 2018, 09:59 pm
Pour ma culture personel :)
Pourquoi quand les declarations ci dessous son dans le .cpp il prenne 2 octets de plus que quand il sont dans le .h ?
Code: [Select]
const uint8_t maxSsid = 30;// prévoir la bonne longueur
const uint8_t maxMdp = 30;// prévoir la bonne longueur
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 01, 2018, 11:25 pm
Parce qu'il semblerait que dans un cas l'optimiseur réussisse à les virer (remplacement direct en mémoire là où ces constantes sont utilisées) et pas dans l'autre...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Aug 02, 2018, 10:07 am
Tout dépend si ces variables sont utilisées dans d'autres fichiers. Si ce n'est pas le cas, le linker les ignore.

Il est déconseillé de déclarer des variables dans un .h
Cela conduit forcément à une double définition si tu les utilises dans 2 .cpp ou .ino différents.

Dans un .cpp ou .ino :

Code: [Select]

const uint8_t maxSsid = 30;// prévoir la bonne longueur
const uint8_t maxMdp = 30;// prévoir la bonne longueur


Dans un .h :

Code: [Select]

extern const uint8_t maxSsid;
extern const uint8_t maxMdp;


@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 02, 2018, 11:18 am
Peut être n'as tu pas suivi la manière dont est sont faite les déclarations dans mon fichier :
J'ai mon .ino qui comporte bibliothèque setup et loop.
Pour chaque fonction principal j'ai un .h + un .cpp
et j'ai en plus un pin.h ou sont les déclarations de toutes les pin, et un global.h contenant en "extern" toute les variable utiliser dans plusieurs .cpp
j'appel global.h dans les .cpp qui utilise une variable commune.

Si dans un .cpp j'utilise une fonction qui est dans déclarer dans un autre .h je suis obliger d''appeler le .h dans le .cpp en question.

Je ne sait pas si c'est très claire mais explication. :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 02, 2018, 11:25 am
un petit aperçu du pcb.
Il ne devrait plus y avoir de modification.
Si des modification ont lieu ce seras sur la partie alimentation en amont (pour ceux qui voudrais un système sur batterie en cas de coupure EDF) dans un boitier dédier.
Pour les sorties flotteur et oscillateur il y auras 2 très petite carte déporter pour diviser les flotteurs/oscillateurs (cela évite d'avoir 5x 2fils flotteurs partant du boitier et 3x 3 fils oscillateur)

(https://image.noelshack.com/fichiers/2018/31/4/1533201563-pcb-dessus.jpg)
(https://image.noelshack.com/fichiers/2018/31/4/1533201549-pcb-face-1.jpg)
(https://image.noelshack.com/fichiers/2018/31/4/1533201540-pcb-face-2.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: hbachetti on Aug 02, 2018, 12:14 pm
Quote
Peut être n'as tu pas suivi la manière dont est sont faite les déclarations dans mon fichier :
Si, parfaitement.

Quote
et j'ai en plus un pin.h ou sont les déclarations de toutes les pin, et un global.h contenant en "extern" toute les variable utiliser dans plusieurs .cpp
C'est bien ce que je disais. Déclarations "extern" dans les .h.

Dans ton  #775, tu parlais de déclarations de constantes dans un .h, sans "extern".
A proscrire.


@+
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 02, 2018, 01:19 pm
Dans ton  #775, tu parlais de déclarations de constantes dans un .h, sans "extern".
A proscrire.
effectivement, j'ai "retrouver" ces deux variables dans un .h et de mémoire je les avait mis la car j'avais une erreur de compil des que je l'ai mettais ailleurs.
Je les est bien basculer dans le .cpp correspondant sans erreur de compil (c'est que j'ai du m'améliorer :) )
et ces la que j'ai vu c'est 2 octets d'augmentation donc je me demandait pourquoi.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Aug 03, 2018, 10:47 am
Bouns bonjour.

Sympa le montage à blanc de ton système.

Bonne journée à toi.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 03, 2018, 10:59 am
Parce qu'il semblerait que dans un cas l'optimiseur réussisse à les virer (remplacement direct en mémoire là où ces constantes sont utilisées) et pas dans l'autre...
j'avais pas vu ton message.

ok


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 03, 2018, 11:01 am
Bouns bonjour.

Sympa le montage à blanc de ton système.

Bonne journée à toi.

j'attend un jack 2.5 pour pcb en remplacement du 2e jack DC pour qu'il n'y est pas de confusion lors du branchement et je fait un pcb "final avec toutes les prises et si tout est Ok.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Aug 03, 2018, 11:41 am
Bouns,

Cela le seras Ok c'est sur....

Bon je retourne essayer de comprendre le Millis..

Pascal.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 03, 2018, 11:45 am
bon courage ;)
j'ai mis du temps moi aussi.
C'était tellement plus simple delay(500) lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 03, 2018, 11:47 am
oups, je vais me faire taper sur les doigt,
C'était tellement plus simple delay(500); lol
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 03, 2018, 08:46 pm
Cc,
Code: [Select]
localBuffer[0] = '\0';
  memset(localBuffer, '\0', localBufferSize);

Le premier indique au premier caractere le caractere de fin
Le deuxième écrit un caractere de fin sur tout les emplacement jusque a la taille max du char (localBufferSize)
j'ai bon ? :)

y a t'il une différence et une préférence a avoir entre les deux ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: Breisleach on Aug 04, 2018, 06:19 pm
Bouns bonjour,

Tu as raison le millis c'est bien, mais la je me prend la tête, alors comme avec delay; cela fonctionne pour ce que je veux faire et que je ne bloque l' arduino qu'une fois par jour pour le nourrissage de mes bestioles, je verrais plus tard le millis.


Bonne soirée à toi.


Et vive l' Aquabouns.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 05, 2018, 06:13 am
Cc,
Code: [Select]
localBuffer[0] = '\0';
  memset(localBuffer, '\0', localBufferSize);

Le premier indique au premier caractere le caractere de fin
Le deuxième écrit un caractere de fin sur tout les emplacement jusque a la taille max du char (localBufferSize)
j'ai bon ? :)

y a t'il une différence et une préférence a avoir entre les deux ?
Vous avez bon :)

La différence est celle que vous expliquez donc tout dépend de si votre a besoin d'avoir des 0 partout ou pas (la première version est bien sur localBufferSize fois plus rapide puisqu'on écrit qu'a Un seul endroit)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 05, 2018, 11:34 am
quelle intérêt d'avoir des 0 partout ?

Que ce soit l'une ou l'autre, il sont utilisé juste avant que localBuffer ne soit de nouveau utilisé.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 05, 2018, 02:41 pm

ça sert parfois quand on remplit une cstring caractère par caractère et qu'on a la flemme ou pas le temps au moment de la réception d'ajouter le '\0' ou qu'il y a plusieurs  processus écrivant en mémoire par interruption et qu'il,faut aller vite (et quand vous avez prévu une case de plus à la fin) de cette façon vous avez en permanence une cstring bien formée;..

mais effectivement bien Souvent aucun intérêt si ce n'est de connaître la fonction :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 05, 2018, 09:39 pm
ok merci  :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 06, 2018, 10:31 pm
Petit break de quelque jour.
Je ne prend pas l'arduino :)
Mais juste le code pour continuer a commenter, il me reste 1 page, l'affichage, 1500 lignes :)
a mon retour faut vraiment je me mette sur le wifi et html.
Pour ceux qui sont déjà en vacance, bonne vacance.
Pour les autres, bon courage :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 07, 2018, 02:57 pm
Profite(z) bien !
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 23, 2018, 02:30 pm
cc tout le monde,

de retour, ça avance ...

(https://forums.futura-sciences.com/attachment.php?attachmentid=371973&d=1535026970)
(https://forums.futura-sciences.com/attachment.php?attachmentid=371974&d=1535027015)
(https://forums.futura-sciences.com/attachment.php?attachmentid=371975&d=1535027063)
(https://forums.futura-sciences.com/attachment.php?attachmentid=371976&d=1535027104)
(https://forums.futura-sciences.com/attachment.php?attachmentid=371977&d=1535027171)

le montage ma permis de mettre le doit sur des petit bug/erreur que je n'avait pas vu jusque la.
Ça commence a ressembler a quelque chose :)

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 23, 2018, 03:47 pm
j'ai profiter de se repos pour lire.
D'un coté de l'électronique et de l'autre html et fonctionnement du wemos d1 mini.
Ok pour programmer l'ESP via usb et afficher une page web.
Sur le net on trouve pour programmer l'ESP ou pour que l'arduino échange avec l'ESP (sans programmation de l'ESP) par exemple (https://forum.arduino.cc/index.php?topic=511147.0)  ;)
Par contre difficile facile de trouver des tuto / exemple pour se dont j'ai besoin, échange de donner entre arduino et ESP ( l'ESP étant indépendamment programmer)
Pourtant, c'est le même principe qu'avec l'écran nextion donc il y a peut etre une bibliothèque spécifique ?
Car dans mon cas c'est l'ESP qui va demander des info a l'arduino et non l'inverse.
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 23, 2018, 08:29 pm
Welcome back :)

Il me semble que j'avais posté un petit exemple de discussion entre un esp (qui a un programme arduino) et un arduino non ?

En gros suffit d'inventer un petit protocole série d'échange d'infos
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 23, 2018, 09:47 pm
Il me semble que j'avais posté un petit exemple de discussion entre un esp (qui a un programme arduino) et un arduino non ?
Si c'est sur l'une des 54 pages, je ne l'ai pas trouvé mais je m'était fait la remarque également que j'avais vu cela passer (mais j'en lit tellement a droite a gauche ...), je vais reparcourir les pages ...
si c'est sur l'un de tes tuto ... pas trouver non plus, en même temps, retrouver cela parmi tes 12291 messages ... c'est comme cherché un point virgule manquant dans une page de code :)

En gros suffit d'inventer un petit protocole série d'échange d'infos
lol, oui, y a qu'a ... lol


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 23, 2018, 09:51 pm
De mémoire j'avais posté dans cette discussion mais peut être pas... je vais voir (là je suis sur mon tel) si je retrouve mon exemple
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 23, 2018, 10:04 pm
jusque a la page 10 on parle ESP mais sans qu'il soit programmer.( donc maintenant cette partie de code est directement dans l'ESP avec la page web)
A partir de page 11 on attaque la partie GSM.
Je continu ...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 23, 2018, 10:10 pm
Apres la parti GSM on parle CARTE SD et puis NEXTION, on ne revient pas sur le wifi donc je ne crois pas que cela soit ici
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 23, 2018, 10:49 pm
Ok - je regarde ce week end - mais ça nécessitera bcp de changements...
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 24, 2018, 08:08 am
Ok - je regarde ce week end
merci

mais ça nécessitera bcp de changements...
:o
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 24, 2018, 08:54 am
Il vous faudra une architecture propre donc toutes les valeurs affichables et modifiables sur le web devront être en cache sur l'ESP.

Quand l'utilisateur ou le programme côté Arduino modifie une de ces valeurs ils faut informer l'ESP

Quand l'utilisateur modifie une valeur par le biais du web il faut informer l'Arduino pour que l'Arduino le prenne en compte

Une façon de faire cela est « simple ».

Au setup l'Arduino lit en eeprom toutes ses valeurs et par le biais d'un protocole  notifie l'ESP (envoi d'un message de RESET et pleins de variable=valeur\n par exemple )

Donc l'ESP doit avoir dans sa loop() une écoute d'une communication série (Serial ou I2C etc). L'ESP écoute aussi bien sûr les requêtes web

Ensuite côté Arduino à chaque fois que vous modifiez une variable qui est en cache côté ESP s'il faut envoyer de la même manière la mise à jour

Enfin - côté  Arduino il faut que la loop() écoute un protocole similaire de la part de l'ESP qui lui dira « eh l'utilisateur web vient de changer un truc, modifie cette valeur et déclenche ce qu'il faut pour que ce soit pris en compte »

Maintenant si votre page web ne permet pas de modifs mais juste la consultation alors c'est plus simple, il n'y a qu'un sens à coder


Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 24, 2018, 09:03 am
Dans mon rêve je voudrait que l'interface ecran soit dupliqué sur la page web.
Mais dans un premier temps je me met sur la page web "menu" (qui affiche les info sans modif)
en se qui concerne les variable, je pensait que l'ESP allait demander les variable uniquement lors de la demande de page. je ne vois pas l'utilité d'envoyer a chaque fois les variable alors que la page web n'est pas demandé.

Ça a l'air encore bien compliqué :(

Il n'y a pas une bibliothèque qui existe tout comme le nextion ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 24, 2018, 09:30 am
Non c'est pas super compliqué. vous pouvez effectivement coder cela « on demand » - l'ESP quand il a besoin des données pour afficher la page web demande toutes les data à l'arduino qui balance tout d'un coup, c'est plus simple mais un peu plus lent  car vous allez envoyer tout d'un coup sans vous poser la question de ce qui a changé ou pas sans doute.. mais bon ça devrait être quasiment transparent puisque derrière il y'a une communication web. dans ce cas vous pouvez aussi même vous permettre de balancer le tout en binaire -  équivalent à la structure de toutes les données pertinentes (il me semble que vous aviez fait le boulot de toutes les mettre dans une structure déjà)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 24, 2018, 10:10 am
Pour la vitesse, l'affichage de la page et le temps de réaction lors des clic sur les bouton était assez long (1 a 3 sec entre le Click et le "réafichage" de la page MAJ
Apparemment il y a possibilité d'afficher juste le champs modifier en utilisant AJAX mais j'ai vraiment du mal avec le HTML.
j'avance très peu du coup sa me saoul :(
Code: [Select]
<!DOCTYPE html>
<html>
  
  <head>
    <style>
body  {
    background-image: url("https://rrzk5q.by.files.1drv.com/y4mCCAD49BMT212H9PwvLw2BZLL2ayFfDNuyycms7GtBHxBAt8t8tskfjOMSJx7F0UnFYm2pVUn7Zy9bCScSyZXZkqdAOlgMlj81-jThw923fX4mZSAvawqJzTXc2HhmcCCEG6rnJDaPBrbXAsalshfUZwEx6YeJBVF8mCVNT-MD0jvDQyNkwsh8B1gFpjBk4l3Cg3eLcTHNYuLuFXtUOWpGA?width=800&height=480&cropmode=none");
    background-repeat:no-repeat;
}
p {
  color: white;
    font-family: Comic Sans MS;
    font-size: 18px;
  }
            div.fix1 {
    position: fixed;
    top: 161px;
    left: 140px;
      }
                  div.fix2 {
    position: fixed;
    top: 192px;
    left: 140px;
      }
</style> </head>
  <body>
<div class="fix1">
      <p> 93</p>
    </div>
    <div class="fix2">
      <p> 58</p>
    </div>
  </body>
</html>


vous pouvez aussi même vous permettre de balancer le tout en binaire -  équivalent à la structure de toutes les données pertinentes (il me semble que vous aviez fait le boulot de toutes les mettre dans une structure déjà)
Si tu parle des variable, oui elle son dans uns structure
Code: [Select]
struct __attribute__ ((packed)) paramS_t {// force l'ordre des champs
  // page menu
  bool tempeteAleatoireOn;
  bool nourrissageON[2];
  uint8_t remonteDelay;
  uint8_t eclairageOnOffPwm[4];
  uint8_t brassageOnOffPwm[3];
  // page config
  uint8_t puissanceMaxEclairage[4];
  uint32_t leverSoleil;
  uint32_t coucherSoleil;
  uint16_t dureelevercoucher;
  float alertetemperaturebasse;
  float alertetemperaturehaute;
  float ventilationaquarium;
  uint8_t ventilationrampe;
  bool adresseSondeRampe;
  bool adresseSondeBac;
  uint32_t heureNourrissage[2];
  uint32_t dureeNourrissageMillis;
  uint16_t dureeOsmolationMillis ;
  uint8_t compteurOsmolationMax;
  uint16_t consignePhRac;
  uint16_t alertephbacbas;
  uint16_t alertephbachaut;
  // page brassage
  uint8_t puissanceMaxBrassage[3];
  uint8_t angle1Oscillo[3];
  uint8_t angle2Oscillo[3];
  uint16_t delaisMouvementOscilloMillis[3];
  uint32_t dureeTempeteMillis;
  uint8_t puissanceTempete;
  uint8_t accalmieNocturne;
  // horloge
  uint32_t heureDebutAlerte;
  uint32_t heureFinAlerte;
};
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 25, 2018, 11:33 am
J'ai retrouvé mon bout de code de démo, effectivement je pense que je ne l'avais pas posté dans cette discussion

SerialComMega et SerialComD1 en PJ car trop gros sinon.

pour le code de l'ESP, pensez à éditer
Code: [Select]
const char* ssid = "***********";
const char* password = "***********";


En gros le programme sur le MEGA écoute des commandes sur la ligne Serial (le moniteur Série Arduino) et balance de l'info ou des commandes sur Serial1. Au bout de Serial1 vous avez un ESP (D1 mini dans mon exemple ici) dont la loop() fait deux choses:
1/ écouter sur Serial si on a des demandes en provenances du MEGA
2/ écouter si on a une connexion web

ce qui est échangé entre les 2 Arduino est dans une structure, ici 3 octets a, b et c
Code: [Select]
struct data_t {
  int8_t a, b, c;
} data;


le MEGA reconnait des petites commandes simples

- taper i incrémentera de 1 a, b et c
- taper 0 remet a, b et c à 0
- taper r demande à recevoir les valeurs depuis le monde ESP


Si vous vous connectez sur le D1 mini (votre ESP) depuis le web en même temps et que vous modifiez a,b et c par les petites commandes, vous verrez que tout cela reste synchronisé.

entre le MEGA et le D1, il y a un petit protocole tout simple. le MEGA envoie $$E quand il veut envoyer des données, donc suivi de la structure et $$R quand il veut que le D1 lui envoie les valeurs courantes.

voilà un truc à explorer :)


Jean-Marc
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 25, 2018, 10:33 pm
toujours au TOP !
merci
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 25, 2018, 10:35 pm
vous verrez que tout cela reste synchronisé.
non c'est pas pour le vous lol, synchronisé oui a condition de rafraîchir la page

bon ba ya plus qu'as ...
déchiffrer tout cela dans un premier temps ... (les sentinelles, c'est pas dans matrix ou les château fort normalement ?:) )
et puis adapter tout cela
et ensuite resteras a faire la/les pages web GRRrrrr
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 26, 2018, 05:33 pm
 ;D  8)  :D  8)  ;D  :D

J'ai fait les modif et integrer le code dans mon code principale
J'ai fait les modif dans le code de L'esp

J'ai fait le test avec 3 variables issu de l'eeprom de l'arduino et sur la page web j'ai bien les bonnes valeurs
 :smiley-sweat:

Il falait bien ajouter a la fin du setup
Code: [Select]
envoyerAd1mini(sauvegarde);
Pour que l'ESP reçoive bien les valeurs après chargement de l'eeprom.

Il faut que j'ajoute cette ligne également après chaque sauvegarde des paramètre fait a partir de l'écran pour que l'ESP soit a jour.


Par contre  :smiley-confuse:
Il s'agit la des paramètres de l'eeprom donc utile pour la page "paramétrage"
Mais pour la page "menu" il me faut les variables "en cours" (puissance éclairage, brassage, température, ph ect ...) et toutes ces variable ne sont pas dans une structure ...
donc il faut tout mettre dans une structure aussi ?
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 26, 2018, 05:36 pm
bravo :)

donc il faut tout mettre dans une structure aussi ?
tel que je l'ai codé c'est assez "bourrin" - ça balance tous les octets d'un coup et une struct c'est pratique pour cela... donc si vous voulez faire autrement, il faut soit rajouter un peu d'intelligence dans la façon dont les cartes discutent, soit effectivement tout mettre dans la même structure...  :smiley-roll-blue:
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 26, 2018, 05:42 pm
euh ... rajouter un peu d'intelligence dans la façon dont les cartes discutent ... je voudrait bien mais j'en ai déjà pas assez pour moi ... alors si il faut en rajouter je passe avant le bout de code :)

mettre dans une structure me parait tout de même plus accessible :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 26, 2018, 05:56 pm
euh ... rajouter un peu d'intelligence dans la façon dont les cartes discutent ... je voudrait bien mais j'en ai déjà pas assez pour moi ... alors si il faut en rajouter je passe avant le bout de code :)
:)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 26, 2018, 07:33 pm
la structure est faite et tout a l'air de fonctionner comme avant.
Un peu de galère mais sa y est.

J'en arrive a la partie "écoute" il faudrait que la même fonction écoute et comprenne quelle structure est demandé.
Mais je ne comprend pas le &d
Code: [Select]
void ecouterCommande(paramS_t& d) {
 


et je pense que paramS_t est implanter a la place du (uint8_t*) ?
Code: [Select]
uint8_t * ptr = (uint8_t *)&d;

on peut lui faire comprendre quelle structure l'on veut ou alors j'écrit 2 début fonctions différent puis je lance la suite commune ?




Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 26, 2018, 08:19 pm
j'ai juste remplacer la structure en attendant
et voila
 (https://i.goopics.net/lm1v2.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 26, 2018, 08:27 pm
J'en arrive a la partie "écoute" il faudrait que la même fonction écoute et comprenne quelle structure est demandé.
Mais je ne comprend pas le &d
Code: [Select]
void ecouterCommande(paramS_t& d) {
 

le & c'est pour dire qu'on passe la structure par référence, donc j'ai une structure globale et quand j'appelle la fonction aucune copie n'est créée, je modifie bien la structure globale

dans mon code d'exemple j'ai
Code: [Select]
void ecouterCommande(data_t& d)
par ce que toutes les data sont stockées dans une structure de ce type là
Code: [Select]
struct data_t {
  int8_t a, b, c;
} data;


donc si dans votre côté arduino vous avez tout dans une structure paramS_t alors il faut déclarer la structure paramS_t aussi côté ESP de la même façon et utiliser cela.

pouvez vous poster ce à quoi ressemble votre grosse structure maintenant ?

--> il y a un truc auquel il faut faire attention, c'est la taille des types suivant les architectures... un int c'est 2 octets sur votre Arduino MEGA mais ce sera 4 sur l'ESP. donc il faut s'assurer de bien déclarer les types de la structure avec des int16_t par exemple des 2 côtés et pas le type "générique". Sinon quand on va balancer les octets d'un côté on va en envoyer 2 et de l'autre il va en attendre 4. Utililsez vous des double côté Arduino ou juste des float ? (ou pas du tout ?)


Il faudrait aussi faire attention si les octets sont inversés (les petits et grands indiens) mais on est en little endian des deux côtés il me semble donc pas  de soucis de ce côté là.

Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: J-M-L on Aug 26, 2018, 08:28 pm
j'ai juste remplacer la structure en attendant
et voila
 (https://i.goopics.net/lm1v2.jpg)
(https://i.goopics.net/lm1v2.jpg)



joli !!!

(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 26, 2018, 09:17 pm
joli !!!
mdr, faut pas exagerer lol
(https://www.hieroglyphes.fr/io/shop_produit/images/dyn_image2_0005502_Herbin_Bon_Point_2_Vert_jpg_large.jpg)
merci :)
Title: Re: AQUABOUN'S /// GESTION D'AQUARIUM RECIFAL
Post by: djbouns on Aug 26, 2018, 10:02 pm
le & c'est pour dire qu'on passe la structure par référence, donc j'ai une structure globale et quand j'appelle la fonction aucune copie n'est créée, je modifie bien la structure globale
je n'est pas bien compris car cette fonction ne modifie rien elle ne fait que lire ?
J'ai fini par trouver ca (http://www.cplusplus.com/doc/tutorial/pointers/)
je n'est pas tout lu mais juste la partie &
il explique que de mètre & pointe vers l'adresse mémoire de la variable (pour nous la structur ?) au lieu de la valeur contenu a cette adresse.


Quote
donc si dans votre côté arduino vous avez tout dans une structure paramS_t alors il faut déclarer la structure paramS_t aussi côté ESP de la même façon et utiliser cela.
J'avais bien compris et c'est bien se que j'ai fait, les structur sont identique dans les 2 code (arduino et esp)

Quote
pouvez vous poster ce à quoi ressemble votre grosse structure maintenant ?
Non, secret defence !

Quote
--> il y a un truc auquel il faut faire attention, c'est la taille des types suivant les architectures...
je n'utilise que des uint*_t depuis que j'ai appris chef :)



Quote
Utililsez vous des double côté Arduino ou juste des float ? (ou pas du tout ?)
que du float

Quote
Il faudrait aussi faire attention si les octets sont inversés (les petits et grands indiens)
c'est toi qui a inversé !!!
c'est pas petits et grands indien,
c'est grand indien, petit indiens



(https://images-na.ssl-images-amazon.com/images/I/61FmERXAEKL._SX391_BO1,204,203,200_.jpg)


pendant que tu souri, j'envoie mes structures :
celle de l'eeprom
Code: [Select]
struct __attribute__ ((packed)) paramS_t {// force l'ordre des champs
  // page menu
  bool tempeteAleatoireOn;
  bool nourrissageON[2];
  uint8_t remonteDelay;
  uint8_t eclairageOnOffPwm[4];
  uint8_t brassageOnOffPwm[3];
  // page config
  uint8_t puissanceMaxEclairage[4];
  uint32_t leverSoleil;
  uint32_t coucherSoleil;
  uint16_t dureelevercoucher;
  float alertetemperaturebasse;
  float alertetemperaturehaute;
  float ventilationaquarium;
  uint8_t ventilationrampe;
  bool adresseSondeRampe;
  bool adresseSondeBac;
  uint32_t heureNourrissage[2];
  uint32_t dureeNourrissageMillis;
  uint16_t dureeOsmolationMillis ;
  uint8_t compteurOsmolationMax;
  uint16_t consignePhRac;
  uint16_t alertephbacbas;
  uint16_t alertephbachaut;
  // page brassage
  uint8_t puissanceMaxBrassage[3];
  uint8_t angle1Oscillo[3];
  uint8_t angle2Oscillo[3];
  uint16_t delaisMouvementOscilloMillis[3];
  uint32_t dureeTempeteMillis;
  uint8_t puissanceTempete;
  uint8_t accalmieNocturne;
  // horloge
  uint32_t heureDebutAlerte;
  uint32_t heureFinAlerte;
};
extern paramS_t sauvegarde;


et la nouvelle des variables