Aggiornamenti OTA su ESP32 tramite browser web: caricamento in HTTPS (SSL/TLS) con certificato autofirmato – 2

Spread the love

In questo articolo, esploreremo come eseguire gli aggiornamenti OTA su ESP32 utilizzando un browser Web e un protocollo HTTPS con un certificato autofirmato. HTTPS fornisce un modo sicuro per trasferire i dati su Internet ed è essenziale per qualsiasi processo di aggiornamento OTA che coinvolge informazioni sensibili. Un certificato autofirmato può essere utilizzato per fornire crittografia e autenticazione senza la necessità di un’autorità di certificazione di terze parti, rendendolo una soluzione conveniente per progetti su piccola scala.

ESP32 OTA update with Web Browser: HTTPS (SSL/TLS) and self signed certificate
ESP32 OTA update with Web Browser: HTTPS (SSL/TLS) and self signed certificate

Inizieremo configurando ESP32 per gli aggiornamenti OTA, quindi genereremo un certificato autofirmato e configureremo il server HTTPS. Infine, testeremo il processo di aggiornamento OTA caricando una nuova versione del firmware utilizzando un browser web. Entro la fine di questo articolo, avrai un processo di aggiornamento OTA funzionante per il tuo progetto ESP32 che utilizza il protocollo HTTPS e un certificato autofirmato.

L’aggiornamento OTA (Over the Air) è il processo di caricamento del firmware su un modulo ESP32 utilizzando una connessione Wi-Fi anziché una porta seriale. Tale funzionalità diventa estremamente utile in caso di accesso fisico limitato o nullo al modulo.

Gli aggiornamenti OTA possono essere effettuati con le seguenti modalità:

  • IDE Arduino
  • Programma di navigazione in rete
  • Server HTTP

Prima di tutto, controlla il tutorial “ESP32: flash del firmware binario compilato (.bin)“.

Introduzione

nnanzitutto, osserviamo che il componente principale di ESP32 core ha bisogno di python installato e, durante l’installazione, ricordati di aggiungerlo alla PATH (per Windows)

ESP Tools Install Python and add It to path
ESP Tools Install Python and add It to path

Quindi vai a leggere come creare un file binario da questo articolo “ESP32: flash del firmware binario compilato (.bin)“.

Aggiornamento del firmware crittografato SSL/TLS protetto da password

Innanzitutto, penso che in questo caso non abbia senso utilizzare un certificato autofirmato perché se lo si desidera utilizzare internamente (nella rete LAN privata), non si aggiunge un certificato, si è già all’interno di una rete sicura e se vuoi esportare su Internet, una soluzione migliore è utilizzare un proxy con un singolo punto di ingresso con un certificato completo (come myhostname.org) e un set di endpoint che puntano al dispositivo.

HTTPS TLS SSL encryption Arduino OTA
HTTPS TLS SSL encryption Arduino OTA

Generare il certificato autofirmato

Se si desidera utilizzare un certificato autofirmato, è possibile utilizzare OpenSSL per la generazione delle chiavi private e del certificato.

Puoi ottenere openssl scaricando la versione Linux da tutti i gestori di pacchetti, oppure scaricarlo per Windows da qui , per usarlo con più semplicità aggiungi l’eseguibile alla path.

openssl req -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout key.pem -days 365 -out cert.pem -subj "/CN=esp32-webupdate.local"

ed ecco la risposta

Generating a RSA private key
................................+++++
..........................................................+++++
writing new private key to 'key.pem'
-----

Ecco il contenuto del key.pem

-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDHgkVGDdBv32Ba
MCgjTyw/dolIeix2YxsBPIvWVNqjq3nTwjGXrXUcr8Z2kJ7NVTXE3UVkHnMZmPeU
m4Gii9z5UbLk8tPhd1ZpQOKPZdioTFAZ6qKxspm4xVJqIW+gBRY849ofkP6DcDec
6dCYj8eJdQgARSfggDHL+Oc+0qh9YEZkRjyYIZWl3R5uVEi51AF5s7rWstuhvIUa
P/kSvvyIB1RRH4sgi8ARpY4uv9v/8EklRuh+eSYxz0U4aYcIqjSHBiG2U3utncxz
wKyz/T4G7Fbp1LAJhJqzPN2N1DznM6gFLlXvHJk8c4sJCHJpd7rgOvJEfte1xTuP
XKE1YNX3AgMBAAECggEACXMCFO9Sj/nkdmERhZqaXecfWW9v66uF++kCNoSOVnIo
sv7fmm98vH8Wx0bSPqdqhIh2YOeQTAYSs9cprKkzLhvQfUeDAYrFbPbFxETungn/
QTr7ua7b2QR/gsdSoiGbjAa+rgAQDemiuKvaVV958+i3GEwuN1PbB+4iBbe0gzuW
jUNjyHLw6TqlmnSS6Vf6JiKJU0czIjWW5lwJE30iyJp03LGbZDCmvyWGqN3zdW8y
PwI8GgrWHX2sgttWfWLlCZV0D582cWLc0ZKEkRyAOuhkUJ8Y/MwUKj/M/frB3Ii+
eEdhKNLUYlQY/Nh3QHL3ohjnzQ7/O+dLRf+6gBYgAQKBgQD9hhD4mt8NYuKRDnu5
4douvEmKLN18hJANFJjkDwQzRJsVnaGIEEJVZ7LpDwTy5+lNw+lvn3D5AVB++f+8
cXkwDIcEZbwk+/eOWz3SEPo1KwGhs8EQM7IzfRlXrkUsXMvu8Up4paueU4W5Pf7c
yXgnNbs0Fu9l90D/mV7OiNR/dwKBgQDJdSQGT9bfq5et8XsVnQQXg6BWc6/k75aa
qlvpgeXQtSKOmzTEkJz34Fu7sIEm1dQ0RUjDEz5EQVZcog34Dn/+K8aRBRrMFn17
wCdL0m3PgXlJlM42m1eaJ0vVO0p1jCtvGK+fP+AORz1hjOWeIHmhw4bYE+1w2F6x
oKFpH0z9gQKBgQCLJ39BNaCgtFovzIdU7AbaCDdFRIL9ybVXuKqC40sm6M1G/BKh
oGsIfbbR/ZB1051XNeV3g0h7JKGOUKJySMZ//SBO5ZhzpGmpFaPFHdR4QnbOzt91
iSqS4GN8oQcO5pB5Qq/hsO2WJboMh17QyTTOMMvkN4KHsUNYCFLlgm1A2QKBgQCS
7ov6yopmkilLpX9nMSEF4Wu1AiV87T3DypLEyYgLY8Ezj4G6B9tkcs+VIdPgtj5S
bWH3XXaho6HQaCWWEUVK5TSrGrUDuzeEZY6Dn5OVr9H9V7nbXAtVlGmbuOXCvBwF
qFSW6qiI4W6kUnY6kWcFE62qtUYNctIF7aksGbc2gQKBgQDK9tuP4pR1WBcK4kDa
r7EYWs5G83ceXVCTMf0XFJPgwNm0RduJ/ntRSWTj2jc5rENMEiFQpMIKz1h/rKkx
c/m7ZT9AbedAUxXOm9a/LKaTsJ11R/XO1MQE3QDZIDIq7C9Osd2Ap2WXdPazCtRR
D9eczO3iHYoTPvDYNWxDf45oig==
-----END PRIVATE KEY-----

