So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By Stevolution2021
#90036 Err? not sure what happened here. I started the original post, then spent the weekend playing about with my first attempt at programming an ESP8266.

Came back, and my account in here was gone, along with my first post (in this thread?) :(

I have made progress, but maybe I have broken some unknown forum rule, so I will hold on to my questions until I know what happened.

Thanks
User avatar
By QuickFix
#90045
Stevolution2021 wrote:Err? not sure what happened here. I started the original post, then spent the weekend playing about with my first attempt at programming an ESP8266.

Maybe you did a double post? :?

When a user's new, the first few posts will be approved manually by a moderator/admin; often a new user isn't aware of this, is unable to find his/her original post and does a repost, which might (all?) be removed for this reason.
When someone posts the same question all over the forum (in different sub forums), these questions could also be removed.

One other option: regularly we suffer from bots spamming our forum (that's why there's a moderation for new users in place) with odd looking or unrelated questions and even with moderation some of them seem to slip through.
Users can report such posts when they think a message might be spam (for instance because it's an exact copy of an earlier posted question here on ESP8266.com or even another site like Reddit or just unrelated to the ESP or electronics in general).

I remember having reported an odd looking message last week that was an exact copy of a message on Reddit: I'm not saying it was your message (I can't recall exactly), but if you actually did a copy-paste from Reddit, you've got your answer.

Don't worry, I'm sure you can post your question here just fine and it was just all a misunderstanding. ;)

[EDIT]

Hmmm, I've taken a look at your original message:
Hello clever folk

I have some (quite complicated) electronics projects sitting here, and I decided it's time they became IOT.

Digging out a selection of ESP8266's that I seem to have accumulated in various formats, I have started to tinker.

I will lay out my aim, and we can go from there.

My usual way of learning, is find some code, take it apart and re-assemble it as I need, learning as I go.
At 53, it's worked like that so far. I find it harder and harder to learn stuff from a book these days.
Saying that, I have looked high and low for a book to learn from, but none of them get great reviews.

I would like to eventually have an interactive webpage, hosting in SPIFFS, that allows me to control a couple of buttons on my Arduino/Teensy projects, and report back various sets of data to the webpage.
Also, have the ability to send a .TXT file to the ESP8266 from the webpage.

I have the ESP8266 (ESP-12E) all working fine, hosted in SPIFFS, and I am able to log into it etc.

This is my issue. I have searched high and low for an idiots guide to learning the basics of HTML programming to create the actual webpage.

I found this document as a starting point. It's very good, but limited to HTML.

https://tttapa.github.io/ESP8266/Chap01 ... P8266.html

Now seeing as it would be advantageous to use this page on mobile devices too, it seemed logical to maybe use Bootstrap.

So I found this tutorial, but bits appear to be missing...

https://diyprojects.io/esp8266-web-serv ... ml-css-js/

But I have yet to get this code to work.

And this source of information...

https://tttapa.github.io/ESP8266/Chap01 ... P8266.html

So, my questions are...

Bootstrap? Worth pursuing, or can I achieve a decent multi-platform page just using HTML, Java etc?

This following code is my 'basis'. I thought this would give me all options and I could work outwards from this.
I can log into this routine on a mobile, but the Bootstrap theme doesn't load. I just get normal HTML layout.
If I view the index.HTML file on my laptop however, it works fine, including the Bootstrap driven themes.

The attached index.html file is also my 'basis'. I know it doesn't interact with the ESP8266 code yet, but that was further down the line. And yes, it's lifted from the links above (so some of the text is still French).

Does anyone know of maybe some software that I can use to develop my front page, and then lift that code over to my ESP8266? From that code, I can see how the pages are formed.

I found these:

https://www.codeply.com/ Nice, but not really a basis for buttons, reporting etc
https://bootstrapstudio.io/ I would need to purchase this, but not sure it will do what I need.

I TOTALLY understand this is a wide request, and maybe trying to run before I can walk. But, this is the best I have found to date.

