Salvare log.txt su google drive con ESP32C6

Sto facendo vari test per cercare di salvare un file .txt e/o aggiornarne il contenuto usando un ESP32C6.

Non riesco però a far funzionare lo script. Ma andiamo per punti:

Su google app script ho creato e reso eseguibile il seguente script:

function doPost(e) {
  try {
  if (e.parameter.data) {
    return ContentService.createTextOutput("Ricevuto: " + e.parameter.data);
  }
  // Folder and file details
  var folderName = "ESP32_Logs";
  var fileName = "log.txt";
  // Find or create folder
  var folders = DriveApp.getFoldersByName(folderName);
  var folder = folders.hasNext() ? folders.next() : DriveApp.createFolder(folderName);

  // Find or create file
  var files = folder.getFilesByName(fileName);
  var file = files.hasNext() ? files.next() : folder.createFile(fileName, "");

  // Check for data parameter
  if (!e.parameter.data) {
    return ContentService.createTextOutput("Error: 'data' parameter is missing.");
  }
  // Append data to the file (handle potential JSON data)
  var data = e.parameter.data;
  try {
    var jsonData = JSON.parse(data); // Try parsing as JSON
    data = JSON.stringify(jsonData, null, 2); // Pretty-print for readability
  } catch (err) {
    // Not valid JSON, keep as plain text
  }
  file.appendText(data);
  return ContentService.createTextOutput("Log saved successfully.");
} catch (error) {
  return ContentService.createTextOutput("Error: " + error.toString());
}
}

Contemporaneamente ho usato il seguente codice sulla ESP32:

void sendLogData(const String& logData) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    WiFiClientSecure client;
    client.setInsecure(); // Disabilita la verifica del certificato
    
    String currentUrl = serverName; // URL iniziale
    int maxRedirects = 5;          // Numero massimo di redirect consentiti
    int redirectCount = 0;

    while (redirectCount < maxRedirects) {
      Serial.println("Connecting to: " + currentUrl);
      http.begin(client, currentUrl);
      http.addHeader("Content-Type", "application/x-www-form-urlencoded");

      String postData = "data=" + logData;
      int httpResponseCode = http.POST(postData);

      if (httpResponseCode > 0) {
        String response = http.getString();

        if (httpResponseCode >= 300 && httpResponseCode < 400) {
          // Cerca il tag <a href> per ottenere il nuovo URL
          int hrefStart = response.indexOf("<A HREF=\"");
          if (hrefStart != -1) {
            hrefStart += 9; // Salta "<A HREF=\""
            int hrefEnd = response.indexOf("\"", hrefStart);
            if (hrefEnd != -1) {
              String newUrl = response.substring(hrefStart, hrefEnd);
              Serial.println("Redirecting to: " + newUrl);

              // Controlla se l'URL è relativo o assoluto
              if (newUrl.startsWith("/")) {
                // Combina l'URL relativo con il dominio originale
                int protocolEnd = currentUrl.indexOf("//") + 2;
                int pathStart = currentUrl.indexOf("/", protocolEnd);
                if (pathStart == -1) pathStart = currentUrl.length();
                newUrl = currentUrl.substring(0, pathStart) + newUrl;
              }
              currentUrl = newUrl;
              redirectCount++;
              http.end(); // Chiude la connessione prima di reindirizzare
              continue;   // Procede al prossimo loop
            }
          }
          Serial.println("Redirect URL not found in <A HREF>");
          break; // Interrompi se non riesci a trovare il redirect
        } else {
          // Risposta valida
          Serial.println("Response: " + response);
          break; // Esci dal ciclo su successo
        }
      } else {
        // Errore HTTP
        Serial.println("Error: " + String(httpResponseCode));
        break;
      }
      http.end(); // Chiude la connessione dopo ogni iterazione
    }

    if (redirectCount >= maxRedirects) {
      Serial.println("Too many redirects!");
    }
  } else {
    Serial.println("WiFi not connected");
  }
}

Il problema che non riesco a capire è che se il file e la cartella non esistono vengono creati ma il file è vuoto. Se invece il file esiste in serial print mi ritrovo:

