Esp 8266 - accéder à son IP Fixe depuis l'extérieur

Bonjour,
J'ai acheté une : WeMos – carte de développement WiFi intelligente D1 R3 CH340 CH340G, basée sur bouclier ESP8266, PCB électronique pour Arduino Compatible IDE, ESP-12E.

WeMos D1 R3 CH340 CH340G basée sur bouclier ESP8266

Avec ce code j'allume et j'éteins une lampe en 220v à l'aide d'un relais :

#include <ESP8266WiFi.h> 
const char* ssid = "xxxx";
const char* password = "xxxxxxx";
WiFiServer server(80);

int ledPin = 13;
// ATTENTION GPIO13 correspond à la PIN 07

void setup() {
  Serial.begin(115200);
  //delay(10);
   pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
 
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA); // Configure ESP8266 en Mode STA  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.println("WiFi connecte a : ");
  Serial.println(WiFi.SSID());
  
  // Start the server
  server.begin();
  Serial.println("demarrage du serveur");
 
  // Print the IP address
  Serial.print("Utilisez cette URL pour vous connecter : ");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
}
 
void loop() {
  // Control de la connection client
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Attente de l'envoi de quelque chose du client
  Serial.println("nouveau client");
  while(!client.available()){
    delay(1);
  }
 
  // Première ligne de la requête
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();
 
  // Lecture-préparation réponse de la requête
  int value = LOW;
  if (request.indexOf("/LED=ON") != -1)  {
    digitalWrite(ledPin, HIGH);
    value = HIGH;
  }
  if (request.indexOf("/LED=OFF") != -1)  {
    digitalWrite(ledPin, LOW);
    value = LOW;
  }
 
  // Réponse à la requête
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); 
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("</head>");
  client.println("<body>");
  client.println("<div style=\"text-align:center\">");
  client.println("<h1>TEST DU SERVEUR WIFI DE PHILIPPE</h1><br><br>");
  client.print("La Lampe est maintenent : ");
  if(value == HIGH) {
    client.print("Allumee");
  } else {
    client.print("Eteinte");
  }
  client.println("<br><br>");
  client.println("<a href=\"/LED=ON\"\"><button style=\"height: 50px; width: 100px\"> ON </button></a>");
  client.println("<a href=\"/LED=OFF\"\"><button style=\"height: 50px; width: 100px\"> OFF </button></a><br />");
  client.println("</body>");
  client.println("</html>");
 
  delay(1);
  //client.stop();
  Serial.println("Client deconnecte");
  Serial.println("");

 
}

J'ai deux problèmes :

  • Au bout d'un certain temps, le serveur n'est plus accessible et je suis obligé de faire un reset de ma carte en appuyant sur le bouton prévu pour ça sur la carte (j'ai essayé le mode wifi par défaut et le mode STA - la connexion semble durer plus longtemps en STA) ;
  • Je ne sais pas comment rendre l'adresse IP de mon ESP8266 accessible depuis l'extérieur. J'ai un abonnement à FREE avec une freebox delta.

Merci par avance pour votre aide.

Pour le premier problème, j'ai trouvé les réponses là :

https://forum.arduino.cc/t/serveur-sur-esp8266-qui-plante/504217/19

Désolé, je n'étais jamais tombé sur ce lien. Je comprends que rabâcher les mêmes choses doit être fatiguant !
Je vous prie de bien vouloir m'excuser.

Par contre je n'arrive pas à comprendre pour rendre l'IP de mon esp accessible depuis l'extérieur.
J'ai trouvé des trucs mais je ne comprends pas.

Merci

Bonjour philippe86220

Dans ta Freebox, il faut faire de la redirection de port (port forwarding). Supposons que l'adresse IP de ta WeMos soit 192.168.1.122 (Adresse privée) , il faut diriger le port 80 , en entrée de la Freebox sur l'IP de la WeMos port 80.
Petit bémol, il n'est pas prudent d'"ouvrir" ainsi le port 80, trop de hackers recherchent ce type de ports, ouverts. C'est pourquoi il faut faire une petite modification au programme.

WiFiServer server(80);
// Passe le port en 
WiFiServer server(5080);     // Par exemple

Ainsi il faut rediriger le port 5080
Tu accèdera à ta WeMos, en local par 192.168.1.122:5080
Depuis l'extérieure par '"adresse publique de ta Freebox":5080.
Depuis l'extérieure par MonNomDeDomaine:5080.

PS: Si tu n'as pas d'adresse ip publique fixe, il faudra passer par un service de DNS dynamique par lequel tu obtiendra un nom de domaine. Ce service s'occupera de gérer les éventuels changements de ton adresse IP publique. Il faudra installer dans ton réseau un programme spécifique pour renseigner le DNS dynamique. Souvent on peut faire ça directement dans le routeur du provider.

Cordialement
jpbbricole

Merci beaucoup jpbbricole.
Cordialement.

Philippe

Il faut aussi penser à mettre ta carte WeMos en IP fixe parce que sinon à chaque mise sous tension la Freebox allouera une adresse différente.

Les Freebox ont une IP fixe, a ma connaissance.

Bonsoir

oui ip Fixe pour les Freebox (par défaut) sauf cas particulier de certaines Freebox pour lesquelles il fallait faire la demande)