Any suggestions greatly appreciated

My ESP8266 base code:

Code: Select all// HTTP GET requests are used to retrieve data from a server, a web page for instance. It shouldn't change anything on the server, it just gets the data from the server, without side effects.

// HTTP POST requests are used to send data to the server, for example, to send your user name and password to the server when you log in, or when you upload a photo. Unlike GET, POST can change the data on the server or the state of the server.
// HTTP POST has a body that can contain data that is sent to the server.

// All server requests should be answered with a code. HTTP Status Code  Meanings...
// 200   OK: the request was successful
// 303   See Other: used to redirect to a different URI, after a POST request, for instance
// 400   Bad Request: the server couldn't understand the request, because the syntax was incorrect
// 401   Unauthorized: user authentication is required
// 403   Forbidden: the server refuses to execute the request, authorization won't help
// 404   Not Found: the requested URI was not found
// 500   Internal Server Error: The server encountered an unexpected condition and couldn't fulfill the request

// The PORT number directs the data to the correct application. For instance, port 80 is a webserver.  Email is port 25.  DNS request is 53.      https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

// Uploading data to Spiffs:  Hold Program. Pulse Reset. Press upload data.  Release Program
// Uploading code:  Press upload and await 'uploading'. Press and hold Program. Pulse Reset. Release Program

//==========================================================================================================================================================================================================================================================

#include <ESP8266WiFi.h>                            // Main WiFi library
#include <ESP8266WiFiMulti.h>                       // Allows for connection to multiple WiFi networks.  Automatically connected to the strongest signal
#include <ArduinoOTA.h>                             // Allows for 'Over the air' processor updating.
#include <ESP8266WebServer.h>                       // Allows hosting of a webpage on this processor
#include <ESP8266mDNS.h>                            // Allows you to connect to a local LAN network using .local suffix, rather than just the IP address.  Outside the local network, the DNS (domain name system) changes the IP address into a webpage name.
#include <FS.h>                                     // File system for the SPIFFS (flash memory storage of the webpage)
#include <WebSocketsServer.h>                       // Allows constant updating of the webpage without reloading

//==========================================================================================================================================================================================================================================================

ESP8266WiFiMulti wifiMulti;                                                                                                           // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'

ESP8266WebServer server(80);                                                                                                          // Create a webserver object that listens for HTTP request on port 80
WebSocketsServer webSocket(81);                                                                                                       // create a websocket server on port 81

File fsUploadFile;                                                                                                                    // a File variable to temporarily store the Spiffs file

const char *ssid = "TestAccess";                                                                                                   // The name of the Wi-Fi network that will be created
const char *password = "Test9999";                                                                                                 // The password required to connect to it, leave blank for an open network

const char *OTAName = "Testupdater";                                                                                               // A name and a password for the OTA service.  This is the 'over the air' updating service
const char *OTAPassword = "Test1234";

const char* mdnsName = "Testmdns";                                                                                                     // Domain name for the mDNS responder.  If searching on a local network, this is the name it will use:

#define LED_RED     15                                                                                                                // specify the pins with an RGB LED connected
#define LED_GREEN   12
#define LED_BLUE    13

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void setup() {
 
  pinMode(LED_RED, OUTPUT);                                                                                                           // the pins with LEDs connected are outputs
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);

  Serial.begin(115200);                                                                                                               // Start the Serial communication to send messages to the computer
  delay(10);
  Serial.println("\r\n");

  startWiFi();                                                                                                                        // Start a Wi-Fi access point, and try to connect to some given access points. Then wait for either an AP or STA connection

  startOTA();                                                                                                                         // Start the OTA service (Over the air)

  startSPIFFS();                                                                                                                      // Start the SPIFFS and list all contents (This onboard memoey stores the webpage)

  startWebSocket();                                                                                                                   // Start a WebSocket server (Allows for continual updating of the webpage without reloading the whole page)

  startMDNS();                                                                                                                        // Start the mDNS responder (Allows you to connect to a local LAN network using .local suffix, rather than just the IP address)

  startServer();                                                                                                                      // Start a HTTP server with a file read handler and an upload handler

}