5:29:48.215 -> Connecting to: https://script.google.com/macros/s/XXXXXXXXXXXXXX/exec
15:29:50.424 -> Redirecting to: https://script.googleusercontent.com/macros/echo?user_content_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWckm76-hGir53bGrc602iLx2va1MhS-rt0212NZu7tmNo-CGKJJXzB5jRm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnEtCOQ2ISU2aAbVqEpmvfml3MPAGL4Fz83fsHzP4Oceo5EzePk_rqhpSrpR5JWlbqdx58zHd7cVQnwZuu1UjrY8rglz6y9OqyA&amp;lib=MG7DD04kIxA_rxQD0tnOzuYFIwK-8SiuQ
15:29:50.457 -> Connecting to: https://script.googleusercontent.com/macros/echo?user_content_key=XXXXXXXXXXXXckm76-hGir53bGrc602iLx2va1MhS-rt0212NZu7tmNo-CGKJJXzB5jRm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnEtCOQ2ISU2aAbVqEpmvfml3MPAGL4Fz83fsHzP4Oceo5EzePk_rqhpSrpR5JWlbqdx58zHd7cVQnwZuu1UjrY8rglz6y9OqyA&amp;lib=MG7DD04kIxA_rxQD0tnOzuYFIwK-8SiuQ
15:29:51.145 -> Response: <!DOCTYPE html><html lang="it"><head><meta name="description" content="Elaborazione di testi, presentazioni e fogli di lavoro sul Web"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"><link rel="shortcut icon" href="//docs.google.com/favicon.ico"><title>Pagina non trovata</title><meta name="referrer" content="origin"><link href="//fonts.googleapis.com/css?family=Product+Sans" rel="stylesheet" type="text/css" nonce="wrIhtRWWO1osi8skGK7s6A"><style nonce="wrIhtRWWO1osi8skGK7s6A">.goog-inline-block{position:relative;display:-moz-inline-box;display:inline-block}* html .goog-inline-block{display:inline}*:first-child+html .goog-inline-block{display:inline}#drive-logo{margin:18px 0;position:absolute;white-space:nowrap}.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png);-webkit-background-size:116px 41px;background-size:116px 41px;display:inline-block;height:41px;vertical-align:bottom;width:116px}.docs-drivelogo-text{color:#000;display:inline-block;opacity:.54;text-decoration:none;font-family:"Product Sans",Arial,Helvetica,sans-serif;font-size:32px;text-rendering:optimizeLegibility;position:relative;top:-6px;left:-7px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (-webkit-min-device-pixel-ratio:1.5),(min-resolution:144dpi){.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_116x41dp.png)}}sentinel{}</style><style type="text/css" nonce="wrIhtRWWO1osi8skGK7s6A">body {background-color: #fff; font-family: Arial,sans-serif; font-size: 13px; margin: 0; padding: 0;}a, a:link, a:visited {color: #112ABB;}</style><style type="text/css" nonce="wrIhtRWWO1osi8skGK7s6A">.errorMessage {font-size: 12pt; font-weight: bold; line-height: 150%;}</style></head><body><div id="outerContainer"><div id="innerContainer"><div style="position: absolute; top: -80px;"><div id="drive-logo"><a href="/"><span class="docs-drivelogo-img" title="Logo Google"></span><span class="docs-drivelogo-text">&nbsp;Drive</span></a></div></div><div align="center"><p class="errorMessage" style="padding-top: 50px">Impossibile aprire il file in questo momento.</p><p> Verifica l'indirizzo e riprova.</p><div style="background: #F0F6FF; border: 1px solid black; margin-top: 35px; padding: 10px 125px; width: 300px;"><p><strong>Aumenta la tua produttività con Google Drive</strong></p><p>Le app in Google Drive rendono più facile creare, salvare e condividere online documenti, fogli di lavoro, presentazioni e altro ancora.</p><p>Per ulteriori informazioni, consulta <a href="https://drive.google.com/start/apps">drive.google.com/start/apps</a>.</p></div></div></div></div></body><style nonce="wrIhtRWWO1osi8skGK7s6A">html {height: 100%; overflow: auto;}body {height: 100%; overflow: auto;}#outerContainer {margin: auto; max-width: 750px;}#innerContainer {margin-bottom: 20px; margin-left: 40px; margin-right: 40px; margin-top: 80px; position: relative;}</style></html>