e cert.pem

-----BEGIN CERTIFICATE-----
MIIDITCCAgmgAwIBAgIUdZdm1T/ibN+bQ5JB0+c+rnFPOZcwDQYJKoZIhvcNAQEL
BQAwIDEeMBwGA1UEAwwVZXNwMzItd2VidXBkYXRlLmxvY2FsMB4XDTIxMDkyNDEw
MjUwMloXDTIyMDkyNDEwMjUwMlowIDEeMBwGA1UEAwwVZXNwMzItd2VidXBkYXRl
LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx4JFRg3Qb99g
WjAoI08sP3aJSHosdmMbATyL1lTao6t508Ixl611HK/GdpCezVU1xN1FZB5zGZj3
lJuBoovc+VGy5PLT4XdWaUDij2XYqExQGeqisbKZuMVSaiFvoAUWPOPaH5D+g3A3
nOnQmI/HiXUIAEUn4IAxy/jnPtKofWBGZEY8mCGVpd0eblRIudQBebO61rLbobyF
Gj/5Er78iAdUUR+LIIvAEaWOLr/b//BJJUbofnkmMc9FOGmHCKo0hwYhtlN7rZ3M
c8Css/0+BuxW6dSwCYSaszzdjdQ85zOoBS5V7xyZPHOLCQhyaXe64DryRH7XtcU7
j1yhNWDV9wIDAQABo1MwUTAdBgNVHQ4EFgQULJvBhUDPFKnnSkWxNSH24EVWZbgw
HwYDVR0jBBgwFoAULJvBhUDPFKnnSkWxNSH24EVWZbgwDwYDVR0TAQH/BAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEAVc6IOt7zUDmy4sX2hcKnhzmpi5O9M0MqL9wx
46ocbTbFZfc5MecyyKQJ7vEk013f+tD9Vdj/OFBXXyffkBEe0JU5cpbzPMZb22Nu
24dP1hGt/kdsJEbXg3ZUGJbpJgfmF7mgMn6vp0ggp1Yprn3794Xh+QtnaVLnfGIc
dPH4qMLclwoZyA6xKeJjaGz6zQcHITzA6Eb9xX+HJKn91AOEJluUB+RubJBQlNpC
BeI1DvXhssiknKx4e/axcbbRxsW7VBeSK+5CR6y8yTHFJqXPJ0JWkby0NOi6C4es
UhplRTTHcxfOONyYWUIHas659U9yrEu8t8sTOyNQZPJ2ckdW5A==
-----END CERTIFICATE-----

Convertilo in bytearray

SSLCert ha bisogno del certificato e della chiave in formato bytearray

// Create an SSL certificate object from the files above
SSLCert cert = SSLCert(
    (unsigned char *)cert_pem, cert_pem_len,
    (unsigned char *)key_pem, key_pem_len
);

puoi usare il mio convertitore online per convertire.

Convert certificate and key self signed to bytearray
Convert certificate and key self-signed to byte array

Sketch di esempio HTTPS

Ottenere la libreria per il server HTTPS

Per eseguire questo esempio, hai bisogno di una libreria esterna che puoi trovare qui su GitHub .

Arduino IDE sketchbook location library base path
Arduino IDE sketchbook location library base path

Puoi SCARICARE il file zip della libreria, quindi estrarre il contenuto e copiarlo in formato <sketchbook location>\libraries.

Sketch di esempio

Ora aggiungiamo i certificati al codice di esempio

/**
 * Example for the ESP32 HTTP(S) OTA Update Webserver
 *
 * Check the guide to how to generate key and cert
 * and convert in bytearray with this tool
 * https://mischianti.org/online-converter-file-to-cpp-gzip-byte-array-3/
 *
 * Renzo Mischianti <www.mischianti.org>
 *
 * https://mischianti.org/
 *
 */

#define WIFI_SSID "<YOUR-SSID>"
#define WIFI_PSK  "<YOUR-PASSWD>"

// We will use wifi
#include <WiFi.h>

// Includes for the server
#include <HTTPSServer.hpp>
#include <SSLCert.hpp>
#include <HTTPRequest.hpp>
#include <HTTPResponse.hpp>
#include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp>
#include <HTTPURLEncodedBodyParser.hpp>
#include <Update.h>
#include <SPIFFS.h>