bool rainbow = false;                                                                                                                 // The rainbow effect is turned off on startup

unsigned long prevMillis = millis();
int hue = 0;


//============================================================================================================================================================================================================================================================
//============================================================================================================================================================================================================================================================
//============================================================================================================================================================================================================================================================

void loop() {

  webSocket.loop();                                                                                                                   // constantly check for websocket events
  server.handleClient();                                                                                                              // run the server
  ArduinoOTA.handle();                                                                                                                // listen for OTA events

  if (rainbow) {                                                                                                                      // if the rainbow effect is turned on
    if (millis() > prevMillis + 32) {
      if (++hue == 360)                                                                                                               // Cycle through the color wheel (increment by one degree every 32 ms)
        hue = 0;
      setHue(hue);                                                                                                                    // Set the RGB LED to the right color
      prevMillis = millis();
    }
  }
}

//============================================================================================================================================================================================================================================================
//============================================================================================================================================================================================================================================================
//============================================================================================================================================================================================================================================================

void startWiFi() {                                                                                                         // Start a Wi-Fi access point, and try to connect to some given access points. Then wait for either an AP or STA connection

  WiFi.softAP(ssid, password, 1, false, 4);                                                                                // Channel = 1-13. Default is channel 1.    Hidden: True will hide ssid.   Max connection. Number of stations 0-8. Default is 4

  IPAddress local_IP(192, 168, 1, 40);                                                                                     // Set our ip address  Get these details by typing 'ipconfig' into a command prompt page
  IPAddress gateway(192, 168, 1, 254);
  IPAddress subnet(255, 255, 255, 0);

  WiFi.softAPConfig(local_IP, gateway, subnet);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  wifiMulti.addAP("PLUSNET-S7MQ", "ae383b4d27");                                                                           // add Wi-Fi networks you want to connect to
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
  wifiMulti.addAP("ssid_from_AP_4", "your_password_for_AP_4");
  wifiMulti.addAP("ssid_from_AP_5", "your_password_for_AP_5");

  Serial.println("Connecting");
  while (wifiMulti.run() != WL_CONNECTED && WiFi.softAPgetStationNum() < 1) {                                              // Wait for the Wi-Fi to connect
    delay(250);
    Serial.print('.');
  }
  Serial.println("\r\n");
  if (WiFi.softAPgetStationNum() == 0) {                                                                                   // If the ESP8266 is connected to an AP  (Access point is the router/method of obtaining the internet)
    Serial.print("Connected to ");
    Serial.println(WiFi.SSID());                                                                                           // Tell us what network we're connected to
    Serial.print("IP address:\t");
    Serial.print(WiFi.localIP());                                                                                          // Send the IP address of the ESP8266 to the computer
  } else {                                                                                                                 // If a station is connected to the ESP SoftAP (Station means a device consuming the internet data)
    Serial.print("Station connected to ESP8266 AP");                                                                       // The ESP8266 as an AP means it is now of the point of connection
  }
  Serial.println("\r\n");
}


