ESP8266 Esp-01 WiFi server e client attivi contemporaneamente

Ciao a tutti,
ho un piccolo problema con il progetto di domotica che sto sviluppando.

  1. Voglio usare un ESP8266 per comandare un relè per l'accensione della caldaia, lo configuro come server così dalla rete interna di casa ci si può connettere con lo smartphone usando l'IP statico.... e fino a quì tutto bene, ci sono riuscito.

  2. Vorrei anche implementare l'accensione automatica programmata a determinati orari, per far questo mi serve leggere l'ora da qualche parte su internet (voglio evitare un RTC hardware): ho visto che si può richiedere ai server NTP o anche la si può leggere con una richiesta http da google.it, i codici che ho trovato in internet con il client funzionano benissimo.

Problema: quando provo a inserire il codice 2) in 1) non funziona più la lettura dell'ora via internet, il client non riesce più a leggere l'ora.

Quando l'ESP legge l'ora non è necessario che il server continui a rispondere, ho provato a bloccarlo con stop() e close() ma non c'è stato verso, il client interno non si connette al server google.it.

C'è modo di far coesistere entrambi?

Grazie fin d'ora per l'aiuto.

Marco P.

Di seguito c'è tutto il codice.

prima parte del codice

/*
 
  Controllo RELE' per CALDAIA e POMPA
  
  versione 4:  aggiunta la data senza server NTP
               ma con una richiesta HTTP
               NON FUNZIONA L'ORA PERCHE' QUANDO SI ABILITA 
               WIFICONFIG PER L'IP STATICO NON VA PIU' IL CLIENT
               CHE LEGGE L'ORA.
*/
#include <ESP8266WiFi.h>    // Load Wi-Fi library

#define TEST_MODE // serve a abilitare la stampa su monitor seriale

#define TIME_LAST_UPDATE  // aggiungi l'ora

// Replace with your network credentials
const char* ssid     = "******"; //"REPLACE_WITH_YOUR_SSID";
const char* password = "*****";      //"REPLACE_WITH_YOUR_PASSWORD";

// data e ora interna - variabili
int time_Hours = 0, time_Minutes = 0, time_Day = 0; // variabili per ore, minuti e gg 
const String time_dayName[] = {"LUN", "MAR", "MER", "GIO", "VEN", "SAB","DOM"}; // array per il gg

#ifdef TIME_LAST_UPDATE
// time from HTTP
const char* server2 = "www.google.it";   // an example URL
const int serverPort = 80;      // a port number
const char* resource = "/";         // http resource
const unsigned long HTTP_TIMEOUT = 1000;   // max respone time from server
#endif

// prototipi di funzione
void updateDateAndTime();
byte translateDay(String dayStr);
String dateAndTime; // stores date and time from HTTP response header

WiFiServer server(80);  // Set web server port number to 80
WiFiClient client;      // client anche per il server

void getDataAndHoursFromGoogle();

String header;          // Variable to store the HTTP request

// Auxiliar variables to store the current output state
String output_GPIO_2_State = "off";
String output_GPIO_0_State = "off";

// Assign output variables to GPIO pins
const int output_GPIO_2 = 2;       // GPIO 2
const int output_GPIO_0 = 0;  // GPIO 0

// variabili caldaia
const unsigned long PAUSA = 10 * 1000;  // 1 minuto tra gli aggiornamenti orari 
unsigned long premillis = 10000;
bool statoUscitaCaldaia=LOW,statoUscitaPompa=LOW;

// config static IP
IPAddress ip(192, 168, 1, 110); // where xx is the desired IP Address
IPAddress gateway(192, 168, 1, 1); // set gateway to match your network
IPAddress subnet(255, 255, 255, 0); // set subnet mask to match your network
  
