Projet Terminale Contrôler LED et afficher Capteur sur un site

Bonjour,

Je suis en train de travailler sur mon projet de terminale STI2D,
J'aimerais piloter des LED à distance et afficher les informations d'un capteur sur mon site,
J'ai déjà réussi à faire un programme fonctionnel seulement, les informations ne s'affichent pas en même temps, je m'explique :

-Je rafraîchis une première fois ma page et ça m'affiche les informations du capteur

-Je rafraîchis une deuxième fois la page et il se peut que ce soit les LED

J'ai regardé et ça change de manière aléatoire, ça peut très bien être 5 fois le capteur et 27 fois les LED.

Je précise que j'ai un niveau très médiocre en arduino donc merci de m'expliquer avec des mots simples.
Je précise aussi que mon programme est assez immonde à regarder, puisque je me suis basé sur deux programme trouvé sur internet que j'ai assemblé par la suite.

Je vous laisse mon programmes juste en dessous:

#include <SPI.h> //bibliothèqe pour SPI
#include <Ethernet.h> //bibliothèque pour Ethernet
byte mac[] = {0x90, 0xA2, 0xDA, 0x0F, 0xDF, 0xAB}; //adresse mac de votre carte
byte ip[] = {113, 113,113, 113}; //adresse IP
unsigned long tpsDep; //temps départ pour la gestion des LED
int pinLed[3] = {2,5,7}; //tableau des pins de LED
boolean etatLed[5] = {0, 0, 0, 0, 0}; //tableau des états des LED
int modeLed[5] = {0, 0, 0, 0, 0}; // tableau des modes des LED
EthernetServer serveur(113); // déclare l'objet serveur au port d'écoute 80

void setup() 
{
 char erreur = 0
   pinMode(A2, INPUT);
  pinMode(A3, INPUT);
Serial.begin (9600);
  for (int l = 0; l < 3; l++) {
    pinMode(pinLed[3], OUTPUT);
  }
  Ethernet.begin (mac, ip); //initialisation de la communication Ethernet
  Serial.print("*\n-> Le serveur est sur l'adresse : ");
  Serial.println(Ethernet.localIP()); //on affiche l'adresse IP de la connexion
  serveur.begin(); // démarre l'écoute
}


void loop() {
  //Programme Capteur
// Regarde si un client est connecté et attend une réponse
  EthernetClient client = serveur.available();
  if (client) {
    // Quelqu'un est connecté !
    Serial.print("On envoi !");
    // On fait notre en-tête
    // Tout d'abord le code de réponse 200 = réussite
    client.println("HTTP/1.1 200 OK");
    // Puis le type mime du contenu renvoyé, du json
    client.println("Content-Type: application/json");
    // Et c'est tout !
    // On envoie une ligne vide pour signaler la fin du header
    client.println();

    // Puis on commence notre JSON par une accolade ouvrante
    client.println("{");
    // On envoie la première clé : "uptime"
    client.print("\t\"uptime (ms)\": ");
    // Puis la valeur de l'uptime
    client.print(millis());
    //Une petite virgule pour séparer les deux clés
    client.println(",");
    // Et on envoie la seconde nommée "analog 0"
    client.print("\t\"analog 0\": ");
    client.println(analogRead(A0));
    // Et enfin on termine notre JSON par une accolade fermante
    client.println("}");
    // Donne le temps au client de prendre les données
    delay(10);
    // Ferme la connexion avec le client
    client.stop();
  } 
  //Programme LED
  Serial.println (analogRead(A3));
delay(1000);
  gestionClient(); // fonction qui gère toute la communication avec le client
  gestionLed(); // fonction qui gère l'allumage des LED
}


