2022年1月2日 星期日

ESP32 Async Web Server & MQTT – Control LED

 ESP32 Async Web Server & MQTT  – Control LED

源自於https://randomnerdtutorials.com/esp32-async-web-server-espasyncwebserver-library/










// Import required libraries

#include <WiFi.h>

#include <AsyncTCP.h>

#include <ESPAsyncWebServer.h>


//================MQTT=====================

#include <PubSubClient.h>  //MQTT


// Replace with your network credentials

//const char* ssid = "REPLACE_WITH_YOUR_SSID";

//const char* password = "REPLACE_WITH_YOUR_PASSWORD";

const char* ssid     = "TOTOLINK_A3002MU";

const char* password = "24063173";


const char* PARAM_INPUT_1 = "output";

const char* PARAM_INPUT_2 = "state";


String inputMessage1;

String inputMessage2;


const int output2 = 2;

const int output4 = 4;

const int output33 = 33;

// Auxiliar variables to store the current output state

String output2State = "off";

String output4State = "off";

String output33State = "off";


// Create AsyncWebServer object on port 80

AsyncWebServer server(80);


//================MQTT=====================

const char* mqtt_server = "broker.mqtt-dashboard.com" ; //MQTT

//================MQTT=====================

WiFiClient espClient;

PubSubClient client(espClient);

long lastMsg = 0;

char msg[50];


//=========================================

const char index_html[] PROGMEM = R"rawliteral(

<!DOCTYPE HTML><html>

<head>

  <title>ESP Web Server</title>

  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link rel="icon" href="data:,">

  <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: 120px; height: 68px} 

    .switch input {display: none}

    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}

    .slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 3px}

    input:checked+.slider {background-color: #b30000}

    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}

  </style>

</head>

<body>

  <h2>ESP Web Server</h2>

  %BUTTONPLACEHOLDER%