//File: cert.pem, Size: 1170
#define cert_pem_len 1170
const uint8_t cert_pem[] PROGMEM = {
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A, 0x4D, 0x49, 0x49,
0x44, 0x4A, 0x54, 0x43, 0x43, 0x41, 0x67, 0x32, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49,
0x55, 0x49, 0x62, 0x54, 0x73, 0x6D, 0x66, 0x2F, 0x50, 0x55, 0x4C, 0x4C, 0x70, 0x75, 0x75, 0x51,
0x50, 0x41, 0x77, 0x61, 0x39, 0x7A, 0x30, 0x32, 0x79, 0x79, 0x78, 0x41, 0x77, 0x44, 0x51, 0x59,
0x4A, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, 0x4C, 0x0D, 0x0A, 0x42,
0x51, 0x41, 0x77, 0x49, 0x6A, 0x45, 0x67, 0x4D, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41,
0x77, 0x77, 0x58, 0x5A, 0x58, 0x4E, 0x77, 0x4F, 0x44, 0x49, 0x32, 0x4E, 0x69, 0x31, 0x33, 0x5A,
0x57, 0x4A, 0x31, 0x63, 0x47, 0x52, 0x68, 0x64, 0x47, 0x55, 0x75, 0x62, 0x47, 0x39, 0x6A, 0x59,
0x57, 0x77, 0x77, 0x48, 0x68, 0x63, 0x4E, 0x4D, 0x6A, 0x45, 0x77, 0x4F, 0x54, 0x41, 0x32, 0x0D,
0x0A, 0x4D, 0x54, 0x55, 0x7A, 0x4F, 0x54, 0x55, 0x33, 0x57, 0x68, 0x63, 0x4E, 0x4D, 0x6A, 0x49,
0x77, 0x4F, 0x54, 0x41, 0x32, 0x4D, 0x54, 0x55, 0x7A, 0x4F, 0x54, 0x55, 0x33, 0x57, 0x6A, 0x41,
0x69, 0x4D, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x64,
0x6C, 0x63, 0x33, 0x41, 0x34, 0x4D, 0x6A, 0x59, 0x32, 0x4C, 0x58, 0x64, 0x6C, 0x59, 0x6E, 0x56,
0x77, 0x0D, 0x0A, 0x5A, 0x47, 0x46, 0x30, 0x5A, 0x53, 0x35, 0x73, 0x62, 0x32, 0x4E, 0x68, 0x62,
0x44, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4A, 0x4B, 0x6F, 0x5A, 0x49, 0x68,
0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41,
0x44, 0x43, 0x43, 0x41, 0x51, 0x6F, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4D, 0x64, 0x35, 0x4A,
0x51, 0x72, 0x55, 0x0D, 0x0A, 0x4E, 0x61, 0x43, 0x79, 0x43, 0x72, 0x66, 0x57, 0x72, 0x56, 0x30,
0x56, 0x50, 0x58, 0x6D, 0x37, 0x63, 0x31, 0x59, 0x67, 0x6F, 0x56, 0x49, 0x75, 0x58, 0x57, 0x37,
0x4C, 0x72, 0x74, 0x4D, 0x67, 0x4B, 0x33, 0x33, 0x5A, 0x62, 0x78, 0x64, 0x4F, 0x6F, 0x4B, 0x49,
0x4E, 0x63, 0x2B, 0x61, 0x72, 0x78, 0x54, 0x4E, 0x6C, 0x68, 0x41, 0x67, 0x39, 0x53, 0x32, 0x50,
0x6A, 0x32, 0x52, 0x65, 0x59, 0x0D, 0x0A, 0x35, 0x4B, 0x67, 0x32, 0x61, 0x67, 0x70, 0x37, 0x39,
0x70, 0x64, 0x30, 0x2B, 0x2F, 0x76, 0x57, 0x34, 0x54, 0x69, 0x47, 0x6F, 0x6E, 0x39, 0x6B, 0x37,
0x42, 0x45, 0x55, 0x38, 0x65, 0x77, 0x64, 0x44, 0x44, 0x4F, 0x38, 0x64, 0x65, 0x37, 0x4A, 0x52,
0x62, 0x63, 0x32, 0x30, 0x56, 0x49, 0x38, 0x42, 0x52, 0x33, 0x72, 0x51, 0x52, 0x61, 0x6C, 0x75,
0x6F, 0x70, 0x35, 0x5A, 0x79, 0x44, 0x43, 0x0D, 0x0A, 0x62, 0x4D, 0x48, 0x63, 0x4B, 0x5A, 0x56,
0x61, 0x39, 0x58, 0x71, 0x68, 0x32, 0x57, 0x4A, 0x45, 0x47, 0x73, 0x6C, 0x75, 0x57, 0x70, 0x56,
0x79, 0x67, 0x74, 0x4E, 0x6A, 0x5A, 0x41, 0x73, 0x62, 0x55, 0x56, 0x69, 0x34, 0x32, 0x6A, 0x48,
0x32, 0x69, 0x70, 0x6F, 0x74, 0x53, 0x69, 0x68, 0x65, 0x56, 0x79, 0x31, 0x68, 0x68, 0x56, 0x4A,
0x75, 0x63, 0x63, 0x52, 0x43, 0x55, 0x4D, 0x6A, 0x75, 0x0D, 0x0A, 0x72, 0x6B, 0x42, 0x76, 0x35,
0x55, 0x45, 0x5A, 0x6D, 0x73, 0x33, 0x6B, 0x55, 0x42, 0x47, 0x68, 0x41, 0x7A, 0x66, 0x74, 0x48,
0x48, 0x31, 0x63, 0x31, 0x6D, 0x70, 0x58, 0x34, 0x41, 0x7A, 0x51, 0x5A, 0x4F, 0x75, 0x78, 0x32,
0x53, 0x65, 0x6A, 0x4F, 0x57, 0x4D, 0x64, 0x65, 0x75, 0x42, 0x4D, 0x30, 0x53, 0x68, 0x58, 0x30,
0x53, 0x78, 0x39, 0x46, 0x31, 0x64, 0x73, 0x37, 0x51, 0x61, 0x4E, 0x0D, 0x0A, 0x44, 0x56, 0x54,
0x73, 0x42, 0x74, 0x67, 0x77, 0x67, 0x75, 0x4A, 0x6F, 0x4C, 0x48, 0x36, 0x31, 0x64, 0x56, 0x63,
0x4A, 0x34, 0x33, 0x5A, 0x65, 0x53, 0x47, 0x65, 0x37, 0x4E, 0x39, 0x71, 0x57, 0x71, 0x50, 0x74,
0x5A, 0x53, 0x48, 0x2B, 0x4F, 0x52, 0x50, 0x64, 0x4C, 0x2F, 0x6D, 0x4B, 0x2F, 0x58, 0x78, 0x4D,
0x6C, 0x71, 0x71, 0x54, 0x75, 0x6A, 0x53, 0x48, 0x34, 0x61, 0x64, 0x31, 0x71, 0x0D, 0x0A, 0x36,
0x70, 0x62, 0x62, 0x77, 0x49, 0x43, 0x54, 0x36, 0x4B, 0x31, 0x57, 0x54, 0x51, 0x30, 0x43, 0x41,
0x77, 0x45, 0x41, 0x41, 0x61, 0x4E, 0x54, 0x4D, 0x46, 0x45, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56,
0x52, 0x30, 0x4F, 0x42, 0x42, 0x59, 0x45, 0x46, 0x48, 0x59, 0x35, 0x37, 0x74, 0x63, 0x56, 0x6A,
0x54, 0x51, 0x70, 0x35, 0x74, 0x69, 0x70, 0x57, 0x66, 0x67, 0x51, 0x54, 0x31, 0x70, 0x65, 0x0D,
0x0A, 0x45, 0x72, 0x45, 0x5A, 0x4D, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51,
0x59, 0x4D, 0x42, 0x61, 0x41, 0x46, 0x48, 0x59, 0x35, 0x37, 0x74, 0x63, 0x56, 0x6A, 0x54, 0x51,
0x70, 0x35, 0x74, 0x69, 0x70, 0x57, 0x66, 0x67, 0x51, 0x54, 0x31, 0x70, 0x65, 0x45, 0x72, 0x45,
0x5A, 0x4D, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2F, 0x77, 0x51,
0x46, 0x0D, 0x0A, 0x4D, 0x41, 0x4D, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4A, 0x4B,
0x6F, 0x5A, 0x49, 0x68, 0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, 0x4C, 0x42, 0x51, 0x41, 0x44, 0x67,
0x67, 0x45, 0x42, 0x41, 0x49, 0x38, 0x32, 0x6F, 0x44, 0x32, 0x41, 0x36, 0x4D, 0x51, 0x48, 0x78,
0x78, 0x79, 0x35, 0x39, 0x31, 0x58, 0x36, 0x56, 0x52, 0x2F, 0x45, 0x49, 0x58, 0x39, 0x72, 0x57,
0x46, 0x32, 0x54, 0x0D, 0x0A, 0x58, 0x68, 0x65, 0x6E, 0x34, 0x49, 0x6D, 0x53, 0x79, 0x6D, 0x71,
0x6D, 0x35, 0x56, 0x46, 0x73, 0x51, 0x44, 0x41, 0x71, 0x52, 0x4C, 0x70, 0x62, 0x42, 0x71, 0x57,
0x4F, 0x36, 0x74, 0x30, 0x42, 0x67, 0x69, 0x41, 0x66, 0x62, 0x51, 0x4E, 0x47, 0x37, 0x6C, 0x33,
0x6B, 0x6B, 0x58, 0x51, 0x78, 0x41, 0x33, 0x73, 0x42, 0x2B, 0x6C, 0x49, 0x5A, 0x67, 0x4A, 0x65,
0x76, 0x67, 0x52, 0x4B, 0x74, 0x0D, 0x0A, 0x65, 0x37, 0x74, 0x65, 0x79, 0x31, 0x48, 0x7A, 0x64,
0x59, 0x75, 0x50, 0x76, 0x46, 0x46, 0x42, 0x65, 0x31, 0x58, 0x6F, 0x54, 0x38, 0x72, 0x52, 0x2F,
0x6C, 0x7A, 0x2B, 0x41, 0x63, 0x74, 0x51, 0x54, 0x67, 0x49, 0x61, 0x46, 0x42, 0x4E, 0x50, 0x45,
0x66, 0x74, 0x6F, 0x57, 0x65, 0x55, 0x70, 0x4F, 0x4B, 0x4A, 0x48, 0x58, 0x5A, 0x37, 0x4E, 0x61,
0x57, 0x69, 0x41, 0x76, 0x6D, 0x70, 0x43, 0x0D, 0x0A, 0x6A, 0x69, 0x7A, 0x78, 0x30, 0x6E, 0x72,
0x64, 0x70, 0x61, 0x6E, 0x6E, 0x47, 0x65, 0x67, 0x77, 0x39, 0x63, 0x69, 0x46, 0x42, 0x70, 0x6E,
0x36, 0x2B, 0x38, 0x44, 0x6F, 0x4D, 0x56, 0x71, 0x2B, 0x47, 0x75, 0x51, 0x34, 0x45, 0x48, 0x76,
0x78, 0x6E, 0x56, 0x58, 0x50, 0x35, 0x4F, 0x59, 0x7A, 0x44, 0x50, 0x36, 0x47, 0x6D, 0x79, 0x75,
0x43, 0x73, 0x7A, 0x76, 0x47, 0x6D, 0x4B, 0x4E, 0x54, 0x0D, 0x0A, 0x34, 0x2B, 0x2F, 0x4B, 0x78,
0x7A, 0x38, 0x32, 0x46, 0x48, 0x6A, 0x71, 0x79, 0x6B, 0x67, 0x41, 0x32, 0x41, 0x76, 0x44, 0x2F,
0x39, 0x6D, 0x4F, 0x4C, 0x53, 0x61, 0x4F, 0x68, 0x4B, 0x6E, 0x66, 0x73, 0x38, 0x43, 0x64, 0x58,
0x78, 0x2B, 0x30, 0x72, 0x33, 0x4A, 0x31, 0x78, 0x58, 0x4D, 0x55, 0x38, 0x30, 0x37, 0x64, 0x6A,
0x57, 0x42, 0x4C, 0x38, 0x4B, 0x42, 0x55, 0x67, 0x54, 0x54, 0x66, 0x0D, 0x0A, 0x62, 0x4A, 0x79,
0x50, 0x50, 0x6C, 0x6D, 0x30, 0x57, 0x6C, 0x66, 0x79, 0x37, 0x64, 0x79, 0x57, 0x55, 0x78, 0x54,
0x38, 0x50, 0x46, 0x6D, 0x6F, 0x58, 0x45, 0x52, 0x38, 0x71, 0x75, 0x36, 0x71, 0x68, 0x66, 0x6D,
0x77, 0x39, 0x6F, 0x63, 0x4C, 0x43, 0x70, 0x34, 0x6C, 0x61, 0x42, 0x75, 0x36, 0x66, 0x46, 0x63,
0x49, 0x34, 0x50, 0x6F, 0x3D, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20,
0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D,
0x0D, 0x0A
};
//File: key.pem, Size: 1732
#define key_pem_len 1732
const uint8_t key_pem[] PROGMEM = {
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41,
0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A, 0x4D, 0x49, 0x49,
0x45, 0x76, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69,
0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x53, 0x43, 0x42, 0x4B, 0x67,
0x77, 0x67, 0x67, 0x53, 0x6B, 0x41, 0x67, 0x45, 0x41, 0x41, 0x6F, 0x49, 0x42, 0x41, 0x51, 0x44,
0x48, 0x65, 0x53, 0x55, 0x4B, 0x31, 0x44, 0x57, 0x67, 0x73, 0x67, 0x71, 0x33, 0x0D, 0x0A, 0x31,
0x71, 0x31, 0x64, 0x46, 0x54, 0x31, 0x35, 0x75, 0x33, 0x4E, 0x57, 0x49, 0x4B, 0x46, 0x53, 0x4C,
0x6C, 0x31, 0x75, 0x79, 0x36, 0x37, 0x54, 0x49, 0x43, 0x74, 0x39, 0x32, 0x57, 0x38, 0x58, 0x54,
0x71, 0x43, 0x69, 0x44, 0x58, 0x50, 0x6D, 0x71, 0x38, 0x55, 0x7A, 0x5A, 0x59, 0x51, 0x49, 0x50,
0x55, 0x74, 0x6A, 0x34, 0x39, 0x6B, 0x58, 0x6D, 0x4F, 0x53, 0x6F, 0x4E, 0x6D, 0x6F, 0x4B, 0x0D,
0x0A, 0x65, 0x2F, 0x61, 0x58, 0x64, 0x50, 0x76, 0x37, 0x31, 0x75, 0x45, 0x34, 0x68, 0x71, 0x4A,
0x2F, 0x5A, 0x4F, 0x77, 0x52, 0x46, 0x50, 0x48, 0x73, 0x48, 0x51, 0x77, 0x7A, 0x76, 0x48, 0x58,
0x75, 0x79, 0x55, 0x57, 0x33, 0x4E, 0x74, 0x46, 0x53, 0x50, 0x41, 0x55, 0x64, 0x36, 0x30, 0x45,
0x57, 0x70, 0x62, 0x71, 0x4B, 0x65, 0x57, 0x63, 0x67, 0x77, 0x6D, 0x7A, 0x42, 0x33, 0x43, 0x6D,
0x56, 0x0D, 0x0A, 0x57, 0x76, 0x56, 0x36, 0x6F, 0x64, 0x6C, 0x69, 0x52, 0x42, 0x72, 0x4A, 0x62,
0x6C, 0x71, 0x56, 0x63, 0x6F, 0x4C, 0x54, 0x59, 0x32, 0x51, 0x4C, 0x47, 0x31, 0x46, 0x59, 0x75,
0x4E, 0x6F, 0x78, 0x39, 0x6F, 0x71, 0x61, 0x4C, 0x55, 0x6F, 0x6F, 0x58, 0x6C, 0x63, 0x74, 0x59,
0x59, 0x56, 0x53, 0x62, 0x6E, 0x48, 0x45, 0x51, 0x6C, 0x44, 0x49, 0x37, 0x71, 0x35, 0x41, 0x62,
0x2B, 0x56, 0x42, 0x0D, 0x0A, 0x47, 0x5A, 0x72, 0x4E, 0x35, 0x46, 0x41, 0x52, 0x6F, 0x51, 0x4D,
0x33, 0x37, 0x52, 0x78, 0x39, 0x58, 0x4E, 0x5A, 0x71, 0x56, 0x2B, 0x41, 0x4D, 0x30, 0x47, 0x54,
0x72, 0x73, 0x64, 0x6B, 0x6E, 0x6F, 0x7A, 0x6C, 0x6A, 0x48, 0x58, 0x72, 0x67, 0x54, 0x4E, 0x45,
0x6F, 0x56, 0x39, 0x45, 0x73, 0x66, 0x52, 0x64, 0x58, 0x62, 0x4F, 0x30, 0x47, 0x6A, 0x51, 0x31,
0x55, 0x37, 0x41, 0x62, 0x59, 0x0D, 0x0A, 0x4D, 0x49, 0x4C, 0x69, 0x61, 0x43, 0x78, 0x2B, 0x74,
0x58, 0x56, 0x58, 0x43, 0x65, 0x4E, 0x32, 0x58, 0x6B, 0x68, 0x6E, 0x75, 0x7A, 0x66, 0x61, 0x6C,
0x71, 0x6A, 0x37, 0x57, 0x55, 0x68, 0x2F, 0x6A, 0x6B, 0x54, 0x33, 0x53, 0x2F, 0x35, 0x69, 0x76,
0x31, 0x38, 0x54, 0x4A, 0x61, 0x71, 0x6B, 0x37, 0x6F, 0x30, 0x68, 0x2B, 0x47, 0x6E, 0x64, 0x61,
0x75, 0x71, 0x57, 0x32, 0x38, 0x43, 0x41, 0x0D, 0x0A, 0x6B, 0x2B, 0x69, 0x74, 0x56, 0x6B, 0x30,
0x4E, 0x41, 0x67, 0x4D, 0x42, 0x41, 0x41, 0x45, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4B, 0x64,
0x67, 0x73, 0x41, 0x52, 0x32, 0x4C, 0x4D, 0x6D, 0x36, 0x6D, 0x2B, 0x50, 0x47, 0x37, 0x35, 0x47,
0x37, 0x30, 0x4F, 0x6E, 0x6B, 0x73, 0x4E, 0x4D, 0x45, 0x62, 0x6C, 0x6C, 0x58, 0x4C, 0x6D, 0x39,
0x5A, 0x32, 0x6B, 0x69, 0x75, 0x4A, 0x64, 0x42, 0x6B, 0x0D, 0x0A, 0x4D, 0x79, 0x4F, 0x4C, 0x68,
0x70, 0x35, 0x30, 0x53, 0x31, 0x79, 0x7A, 0x70, 0x62, 0x57, 0x4B, 0x36, 0x55, 0x39, 0x41, 0x6E,
0x35, 0x49, 0x69, 0x44, 0x6E, 0x67, 0x4F, 0x67, 0x30, 0x2F, 0x69, 0x32, 0x50, 0x67, 0x54, 0x4C,
0x4D, 0x66, 0x4B, 0x45, 0x65, 0x63, 0x77, 0x56, 0x36, 0x76, 0x6D, 0x7A, 0x56, 0x4F, 0x34, 0x69,
0x35, 0x32, 0x4A, 0x78, 0x62, 0x59, 0x71, 0x61, 0x61, 0x4B, 0x2F, 0x0D, 0x0A, 0x38, 0x50, 0x56,
0x39, 0x54, 0x6C, 0x4A, 0x2B, 0x58, 0x51, 0x5A, 0x7A, 0x39, 0x70, 0x63, 0x30, 0x59, 0x46, 0x6C,
0x77, 0x6C, 0x79, 0x61, 0x36, 0x32, 0x42, 0x35, 0x56, 0x42, 0x6F, 0x31, 0x6C, 0x41, 0x44, 0x2B,
0x6A, 0x49, 0x33, 0x6A, 0x54, 0x64, 0x6D, 0x56, 0x4F, 0x59, 0x47, 0x76, 0x46, 0x66, 0x5A, 0x30,
0x4A, 0x69, 0x56, 0x31, 0x33, 0x65, 0x4F, 0x73, 0x59, 0x38, 0x52, 0x6C, 0x51, 0x0D, 0x0A, 0x42,
0x77, 0x47, 0x52, 0x2B, 0x38, 0x74, 0x67, 0x56, 0x7A, 0x53, 0x39, 0x55, 0x45, 0x71, 0x2F, 0x36,
0x2B, 0x50, 0x44, 0x35, 0x77, 0x75, 0x6C, 0x73, 0x79, 0x6F, 0x6A, 0x4D, 0x2B, 0x70, 0x39, 0x78,
0x2F, 0x72, 0x6D, 0x71, 0x36, 0x31, 0x6A, 0x63, 0x36, 0x6A, 0x63, 0x66, 0x7A, 0x71, 0x45, 0x75,
0x70, 0x7A, 0x55, 0x64, 0x69, 0x5A, 0x4D, 0x65, 0x45, 0x69, 0x75, 0x50, 0x7A, 0x4C, 0x71, 0x0D,
0x0A, 0x77, 0x5A, 0x64, 0x32, 0x65, 0x46, 0x68, 0x50, 0x51, 0x46, 0x43, 0x76, 0x64, 0x58, 0x6F,
0x55, 0x69, 0x61, 0x78, 0x53, 0x67, 0x4A, 0x2B, 0x47, 0x31, 0x54, 0x69, 0x6B, 0x44, 0x4D, 0x58,
0x61, 0x51, 0x58, 0x67, 0x55, 0x53, 0x41, 0x4D, 0x43, 0x65, 0x49, 0x42, 0x74, 0x53, 0x58, 0x4C,
0x41, 0x64, 0x4D, 0x65, 0x68, 0x70, 0x43, 0x75, 0x6C, 0x51, 0x35, 0x6C, 0x33, 0x41, 0x73, 0x38,
0x30, 0x0D, 0x0A, 0x77, 0x6B, 0x48, 0x64, 0x36, 0x72, 0x42, 0x46, 0x78, 0x6C, 0x71, 0x69, 0x74,
0x4D, 0x47, 0x4C, 0x4A, 0x30, 0x65, 0x4D, 0x47, 0x6F, 0x54, 0x58, 0x79, 0x67, 0x51, 0x77, 0x2F,
0x7A, 0x58, 0x4C, 0x6F, 0x5A, 0x62, 0x4C, 0x7A, 0x72, 0x6A, 0x66, 0x4F, 0x4D, 0x45, 0x43, 0x67,
0x59, 0x45, 0x41, 0x38, 0x30, 0x6A, 0x4E, 0x59, 0x75, 0x2F, 0x61, 0x41, 0x6B, 0x69, 0x52, 0x77,
0x4A, 0x72, 0x71, 0x0D, 0x0A, 0x74, 0x2F, 0x72, 0x6D, 0x7A, 0x30, 0x49, 0x74, 0x39, 0x33, 0x44,
0x36, 0x59, 0x6C, 0x50, 0x44, 0x32, 0x59, 0x51, 0x4B, 0x35, 0x75, 0x47, 0x52, 0x71, 0x7A, 0x76,
0x4F, 0x33, 0x6E, 0x6F, 0x6F, 0x54, 0x6B, 0x4E, 0x48, 0x65, 0x73, 0x35, 0x59, 0x54, 0x4A, 0x2B,
0x6F, 0x2B, 0x4F, 0x38, 0x61, 0x4E, 0x38, 0x61, 0x37, 0x61, 0x36, 0x73, 0x4F, 0x6B, 0x4E, 0x55,
0x66, 0x6B, 0x64, 0x64, 0x31, 0x0D, 0x0A, 0x74, 0x2B, 0x68, 0x52, 0x63, 0x63, 0x66, 0x70, 0x30,
0x6C, 0x58, 0x61, 0x61, 0x69, 0x4C, 0x77, 0x65, 0x64, 0x59, 0x67, 0x2F, 0x36, 0x2B, 0x38, 0x77,
0x64, 0x75, 0x6F, 0x47, 0x53, 0x34, 0x4C, 0x58, 0x68, 0x46, 0x52, 0x56, 0x2F, 0x47, 0x41, 0x32,
0x4B, 0x59, 0x64, 0x6C, 0x4E, 0x65, 0x74, 0x39, 0x4D, 0x6A, 0x76, 0x54, 0x6E, 0x35, 0x6C, 0x68,
0x52, 0x4B, 0x78, 0x6B, 0x44, 0x77, 0x45, 0x0D, 0x0A, 0x56, 0x36, 0x67, 0x34, 0x45, 0x2B, 0x74,
0x37, 0x59, 0x34, 0x73, 0x4F, 0x79, 0x32, 0x32, 0x74, 0x6D, 0x70, 0x54, 0x45, 0x37, 0x49, 0x30,
0x56, 0x66, 0x47, 0x73, 0x43, 0x67, 0x59, 0x45, 0x41, 0x30, 0x65, 0x59, 0x6A, 0x75, 0x74, 0x74,
0x74, 0x6A, 0x37, 0x6F, 0x70, 0x39, 0x35, 0x59, 0x76, 0x37, 0x2F, 0x57, 0x6F, 0x7A, 0x64, 0x77,
0x53, 0x48, 0x72, 0x6E, 0x4C, 0x79, 0x56, 0x32, 0x55, 0x0D, 0x0A, 0x79, 0x36, 0x52, 0x6F, 0x33,
0x79, 0x33, 0x66, 0x56, 0x71, 0x55, 0x49, 0x6A, 0x61, 0x66, 0x74, 0x4F, 0x65, 0x78, 0x41, 0x6E,
0x6E, 0x49, 0x4E, 0x53, 0x5A, 0x62, 0x56, 0x6D, 0x69, 0x6B, 0x38, 0x63, 0x51, 0x64, 0x44, 0x70,
0x49, 0x6B, 0x47, 0x46, 0x63, 0x51, 0x4C, 0x78, 0x6F, 0x69, 0x66, 0x38, 0x4A, 0x67, 0x68, 0x6D,
0x77, 0x79, 0x4A, 0x43, 0x6E, 0x53, 0x4C, 0x34, 0x58, 0x33, 0x73, 0x0D, 0x0A, 0x55, 0x6E, 0x50,
0x2B, 0x59, 0x58, 0x39, 0x57, 0x76, 0x2B, 0x67, 0x34, 0x63, 0x4B, 0x53, 0x58, 0x51, 0x48, 0x57,
0x30, 0x65, 0x4F, 0x32, 0x6E, 0x33, 0x63, 0x49, 0x71, 0x63, 0x50, 0x33, 0x4C, 0x33, 0x70, 0x67,
0x6F, 0x42, 0x31, 0x42, 0x68, 0x43, 0x77, 0x41, 0x71, 0x56, 0x6F, 0x65, 0x56, 0x42, 0x39, 0x49,
0x58, 0x71, 0x6A, 0x66, 0x33, 0x6F, 0x55, 0x51, 0x6F, 0x48, 0x63, 0x6E, 0x64, 0x0D, 0x0A, 0x68,
0x63, 0x55, 0x70, 0x35, 0x31, 0x4C, 0x44, 0x4F, 0x6D, 0x63, 0x43, 0x67, 0x59, 0x42, 0x33, 0x6C,
0x49, 0x42, 0x48, 0x73, 0x69, 0x64, 0x52, 0x57, 0x67, 0x51, 0x79, 0x54, 0x4C, 0x4D, 0x30, 0x62,
0x57, 0x49, 0x48, 0x32, 0x37, 0x71, 0x6D, 0x56, 0x6D, 0x54, 0x72, 0x38, 0x63, 0x70, 0x68, 0x58,
0x78, 0x4C, 0x51, 0x75, 0x32, 0x30, 0x54, 0x59, 0x70, 0x6C, 0x6A, 0x4A, 0x31, 0x34, 0x71, 0x0D,
0x0A, 0x59, 0x63, 0x31, 0x2F, 0x6F, 0x6D, 0x38, 0x71, 0x63, 0x6F, 0x76, 0x6D, 0x6C, 0x2F, 0x67,
0x6D, 0x46, 0x45, 0x76, 0x4A, 0x4E, 0x31, 0x49, 0x34, 0x68, 0x46, 0x6B, 0x35, 0x49, 0x56, 0x4F,
0x65, 0x61, 0x74, 0x57, 0x6C, 0x66, 0x4B, 0x4D, 0x45, 0x6E, 0x4F, 0x68, 0x33, 0x70, 0x4F, 0x62,
0x59, 0x72, 0x42, 0x53, 0x61, 0x4F, 0x50, 0x49, 0x70, 0x77, 0x32, 0x4D, 0x54, 0x78, 0x56, 0x73,
0x58, 0x0D, 0x0A, 0x43, 0x4B, 0x49, 0x58, 0x2F, 0x50, 0x2F, 0x63, 0x2F, 0x59, 0x47, 0x71, 0x79,
0x48, 0x79, 0x62, 0x78, 0x69, 0x78, 0x43, 0x51, 0x38, 0x52, 0x34, 0x72, 0x57, 0x43, 0x54, 0x79,
0x62, 0x78, 0x45, 0x72, 0x63, 0x32, 0x71, 0x6C, 0x4F, 0x4F, 0x59, 0x59, 0x53, 0x43, 0x4C, 0x67,
0x30, 0x53, 0x43, 0x70, 0x37, 0x39, 0x48, 0x6D, 0x6D, 0x31, 0x47, 0x4D, 0x77, 0x4B, 0x42, 0x67,
0x51, 0x44, 0x41, 0x0D, 0x0A, 0x70, 0x55, 0x38, 0x70, 0x30, 0x76, 0x63, 0x74, 0x73, 0x52, 0x6D,
0x50, 0x69, 0x61, 0x4B, 0x5A, 0x78, 0x49, 0x69, 0x58, 0x32, 0x47, 0x49, 0x78, 0x48, 0x53, 0x6D,
0x79, 0x75, 0x56, 0x63, 0x31, 0x79, 0x4D, 0x49, 0x51, 0x42, 0x46, 0x51, 0x31, 0x65, 0x2B, 0x62,
0x72, 0x7A, 0x4C, 0x4A, 0x6F, 0x4E, 0x54, 0x50, 0x68, 0x75, 0x4B, 0x41, 0x46, 0x61, 0x4A, 0x44,
0x48, 0x6D, 0x77, 0x31, 0x45, 0x0D, 0x0A, 0x56, 0x2F, 0x78, 0x33, 0x61, 0x4F, 0x50, 0x53, 0x32,
0x6B, 0x70, 0x4D, 0x66, 0x31, 0x7A, 0x38, 0x50, 0x30, 0x53, 0x6F, 0x76, 0x38, 0x71, 0x50, 0x64,
0x41, 0x52, 0x6D, 0x67, 0x32, 0x4B, 0x42, 0x45, 0x73, 0x44, 0x6F, 0x7A, 0x79, 0x7A, 0x5A, 0x6D,
0x64, 0x4D, 0x6A, 0x58, 0x34, 0x30, 0x4B, 0x74, 0x6E, 0x31, 0x62, 0x65, 0x42, 0x52, 0x58, 0x37,
0x6A, 0x74, 0x78, 0x31, 0x52, 0x35, 0x6D, 0x0D, 0x0A, 0x51, 0x4A, 0x53, 0x4D, 0x6B, 0x66, 0x4E,
0x66, 0x57, 0x31, 0x6D, 0x41, 0x62, 0x5A, 0x51, 0x55, 0x78, 0x33, 0x69, 0x38, 0x32, 0x2F, 0x31,
0x46, 0x58, 0x2F, 0x37, 0x4A, 0x79, 0x46, 0x71, 0x75, 0x79, 0x68, 0x54, 0x35, 0x6F, 0x50, 0x5A,
0x61, 0x42, 0x51, 0x4B, 0x42, 0x67, 0x47, 0x77, 0x44, 0x79, 0x64, 0x35, 0x34, 0x36, 0x58, 0x62,
0x77, 0x4D, 0x65, 0x33, 0x77, 0x43, 0x31, 0x69, 0x5A, 0x0D, 0x0A, 0x42, 0x4A, 0x76, 0x70, 0x6C,
0x68, 0x4A, 0x53, 0x6E, 0x43, 0x34, 0x32, 0x50, 0x61, 0x70, 0x4F, 0x4F, 0x58, 0x46, 0x55, 0x6B,
0x63, 0x67, 0x32, 0x63, 0x63, 0x65, 0x37, 0x69, 0x59, 0x50, 0x6B, 0x37, 0x5A, 0x50, 0x4F, 0x67,
0x57, 0x72, 0x57, 0x54, 0x70, 0x39, 0x53, 0x52, 0x41, 0x68, 0x49, 0x45, 0x54, 0x66, 0x75, 0x41,
0x6E, 0x67, 0x47, 0x38, 0x57, 0x71, 0x52, 0x36, 0x37, 0x71, 0x63, 0x0D, 0x0A, 0x7A, 0x4C, 0x44,
0x52, 0x42, 0x51, 0x67, 0x42, 0x73, 0x66, 0x30, 0x71, 0x41, 0x2B, 0x50, 0x6C, 0x66, 0x66, 0x39,
0x45, 0x62, 0x63, 0x31, 0x71, 0x7A, 0x6A, 0x31, 0x79, 0x51, 0x32, 0x64, 0x53, 0x31, 0x61, 0x76,
0x72, 0x55, 0x75, 0x72, 0x78, 0x4F, 0x4F, 0x5A, 0x55, 0x63, 0x53, 0x7A, 0x71, 0x57, 0x56, 0x4C,
0x5A, 0x2F, 0x7A, 0x33, 0x4F, 0x4E, 0x32, 0x4E, 0x4E, 0x45, 0x58, 0x76, 0x53, 0x0D, 0x0A, 0x67,
0x51, 0x32, 0x70, 0x62, 0x4A, 0x7A, 0x61, 0x75, 0x78, 0x4F, 0x71, 0x59, 0x57, 0x56, 0x74, 0x36,
0x41, 0x7A, 0x6F, 0x74, 0x7A, 0x6B, 0x4E, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E,
0x44, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D,
0x2D, 0x2D, 0x0D, 0x0A
};