Ovviamente ho controllato che cartella e file txt in drive abbiano i permessi per essere editati da chiunque anche se teoricamente non dovrebbe essere necessario dato che lo script viene eseguito come se fossi io quindi con pieni poteri.

Non è chiaro se lo script lo hai scritto tu o se lo hai preso da qualche parte online, però ci sono molte cose che non vanno.

In questo pezzo di codice, quando la tua richiesta POST contiene il parametro data lo script risponde con "Ricevuto + " e poi si chiude non andando a salvare nulla nel file (istruzione return)
Questo significa che il file viene creato solo nel caso di richiesta malformata (ad esempio con il browser) che non contiene il parametro data.

Qui invece lo script si aspetta un contenuto di tipo JSON (e non è questo il tuo caso).
Se data non è un JSON viene sollevato un errore anche se poi non viene fatto nulla e dovrebbe proseguire con il resto, ma rimane comunque un pezzo di codice "estraneo"

Infine questa istruzione è proprio sbagliata perché appendText() non è un metodo della classe File

Ho modificato al volo il tuo script per farlo funzionare, anche se l'ho provato solo con Postman (fantastica app che ti consiglio di scaricare se vuoi sviluppare questo genere di cose).
Ci sono altre cose che si possono migliorare, ma almeno può essere una base di partenza funzionante.

Per quanto riguarda la risposta ottenuta con l'ESP32, sei sicuro di aver fatto il deploy dello script impostando "chiunque" come utenti autorizzati?

1 Like

Sono partito da progetti di terzi che ho trovato online e ho cercato di ispirarmi evidentemente senza troppo successo.

Ho modificato lo script:

function doPost(e) {
  try {
    // Folder and file details
    var folderName = "ESP32_Logs";
    var fileName = "log.txt";
    
    // Find or create folder
    var folders = DriveApp.getFoldersByName(folderName);
    var folder = folders.hasNext() ? folders.next() : DriveApp.createFolder(folderName);

    // Find or create file
    var files = folder.getFilesByName(fileName);
    var file = files.hasNext() ? files.next() : folder.createFile(fileName, "");

    // Check for data parameter
    if (!e.parameter.data) {
      return ContentService.createTextOutput("Error: 'data' parameter is missing.");
    }    
    var data = e.parameter.data;

    // Get actual file content
    var text = file.getBlob().getDataAsString();

    // Append data to a new line 
    text += '\n' + data;

    // Save file content
    file.setContent(text);
    
    return ContentService.createTextOutput("Log saved successfully.");
  } catch (error) {
    return ContentService.createTextOutput("Error: " + error.toString());
  }
}

Ma ciò nonostante l'ESP32 mi risponde:

12:32:49.261 -> Connecting to: https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxpH49JWQwgo3e1BqKLbaQQESv3B_zRyIlnXPemkcHicK4qp/exec
12:32:52.566 -> Redirecting to: https://script.googleusercontent.com/macros/echo?user_content_key=xxxxxxxxxxxxxxxxxxxxxxxxxxHyUkDz6Cvl13NVRwMmtDtYtxdvZg8bSKq6n8SyOuEQ3RZEou95jhDIq8nJKONndm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnEYi9axUjhgtB4nDp7htJv7lmbuf-FwmeZQx1DhjEuHhSrktuhOA3z3KUnin9_fHyMtVL-Jmqvx5iTcb2bvXRuY8W646K3Opow&amp;lib=MG7DD04kIxA_rxQD0tnOzuYFIwK-8SiuQ
12:32:52.598 -> Connecting to: https://script.googleusercontent.com/macros/echo?user_content_key=xxxxxxxxxxxxxxxxxxxxxDz6Cvl13NVRwMmtDtYtxdvZg8bSKq6n8SyOuEQ3RZEou95jhDIq8nJKONndm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnEYi9axUjhgtB4nDp7htJv7lmbuf-FwmeZQx1DhjEuHhSrktuhOA3z3KUnin9_fHyMtVL-Jmqvx5iTcb2bvXRuY8W646K3Opow&amp;lib=MG7DD04kIxA_rxQD0tnOzuYFIwK-8SiuQ
12:32:53.276 -> Response: <!DOCTYPE html><html lang="it"><head><meta name="description" content="Elaborazione di testi, presentazioni e fogli di lavoro sul Web"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"><link rel="shortcut icon" href="//docs.google.com/favicon.ico"><title>Pagina non trovata</title><meta name="referrer" content="origin"><link href="//fonts.googleapis.com/css?family=Product+Sans" rel="stylesheet" type="text/css" nonce="PTQGHNGl4Oo9k0mSN4v-lQ"><style nonce="PTQGHNGl4Oo9k0mSN4v-lQ">.goog-inline-block{position:relative;display:-moz-inline-box;display:inline-block}* html .goog-inline-block{display:inline}*:first-child+html .goog-inline-block{display:inline}#drive-logo{margin:18px 0;position:absolute;white-space:nowrap}.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png);-webkit-background-size:116px 41px;background-size:116px 41px;display:inline-block;height:41px;vertical-align:bottom;width:116px}.docs-drivelogo-text{color:#000;display:inline-block;opacity:.54;text-decoration:none;font-family:"Product Sans",Arial,Helvetica,sans-serif;font-size:32px;text-rendering:optimizeLegibility;position:relative;top:-6px;left:-7px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (-webkit-min-device-pixel-ratio:1.5),(min-resolution:144dpi){.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_116x41dp.png)}}sentinel{}</style><style type="text/css" nonce="PTQGHNGl4Oo9k0mSN4v-lQ">body {background-color: #fff; font-family: Arial,sans-serif; font-size: 13px; margin: 0; padding: 0;}a, a:link, a:visited {color: #112ABB;}</style><style type="text/css" nonce="PTQGHNGl4Oo9k0mSN4v-lQ">.errorMessage {font-size: 12pt; font-weight: bold; line-height: 150%;}</style></head><body><div id="outerContainer"><div id="innerContainer"><div style="position: absolute; top: -80px;"><div id="drive-logo"><a href="/"><span class="docs-drivelogo-img" title="Logo Google"></span><span class="docs-drivelogo-text">&nbsp;Drive</span></a></div></div><div align="center"><p class="errorMessage" style="padding-top: 50px">Impossibile aprire il file in questo momento.</p><p> Verifica l'indirizzo e riprova.</p><div style="background: #F0F6FF; border: 1px solid black; margin-top: 35px; padding: 10px 125px; width: 300px;"><p><strong>Aumenta la tua produttività con Google Drive</strong></p><p>Le app in Google Drive rendono più facile creare, salvare e condividere online documenti, fogli di lavoro, presentazioni e altro ancora.</p><p>Per ulteriori informazioni, consulta <a href="https://drive.google.com/start/apps">drive.google.com/start/apps</a>.</p></div></div></div></div></body><style nonce="PTQGHNGl4Oo9k0mSN4v-lQ">html {height: 100%; overflow: auto;}body {height: 100%; overflow: auto;}#outerContainer {margin: auto; max-width: 750px;}#innerContainer {margin-bottom: 20px; margin-left: 40px; margin-right: 40px; margin-top: 80px; position: relative;}</style></html>
12:32:53.634 -> WiFi spento completamente

Ho provato anche da prompt con curl ma il risultato rimane lo stesso. Il deployment per sicurezza l'ho rifatto da zero con esegui come "me" e accessibilità "chiunque".

EDIT: per la serie le stranezze e dove incontrarle nonostante nel seriale dia quella risposta di errore. Invece adesso i dati vengono caricati e salvati correttamente. Bizzarro che dia quella strana risposta ma comunque almeno ho una base di partenza.

Quindi lo script funziona adesso ed è già un passo avanti.

Per quanto riguarda lo sketch (che prima avevo guardato poco) vedo che viene gestito in modo "manuale" il redirect della pagina.