//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void startOTA() {                                                                                                          // Start the OTA service
  ArduinoOTA.setHostname(OTAName);
  ArduinoOTA.setPassword(OTAPassword);

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
    digitalWrite(LED_RED, 0);                                                                                              // turn off the LEDs
    digitalWrite(LED_GREEN, 0);
    digitalWrite(LED_BLUE, 0);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\r\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("OTA ready\r\n");
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void startSPIFFS() {                                                                                                       // Start the SPIFFS and list all contents
  SPIFFS.begin();                                                                                                          // Start the SPI Flash File System (SPIFFS)
  Serial.println("SPIFFS started. Contents:");
  {
    Dir dir = SPIFFS.openDir("/");
    while (dir.next()) {                                                                                                   // List the file system contents (data file)
      String fileName = dir.fileName();
      size_t fileSize = dir.fileSize();
      Serial.printf("\tFS File: %s, size: %s\r\n", fileName.c_str(), formatBytes(fileSize).c_str());
    }
    Serial.printf("\n");
  }
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void startWebSocket() {                                                                                                    // Start a WebSocket server  (Live page updating)
  webSocket.begin();                                                                                                       // start the websocket server
  webSocket.onEvent(webSocketEvent);                                                                                       // if there's an incomming websocket message, go to function 'webSocketEvent'
  Serial.println("WebSocket server started.");
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void startMDNS() {                                                                                                         // Start the mDNS responder
  MDNS.begin(mdnsName);                                                                                                    // start the multicast domain name server
  Serial.print("mDNS responder started: http://");
  Serial.print(mdnsName);
  Serial.println(".local");
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void startServer() {                                                                                                       // Start a HTTP server with a file read handler and an upload handler
  server.on("/edit.html",  HTTP_POST, []() {                                                                               // If a POST request is sent to the /edit.html address.   POST requests send data to the server, E.G. Passwords
    server.send(200, "text/plain", "");
  }, handleFileUpload);                                                                                                    // go to 'handleFileUpload'

  server.onNotFound(handleNotFound);          // if someone requests any other file or page, go to function 'handleNotFound'    // and check if the file exists

  server.begin();                             // start the HTTP server
  Serial.println("HTTP server started.");
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void handleNotFound() {                                                                                                    // if the requested file or page doesn't exist, return a 404 not found error
  if (!handleFileRead(server.uri())) {                                                                                     // check if the file exists in the flash memory (SPIFFS), if so, send it
    server.send(404, "text/plain", "404: File Not Found");
  }
}

bool handleFileRead(String path) {                                                                                         // send the right file to the client (if it exists)
  Serial.println("handleFileRead: " + path);
  if (path.endsWith("/")) path += "index.html";                                                                            // If a folder is requested, send the index file
  String contentType = getContentType(path);                                                                               // Get the MIME type
  String pathWithGz = path + ".gz";
  if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) {                                                                  // If the file exists, either as a compressed archive, or normal
    if (SPIFFS.exists(pathWithGz))                                                                                         // If there's a compressed version available
      path += ".gz";                                                                                                       // Use the compressed verion
    File file = SPIFFS.open(path, "r");                                                                                    // Open the file
    size_t sent = server.streamFile(file, contentType);                                                                    // Send it to the client
    file.close();                                                                                                          // Close the file again
    Serial.println(String("\tSent file: ") + path);
    return true;
  }
  Serial.println(String("\tFile Not Found: ") + path);                                                                     // If the file doesn't exist, return false
  return false;
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void handleFileUpload() {                                                                                                  // upload a new file to the SPIFFS
  HTTPUpload& upload = server.upload();
  String path;
  if (upload.status == UPLOAD_FILE_START) {
    path = upload.filename;
    if (!path.startsWith("/")) path = "/" + path;
    if (!path.endsWith(".gz")) {                                                                                           // The file server always prefers a compressed version of a file
      String pathWithGz = path + ".gz";                                                                                    // So if an uploaded file is not compressed, the existing compressed
      if (SPIFFS.exists(pathWithGz))                                                                                       // version of that file must be deleted (if it exists)
        SPIFFS.remove(pathWithGz);
    }
    Serial.print("handleFileUpload Name: "); Serial.println(path);
    fsUploadFile = SPIFFS.open(path, "w");                                                                                 // Open the file for writing in SPIFFS (create if it doesn't exist)
    path = String();
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (fsUploadFile)
      fsUploadFile.write(upload.buf, upload.currentSize);                                                                  // Write the received bytes to the file
  } else if (upload.status == UPLOAD_FILE_END) {
    if (fsUploadFile) {                                                                                                    // If the file was successfully created
      fsUploadFile.close();                                                                                                // Close the file again
      Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize);
      server.sendHeader("Location", "/success.html");                                                                      // Redirect the client to the success page
      server.send(303);
    } else {
      server.send(500, "text/plain", "500: couldn't create file");
    }
  }
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {                                        // When a WebSocket message is received
  switch (type) {
    case WStype_DISCONNECTED:                                                                                              // if the websocket is disconnected
      Serial.printf("[%u] Disconnected!\n", num);
      break;
    case WStype_CONNECTED: {                                                                                               // if a new websocket connection is established
        IPAddress ip = webSocket.remoteIP(num);
        Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
        rainbow = false;                                                                                                   // Turn rainbow off when a new connection is established
      }
      break;
    case WStype_TEXT:                                                                                                      // if new text data is received
      Serial.printf("[%u] get Text: %s\n", num, payload);
      if (payload[0] == '#') {                                                                                             // we get RGB data
        uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);   // decode rgb data
        int r = ((rgb >> 20) & 0x3FF);                                                                                     // 10 bits per color, so R: bits 20-29
        int g = ((rgb >> 10) & 0x3FF);                                                                                     // G: bits 10-19
        int b =          rgb & 0x3FF;                                                                                      // B: bits  0-9

        analogWrite(LED_RED,   r);                                                                                         // write it to the LED output pins
        analogWrite(LED_GREEN, g);
        analogWrite(LED_BLUE,  b);
      } else if (payload[0] == 'R') {                                                                                      // the browser sends an R when the rainbow effect is enabled
        rainbow = true;
      } else if (payload[0] == 'N') {                                                                                      // the browser sends an N when the rainbow effect is disabled
        rainbow = false;
      }
      break;
  }
}

String formatBytes(size_t bytes) {                                                                                         // convert sizes in bytes to KB and MB
  if (bytes < 1024) {
    return String(bytes) + "B";
  } else if (bytes < (1024 * 1024)) {
    return String(bytes / 1024.0) + "KB";
  } else if (bytes < (1024 * 1024 * 1024)) {
    return String(bytes / 1024.0 / 1024.0) + "MB";
  }
}

String getContentType(String filename) {                                                                                   // determine the filetype of a given filename, based on the extension
  if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".ico")) return "image/x-icon";
  else if (filename.endsWith(".gz")) return "application/x-gzip";
  else if (filename.endsWith(".png")) return "image/img";                                                                  // ########## I added this line?  No idea if it works
  return "text/plain";
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void setHue(int hue) {                                                                                                     // Set the RGB LED to a given hue (color) (0° = Red, 120° = Green, 240° = Blue)
  hue %= 360;                                                                                                              // hue is an angle between 0 and 359°
  float radH = hue * 3.142 / 180;                                                                                          // Convert degrees to radians
  float rf, gf, bf;

  if (hue >= 0 && hue < 120) {                                                                                             // Convert from HSI color space to RGB
    rf = cos(radH * 3 / 4);
    gf = sin(radH * 3 / 4);
    bf = 0;
  } else if (hue >= 120 && hue < 240) {
    radH -= 2.09439;
    gf = cos(radH * 3 / 4);
    bf = sin(radH * 3 / 4);
    rf = 0;
  } else if (hue >= 240 && hue < 360) {
    radH -= 4.188787;
    bf = cos(radH * 3 / 4);
    rf = sin(radH * 3 / 4);
    gf = 0;
  }
  int r = rf * rf * 1023;
  int g = gf * gf * 1023;
  int b = bf * bf * 1023;

  analogWrite(LED_RED,   r);                                                                                               // Write the right color to the LED output pins
  analogWrite(LED_GREEN, g);
  analogWrite(LED_BLUE,  b);
}


The index.html file:
Code: Select all<!DOCTYPE html>
<html charset="UTF-8">
  <head>
    <meta name="viewport">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.11.0/bootstrap-table.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.11.0/bootstrap-table.min.js"></script>
    <link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/superhero/bootstrap.min.css" rel="stylesheet" title="main">

    <title>Maintenance and setup</title>                                           <!--Page title (top of actual web browser page)-->

  </head>

  <body>
    <div class="container-fluid">
      <h1>HIDecho</h1>                                                <!--Header (Project title)-->
      <ul class="nav nav-tabs" id="tab">                                       <!--Navigation bar-->
        <li class="active"><a href="#tab_Macros" data-toggle="tab">Macros</a></li>                        <!--Macros page-->
        <li><a href="#tab_graphs" data-toggle="tab">Graphs</a></li>                              <!--Graphs page-->
        <li><a href="#tab_gpio" data-toggle="tab">GPIO  </a></li>                              <!--GPIO page-->
        <li><a href="#tab_configuration" data-toggle="tab">Configuration</a></li>                        <!--Configuration page-->
      </ul>
      <div class="tab-content">
        <div class="tab-pane fade in active" id="tab_Macros">                                   <!--Fade between pages-->
          <h2>Human Interface Emulator</h2>                                       <!--Sub header-->
          <ul class="nav nav-pills">
            <li class="active"><a href="#">
                <div class="span badge pull-right" id="temperature">-</div> Temp&eacute;rature</a></li>
            <li><a href="#">
                <div class="span badge pull-right" id="humidite">-</div> Humidit&eacute;</a></li>
            <li><a href="#">
                <div class="span badge pull-right" id="pa">-</div> Pression atmosph&eacute;rique</a></li>
          </ul>
          <table id="tab_mesures" data-toggle="table" data-show-colunns="true">                           <!--Create a table-->
            <thead>
              <tr>
                <th data-field="mesure" data-align="left" datsortable="true" data-formatter="labelFormatter">Mesure</th>
                <th data-field="valeur" data-align="left" datsortable="true" data-formatter="valueFormatter">Valeur</th>
                <th data-field="precedente" data-align="left" datsortable="true" data-formatter="vpFormatter">ValeuPr&eacute;c&eacute;dente</th>
              </tr>
            </thead>
          </table>
        </div>
        <div class="tab-pane fade" id="tab_graphs">                                    <!--Graphs page-->
          <h2>Graphs</h2>
        </div>
        <div class="tab-pane fade" id="tab_gpio">                                    <!--GPIO page-->
          <h2>GPIO</h2>
          <div class="row">
            <div class="col-xs-6 col-md-4">
              <h4 class="text-left">D5
                <div class="span badge" id="D5_etat">OFF</div>
              </h4>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-success btn-lg" id="D5_On" type="button">ON</div>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-danger btn-lg" id="D5_Off" type="button">OFF</div>
            </div>
            <div class="col-xs-6 col-md-4">
              <h4 class="text-left">D6
                <div class="span badge" id="D6_etat">OFF</div>
              </h4>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-success btn-lg" id="D6_On" type="button">ON</div>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-danger btn-lg" id="D6_Off" type="button">OFF</div>
            </div>
            <div class="col-xs-6 col-md-4">
              <h4 class="text-left">D7
                <div class="span badge" id="D7_etat">OFF</div>
              </h4>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-success btn-lg" id="D7_On" type="button">ON</div>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-danger btn-lg" id="D7_Off" type="button">OFF</div>
            </div>
            <div class="col-xs-6 col-md-4">
              <h4 class="text-left">D8
                <div class="span badge" id="D8_etat">OFF</div>
              </h4>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-success btn-lg" id="D8_On" type="button">ON</div>
            </div>
            <div class="col-xs-6 col-md-4">
              <div class="button btn btn-danger btn-lg" id="D8_Off" type="button">OFF</div>
            </div>
          </div>
        </div>
        <div class="tab-pane fade" id="tab_configuration">
          <h2>Configuration        </h2>
          <div class="btn-group">
            <button class="btn btn-default" id="labelTheme">Theme</button>
            <button class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>            <!--Drop down selection of the theme-->
            <ul class="dropdown-menu">
              <li><a class="change-style-menu-item" href="#" rel="bootstrap">Boostrap</a></li>
              <li><a class="change-style-menu-item" href="#" rel="cerulean">Cerulean</a></li>
              <li><a class="change-style-menu-item" href="#" rel="cosmo">Cosmo</a></li>
              <li><a class="change-style-menu-item" href="#" rel="cyborg">Cyborg</a></li>
              <li><a class="change-style-menu-item" href="#" rel="darkly">Darkly</a></li>
              <li><a class="change-style-menu-item" href="#" rel="flatly">Flatly</a></li>
              <li><a class="change-style-menu-item" href="#" rel="journal">Journal</a></li>
              <li><a class="change-style-menu-item" href="#" rel="lumen">Lumen</a></li>
              <li><a class="change-style-menu-item" href="#" rel="paper">Paper</a></li>
              <li><a class="change-style-menu-item" href="#" rel="readable">Readable</a></li>
              <li><a class="change-style-menu-item" href="#" rel="sandstone">Sandstone</a></li>
              <li><a class="change-style-menu-item" href="#" rel="simplex">Simplex</a></li>
              <li><a class="change-style-menu-item" href="#" rel="slate">Slate</a></li>
              <li><a class="change-style-menu-item" href="#" rel="spacelab">Spacelab</a></li>
              <li><a class="change-style-menu-item" href="#" rel="superhero">Superhero</a></li>
              <li><a class="change-style-menu-item" href="#" rel="united">United</a></li>
              <li><a class="change-style-menu-item" href="#" rel="yeti">Yeti  </a></li>
            </ul>
          </div>
        </div>
      </div>

      <div class="row" style="position:absolute; bottom:0; width:100%">                              <!--Set up a page footer (shown on all pages)-->
        <div class="col-xs-2 col-md-2"><img src="img/logo.png" width="200" height="50"></div>                     <!--Logo image-->
        <div class="col-xs-5 col-md-5">
          <p><a href="http://www.umd.net">Steve Croot Developments</a></p>                           <!--Link at bottom of page-->
        </div>
        <div class="col-xs-5 col-md-5">
          <p><a href="http://www.google.com">Support and documentation</a></p>                           <!--Link at bottom of page-->
        </div>
      </div>
    </div>
    <script>   

      // Adapté de - Adapted from : https://wdtz.org/bootswatch-theme-selector.html                        <!--Change the current theme-->
      var supports_storage = supports_html5_storage();
      if (supports_storage) {
        var theme = localStorage.theme;
        if ( typeof theme != 'undefined' ) {
          console.log("Recharge le theme " + theme);
          set_theme(get_themeUrl(theme));
        }
      }
     

      jQuery(function($){                                             <!--A new theme has been selected-->
        $('body').on('click', '.change-style-menu-item', function() {
          var theme_name = $(this).attr('rel');
          console.log("Changement de theme " + theme_name);
          var theme_url = get_themeUrl(theme_name);
          console.log("URL theme : " + theme_url);
          set_theme(theme_url);
        });
      });

      function get_themeUrl(theme_name){                                       <!--Get theme URL. We are retrieving the themes directly online-->
        $('#labelTheme').html("Th&egrave;me : " + theme_name);
        var url_theme = "";
        if ( theme_name === "bootstrap" ) {
          url_theme = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css";
        } else {
          url_theme = "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/" + theme_name + "/bootstrap.min.css";
        }
        if (supports_storage) {                                             <!--Save into the local database the selected theme-->
          localStorage.theme = theme_name;
        }
        return url_theme;
      }

      function set_theme(theme_url) {                                          <!--Apply theme-->
        $('link[title="main"]').attr('href', theme_url);
      }
      function supports_html5_storage(){                                       <!--Local storage available ?-->
        try {
          return 'localStorage' in window && window['localStorage'] !== null;
        } catch (e) {
          return false;
        }
      }
    </script>
  </body>
</html>
and I'm not sure why your message got deleted.

Did you double post it perhaps? :?
Or maybe your account (and thus all your messages) got deleted for some reason?