Les Bases d'un Serveur Web sur ESP-01 en commande AT

Cette fonction nous sera bien utile, après avoir envoyé une commande à l'ESP pour s'assurer qu'il nous répond bien "Ready" ou "OK".

Se pose donc la question de l'envoi des données à l'ESP. Certes, c'est simplement écrire sur le port série, mais comme on va le faire souvent, autant se dotter de petits outils qui vont nous simplifier la vie.

Il nous faut une fonction qui envoie une commande, et attends pendant un certain temps le code de réponse et retourne VRAI si ça s'est bien passé et faux sinon.

Mais ce n'est pas toujours aussi simple, parfois il faut passer des variables au coeur des commandes, par exemple le SSID et le mot de passe quand on envoie

AT+CWJAP="[color=blue]SSID[/color]","[color=blue]MotDePasse[/color]"

Soit il faut bâtir une chaîne avec tout le contenu avant de l'envoyer - mais ça mange de la mémoire pour rien, soit il faut pouvoir construire petit à petit la requête avec des print ou write.

On s'équipe donc pour simplification des 3 outils suivants

// --------------------------------------
// espPrintlnATCommand executes an AT commmand by adding at the end a CR LF
// then it checks if endMarker string is receivedon the ESP Serial port
// for max duration ms returns a boolean stating if the marker was found
// --------------------------------------

boolean espPrintlnATCommand(const char * command, const char * endMarker, unsigned long duration)
{
  ESPSEPRIAL.println(command);
  return waitForString(endMarker, duration);
}

// --------------------------------------
// espPrintATCommand or espWriteATCommand 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 espPrintATCommand(...) ESPSEPRIAL.print(__VA_ARGS__)
#define espWriteATCommand(...) ESPSEPRIAL.write(__VA_ARGS__)

la fonction espPrintlnATCommand() envoie la commande et attends une réponse pendant un certain temps et retourne vrai (ça s'est bien passé) ou faux (mal passé). et j'ai deux marcros qui ne font qu'appeler print ou write, juste par convenance.

et tant qu'on est dans les utilitaires, dotons nous de

  • 2 fonctions d'affichage sélectif pour être en mode debug ou pas. Pour cela on utilise de la compilation conditionnelle, si le drapeau debugFlag est défini alors la macro debugMessage() effectue l'impression sur le port Serial sinon la macro ne fait rien. idem pour l'autre. (attention au remplacement de texte comme c'est une macro et pas une fonction)

  • On définit aussi des éléments globaux dont on aura besoin souvent, par exemple la chaîne "OK" avec son passage à la ligne ou des pauses de durée variable.

// comment this line to remove Debug information
#define debugFlag

// comment this line to remove the detailed Debug information
#define deepDebugFlag


#ifdef debugFlag
#define debugMessage(...) Serial.print(__VA_ARGS__)
#else
#define debugMessage(...) {}
#endif


#ifdef deepDebugFlag
#define deepDebugMessage(...) Serial.print(__VA_ARGS__)
#else
#define deepDebugMessage(...) {}
#endif

#define SHORT_PAUSE (1000ul)
#define LONG_PAUSE  (10000ul)
const char * OK_STR = "OK\r\n";
const char * DOT_STR = ".";

Essayons de mettre un peu tout cela ensemble par exemple pour envoyer la commande qui demande notre adresse IP et ensuite la récupérer. Voici à quoi ça pourrait ressembler

byte myIPAddress[4];  // une variable globale pour lire l'adresse

...

// --------------------------------------
// extract from the flow of data our IP address
// --------------------------------------
boolean getMyIPAddress()
{
  unsigned long currentTime;

  const char * searchForString = "+CIFSR:STAIP,";
  const byte searchForStringLength = strlen(searchForString);

  char * ptr;
  boolean foundMyIPAddress = false;

  espPrintATCommand(F("AT+CIFSR\r\n")); // ask for our IP address

  // this returns something like
  //  AT+CIFSR
  //
  //  +CIFSR:STAIP,"192.168.1.28"
  //  +CIFSR:STAMAC,"18:fe:34:e6:27:8f"
  //
  //  OK

  currentTime = millis();
  while (millis() - currentTime <= LONG_PAUSE) {
    if (gotLine()) {
      if (ptr = strstr(ESP_MessageLine, searchForString)) {
        ptr += searchForStringLength + 1; // +1 to skip the "
        if (!(ptr = strtok (ptr, DOT_STR))) break;
        myIPAddress[0] = atoi(ptr);
        if (!(ptr = strtok (NULL, DOT_STR))) break;
        myIPAddress[1] = atoi(ptr);
        if (!(ptr = strtok (NULL, DOT_STR))) break;
        myIPAddress[2] = atoi(ptr);
        if (!(ptr = strtok (NULL, DOT_STR))) break;
        myIPAddress[3] = atoi(ptr);
        if (foundMyIPAddress = waitForString(OK_STR, SHORT_PAUSE)) { // wait for the final OK
          debugMessage(F("\nmy IP address is: "));
          debugMessage(myIPAddress[0]); debugMessage(DOT_STR);
          debugMessage(myIPAddress[1]); debugMessage(DOT_STR);
          debugMessage(myIPAddress[2]); debugMessage(DOT_STR);
          debugMessage(myIPAddress[3]);
          debugMessage(F("\n"));
          break;
        }
      }
    }
  }
  return foundMyIPAddress ;
}

Vous voyez qu'on balance la commande à l'ESP, puis on lit ligne par ligne la réponse et on regarde si la réponse contient "+CIFSR:STAIP," qui est l'indication que l'adresse IP suit et là j'utilise strtok() pour passer de bout en bout d'adresse IP et extraire le nombre. Enfin on vide le reste du buffer de la commande en attendant le OK final et si le debug est activé alors on imprime l'adresse IP.