void setup()
{
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  
  // Initialize the output variables as outputs
  pinMode(output_GPIO_2, OUTPUT);
  pinMode(output_GPIO_0, OUTPUT);
  // Set outputs to LOW
  digitalWrite(output_GPIO_2, LOW);
  digitalWrite(output_GPIO_0, LOW);

  #ifdef TEST_MODE
  Serial.print(F("Setting static ip to : "));
  Serial.println(ip);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  #endif
  
  /* 
  * Viene impostata l'impostazione station (differente da AP o AP_STA)
  * La modalità STA consente all'ESP8266 di connettersi a una rete Wi-Fi
  * (ad esempio quella creata dal router wireless), mentre la modalità AP 
  * consente di creare una propria rete e di collegarsi
  * ad altri dispositivi (ad esempio il telefono).
  */
  WiFi.mode(WIFI_STA);

  // se fisso l'IP non funziona più il client per l'ora
  WiFi.config(ip, gateway, subnet);
    
  WiFi.begin(ssid, password); // Connect to Wi-Fi network with SSID and password
  
  while (WiFi.status() != WL_CONNECTED) 
  {
     Serial.print(".");
     delay(500);
  }
  
  server.begin();

  #ifdef TEST_MODE
  Serial.println("");
  Serial.println("WiFi connected as server");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  #endif
}

