Pretzel Board IOT - Horloge TCP écran LCD 2*16 - Bug bizarre

Bonjour,

j’ai donc commencé à expérimenter avec le coffret Franzis Maker Kit IOT

La boite contient une carte Pretzel Wifi, c’est une carte compatible Arduino Nano (Nano ESP) avec module ESP8266 WIFI.

J’ai installé le driver série USB CH340G, ainsi que l’IDE Arduino 1.8.12, avec mon PC sous Windows 7 pro 64.

Pour la configuration :

  • Type de carte “Arduino Nano”
  • Processeur “ATmega328P (Old Bootloader)”
  • Port: “COM6”
  • Programmateur “USBasp”

J’ai suivit les premiers exemples.
On arrive à un truc intéressant avec l’horloge TCP.

J’ai adapté le code pour me familiariser avec l’outil, ça fonctionne :

#include <SD.h>

#define SSID "XXXX"
#define PASSWORD "MA_CLEF_WEP"

#define DEBUG true

#define LED_WLAN 13

#include <SoftwareSerial.h>
#include <TimeLib.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);
SoftwareSerial esp8266(11, 12); // RX, TX

void setup() {
  Serial.begin(19200);
  esp8266.begin(19200);


  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Horloge Web");


  if (!espConfig()) serialDebug();
  else digitalWrite(LED_WLAN, HIGH);


  lcd.setCursor(0, 1);
  lcd.print("Liaison WIFI OK");


  getTime("chronic.herokuapp.com", "/utc/in+two+hours"); //Gets Time from Page and Sets it
}

void loop() {
  String shour, sminute, ssecond, sday, smonth, sweekday;

  delay(1000);

  if (hour() <= 9) shour = "0" + String(hour()); else shour = String(hour()); // adjust for 0-9
  if (minute() <= 9) sminute = "0" + String(minute());  else sminute = String(minute());
  if (second() <= 9) ssecond = "0" + String(second());  else ssecond = String(second());

sweekday = String(weekday()) + " Jeudi";

  String Time =  shour + "h" + sminute + ":" + ssecond + " " + sweekday;

sday = String(day()); 
switch (month()) {
  case 1:
    smonth = "janvier";
    break;
  case 2:
    smonth = "fevrier";
    break;
  case 3:
    smonth = "mars";
    break;
  case 4:
    smonth = "avril";
    break;
  case 5:
    smonth = "mai";
    break;
  case 6:
    smonth = "juin";
    break;
  case 7:
    smonth = "juillet";
    break;
  case 8:
    smonth = "aout";
    break;
  case 9:
    if (sday.length()>1) {
      smonth = "septembr";  
    } else {
      smonth = "septembre";
    }
    break;
  case 10:
    smonth = "octobre";
    break;
  case 11:
    smonth = "novembre";
    break;
  default:
    smonth = "decembre";
    break;
}

  String Date = sday + " " + smonth + " " + String(year()) ;
  
  int LgTxt;
  int NbSp;
  LgTxt = Date.length();
  if (LgTxt<16) {
    NbSp = (16 - LgTxt) / 2;
    for (int i=1;i<=NbSp;i++) {
      Date = " " + Date;    
    }
    NbSp = 16 - LgTxt - NbSp;
    for (int i=1;i<=NbSp;i++) {
      Date = Date + " ";
    }
  }

  debug(Date);
  debug(Time);

  lcd.setCursor(0, 0);
  lcd.print(Time);

  lcd.setCursor(0, 1);
  lcd.print(Date);
  
}


String getTCP(String Host, String Subpage)
{
  boolean success = true;

  success &= sendCom("AT+CIPSTART=\"TCP\",\"" + Host + "\",80", "OK");
  String getRequest = "GET " + Subpage + " HTTP/1.1\r\nHost:" + Host + "\r\n\r\n";
  success &= sendCom("AT+CIPSEND=" + String(getRequest.length() + 2), ">");

  return sendCom(getRequest);
}

