[RISOLTO]problema a far digerire i parametri wifi alla scheda esp8266

Ciao a tutti/e
Sto cercando di gestire la configurazione della esp8266 tramite un file txt su scheda SD
Nessun prb per la lettura dei file su SD, ma quando passo le stringhe come parametri di configurazione WIFI non si connette più alla rete.

Se uso questo codice funziona tutto:

  char* ssid = "nomerete";
  char* password = "password_rete";
  char* deviceName = "nome_device";

  IPAddress staticIP(192, 168, 1, 100); //ESP static ip
  IPAddress gateway(192, 168, 1, 1);   //IP Address of your WiFi Router (Gateway)
  IPAddress subnet(255, 255, 255, 0);  //Subnet mask
  IPAddress dns(8, 8, 8, 8);  //DNS

  Serial.println("Avvio configurazione del WiFi...");
  WiFi.hostname(deviceName);
  WiFi.config(staticIP, subnet, gateway, dns);
  WiFi.begin(ssid, password);
  
  // Wait for connection
  Serial.print("Wait for wifi connection");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

se uso il mio codice non si connette alla rete, presumo sia un prb di conversione delle stringhe SSID e PASSWORD:

  if (!SD.begin(chipSelect)) {
    Serial.println("SD initialization failed!");
    return;
  }
  cfgFile = SD.open("cfgwifi.txt");
  if (cfgFile) {
    Serial.println("cfgwifi.txt:");
    int conta = 0;
        
    while (cfgFile.available()) {
      
      txtBuffer = "";
      txtBuffer = cfgFile.readStringUntil('n');
      if(txtBuffer == "")
      {
        Serial.println("break");
        break;
      }
      
      conta ++;
      switch (conta) {
        case 1:
          ssid = txtBuffer;
          Serial.print("ssid: ");
          Serial.println(ssid);
          break;
        case 2:
          password = txtBuffer;
          Serial.print("password: ");
          Serial.println(password);
          break;
        case 3:
          deviceName = txtBuffer;
          Serial.print("deviceName: ");
          Serial.println(deviceName);
          break;
        case 4:
          gateway.fromString(txtBuffer);
          Serial.print("gateway: ");
          Serial.println(gateway);
          break;
        case 5:
          subnet.fromString(txtBuffer);
          Serial.print("subnet: ");
          Serial.println(subnet);
          break;
        case 6:
          dns.fromString(txtBuffer);
          Serial.print("dns: ");
          Serial.println(dns);
          break;
        case 7:
          staticIP.fromString(txtBuffer);
          Serial.print("staticIP: ");
          Serial.println(staticIP);
          break;
        default:
          break;
      }
    }
    // close the file:
    cfgFile.close();
  } else {
    Serial.println("errore apertura cfgwifi.txt");
  }

  Serial.println("Avvio configurazione del WiFi...");
  WiFi.hostname(deviceName);
  WiFi.config(staticIP, subnet, gateway, dns);
  WiFi.begin(ssid, password);
  
  // Wait for connection
  Serial.print("Wait for wifi connection");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

sul monitor seriale si ferma a :
"Wait for wifi connection ..............." (continuando a scriver puntini in attesa di una connessione valida)

Cosa sto sbagliando?

Grazie in anticipo

FabrizioVC65:
Ciao a tutti/e
Sto cercando di gestire la configurazione della esp8266 tramite un file txt su scheda SD
Nessun prb per la lettura dei file su SD, ma quando passo le stringhe come parametri di configurazione WIFI non si connette più alla rete.

ma sul monitor seriale, leggi correttamente i dati letti?

Perchè se l'intenzione è leggere fino a fine riga, qui c'è un errore

txtBuffer = cfgFile.readStringUntil('n');

dovrebbe essere '\n' e non 'n', che poi in ogni caso dipende da come hai salvato il file, potrebbe essere \r\n, e allora devi gestirlo in maniera diversa;

FabrizioVC65:
se uso il mio codice non si connette alla rete, presumo sia un prb di conversione delle stringhe SSID e PASSWORD

forse mi sbaglio (mancano le definizion), ma se usi readStringUntil, immagino, txtBuffer sia definita String , e ssid sia definita char*, come riesci a fare questo senza che il compilatore dia errore?

