2018-11-17 16:59:33 +01:00
# include <ESP8266WebServer.h> //Local WebServer used to serve the configuration portal
# include <WiFiManager.h> //https://github.com/tzapu/WiFiManager WiFi Configuration Magic
# include <ESP8266WiFi.h>
# include <DNSServer.h>
# include <ESP8266WiFiMulti.h>
# include <ESP8266HTTPClient.h>
# include <ESP8266httpUpdate.h>
# include <time.h>
# include <CertStoreBearSSL.h>
# include <FS.h>
2018-11-17 21:59:00 +01:00
// TODO: figure out how these freakin summertime works
// best would be some kind of automatic change
2018-11-17 16:59:33 +01:00
# define DEVICE_NAME "OTA TEST DEVICE"
# define TZ 1 // (utc+) TZ in hours
# define DST_MN 0 // use 60mn for summer time in some countries
# define TZ_MN ((TZ)*60)
# define TZ_SEC ((TZ)*3600)
# define DST_SEC ((DST_MN)*60)
ESP8266WiFiMulti WiFiMulti ;
BearSSL : : CertStore certStore ;
WiFiManager wifiManager ;
String config_password ;
2018-11-17 21:59:00 +01:00
// Copy&Pasted code from the esp core example based on BeadSSL
2018-11-17 16:59:33 +01:00
class SPIFFSCertStoreFile : public BearSSL : : CertStoreFile {
public :
SPIFFSCertStoreFile ( const char * name ) {
_name = name ;
} ;
virtual ~ SPIFFSCertStoreFile ( ) override { } ;
// The main API
virtual bool open ( bool write = false ) override {
_file = SPIFFS . open ( _name , write ? " w " : " r " ) ;
return _file ;
}
virtual bool seek ( size_t absolute_pos ) override {
return _file . seek ( absolute_pos , SeekSet ) ;
}
virtual ssize_t read ( void * dest , size_t bytes ) override {
return _file . readBytes ( ( char * ) dest , bytes ) ;
}
virtual ssize_t write ( void * dest , size_t bytes ) override {
return _file . write ( ( uint8_t * ) dest , bytes ) ;
}
virtual void close ( ) override {
_file . close ( ) ;
}
private :
File _file ;
const char * _name ;
} ;
SPIFFSCertStoreFile certs_idx ( " /certs.idx " ) ; // auto generated. No upload required
SPIFFSCertStoreFile certs_ar ( " /certs.ar " ) ; // use fetch_le_root_crt.py and then upload
// Set time via NTP, as required for x.509 validation
void setClock ( ) {
configTime ( TZ_SEC , DST_SEC , " pool.ntp.org " , " time.nist.gov " ) ;
Serial . print ( F ( " Waiting for NTP time sync: " ) ) ;
time_t now = time ( nullptr ) ;
while ( now < 8 * 3600 * 2 ) {
yield ( ) ;
delay ( 500 ) ;
Serial . print ( F ( " . " ) ) ;
now = time ( nullptr ) ;
}
Serial . println ( F ( " " ) ) ;
struct tm timeinfo ;
gmtime_r ( & now , & timeinfo ) ;
Serial . print ( F ( " Current time: " ) ) ;
Serial . print ( asctime ( & timeinfo ) ) ;
}
void setup ( ) {
Serial . begin ( 115200 ) ;
// USE_SERIAL.setDebugOutput(true);
Serial . println ( ) ;
Serial . println ( ) ;
Serial . println ( ) ;
for ( uint8_t t = 4 ; t > 0 ; t - - ) {
Serial . printf ( " [SETUP] WAIT %d... \n " , t ) ;
Serial . flush ( ) ;
delay ( 1000 ) ;
}
WiFi . mode ( WIFI_STA ) ;
SPIFFS . begin ( ) ;
int numCerts = certStore . initCertStore ( & certs_idx , & certs_ar ) ;
Serial . print ( F ( " Number of CA certs read: " ) ) ; Serial . println ( numCerts ) ;
if ( numCerts = = 0 ) {
2018-11-17 21:59:00 +01:00
Serial . println ( F ( " No certs found. HTTPS requests will most likely fail. " ) ) ;
2018-11-17 16:59:33 +01:00
}
if ( SPIFFS . exists ( " /config_password.txt " ) ) {
File f = SPIFFS . open ( " /config_password.txt " , " r " ) ;
if ( f & & f . size ( ) ) {
while ( f . available ( ) ) {
config_password + = char ( f . read ( ) ) ;
}
f . close ( ) ;
}
wifiManager . autoConnect ( DEVICE_NAME , config_password . c_str ( ) ) ;
} else {
2018-11-17 21:59:00 +01:00
Serial . println ( F ( " Failed to find AP password file in SPIFFS. Refusing to set up the wifi manager in an usecure way. Upload config_password.txt with the configuration password included " ) ) ;
2018-11-17 16:59:33 +01:00
}
}
void loop ( ) {
2018-11-17 21:59:00 +01:00
checkUpdate ( ) ; // Checks for updates and applies it if available
2018-11-17 16:59:33 +01:00
delay ( 10000 ) ;
}
void checkUpdate ( ) {
// wait for WiFi connection
if ( ( WiFiMulti . run ( ) = = WL_CONNECTED ) ) {
setClock ( ) ;
BearSSL : : WiFiClientSecure client ;
bool mfln = client . probeMaxFragmentLength ( " companioncu.be " , 443 , 1024 ) ; // server must be the same as in ESPhttpUpdate.update()
Serial . printf ( " MFLN supported: %s \n " , mfln ? " yes " : " no " ) ;
if ( mfln ) {
client . setBufferSizes ( 1024 , 1024 ) ;
}
client . setCertStore ( & certStore ) ;
// The line below is optional. It can be used to blink the LED on the board during flashing
// The LED will be on during download of one buffer of data from the network. The LED will
// be off during writing that buffer to flash
// On a good connection the LED should flash regularly. On a bad connection the LED will be
// on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
// value is used to put the LED on. If the LED is on with HIGH, that value should be passed
ESPhttpUpdate . setLedPin ( LED_BUILTIN , LOW ) ;
t_httpUpdate_return ret = ESPhttpUpdate . update ( client , " https://iotupdates.companioncu.be/update " ) ;
switch ( ret ) {
case HTTP_UPDATE_FAILED :
Serial . printf ( " HTTP_UPDATE_FAILED Error (%d): %s \n " , ESPhttpUpdate . getLastError ( ) , ESPhttpUpdate . getLastErrorString ( ) . c_str ( ) ) ;
break ;
case HTTP_UPDATE_NO_UPDATES :
Serial . println ( " HTTP_UPDATE_NO_UPDATES " ) ;
break ;
case HTTP_UPDATE_OK :
Serial . println ( " HTTP_UPDATE_OK " ) ;
break ;
}
}
}