[RISOLTO] While bloccante su programma con ESP8266WiFi.h

Buongiorno a tutti,

sto ultimando un progetto dove faccio uso di un esp per la connessione wifi. Sto utilizzando la soluzione come da esempio libreria con la sola differenza di aver spostato il while nel loop per fare in modo che se la connessione venisse meno la scheda non si blocchi a causa del watchdog.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
WiFiServer server(80);
const char* ssid = "XXXXXXX";
const char* password = "XXXXXX";
......

void setup()
{
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  server.begin();
......
}

void loop()
{
  // Queste righe servono a verificare se è attiva la connessione tra l’ESP e un router
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println(".");
    delay(500);
  }
.......
}

Questa soluzione che ho in prova ormai da 2 settimane si sta rivelando molto stabile, il programma fa esattamente quello che deve fare.

Purtroppo però, quel while, provvidenziale per altro, è bloccante se il router dovesse spegnersi, in poche parole il loop è bloccato in attesa che ritorni la connessione e il resto del listato non viene eseguito e ciò non va bene per il mio scopo.

In base alla vostra esperienza, posso salvare capre e cavoli, e come?

Grazie 1000

Nicola

Ciao! Il while serve per attendere che la connessione sia stabilita, negli esempi proposti delle librerie generalmente il programma non deve fare niente se non c'è connessione, per cui ha senso attendere e per questo motivo viene usato il while.

Adesso mi pare di capire che tu devi fare altro se la connessione non è disponibile, puoi farlo sostituendo il while con un if()

void loop(){

     While(se non c'è connessione){//WiFi.status() != WL_CONNECTED
    
          //continua il while e attendi

     }

// Può essere sostituito


    if(c'è connessione){//WiFi.status() == WL_CONNECTED



         //Tutto il codice da eseguire se c'è connessione


    }

}

In questo modo, se la connessione è stabilita fa tutto il necessario, se non è stabilita non esegue la comunicazione ma comunque esegue il codice del loop()

Grazie torn24!

Vorrei approfondire questo con chi ha molta esperienza: da quel che ho capito leggendo varie cose, e correggetemi se sto dicendo castronerie, il delay presente nel while serve a resettare il counter del watchdog della schedina. Se elimino il while per consentire al loop di scorrere anche in assenza di connessione, rischio che la schedina possa riavviarsi se la connessione per qualche motivo vada via o sia genericamente un pò ballerina?
Grazie

il delay serve solo a rallentare il ciclo interno del while,
senza delay ogni millisecondo o giù di li viene ripetuta la domanda WiFi.status() != WL_CONNECTED
con il delay la stessa domanda viene ripetuta ogni mezzo secondo
tutto li

potresti modificarlo anche così…

void loop(){
  // Queste righe servono a verificare se è attiva la connessione tra l'ESP e un router
  for (int x=0; x< 10;x++){
     if (WiFi.status() != WL_CONNECTED) {
       Serial.println(".");
       delay(500);
     } else {
        break;
     }
  }
.......
}

in questo modo ripete la ricerca del wifi per il numero di volte che imposti nel for e poi esce anche se non collegato

ok, grazie per la precisazione, riformulo meglio: vi risulta che il while come indicato da me, serva ad evitare i riavvi dell'esp se la connessione per qualche motivo vada via o sia genericamente un pò ballerina?

Patrick, grazie per il codice, mi piace molto come soluzione. Lo provo di sicuro stasera...

droidprova:
ok, grazie per la precisazione, riformulo meglio: vi risulta che il while come indicato da me, serva ad evitare i riavvi dell'esp se la connessione per qualche motivo vada via o sia genericamente un pò ballerina?

Patrick, grazie per il codice, mi piace molto come soluzione. Lo provo di sicuro stasera...

no, se la connessione è ballerina o è assente il ciclo verrà ripetuto all'infinito... e (per inciso) non è un riavvio, è un controllo sul fatto che sia attivo/connesso
l'avvio della connessione viene fatto da
WiFi.begin(ssid, password);
dopodichè appunto attende che l'ambaradan si sia connesso :wink:

ragionando....
se si spegne il wifi e quindi la connessione casca....
non essendoci nel loop il begin, mi sa che non riesci più a riattivarla.... ma è da verificare

droidprova:
il delay presente nel while serve a resettare il counter del watchdog della schedina.

Su ESP questo è vero. Infatti, il core ESP deve anche fare funzionare il wifi, che è gestito dallo stesso processore, per cui ogni tanto deve prendere il controllo per "fare le sue cose". Questo avviene, ad esempio, in occasione dei delay() visto che, se intanto il tuo programma deve aspettare, tanto vale che il core faccia qualcosa di utile.

Come dici giustamente, il core ha un watchdog interno che scatta se il core non riesce a prendere il controllo per un certo periodo, per segnalare che non è stato in grado di gestire la connessione wifi. Questo avviene quando lo sketch è impegnato in una lunga elaborazione, ad esempio. In questo caso è bene cedere volontariamente il controllo al core ogni tanto e, invece di farlo con una delay (visto che magari non vogliamo fermarci a tutti i costi), è possibile farlo con yield().

Infine, il core prende il controllo al termine di ogni iterazione del loop().

Col codice di Patrick_M ci vorrà comunque un if() che verifichi la connessione.

Esempio esegue il for 10 controlli e la connessione non è attiva, esce comunque dal for ed esegue il codice restante, se non vogliamo fare eseguire il codice in mancanza di connessione, allora occorre sempre un if().