//----------------------Fonctions----------------------
//fonction qui gère la communication avec le client
void gestionClient() {
  EthernetClient client = serveur.available(); //on écoute le port
  if (client) { //si client existe
    Serial.println("Client en ligne"); //on le dit...
    if (client.connected()) { // si le client est connecté
      GET(client); //appel de la fonction de décodage
      //réponse au client
      entete(client); // fonction pour l'entête de la page HTML
      corps(client); // fonction pour le corps
      piedPage(client); // fonction pour le pied de page
      Serial.println("Fin de communication avec le client\n");
      client.stop(); //on déconnecte le client
    }
  }
}
//fonction de fabrication de l'entête HTML
void entete(EthernetClient cl) {
  //infos pour le navigateur
  cl.println("HTTP/1.1 200 OK"); // type du HTML
  cl.println("Content-Type: text/html; charset=ascii"); //type de fichier et encodage des caractères
  cl.println("Connection: close");  // fermeture de la connexion quand toute la réponse sera envoyée
  cl.println();
  //balises d'entête
  cl.println("<!DOCTYPE HTML>");
  cl.println("<html>");
  cl.println("<head><title>Projet ETT</title></head>");
  cl.println("<body><h1>Projet ETT</h1><hr>
");
}
//fonction de fabrication du corps de page
void corps(EthernetClient cl) {
  cl.println("
"); // saut de ligne
  //boucle pour construire chaque ligne en fonction des LED
  for (int l = 0; l < 4; l++) {
    cl.print("
LED ");
    cl.print(l);
    cl.print(" ");
    Serial.println(l);
    switch (modeLed[l]) {
      case 0:
        cl.print("OFF ");
        break;
      case 1:
        cl.print("ON ");
        break;
      case 2:
        cl.print("CLI ");
        break;
        case 3:
             GET(analogRead(A3));
             cl.print("
CAPTEUR ");
    cl.print(l);
    cl.print(" ");
          cl.println("Capteur"); // saut de ligne
          cl.print("
Lumière = "); 
          cl.print(analogRead(A3)); 
          cl.print("lux"); 
             cl.println("
");
              
     
          cl.println("</html>");
          break; 
    }
    cl.print(" <a href=?"); //création du lien inutile de répéter l'adresse du site
    cl.print(l);
    cl.println(" target=_self >Change</a>
");
  }
}
//fonction de fabrication du pied de page
void piedPage(EthernetClient cl) {
  //balises de pied de page
  cl.println("
<hr>");
  cl.println("</body>");
  cl.println("</html>");
}
//fonctin décodage GET
void GET(EthernetClient cl) {
  boolean lu = 0; //variable pour indiquer l'état de lecture
  while (cl.available()) { // tant qu'il a des infos à transmettre
    char c = cl.read(); // on lit le caractère
    delay(1); //delai de lecture
    if (c == '?' && lu == 0) { //si "?" repéré
      c = cl.read(); //on lit le caractère suivant qui contient la donnée
      int led = int(c) - 48; //on la transforme en nombre
      modeLed[led] = (modeLed[led] + 1) % 3; //on change l'état de la LED
      delay(10);
      lu = 1; // on dit qu'on a lu l'info
    }

  }
}
//fonction d'allumage des LED par rapport au tableau de mode.
void gestionLed() {
  unsigned long tpsAct = millis(); // récupération du temps actuel
  if (tpsAct - tpsDep > 250) { //si délai dépassé
    for (int l = 0; l < 5; l++) { // chaque LED
      if (modeLed[l] == 0) { // si mode éteint
        etatLed[l] = 0; // on éteind
      }
      else if (modeLed[l] == 1) {// si mode allumé
        etatLed[l] = 1; //on allume
      }
      else if (modeLed[l] == 2) { //si mode clignotant
        etatLed[l] = !etatLed[l]; //on inverse l'état
      }
      digitalWrite(pinLed[l], etatLed[l]); //on met le pin à jour
      tpsDep = tpsAct; //on réinitialise le temps
    }
  }
//Programme Capteur
// Regarde si un client est connecté et attend une réponse
  EthernetClient client = serveur.available();
  if (client) {
    // Quelqu'un est connecté !
    Serial.print("On envoi !");
    // On fait notre en-tête
    // Tout d'abord le code de réponse 200 = réussite
    client.println("HTTP/1.1 200 OK");
    // Puis le type mime du contenu renvoyé, du json
    client.println("Content-Type: application/json");
    // Et c'est tout !
    // On envoie une ligne vide pour signaler la fin du header
    client.println();

    // Puis on commence notre JSON par une accolade ouvrante
    client.println("{");
    // On envoie la première clé : "uptime"
    client.print("\t\"uptime (ms)\": ");
    // Puis la valeur de l'uptime
    client.print(millis());
    //Une petite virgule pour séparer les deux clés
    client.println(",");
    // Et on envoie la seconde nommée "analog 0"
    client.print("\t\"analog 0\": ");
    client.println(analogRead(A0));
    // Et enfin on termine notre JSON par une accolade fermante
    client.println("}");
    // Donne le temps au client de prendre les données
    delay(10);
    // Ferme la connexion avec le client
    client.stop();
  }
}

Annonce projet scolaire : check.
Code entre balises : check.

Ça s'annonce bien... :sunglasses: Tu aurais pu faire un CTRL T dans l'IDE pour une indentation automatique...

Pourquoi les lignes de l'envoi du json capteur se retrouvent-elles identiques à deux endroits différents (loop et gestion led) ?

lesept:
Annonce projet scolaire : check.
Code entre balises : check.

Ça s'annonce bien... :sunglasses: Tu aurais pu faire un CTRL T dans l'IDE pour une indentation automatique...

Désolé, comme je l'ai précisé je ne m'y connais pas en arduino, je ne connaissais pas cette fonctionnalité

J'ai examiné ton code.

Ce qui m'étonne est la présence de plusieurs lignes du type EthernetClient client = serveur.available();

Cette ligne devrait être unique.

Comme tu peux le voir dans cet exemple : http.cpp.

La méthode http_request::read() est appelée par la fonction loop() comme ceci :

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    // lit et exécute la prochaine requête
    http.read(&client);
  }
}

Une requête HTTP ressemble à ceci :
/nom?arg1=valeur1&arg2=valeur2

A chaque fois que server.available() renvoie True la méthode http_request::read() est appelée et elle décompose la requête :

  • le nom
  • les arguments avec leur valeur

Elle appelle ensuite la fonction de traitement qui correspond à l'identifiant.

Il y a je pense une confusion comme le suggère ton commentaire :

// Regarde si un client est connecté et attend une réponse
// ce commentaire n'est pas correct
// ce serait plutôt :
// Regarde si un client vient a envoyé une requête

Tu dois lire la requête en entier à chaque fois que server.available() retourne une valeur différente de ZÉRO.
Ensuite tu dois analyser la requête et prendre les décisions qui s'imposent.

La fonction gestionLed() ne devrait pas appeler server.available(), car gestionClient() a déjà lu le requête et il n'y a plus rien à lire.
Je pense qu'en supprimant les lignes 182 183 (plus l'accolade fermante en 212) cela devrait déjà améliorer pas mal.

Remarques :
Il n'y a qu'une seule URL ( / ou /index) car tu ignores tous les caractères avant le '?'.
Je ne vois aucun bouton dans le code HTML qui permettrait d'actionner les LEDs ON, OFF, BLINK avec la souris.
Je suppose que tu le fais en entrant les URL dans la barre du navigateur ?
Pas très pratique.

hbachetti:
J'ai examiné ton code.

Ce qui m'étonne est la présence de plusieurs lignes du type EthernetClient client = serveur.available();

Cette ligne devrait être unique.

Comme tu peux le voir dans cet exemple : http.cpp.

La méthode http_request::read() est appelée par la fonction loop() comme ceci :

void loop() {

// listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    // lit et exécute la prochaine requête
    http.read(&client);
  }
}




Une requête HTTP ressemble à ceci :
/nom?arg1=valeur1&arg2=valeur2

A chaque fois que server.available() renvoie True la méthode http_request::read() est appelée et elle décompose la requête :
- le nom
- les arguments avec leur valeur

Elle appelle ensuite la fonction de traitement qui correspond à l'identifiant.

Il y a je pense une confusion comme le suggère ton commentaire :



// Regarde si un client est connecté et attend une réponse
// ce commentaire n'est pas correct
// ce serait plutôt :
// Regarde si un client vient a envoyé une requête




Tu dois lire la requête en entier à chaque fois que server.available() retourne une valeur différente de ZÉRO.
Ensuite tu dois analyser la requête et prendre les décisions qui s'imposent.

La fonction gestionLed() ne devrait pas appeler server.available(), car gestionClient() a déjà lu le requête et il n'y a plus rien à lire.
Je pense qu'en supprimant les lignes 182 183 (plus l'accolade fermante en 212) cela devrait déjà améliorer pas mal.

Remarques :
Il n'y a qu'une seule URL ( / ou /index) car tu ignores tous les caractères avant le '?'.
Je ne vois aucun bouton dans le code HTML qui permettrait d'actionner les LEDs ON, OFF, BLINK avec la souris.
Je suppose que tu le fais en entrant les URL dans la barre du navigateur ?
Pas très pratique.

Merci beaucoup pour ton message et pour ton temps. je vais tester ça quand j'aurais le temps

Sur le fond, ça ne me paraît pas une bonne idée que de chercher à faire marcher un programme que son auteur :confused: ne maitrise pas du tout du tout...