// The HTTPS Server comes in a separate namespace. For easier use, include it here.
using namespace httpsserver;

// Create an SSL certificate object from the files included above
SSLCert cert = SSLCert(
    (unsigned char *)cert_pem, cert_pem_len,
    (unsigned char *)key_pem, key_pem_len
);

// Create an SSL-enabled server that uses the certificate
// The contstructor takes some more parameters, but we go for default values here.
HTTPSServer secureServer = HTTPSServer(&cert);

void handleRoot(HTTPRequest * req, HTTPResponse * res);
void handleFormUpload(HTTPRequest * req, HTTPResponse * res);
void handle404(HTTPRequest * req, HTTPResponse * res);

void setup() {
  // For logging
  Serial.begin(115200);
  // Connect to WiFi
  Serial.println("Setting up WiFi");
  WiFi.begin(WIFI_SSID, WIFI_PSK);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.print("Connected. IP=");
  Serial.println(WiFi.localIP());

  ResourceNode * nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
  ResourceNode * nodeForm = new ResourceNode("/upload", "GET", &handleRoot);

  // 404 node has no URL as it is used for all requests that don't match anything else
  ResourceNode * node404  = new ResourceNode("", "GET", &handle404);

  // Add all nodes to the server so they become accessible:
  secureServer.registerNode(nodeForm);
  secureServer.registerNode(nodeFormUpload);
  secureServer.setDefaultNode(node404);

  Serial.println("Starting server...");
  secureServer.start();
  if (secureServer.isRunning()) {
    Serial.println("Server ready.");
  }
}