<script>function toggleCheckbox(element) {

  var xhr = new XMLHttpRequest();

  if(element.checked){ xhr.open("GET", "/update?output="+element.id+"&state=1", true); }

  else { xhr.open("GET", "/update?output="+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 = "";

    buttons += "<h4>Output - GPIO 2</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"2\" " + outputState(2) + "><span class=\"slider\"></span></label>";

    buttons += "<h4>Output - GPIO 4</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"4\" " + outputState(4) + "><span class=\"slider\"></span></label>";

    buttons += "<h4>Output - GPIO 33</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"33\" " + outputState(33) + "><span class=\"slider\"></span></label>";

    return buttons;

  }

  return String();

}

//=========================================

String outputState(int output){

  if(digitalRead(output)){

    return "checked";

  }    

  else {

    return "";

  }

}

//================MQTT=====================

void callback(char* topic, byte* message, unsigned int length) {

  Serial.print("Message arrived on topic: ");

  Serial.print(topic);

  Serial.print(". Message: ");

  String messageTemp;

  

  for (int i = 0; i < length; i++) {

    Serial.print((char)message[i]);

    messageTemp += (char)message[i];

  }

  Serial.println();


  // Feel free to add more if statements to control more GPIOs with MQTT


  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". 

  // Changes the output state according to the message

  if (String(topic) == "alex9ufo/esp32/input/LED2") {

    Serial.print("Changing output to ");

    if(messageTemp == "on"){

      Serial.println("on");

      output2State = "on";

      digitalWrite(output2, HIGH);

    }

    else if(messageTemp == "off"){

      Serial.println("off");

      output2State = "off";

      digitalWrite(output2, LOW);

    }

  }


 if (String(topic) == "alex9ufo/esp32/input/LED4") {

    Serial.print("Changing output to ");

    if(messageTemp == "on"){

      Serial.println("on");

      output4State = "on";

      digitalWrite(output4, HIGH);

    }

    else if(messageTemp == "off"){

      Serial.println("off");

      output4State = "off";

      digitalWrite(output4, LOW);

    }

  }

  

 if (String(topic) == "alex9ufo/esp32/input/LED33") {

    Serial.print("Changing output to ");

    if(messageTemp == "on"){

      Serial.println("on");

      output33State = "on";

      digitalWrite(output33, HIGH);

    }

    else if(messageTemp == "off"){

      Serial.println("off");

      output33State = "off";

      digitalWrite(output33, LOW);

    }

  }

  

  loop_mqtt();

  

 }

//================MQTT=====================

void reconnect() {

  // Loop until we're reconnected

  while (!client.connected()) {

    Serial.print("Attempting MQTT connection...");

    // Attempt to connect

    if (client.connect("ESP32Client")) {

      Serial.println("connected");

      // Subscribe

      client.subscribe("alex9ufo/esp32/input/LED2");

      client.subscribe("alex9ufo/esp32/input/LED4");

      client.subscribe("alex9ufo/esp32/input/LED33");            

    } else {

      Serial.print("failed, rc=");

      Serial.print(client.state());

      Serial.println(" try again in 5 seconds");

      // Wait 5 seconds before retrying

      delay(5000);

    }

  }

}

//================MQTT===================== 

void loop_mqtt(){

  if (!client.connected()) {

    reconnect();

  }

  client.loop();

  long now = millis();

  if (now - lastMsg > 5000) {

    lastMsg = now;

    

    client.publish("alex9ufo/esp32/output/LED2", String(output2State).c_str());

    client.publish("alex9ufo/esp32/output/LED4", String(output4State).c_str());

    client.publish("alex9ufo/esp32/output/LED33", String(output33State).c_str());    

  }  

}

//=========================================


void setup(){

  // Serial port for debugging purposes

  Serial.begin(115200);


  pinMode(2, OUTPUT);

  digitalWrite(2, LOW);

  pinMode(4, OUTPUT);

  digitalWrite(4, LOW);

  pinMode(33, OUTPUT);

  digitalWrite(33, LOW);

  

  // Connect to Wi-Fi

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(1000);

    Serial.println("Connecting to WiFi..");

  }


  // Print ESP Local IP Address

  Serial.println(WiFi.localIP());


  // 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?output=<inputMessage1>&state=<inputMessage2>

  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {

    //String inputMessage1;

    //String inputMessage2;

    // GET input1 value on <ESP_IP>/update?output=<inputMessage1>&state=<inputMessage2>

    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {

      inputMessage1 = request->getParam(PARAM_INPUT_1)->value();

      inputMessage2 = request->getParam(PARAM_INPUT_2)->value();

      digitalWrite(inputMessage1.toInt(), inputMessage2.toInt());

    }

    else {

      inputMessage1 = "No message sent";

      inputMessage2 = "No message sent";

    }

    Serial.print("GPIO: ");

    Serial.print(inputMessage1);

    Serial.print(" - Set to: ");

    Serial.println(inputMessage2); 

       

    Serial.println(inputMessage1.substring(0,1));

    Serial.println(inputMessage2.substring(0));

    

    //=========================================

    if (inputMessage1.substring(0,1)=="2"){

        if (inputMessage2.substring(0,1)=="1") {

          output2State="on";

          //client.publish("alex9ufo/esp32/output/LED2", String("on").c_str());

        } else {

          output2State="off";

          client.publish("alex9ufo/esp32/output/LED2", String("off").c_str());

        }

    }

    //=========================================

    if (inputMessage1.substring(0,1)=="4"){

        if (inputMessage2.substring(0,1)=="1") {

          output4State="on";

          //client.publish("alex9ufo/esp32/output/LED4", String("on").c_str());

        } else {

          output4State="off";          

          client.publish("alex9ufo/esp32/output/LED4", String("off").c_str());

        }

 

    }

    //=========================================

    if (inputMessage1.substring(0,2)=="33"){

        if (inputMessage2.substring(0,1)=="1" ){

          output33State="on";          

          //client.publish("alex9ufo/esp32/output/LED33", String("on").c_str());

        } else {

          output2State="off";          

          //client.publish("alex9ufo/esp32/output/LED33", String("off").c_str());

        }

 

    }

    

    //=========================================

    request->send(200, "text/plain", "OK");

  });


  // Start server

  server.begin();

  //================MQTT===================== 

  client.setServer(mqtt_server, 1883);

  client.setCallback(callback);

}