void loop()
{
  // ogni 15 secondi leggi la data
  if(millis()-premillis>= PAUSA)
  {
    premillis = millis();
    
    #ifdef TEST_MODE
    Serial.println("\nStato interno: ");
    Serial.print("1) uscita relè caldaia = ");
    Serial.println(statoUscitaCaldaia);
    Serial.print("2) uscita relè pompa = ");
    Serial.println(statoUscitaPompa);
    #endif

    #ifdef TIME_LAST_UPDATE 
    getDataAndHoursFromGoogle(); // funzione che dà problemi
    #endif
   }


  // ECHO
  if(Serial.available())
  {
    char carattere = Serial.read();
    Serial.print(carattere);
  }

  // parte essenziale: gestione pag web, pulsanti e uscite
  client = server.available();   // Listen for incoming clients

  if (client)                               // If a new client connects,
  { 
    #ifdef TEST_MODE
    Serial.println("New Client.");          // print a message out in the serial port
    #endif
   
    String currentLine = "";                // make a String to hold incoming data from the client
    // c'era il while
    while(client.connected()) //             // loop while the client's connected
    { 
      if (client.available())               // if there's bytes to read from the client,
      { 
        char c = client.read();             // read a byte, then

        #ifdef TEST_MODE
        Serial.write(c);                    // print it out the serial monitor
        #endif
        
        header += c;
        if (c == '\n')                      // if the byte is a newline character
        { 
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0)
          {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // turns the GPIOs on and off
            if (header.indexOf("GET /5/on") >= 0)
            {
              
              Serial.println("GPIO 5 on");
              output_GPIO_2_State = "on";
              digitalWrite(output_GPIO_2, HIGH);
            }
            else if (header.indexOf("GET /5/off") >= 0)
            {
              Serial.println("GPIO 5 off");
              output_GPIO_2_State = "off";
              digitalWrite(output_GPIO_2, LOW);
            }
            else if (header.indexOf("GET /4/on") >= 0)
            {
              Serial.println("GPIO 4 on");
              output_GPIO_0_State = "on";
              digitalWrite(output_GPIO_0, HIGH);
            }
            else if (header.indexOf("GET /4/off") >= 0)
            {
              Serial.println("GPIO 4 off");
              output_GPIO_0_State = "off";
              digitalWrite(output_GPIO_0, LOW);
            }

            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\", charset=\"UTF-8\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 2px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");

            // Web Page Heading
            client.println("<body><h1>&#x1F3E0 Casa Piovesan</h1><h2>Controllo CALDAIA e POMPA &#x26A0</h2><p>ESP8266 Web Server</p>
");

            // Display current state, and ON/OFF buttons for GPIO 5
            client.println("<h3>Stato CALDAIA:  "+output_GPIO_2_State);
            // aggiunta emoij freddo: fuoco: 
            // es &#x1F354 panino
            if(output_GPIO_2_State=="off")
            {
              client.println("&#x2744"); // freddo
            }
            else
            {
              client.println("&#x1F525"); // fuoco
            }
            client.println("</h3>");

Ho notato anche che se fisso l'IP non funziona più il client per l'ora
con

WiFi.config(ip, gateway, subnet);

seconda parte, la funzione incriminata è alla fine.

            // If the output_GPIO_2_State is off, it displays the ON button
            if (output_GPIO_2_State == "off")
            {
              client.println("<p><a href=\"/5/on\"><button class=\"button\">Accendi Caldaia</button></a></p>");
            }
            else
            {
              client.println("<p><a href=\"/5/off\"><button class=\"button button2\">Spegni Caldaia</button></a></p>");
            }

            // Display current state, and ON/OFF buttons for GPIO 4
            client.println("<h3>Stato POMPA: " + output_GPIO_0_State);
            // aggiunta emoij freddo: fuoco: 
            // es &#x1F354 panino
            if(output_GPIO_0_State=="off")
            {
              client.println("&#x1F6B1"); // divieto acqua
            }
            else
            {
              client.println("&#x1F503"); // circola
            }
            client.println("</h3>");

            
            // If the output_GPIO_2_State is off, it displays the ON button
            if (output_GPIO_0_State == "off")
            {
              client.println("<p><a href=\"/4/on\"><button class=\"button\">Accendi Pompa</button></a></p>");
            }
            else
            {
              client.println("<p><a href=\"/4/off\"><button class=\"button button2\">Spegni Pompa</button></a></p>");
            }

            #ifdef TIME_LAST_UPDATE
            // stampa data e tempo
            client.println("<p> Ultimo aggiornamento: 
"+time_dayName[time_Day]+" - "+time_Hours+":"+time_Minutes+"</p>");
            #endif
            
            client.println("</body></html>"); // end web page

            // The HTTP response ends with another blank line
            client.println();
            
            break;  // Break out of the while loop - commentata, c'era while
          }
          else
          { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        }
        else if (c != '\r')
        { // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    
    #ifdef TEST_MODE
    Serial.println("Client disconnected.");
    Serial.println("");
    #endif
  }
}


#ifdef TIME_LAST_UPDATE
// elaborazioni per estrarre giorno, ora e mese
void updateDateAndTime()
{
    String dayStr = dateAndTime.substring(0, 3);
    time_Day = translateDay(dayStr);
    uint8_t firstColon = dateAndTime.indexOf(':');
    String hourStr = dateAndTime.substring(firstColon, firstColon-2);
    // adjust GMT time
    time_Hours = hourStr.toInt();
    time_Hours++;  // ITALIA GMT + 1
    //time_Hours += 2; // summertime
    //time_Hours += 1; // wintertime
    uint8_t secondColon = dateAndTime.lastIndexOf(':');
    String minuteStr = dateAndTime.substring(secondColon, secondColon-2);
    time_Minutes = minuteStr.toInt();
    
    #ifdef TEST_MODE
    Serial.print("Day: ");
    Serial.println(dayStr);//.c_str()
    Serial.print("Giorno: ");
    Serial.println(time_Day);//.c_str()
    Serial.print("Hour (GMT): ");
    Serial.println(hourStr);//.c_str() 
    Serial.print("Hour (adjusted for Italy wintertime): ");
    Serial.println(time_Hours);
    Serial.print("Minute: ");
    Serial.println(minuteStr);//.c_str()
    #endif
}
        
// Day String -> Giorno in numero
byte translateDay(String dayStr) 
{
  if(dayStr.equals(String("Mon"))) return 0;
  if(dayStr.equals(String("Tue"))) return 1;
  if(dayStr.equals(String("Wed"))) return 2;
  if(dayStr.equals(String("Thu"))) return 3;
  if(dayStr.equals(String("Fri"))) return 4;
  if(dayStr.equals(String("Sat"))) return 5;
  if(dayStr.equals(String("Sun"))) return 6;
}
#endif

// time
void getDataAndHoursFromGoogle()
{
  
#ifdef TIME_LAST_UPDATE
   
   server.stop();        // server stop
   server.close();       // server chiudi
   
   WiFiClient clientTime;  // client anche per leggere l'ora da google 
   //Serial.printf("Connection status: %d\n", WiFi.status());

#ifdef TEST_MODE
    Serial.println("loop: get date and time");
    Serial.print("Connect to ");
    Serial.println(server2);
    #endif
    
    #ifdef TEST_MODE
    Serial.print("Tentativo: ");
    #endif
    
    bool ok = LOW;
    int try_1 = 0;
    
    while(try_1 < 5 && ok == LOW)
    {
      ok = clientTime.connect(server2, serverPort); // connessione al client
      delay(100); 
      
      #ifdef TEST_MODE
      Serial.print(try_1);
      Serial.print(",");
      #endif
      
      try_1++;
    }
    
    #ifdef TEST_MODE
    Serial.println();
    Serial.println(ok ? "Connected" : "Connection Failed!");
    #endif
    
    if( ok ) 
    {
      #ifdef TEST_MODE
      Serial.print("GET ");
      Serial.println(resource);
      #endif
      
      clientTime.print("GET ");
      clientTime.print(resource);
      clientTime.println(" HTTP/1.1");
      clientTime.print("Host: ");
      clientTime.println(server2);

      clientTime.println("Accept: */*");
      clientTime.println("Connection: close");
      clientTime.println();
      // date and time string starts with Date: and ends with GMT
      // example: Date: Sun, 29 May 2016 10:00:14 GMT
      clientTime.setTimeout(HTTP_TIMEOUT);
      char header[85];
      size_t length = clientTime.readBytes(header, 85);
      header[length] = 0;
      String headerString = String(header);
      int ds = headerString.indexOf("Date: ");
      int de = headerString.indexOf("GMT");
      dateAndTime = headerString.substring(ds+6, de);
      // date and time: Sun, 29 May 2016 10:00:14

      #ifdef TEST_MODE
      Serial.print("HTTP response header ");
      Serial.println(headerString.c_str());
      Serial.print("index start date ");
      Serial.println(ds);
      Serial.print("index end time ");
      Serial.println(de);
      Serial.println(  );
      Serial.print("date and time: ");
      Serial.println(dateAndTime.c_str());
      #endif
           
      if( dateAndTime.length()>15 ) 
      {
        #ifdef TEST_MODE
        Serial.print( "Date and Time from HTTP response header: " );
        Serial.println( dateAndTime.c_str() );
        #endif
        
        updateDateAndTime(); // aggiorna giorno e ora
      }
    }
        
    //disconnect(); 
    #ifdef TEST_MODE
    Serial.println("Disconnect from HTTP server");
    #endif
    
    clientTime.stop(); // ferma il client
   
    //delay(500);  
    //server.begin();      // riconnessione al server
#endif
}

Buongiorno,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

L'ESP8266 ha un client NTP incluso nel core.

Vedi questo sketch

e magari aggiungi questa correzione, per evitare di avere il tempo azzerato se non si riesce a sincronizzare l'ora

Questa riga

setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 0);

vale per il fuso orario CET usato in Italia e gestisce anche il passaggio tra ora estiva ed invernale.

Ancora non ho capito perché non compaia tra gli esempi dove c'è il vecchio metodo che gestiva esplicitamente la connessione UDP.

Grazie zoomx!!

ho risolto poco fa, era un problema di overload della funzione

WiFi.config(ip, gateway, subnet);

aggiungendo anche il DNS ha iniziato a lavorare correttamente, con

IPAddress dns(192, 168, 1, 1);//dns 1
WiFi.config(ip, dns, gateway, subnet);

Proverò anche l'altro codice che mi hai segnalato.

Grazie ancora!

Questo è sbagliato

WiFi.config(ip, dns, gateway, subnet);

il DNS è all'ultimo.
Qualcosa come

  IPAddress ip(192, 168, 137, 10);
  IPAddress gateway(192, 168, 137, 1);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress dns1(1, 1, 1, 1);
  IPAddress dns2(8, 8, 8, 8);


  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet, dns1, dns2);