boolean getTime(String Host, String Subpage)
{
  boolean success = true;
  int xyear, xmonth, xday, xhour, xminute, xsecond;  //lokal variables

  success &= sendCom("AT+CIPSTART=\"TCP\",\"" + Host + "\",80", "OK");
  String getRequest = "GET " + Subpage + " HTTP/1.1\r\nHost:" + Host + "\r\n";
  success &= sendCom("AT+CIPSEND=" + String(getRequest.length() + 2), ">");

  esp8266.println(getRequest);

  if (esp8266.find("+IPD"))
  {
    if (esp8266.find("\r\n\r\n"))
    {
      xyear = esp8266.parseInt();
      xmonth = esp8266.parseInt();
      xday = esp8266.parseInt();
      xhour = esp8266.parseInt();
      xminute = esp8266.parseInt();
      xsecond = esp8266.parseInt();

      if (xday < 0) xday *= -1;          //Because of date seperator - parseInt detects negativ integer
      if (xmonth < 0) xmonth *= -1;    //Because of date seperator - parseInt detects negativ integer


      setTime(xhour, xminute, xsecond, xday, xmonth, xyear);
      sendCom("AT+CIPCLOSE", "OK");
      return true;
    }
    else return false;
  }
  else return false;
}

//-----------------------------------------Config ESP8266------------------------------------

boolean espConfig()
{
  boolean success = true;
  esp8266.setTimeout(5000);
  success &= sendCom("AT+RST", "ready");
  esp8266.setTimeout(1000);
  if (configStation(SSID, PASSWORD)) {
    success &= true;
    debug("WLAN Connected");
    debug("My IP is:");
    debug(sendCom("AT+CIFSR"));
  }
  else
  {
    success &= false;
  }
  //shorter Timeout for faster wrong UPD-Comands handling
  success &= sendCom("AT+CIPMODE=0", "OK");  //So rum scheit wichtig!
  success &= sendCom("AT+CIPMUX=0", "OK");

  return success;
}

boolean configTCPServer()
{
  boolean success = true;

  success &= (sendCom("AT+CIPMUX=1", "OK"));
  success &= (sendCom("AT+CIPSERVER=1,80", "OK"));

  return success;

}

boolean configTCPClient()
{
  boolean success = true;

  success &= (sendCom("AT+CIPMUX=0", "OK"));
  //success &= (sendCom("AT+CIPSERVER=1,80", "OK"));

  return success;

}


boolean configStation(String vSSID, String vPASSWORT)
{
  boolean success = true;
  success &= (sendCom("AT+CWMODE=1", "OK"));
  esp8266.setTimeout(20000);
  success &= (sendCom("AT+CWJAP=\"" + String(vSSID) + "\",\"" + String(vPASSWORT) + "\"", "OK"));
  esp8266.setTimeout(1000);
  return success;
}

boolean configAP()
{
  boolean success = true;

  success &= (sendCom("AT+CWMODE=2", "OK"));
  success &= (sendCom("AT+CWSAP=\"NanoESP\",\"\",5,0", "OK"));

  return success;
}

boolean configUDP()
{
  boolean success = true;

  success &= (sendCom("AT+CIPMODE=0", "OK"));
  success &= (sendCom("AT+CIPMUX=0", "OK"));
  success &= sendCom("AT+CIPSTART=\"UDP\",\"192.168.255.255\",90,91,2", "OK"); //Importand Boradcast...Reconnect IP
  return success;
}

//-----------------------------------------------Controll ESP-----------------------------------------------------

boolean sendUDP(String Msg)
{
  boolean success = true;

  success &= sendCom("AT+CIPSEND=" + String(Msg.length() + 2), ">");    //+",\"192.168.4.2\",90", ">");
  if (success)
  {
    success &= sendCom(Msg, "OK");
  }
  return success;
}


boolean sendCom(String command, char respond[])
{
  esp8266.println(command);
  if (esp8266.findUntil(respond, "ERROR"))
  {
    return true;
  }
  else
  {
    debug("ESP SEND ERROR: " + command);
    return false;
  }
}

String sendCom(String command)
{
  esp8266.println(command);
  return esp8266.readString();
}


void serialDebug() {
  while (true)
  {
    if (esp8266.available())
      Serial.write(esp8266.read());
    if (Serial.available())
      esp8266.write(Serial.read());
  }
}

void debug(String Msg)
{
  if (DEBUG)
  {
    Serial.println(Msg);
  }
}

Voici une photo de ce que ça donne :

Mais quand je souhaite remplacer la ligne :

sweekday = String(weekday()) + " Jeudi";

par le code suivant :