ssid = txtBuffer;

Dai un'occhiata qui, ma, a prescindere dall'errore, prova a non usare l'oggetto String, usa solo le stringhe C

Federico

e magari anche qui:
https://forum.arduino.cc/index.php?topic=648465.msg4373763#msg4373763
che li l'utente ha risolto....

Alla fine ho risolto così:

String txtBuffer;
const byte cs = 4;
char ssid[20];
char pass[20];
char deviceName[20];
byte i;
File dataFile;

IPAddress staticIP;
IPAddress gateway;
IPAddress subnet;
IPAddress dns;

void setup(void){
  pinMode(led, OUTPUT);
  digitalWrite(led, 0);
  Serial.begin(115200);
  
  if (!SD.begin(chipSelect)) {
    Serial.println("SD initialization failed!");
    return;
  }else{
    //recupero la pssword
    dataFile = SD.open("password.txt");
    while (dataFile.available()) pass[i++] = dataFile.read();
    pass[i] = '\0'; // mark end
    dataFile.close();
    i=0;
    //recupero il nome  SSID
    dataFile = SD.open("SSID.txt");
    while (dataFile.available()) ssid[i++] = dataFile.read();
    ssid[i] = '\0'; // mark end
    dataFile.close();
    i=0;
    //recupero il DeviceName
    dataFile = SD.open("deviceName.txt");
    while (dataFile.available()) deviceName[i++] = dataFile.read();
    deviceName[i] = '\0'; // mark end
    dataFile.close();
    i=0;
    //recupero indirizzi IP
    dataFile = SD.open("cfgwifi.txt");
    if (dataFile) {
      Serial.println("  leggo cfgwifi.txt:");
      int conta = 0;
      while (dataFile.available()) {
        
        txtBuffer = "";
        txtBuffer = dataFile.readStringUntil('\n');
        Serial.println(txtBuffer);
        if(txtBuffer == "")
        {
          Serial.println("break");
          break;
        }
        conta ++;
        switch (conta) {
          case 1:
            gateway.fromString(txtBuffer);
            Serial.print("read gateway: ");
            Serial.println(gateway);
            break;
          case 2:
            subnet.fromString(txtBuffer);
            Serial.print("read subnet: ");
            Serial.println(subnet);
            break;
          case 3:
            dns.fromString(txtBuffer);
            Serial.print("read dns: ");
            Serial.println(dns);
            break;
          case 4:
            staticIP.fromString(txtBuffer);
            Serial.print("read staticIP: ");
            Serial.println(staticIP);
            break;
          default:
            break;
        }
      }
    // chiudo il file:
    dataFile.close();
   } else {
    Serial.println("errore apertura cfgwifi.txt");
   }  
  }
  
  
  Serial.println();
  Serial.println("Avvio configurazione del WiFi...");
  WiFi.hostname(deviceName);
  WiFi.config(staticIP, subnet, gateway, dns);
  WiFi.begin(ssid, pass);

  // Wait for connection
  Serial.print("Wait for wifi connection");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  
}

Ho optato per la soluzione di diversi file txt per password e SSID e un solo file per gli IPAddress.
Mi chiedevo... per snellire il codice non sarebbe possibile, secondo voi, riunire Password e SSID in un singolo file? Penso di si ... ma come li devo leggere se scritti su diverse righe?

FabrizioVC65:
Ho optato per la soluzione di diversi file txt per password e SSID e un solo file per gli IPAddress.

Pur di non utilizzare la funzione la funzione toCharArray :frowning:

che si usa cosi

//converte (trasferisce) 19 car. dalla stringa txtBuffer nell'array pass
txtBuffer.toCharArray(pass, 20);

FabrizioVC65:
Mi chiedevo... per snellire il codice non sarebbe possibile, secondo voi, riunire Password e SSID in un singolo file? Penso di si ... ma come li devo leggere se scritti su diverse righe?

in realtà tutti i dati che ti servono li puoi mettere in un solo file, compresi gli ip.

const byte max_chars = 21;
char buffer[max_chars];  
byte line_idx = 0;
byte char_idx = 0;

