Terrify your coworkers! Annoy your friends! How many people in upper management can I frighten without losing my job?
In this Enginursday, I've repurposed a project I was using to light fireworks during the Fourth of July. Now I can't really tell you how I did that, but I had an airhorn lying around and figured I could hook that up and have a little fun. The concept is pretty simple: have an ESP32 host up a webpage, click a button on your phone on said webpage, and set off the airhorn! I'm pretty lazy and wanted to do things solderless, so I grabbed a Qwiic Relay and was off to the races. All I had to do was connect my airhorn-battery circuit up to the common and normally open connections on the relay, connect the relay to my ESP32 and add a LiPo to power my ESP32. The whole setup is one of the simplest things I've ever made, but oh boy is it super effective. Check the whole thing out below.
We just need to add some code for our web server to serve up our button. To do this, we configure our ESP32 as a soft access point, and have it serve up a button for our horn. We then attach our relay functions to our on and off URLs. Lines 69-78 are where our web interface is actually doing actions on the ESP32, so check in here if you want the ESP32 to do some other things on your button presses. Check out lines 17 and 18 to change your WiFi settings to something neat and super secret.
/******************************************************************************
Horn.ino
Example for controlling a relay using a webpage served by an ESP32
by: Rui Santos
Adapted for horn by: Andy England, SparkFun Electronics
******************************************************************************/
#include <WiFi.h>
#include <Wire.h>
#include "SparkFun_Qwiic_Relay.h"
#define RELAY_ADDR 0x18 // Alternate address 0x19
Qwiic_Relay relay(RELAY_ADDR);
// Replace with your network credentials
const char* ssid = "HORN";
const char* password = "beepbeep1";
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Auxiliar variables to store the current output state
String hornState = "off";
void setup() {
Wire.begin();
Serial.begin(115200);
relay.begin();
relay.singleRelayVersion();
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.softAP(ssid, password);
server.begin();
}
void loop() {
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
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()) { // loop while the client's connected
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 horn on and off
if (header.indexOf("GET /horn/on") >= 0) {
Serial.println("Horn on");
hornState = "on";
relay.turnRelayOn();
} else if (header.indexOf("GET /horn/off") >= 0) {
Serial.println("Horn off");
hornState = "off";
relay.turnRelayOff();
}
// 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: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #555555;}</style></head>");
// Web Page Heading
client.println("<body><h1>The Big Old Beeper</h1>");
// Display current state, and ON/OFF buttons for our horn
client.println("<p>Horn - State " + hornState + "</p>");
// If the hornState is off, it displays the ON button
if (hornState == "off") {
client.println("<p><a href=\"/horn/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/horn/off\"><button class=\"button button2\">OFF</button></a></p>");
}
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("");
}
}
Upload this to your ESP32 and you should see a WiFi hotspot with your chosen SSID pop up when looking for networks on a phone or other device. Go ahead and connect to it. If it's not popping up, open up a Serial connection at 115200 baud to try and see why your ESP32 is unhappy.
At this point your phone might tell you that there isn't an internet connection. This is fine, as we only need the ESP32 to serve up its own webpage. Once connected, open up a web browser and navigate to 192.168.4.1 (this is the default IP address, as occasionally the ESP32 has trouble hosting a DNS server). You should see a webpage like the one below.
Now, hide the thing somewhere and scare some folks!