switch (weekday()) {
//switch (second()%7+1) {
  case 1:
    sweekday = "Dimanch";
    break;
  case 2:
    sweekday = "  Lundi";
    break;
  case 3:
    sweekday = "  Mardi";
    break;
  case 4:
    sweekday = "Mercred";
    break;
  case 5:
    sweekday = "  Jeudi";
    break;
  case 6:
    sweekday = "Vendred";
    break;
  default:
    sweekday = " Samedi";
    break;
}

Ca ne marche plus !

Ca compile sans soucis, ça se téléverse sans soucis, mais l’afficheur LCD reste bloqué sur “Horloge Web”

Je ne vois pas le message “Liaison WIFI OK”, ni l’heure et la date qui s’affiche ensuite dans le LCD

Le moniteur série reste lui aussi muet, mais il réagit normalement si je lui tape une commande comme par exemple “AT+GMR”

20:12:05.376 -> AT+GMR
20:12:05.376 -> AT version:0.22.0.0(Mar 20 2015 10:04:26)
20:12:05.410 -> SDK version:1.0.0
20:12:05.410 -> compile time:Mar 20 2015 11:00:32
20:12:05.410 -> 
20:12:05.410 -> OK

Bizarrement dans le menu admin de ma freebox, je vois que ma carte PRETZEL est connectée, et qu’elle communique :

(c’est la carte Espressif Inc.)

Donc c’est à moitié planté (l’affichage ne se fait plus sur l’écran LCD ni sur le moniteur série)

Je viens de passer l’après midi sur ce problème sans comprendre pourquoi ça ne fonctionne pas…

Avez-vous une piste ?

Merci

A bientôt

Bonjour,

J’ai mis à jour le firmware de l’ESP8266 sans succès.

Il semble qu’il y a une incompatibilité entre SoftwareSerial et LiquidCrystal, dans certains cas l’usage de l’un plante l’usage de l’autre.

C’est franchement merdique !

J’ai trouvé d’autres personnes ayant un problème similaire avec ces deux bibliothèques sur des forums anglophones mais pas de solution.

Le gros soucis c’est que dans la carte Pretzel, SoftwareSerial est nécessaire pour que la partie Arduino Nano communique avec la partie ESP8266

A bientôt

La où c’est bizarre, c’est le programme suivant qui marche bien en utilisant juste le moniteur série :

#include <SD.h>

/*
TCP Time Sync.

Time Source:
http://chronic.herokuapp.com/

Change SSID and PASSWORD.
*/

#define SSID "BOX"
#define PASSWORD "WEP"

#define DEBUG false
#define LED_WLAN 13
#include <SoftwareSerial.h>
#include <TimeLib.h>
#include <LiquidCrystal.h>

#define LCD false
//LiquidCrystal lcd(A0, A1, A2, A3, A4, A5); // RS, E, D4, D5, D6, D7
SoftwareSerial esp8266(11, 12); // RX, TX

void setup() {
  Serial.begin(19200);
  esp8266.begin(19200);


  EcrireTitre();

  if (!espConfig()) {
    EcrirePasWIFI();
  }  else {
    digitalWrite(LED_WLAN, HIGH);
    EcrireWIFI();
  }

  getTime("chronic.herokuapp.com", "/utc/in+two+hours"); //Gets Time from Page and Sets it
}