void loop() {
  // This call will let the server do its work
  secureServer.loop();
  delay(1);
}

static const char serverIndex[] PROGMEM =
R"(<!DOCTYPE html>
     <html lang='en'>
     <head>
         <meta charset='utf-8'>
         <meta name='viewport' content='width=device-width,initial-scale=1'/>
     </head>
     <body>
     <form method='POST' action='' enctype='multipart/form-data'>
         Firmware:<br>
         <input type='file' accept='.bin,.bin.gz' name='firmware'>
         <input type='submit' value='Update Firmware'>
     </form>
     <form method='POST' action='' enctype='multipart/form-data'>
         FileSystem:<br>
         <input type='file' accept='.bin,.bin.gz,.image' name='filesystem'>
         <input type='submit' value='Update FileSystem'>
     </form>
     </body>
     </html>)";
static const char successResponse[] PROGMEM =
"<p>Update Success! Reset device and restart webpage.</p>";

void handleRoot(HTTPRequest * req, HTTPResponse * res) {
  res->setHeader("Content-Type", "text/html");

  // Just the regular HTML document structure, nothing special to forms here....
  res->println(serverIndex);
}

void handleFormUpload(HTTPRequest * req, HTTPResponse * res) {
  HTTPBodyParser *parser;
  std::string contentType = req->getHeader("Content-Type");

  size_t semicolonPos = contentType.find(";");
  if (semicolonPos != std::string::npos) {
    contentType = contentType.substr(0, semicolonPos);
  }

  // Now, we can decide based on the content type:
  if (contentType == "multipart/form-data") {
    parser = new HTTPMultipartBodyParser(req);
  } else {
    Serial.printf("Unknown POST Content-Type: %s\n", contentType.c_str());
    return;
  }

  while(parser->nextField()) {
    std::string name = parser->getFieldName();
    std::string filename = parser->getFieldFilename();
    std::string mimeType = parser->getFieldMimeType();

    Serial.printf("handleFormUpload: field name='%s', filename='%s', mimetype='%s'\n", name.c_str(), filename.c_str(), mimeType.c_str());

    if (name != "firmware" && name != "filesystem" ) {
      Serial.println("Skipping unexpected field");
      break;
    }

    if (name == "filesystem") {
      Serial.println(F("Filesystem update found!"));
        if (!Update.begin(SPIFFS.totalBytes(), U_SPIFFS)) {//start with max available size
            Update.printError(Serial);
        }
    }
    else {
      Serial.println(F("Firmware update found!"));
        uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
        if (!Update.begin(maxSketchSpace, U_FLASH)) {//start with max available size
          Update.printError(Serial);
        }
    }

  Serial.println(F("Starting update!"));
    size_t fileLength = 0;

  while (!parser->endOfField()) {
    byte buf[512];
    size_t readLength = parser->read(buf, 512);

    if (Update.write(buf, readLength) != readLength) {
      Update.printError(Serial);
    }

    fileLength += readLength;

    Serial.printf("Upload and updated %u byte\n", fileLength);
  }
    if (Update.end(true)) { //true to set the size to the current progress
        Serial.printf("Update Success: %u\n", fileLength);
        // res->println("<p>Update Success: \nRebooting...\n</p>");
        res->println(successResponse);
    }
    else {
      Update.printError(Serial);
      res->println(Update.getError());
    }
  }

  delete parser;
}

