//-------------------------------------------------------------------------
// 2023/07/10
//
// S James Parsons Jr
// www.sjamesparsonsjr.com
//
//-------------------------------------------------------------------------
// to control relay from terminal curl -X GET "http://localhost:9080/update?relay=1&state=1"
//-------------------------------------------------------------------------
// +++ Libraries +++
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
//-------------------------------------------------------------------------
// +++ Variables +++
// Relay
#define RELAY_NO true // Set to true to define Relay as Normally Open (NO)
#define NUM_RELAYS 8 // Set number of relays
const int relayGPIOs[NUM_RELAYS] = {13, 12, 14, 18, 5, 4, 2, 15}; // Assign each GPIO to a relay
const char* PARAM_INPUT_1 = "relay";
const char* PARAM_INPUT_2 = "state";
// Wi-Fi
const char* ssid = "Wokwi-GUEST";// <-- Add to EEPROM
const char* password = "";
AsyncWebServer server(80); // Create AsyncWebServer object on port 80
//-------------------------------------------------------------------------
// +++ Functions +++
//-------------------------------------------------------------------------
// +++ Setup +++
//-------------------------------------------------------------------------
// +++ Loop +++
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 3.0rem;}
p {font-size: 3.0rem;}
body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
.switch {position: relative; display: inline-block; width: 60px; height: 34px}
.switch input {display: none}
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 17px}
.slider:before {position: absolute; content: ""; height: 26px; width: 26px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 34px}
input:checked+.slider {background-color: #2196F3}
input:checked+.slider:before {-webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px)}
</style>
</head>
<body>
<h2>Smart Plug PNS</h2>
<div style = "flex-wrap: wrap;display: flex;">
%BUTTONPLACEHOLDER%
</div>
<script>function toggleCheckbox(element) {
var xhr = new XMLHttpRequest();
if(element.checked){ xhr.open("GET", "/update?relay="+element.id+"&state=1", true); }
else { xhr.open("GET", "/update?relay="+element.id+"&state=0", true); }
xhr.send();
}</script>
</body>
</html>
)rawliteral";
// Replaces placeholder with button section in your web page
String processor(const String& var){
//Serial.println(var);
if(var == "BUTTONPLACEHOLDER"){
String buttons ="";
for(int i=1; i<=NUM_RELAYS; i++){
String relayStateValue = relayState(i);
buttons+= "<div>";
buttons+= "<h4>Switch #" + String(i) + " - GPIO " + relayGPIOs[i-1] + "</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"" + String(i) + "\" "+ relayStateValue +"><span class=\"slider\"></span></label>";
buttons+="</div>";
}
return buttons;
}
return String();
}
String relayState(int numRelay){
if(RELAY_NO){
if(digitalRead(relayGPIOs[numRelay-1])){
return "";
}
else {
return "checked";
}
}
else {
if(digitalRead(relayGPIOs[numRelay-1])){
return "checked";
}
else {
return "";
}
}
return "";
}
void setup(){
Serial.begin(115200); // Serial port for debugging purposes
// Set all relays to off when the program starts - if set to Normally Open (NO), the relay is off when you set the relay to HIGH
for(int i=1; i<=NUM_RELAYS; i++){
pinMode(relayGPIOs[i-1], OUTPUT);
if(RELAY_NO){
digitalWrite(relayGPIOs[i-1], HIGH);
}
else{
digitalWrite(relayGPIOs[i-1], LOW);
}
}
// Connect to Wi-Fi
WiFi.begin(ssid, password, 6); // Channel 6 to improve speed
Serial.print("Connecting to WiFi.");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP()); // Print ESP32 Local IP Address
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Send a GET request to <ESP_IP>/update?relay=<inputMessage>&state=<inputMessage2>
server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage;
String inputParam;
String inputMessage2;
String inputParam2;
// GET input1 value on <ESP_IP>/update?relay=<inputMessage>
if (request->hasParam(PARAM_INPUT_1) & request->hasParam(PARAM_INPUT_2)) {
inputMessage = request->getParam(PARAM_INPUT_1)->value();
inputParam = PARAM_INPUT_1;
inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
inputParam2 = PARAM_INPUT_2;
if(RELAY_NO){
Serial.print("NO ");
digitalWrite(relayGPIOs[inputMessage.toInt()-1], !inputMessage2.toInt());
}
else{
Serial.print("NC ");
digitalWrite(relayGPIOs[inputMessage.toInt()-1], inputMessage2.toInt());
}
}
else {
inputMessage = "No message sent";
inputParam = "none";
}
Serial.println(inputMessage + inputMessage2);
request->send(200, "text/plain", "OK");
});
// Start server
server.begin();
}
void loop() {
}