Tiny HTTP server controlling a DigitalOutput.
Turn LED1, or other digital output, on/off using a web browser.
In this example we create a HTTP server for the STM32F407VET6 black board that will serve a simple Web page to remotely turn LED1, or other digital output, on/off by using a web browser.
Notice that DHCP is turned on by default. The IP address assigned to the WebSwitch server along with an instruction how to use it is printed to the connected PC's serial terminal window during program start up.
To use static IP address uncomment and adjust line #221 in main.cpp.
A DP83848 module is used as Ethernet interface.
Wiring
DP83848 module | STM32F407VET6 board | |||
---|---|---|---|---|
VCC | <=> | +3.3V | ||
GND | <=> | GND | ||
MDIO | <=> | PA_2 | ||
MDC | <=> | PC_1 | ||
OSCIN | <=> | PA_1 | ||
CRS | <=> | PA_7 | ||
RX0 | <=> | PC_4 | ||
RX1 | <=> | PC_5 | ||
TX_EN | <=> | PB_11 | ||
TX0 | <=> | PB_12 | ||
TX1 | <=> | PB_13 |
Notice that because the RX_ER
line is not used the DP83848 module doesn't have to be modified.
The project was inspired by the Tuxgraphics Web Switch. Thank you Guido!
main.cpp
- Committer:
- hudakz
- Date:
- 2020-10-29
- Revision:
- 10:6860e839277e
- Parent:
- 9:3716ffcf2f27
File content as of revision 10:6860e839277e:
#include "mbed.h" #include "EthernetInterface.h" #include "TCPSocket.h" #include <stdio.h> #include <string> DigitalOut led(PA_6); FileHandle* mbed::mbed_override_console(int) { static BufferedSerial arch_max_serial1(PA_9, PA_10, 9600); return &arch_max_serial1; } #define PORT 80 /* */ EthernetInterface* net; TCPSocket server; TCPSocket* client; char httpBuf[1500]; char httpHeader[256]; const int OFF = 0; const int ON = 1; const char PASSWORD[] = "secret"; // Change as you like DigitalOut output(LED1); float roomTemp = 21.8; // A temperature sensor output FileHandle* mbed_override_console(int) { static BufferedSerial arch_max_serial1(PA_9, PA_10, 9600); return &arch_max_serial1; } /** * @brief Analyses the received URL * @note The string passed to this function will look like this: * GET /password HTTP/1..... * GET /password/ HTTP/1..... * GET /password/?sw=1 HTTP/1..... * GET /password/?sw=0 HTTP/1..... * @param url URL string * @retval -1 invalid password * -2 no command given but password valid * -3 just refresh page * 0 switch off * 1 switch on */ int8_t analyseURL(char* url) { if (strlen(url) < (5 + strlen(PASSWORD) + 1)) return(-1); //if (url.substr(5, PASSWORD.size()) != PASSWORD) if (strncmp(url + 5, PASSWORD, strlen(PASSWORD)) != 0) return(-1); uint8_t pos = 5 + strlen(PASSWORD); //if (url.substr(pos, 1) != "/") if (*(url + pos) != '/') return(-1); //if (url.substr(pos++, 1) == " ") if (*(url + pos++) == ' ') return(-2); //string cmd(url.substr(pos, 5)); *(url + pos + 5) = '\0'; // terminate the cmd string char* cmd = ((url + pos)); if (strcmp(cmd, "?sw=0") == 0) return(0); if (strcmp(cmd, "?sw=1") == 0) return(1); return(-3); } /** * @brief * @note * @param * @retval */ char* movedPermanently(uint8_t flag) { memset(httpBuf, 0, sizeof(httpBuf)); if (flag == 1) { strcpy(httpBuf, "/"); strcat(httpBuf, PASSWORD); strcat(httpBuf, "/"); } strcat(httpBuf, "<h1>301 Moved Permanently</h1>\r\n"); return(httpBuf); } /** * @brief * @note * @param * @retval */ char* showWebPage(int status) { char roomTempStr[10] = { }; //roomTemp = ds1820.read(); sprintf(roomTempStr, "%3.1f", roomTemp); memset(httpBuf, 0, sizeof(httpBuf)); /*$off*/ strcat ( httpBuf, "<head>" "<meta charset=\"utf-8\">" "<meta name=\"viewport\" content=\" initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=0;\"/>" "<title>Smart Home</title>" "<link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>" "<style>" ".switch {" "position: relative;" "display: inline-block;" "width: 60px;" "height: 34px;" "}" ".switch input {display:none;}" ".slider {" "position: absolute;" "cursor: pointer;" "top: 0;" "left: 0;" "right: 0;" "bottom: 0;" "border-radius: 34px;" "background-color: #ccc;" "-webkit-transition: .4s;" "transition: .4s;" "}" ".slider:before {" "position: absolute;" "content: \"\";" "height: 26px;" "width: 26px;" "left: 4px;" "bottom: 4px;" "border-radius: 50%;" "background-color: white;" "-webkit-transition: .4s;" "transition: .4s;" "}" "input:checked + .slider {" "background-color: #8ce196;" "}" "input:focus + .slider {" "box-shadow: 0 0 1px #8ce196;" "}" "input:checked + .slider:before {" "-webkit-transform: translateX(26px);" "-ms-transform: translateX(26px);" "transform: translateX(26px);" "}" "</style>" "</head>" "<body>" "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>" "<pre>Temperature:\t" ); strcat(httpBuf, roomTempStr); strcat(httpBuf, "°C</pre>"); strcat ( httpBuf, "<pre>Heating:\t" ); if(status == ON) { strcat ( httpBuf, "<a href=\"./?sw=0\" class=\"switch\"> " "<input type=\"checkbox\" checked>" ); } else { strcat ( httpBuf, "<a href=\"./?sw=1\" class=\"switch\"> " "<input type=\"checkbox\">" ); } strcat ( httpBuf, "<div class=\"slider\"></div>" "</a>" "</pre>" "<hr>" "<pre>2017 ARMmbed</pre>" "</body>" ); /*$on*/ return httpBuf; } /** * @brief * @note * @param * @retval */ void sendHTTP(TCPSocket* client, char* header, char* content) { char content_length[10] = { }; sprintf(content_length, "%u\r\n", strlen(content)); strcat(header, "\r\nContent-Type: text/html\r\n"); strcat(header, "Content-Length: "); strcat(header, content_length); strcat(header, "Pragma: no-cache\r\n"); strcat(header, "Connection: About to close\r\n\r\n"); char c = content[0]; memmove(httpBuf + strlen(header), httpBuf, strlen(content)); // make room for the header strcpy(httpBuf, header); // copy the header on front of the content httpBuf[strlen(header)] = c; client->send((uint8_t*)httpBuf, strlen(httpBuf)); } /** * @brief * @note * @param * @retval */ int main() { printf("starting\r\n"); net = new EthernetInterface(); //net->set_network("192.168.1.181","255.255.255.0","192.168.1.1"); // use static IP address, netmask, gateway if (!net) { printf("Error! No network inteface found.\n"); return 0; } //net->set_network (IP, NETMASK, GATEWAY); // include this for using static IP address nsapi_size_or_error_t r = net->connect(); if (r != NSAPI_ERROR_OK) { printf("Error! net->connect() returned: %d\n", r); return r; } // Show the network address SocketAddress addr; net->get_ip_address(&addr); printf("IP address: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None"); net->get_netmask(&addr); printf("Netmask: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None"); net->get_gateway(&addr); printf("Gateway: %s\n", addr.get_ip_address() ? addr.get_ip_address() : "None"); /* Open the server on ethernet stack */ server.open(net); /* Bind the HTTP port (TCP 80) to the server */ server.bind(PORT); /* Listen for clients */ server.listen(); //listening for http GET request while (true) { printf("=========================================\r\n"); printf("Ready to serve clients.\r\n"); net->get_ip_address(&addr); printf("Usage: Type http:\/\/%s\/%s\/ into your web browser and hit ENTER\r\n", addr.get_ip_address(), PASSWORD); client = server.accept(); if (client) { client->getpeername(&addr); printf("Connection succeeded!\n\rIP: %s\n\r", addr.get_ip_address()); client->recv(httpBuf, 1500); if (strncmp(httpBuf, "GET", 3) != 0) { strcpy(httpHeader, "HTTP/1.0 200 OK"); strcpy(httpBuf, "<h1>200 OK</h1>"); sendHTTP(client, httpHeader, httpBuf); } else if ((strncmp(httpBuf, "GET", 3) == 0) && (strncmp(httpBuf + 3, " / ", 3 == 0))) { strcpy(httpHeader, "HTTP/1.0 200 OK"); strcpy(httpBuf, "<p>Usage: http://host_or_ip/password</p>\r\n"); sendHTTP(client, httpHeader, httpBuf); } else { int cmd = analyseURL(httpBuf); switch (cmd) { case -3: // update webpage strcpy(httpHeader, "HTTP/1.0 200 OK"); sendHTTP(client, httpHeader, showWebPage(output)); break; case -2: // redirect to the right base url strcpy(httpHeader, "HTTP/1.0 301 Moved Permanently\r\nLocation: "); sendHTTP(client, httpHeader, movedPermanently(1)); break; case -1: strcpy(httpHeader, "HTTP/1.0 401 Unauthorized"); strcpy(httpBuf, "<h1>401 Unauthorized</h1>"); sendHTTP(client, httpHeader, httpBuf); break; case 0: output = OFF; // output off strcpy(httpHeader, "HTTP/1.0 200 OK"); sendHTTP(client, httpHeader, showWebPage(output)); break; case 1: output = ON; // output on strcpy(httpHeader, "HTTP/1.0 200 OK"); sendHTTP(client, httpHeader, showWebPage(output)); break; } } client->close(); } } }