Wennekes' template
for the ESP8266

This is a template script for the esp8266.
What are the benefits?

  • Wifi connect by wps.
  • Hostname & port adjustable by user.
  • Configuration stored in spiffs memory even after power disconnect.
  • Secured webaccess on browser-cookie level.
  • Example of time display on main webpage in svg format.
  • User can update esp8266 with bin file thru webpage.

First time use.
Connect your esp8266 open your arduino-ide program. Make sure you choose the right board and com port. Open your serial monitor output and set it to 9600 baud. Open the template sketch which you can download from the link on this page. For the first time as the output shows, you will be asked to press the wps button of your router. If everything goes well, the script continues and gives you a ip-adress and/or hostname and port number. Rightclick to see full picture In the meantime the template script stores your wifi credentials in spiffs memory file called wifi.txt which will remain even after power disconnection. Open your browser with http://hostname.port and you will be asked for login credentials. For the first time this will be admin and esp8266 as password. The template script will store now a browser-cookie. This means that if you are using a public computer you must not forget to log out! You are able to change your password and username in the http://hostname/config page. Very important to instruct users to do that.
After logging in the browser-cookie is set to see all pages until you log out. You will be able too see the time on the main page. Rightclick to see full picture On the page you will find a link called settings. You can change the username and password and network settings like hostname and port number. Hostname and portnumber will only applied if the esp8266 restarts. After first time changes in the config-page a file config.txt will be written in the spiffs memory which will be remail even after power disconnecting. I put a function in the script called factorysettings() which will be activated when a button is pressed during the boot process of the esp8266. During this function the wifi.txt en config.txt files will be deleted. Which means that all configuration and wifi settings are lost.
Rightclick to see full picture In the main page you will also the version number. For better administration keep in mind that when you name the sketch that you put the text -version and a version number behind it (ex. dht22-sensor-version1.01).
The version number is also a link to http://hostname/update from which you can update the esp8266 with dismounting the device/esp8266 and without connecting a pc. This is the situation for commercial use when users can download a firmware upgrade form your website. You make this bin file from your arduino-ide.



template-version0.48.ino

// *****************************************************************
// * Wennekes' Template *
// * for ESP8266 *
// * *
// * # Wifi connected once by wps. *
// * # Hostname & port adjustable *
// * # All configurations save on spiffs. *
// * # Secured web acces based on cookie-level. *
// * # Example of svg webpage showing current time . *
// * # Update esp8266 by upload bin file without *
// * dismounting esp8266 just thru webpage. *
// * *
// * This script is free of use *
// * if you find this script useful *
// * consider to buy me a cup of coffee *
// * see http://www.wennekes.info *
// * or like my video on *
// * https://www.youtube.com/c/ReneWennekes *
// *****************************************************************


#include <Wire.h>
#include "TimeLib.h"
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <FS.h>

uint8_t setbuttonPin = 2; // D4 of ESP8266 (Button)


// Determine version for administration, display it on a webpage and/or output device during boot.
// Use always this format: <your projectname>version<version>
// Increase version each time you update the sketch
String strFilepath =__FILE__;
String strVersion = strFilepath.substring(strFilepath.lastIndexOf("version")+7, strFilepath.lastIndexOf(".ino"));

// ********** wifi ************
String strSSID;
String strPASS;

// ********** webserver ************
String strChipID = String(ESP.getChipId(), HEX); //Unique number of each esp8266 device
String strHostname = "esp8266-" + strChipID; //default
uint16_t port = 80; //default
String strPort = String(port);
// CSS style (themes) example
//String strDefaulttheme = "";
String strDefaulttheme = "<style>body {background: #333; color: #EEE; margin: 20px; font-family: Arial;} a {color: #EEE;} label, input, button {vertical-align: middle; display: inline-block; width: 400px; height: 32px; margin: 2px; padding: 0px 20px; font-size: 16pt; color: #EEE; border: 0px; background: #555;} label {width: 200px;} button {background: transparent; border: 2px solid orange; width: 100px; height: 100px; border-radius: 50%; cursor: pointer;}</style>";
String strFavicon = "";
//String strFavicon = "<link rel=\"shortcut icon\" href=\"data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABMLAAATCwAAAAAAAAAAAAAxTTH/LVAt/y9RL/8uUS//LlAu/y9RL/8uUC7/L1Av/y9QL/8uTy7/L1Av/y5PLv8uTy7/L1Av/y5PLv8xUDH/ODU4/zUxNf82NDj/NjI1/zUyNf83NDf/NTI1/zYzNv83Mzf/NTE1/zczN/82Mjb/NjI2/zczN/81MTX/ODQ4/zU2Nf8zNTX/NjIu/zM3N/80NDP/NDU0/zQ1NP80NTT/NDU0/zQ1NP80NTT/NDU0/zM0M/81NjX/NDQ0/zU2Nf8zNjf/Niwm/yNWcf8EnO7/LzxD/zQwLv8zMzT/MzMz/zMzM/8zMjL/MzMz/zMzM/8kJCT/Kysr/zQ0NP80NDT/NjIv/y87Q/8Cp/n/FHyv/zUvLP8yMzT/MzMz/zMyMv80Nzj/Lj9I/zIzNP80NDP/Kysr/yAgIP8wMDD/NTU1/zkqJP8XdKL/BJ/u/zQwL/80MTD/NTY3/zU1Nf83Nzf/OTk5/zQ2N/83Nzf/NDQ0/zQ0NP8lJSb/Jico/zU2Nv81MzH/Bpvo/xptmv83KiP/MjY5/zo7O/85Ojr/Ojo7/z4/P/86Ozv/Ozs7/zQ1Nv80NDX/Li4t/yMcGP8zMjH/L0BI/wGk+/8lU2z/Nyki/zQxMP80MC7/NTIw/zQxMP80MjH/NTAu/zM0NP80MC3/NTAu/zExMv8bPlD/LjY6/y5ET/8Apf3/KEte/y5ASP8rRlT/LENP/y4+Rv8wOkD/MDpA/yxEUf81Lyv/K0ZU/y5AS/8vO0D/Aab4/yZUbP8yOj7/AqL3/yJZdv8tQUr/Il1+/yFfgf8uQEr/KUxe/yZUbf8jWnn/LUNP/yVWcv8wPET/KUpb/wCm/f8rSln/OC0o/wyNzv8Qg77/MjY4/ydRZ/8nUGb/MzQ1/ylMXf8mU2v/Kkpc/ytIWv8nT2X/MDpB/xptmP8FnOr/NTQz/zgtJ/8jV3H/ALD//ypIWf84Jx7/MzMy/zI0Nf80MTD/NS8s/zQxMP8zMzT/Nism/zA5Pv8Bqfz/G2qT/zgrJP80NTb/NS0p/xCFv/8DpvT/LEJP/zgpIf80MC7/MzMz/zM0NP80MTD/Nyoj/zE3PP8ImN7/CZfc/zMyM/81NDP/NDU2/zMxMP8zNDX/DYzM/wCt//8abJj/LkBJ/zMzMv8zMjH/LzxC/x5hhv8Cpfb/B5rj/y88RP80Ly3/NDY2/zQ0NP8yMzT/NDEw/zQwLf8baZP/AqH2/wCm/v8Em+3/BZrr/wGk+/8BpPz/FXSn/zI1Nv80Ly3/MjQ1/zQ0NP82Njb/NDQ0/zQ1Nv80NDT/OCsk/zM3Of8mVnD/HGuV/xtsmP8jWnf/MTxB/zgrJP81MzL/NDY3/zQ0NP81Njb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\" />";

String strCookie;

// ********** security ************
String strUser = "admin"; //default username
String strPass = "esp8266"; //default password

//Set to European (if other region disable or adjust settings in adjustDstEurope() function in case summer/wintertime)
uint16_t timeZone = 7200;

String strTime;

unsigned int localPort = 2390; // local port to listen for UDP packets

/* Don't hardwire the IP address or we won't get the benefits of the pool.
* Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;

//Webserver
ESP8266WebServer server(port);

//WiFiClient client
HTTPClient http;


void setup() {
Serial.begin(9600);

// initialize the pushbutton pins as an input:
pinMode(setbuttonPin, INPUT);

//Display firmware version
//Consider display version briefly on output device during startup
//and one or more webpages.
Serial.println("Firmware Version: " + strVersion);

//Display Chip ID
Serial.println("Chip ID: " + strChipID);
//Serial.println(ESP.getChipId());

//Initialize File System
if(SPIFFS.begin()){
Serial.println("SPIFFS Initialize....ok");
} else{
Serial.println("SPIFFS Initialization...failed");
}

//Display directory of filesystem
Dir dir = SPIFFS.openDir("");
while (dir.next()) {
Serial.print(dir.fileName());
File f = dir.openFile("r");
Serial.print("\t");
Serial.println(f.size());
}

//Press the button to erase config files
//if (digitalRead(setbuttonPin) == HIGH) {factory_reset();}


//Restore webserver configuration from config.txt
//------------------------------------------------------------------------
if (SPIFFS.exists("/config.txt")) {
File f = SPIFFS.open("/config.txt", "r");
strHostname = f.readStringUntil('\n');
strPort = f.readStringUntil('\n');
strUser = f.readStringUntil('\n');
strPass = f.readStringUntil('\n');
strHostname.trim();
strPort.trim();
strUser.trim();
strPass.trim();
Serial.println("Hostname=" + strHostname);
Serial.println("Port=" + strPort);
Serial.println("User=" + strUser);
Serial.println("Pass=" + strPass);
f.close();
Serial.println("Data read from config.txt.");
}


//Restore SSID & WPA2 password from wifi.txt
//------------------------------------------------------------------------
if (SPIFFS.exists("/wifi.txt")) {
File f = SPIFFS.open("/wifi.txt", "r");
strSSID = f.readStringUntil('\n');
strPASS = f.readStringUntil('\n');
strSSID.trim();
strPASS.trim();
Serial.println("SSID=" + strSSID);
Serial.println("PASS=" + strPASS);
f.close();
Serial.println("Data read from wifi.txt.");

// ********************** Wifi ***********************
//Convert String to char

char charSSID[strSSID.length()];
char charPASS[strPASS.length()];
strSSID.toCharArray(charSSID, strSSID.length()+1);
strPASS.toCharArray(charPASS, strPASS.length()+1);
WiFi.hostname(strHostname);
WiFi.begin(charSSID, charPASS);
WiFi.mode(WIFI_STA);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
//if (digitalRead(setbuttonPin) == HIGH) {factory_reset();}
}
Serial.println("");
Serial.println("Connecting to:");
Serial.println(strSSID);
Serial.println(strPASS);
Serial.println("WiFi connected");

} else {

//-----------------Retrieve credentials by wps----------------------------
//------------------------------------------------------------------------
Serial.println("wifi.txt not exist.");
Serial.println("Let's make a wps connection now.");
Serial.println("Press the WPS button on your router now ...");
if (startWPSPBC()) {
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("Connecting to:");
strSSID = WiFi.SSID();
strPASS = WiFi.psk();
Serial.println("SSID retrieved by wps="+strSSID);
Serial.println("PASS retrieved by wps="+strPASS);
Serial.println("WiFi connected");
//-----------------Store SSID & WPA2 password in wifi.txt----------------------
//-----------------------------------------------------------------------------
File f = SPIFFS.open("/wifi.txt", "w");
f.println(strSSID);
f.println(strPASS);
f.close();
Serial.println("Data written to wifi.txt.");

} else {

//WPS failed
Serial.println();
Serial.println("WPS failed ...");
}
}


server.on ( "/", showClock );
server.on ( "/config", showConfig );
server.on ( "/login", showLogin );

//********* webform firmware upload ************************
server.on("/update", HTTP_GET, [](){
Serial.print(strTime);
Serial.print(" /update\trequested by ");
Serial.print(server.client().remoteIP());
Serial.print("\t");
if (!is_authentified()){
Serial.println("not authentified, redirect to \login");
server.sendHeader("Location","/login");
server.sendHeader("Cache-Control","no-cache");
server.send(301);
return;
}
Serial.println("authentified");
server.sendHeader("Connection", "close");
String strHTML;
strHTML += "<!DOCTYPE HTML>\n<html>\n<head>\n";
strHTML += "<title>" + strHostname + "</title>\n";
strHTML += strDefaulttheme + "\n"; //Inline css
strHTML += strFavicon + "\n"; //Favicon
strHTML += "</head>\n";
strHTML += "<body>\n";
strHTML += "<form method='POST' action='/flash' enctype='multipart/form-data'>\n";
strHTML += "<center>\n";
strHTML += "<input type='file' name='update'><br />\n";
strHTML += "Current firmware: " + strVersion + "<br /><br />\n";
//strHTML += "<input type='submit' value='Update'>\n";
strHTML += "<button type='submit' name='Update'>Update</button><br /><br />\n";
strHTML += "</center>\n";
strHTML += "</form>\n";
strHTML += "<center>\n";
strHTML += "<a href=\"/\">Back to panel</a>\n";
strHTML += "</center>\n";
strHTML += "</body>\n</html>";
server.send(200, "text/html", strHTML);
});

//********* upload the flash file ***************************
server.on("/flash", HTTP_POST, [](){
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
ESP.restart();
},[](){
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
Serial.setDebugOutput(true);
WiFiUDP::stopAll();
Serial.printf("Update: %s\n", upload.filename.c_str());
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if(!Update.begin(maxSketchSpace)){//start with max available size
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_WRITE){
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_END){
if(Update.end(true)){ //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); //
} else {
Update.printError(Serial);
}
Serial.setDebugOutput(false);
}
//******************************************************************************************
yield();
});

server.on ( "/inline", []() {
server.send ( 200, "text/plain", "this works as well" );
} );

//server.onNotFound ( showNotFound );

//!!!!!!!These lines are important to work with cookies !!!!!!!!!!
//here the list of headers to be recorded
const char * headerkeys[] = {"User-Agent","Cookie"} ;
size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*);
//ask server to track these headers
server.collectHeaders(headerkeys, headerkeyssize );


char host[strHostname.length()];
strHostname.toCharArray(host, strHostname.length()+1);
port = strPort.toInt();

// Start the server
Serial.println("Starting webserver");
MDNS.begin(host);
server.begin();
MDNS.addService("http", "tcp", port);
Serial.print("http://");
Serial.print(WiFi.localIP()); //Consider to display ip on output device.
Serial.print(":");
Serial.println(port); //Consider to display ip on output device.

Serial.println("Starting UDP");
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(udp.localPort());

} //EOF setup


void showClock() {
Serial.print(strTime);
Serial.print(" /\t\trequested by ");
Serial.print(server.client().remoteIP());
Serial.print("\t");
if (!is_authentified()){
Serial.println("not authentified, redirect to \login");
server.sendHeader("Location","/login");
server.sendHeader("Cache-Control","no-cache");
server.send(301);
return;
}
Serial.println("authentified");

String strHTML;
strHTML += "<!DOCTYPE HTML>\n<html>\n<head>\n";
strHTML += "<title>" + strHostname + "</title>\n";
strHTML += "</head>\n";
strHTML += "<body onload=\"JavaScript:setTimeout(\'window.location = window.location.pathname;',60000);\">\n";
strHTML += "<svg style=\"background: #333333; width: 100%; height: 100%; position:fixed; top:0; bottom:0; left:0; right:0; border: 5px red;\" viewBox=\"0 0 600 600\">\n";
strHTML += "<circle cx=\"300\" cy=\"300\" r=\"250\" fill=\"none\" stroke= \"orange\" stroke-width=\"30\" />\n";
strHTML += "<text x=\"300\" y=\"300\" text-anchor=\"middle\" dominant-baseline=\"middle\" fill=\"orange\" font-family=\"Arial\" font-size=\"150\" stroke-width=\"1px\">"+strTime.substring(0, 5)+"</text>\n";
strHTML += "<a href= \"login\"><text x=\"0\" y=\"550\" text-anchor=\"left\" fill= \"orange\" font-family=\"Arial\" font-size=\"12\" stroke-width=\"1px\">Logout</text></a>\n";
strHTML += "<a href= \"config\"><text x=\"600\" y=\"550\" text-anchor=\"end\" fill= \"orange\" font-family=\"Arial\" font-size=\"12\" stroke-width=\"1px\">Settings</text></a>\n";
strHTML += "<a href= \"update\"><text x=\"600\" y=\"570\" text-anchor=\"end\" fill= \"orange\" font-family=\"Arial\" font-size=\"12\" stroke-width=\"1px\">v"+strVersion+"</text></a>\n";
strHTML += "</svg>\n";
strHTML += "</body>\n</html>";
//strHTML += "</html>";
server.send ( 200, "text/html", strHTML );
}

void showConfig() {
Serial.print(strTime);
Serial.print(" /config\trequested by ");
Serial.print(server.client().remoteIP());
Serial.print("\t");
if (!is_authentified()){
Serial.println("not authentified, redirect to \login");
server.sendHeader("Location","/login");
server.sendHeader("Cache-Control","no-cache");
server.send(301);
return;
}
Serial.println("authentified");

if (server.hasArg("newhostname") or server.hasArg("newport") or server.hasArg("newusername")){
strHostname = server.arg("newhostname");
strPort = server.arg("newport");
strUser = server.arg("newusername");
if (server.arg("newpassword") != "") {
strPass = server.arg("newpassword"); //if empty keep old password !!!
} else {
Serial.println("Password not changed.");
}
Serial.println("New hostname="+strHostname);
Serial.println("New port="+strPort);
Serial.println("New username="+strUser);
Serial.println("New password="+strPass);
//Store configuration in config.txt
//------------------------------------------------------------------------
File f = SPIFFS.open("/config.txt", "w");
f.println(strHostname);
f.println(strPort);
f.println(strUser);
f.println(strPass);
f.close();
Serial.println("Data written to config.txt.");
}
String strHTML;
strHTML += "<!DOCTYPE HTML>\n<html>\n<head>\n";
//strHTML += "<html>\n";
//strHTML += "<head>\n";
strHTML += "<title>" + strHostname + "</title>\n";
strHTML += strDefaulttheme + "\n"; //Inline css
strHTML += "</head>\n";
strHTML += "<body>\n";
strHTML += "<form action='/config' method='POST'>\n";
strHTML += "<center>\n";
strHTML += "<label>Hostname</label><input type='text' name='newhostname' value=\"" + strHostname + "\" /><br />\n";
strHTML += "<label>Port</label><input type='text' name='newport' value=\"" + strPort + "\" /><br />\n";
strHTML += "<label>Username</label><input type='text' name='newusername' value=\"" + strUser + "\" /><br />\n";
strHTML += "<label>Password</label><input type='password' name='newpassword' value=\"\" /><br />\n";
strHTML += "<span style=\"font-size: 10pt;\">*** The Hostname & Port only applied after restart. ***</span><br /><br />\n";
strHTML += "<button type='submit' name='submit'>Modify</button><br /><br />\n";
strHTML += "</center>\n";
strHTML += "</form>\n";
strHTML += "<center>\n";
strHTML += "<a href=\"/\">Back to panel</a>\n";
strHTML += "</center>\n";
strHTML += "</body>\n</html>";
//strHTML += "</html>";
server.send ( 200, "text/html", strHTML );
}

void showLogin() {
Serial.print(strTime);
Serial.print(" /login\trequested by ");
Serial.print(server.client().remoteIP());
Serial.print("\t");
String strHTML;
strHTML += "<!DOCTYPE HTML>\n<html>\n<head>\n";
strHTML += "<title>" + strHostname + "</title>\n";
strHTML += strDefaulttheme + "\n"; //Inline css
strHTML += "</head>\n";
strHTML += "<body>\n";
//**** Login ****
if (server.hasArg("login")){
if (server.arg("user") == strUser && server.arg("pass") == strPass){
server.sendHeader("Location","/login");
server.sendHeader("Cache-Control","no-cache");
server.sendHeader("Set-Cookie","authlevel=1"); //Set browsercookie to 1
server.send(301);
Serial.print("Login succeeded ");
strHTML += "<center>\n";
strHTML += "Username and Password are correct<br /><br />\n";
strHTML += "</center>\n";
} else {
Serial.print("Login failed, try again ");
strHTML += "<center>\n";
strHTML += "Wrong username or password<br /><br />\n";
strHTML += "</center>\n";
}
}
//**** Logout ****
if (server.hasArg("logout")){
server.sendHeader("Location","/login");
server.sendHeader("Cache-Control","no-cache");
server.sendHeader("Set-Cookie","authlevel=0"); //Set browsercookie to 0
server.send(301);
Serial.print("logged out succesfully ");
}
if (!is_authentified()){
Serial.println("not authentified");
//********** login form & button ************
strHTML += "<form action='/login' method='POST'>\n";
strHTML += "<center>\n";
strHTML += "<input type='text' name='user' placeholder='User name' /><br />\n";
strHTML += "<input type='password' name='pass' placeholder='Password' /><br /><br />\n";
strHTML += "<button type='submit' name='login'>login</button>\n";
strHTML += "</center>\n";
strHTML += "</form>\n";
} else {
Serial.println("authentified");
//*********** logout button *************
strHTML += "<form action='/login' method='POST'>\n";
strHTML += "<center>\n";
strHTML += "You are succesfully logged in<br /><br />\n";
strHTML += "<a href=\"/\">Main panel</a><br /><br />\n";
strHTML += "<a href=\"config\">Settings</a><br /><br />\n";
strHTML += "<button type='submit' name='logout'>logout</button>\n";
strHTML += "</center>\n";
strHTML += "</form>\n";
}

strHTML += "</body>\n</html>";
server.send ( 200, "text/html", strHTML );
}


void loop() {
//sync once a hour on xx:00:25
if (minute() == 0 && second() == 25) {
long t = ntpSync();
if (adjustDstEurope(t)) {timeZone = 7200;} else {timeZone = 3600;}
if (t) {setTime(t+timeZone);}
//Serial.println(t);
Serial.println("Synced now.");
}

unsigned long Hour = hour();
unsigned long Minute = minute();
unsigned long Second = second();
unsigned long Year = year();
unsigned long Month = month();
unsigned long Day = day();

int hour1 = (Hour%10);
int hour10 = (Hour/10);
int minute1 = (Minute%10);
int minute10 = (Minute/10);
int second1 = (Second%10);
int second10 = (Second/10);
int year1 = (Year%10);
int year10 = ((Year/10)%10);
int year100 = ((Year/100)%10);
int year1000 = (Year/1000);
int month1 = (Month%10);
int month10 = (Month/10);
int day1 = (Day%10);
int day10 = (Day/10);

strTime = String(hour10, DEC)+String(hour1, DEC)+":"+String(minute10, DEC)+String(minute1, DEC)+":"+String(second10, DEC)+String(second1, DEC); //for serial output log


//Webserver
//-----------------------------------------------------------------
// Check if a client has connected
server.handleClient();


delay(100);
} //EOF loop


int ntpSync()
{
//get a random server from the pool
WiFi.hostByName(ntpServerName, timeServerIP);

sendNTPpacket(timeServerIP); // send an NTP packet to a time server
// wait to see if a reply is available
delay(1000);

int cb = udp.parsePacket();
if (cb) {
//Serial.print("packet received, length=");
//Serial.println(cb);
// We've received a packet, read the data from it
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
//Serial.print("Seconds since Jan 1 1900 = " );
//Serial.println(secsSince1900);

// now convert NTP time into everyday time:
//Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
//Serial.println(epoch);
return epoch;
} else {
//Serial.println("no packet yet");
return false;
}
}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address)
{
//Serial.println("sending NTP packet...");
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
}


long adjustDstEurope(long epoch)
{
// last sunday of march
int beginDSTDate= (31 - (5* year(epoch) /4 + 4) % 7);
int beginDSTMonth=3;
//last sunday of october
int endDSTDate= (31 - (5 * year(epoch) /4 + 1) % 7);
int endDSTMonth=10;
// DST is valid as:
if (((month(epoch) > beginDSTMonth) && (month(epoch) < endDSTMonth))
|| ((month(epoch) == beginDSTMonth) && (day(epoch) >= beginDSTDate))
|| ((month(epoch) == endDSTMonth) && (day(epoch) < endDSTDate)))
return true; // DST europe = GMT +2
else return false; // nonDST europe = GMT +1
}


bool startWPSPBC() {
// from https://gist.github.com/copa2/fcc718c6549721c210d614a325271389
// wpstest.ino
//Serial.println("WPS config start");
WiFi.mode(WIFI_STA);
bool wpsSuccess = WiFi.beginWPSConfig();
String newSSID = WiFi.SSID();
String newPASS = WiFi.psk();
if (wpsSuccess) {
if(newSSID.length() > 0) {return wpsSuccess;} else {wpsSuccess = false;}
}
return wpsSuccess;
} // EOF startWPSPBC()


String httprequest(String urlrequest) {
String payload = "";
http.begin(urlrequest); //Specify request destination
int httpCode = http.GET(); //Send the request
//Serial.println(httpCode);

if (httpCode > 0) { //Check the returning code
payload = http.getString(); //Get the request response payload
//Serial.println(payload); //Print the response payload
}
http.end(); //Close connection
return payload;
} // EOF httprequest()


void factory_reset() {
Serial.println("Factory reset start in 5 seconds ...");
for (int i = 0; i < 5; i++) {
Serial.print("*");
//display output device
delay(1000);
}
Serial.println();
//***** Actually clearing *****
if (SPIFFS.exists("/config.txt")) {SPIFFS.remove("/config.txt");}
if (SPIFFS.exists("/wifi.txt")) {SPIFFS.remove("/wifi.txt");}

while (digitalRead(setbuttonPin) == HIGH) {
//Do nothing until button is released.
}
delay(5000);
} // EOF factory_reset()


bool is_authentified() {
if (server.hasHeader("Cookie")){
//Serial.print("Found cookie: ");
strCookie = server.header("Cookie");
//Serial.println(strCookie);
if (strCookie.indexOf("authlevel=1") != -1) {return true;} else {return false;}
}
} // EOF is_authentified()

Example of the serial output

Firmware Version: 0.46
Chip ID: 877e71
SPIFFS Initialize....ok
/wifi.txt 30
/config.txt 27
Hostname=clock
Port=80
User=admin
Pass=esp8266
Data read from config.txt.
SSID=XXXXXXXXXX
PASS=YYYYYYYYYY
Data read from wifi.txt.
.
Connecting to:
XXXXXXXXXX
YYYYYYYYYY
WiFi connected
Starting webserver
http://192.168.0.157:80
Starting UDP
Local port: 2390
Synced now.
08:20:40 /config requested by 192.168.0.117 authentified
08:20:43 / requested by 192.168.0.117 authentified



Download template-version0.49.zip and extract the zip in your sketches folder.

Buy me a cup of coffee

If you like this project, keep in mind that a huge amount of coffee was consumed in the process of making this script. Please donate a cup of coffee if you want me to keep going.