Grazie Sukko per aver confermato ciò che più o meno ho capito e che sto tentando di verificare in campo.
Dunque se ho capito bene, al posto della condizione while è meglio usare la funzione yield() per dare "respiro" all'esp e consentire al core di svolgere le sue operazioni.

Come posso usarlo? Hai dei link da approfondire, o delle righe da provare?

Grazie come sempre!

yield();

E basta. È come dire al core "fai quello che devi per tenere in piedi la connessione e ridammi il controllo appena possible".

È una specie di delay(0), apparentemente inutile se non ci fosse questa gabola del wifi.

ah, e lo inserisco ad esempio alla fine del loop? In questo modo posso fare a meno del while o del bel codice di Patrick_M?

Grazie

Non hai capito un tubo :D. Rileggi con calma e fai tuoi i concetti! :slight_smile:

Comunque io ho solo spiegato la storia del watchdog, non mi sono espresso sulla questione del while o quant'altro. In quel che vedo sopra non credo ci sia da cambiare niente in merito al watchdog appunto.

Come dici giustamente, il core ha un watchdog interno che scatta se il core non riesce a prendere il controllo per un certo periodo, per segnalare che non è stato in grado di gestire la connessione wifi. Questo avviene quando lo sketch è impegnato in una lunga elaborazione, ad esempio. In questo caso è bene cedere volontariamente il controllo al core ogni tanto e, invece di farlo con una delay (visto che magari non vogliamo fermarci a tutti i costi), è possibile farlo con yield().

Infine, il core prende il controllo al termine di ogni iterazione del loop()

Quindi da quello che leggo....

1)E' utile se c'è una lunga elaborazione, altrimenti se ne può fare a meno
2)Ogni volta che riprende il loop() il controllo passa al core, per cui metterlo a fine loop() non ha senso
il loop() termina e ricomincia dando comunque il controllo al core

3)Questo non assicura che una connessione sia stabilita, per cui dovrai fare comunque i tuoi controlli

Potresti usare un if else, controllo la connessione,

se è stabilita eseguo il codice

else altrimenti, eseguo di nuovo il begin! Potresti se credi necessario, mettere il codice di patrick nell'else, che in pratica attende 5 secondi che la connessione sia stabilita prima di proseguire con codice seguente.

occhio che di solito… cioè sempre!
questo pezzo di programma (il while intendo) è inserito nel setup e viene eseguito una volta soltanto!
cioè dopo il begin si da il tempo all’esp di effettuare la connessione, rimanendo in attesa fino a risposta affermativa. Il programma poi prosegue e non rientra più in questo while.
Quello di cui non sono sicuro è che spostare questo pezzo di programma nel loop abbia senso.

torn24:
Col codice di Patrick_M ci vorrà comunque un if() che verifichi la connessione.

Esempio esegue il for 10 controlli e la connessione non è attiva, esce comunque dal for ed esegue il codice restante, se non vogliamo fare eseguire il codice in mancanza di connessione, allora occorre sempre un if().

non ho capito cosa intendi

for (int x=0; x< 10;x++){
     if (WiFi.status() != WL_CONNECTED) {

l’if di controllo c’è…

Patrick, intendo se il controllo risulta non connesso per 10 volte, esce dal for, non è un ciclo come il primo while che termina solo se avviene la connessione. Il tuo for fa al massimo 10 iterazioni poi esce anche se la connessione non è stabilita! A questo punto cosa facciamo? Eseguiamo comunque il codice o mettiamo un if
che lo esegue solo se effettivamente c'è una connessione.

Il codice di Patrick va già meglio del while che attualmente uso:

in perdurata assenza di connessione dopo le 10 iterazioni, esco dal for eseguo il loop e le funzioni che esso richiama e sono di nuovo ad inizio loop. a questo punto se c'è connessione il for mi manda sull'else che attraverso il break mi fa proseguire nel loop, o no? Altrimenti attendo altre 10 iterazioni per rifare quello di cui sopra.

Non sarà il massimo, ma in assenza della connessione almeno cosi va a tratti ma va.

Siete un po duri :slight_smile: :slight_smile: :slight_smile:

Io attendo la connessione con un while, o verifico la connessione con un if, ci sarà un motivo per cui lo faccio !? Il motivo potrebbe essere che il codice va eseguito solo se c'è connessione! Se io voglio eseguire il codice in ogni caso, allora non serve ne un while ne un if ne un for.

A questo punto con l'esempio del for() può comunque terminare il for senza avere una connessione, comprende

Il for di patrick da un tempo massimo di 5 secondi perché avvenga la connessione, se si connette in meno tempo fa un break, ma questo non assicura che terminati i cinque secondi ci sia una connessione, e quindi eseguiresti il codice di comunicazione senza una connessione da qui un if(c'è connessione eseguo)

torn nel mio caso ho due intoppi:

  1. ho una connessione ballerina, che per via del wacthdog ha bloccato varie volte la schedina.

Questa cosa l'ho già risolta semplicemente spostando il while dal setup al loop. Cioè facendo aspettare che la connessione torni, il famoso counter dell'esp non blocca la schedina.

  1. il mio progetto ha bisogno si, della connessione, ma in assenza di essa ho delle funzioni che possono e devono funzionare anche senza la connessione.

Per cui io ho fatto questa domanda in quanto ho bisogno di uno stratagemma che blocchi gli effetti del punto 1 per poter fare ciò che mi serve al punto 2.

Non sto cercando di risolvere tutti i casi, ma solo il mio.

Grazie

Ho capito che scrivere un
if(WiFi.status() == WL_CONNECTED) allora eseguo la comunicazione

Non so per quale motivo ma ti costa molto :slight_smile: :slight_smile: fai come pensi sia meglio...