void handle404(HTTPRequest * req, HTTPResponse * res) {
  req->discardRequestBody();
  res->setStatusCode(404);
  res->setStatusText("Not Found");
  res->setHeader("Content-Type", "text/html");
  res->println("<!DOCTYPE html>");
  res->println("<html>");
  res->println("<head><title>Not Found</title></head>");
  res->println("<body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body>");
  res->println("</html>");
}

In questo sketch, creiamo il certificato con il contenuto di cer e key.

// Create an SSL certificate object from the files above
SSLCert cert = SSLCert(
    (unsigned char *)cert_pem, cert_pem_len,
    (unsigned char *)key_pem, key_pem_len
);

// Create an SSL-enabled server that uses the certificate
// The contstructor takes some more parameters, but we go for default values here.
HTTPSServer secureServer = HTTPSServer(&cert);

E pubblicheremo l’endpoint di caricamento in GET per la pagina e in POST per caricare il firmware.

  ResourceNode * nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
  ResourceNode * nodeForm = new ResourceNode("/upload", "GET", &handleRoot);

  // 404 node has no URL as it is used for all requests that don't match anything else
  ResourceNode * node404  = new ResourceNode("", "GET", &handle404);

  // Add all nodes to the server so they become accessible:
  secureServer.registerNode(nodeForm);
  secureServer.registerNode(nodeFormUpload);
  secureServer.setDefaultNode(node404);

Riutilizzo la pagina dell’HTTPUpdateServer.

static const char serverIndex[] PROGMEM =
R"(<!DOCTYPE html>
     <html lang='en'>
     <head>
         <meta charset='utf-8'>
         <meta name='viewport' content='width=device-width,initial-scale=1'/>
     </head>
     <body>
     <form method='POST' action='' enctype='multipart/form-data'>
         Firmware:<br>
         <input type='file' accept='.bin,.bin.gz' name='firmware'>
         <input type='submit' value='Update Firmware'>
     </form>
     <form method='POST' action='' enctype='multipart/form-data'>
         FileSystem:<br>
         <input type='file' accept='.bin,.bin.gz,.image' name='filesystem'>
         <input type='submit' value='Update FileSystem'>
     </form>
     </body>
     </html>)";

Successivamente, quando riceviamo i dati del modulo POST, verificheremo se si tratta di firmware o filesystem e chiameremo il begin della classe Update con il parametro corretto U_FLASH U_FS.

    if (name == "filesystem") {
      Serial.println(F("Filesystem update found!"));
        if (!Update.begin(SPIFFS.totalBytes(), U_SPIFFS)) {//start with max available size
            Update.printError(Serial);
        }
    }
    else {
      Serial.println(F("Firmware update found!"));
        uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
        if (!Update.begin(maxSketchSpace, U_FLASH)) {//start with max available size
          Update.printError(Serial);
        }
    }

Quando lo stream inizia, userò Update.write

  while (!parser->endOfField()) {
    byte buf[512];
    size_t readLength = parser->read(buf, 512);

    if (Update.write(buf, readLength) != readLength) {
      Update.printError(Serial);
    }

    fileLength += readLength;

    Serial.printf("Upload and updated %u byte\n", fileLength);
  }

E infine, l’end

    if (Update.end(true)) { //true to set the size to the current progress
        Serial.printf("Update Success: %u\n", fileLength);
        // res->println("<p>Update Success: \nRebooting...\n</p>");
        res->println(successResponse);
    }
    else {
      Update.printError(Serial);
      res->println(Update.getError());
    }

Con un certificato autofirmato senza una vera autorità di certificazione, quando provi ad aprire il browser ti invia un messaggio per informarti del potenziale rischio, ma la connessione sarà comunque criptata.

self signed certificate on Web Arduino OTA browser message
self-signed certificate on Web Arduino OTA browser message

Grazie

  1. ESP32: piedinatura, specifiche e configurazione dell’Arduino IDE
  2. ESP32: fileSystem integrato SPIFFS
  3. ESP32: gestire più seriali e logging per il debug
  4. ESP32 risparmio energetico pratico
    1. ESP32 risparmio energetico pratico: gestire WiFi e CPU
    2. ESP32 risparmio energetico pratico: modem e light sleep
    3. ESP32 risparmio energetico pratico: deep sleep e ibernazione
    4. ESP32 risparmio energetico pratico: preservare dati al riavvio, sveglia a tempo e tramite tocco
    5. ESP32 risparmio energetico pratico: sveglia esterna e da ULP
    6. ESP32 risparmio energetico pratico: sveglia da UART e GPIO
  5. ESP32: filesystem integrato LittleFS
  6. ESP32: filesystem integrato FFat (Fat/exFAT)
  7. ESP32-wroom-32
    1. ESP32-wroom-32: flash, piedinatura, specifiche e configurazione dell’Arduino IDE
  8. ESP32-CAM
    1. ESP32-CAM: piedinatura, specifiche e configurazione dell’Arduino IDE
    2. ESP32-CAM: upgrade CamerWebServer con gestione della luce flash
  9. ESP32: ethernet w5500 con chiamate standard (HTTP) e SSL (HTTPS)
  10. ESP32: ethernet enc28j60 con chiamate standard (HTTP) e SSL (HTTPS)
  11. Come usare la scheda SD con l’esp32
  12. esp32 e esp8266: file system FAT su memoria SPI flash esterna
  13. Gestione aggiornamenti firmware e OTA
    1. Gestione del firmware
      1. ESP32: flash del firmware binario compilato (.bin)
      2. ESP32: flash del firmware e filesystem (.bin) con strumenti grafici
    2. Aggiornamento OTA con Arduino IDE
      1. Aggiornamenti OTA su ESP32 con Arduino IDE: filesystem, firmware e password
    3. Aggiornamento OTA con browser web
      1. Aggiornamenti OTA su ESP32 tramite browser web: firmware, filesystem e autenticazione
      2. Aggiornamenti OTA su ESP32 tramite browser web: caricamento in HTTPS (SSL/TLS) con certificato autofirmato
      3. Aggiornamenti OTA su ESP32 tramite browser web: interfaccia web personalizzata
    4. Aggiornamenti automatici OTA da un server HTTP
      1. Aggiornamento automatico Firmware OTA dell’ESP32 dal server
      2. Aggiornamento automatico Firmware OTA dell’ESP32 dal server con controllo della versione
      3. Aggiornamento automatico Firmware OTA dell’ESP32 in HTTPS (SSL/TLS) con certificato autofirmato affidabile
    5. Aggiornamento del firmware non standard
      1. Aggiornamento firmware e filesystem ESP32 dalla scheda SD
      2. Aggiornamento firmware e filesystem ESP32 con client FTP
  14. Integrare LAN8720 con ESP32 per la connettività Ethernet con plain (HTTP) e SSL (HTTPS)
  15. Collegare l’EByte E70 (CC1310) ai dispositivi ESP32 c3/s3 ed un semplice sketch di esempio
  16. ESP32-C3: piedinatura, specifiche e configurazione dell’IDE Arduino
  17. i2c esp32: gestione rete a 5v, 3.3v e interfaccia aggiuntiva
  18. […]

Spread the love

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *