1. Introduction
In this tutorial, I will show you how to make an application like Raspberry WebGPIO.
The GUI of Web look like below:
- I will create 2 version of this demo:
+ Version 1: without using sdcard to store html code.
+ Version 2: Using sdcard to store html code.
- In order to make this demo, I will reuse 2 previous demos:
Demo 7: How to use Arduino ESP32 to store data to sdcard
Demo 12: How to turn the Arduino ESP32 into a Web Server
2. Hardware
We connect ESP32 to microSD module like below:
[ESP32 IO14 – MOSI MICROSD]
[ESP32 IO12 – MISO MICROSD]
[ESP32 IO27 – SCK MICROSD]
- Here we use boostrap and jquery library. Bootstrap for creating GUI and jquery to handle user click action and create GET request to ESP32 web server.
- Create an Arduino project , save as esp32webgpio with code:
4. Resul
Figure: ESP32 WebGPIO demo
In this tutorial, I will show you how to make an application like Raspberry WebGPIO.
The GUI of Web look like below:
Figure: ESP32 WebGPIO interface
- From this GUI you can select which GPIO, direction (Input/Output), the value (HIGH/LOW) need to be written to GPIO in output mode or read the value of GPIO in input mode. The status or read value will be showed in Status column.- I will create 2 version of this demo:
+ Version 1: without using sdcard to store html code.
+ Version 2: Using sdcard to store html code.
- In order to make this demo, I will reuse 2 previous demos:
Demo 7: How to use Arduino ESP32 to store data to sdcard
Demo 12: How to turn the Arduino ESP32 into a Web Server
2. Hardware
We connect ESP32 to microSD module like below:
Figure: ESP32 connect microSD module
Here we connect:
[ESP32 IO26 – CS MICROSD][ESP32 IO14 – MOSI MICROSD]
[ESP32 IO12 – MISO MICROSD]
[ESP32 IO27 – SCK MICROSD]
3. Software
I created 2 versions: with and without sdcard
3.1 Without sdcard
To test it from web browser go to http://ip_address_of_esp32
3.2 With sdcard
I created 2 versions: with and without sdcard
3.1 Without sdcard
To test it from web browser go to http://ip_address_of_esp32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | #include <WiFiClient.h> #include <ESP32WebServer.h> #include <WiFi.h> /* thay doi ssid va password */ const char* ssid = "dd-wrt"; const char* password = "0000000000"; ESP32WebServer server(80); /* day la phan code giao dien, dung jquery va boostrap */ char res[3000] = "<!DOCTYPE html>\n\ <html>\n\ <head>\n\ <meta name='viewport' content='width=device-width, initial-scale=1'>\n\ <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>\n\ <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>\n\ <script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>\n\ </head>\n\ <body>\n\ \n\ <div class='container'>\n\ <h2>iotsharing.com - ESP32 WEBGPIO</h2>\n\ </br> \n\ <table class='table'>\n\ <thead>\n\ <tr>\n\ <th>Status</th>\n\ <th>GPIO</th>\n\ <th>In/Out</th>\n\ <th>Write HIGH</th>\n\ <th>Write LOW</th>\n\ <th>Read</th>\n\ </tr>\n\ </thead>\n\ <tbody>\n\ <tr>\n\ <td> \n\ <button class='btn btn-default dropdown-toggle' type='status' id='status' >#status</button>\n\ </td>\n\ <td> \n\ <select id = 'gpio' class='btn btn-default dropdown-toggle'>\n\ <option>GPIO0</option>\n\ <option>GPIO2</option>\n\ <option>GPIO4</option>\n\ </select>\n\ </td>\n\ <td> \n\ <select id = 'dir' class='btn btn-default dropdown-toggle'>\n\ <option>Out</option>\n\ <option>In</option>\n\ </select>\n\ </td>\n\ <td> \n\ <button class='btn btn-default dropdown-toggle' type='button' id='write1' >Write HIGH</button>\n\ </td>\n\ <td> \n\ <button class='btn btn-default dropdown-toggle' type='button' id='write0' >Write LOW</button>\n\ </td>\n\ <td> \n\ <button class='btn btn-default dropdown-toggle' type='button' id='read' >Read</button>\n\ </td>\n\ </tr>\n\ </tbody>\n\ </table> \n\ </div>\n\ <script>\n\ function ml(gpio, dir, value) {\n\ var io = gpio.replace('GPIO', '');\n\ var d = (dir == 'In') ? 'i' : 'o';\n\ if(value != null){\n\ var v = (value == 'Write LOW') ? '0' : '1';\n\ return (io+d+v); \n\ } else {\n\ return (io+d); \n\ }\n\ }\n\ $(function() {\n\ $('#status').css('background','grey');\n\ $('#write1').on('click', function (e) {\n\ var dir = $('#dir').val();\n\ $('#status').css('background','red');\n\ $('#status').html('#status');\n\ if(dir == 'In'){\n\ alert('direction is In');\n\ } else {\n\ var gpio = $('#gpio').val();\n\ var value = $('#write1').text();\n\ $.get('/req?out=' + ml(gpio, dir, value), function(d, s){\n\ $('#status').css('background','green');\n\ $('#status').html(s);\n\ }); \n\ }\n\ })\n\ $('#write0').on('click', function (e) {\n\ var dir = $('#dir').val();\n\ $('#status').css('background','red');\n\ $('#status').html('#status');\n\ if(dir == 'In'){\n\ alert('direction is In');\n\ } else {\n\ var gpio = $('#gpio').val();\n\ var value = $('#write0').text();\n\ $.get('/req?out=' + ml(gpio, dir, value), function(d, s){\n\ $('#status').css('background','green');\n\ $('#status').html(s);\n\ }); \n\ }\n\ })\n\ $('#read').on('click', function (e) {\n\ var dir = $('#dir').val();\n\ $('#status').css('background','red');\n\ $('#status').html('#value');\n\ if(dir == 'Out'){\n\ alert('direction is Out');\n\ } else {\n\ var gpio = $('#gpio').val();\n\ $.get('/req?in=' + ml(gpio, dir, null), function(d, s){\n\ if(s == 'success'){\n\ $('#status').css('background','yellow');\n\ $('#status').html(d);\n\ }else{\n\ $('#status').html(s);\n\ } \n\ }); \n\ }\n\ })\n\ });\n\ </script>\n\ </body>\n\ </html>"; void handleRoot() { server.send(200, "text/html", res); } /* ham nay de xu lu yeu cau cua nguoi dung req?out=0o1 -> user request GPIO0 output gia tri HIGH req?in=0i -> user request GPIO0 input */ void handleGPIO() { Serial.println("got request"); if(server.args() > 0){ String req = server.argName(0); if(req == "out"){ server.send(200, "text/plain", "OK"); /* parse req */ String param = server.arg(0); int p = param.indexOf('o'); int pin = param.substring(0,p).toInt(); int value = param.substring(p+1).toInt(); /* cai dat pin va ghi gia tri */ pinMode(pin, OUTPUT); digitalWrite(pin, value); }else if(req == "in"){ String param = server.arg(0); /* parse req */ int p = param.indexOf('i'); int pin = param.substring(0,p).toInt(); /* cai dat pin va doc input */ pinMode(pin, INPUT); int value = digitalRead(pin); char str[3] = {0,0,0}; sprintf(str, "%d", value); /* respond cho nguoi dung */ server.send(200, "text/plain", str); } } } /* cannot handle request so return 404 */ void handleNotFound(){ String message = "File Not Found\n\n\n\n"; server.send(404, "text/plain", message); } void setup(void){ Serial.begin(115200); WiFi.begin(ssid, password); Serial.println(""); /*cho wifi ket not */ while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); /* nhung ham nay se duoc goi khi co user request va respond */ server.on("/", handleRoot); /* this callback handle GPIO request and respond*/ server.on("/req", handleGPIO); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); } void loop(void){ server.handleClient(); } |
- Create a index.html file in memory card at root "/" with content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </head> <body> <div class="container"> <h2>iotsharing.com - ESP32 WEBGPIO</h2> </br> <table class="table"> <thead> <tr> <th>Status</th> <th>GPIO</th> <th>In/Out</th> <th>Write HIGH</th> <th>Write LOW</th> <th>Read</th> </tr> </thead> <tbody> <tr> <td> <button class="btn btn-default dropdown-toggle" type="status" id="status" >#status</button> </td> <td> <select id = "gpio" class="btn btn-default dropdown-toggle"> <option>GPIO0</option> <option>GPIO2</option> <option>GPIO4</option> </select> </td> <td> <select id = "dir" class="btn btn-default dropdown-toggle"> <option>Out</option> <option>In</option> </select> </td> <td> <button class="btn btn-default dropdown-toggle" type="button" id="write1" >Write HIGH</button> </td> <td> <button class="btn btn-default dropdown-toggle" type="button" id="write0" >Write LOW</button> </td> <td> <button class="btn btn-default dropdown-toggle" type="button" id="read" >Read</button> </td> </tr> </tbody> </table> </div> <script> function ml(gpio, dir, value) { var io = gpio.replace("GPIO", ""); var d = (dir == "In") ? "i" : "o"; if(value != null){ var v = (value == "Write LOW") ? "0" : "1"; return (io+d+v); } else { return (io+d); } } $(function() { $("#status").css("background","grey"); $('#write1').on('click', function (e) { var dir = $('#dir').val(); $("#status").css("background","red"); $("#status").html("#status"); if(dir == "In"){ alert("direction is In"); } else { var gpio = $('#gpio').val(); var value = $('#write1').text(); $.get("/req?out=" + ml(gpio, dir, value), function(d, s){ $("#status").css("background","green"); $("#status").html(s); }); } }) $('#write0').on('click', function (e) { var dir = $('#dir').val(); $("#status").css("background","red"); $("#status").html("#status"); if(dir == "In"){ alert("direction is In"); } else { var gpio = $('#gpio').val(); var value = $('#write0').text(); $.get("/req?out=" + ml(gpio, dir, value), function(d, s){ $("#status").css("background","green"); $("#status").html(s); }); } }) $('#read').on('click', function (e) { var dir = $('#dir').val(); $("#status").css("background","red"); $("#status").html("#value"); if(dir == "Out"){ alert("direction is Out"); } else { var gpio = $('#gpio').val(); $.get("/req?in=" + ml(gpio, dir, null), function(d, s){ if(s == "success"){ $("#status").css("background","yellow"); $("#status").html(d); }else{ $("#status").html(s); } }); } }) }); </script> </body> </html> |
- Create an Arduino project , save as esp32webgpio with code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | #include <WiFiClient.h> #include <ESP32WebServer.h> #include <WiFi.h> #include <ESPmDNS.h> #include <SPI.h> #include <mySD.h> const char* ssid = "dd-wrt"; const char* password = "0000000000"; ESP32WebServer server(80); void handleRoot() { /* we load the chart.html from microSD */ File myFile = SD.open("INDEX~1.HTM"); if (myFile) { /* respond the content of file to client by calling streamFile()*/ size_t sent = server.streamFile(myFile, "text/html"); /* close the file */ myFile.close(); } else { Serial.println("error opening test.txt"); } } /* this callback is to handle user request req?out=0o1 -> user request GPIO0 output value HIGH req?in=0i -> user request GPIO0 input */ void handleGPIO() { if(server.args() > 0){ String req = server.argName(0); if(req == "out"){ server.send(200, "text/plain", "OK"); /* this code is to parse req */ String param = server.arg(0); int p = param.indexOf('o'); int pin = param.substring(0,p).toInt(); int value = param.substring(p+1).toInt(); /* set pin and output value */ pinMode(pin, OUTPUT); digitalWrite(pin, value); }else if(req == "in"){ String param = server.arg(0); /* this code is to parse req */ int p = param.indexOf('i'); int pin = param.substring(0,p).toInt(); /*set pin and read input */ pinMode(pin, INPUT); int value = digitalRead(pin); char str[3] = {0,0,0}; sprintf(str, "%d", value); /* respond the read value */ server.send(200, "text/plain", str); } } } /* cannot handle request so return 404 */ void handleNotFound(){ String message = "File Not Found\n\n"; server.send(404, "text/plain", message); } void setup(void){ Serial.begin(115200); WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); if (MDNS.begin("esp32")) { Serial.println("MDNS responder started"); } /* register the callbacks to process client request */ /* root request we will read the memory card to get the content of chrt.html and respond that content to client */ server.on("/", handleRoot); /* this callback handle GPIO request and respond*/ server.on("/req", handleGPIO); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); Serial.print("Initializing SD card..."); /* initialize microSD */ if (!SD.begin(26, 14, 12, 27)) { Serial.println("initialization failed!"); return; } Serial.println("initialization done."); } void loop(void){ server.handleClient(); } |
Figure: ESP32 WebGPIO demo
2 Comments