Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Arduino.h>
- #include <WiFi.h>
- #include <WiFiClient.h>
- #include <WebServer.h>
- #include <uri/UriBraces.h>
- #include <ESP32Servo.h>
- /*
- Ludwig Punisher: ESP32 simple servo/relay webserver. This will trigger servos and
- relays based on URLs, while serving a webpage full of buttons you can press to call
- those URLs. This is system is still lacking some "proper" programming practices, however
- it is generating the webpage and all the settings based entirely on the objects/arrays at
- the top of this file. You should never have to change anything except the first few rows
- of variables to get this working.
- Assuming the IP is 192.168.1.2, it might look something like this
- URL example: 192.168.1.2/servo/bidet1/open
- URL example: 192.168.1.2/servo/bidet1/close
- URL example: 192.168.1.2/relay/seatkicker1/open
- Servo and relay names are case insensitive in the URL. All other URL parts are case sensitive.
- You might want to fix that.
- Webpage frontend is using jQuery and Bootstrap, because I'm lazy. If you want something more
- efficient and less "wtf is he using jQuery for", do that yourself. I like jQuery because it's
- always 2012 in my mind.
- @author: Tanner McCoolman 2024
- */
- // Define your wifi credentials
- #define WIFI_SSID "SSID"
- #define WIFI_PASSWORD "Password123#"
- // Defining the WiFi channel speeds up the connection:
- #define WIFI_CHANNEL 6
- WebServer server(80);
- bool debug = true;
- const int servoCount = 5;
- String servoNames[5] = { "Bidet1", "Bidet2", "Airhorn1", "Airhorn2", "Fartbox" }; // servo name for URL
- int servoPins[5] = { 13, 33, 26, 32, 25, }; // pin number
- int servoStartPoints[5] = { 0, 0, 0, 0, 0, }; // angle in start position
- int servoMovePoints[5] = { 165, 165, 90, 90, 90, }; // angle to move to when not in start position
- int servoAngleCurrent[5] = { 0, 0, 0, 0, 0, }; // angle it currently is
- int servoAngle[5] = { 0, 0, 0, 0, 0, }; // angle we want it to be
- int servoReturnAfterMove[5] = { 0, 0, 1, 1, 1, }; // go back to default after a time (TRUE = 1)
- int servoWaitAfterMove[5] = { 100, 100, 1000, 1000, 1000, }; // amount of time to wait to go to default (if returnAfterMove = 1)
- unsigned long servoTimers[5] = { 0, 0, 0, 0, 0, }; // holder for the timers
- Servo servos[5];
- const int relayCount = 5;
- String relayNames[5] = { "Gelblaster", "Seatkicker1", "Seatkicker2", "PCPower", "Heaters" }; // servo name for URL
- int relayPins[5] = { 12, 14, 27, 22, 23 }; // pin number
- int relayStartPoints[5] = { 0, 0, 0, 0, 0 }; // start point 0 = off, 1 = on
- int relayStateCurrent[5] = { 0, 0, 0, 0, 0 }; // state it currently is
- int relayState[5] = { 0, 0, 0, 0, 0 }; // state we want it to be
- int relayReturnAfterMove[5] = { 1, 1, 1, 1, 1 }; // go back to default after a time (TRUE = 1)
- int relayWaitAfterMove[5] = { 1400, 500, 500, 1500, 30000 }; // amount of time to wait to go to default (if returnAfterMove = 1)
- unsigned long relayTimers[5] = { 0, 0, 0, 0, 0 }; // holder for the timers
- unsigned long currentMillis; // Current time in ms to compare waitAfterMove
- int steppingDelay = 10; // Amount of time to wait before changing the angle of the servo in a stepping situation
- String triggerElems; // String to hold the JSON of relay/servo names for auto generating the buttons on the frontend
- void sendHtml() {
- // @TODO replace jQuery and full bootstrap, they are 99% bloat for this. I just like jQuery syntax and
- // think Bootstrap makes things look pretty with very little effort
- String response = R"(
- <!DOCTYPE html><html>
- <head>
- <title>Ludwig Punisher</title>
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
- </head>
- <body>
- <div id="button-holder" class="container"></div>
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
- <script>
- $(document).ready(function() {
- var triggerEles = {triggerElems};
- var defaultUrl = "http://10.20.2.51";
- var buttonOpenCloseElem = "<div class=\"row\"><div class=\"col-md-6 col-sm-12 text-end\"><div class=\"d-grid gap-2 py-3\"><button data-trigger=\"{openUrl}\" type=\"button\" class=\"btn btn-success btn-block px-3\"><h2>Open {element}</h2></button></div></div><div class=\"col-md-6 col-sm-12 text-start\"><div class=\"d-grid gap-2 py-3\"><button data-trigger=\"{closeUrl}\" type=\"button\" class=\"btn btn-block btn-danger px-3\"><h2>Close {element}</h2></button></div></div></div>";
- var currentTargets = [];
- for (var key in triggerEles) {
- for (var element of triggerEles[key]) {
- var newUrl = defaultUrl + "/" + key + "/" + element;
- var newButtonElem = buttonOpenCloseElem;
- var newUrlObj = {
- "openUrl": newUrl+"/open",
- "closeUrl": newUrl+"/close",
- "element": element
- };
- for (var placeholder in newUrlObj) {
- newButtonElem = newButtonElem.replaceAll("{"+placeholder+"}", newUrlObj[placeholder]);
- }
- $("#button-holder").append(newButtonElem);
- }
- }
- $("button").click(function(e){
- e.preventDefault();
- var urlTarget = $(this).data('trigger');
- if (currentTargets.includes(urlTarget)) {
- console.log("preventing this due to current target: "+urlTarget);
- return;
- }
- currentTargets.push(urlTarget);
- $.get(urlTarget, function (e) {
- var currentTargetIndex = currentTargets.indexOf(urlTarget);
- if (currentTargetIndex > -1) {
- delete currentTargets[currentTargetIndex];
- }
- });
- });
- });
- </script>
- </body>
- </html>
- )";
- response.replace("{triggerElems}", triggerElems); // Add the servo/relay names in JSON form to the response string
- server.send(200, "text/html", response);
- }
- void setup(void) {
- if (debug) {
- // Serial.begin(115200);
- Serial.begin(9600);
- }
- delay(10);
- WiFi.begin(WIFI_SSID, WIFI_PASSWORD, WIFI_CHANNEL);
- if (debug) {
- Serial.print("Connecting to WiFi ");
- Serial.print(WIFI_SSID);
- // Wait for connection
- while (WiFi.status() != WL_CONNECTED) {
- delay(100);
- Serial.print(".");
- }
- Serial.println(" Connected!");
- Serial.print("IP address: ");
- Serial.println(WiFi.localIP());
- } else {
- while (WiFi.status() != WL_CONNECTED) {
- delay(100);
- }
- }
- server.on("/", sendHtml);
- server.enableCORS(true);
- // Build triggerElems for HTML response
- // @TODO put triggerElems building into a proper function to maximize reusability so servo and relay additions use the same code
- // Start Servo section of triggerElems
- triggerElems = "{\"servo\":";
- int finalIndex = servoCount - 1;
- for (int index = 0; index < servoCount; index++) {
- if (index == 0) {
- triggerElems += "[";
- }
- triggerElems += "\""+servoNames[index]+"\"";
- if (index < finalIndex) {
- triggerElems += ",";
- }
- }
- triggerElems += "],\"relay\":";
- // Start Relay section of triggerElems
- finalIndex = relayCount - 1;
- for (int index = 0; index < relayCount; index++) {
- if (index == 0) {
- triggerElems += "[";
- }
- triggerElems += "\""+relayNames[index]+"\"";
- if (index < finalIndex) {
- triggerElems += ",";
- }
- }
- triggerElems += "]";
- triggerElems += "}"; // end the JSON
- // Output the triggerElems JSON so we can verify things haven't gone horribly wrong
- if (debug) {
- Serial.println(triggerElems);
- }
- // Set up servos
- for (int index = 0; index < servoCount; index++) {
- servos[index].attach(servoPins[index]);
- // servoAngleCurrent[index] = servos[index].read();
- servos[index].write(servoStartPoints[index]);
- if (debug) {
- Serial.println(servoNames[index]+": "+servoAngleCurrent[index]);
- }
- }
- // Set up relays
- for (int index = 0; index < relayCount; index++) {
- pinMode(relayPins[index], OUTPUT);
- if (relayStartPoints[index] == 1) {
- digitalWrite(relayPins[index], HIGH);
- } else {
- digitalWrite(relayPins[index], LOW);
- }
- }
- // Set up relay toggle URLs
- server.on(UriBraces("/relay/{}"), []() {
- String relayPath = server.pathArg(0);
- if (debug) {
- Serial.println(relayPath);
- }
- for (int index = 0; index < relayCount; index++) {
- String relayNameLowerCase = relayNames[index];
- relayNameLowerCase.toLowerCase();
- if (relayPath == relayNames[index] || relayPath == relayNameLowerCase) {
- if (relayState[index] == 1) {
- relayState[index] = 0;
- } else {
- relayState[index] = 1;
- }
- }
- }
- sendHtml();
- });
- // Set up relay switch URLs (specifically turn on or off)
- server.on(UriBraces("/relay/{}/{}"), []() {
- String relayPath = server.pathArg(0);
- String relayAction = server.pathArg(1);
- if (debug) {
- Serial.println(relayPath);
- Serial.println(relayAction);
- }
- relayAction.toLowerCase();
- for (int index = 0; index < relayCount; index++) {
- String relayNameLowerCase = relayNames[index];
- relayNameLowerCase.toLowerCase();
- if (relayPath == relayNames[index] || relayPath == relayNameLowerCase) {
- if (relayAction == "start" || relayAction == "go" || relayAction == "open" || relayAction == "on") {
- relayState[index] = 1;
- relayTimers[index] = millis();
- } else if (relayAction == "stop" || relayAction == "end" || relayAction == "close" || relayAction == "off") {
- relayState[index] = 0;
- }
- }
- }
- sendHtml();
- });
- // Setup Reset URL
- server.on(UriBraces("/reset"), []() {
- if (debug) {
- Serial.println("reseting all");
- }
- // reset servos
- for (int index = 0; index < servoCount; index++) {
- servoAngle[index] = servoStartPoints[index];
- }
- // reset relays
- for (int index = 0; index < relayCount; index++) {
- relayState[index] = relayStartPoints[index];
- }
- sendHtml();
- });
- // Set up servo toggle URLS
- server.on(UriBraces("/servo/{}"), []() {
- String servoPath = server.pathArg(0);
- String servoAction = "toggle";
- if (debug) {
- Serial.println(servoPath);
- Serial.println(servoAction);
- }
- for (int index = 0; index < servoCount; index++) {
- String servoNameLowerCase = servoNames[index];
- servoNameLowerCase.toLowerCase();
- if (servoPath == servoNames[index] || servoPath == servoNameLowerCase) {
- if (debug) {
- Serial.print("Moving ");
- Serial.print(servoNames[index]);
- Serial.print(" to ");
- }
- if (servoAngleCurrent[index] == servoStartPoints[index]) {
- servoAngle[index] = servoMovePoints[index];
- if (debug) {
- Serial.print(servoAngle[index]);
- Serial.print(" deg from ");
- Serial.print(servoAngleCurrent[index]);
- }
- } else if (servoAngleCurrent[index] == servoMovePoints[index]) {
- servoAngle[index] = servoStartPoints[index];
- if (debug) {
- Serial.print(servoAngle[index]);
- Serial.print(" deg from ");
- Serial.print(servoAngleCurrent[index]);
- }
- } else if (debug) {
- Serial.print("nowhere lol");
- }
- if (debug) {
- Serial.println("");
- }
- }
- }
- sendHtml();
- });
- // Set up servo switch URLs
- server.on(UriBraces("/servo/{}/{}"), []() {
- String servoPath = server.pathArg(0);
- String servoAction = server.pathArg(1);
- if (debug) {
- Serial.println(servoPath);
- Serial.println(servoAction);
- }
- if (servoAction == "") {
- servoAction = "toggle";
- }
- for (int index = 0; index < servoCount; index++) {
- String servoNameLowerCase = servoNames[index];
- servoNameLowerCase.toLowerCase();
- if (servoPath == servoNames[index] || servoPath == servoNameLowerCase) {
- if (servoAction == "open" || servoAction == "start") {
- servoAngle[index] = servoMovePoints[index];
- if (debug) {
- Serial.print("opening ");
- Serial.println(servoNames[index]);
- }
- servoTimers[index] = millis();
- } else if (servoAction == "close" || servoAction == "end") {
- servoAngle[index] = servoStartPoints[index];
- if (debug) {
- Serial.print("closing ");
- Serial.println(servoNames[index]);
- }
- } else if (servoAction == "toggle") {
- if (debug) {
- Serial.print("toggling ");
- Serial.println(servoNames[index]);
- }
- if (servoAngleCurrent[index] == servoStartPoints[index]) {
- servoTimers[index] = millis();
- }
- if (servoAngleCurrent[index] == servoStartPoints[index]) {
- servoAngle[index] = servoMovePoints[index];
- } else if (servoAngleCurrent[index] == servoMovePoints[index]) {
- servoAngle[index] = servoStartPoints[index];
- }
- }
- }
- }
- sendHtml();
- });
- server.begin();
- if (debug) {
- Serial.println("HTTP server started");
- }
- }
- void doServoChanges() {
- for (int index = 0; index < servoCount; index++) {
- if (servoAngleCurrent[index] != servoAngle[index]) {
- int bigAngle = (servoAngleCurrent[index] > servoAngle[index]) ? servoAngleCurrent[index] : servoAngle[index];
- int angleStep = (bigAngle % 2 == 0) ? bigAngle / 2 : (bigAngle - 1) / 2;
- int i = servoAngleCurrent[index];
- if (debug) {
- Serial.print("Big Angle: ");
- Serial.print(bigAngle);
- Serial.print(" | ");
- }
- // If the start position is current and we're moving off of that, set up a timer
- if (servoStartPoints[index] == servoAngleCurrent[index]) {
- servoTimers[index] = millis();
- }
- // going down
- if (servoAngleCurrent[index] > servoAngle[index]) {
- if (debug) {
- Serial.print("Going Down. Current Angle: ");
- Serial.print(servoAngleCurrent[index]);
- Serial.print(" Desired Angle: ");
- Serial.print(servoAngle[index]);
- Serial.print(" Angle Step: ");
- Serial.println(angleStep);
- Serial.print("I: ");
- }
- while (i > servoAngle[index]) {
- if (debug) {
- Serial.print(i);
- Serial.print(" ");
- }
- servos[index].write(i);
- delay(steppingDelay);
- i -= angleStep;
- }
- if (debug) {
- Serial.println("");
- }
- // going up
- } else if (servoAngleCurrent[index] < servoAngle[index]) {
- if (debug) {
- Serial.print("Going Up. Current Angle: ");
- Serial.print(servoAngleCurrent[index]);
- Serial.print(" Desired Angle: ");
- Serial.print(servoAngle[index]);
- Serial.print(" Angle Step: ");
- Serial.println(angleStep);
- Serial.print("I: ");
- }
- while (i < servoAngle[index]) {
- if (debug) {
- Serial.print(i);
- Serial.print(" ");
- }
- servos[index].write(i);
- delay(steppingDelay);
- i += angleStep;
- }
- if (debug) {
- Serial.println("");
- }
- }
- servos[index].write(servoAngle[index]);
- servoAngleCurrent[index] = servoAngle[index];
- }
- }
- }
- void doServoReset() {
- for (int index = 0; index < servoCount; index++) {
- if (servoReturnAfterMove[index] == 1 && servoAngleCurrent[index] != servoStartPoints[index]) {
- if (servoWaitAfterMove[index] > 0) {
- if (servoTimers[index] + servoWaitAfterMove[index] < currentMillis) {
- if (debug) {
- Serial.print("Resetting ");
- Serial.print(servoNames[index]);
- Serial.print(" after waiting for ");
- Serial.print(servoWaitAfterMove[index]);
- Serial.println(" ms");
- Serial.print("Reset wait for ");
- Serial.print(servoNames[index]);
- Serial.print(" complete");
- }
- servoAngle[index] = servoStartPoints[index];
- }
- } else {
- if (debug) {
- Serial.print("Resetting ");
- Serial.print(servoNames[index]);
- Serial.println("");
- }
- servoAngle[index] = servoStartPoints[index];
- }
- }
- }
- }
- void doRelayChanges() {
- for (int index = 0; index < relayCount; index++) {
- if (relayStateCurrent[index] != relayState[index]) {
- // Set the timer
- if (relayStateCurrent[index] == relayStartPoints[index]) {
- relayTimers[index] = millis();
- }
- // Write the changes
- if (relayState[index] == 0) {
- digitalWrite(relayPins[index], LOW);
- relayStateCurrent[index] = relayState[index];
- } else if (relayState[index] == 1) {
- digitalWrite(relayPins[index], HIGH);
- relayStateCurrent[index] = relayState[index];
- }
- }
- }
- }
- void doRelayReset() {
- for (int index = 0; index < relayCount; index++) {
- if (relayReturnAfterMove[index] == 1 && relayStateCurrent[index] != relayStartPoints[index]) {
- if (relayWaitAfterMove[index] > 0) {
- if (relayTimers[index] + relayWaitAfterMove[index] < currentMillis ) {
- if (debug) {
- Serial.print("Timer: ");
- Serial.print(relayTimers[index]);
- Serial.print(" | Wait: ");
- Serial.print(relayWaitAfterMove[index]);
- Serial.print(" | Total Time: ");
- Serial.print(relayTimers[index] + relayWaitAfterMove[index]);
- Serial.print(" | currentMillis: ");
- Serial.println(currentMillis);
- Serial.print("Resetting ");
- Serial.print(relayNames[index]);
- Serial.print(" after waiting for ");
- Serial.print(relayWaitAfterMove[index]);
- Serial.println(" ms");
- Serial.print("Reset wait for ");
- Serial.print(relayNames[index]);
- Serial.print(" complete");
- }
- relayState[index] = relayStartPoints[index];
- }
- } else {
- if (debug) {
- Serial.print("Resetting ");
- Serial.print(relayNames[index]);
- Serial.println("");
- }
- relayState[index] = relayStartPoints[index];
- }
- }
- }
- }
- // Since none of the actions set up through URLs actually do anything except
- // change variable numbers, all the real moving gets done in the loop. If you
- // set servoAngle[3] = 90, for example, and servoAngleCurrent[3] is set to 180,
- // this code will move the servo from 180 to 90 and update servoAngleCurrent[3]
- // to be 180.
- void loop(void) {
- currentMillis = millis();
- server.handleClient();
- doServoReset();
- doRelayReset();
- doServoChanges();
- doRelayChanges();
- delay(2);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement