WeMos D1 webserver with protected WiFi login and OTA

**************************************************************************
If you have the same trouble as I had, that the OTA port (from the ArduinoOTA library) will not show up in the programming ports on the ArduinoIDE I can advise to solve this trouble to disable/re-enable network interface of your computer. When i did this (under Ubuntu) the OTA port shows up again. A bug in the ArduinoIDE programm? Maybe
**************************************************************************

In this article I describe a web server that logs in to the home WiFi network. The WeMos webserver I decribe is programmable Over The Air (OTA) and has a (limited) security of the login to the WiFi network. This entails security problems, since the data transport via the WiFi network is not encrypted by default. This means that the SSID and Password of the WiFi network  in principle can be read.

**************************************************************************
*                For  Arduino WeMos D1 R1 Board layout and GPIO  Look here
*************************** ***********************************************
Arduino-IDE settings for (LOLIN)WeMos D1R1

* – Flash size : 4Mb (FS:2Mb OTA ca 1019Kb)
* – Debug port : Disabled
* – Debug level : None
* – IwIP variant : v2 Lower Memory
* – VTables : Flash
* – Reset Method :
* – Upload Speed : 115200
* – CPU Frequency : 80 MHz
* – BuiltIn LED : GPIO5
* – Erase Flash : Only Sketch

The WeMos has a 4Mb EEPROM available for the sketch and a (much) smaller DRAM for data. We will come back to the 4 Mb EEPROM when discussing OTA functionality.

*************************** Security and OTA *******************************
There is no imposed security on OTA process from being hacked. Once update is complete, module restarts and new code is executed. Therefore protect your uploads with password, and selecting certain OTA port:
– void setPort(uint16_t port);
– void setHostname(const char* hostname);
– void setPassword(const char* password);

**************************** Safety and OTA ********************************
OTA process restarted module and a new sketch is executed. If the module is placed in a critical proces no answer will be return if it’s ok and works safe. The following functions are provided with ArduinoOTA library and intended to handle functionality of your application during specific stages of OTA or on an OTA error:
* – void onStart(OTA_CALLBACK(fn));
* – void onEnd(OTA_CALLBACK(fn));
* – void onProgress(OTA_CALLBACK_PROGRESS(fn));
* – void onError(OTA_CALLBACK_ERROR (fn));
In the sketch given below this is not built in.

************************* Basic Requirements *******************************
It should be noted that the EEPROM memory size must be at least 2x larger than the size of the sketch in order for OTA to work smoothly.

******************* Basic Steps – Using Arduino IDE *************************
After prepare IDE for OTA and the fist upload have been done with serial connection, you can start over again by using the port ESP8266— ect. The USB port then is out of use!!
Start over again will take place by pushing-” Ctrl+U “-
Unfortunately, this upload information you will not find anywhere on the internet and certainly not where there are OTA sketches.

**************************************************************************
For further info: http://arduino.esp8266.com/Arduino/versions/2.0.0/doc/ota_updates/ota_updates.html

************************** WiFi protection *******************************
The communication between WiFi board and the WiFi hotspot is not encrypt. That means it is readeble. For protection of our Passfrase we need to take some extra. Here it is suggested to place the Passfrase and the SIDD in a separate file, for example secrets.h, and put that in the same folder or elswhere or record it in the ArduinoIDE. Even then it is possible to read the communication but it will cost much more effert to do so.
So there are two ways to get the secretswifi.h file included in the main sketch:
– by placing it in the same folder as the sketch and
– by including it in the ArduinoIDE library.

In the same folder
The file secretswifi.h (or whatever you name it) be in the same folder as the sketch.
The function you need, to connect it with the sketch are:
– #import “secretswifi.h”
or
– #include “secretswifi.h”

In the first example the file secretswifi.h wil be part of the sketch. Because the file is not sent when the sketch is uploaded, the SSID and the Passphrase are not visible. Detecting this data is possible but is quite complicated to pick out of the blue.
In the second example the file will be included in the sketch and is part of the program.
I prefere the second solution for WiFi inlog protection.

As library file
You can also place the file in the ArduinoIDE library folder. But then you will have to find out in which of the three possible library places the file should be placed.
The ArduinoIDE has three different places where it stores the library files. Take a look under the include library tab from the IDE. You will find:
– Arduino libraries,
– Contributed libraries,
– Recomended libraries.
The file secretswifi.h must be included in the “Contributed Libraries” folder otherwise it will not be readeble and included in the sketch. The function you need to connect it with the sketch are:
#include <secretswifi.h>

Creating the secretswifi.h file
The file secretswifi.h is a file that can be created with the ArduinoIDE. Start with the main program and click in the top bar of the IDE on the arrowhead that points downwards. A new screen will open in which the secretswifi.h file can be created. This is the easiest method because the file is immediately saved in the folder of the sketch.

The second method is to use a word processor capable of saving plain text. That is, text that does not contain punctuation. Not even the infamous CR and LF!!

The secretswifi.h file
/**************************** PA3BYB *************************************
*                                     Use -secretsfile.h- file for WiFi login
**************************************************************************
* Date : 2022 01 05 Filename: secretswifi.h
* contributed library - home/pa3byb/snap/arduino/current/arduino/libraries
*************************************************************************/
#ifndef STASSID
#define STASSID "Your SIDD"
#define STAPSK "Your Passphrase"
#endif

#ifndef APSSID
#define APSSID ""
#define APPSK ""
#endif

const char *ssidsta            = STASSID;
const char *passwordsta  = STAPSK;

const char *ssidap             = STASSID;
const char *passwordap   = STAPSK;
=======================================================

This is a “hard way” to configure your local WiFi network SSID and passphrase into the source code and the uploaded sketch. This can be done for aswell:
– STAtions or Client – STASSID / STAPSK
– Acces Point              – APSSID   / APPSK
This library contains the SSID and Password and put them in *ssidsta and *passwordsta or in *ssidap and *passwordap
These constants can be used in the sketch.

https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WebServer/examples/WebServer/secrets.h
**************************************************************************

================== The WeMoS D1 WebServer Sketch =====================

//-------------------------------------- includes libraries ----------------------------------------------
#include <FS.h>                                      // File System wrapper
#include <LittleFS.h>                            // FileSystem for onboard flash (SPIFFS - also)
#include <ArduinoOTA.h>                   // Over The Air re-programming
#include <ESP8266mDNS.h>             //
#include <ESP8266WebServer.h>
#include <secretswifi.h>                     //Secret login for your local home network

//----------------------------------- mDNS and OTA Constants ---------------------------------------

// TRACE output simplified, can be deactivate here
#define TRACE(...) Serial.printf(__VA_ARGS__)

// Hostname. The setup function adds the ChipID at the end.
#define HOSTNAME "ESP8266-OTA-WeMos-"

const int ledPin = LED_BUILTIN;            // Use built-in led WeMos
int ledState = LOW;
int I = 0;                                                          // Used for-next counting in for-loop

ESP8266WebServer server(80);              // Webserver start on standard port 80

//------------------------------------- Arduino Setup function -----------------------------------------
void setup() {
   Serial.begin(115200);
   delay(500);                                                                   // Wait a moment for serial monitor

   pinMode(ledPin, OUTPUT);                                    // ledPin is output

   TRACE("Starting webserver example....\n");

   Serial.println("\r\n");                                               // Get Chip ID
   Serial.print(" WeMos D1 Chip ID: 0x");
   Serial.println(ESP.getChipId(), HEX);

   String hostname(HOSTNAME);                           // Set Hostname.
   hostname += String(ESP.getChipId(), HEX);
   WiFi.hostname(hostname);
   Serial.println(" Hostname: " + hostname);       // Print hostname.
   //Serial.println(WiFi.hostname());

   if (!LittleFS.begin()) {                                           // Initialize file system LittleFS.
      Serial.println(" Failed to mount file system");
      return;
   }

   StartWifiConnect();                                             // Subroutine for starting WiFi

//--------------------------------------- Start OTA server -----------------------------------------------
//--- .c_str()-- convert the content of a string in a "null"-terminated string
//--- The string pointer will replaced to the begin of the string
//-----------------------------------------------------------------------------------------------------------
   ArduinoOTA.setHostname((const char *)hostname.c_str());
   Serial.print(" Start OTA on WeMos D1 with Hostname : ");
   Serial.println(hostname.c_str());
   ArduinoOTA.begin();

   if (MDNS.begin("esp8266")) {
       Serial.println("****** MDNS responder started *******");
   }
   server.on("/", handleRoot);                             // Jump to subroutine handleRoot
   server.on("/inline", [](){
   server.send(200, "text/plain", "this works as well");
   });

   server.onNotFound(handleNotFound); // Jump to subroutine

   server.begin();
       Serial.println("******* HTTP server started ********");
}

//----------------------------- Arduino loop function ----------------------------------
void loop() {
   // Handle OTA server.
   ArduinoOTA.handle();

   server.handleClient();

   for(int I=0; I<5; I++){
      digitalWrite(ledPin, !digitalRead(ledPin)); //-- Built In LED blinkt
      delay(1000);
   }
   I = 0;
}

//******************************* Sub Routines ********************************

//------------------------------------ Start WiFi Connect -------------------------------------
void StartWifiConnect(){                                  //... Connect as STAstion of Client
   if (WiFi.getMode() != WIFI_STA) {           //... check mode if not STA
      WiFi.mode(WIFI_STA); //... Make it STA
     delay(10);
   }
   WiFi.begin(ssidsta, passwordsta);             //... Try to connect to WiFi station.

   Serial.print(" Connect with SSID: ");        //... Print connected SSID
   Serial.println(WiFi.SSID());
   Serial.print(" Wait for WiFi connection.");

            // ... Give WeMos D1 some seconds to connect as STAtion/Client WiFi.
   unsigned long startTime = millis();
   while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) {
   Serial.write('.');
   delay(500);
   }

   // Check connection and start AP if STA don't work
   if (WiFi.status() == WL_CONNECTED) {
       Serial.print("\n IP address: ");             //... print IP Address
      Serial.println(WiFi.localIP());
   } else {
      Serial.println("Can not connect to WiFi station. Go into Acces Point mode.");

      WiFi.mode(WIFI_AP); //...Go into Acces Point mode.
      delay(10);

      WiFi.softAP(ssidap, passwordap);

      Serial.print("IP address: ");
      Serial.println(WiFi.softAPIP());
   }
}

//------------------------------- Handle File ------------------------------------------
void handleRoot(){
   server.send(200, "text/plain", "Hello from WeMos D1 ESP8266");
}

//------------------------- Handle File not Found --------------------------------------
void handleNotFound(){
   String message = "****** File Not Foundnn ********";
   message += "URI: ";
   message += server.uri();
   message += "nMethod: ";
   message += (server.method() == HTTP_GET)?"GET":"POST";
   message += "nArguments: ";
   message += server.args();
   message += "n";
   for (uint8_t i=0; i<server.args(); i++){
      message += " " + server.argName(i) + ": " + server.arg(i) + "n";
   }
   server.send(404, "text/plain", message);
}

To idea:  https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer/examples/WebServer/
================================================================
PA3BYB email: info@pa3byb.nl