Au bout d'un certain temps, le serveur n'est plus accessible et je suis obligé de faire un reset de ma carte

le 'un certain temps' se mesure en jours, en semaines , en mois ?
perte d'adresse ip par l'ESP8266 ? le recours à un bail DHCP statique améliorera peut être les choses, c'est facile çà faire avec une Freebox Revolution , avec une Delta sans doute aussi.
https://www.astuces-pratiques.fr/informatique/freebox-revolution-dhcp-assigner-une-ip-fixe

Bonjour fdufnews

Bonne remarque, je suis en Suisse et mon routeur Swisscom remets la même adresse pour autant qu'il n'y aie pas une inutilisation trop longue.

Je ne connais pas les us et coutumes des réseaux Internet en France, mais en Suisse pour ce qui est des connexions DSL, l'IP est susceptible de changer. Je pratique le dynamic DNS depuis longtemps et je peut dire que ça sert.

Cordialement
jpbbricole

oui @jpbricole, et en France : ça a bien servi et sa sert moins avec l'arrivée de box diverses travaillant par défaut en ip fixe

Bonjour
Pas vraiment mon "truc" , mais Il me semble avoir lu que chez freebox ,il faut explicitement faire la demande d'une IP fullstack, mais je ne sais plus si c'est dans le cas adsl ou fibre

la demande d'ip fixe était à faire dans le cas particulier de l'ADSL en 'zone non dégroupée' :
https://assistance.free.fr/articles/355

Merci à tous pour votre aide.
Pour accéder à internet de l'extérieur, j'ai suivi les instructions de jpbbricole et ça fonctionne (j'ai une IP publique).
Par contre j'ai des coupures qui peuvent intervenir au bout de 5 comme 40 minutes. Le programme que j'ai modifié en suivant ce fil de discussion fonctionne mieux que mon code initial :
https://forum.arduino.cc/t/serveur-sur-esp8266-qui-plante/504217/19

Voici mon code :

#include <ESP8266WiFi.h> 
const char* ssid = "yyy";
const char* password = "xxxxxx";
WiFiServer server(aa);

int ledPin = 13;
// ATTENTION GPIO13 correspond à la PIN 07

void setup() {
  Serial.begin(115200);
  //delay(10);
   pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
 
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connexion à ");
  Serial.println(ssid);
  //WiFi.mode(WIFI_STA); // Configure ESP8266 en Mode STA  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.println("WiFi connecte a : ");
  Serial.println(WiFi.SSID());
  
  // Start the server
  server.begin();
  Serial.println("demarrage du serveur");
 
  // Print the IP address
  Serial.print("Utilisez cette URL pour vous connecter : ");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
}
 
void loop() {
  // Control de la connection client
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Attente de l'envoi de quelque chose du client
  Serial.println("nouveau client");
  //if(!client.available()){
  while(!client.available()){
    //delay(1);
  }
 
  // Première ligne de la requête
  String request = client.readStringUntil('\r');
  Serial.println(request);
  while (client.available()) client.read();
  //client.flush();
 
  // Lecture-préparation réponse de la requête
  int value = LOW;
  if (request.indexOf("/LED=ON") != -1)  {
    digitalWrite(ledPin, HIGH);
    value = HIGH;
  }
  if (request.indexOf("/LED=OFF") != -1)  {
    digitalWrite(ledPin, LOW);
    value = LOW;
  }

if (request.indexOf("/favicon.ico")!= -1){
   client.println("HTTP/1.1 200 OK\r\n");
   client.println("Content-Type: image/x-icon\r\n");
   client.println("Content-Length: 0\r\n\r\n");
  }
 else {
  // Réponse à la requête
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); 
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("</head>");
  client.println("<body>");
  client.println("<div style=\"text-align:center\">");
  client.println("<h1>TEST DU SERVEUR WIFI DE PHILIPPE</h1><br><br>");
  client.print("La Lampe est maintenent : ");
  if(value == HIGH) {
    client.print("Allumee");
  } else {
    client.print("Eteinte");
  }
  client.println("<br><br>");
  client.println("<a href=\"/LED=ON\"\"><button style=\"height: 50px; width: 100px\"> ON </button></a>");
  client.println("<a href=\"/LED=OFF\"\"><button style=\"height: 50px; width: 100px\"> OFF </button></a><br />");
  client.println("</body>");
  client.println("</html>");
  } // fin du else lié au favicon ou non
  delay(1);
  //client.stop();
  if (client.connected())
  {  /* Le client est encore connecté */
  client.stop(); // termine la connexion
  Serial.println("Client déconnecté par client.stop");
  }
  Serial.println("Client deconnecte");
  Serial.println("");

 
}