Forse l'esempio di partenza è un po' datato perché la libreria HTTPClient supporta il redirect già di suo, basta abilitarlo e puoi rimuovere tutta la logica di estrazione dell'url di redirect e di tentativi di connessione.

http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);

La risposta che ottieni dal server è una risposta "generica" di errore, probabilmente la richiesta HTTP non è del tutto "conforme" a quanto richiesto, ma comunque basta per eseguire correttamente lo script o qualcosa di simile.

Forse ti conviene fare una richiesta di tipo GET che tipicamente è un po' più facile da gestire in quanto sta tutto nell'url e non devi costruire il body specificandone il Content-Type.
In tal caso ti basta modificare lo script chiamando la funzione doGet() invece di doPost() e ovviamente adattare anche lo sketch dell'ESP32

1 Like

Purtroppo il GET mi torna male in quanto il contenuto della variabile di log sono svariate righe con "a capo" e punteggiatura varia quindi quando va a comporre l'url mi crea una moltitudine infinita di errori.

Per farti capire meglio questo è quello che trasmette in un colpo solo:

WiFi connesso
Indirizzo IP: 192.168.1.42

OTA avviato
Starting TelegramBot...
Manca meno di zero secondi. Dormo fino alle 08 del giorno successivo: 82920 secondi
Time to sleep: 82920 seconds

Test Telegram connection... OK
Configuro ESP32 per dormire 82920 secondi
Inizio a dormire

In ogni caso seguendo i tuoi consigli ho modificato lo sketch così:

void sendLogData(const String& logData) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    WiFiClientSecure client;
    client.setInsecure();  // Disabilita la verifica del certificato

    String currentUrl = serverName;  // URL iniziale

    Serial.println("Connecting to: " + currentUrl);
    http.begin(client, currentUrl);
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");

    String postData = "data=" + logData;
    int httpResponseCode = http.POST(postData);

    http.end();  // Chiude la connessione dopo ogni iterazione

  } else {
    Serial.println("WiFi not connected");
  }
}

E funziona. Peccato per il GET perché mi sarebbe piaciuto approfondire ma sarà per un'altra volta.

Si il GET ha il problema che i valori vanno codificati in modo tale che siano una stringa "valida" come url, inoltre se non ricordo male ha un limite di 2048 byte massimi.

Ad ogni modo se vuoi approfondire o per utilizzi futuri questo potrebbe essere un modo:

// Funzione per codificare i parametri URL
String urlEncode(const String& str) {
  String encoded = "";
  for (size_t i = 0; i < str.length(); i++) {
    char c = str[i];
    if (isalnum(c)) {
      encoded += c; // Lettere e numeri non richiedono codifica
    } else if (c == ' ') {
      encoded += '+'; // Gli spazi diventano "+"
    } else {
      char hex[4];
      sprintf(hex, "%%%02X", (unsigned char)c); // Codifica il carattere speciale
      encoded += hex;
    }
  }
  return encoded;
}

void sendLogData(const String& logData) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    NetworkClientSecure client;
    client.setInsecure();  // Disabilita la verifica del certificato

    String currentUrl = serverName; 
    currentUrl += "?data=";
    currentUrl += urlEncode(logData);

    Serial.println("Connecting to: " + currentUrl);
    http.begin(client, currentUrl);
    http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
    int httpResponseCode = http.GET();

    if (httpResponseCode > 0) {
      String response = http.getString();
      Serial.println(response);
    } else {
      // Errore HTTP
      Serial.println("Error: " + String(httpResponseCode));
    }
    http.end();  // Chiude la connessione dopo ogni iterazione
  }

  else {
    Serial.println("WiFi not connected");
  }
}

Ho nuovamente bisogno del tuo aiuto. Grazie al log e alle modifiche che abbiamo discusso mi sono accorto di qualcosa di anomalo:

#include <WiFi.h>
#include <AsyncTelegram2.h>
#include <ArduinoOTA.h>
#include <HTTPClient.h>
#include <time.h>
#include <WiFiClientSecure.h>

