15. Interface & Application Programming¶
Controlling something through an interface. Per Andri’s suggestion I decided to keep things simple for now. I’m using a Xiao ESP32S3 and the board I made in Assignment 9. Electronics Production.
Hero Shot¶
Research¶
Andri suggested following this Guide which shows how to create a standalone webserver on an ESP32 that controls two LEDs. This fits my use case exactly. I already have the board made and the example code only needed slight modifications to function.
I initially wanted to add more to the code. But I’ve been extremely busy this week. I was working at my second job over the weekend (Never work retail on a payday weekend) so I ended up having to do this week’s assignment while working on-call at the lab.
Here’s some of the things I read up on and considered adding.
- Adding a hostname and custom DNS address
- Using the ESP32S3 Sense Camera
- Using the button I included on the original board to control something in the interface.
- Adding Over-The-Air firmware updates
- Adding a captive portal to input WiFi credentials
-
PWM Brightness control with a slider.
-
Controlling a stepper motor
All of these were interesting rabbit holes to read into but I had to rush and get it done.
The Code¶
I ended up re-writing the example code from the website with minimal changes. I changed the pin variable names and adjusted the colors of the buttons and the font for the page. It took me some time to wrap my head around the idea of printing the HTML/CSS using Client.println
and calling if (header.indexOf"(GET 26/on")
which uses the directories to trigger events on the board.
The only thing I added was a Wi-Fi Signal strength printout using Arduino WiFi.RSSI. Fairly simple stuff. Before displaying the HTML I set an integer equal to Wifi.RSSI then later print the integer whenever one of the buttons is pressed.
I also rounded the buttons. But I did that after I recorded the Hero Shot.
⌨️ show / hide code
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
// Include Wi-Fi Library
#include <WiFi.h>
const char* ssid = "SSID";
const char* password = "PASSWORD";
// Set to standard HTTP port "80"
WiFiServer server(80);
// Variable to store the HTTP request
String header;
//Auxiliary variables to store the current output state
String LED1State = "off";
String LED2State = "off";
String BTNState = "up";
// Assign output variables to GPIO pins
const int LED1 = D0;
const int LED2 = D2;
const int BUTT_PIN = D4;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds
const long timeoutTime = 2000;
void setup() {
Serial.begin(115200);
//Initialize the LED pins as outputs and the button as an input
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(BUTT_PIN, INPUT);
// set starting outputs to LOW
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
// Connect to a Wi-Fi Network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() !=WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop(){
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
if (header.indexOf("GET /26/on") >= 0) {
Serial.println("BLUE LED on");
LED1State = "on";
digitalWrite(LED1, HIGH);
} else if (header.indexOf("GET /26/off") >= 0) {
Serial.println("BLUE LED off");
LED1State = "off";
digitalWrite(LED1, LOW);
} else if (header.indexOf("GET /27/on") >= 0) {
Serial.println("RED LED on");
LED2State = "on";
digitalWrite(LED2, HIGH);
} else if (header.indexOf("GET /27/off") >= 0) {
Serial.println("GPIO 27 off");
LED2State = "off";
digitalWrite(LED2, LOW);
}
// Get Wi-Fi Signal Strength
long signalStrength = WiFi.RSSI();
// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS to style the on/off buttons
// Feel free to change the background-color and font-size attributes to fit your preferences
client.println("<style>html { font-family: Consolas; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color:rgb(51, 51, 51); border: none; border-radius: 5px; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color:rgb(32, 209, 26);}</style></head>");
// Web Page Heading
client.println("<body><h1>Blinky Thingy. Network edition!</h1>");
// Display current state, and ON/OFF buttons for BLUE LED
client.println("<p>Blue LED is: " + LED1State + "</p>");
// If the LED1State is off, it displays the ON button
if (LED1State=="off") {
client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
}
// Display current state, and ON/OFF buttons for RED LED
client.println("<p>Red LED is: " + LED2State + "</p>");
// If the LED2State is off, it displays the ON button
if (LED2State=="off") {
client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");
}
// Display Wi-Fi signal strength
client.println("<div class=\"signal\">Signal Strength: " + String(signalStrength) + " dBm</div>");
client.println("</body></html>");
// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
Not a lot to write about this week as it’s mostly code. It was good to get a rough refresh on HTML and I particularly liked playing around with the Wi-Fi Strength readout. I have two Access points at home and I was able to compare the signal between them using my laptop positioned in different rooms. I was surprised that the AP that I thought was more blocked to the living room turned out to have a stronger signal than the other. Fun stuff.