//=========================================

void loop() {

  loop_mqtt();

}



[{"id":"5e289c8ea4044b2c","type":"mqtt in","z":"9f46f02887319d42","name":"","topic":"alex9ufo/esp32/output/LED2","qos":"1","datatype":"auto","broker":"3d43a51a.c133a2","nl":false,"rap":true,"rh":0,"x":380,"y":80,"wires":[["33bfcb1ee767c120","fcfcca7aa513e04a"]]},{"id":"0e80ae8c04659e32","type":"mqtt in","z":"9f46f02887319d42","name":"","topic":"alex9ufo/esp32/output/LED4","qos":"1","datatype":"auto","broker":"3d43a51a.c133a2","nl":false,"rap":true,"rh":0,"x":380,"y":140,"wires":[["2381afd0958ddec5","33bfcb1ee767c120"]]},{"id":"100d4757648edfe6","type":"ui_switch","z":"9f46f02887319d42","name":"","label":"switch LED2","tooltip":"","group":"fc89dc38.347898","order":19,"width":"5","height":4,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":330,"y":360,"wires":[["17337d056f64cfac"]],"info":"<i class=\"fa fa-camera-retro fa-3x\"></i> fa-3x"},{"id":"1c64f4deecb782d4","type":"ui_switch","z":"9f46f02887319d42","name":"","label":"switch LED4","tooltip":"","group":"fc89dc38.347898","order":21,"width":"5","height":4,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":330,"y":400,"wires":[["372d7cf1744c2ade"]],"info":"<i class=\"fa fa-camera-retro fa-3x\"></i> fa-3x"},{"id":"8c66feccb8ba7465","type":"ui_led","z":"9f46f02887319d42","order":2,"group":"fc89dc38.347898","width":"5","height":4,"label":"LED2","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"#000000","value":"false","valueType":"bool"},{"color":"#0000ff","value":"true","valueType":"bool"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":true,"name":"","x":770,"y":80,"wires":[],"info":".led {\r\n    float: right;\r\n    padding: 3px;\r\n    width: 10px;\r\n    height: 10px;\r\n    margin: 5px 5px 5px 5px;\r\n    border-radius: 50%;\r\n    \r\n}\r\n</style>\r\n\r\n<div><span class=\"led\" style=\"background-color: {{msg.payload}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.payload}} 0 3px 15px;\"></span></div>```"},{"id":"6a8fe6d2114888b3","type":"ui_led","z":"9f46f02887319d42","order":4,"group":"fc89dc38.347898","width":"5","height":4,"label":"LED4","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"#000000","value":"false","valueType":"bool"},{"color":"#ff0000","value":"true","valueType":"bool"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":true,"name":"","x":770,"y":140,"wires":[]},{"id":"f0ee2c75a75392bb","type":"mqtt in","z":"9f46f02887319d42","name":"","topic":"alex9ufo/esp32/output/LED33","qos":"1","datatype":"auto","broker":"3d43a51a.c133a2","nl":false,"rap":true,"rh":0,"x":380,"y":200,"wires":[["04cefb96dcc34818","33bfcb1ee767c120"]]},{"id":"06cc6e28dc7c6bee","type":"ui_led","z":"9f46f02887319d42","order":4,"group":"fc89dc38.347898","width":"5","height":4,"label":"LED33","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"#000000","value":"false","valueType":"bool"},{"color":"#ffff00","value":"true","valueType":"bool"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":true,"name":"","x":770,"y":200,"wires":[]},{"id":"d37a12e1f2ca3f44","type":"ui_switch","z":"9f46f02887319d42","name":"","label":"switch LED33","tooltip":"","group":"fc89dc38.347898","order":21,"width":"5","height":4,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":340,"y":440,"wires":[["146d17408dd1ff9f"]],"info":"<i class=\"fa fa-camera-retro fa-3x\"></i> fa-3x"},{"id":"8fd5ff06add949bd","type":"mqtt out","z":"9f46f02887319d42","name":"","topic":"alex9ufo/esp32/input/LED2","qos":"1","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"3d43a51a.c133a2","x":700,"y":360,"wires":[]},{"id":"81b060facfdb6348","type":"mqtt out","z":"9f46f02887319d42","name":"","topic":"alex9ufo/esp32/input/LED4","qos":"1","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"3d43a51a.c133a2","x":700,"y":400,"wires":[]},{"id":"e0067ec1eb8d37a5","type":"mqtt out","z":"9f46f02887319d42","name":"","topic":"alex9ufo/esp32/input/LED33","qos":"1","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"3d43a51a.c133a2","x":700,"y":440,"wires":[]},{"id":"17337d056f64cfac","type":"function","z":"9f46f02887319d42","name":"","func":"var onoff=msg.payload;\n\nif (onoff === true) {\n\tmsg.payload='on';\n} \nelse {\n    msg.payload='off';\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":360,"wires":[["8fd5ff06add949bd"]]},{"id":"372d7cf1744c2ade","type":"function","z":"9f46f02887319d42","name":"","func":"var onoff=msg.payload;\n\nif (onoff === true) {\n\tmsg.payload='on';\n} \nelse {\n    msg.payload='off';\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":400,"wires":[["81b060facfdb6348"]]},{"id":"146d17408dd1ff9f","type":"function","z":"9f46f02887319d42","name":"","func":"var onoff=msg.payload;\n\nif (onoff === true) {\n\tmsg.payload='on';\n} \nelse {\n    msg.payload='off';\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":440,"wires":[["e0067ec1eb8d37a5"]]},{"id":"2381afd0958ddec5","type":"function","z":"9f46f02887319d42","name":"","func":"var onoff=msg.payload;\n\nif (onoff === \"on\") {\n\n//if (onoff === \"on\\n\") {    \n\tmsg.payload=true;\n} \nelse {\n    msg.payload=false;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":140,"wires":[["6a8fe6d2114888b3"]]},{"id":"04cefb96dcc34818","type":"function","z":"9f46f02887319d42","name":"","func":"var onoff=msg.payload;\n\nif (onoff === \"on\") {\n\n//if (onoff === \"on\\n\") {    \n\tmsg.payload=true;\n} \nelse {\n    msg.payload=false;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":200,"wires":[["06cc6e28dc7c6bee"]]},{"id":"33bfcb1ee767c120","type":"debug","z":"9f46f02887319d42","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":610,"y":240,"wires":[]},{"id":"fcfcca7aa513e04a","type":"function","z":"9f46f02887319d42","name":"","func":"var onoff=msg.payload;\n\nif (onoff === \"on\") {\n\n//if (onoff === \"on\\n\") {    \n\tmsg.payload=true;\n} \nelse {\n    msg.payload=false;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":80,"wires":[["8c66feccb8ba7465"]]},{"id":"3d43a51a.c133a2","type":"mqtt-broker","name":"broker.mqtt-dashboard.com","broker":"broker.mqtt-dashboard.com","port":"1883","clientid":"","usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willRetain":"false","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"fc89dc38.347898","type":"ui_group","name":"LED show","tab":"ec4c23e9246d7836","order":1,"disp":true,"width":16,"collapse":false,"className":""},{"id":"ec4c23e9246d7836","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

沒有留言:

張貼留言

2024_09 作業3 以Node-Red 為主

 2024_09 作業3  (以Node-Red 為主  Arduino 可能需要配合修改 ) Arduino 可能需要修改的部分 1)mqtt broker  2) 主題Topic (發行 接收) 3) WIFI ssid , password const char br...