|
Static Web siteA static web page contains HTML code and requires no server action other than returning the text as HTTP response. To simplify the file management, only a single page can be saved. The HTML text is transferred to the ESP32 using the saveHTML() command. // SaveHTML1.ino #include <linkup.h> void s(const char* line) { saveHTML(line); } void setup() { Serial.begin(9600); Wire.begin(); Serial.println("Transferring HTML file..."); s("<!DOCTYPE html>\n"); s("<html>\n"); s("<head>"); s("<meta name='viewport' content='width=device-width, initial-scale=1'>"); s("</head>\n"); s("<body>\n"); s("<h1>Welcome to the Arduino</h1>\n"); s("<p>Enjoy programming!</p>\n"); s("</body>\n"); s("</html>\n"); s("\0"); Serial.println("done"); } void loop() {} The LinkUp first logs in a existing access point with the SSID/Password with the function connectAP that returns the IP address that must be known as browser URL. It is written to the Serial console. startHTTPServer(onRequest) is a blocking function that starts the server and registers the callback function onRequest that is called when a HTTP GET request arrives. The parameters provides the information as char array from the URL, e.g. the host, the path (string) and the query parameters. response returns information for the HTTP response. Here nothing is returned, so just the downloaded HTML text is send to the browser. Only HTTP GET requests are supported. // WebServer1.ino #include <linkup.h> void onRequest(char* clientIP, char* filename, char* params, char* response) { } void setup() { char reply[20]; Serial.begin(9600); Wire.begin(); Serial.println("Connecting"); terminateHTTPServer(); connectAP("myssid", "mypassword", reply); Serial.println(reply); startHTTPServer(onRequest); } void loop() {} Since the HTTPServer is blocking, the ESP32 should be resetted manually before the next program is run. It can also be deblocked by calling terminateHTTPServer() as in this example. The browser shows: If a terminal program (e.g. puTTY, 115200 baud) is connected to the ESP32, debug information is written there: Wait for master command... The output shows that the ESP32 is waiting for a command from the micro:bit. Command ID 5 starts the HTTP server that is waiting on a blocking accept() for an incomming TCP connection. When this happens it extracts the URL from the HTTP GET request, sends the information to the micro:bit and waits for a reply that arrives after 0.26 s. Then it sends the HTTP response to the client and waits for the next connection. The whole process is hidden to the application programmer. Instead of using an external WLAN router, an local access point can be started on the ESP32 using the function createAP() that takes the ssid and the password (empty, if no password is reequired). This is useful for home automation and remote control. // WebServer1.ino #include <linkup.h> void onRequest(char* clientIP, char* filename, char* params, char* response) { } void setup() { Serial.begin(9600); Wire.begin(); Serial.println("Creating access point"); terminateHTTPServer(); createAP("arduino", ""); startHTTPServer(onRequest); } void loop() {} To access it, you must first log in to the access point arduino with no password and then select the URL 192.168.4.1 in your browser
Interactive (dynamic) Web siteAn interactive Web page contains information as part of the URL or as query parameters that is used by the Webserver to perform particular actions. In this example the URL is supplemented with /on or /off. that is used to switch on or off a hardware device (here for the demonstration just the LED on Arduino's port 13). # SaveHTML2.py from linkup import * html = """<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Welcome to the micro:bit</h2> <p><a href="on">Light On</a></p> <p><a href="off">Light Off</a></p> </body> </html> """ print("Saving HTML...") saveHTML(html) print("Done") The code to run the server that connects to an existing router is simple. The callback onRequest() uses the filename parameter to check if /on or /off has been sent. // WebServer2.ino #include <linkup.h> void turnOn() { digitalWrite(13, HIGH); Serial.println("Device switched on"); } void turnOff() { digitalWrite(13, LOW); Serial.println("Device switched off"); } void onRequest(char* clientIP, char* filename, char* params, char* response) { if (strcmp(filename, "/on") == 0) turnOn(); else if (strcmp(filename, "/off") == 0) turnOff(); } void setup() { char reply[20]; pinMode(13, OUTPUT); turnOff(); Serial.begin(9600); Wire.begin(); Serial.println("Connecting"); terminateHTTPServer(); connectAP("myssid", "mypassword", reply); Serial.println(reply); startHTTPServer(onRequest); } void loop() {} The browser shows: Two buttons can be used to embellish the display: # SaveHTML2a.py from linkup import * html = """<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Welcome to the micro:bit</H2> <button style="font-size:22px; height:50px;width:130px" onclick="window.location.href='on'">Light On</button> <button style="font-size:22px; height:50px;width:130px" onclick="window.location.href='off'">Light Off</button> </body> </html> """ print("Saving HTML...") saveHTML(html) print("Done") The browser now shows:
Use of URL query parametersInformation can transferred using query parameters. The callback function onRequest() receives these as a character array in the format {key1=value1,key2=value2,...}. In this example the returned Web page contains a text entry that reports the current state of the system, namely the line Current state: on resp. Current state: off To do this, string format parameters are used in the HTML text: Current state: %s<br> The HTML uses a HTTP form element to generate the query strings and is downloaded with: // SaveHTML3.ino #include <linkup.h> void s(const char* line) { saveHTML(line); } void setup() { Serial.begin(9600); Wire.begin(); Serial.println("Transferring HTML file..."); s("<!DOCTYPE html>\n"); s("<html>\n"); s("<head>"); s("<meta name='viewport' content='width=device-width, initial-scale=1'>"); s("</head>\n"); s("<body>\n"); s("<h1>Arduino Switch</h1>\n"); s("<form method='get'>\n"); s("<input type='submit' style='font-size:22px; height:50px;\n"); s("width:110px' name='btn' value='on'/>\n"); s("<input type='submit' style='font-size:22px; height:50px;\n"); s("width:110px' name='btn' value='off'/>\n"); s("</form><br>\n"); s("Current state: %s<br>\n"); s("</body>\n"); s("</html>\n"); s("\0"); Serial.println("done"); } void loop() {} The values of these format parameters are passed back to the ESP32 by the return value of the onRequest() calllback. When it is returned as a list in format [value1, value2, ...] the ESP32 recognizes the list elements as format parameters and inserts them in the HTML page before returning the page to the browser. The code on the Arduino is as follows: // WebServer3.ino #include <linkup.h> char state[10] = "off"; void turnOn() { digitalWrite(13, HIGH); Serial.println("Device switched on"); } void turnOff() { digitalWrite(13, LOW); Serial.println("Device switched off"); } void onRequest(char* clientIP, char* filename, char* params, char* response) { Serial.println(params); if (strcmp(params, "{btn=on}") == 0) { strcpy(state, "on"); turnOn(); } if (strcmp(params, "{btn=off}") == 0) { strcpy(state, "off"); turnOff(); } strcpy(response, "["); strcat(response, state); strcat(response, "]"); } void setup() { char reply[20]; pinMode(13, OUTPUT); turnOff(); Serial.begin(9600); Wire.begin(); Serial.println("Connecting"); terminateHTTPServer(); connectAP("myssid", "mypassword", reply); Serial.println(reply); startHTTPServer(onRequest); } void loop() {} When the Web client enters the first time, it does not send any query parameters and params is just the empty paranthesis {}. In this case only the current state is returned and no switching action is perfomed. As seen the return value is a list with the format parameters, which are inserted into the the HTML page (respecting the given order if more than one element is in the list). For home automation applications, a local access point on the micro:bit could be used. In a terminal window of the ESP32 you can follow what is actually going on: -->blocking accept
| ||