char pass[max_chars];
char ssid[max_chars];
  
while (file.available() > 0) {
  char rc = file.read();
  if (rc == '\n') {
    buffer[char_idx] = '\0';
    switch (line_idx) {
      case 0: //prima linea
        strcpy(ssid, buffer);
        break;
      case 1: //seconda linea
        strcpy(pass, buffer);
        break;
        //... e cosi via
    }
    line_idx++;
    char_idx = 0;
  } else if (rc == '\r') {

  } else {
    buffer[char_idx] = rc;
    char_idx++;
    if (char_idx >= max_chars)
      char_idx = max_chars - 1;
    }
}

Scritto al volo, potrebbero esserci errori, ma spero ti spinga a studiare e provare.

Federico

Grazie per le idee,
purtroppo c'è ancora qualcosa che non va.
In realtà l'esempio di Federico66 funziona ma solo per Pass e SSID che sono variabili char
Gli indirizzi IP nelle dichiarazioni sono "IPAddress" (se non sbaglio char*)
Quindi devo distinguere i 2 gruppi di variabili con 2 contenitori diversi.

Ad ogni modo la strada che avevo scelto funziona al 90%, la cosa che mi sfugge è che nell'importare la stringa degli indirizzi IP mi succede questo:

gateway.fromString(txtBuffer);

Serial.println(txtBuffer); >> 192.168.1.1

Serial.println(gateway); >> 192.168.1.0

Da dove c.... arriva quello 0 finale? :frowning:

FabrizioVC65:
In realtà l'esempio di Federico66 funziona ma solo per Pass e SSID che sono variabili char

Sei sicuro?

FabrizioVC65:
Gli indirizzi IP nelle dichiarazioni sono "IPAddress" (se non sbaglio char*)

E quindi?

Federico

Federico66:
Sei sicuro?

E quindi?

Federico

questo è il tuo codice:

const byte max_chars = 21;
char buffer[max_chars]; 
byte line_idx = 0;
byte char_idx = 0;
char pass[max_chars];
char ssid[max_chars];
char deviceName[max_chars];

File file;
//IPAddress 
char staticIP[max_chars];
char gateway[max_chars];
char subnet[max_chars];
char dns[max_chars];

