Go Down

Topic: ESP8266 Esp-01 WiFi server e client attivi contemporaneamente (Read 343 times) previous topic - next topic

Marco_Piovesan

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.


Marco_Piovesan

prima parte del codice

Code: [Select]

/*
 
  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><br>");

            // 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>");


Marco_Piovesan

Ho notato anche che se  fisso l'IP non funziona più il client per l'ora
con
Code: [Select]
WiFi.config(ip, gateway, subnet);


 seconda parte, la funzione incriminata è alla fine.

Code: [Select]

            // 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: <br>"+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
}


gpb01

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. :)

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. ;)
Search is Your friend ... or I am Your enemy !

zoomx

L'ESP8266 ha un client NTP incluso nel core.

Vedi questo sketch
https://github.com/esp8266/Arduino/issues/4749#issuecomment-390822737
e magari aggiungi questa correzione, per evitare di avere il tempo azzerato se non si riesce a sincronizzare l'ora
https://github.com/esp8266/Arduino/issues/4749#issuecomment-401597626
Questa riga
Code: [Select]
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.

Marco_Piovesan

Grazie zoomx!!

ho risolto poco fa, era un problema di overload della funzione
Code: [Select]
WiFi.config(ip, gateway, subnet);
aggiungendo anche il DNS ha iniziato a lavorare correttamente, con
Code: [Select]
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!

zoomx

Questo è sbagliato
Code: [Select]
WiFi.config(ip, dns, gateway, subnet);
il DNS è all'ultimo.
Qualcosa come
Code: [Select]
  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);

Go Up