OTA Update tramite Amazon AWS

Buongiorno,

In questi giorni sto implementando la funzione di update su ESP32 utilizzando i server amazon.
Sotto allego codice, l’aggiornamento parte quando viene chiamata la funzione execOTA() premendo un pulsante posizionato sul pin 34.

Tralasciando la parte di verifica dimensione e tipo di file contenuto nel bucket amazon, vorrei discutere con voi (molto più esperti di me :smiley: ) della parte di streaming dei dati dal server all’ESP

    if (canBegin) {
      Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!");
      // No activity would appear on the Serial monitor
      // So be patient. This may take 2 - 5mins to complete
      size_t written = Update.writeStream(client);

quando viene chiamato il metodo .writeStream() l’ESP inizia il download e “non risponde” fino alla fine:

size_t UpdateClass::writeStream(Stream &data) {
    size_t written = 0;
    size_t toRead = 0;
    if(hasError() || !isRunning())
        return 0;

    if(!_verifyHeader(data.peek())) {
        _reset();
        return 0;
    }
    if (_progress_callback) {
        _progress_callback(0, _size);
    }

    if(_ledPin != -1) {
        pinMode(_ledPin, OUTPUT);
    }

    while(remaining()) {
        if(_ledPin != -1) {
            digitalWrite(_ledPin, _ledOn); // Switch LED on
        }
        size_t bytesToRead = SPI_FLASH_SEC_SIZE - _bufferLen;
        if(bytesToRead > remaining()) {
            bytesToRead = remaining();
        }

        toRead = data.readBytes(_buffer + _bufferLen,  bytesToRead);
        if(toRead == 0) { //Timeout
            delay(100);
            toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
            if(toRead == 0) { //Timeout
                _abort(UPDATE_ERROR_STREAM);
                return written;
            }
        }
        if(_ledPin != -1) {
            digitalWrite(_ledPin, !_ledOn); // Switch LED off
        }
        _bufferLen += toRead;
        if((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer())
            return written;
        written += toRead;
        if(_progress_callback) {
            _progress_callback(_progress, _size);
        }
    }
    if(_progress_callback) {
        _progress_callback(_size, _size);
    }
    return written;
}

Quando finisce o fallisce lo streaming dei dati ho return written che mi restituisce il numero di byte scritti e poi il mio codice prosegue con verifica dimensione del file scaricato e riavvio.

Ok, il mio obbiettivo è di avere un feedback di quanti byte vengono scritti man mano che lo streaming procede.

Avete idee o suggerimenti su come potrei procedere? :sweat_smile:

So che è una domanda molto specifica e difficilmente molti utilizzano AWS per l’upload, ma spero che con tutte le info date possiate darmi una mano a modificare la libreria nel modo più corretto. :smiley:

AWS_UPDATE_0.2.ino (10.6 KB)

Button.ino (1.87 KB)

Led.ino (426 Bytes)

Allora ho fatto dei progressi, ma non sono ancora arrivato alla soluzione.

All'interno del file Updater.cpp ho modificato una il metodo writeStream

size_t UpdateClass::writeStream(Stream &data) {
    size_t written = 0;
    size_t toRead = 0;
    if(hasError() || !isRunning())
        return 0;

    if(!_verifyHeader(data.peek())) {
        _reset();
        return 0;
    }
    if (_progress_callback) {
        _progress_callback(0, _size);
    }

    if(_ledPin != -1) {
        pinMode(_ledPin, OUTPUT);
    }

    while(remaining()) {
        
        printf("Downloading in progress: %lu\%%\n", (written * 100) / 694384);
        
        if(_ledPin != -1) {
            digitalWrite(_ledPin, _ledOn); // Switch LED on
        }
        size_t bytesToRead = SPI_FLASH_SEC_SIZE - _bufferLen;
        
        if(bytesToRead > remaining()) {
            bytesToRead = remaining();
        }

        toRead = data.readBytes(_buffer + _bufferLen,  bytesToRead);
        if(toRead == 0) { //Timeout
            delay(100);
            toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
            if(toRead == 0) { //Timeout
                _abort(UPDATE_ERROR_STREAM);
                return written;
            }
        }
        if(_ledPin != -1) {
            digitalWrite(_ledPin, !_ledOn); // Switch LED off
        }
        _bufferLen += toRead;
        if((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer())
            return written;
        written += toRead;
        if(_progress_callback) {
            _progress_callback(_progress, _size);
        }
    }
    if(_progress_callback) {
        _progress_callback(_size, _size);
    }
    return written;
}

Nello specifico dopo il while(remaining()), che è bloccante finché non è finito il download del file .bin, ho aggiunto la funzione printf():

printf("Downloading in progress: %lu\%%\n", (written * 100) / 694384);

questa mi stampa a monitor la percentuale di avanzamento del download, bene e fin qui ok.

Ora, siccome il mio obbiettivo è più complesso rispetto a stampare a monitor, ho fatto un'evoluzione ovvero ho definito la seguente funzione nel mio file .ino:

void sendDownloadPerc(unsigned long int byteWritten) {
  
  static unsigned long int percentage = 0;
  percentage = (byteWritten * 100) / contentLength;

  Serial.println(percentage);
}

e nel file Updater.cpp ho aggiunto la chiamata alla funzione:

sendDownloadPerc(written);

però in fase di compilazione mi da errore. immagino perché prima vengono compilate le librerie e poi il file .ino. Come potrei risolvere ?

La definizione della funzione non la posso mettere nel file .cpp (o forse si ?! non so :confused: ) perché lo scopo finale non sarà quello di stampare a monitor la percentuale ma di inviare il dato via mqtt.

Aggiornamento:

se all'interno della libreria uso printf o Serial.println durante l'esecuzione riesco a compilare senza problemi.

Mentre se all'inizio del file .cpp includo la libreria PubSubClient.h e poi uso il metodo publish() mi da errore in fase di compilazione, perché ?