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
Explore... Chat... Share...
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.
Hello clever folkand I'm not sure why your message got deleted.
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érature</a></li>
<li><a href="#">
<div class="span badge pull-right" id="humidite">-</div> Humidité</a></li>
<li><a href="#">
<div class="span badge pull-right" id="pa">-</div> Pression atmosphé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écé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è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>
It takes about 20-25 seconds for home assistant c[…]
I tried to upgrade tof my sonoff basic R2 with the[…]
a problem Perhaps you want to define "Probl[…]
Rebooting your router will not give you a faster I[…]
There are no other notifications from esptool.py i[…]
Using the Arduino IDE, you'll learn how to set up […]
In this project, you will post to Twitter using an[…]
In this project, we will build a water level contr[…]
I guess I'm late, but I had the same problem and f[…]
Last night I received my first D1 Minis for a lear[…]
Although I am aware that this is an old post, I fe[…]