void setup(void){

    file = SD.open("cfg/cfgfile.txt");
    while (file.available() > 0) {
    char rc = file.read();
    if (rc == '\n') {
      buffer[char_idx] = '\0';
      switch (line_idx) {
        case 0:
          strcpy(ssid, buffer);
          break;
        case 1:
          strcpy(pass, buffer);
          break;
        case 2:
          strcpy(deviceName, buffer);
          break;
        case 3:
          strcpy(gateway, buffer);
          break;
        case 4:
          strcpy(subnet, buffer);
          break;
        case 5:
          strcpy(dns, buffer);
          break;
        case 6:
          strcpy(staticIP, buffer);
          break;
      }
      line_idx++;
      char_idx = 0;
    } else if (rc == '\r') {
  
    } else {
      buffer[char_idx] = rc;
      char_idx++;
      if (char_idx >= max_chars)
        char_idx = max_chars - 1;
      }
    }


  WiFi.hostname(deviceName);
  WiFi.begin(ssid, pass);  
  WiFi.config(staticIP, subnet, gateway, dns);

questa è la risposta dell'IDE:

error: conversion from 'char [21]' to 'IPAddress' is ambiguous

  • WiFi.config(staticIP, subnet, gateway, dns);*

FabrizioVC65:
questo è il tuo codice:
...
questa è la risposta dell'IDE:
error: conversion from 'char [21]' to 'IPAddress' is ambiguous

  • WiFi.config(staticIP, subnet, gateway, dns);*

E' normale, hai solo duplicato quello che ho scritto e che è valido per user e password, per gestire anche i dati di tipo IPAddress, senza effettivamente capire quello che scrivevi ::slight_smile:

Il mio precedente "Sei sicuro?" non era una domanda, era solo per spronarti a capire l'errore.
Magari cercarlo in rete, ti avrebbe aiutato a capire e quindi a risolvere :frowning:
Questo è l'unico modo per imparare.

Comunque, queste le definizioni delle funzioni usate

//char * strcpy (char * destination, const char * source);
//bool IPAddress::fromString(const char *address);
//begin(char* ssid, char *passphrase, //..
//bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, ...

In uno dei tuoi post avevi fatto correttamente la conversione da un String a IPAddress utilizzando fromString che è di bocca buona e implicitamente converte String in char*, ma non puoi convertire implicitamente da char[] o char* a IPAddress , però,in questo caso, non è fondamentale.

Quindi

IPAddress gateway;

//...

case 3:
  gateway.fromString(buffer);
  break;

//...

Nota:
buffer, pass e ssid sono dichiarate come char array, e quando le passi a quelle funzioni, vengono implicitamente convertite in puntatori (char*). Ora, per chiarezza, io solitamente esplicito le conversioni, cosi quando rileggo non ho dubbi su quello che sto facendo, cioè ad esempio, strcpy((char*)ssid, (char*)buffer);

Per finire, ti ripeto, non ho modo di testare quello ti scrivo (non possiedo ESP8266), e non mi reputo "esperto".
Però quando copio, cerco di capire bene quello che scrivo, cerco di farlo mio studiando e modificando per vedere cosa accade.
Se hai dubbi sul C (funzioni, dati, etc), ti consiglio questo sito cplusplus, tutto il reference è corredato di semplici esempi per spiegare l'argomento.

Federico

Ti ringrazio per le spiegazioni, adesso le provo...
Chiedo scusa per la mia ignoranza sul C, fortunatamente per me questo è solo uno dei miei diversi hobby.
Avessi più tempo potrei dedicarmi a studiare il C, che è da tempo che svicolo.
L'hobby principale non è programmare (non più...) ora mi dedico al homebrew.
Programmo da più di 30 anni ho iniziato con il Basic su macchine 286, conosco il VB.Net, l'Html, l'ASP e l'SQL. Ho creato e venduto software gestionali in VB, VB.Net e VB for Applications (Access e Autocad)
Ho iniziato ad assaggiare il C# ma poi ho lasciato per dedicarmi ad altro.
3 lavori e 2 hobby mi sembravano sufficienti per riempire il mio tempo :wink:

Il mio attuale progettino è, creare un misuratore di densità WiFi (per la fermentazione della birra)
L'hardware non mi ha dato prb, le pagine html e la gestione dei dati da memorizzare, che devo fare, non mi preoccupano.
Come si deduce, la programmazione della esp8266 non è il mio forte... :grinning:

Cmq ancora grazie per le imbeccate

Funziona alla perfezione, l'unica nota e che per leggere correttamente l'ultima riga degli indirizzi IP devo lasciare una riga vuota nel file txt alla fine.
Va benissimo così!!
Grazie ancora della disponibilità!

FabrizioVC65:
Programmo da più di 30 anni ho iniziato con il Basic su macchine 286, conosco il VB.Net, l'Html, l'ASP e l'SQL. Ho creato e venduto software gestionali in VB, VB.Net e VB for Applications.

Io faccio ancora tutto questo, aggiungi C#, Asp.net WebForm e MVC e tutto quello che ne consegue :slight_smile:

Non devi scusarti, anche io Arduino e C solo per hobby da una decina di mesi, mi piace la programmazione a basso livello e mi pento per non averla affrontata prima, quindi cerco di studiare. Purtroppo con l'elettronica faccio un po' fatica, ma se non si cerca di strafare, con Arduino & company riesce abbastanza facile; e poi qui c'è sempre qualcuno in grado di darti una mano.

FabrizioVC65:
Funziona alla perfezione, l'unica nota e che per leggere correttamente l'ultima riga degli indirizzi IP devo lasciare una riga vuota nel file txt alla fine.

Non vorrei dire una castronata, ma potrebbe essere un problema di codifica del file.
Se scopro qualcosa, ti scrivo

Federico

FabrizioVC65:
Va benissimo così!!

Adesso che funziona, posso dirti che però, personalmente non mi piace la logica del dato su file legato al numero di riga, preferisco sempre avere qualcosa del tipo NAME:VALUE, in quanto più leggibile e meno incasinato se decidi di aggiungere altri parametri :slight_smile:

Direi che per adesso procedi pure cosi, ma se decidi di affrontare questo discorso, fatti vivo.

Federico

Dai un'occhiata qui

misura la densità in base all'inclinazione misurata con un accelerometro.
Però se vuoi imparare, fai da te e prendi da li solo lo spunto o le ispirazioni.

In quel progetto usano la libreria WiFimanager per gestire la configurazione del WiFi
Oppure usa la flash dell'ESP8266 e SPIFFS invece di una SD.

zoomx:
Dai un'occhiata qui
http://www.ispindel.de/
misura la densità in base all'inclinazione misurata con un accelerometro.
Però se vuoi imparare, fai da te e prendi da li solo lo spunto o le ispirazioni.

In quel progetto usano la libreria WiFimanager per gestire la configurazione del WiFi
Oppure usa la flash dell'ESP8266 e SPIFFS invece di una SD.

Assolutamente Si... mi baso su quello come idea ma ritengo che i dati online su un server gratuito siano limitanti e soggetti a cambiamenti da gestire in futuro.
La mia idea è di avere un DB locale scaricabile da SD e consultabile da pagine web in locale. Questo mi permette di implementare nuove funzioni in futuro o di elaborare i dati raccolti su altre piattaforme.

Per quanto riguarda la scheda uso una LOLIN D1 mini Pro (EPS8262) che è un'evoluzione della D1 mini con l'alimentatore per la batteria al Litio incorporato. L' SPIFFS ho provato a farlo funzionare ma pur avendo configurato tutto come da help, non riesco a caricare i file dall' IDE, ma non me ne preoccupo tanto era già previsto l'uso della SD che mi espande il tutto a x GB invece che a i solo 16MB (in realtà 14) della scheda.
In questo modo posso delegare tutte le funzioni critiche al HTML che mi è più familiare.

Il progetto originale all'inizio non salvava esclusivamente sul web, sarà cambiato.

Hai ragione il progetto tedesco salva in locale e su UbiDots.com
Ma senza sd per un utente poco esperto è un po difficile scaricare i dati o aggiornare le funzioni.
La mia idea è di renderlo User-Friendly.
Magari in futuro abbinarlo ad una App che lo gestisca in tempo reale.

Questo è il mio hardware:
[url=http://Hai ragione il progetto tedesco salva in locale e su UbiDots.com
Ma senza sd per un utente poco esperto è un po difficile scaricare i dati o aggiornare le funzioni.
La mia idea è di renderlo User-Friendly.
Magari in futuro abbinarlo ad una App che lo gestisca in tempo reale.

Io mi pare che di quel progetto ho preso la parte che calcola l'inclinazione usando i quaternioni.

Potresti scaricare i dati usando il piccolo server web (e forse lo fa anche il progetto iSpindle) ma se prevedi di salvarne tanti si, ti serve la SD e dovrai gestirne l'inserzione e l'estrazione.

Non so come si chiama il sistema di calcolo che hanno usato, ma è decisamente sovradimensionato per quello che deve fare. se non ho interpretato male bastano dei riferimenti (Min e Max) e semplici rapporti per calcolare il valore che cerco. Cioè se leggendo gli assi ho un risultato tipo 10,10,20 e so che quel risultato corrisponde a 0 e, se leggendo gli assi ho 50,50,20 e so che quel risultato corrisponde a 100 basta calcolare le frazioni.
In realtà sto usando un inclinometro a 3 assi ma me ne basterebbero 2.

Non mi pare funzioni in questo modo.
L'accelerometro ti restituisce la forza di gravita senstita sui 3 assi. Se è perfettamente orizzontale hai il valore di g solo sull'asse Z mentre X e Y sono a zero (o quasi perché ci sono un po' di rumori). Quando lo inclini su un solo asse diminuisce il valore su Z e aumenta quello sull'asse. Quindi se lo inclini sui due assi ti servono i tre valori,
2 soli assi ti bastano se il terzo è bloccato, ad esempio hai il tuo dispositivo fissato ad un asse orizzontale.
iSpindle è invece flottante, galleggia sulla birra, per cui servono tutti e 3 gli assi.