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!
Just when I thought IoT was only good for useless things like your fridge talking to the grocery store to order more milk when you run out!!
You thought wrong! It can in fact be repurposed to do something actually useful
Ahhhh, it's been a while with the car horn prank. XD
It's cool to see it now in IoT form. =P
You say that until it lands under your desk...
IMHO, it wouuld be a wise idea to have it "automatically" turn the horn off after some maximum number of seconds. You really don't want to come home to find that the neighbors have called 911 because of the racket...
Totally correct, but I really enjoyed being able to toot the thing for different periods of time. All you would need to do would be to add a delay and a call to relay.turnRelayOff(). Also, since the ESP32 is acting as a soft access point, you have to be kind of close to the thing to maintain decent WiFi signal strength.
I learned long ago about the truth in Murphy's Law... so it's always good to have a "failsafe".
On a different tangent, methinks you could use this for something "interesting" the evening of Oct. 31... ;-)
OOOH now we're cookin with peanut oil. Alright, maybe I'll bust it back out come Halloween-time
What, no video?!
You're just gonna have to take my word for it here, we were setting up to film and I went to test the horn and once the camera came on, the horn wouldn't turn off! I didn't want to actually deafen my coworkers so we decided against filming.
The day prior I did come back to my desk, thinking I was the only one connected to the horn. @brambleton asked if I had just given the thing a toot and I said yea, nobody else can connect to it.
Then he triggered the thing and I jumped about 3 feet out of my own body.
Nice! IMO, the best setup of this type of prank is where it triggers off of an action of the person, whether it be them hitting a certain key on their keyboard, touching their screwdriver to something, or simply leaning back in their chair (think image processing...)
The old one was actually installed in a bar stool that would honk when you sat down on it! We've contacted our old horn supplier in an attempt to bring back the honky goodness, so keep your eyes peeled!
The car horn prank revenge included an ignition coil connected under the driver's seat. I heard of this in 1966 from a guy whose first car was a model T Ford.
Nice post. I learn something more challenging on different blogs everyday. It will always be stimulating to read content from other writers and practice a little something from their store. I’d prefer to use some with the content on my blog whether you don’t mind. Natually I’ll give you a link on your web blog. Thanks for sharing.