const char* serverName = "https://script.google.com/macros/s/AKfycbXXXXXXXXXXXXXXXXXXXXXXXX1qS-9AvFZGjJ8fjRnucCHoQdfZH6BDaiEA/exec";

String logString = "";  // Variabile per salvare tutti i log

#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
// Timezone definition
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"

WiFiClientSecure client;
AsyncTelegram2 myBot(client);

const char* ssid = "";                                         // SSID WiFi network
const char* pass = "";                                        // Password  WiFi network
const char* token = "";  // Telegram token
const int MAX_ANALOG_VAL = 4095;

const int ora = 8;
const int minuto = 0;

const float MAX_BATTERY_VOLTAGE = 4.2;
float batteryFraction;
float batteryIniziale;
float voltageLevel;
float voltageIniziale;
long TIME_TO_SLEEP;
static float filteredVoltage;

// Check the userid with the help of bot @JsonDumpBot or @getidsbot (work also with groups)
// https://t.me/JsonDumpBot  or  https://t.me/getidsbot
int64_t userid = 226330024;

void WIFION() {
  unsigned long startTime = millis();  // Registra l'ora di inizio
  WiFi.begin(ssid, pass);

  // Attende la connessione, ma con un limite di 10 secondi
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    int i = 0;
    // Controlla se sono passati più di 10 secondi
    if (millis() - startTime > 10000) {
      Serial.println("\nConnessione WiFi fallita, ritentando...");
      logString += ("\nConnessione WiFi fallita, ritentando...");
      i++;
      if (i > 5) {
        esp_restart();
      }
      WIFION();  // Richiama la funzione per riprovare
      delay(5000);
      return;  // Esce dal ciclo corrente
    }

    delay(500);
  }

  Serial.println("");
  Serial.println("WiFi connesso");
  logString += ("WiFi connesso\n");
  Serial.println("Indirizzo IP: ");
  logString += ("Indirizzo IP: ");
  Serial.println(WiFi.localIP());
  logString += WiFi.localIP().toString() + "\n";
}

float readVoltage(int pin, int numSamples) {
  float sum = 0;
  int validSamples = 0;

  for (int i = 0; i < numSamples; i++) {
    int sample = analogRead(pin);
    if (sample > 1.30) {  // Ignora i campioni con valore pari a 1.30
      sum += sample;
      validSamples++;
    }
    delay(10);
  }

  return validSamples > 0 ? sum / validSamples : 0;  // Ritorna 0 se nessun campione è valido
}

void BATTERY() {
  analogSetPinAttenuation(5, ADC_11db);  // Imposta l'attenuazione per una gamma di tensione più alta
  const int numSamples = 50;             // Aumenta il numero di campioni per una lettura più stabile
  float minVoltage = 2.80;               // Valore minimo per 0%
  float maxVoltage = 4.20;               // Valore massimo per 100%
  float PIN5 = readVoltage(5, numSamples);

  // Calcola la tensione media
  voltageLevel = 1.25 * 3.3f * PIN5 * 2 / 4096.0f;

  // Applica una media pesata per stabilizzare la lettura
  filteredVoltage = voltageLevel;  // Tensione filtrata inizializzata
  const float alpha = 0.2;         // Coefficiente di smorzamento (0 < alpha < 1)
  filteredVoltage = alpha * voltageLevel + (1 - alpha) * filteredVoltage;

  // Calcola il livello di batteria usando la tensione filtrata
  batteryFraction = (filteredVoltage - minVoltage) / (maxVoltage - minVoltage);
  if (batteryFraction < 0) batteryFraction = 0;

  Serial.println((String) "Raw:" + PIN5 + " Voltage:" + filteredVoltage + "V Percent: " + (batteryFraction * 100) + "%");
  delay(1000);
}