void loop() {
  String shour, sminute, ssecond, sday, smonth, sweekday;

  delay(1000);

  if (hour() <= 9) shour = "0" + String(hour()); else shour = String(hour()); // adjust for 0-9
  if (minute() <= 9) sminute = "0" + String(minute());  else sminute = String(minute());
  if (second() <= 9) ssecond = "0" + String(second());  else ssecond = String(second());

switch (weekday()) {
//switch (second()%7+1) {
  case 1:
    sweekday = "Dimanch";
    break;
  case 2:
    sweekday = "  Lundi";
    break;
  case 3:
    sweekday = "  Mardi";
    break;
  case 4:
    sweekday = "Mercred";
    break;
  case 5:
    sweekday = "  Jeudi";
    break;
  case 6:
    sweekday = "Vendred";
    break;
  default:
    sweekday = " Samedi";
    break;
}

  String Time =  shour + "h" + sminute + ":" + ssecond + " " + sweekday;

sday = String(day()); 
//switch ((month()+second())%12+1) {   // Code pour tester l'affichage de chaque mois
switch (month()) {
  case 1:
    smonth = "janvier";
    break;
  case 2:
    smonth = "fevrier";
    break;
  case 3:
    smonth = "mars";
    break;
  case 4:
    smonth = "avril";
    break;
  case 5:
    smonth = "mai";
    break;
  case 6:
    smonth = "juin";
    break;
  case 7:
    smonth = "juillet";
    break;
  case 8:
    smonth = "aout";
    break;
  case 9:
    if (sday.length()>1) {
      smonth = "septembr";  
    } else {
      smonth = "septembre";
    }
    break;
  case 10:
    smonth = "octobre";
    break;
  case 11:
    smonth = "novembre";
    break;
  default:
    smonth = "decembre";
    break;
}

  String Date = sday + " " + smonth + " " + String(year()) ;
  
  //Code pour centrer la date :
  int LgTxt;
  int NbSp;
  LgTxt = Date.length();
  if (LgTxt<16) {
    NbSp = (16 - LgTxt) / 2;
    for (int i=1;i<=NbSp;i++) {
      Date = " " + Date;    
    }
    NbSp = 16 - LgTxt - NbSp;
    for (int i=1;i<=NbSp;i++) {
      Date = Date + " ";
    }
  }

  EcrireHeure(Time);
  EcrireDate(Date);
}


void EcrireTitre() {
    Serial.println("Horloge Web");
}
void EcrirePasWIFI() {
    Serial.println("Pas de WIFI");
}
void EcrireWIFI() {
    Serial.println("Liaison WIFI OK");
}
void EcrireHeure(String Time) {
    Serial.println(Time);
}
void EcrireDate(String Date) {
    Serial.println(Date);
}

/*
void EcrireTitre() {
  if (LCD) {
    lcd.begin(16, 2);
    lcd.setCursor(0, 0);
    lcd.print("Horloge Web");
  } else {
    Serial.println("Horloge Web");
  }
}
void EcrirePasWIFI() {
  if (LCD) {
    lcd.setCursor(0, 1);
    lcd.print("Pas de WIFI");
  } else {
    Serial.println("Pas de WIFI");
  }
}
void EcrireWIFI() {
  if (LCD) {
    lcd.setCursor(0, 1);
    lcd.print("Liaison WIFI OK");
  } else {
    Serial.println("Liaison WIFI OK");
  }
}
void EcrireHeure(String Time) {
  if (LCD) {
    lcd.setCursor(0, 0);
    lcd.print(Time);
  } else {
    Serial.println(Time);
  }
}
void EcrireDate(String Date) {
  if (LCD) {
    lcd.setCursor(0, 1);
    lcd.print(Date);
  } else {
    Serial.println(Date);
  }
}
*/


String getTCP(String Host, String Subpage)
{
  boolean success = true;

  success &= sendCom("AT+CIPSTART=\"TCP\",\"" + Host + "\",80", "OK");
  String getRequest = "GET " + Subpage + " HTTP/1.1\r\nHost:" + Host + "\r\n\r\n";
  success &= sendCom("AT+CIPSEND=" + String(getRequest.length() + 2), ">");

  return sendCom(getRequest);
}

boolean getTime(String Host, String Subpage)
{
  boolean success = true;
  int xyear, xmonth, xday, xhour, xminute, xsecond;  //lokal variables

  success &= sendCom("AT+CIPSTART=\"TCP\",\"" + Host + "\",80", "OK");
  String getRequest = "GET " + Subpage + " HTTP/1.1\r\nHost:" + Host + "\r\n";
  success &= sendCom("AT+CIPSEND=" + String(getRequest.length() + 2), ">");

  esp8266.println(getRequest);

  if (esp8266.find("+IPD"))
  {
    if (esp8266.find("\r\n\r\n"))
    {
      xyear = esp8266.parseInt();
      xmonth = esp8266.parseInt();
      xday = esp8266.parseInt();
      xhour = esp8266.parseInt();
      xminute = esp8266.parseInt();
      xsecond = esp8266.parseInt();

      if (xday < 0) xday *= -1;          //Because of date seperator - parseInt detects negativ integer
      if (xmonth < 0) xmonth *= -1;    //Because of date seperator - parseInt detects negativ integer


      setTime(xhour, xminute, xsecond, xday, xmonth, xyear);
      sendCom("AT+CIPCLOSE", "OK");
      return true;
    }
    else return false;
  }
  else return false;
}

