14. Interface and application programming¶
Group assignment¶
For this week we looked at all kinds of different frameworks to use with our esp based boards. We need a web based interface to use in the final project, so we narrowed it down a bit to this list.
- ESP-UI: https://github.com/s00500/ESPUI
- ESP-DASH: https://ayushsharma82.github.io/ESP-DASH/installation.html
- embeded AJAX: https://github.com/tfry-git/EmbAJAX
- html/javascript: https://randomnerdtutorials.com/esp8266-web-server/
- Bootstrap : https://diyprojects.io/bootstrap-create-beautiful-web-interface-projects-esp8266/#.YJbP0bUzaF4
- esp wifi web interface https://www.etechpath.com/how-to-control-rgb-led-wirelessly-using-esp8266-wifi-web-interface/
- ESP now webserver: https://randomnerdtutorials.com/esp8266-esp-now-wi-fi-web-server/
After comparing we choose the ESPnow webserver path to further work with. It is a basic html/css/javascript running webserver on the module and leaves also room to use the mesh networking capabilities of the EPSnow framework.
Individual¶
1. Mysa machine board¶
For the mysa machine we used a standard arduino board. Now we would like to upgrade it to a custom board with an esp32 inside. So we can make a user interface to control the machine from a phone or tablet.
https://www.espressif.com/sites/default/files/documentation/esp32-wroom-32e_esp32-wroom-32ue_datasheet_en.pdf
I started design of this board, but didn’t continue for the moment.
2. Final project interface¶
For our final project, it would be nice to have an interface on a phone or tablet to set timers and send messages. So we could use an ESP to control the timer and physical display. And also be the Sender for the LORA networked nodes.
- should the timer run autonomous and send message to the node once finished. Then we need to run several timers simultaneous independent from each other?
- should the timer be independent of the networked nodes?
- Timer can also be on the nodes and get started by a message
As a test we thought to make a simple dashboard style interface for the test boards used in the esp-now exercise from the networking week. Meanwhile I’m designing an board for this.
- best to be some sort of html or browser based interface
- Run on the esp itself and not using external server of wifi. We want it to be stand alone and useable in the field, on concerts and festivals.
Test with esp-now webserver¶
I’m using the same examples from networking week to work further on. 1 ESP32 board as sender and 2 wemos D1 boards with neo-pixel as receiver. The aim is to put also a web interface on the esp32 so we can send messages to the nodes from a phone
First I installed the needed libraries
I wrote some code and based myself on the wifi webserver tutorial from randomnerds
First time i compiled the code i got an error saying :Multiple libraries were found for “WiFi.h”
Seems there are some conflicting libraries. Searched the internet and made a good guess at which I could delete and didn’t need.
When I had the correct libraries it still was a bit searching. Thing is that libraries for the esp32 and esp8266 are not the same. So things won’t work on both. I have to think and decide what modules to use.
But, on to the ESP-now example with the ESP32 as sender and also webserver to host the interface and 2 esp8266 with neopixels to send messages to.
Write Html, css and javascript for the UI¶
In my interface I need some sliders to set the RGB color and the time. I also need buttons for the Nodes. Maybe if there are lots of nodes I could use a dropdown for node selection also.
the Html uses css id’s to get and set values on the elements. 4 sliders are used to adjust the R(ed), G(reen), B(lue) and T(imer) variables.
I use an onclick javascript function on the buttons to send all variables to the url
onclick="location.href=this.href+'?n=2&r='+Rslider.value+'&g='+Gslider.value+'&b='+Bslider.value+'&t='+Tslider.value;return false;"
this works fine and gives me this as a resulting URL
testpage.html?n=3&r=254&g=128&b=238&t=16
I can now read these inside the arduino code with help of the AsyncWebServer library
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest * request)
Now I still have to figure out how to adjust the values of the slider on reloading the page. Now everything resets on reload. It would be nice that the last values where remembered in the html also. some editing later I found a way to add some javascript to adjust the sliders based on the variables in the URL on load.
function readVars() {
Rslider.value = document.getElementById("redValue").innerHTML = getUrlVars()['r'];
Gslider.value = document.getElementById("greenValue").innerHTML = getUrlVars()['g'];
Bslider.value = document.getElementById("blueValue").innerHTML = getUrlVars()['b'];
Tslider.value = document.getElementById("timeValue").innerHTML = getUrlVars()['t'];
}
I also have to tweak some more details in the css for the final looks.
I kept working on the interface and got most bugs out, you can see still some more on the project journal
The final html for the interface looks like this:
<!DOCTYPE HTML><html>
<head>
<title>Pink-to-matic Pager</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<style>
html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}
h1 { font-size: 2rem;}
body { margin: 0;}
.topnav { overflow: hidden; background-color: #FF69B4; color: white; font-size: 1.7rem; }
.content { padding: 20px; }
.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.reading { font-size: 2.8rem; }
.button { background-color: #FF69B4; border: none; border-radius: 10px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
.button2 {background-color: #555555;}
.button:hover {background-color: #555555;color: white;}
.button:active { color: #FF69B4; }
.red { color: red; }
.green { color: green; }
.blue { color: blue; }
.slidecontainer { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.slider.blue { color: blue; }
.slider {
-webkit-appearance: none;
width: 75%;
height: 15px;
border-radius: 5px;
background: #555555;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
}
.slider:hover {
opacity: 1;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
border-radius: 30%;
background: #FF69B4;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 25px;
height: 25px;
border-radius: 30%;
background: #FF69B4;
cursor: pointer;
}
</style>
</head>
<body onload="readVars()">
<div class="topnav">
<h1>Pink-to-matic Pager</h1>
</div>
<div class="content">
<div class="slidecontainer">
<p>Timer : <span id="timeValue"></span></br></br><input type="range" min="0" max="60" value="Tslider.value" class="slider" id="timer"></p>
<p class="red">Red : <span id="redValue"></span></br></br><input type="range" min="1" max="255" value="Rslider.value" class="slider" id="red"></p>
<p class="green">Green : <span id="greenValue"></span></br></br><input type="range" min="1" max="255" value="Gslider.value" class="slider" id="green"></p>
<p class="blue">Blue : <span id="blueValue"></span></br></br><input type="range" min="1" max="255" value="Bslider.value" class="slider" class="blue" id="blue"></p>
</div>
<div class="cards">
<div class="card">
<p><a onclick="location.href=this.href+'/dat?n=1&r='+Rslider.value+'&g='+Gslider.value+'&b='+Bslider.value+'&t='+Tslider.value;return false;"><button class="button">Node 1</button></a></p>
</div >
<div class="card">
<p><a onclick="location.href=this.href+'/dat?n=2&r='+Rslider.value+'&g='+Gslider.value+'&b='+Bslider.value+'&t='+Tslider.value;return false;"><button class="button">Node 2</button></a></p>
</div>
<div class="card">
<p><a onclick="location.href=this.href+'/dat?n=3&r='+Rslider.value+'&g='+Gslider.value+'&b='+Bslider.value+'&t='+Tslider.value;return false;"><button class="button">Node 3</button></a></p>
</div>
<div class="card">
<p><a onclick="location.href=this.href+'/dat?n=4&r='+Rslider.value+'&g='+Gslider.value+'&b='+Bslider.value+'&t='+Tslider.value;return false;"><button class="button">Node 4</button></a></p>
</div>
<div class="card">
<p><a onclick="location.href=this.href+'/dat?n=5&r='+Rslider.value+'&g='+Gslider.value+'&b='+Bslider.value+'&t='+Tslider.value;return false;"><button class="button">Node 5</button></a></p>
</div>
</div>
<div class="cards">
</div>
</div>
<script>
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
var Rslider = document.getElementById("red");
var Gslider = document.getElementById("green");
var Bslider = document.getElementById("blue");
var Tslider = document.getElementById("timer");
var Routput = document.getElementById("redValue");
var Goutput = document.getElementById("greenValue");
var Boutput = document.getElementById("blueValue");
var Toutput = document.getElementById("timeValue");
Routput.innerHTML = Rslider.value;
Goutput.innerHTML = Gslider.value;
Boutput.innerHTML = Bslider.value;
Toutput.innerHTML = Tslider.value;
Rslider.oninput = function() {
Routput.innerHTML = this.value;
}
Bslider.oninput = function() {
Boutput.innerHTML = this.value;
}
Gslider.oninput = function() {
Goutput.innerHTML = this.value;
}
Tslider.oninput = function() {
Toutput.innerHTML = this.value;
}
function readVars() {
Rslider.value = document.getElementById("redValue").innerHTML = getUrlVars()['r'];
Gslider.value = document.getElementById("greenValue").innerHTML = getUrlVars()['g'];
Bslider.value = document.getElementById("blueValue").innerHTML = getUrlVars()['b'];
Tslider.value = document.getElementById("timeValue").innerHTML = getUrlVars()['t'];
Routput.innerHTML = Rslider.value;
Goutput.innerHTML = Gslider.value;
Boutput.innerHTML = Bslider.value;
Toutput.innerHTML = Tslider.value;
}
</script>
</body>
</html>
To use this html on the esp webserver I have to embed this in the arduino code. It got a bit complicated because I also have to keep the code for the Esp-now networking working.
As mentioned earlier somewhere else. The ESPnow and the webserver libraries are not the same for the 8266 modules and the ESP32 modules. So I had to deceide which to use before I could go any further and try to debug the errors I got. I was designing a board with a 8266 chip and a LORA chip to use in the final project. So better dump the ESP32 commercial module I was testing with and start on making everything compatible with the board I’m making.
So I had to switch out the AsyncWebServer and use the ESP8266WebServer instead. The code I had to handle the webserver commands had to be rewritten to work with this library. It is similar but still different.
server.on("/", HTTP_GET, handleRoot);
// Call the 'handleRoot' function when a client requests URI "/"
server.on("/dat", HTTP_GET, handleData);
// Call the 'handleData' function when a GET request is made to URI "/dat"
server.onNotFound(handleNotFound);
server.begin();
I made some functions to call when the HTTP GET command was send to the server.
Now all parts of the code work happily together. You can see all code working for serving the html, getting the variables from the sliders and sending it with LORA to another device in the arduino source code.
video of interface and board working together
And now for something completely different
Meanwhile I also started drawing a sketch of how the puck shell should look 🙂
3. Files¶
- espNow_pixel_receiver code
- espNow_sender code for esp32
- espNow_sender code for esp32
- interface html code
- mysa_esp32.sch schematic