void setup() {
  logString = "";
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(4, OUTPUT);
  // initialize the Serial
  Serial.begin(115200);
  digitalWrite(4, LOW);

  WIFION();

  ArduinoOTA.begin();  // Inizializza il servizio OTA
  Serial.println("OTA avviato");
  logString += ("\nOTA avviato");

  Serial.println("\nStarting TelegramBot...");
  logString += "\nStarting TelegramBot...\n";

  // Config time with online NTP servers
  configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
  client.setCACert(telegram_cert);

  // Wait for NTP server sync (with timeout)
  char strTime[64];
  struct tm tInfo;
  uint32_t start = millis();
  time_t now;                           // Dichiarazione della variabile now
  uint32_t timeout = millis() + 10000;  // Timeout di 10 secondi
  do {
    now = time(nullptr);
    tInfo = *localtime(&now);
    delay(500);  // Piccolo ritardo tra i tentativi
  } while (tInfo.tm_year < (1970 - 1900) && millis() < timeout);
  // Time to string
  strftime(strTime, sizeof(strTime), "%A %d/%m/%Y - %T\n", &tInfo);

  // Definisci l'orario target (es. 21:00 di oggi)
  struct tm timeinfo;
  now = time(nullptr);
  struct tm targetTime = timeinfo;
  localtime_r(&now, &targetTime);
  targetTime.tm_hour = ora;    // Imposta l'ora
  targetTime.tm_min = minuto;  // Imposta minuto
  targetTime.tm_sec = 0;       // Imposta i secondi a 0

  // Converti il target time in epoch
  time_t targetEpoch = mktime(&targetTime);

  // Calculate the difference in seconds between target and now
  TIME_TO_SLEEP = difftime(targetEpoch, now);

  // Se l'orario target è già passato oggi, va al giorno successivo
  if ((TIME_TO_SLEEP + 120) <= 0) {
    // Definisci l'orario target come 00:15 del giorno successivo
    struct tm nextDayTargetTime;
    localtime_r(&now, &nextDayTargetTime);
    nextDayTargetTime.tm_hour = ora;
    nextDayTargetTime.tm_min = minuto;

    // Aggiungi un giorno all'ora corrente per puntare al giorno successivo
    nextDayTargetTime.tm_mday += 1;

    // Converti l'orario target in epoch
    time_t nextDayTargetEpoch = mktime(&nextDayTargetTime);
    TIME_TO_SLEEP = difftime(nextDayTargetEpoch, now);

    Serial.printf("Manca meno di zero secondi. Dormo fino alle 08 del giorno successivo: %ld secondi\n", TIME_TO_SLEEP);
    char buffer[100];  // Buffer temporaneo per creare la stringa formattata
    sprintf(buffer, "Manca meno di zero secondi. Dormo fino alle 08 del giorno successivo: %ld secondi\n", TIME_TO_SLEEP);
    logString += buffer;
  }

  // Calcola la differenza in secondi
  Serial.printf("Time to sleep: %ld seconds\n", TIME_TO_SLEEP);
  char buffer[100];  // Buffer temporaneo per creare la stringa formattata
  sprintf(buffer, "Time to sleep: %ld seconds\n", TIME_TO_SLEEP);
  logString += buffer;

  // Set the Telegram bot properies
  myBot.setUpdateTime(900000);
  myBot.setTelegramToken(token);

  // Check if all things are ok
  Serial.print("\nTest Telegram connection... ");
  logString += ("\nTest Telegram connection... ");
  myBot.begin() ? Serial.println("OK") : Serial.println("NOK");
  if (myBot.begin()) {
    Serial.println("OK");
    logString += "OK\n";
  } else {
    Serial.println("NOK");
    logString += "NOK\n";
  }

Preso atto del codice sopra quando lo sleep è molto lungo (23 ore circa) capita che accumuli un errore nel tempo di risveglio di anche 20 minuti.
La cosa che non capisco è che nonostante come è stato strutturato il codice alle volte lo esegue senza aggiornare l'orario quindi anche se sono le 07:40 è convinto che siano le 08:00.

Ho provato tutto ciò che mi veniva in mente incluso dargli più tempo per sincronizzare ma sembra non servire. La cosa bizzarra poi è che non succede sempre. La media è che su 3 giorni sbaglia una volta. Le altre 2 volte invece si aggiorna correttamente e aggiorna correttamente l'ora.

Qualche suggerimento @cotestatnt ?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.