//-----------------------------------------Config ESP8266------------------------------------

boolean espConfig()
{
  boolean success = true;
  esp8266.setTimeout(5000);
  success &= sendCom("AT+RST", "ready");
  esp8266.setTimeout(1000);
  if (configStation(SSID, PASSWORD)) {
    success &= true;
    //debug("WLAN Connected");
    //debug("My IP is:");
    //debug(sendCom("AT+CIFSR"));
  }
  else
  {
    success &= false;
  }
  //shorter Timeout for faster wrong UPD-Comands handling
  success &= sendCom("AT+CIPMODE=0", "OK");  //So rum scheit wichtig!
  success &= sendCom("AT+CIPMUX=0", "OK");

  return success;
}

boolean configStation(String vSSID, String vPASSWORT)
{
  boolean success = true;
  success &= (sendCom("AT+CWMODE=1", "OK"));
  esp8266.setTimeout(20000);
  success &= (sendCom("AT+CWJAP=\"" + String(vSSID) + "\",\"" + String(vPASSWORT) + "\"", "OK"));
  esp8266.setTimeout(1000);
  return success;
}

//-----------------------------------------------Controll ESP-----------------------------------------------------

boolean sendCom(String command, char respond[])
{
  esp8266.println(command);
  if (esp8266.findUntil(respond, "ERROR"))
  {
    return true;
  }
  else
  {
    //debug("ESP SEND ERROR: " + command);
    return false;
  }
}

String sendCom(String command)
{
  esp8266.println(command);
  return esp8266.readString();
}

Mais si je remplace juste
//LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);
par
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);

Le programme n’arrive plus à se connecter en WIFI !

Tout le reste fonctionne…

C’est incompréhensible >:(

A bientôt

Bonjour,

le problème a été résolu, tout est expliqué en détail sur le forum Developpez.com

https://www.developpez.net/forums/d2064281/general-developpement/programmation-systeme/embarque/arduino/pretzel-board-iot-bug-bizarre/

Le problème était lié à l'usage des chaines de caractères avec l'objet String, bien trop gourmand en ressources.

Le fil de discussion explique comment optimiser le code lorsqu'on doit utiliser beaucoup de chaines de caractères.

A bientôt

Bonjour ..et merci pour ce retour qui valide une fois de plus les mises en gardes quotidiennes contre la classe String sur ce forum et les invitation à utiliser les C strings !!

et d'ailleurs 'bug bizarre" et "String" vont souvent ensemble !

autres lectures parmi les nombreuses références sur ce forum :

qui renvoie ici : RitonDuino: ARDUINO : la fragmentation mémoire

Bonjour,

Merci pour les liens, les explications sont très détaillées et en français !

J'ai perdu pas mal de temps pour trouver ces informations pourtant essentielles.

Il est fort dommage que ces informations ne figurent pas dans la référence du site officiel Arduino (ils pourraient au moins mettre un petit avertissement et des liens).

De même, il est fort dommage qu'un kit commercial vendu pour apprendre à utiliser les Arduinos possède des codes sources donnés en exemples aussi mauvais.

Quand on connais les règles à suivre ce n'est pas si difficile que ça. Encore faut-il savoir qu'elles existent !

A trop vouloir rendre une technologie facile on coince ensuite les gens ce qui a l'effet inverse du but recherché.

J'imagine la déconvenue du gamin ou de la gamine de 12 ans qui arrive à faire fonctionner des petits exemples et qui tombe ensuite comme moi sur des bugs incompréhensibles, devoir ensuite passer beaucoup de temps à chercher et à digérer les bonnes réponses, pour les adapter à son Arduino et à son projet.

D'autant que le lien entre le problème initial et sa cause n'avait rien d'évident ! Les moteurs de recherche ne permettent de trouver que ce qu'on cherche, sans poser la bonne question impossible d'avoir la bonne réponse.

A bientôt

Bonjour,

Toujours à propos de cette carte "Pretzel", ici comment réaliser un serveur HTTP correct :

https://www.developpez.net/forums/d2067560/general-developpement/programmation-systeme/embarque/arduino/esp8266-serveur-tcp-page-html-io-error-the-server-failed-to-respond-with-valid-http-response/

La aussi le code source donné dans les exemples était assez édifiant : les auteurs ont oublié de générer la réponse HTTP requise avant d'envoyer les données !

Cordialement