Pourtant lorsque mon site devient inaccessible, si je fais un ping sur l'ip privée de ma WeMos, la réponse est bonne.

Merci.

Bonjour

ce serait donc le serveurHTTP (dans la loop) qui est en cause et pas la partie WiFi de l'ESP8266 ?

En recompilant après avoir sélectionné HTTP-SERVER dans le menu Outils/Debug Level et en laissant la carte connectée à un terminal quelquechose apparaîtra peut être pour mettre sur la voie

Oupss, il restait un delay() et il n'y avait pas les yield(); :persevere:
je ressaye...

Merci.

Voilà le code qui fonctionne avec ma WeMos, je pense qu'il ne fallait pas faire un IF ==> traitement FAVICON ==> ELSE ==> Réponse à la requête (mais c'est moi qui pense ça et je ne suis pas un champion !!!) :

#include <ESP8266WiFi.h> 
const char* ssid = "aaa";
const char* password = "bbb";
WiFiServer server(cc);

int ledPin = 13;
// ATTENTION GPIO13 correspond à la PIN 07

void setup() {
  Serial.begin(115200);
  //delay(10);
   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, LOW);
 
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connexion à ");
  Serial.println(ssid);
  //WiFi.mode(WIFI_STA); // Configure ESP8266 en Mode STA  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
  Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connecte a : ");
  Serial.println(WiFi.SSID());
  
  // Start the server
  server.begin();
  Serial.println("demarrage du serveur");
 
  // Print the IP address
  Serial.print("Utilisez cette URL pour vous connecter : ");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
}
 
void loop() {
  // Controle de la connection client
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Attente de l'envoi de quelque chose du client
  Serial.println("nouveau client");
  while(!client.available()){
    //on fait rien si pas de nouveau client
  }
 
  // Première ligne de la requête
  String request = client.readStringUntil('\r');
  Serial.println(request);
  while (client.available()) client.read();
  
 
  // Lecture-préparation réponse de la requête
  int value = LOW;
  
  if (request.indexOf("/LED=ON") != -1)  {
    digitalWrite(ledPin, HIGH);
    value = HIGH;
  }
  else if (request.indexOf("/LED=OFF") != -1)  {
    digitalWrite(ledPin, LOW);
    value = LOW;
  } 
   yield(); 
    
   if (request.indexOf("/favicon.ico")!= -1){
   client.print("HTTP/1.1 200 OK\r\n");
   client.print("Content-Type: image/x-icon\r\n");
   client.print("Content-Length: 0\r\n\r\n");
  }
 
  yield();
 
  // Réponse à la requête
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); 
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("</head>");
  client.println("<body>");
  client.println("<div style=\"text-align:center\">");
  client.println("<h1>TEST DU SERVEUR WIFI DE PHILIPPE</h1><br><br>");
  client.print("La Lampe est maintenent : ");
  if(value == HIGH) {
    client.print("Allumee");
  } else {
    client.print("Eteinte");
  }
  client.println("<br><br>");
  client.println("<a href=\"/LED=ON\"\"><button style=\"height: 50px; width: 100px\"> ON </button></a>");
  client.println("<a href=\"/LED=OFF\"\"><button style=\"height: 50px; width: 100px\"> OFF </button></a><br />");
  client.println("</body>");
  client.println("</html>");
  
  
  yield();
  
  if (client.connected())
  {  /* Le client est encore connecté */
  client.stop(); // termine la connexion
  Serial.println("Client déconnecté par client.stop");
  }
  Serial.println("Client deconnecte");
  Serial.println("");

 
}

Ce code fonctionne sans plantages.
J'ai vu que J-M-L avait fait des tutos et je vais les lire....
Merci à tous.
Cordialement.
Philippe

vaut mieux éviter de bloquer le code dans une boucle qui peut durer longtemps. éventuellement faire un while(!client.available()) yield();

Merci J-M-L
J'ai rectifié.

En fait si j’enlève carrément cette ligne de code , le programme semble fonctionner correctement :

Ces instructions en début de boucle ne seraient-elles pas suffisantes ?

// Controle de la connection client
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

Ne suffit-il pas de savoir uniquement qu'un client s'est connecté ?

Vous pouvez avoir un client qui est connecté et qui n’a rien envoyé encore
Comme readStringUntil a un timeout assez long, ça ne doit généralement pas poser de souci mais si vraiment les données tardaient…