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.

/media/uploads/hudakz/webswitch03.png/media/uploads/hudakz/webswitch_mobile01.jpg

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.

/media/uploads/hudakz/dp83848_01.jpg

Wiring

DP83848 moduleSTM32F407VET6 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!

Committer:
hudakz
Date:
Sat May 18 09:10:54 2019 +0000
Revision:
1:cae77ef9edaf
Parent:
0:912fb893b03c
Child:
2:8b20e8493a5b
Tiny HTTP server controlling a DigitalOutput.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:912fb893b03c 1 #include "mbed.h"
hudakz 0:912fb893b03c 2 #include "EthernetInterface.h"
hudakz 0:912fb893b03c 3 #include "TCPSocket.h"
hudakz 0:912fb893b03c 4 #include <stdio.h>
hudakz 0:912fb893b03c 5 #include <string>
hudakz 0:912fb893b03c 6
hudakz 0:912fb893b03c 7 using namespace std;
hudakz 0:912fb893b03c 8
hudakz 0:912fb893b03c 9 #define IP "192.168.1.181"
hudakz 0:912fb893b03c 10 #define GATEWAY "192.168.1.1"
hudakz 0:912fb893b03c 11 #define NETMASK "255.255.255.0"
hudakz 0:912fb893b03c 12 #define PORT 80
hudakz 0:912fb893b03c 13
hudakz 0:912fb893b03c 14 Serial pc(PC_6, PC_7);
hudakz 0:912fb893b03c 15 //Serial pc(PA_9, PA_10);
hudakz 0:912fb893b03c 16
hudakz 0:912fb893b03c 17 EthernetInterface* net;
hudakz 0:912fb893b03c 18
hudakz 0:912fb893b03c 19 TCPSocket server;
hudakz 0:912fb893b03c 20 TCPSocket* clientSocket;
hudakz 0:912fb893b03c 21 SocketAddress clientAddress;
hudakz 0:912fb893b03c 22 char receiveBuf[1024] = { };
hudakz 0:912fb893b03c 23
hudakz 0:912fb893b03c 24 const int OFF = 1;
hudakz 0:912fb893b03c 25 const int ON = 0;
hudakz 0:912fb893b03c 26
hudakz 0:912fb893b03c 27 DigitalOut sw(PA_6);
hudakz 0:912fb893b03c 28 float roomTemp = 21.8; // A temperature sensor output
hudakz 0:912fb893b03c 29
hudakz 0:912fb893b03c 30 const string PASSWORD = "secret"; // change as you like
hudakz 0:912fb893b03c 31 const string HTTP_OK = "HTTP/1.0 200 OK";
hudakz 0:912fb893b03c 32 const string MOVED_PERM = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
hudakz 0:912fb893b03c 33 const string UNAUTHORIZED = "HTTP/1.0 401 Unauthorized";
hudakz 0:912fb893b03c 34 string httpHeader; // HTTP header
hudakz 0:912fb893b03c 35 string httpContent; // HTTP content
hudakz 0:912fb893b03c 36
hudakz 0:912fb893b03c 37 /**
hudakz 0:912fb893b03c 38 * @brief Analyses the received URL
hudakz 0:912fb893b03c 39 * @note The string passed to this function will look like this:
hudakz 0:912fb893b03c 40 * GET /password HTTP/1.....
hudakz 0:912fb893b03c 41 * GET /password/ HTTP/1.....
hudakz 0:912fb893b03c 42 * GET /password/?sw=1 HTTP/1.....
hudakz 0:912fb893b03c 43 * GET /password/?sw=0 HTTP/1.....
hudakz 0:912fb893b03c 44 * @param url URL string
hudakz 0:912fb893b03c 45 * @retval -1 invalid password
hudakz 0:912fb893b03c 46 * -2 no command given but password valid
hudakz 0:912fb893b03c 47 * -3 just refresh page
hudakz 0:912fb893b03c 48 * 0 switch off
hudakz 0:912fb893b03c 49 * 1 switch on
hudakz 0:912fb893b03c 50 */
hudakz 0:912fb893b03c 51 int8_t analyseURL(string& url) {
hudakz 0:912fb893b03c 52 if(url.substr(5, PASSWORD.size()) != PASSWORD)
hudakz 0:912fb893b03c 53 return(-1);
hudakz 0:912fb893b03c 54
hudakz 0:912fb893b03c 55 uint8_t pos = 5 + PASSWORD.size();
hudakz 0:912fb893b03c 56
hudakz 0:912fb893b03c 57 if(url.substr(pos, 1) == " ")
hudakz 0:912fb893b03c 58 return(-2);
hudakz 0:912fb893b03c 59
hudakz 0:912fb893b03c 60 if(url.substr(pos++, 1) != "/")
hudakz 0:912fb893b03c 61 return(-1);
hudakz 0:912fb893b03c 62
hudakz 0:912fb893b03c 63 string cmd(url.substr(pos, 5));
hudakz 0:912fb893b03c 64
hudakz 0:912fb893b03c 65 if(cmd == "?sw=0")
hudakz 0:912fb893b03c 66 return(0);
hudakz 0:912fb893b03c 67
hudakz 0:912fb893b03c 68 if(cmd == "?sw=1")
hudakz 0:912fb893b03c 69 return(1);
hudakz 0:912fb893b03c 70
hudakz 0:912fb893b03c 71 return(-3);
hudakz 0:912fb893b03c 72 }
hudakz 0:912fb893b03c 73
hudakz 0:912fb893b03c 74 /**
hudakz 0:912fb893b03c 75 * @brief
hudakz 0:912fb893b03c 76 * @note
hudakz 0:912fb893b03c 77 * @param
hudakz 0:912fb893b03c 78 * @retval
hudakz 0:912fb893b03c 79 */
hudakz 0:912fb893b03c 80 string& movedPermanently(uint8_t flag) {
hudakz 0:912fb893b03c 81 if(flag == 1)
hudakz 0:912fb893b03c 82 httpContent = "/" + PASSWORD + "/";
hudakz 0:912fb893b03c 83 else
hudakz 0:912fb893b03c 84 httpContent = "";
hudakz 0:912fb893b03c 85
hudakz 0:912fb893b03c 86 httpContent += "<h1>301 Moved Permanently</h1>\r\n";
hudakz 0:912fb893b03c 87
hudakz 0:912fb893b03c 88 return(httpContent);
hudakz 0:912fb893b03c 89 }
hudakz 0:912fb893b03c 90
hudakz 0:912fb893b03c 91 /**
hudakz 0:912fb893b03c 92 * @brief
hudakz 0:912fb893b03c 93 * @note
hudakz 0:912fb893b03c 94 * @param
hudakz 0:912fb893b03c 95 * @retval
hudakz 0:912fb893b03c 96 */
hudakz 0:912fb893b03c 97 string& showWebPage(uint8_t status) {
hudakz 0:912fb893b03c 98 char roomTempStr[5];
hudakz 0:912fb893b03c 99
hudakz 0:912fb893b03c 100 //roomTemp = ds1820.read();
hudakz 0:912fb893b03c 101 sprintf(roomTempStr, "%3.1f", roomTemp);
hudakz 0:912fb893b03c 102
hudakz 0:912fb893b03c 103 // CSS toggle switch
hudakz 0:912fb893b03c 104 httpContent = "<head>";
hudakz 0:912fb893b03c 105 httpContent += "<style>";
hudakz 0:912fb893b03c 106
hudakz 0:912fb893b03c 107 httpContent += ".switch {";
hudakz 0:912fb893b03c 108 httpContent += "position: relative;";
hudakz 0:912fb893b03c 109 httpContent += "display: inline-block;";
hudakz 0:912fb893b03c 110 httpContent += "width: 60px;";
hudakz 0:912fb893b03c 111 httpContent += "height: 34px;";
hudakz 0:912fb893b03c 112 httpContent += "}";
hudakz 0:912fb893b03c 113
hudakz 0:912fb893b03c 114 httpContent += ".switch input {display:none;}";
hudakz 0:912fb893b03c 115
hudakz 0:912fb893b03c 116 httpContent += ".slider {";
hudakz 0:912fb893b03c 117 httpContent += "position: absolute;";
hudakz 0:912fb893b03c 118 httpContent += "cursor: pointer;";
hudakz 0:912fb893b03c 119 httpContent += "top: 0;";
hudakz 0:912fb893b03c 120 httpContent += "left: 0;";
hudakz 0:912fb893b03c 121 httpContent += "right: 0;";
hudakz 0:912fb893b03c 122 httpContent += "bottom: 0;";
hudakz 0:912fb893b03c 123 httpContent += "border-radius: 34px;";
hudakz 0:912fb893b03c 124 httpContent += "background-color: #ccc;";
hudakz 0:912fb893b03c 125 httpContent += "-webkit-transition: .4s;";
hudakz 0:912fb893b03c 126 httpContent += "transition: .4s;";
hudakz 0:912fb893b03c 127 httpContent += "}";
hudakz 0:912fb893b03c 128
hudakz 0:912fb893b03c 129 httpContent += ".slider:before {";
hudakz 0:912fb893b03c 130 httpContent += "position: absolute;";
hudakz 0:912fb893b03c 131 httpContent += "content: \"\";";
hudakz 0:912fb893b03c 132 httpContent += "height: 26px;";
hudakz 0:912fb893b03c 133 httpContent += "width: 26px;";
hudakz 0:912fb893b03c 134 httpContent += "left: 4px;";
hudakz 0:912fb893b03c 135 httpContent += "bottom: 4px;";
hudakz 0:912fb893b03c 136 httpContent += "border-radius: 50%;";
hudakz 0:912fb893b03c 137 httpContent += "background-color: white;";
hudakz 0:912fb893b03c 138 httpContent += "-webkit-transition: .4s;";
hudakz 0:912fb893b03c 139 httpContent += "transition: .4s;";
hudakz 0:912fb893b03c 140 httpContent += "}";
hudakz 0:912fb893b03c 141
hudakz 0:912fb893b03c 142 httpContent += "input:checked + .slider {";
hudakz 0:912fb893b03c 143 httpContent += "background-color: #8ce196;";
hudakz 0:912fb893b03c 144 httpContent += "}";
hudakz 0:912fb893b03c 145
hudakz 0:912fb893b03c 146 httpContent += "input:focus + .slider {";
hudakz 0:912fb893b03c 147 httpContent += "box-shadow: 0 0 1px #8ce196;";
hudakz 0:912fb893b03c 148 httpContent += "}";
hudakz 0:912fb893b03c 149
hudakz 0:912fb893b03c 150 httpContent += "input:checked + .slider:before {";
hudakz 0:912fb893b03c 151 httpContent += "-webkit-transform: translateX(26px);";
hudakz 0:912fb893b03c 152 httpContent += "-ms-transform: translateX(26px);";
hudakz 0:912fb893b03c 153 httpContent += "transform: translateX(26px);";
hudakz 0:912fb893b03c 154 httpContent += "}";
hudakz 0:912fb893b03c 155
hudakz 0:912fb893b03c 156 httpContent += "</style>";
hudakz 0:912fb893b03c 157 httpContent += "</head>";
hudakz 0:912fb893b03c 158
hudakz 1:cae77ef9edaf 159 // Web page
hudakz 0:912fb893b03c 160 httpContent += "<body>";
hudakz 0:912fb893b03c 161 httpContent += "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>";
hudakz 0:912fb893b03c 162 httpContent += "<pre>Temperature:\t" + string(roomTempStr) + "&deg;C</pre>";
hudakz 0:912fb893b03c 163 httpContent += "<pre>Heating:\t";
hudakz 0:912fb893b03c 164
hudakz 0:912fb893b03c 165 if(status == ON) {
hudakz 0:912fb893b03c 166 httpContent += "<a href=\"./?sw=0\" class=\"switch\"> ";
hudakz 0:912fb893b03c 167 httpContent += "<input type=\"checkbox\" checked>";
hudakz 0:912fb893b03c 168 }
hudakz 0:912fb893b03c 169 else {
hudakz 0:912fb893b03c 170 httpContent += "<a href=\"./?sw=1\" class=\"switch\"> ";
hudakz 0:912fb893b03c 171 httpContent += "<input type=\"checkbox\">";
hudakz 0:912fb893b03c 172 }
hudakz 0:912fb893b03c 173
hudakz 0:912fb893b03c 174 httpContent += "<div class=\"slider\"></div>";
hudakz 0:912fb893b03c 175 httpContent += "</a></pre>";
hudakz 0:912fb893b03c 176 httpContent += "<hr>";
hudakz 0:912fb893b03c 177 httpContent += "<pre>2017 ARMmbed</pre>";
hudakz 0:912fb893b03c 178 httpContent += "</body>";
hudakz 0:912fb893b03c 179
hudakz 0:912fb893b03c 180 return httpContent;
hudakz 0:912fb893b03c 181 }
hudakz 0:912fb893b03c 182
hudakz 0:912fb893b03c 183 /**
hudakz 0:912fb893b03c 184 * @brief
hudakz 0:912fb893b03c 185 * @note
hudakz 0:912fb893b03c 186 * @param
hudakz 0:912fb893b03c 187 * @retval
hudakz 0:912fb893b03c 188 */
hudakz 0:912fb893b03c 189 void sendHTTP(TCPSocket& client, string& header, string& content) {
hudakz 0:912fb893b03c 190 char content_length[5] = { };
hudakz 0:912fb893b03c 191
hudakz 0:912fb893b03c 192 header += "\r\nContent-Type: text/html\r\n";
hudakz 0:912fb893b03c 193 header += "Content-Length: ";
hudakz 0:912fb893b03c 194 sprintf(content_length, "%d", content.length());
hudakz 0:912fb893b03c 195 header += string(content_length) + "\r\n";
hudakz 0:912fb893b03c 196 header += "Pragma: no-cache\r\n";
hudakz 0:912fb893b03c 197 header += "Connection: About to close\r\n";
hudakz 0:912fb893b03c 198 header += "\r\n";
hudakz 0:912fb893b03c 199
hudakz 0:912fb893b03c 200 string webpage = header + content;
hudakz 0:912fb893b03c 201 client.send((char*)webpage.c_str(), webpage.length());
hudakz 0:912fb893b03c 202 pc.printf("HTTP message sent to client.\n\r");
hudakz 0:912fb893b03c 203 }
hudakz 0:912fb893b03c 204
hudakz 0:912fb893b03c 205 /**
hudakz 0:912fb893b03c 206 * @brief
hudakz 0:912fb893b03c 207 * @note
hudakz 0:912fb893b03c 208 * @param
hudakz 0:912fb893b03c 209 * @retval
hudakz 0:912fb893b03c 210 */
hudakz 0:912fb893b03c 211 int main(void) {
hudakz 0:912fb893b03c 212 pc.printf("Starting.. \r\n\r\n");
hudakz 0:912fb893b03c 213
hudakz 0:912fb893b03c 214 net = new EthernetInterface();
hudakz 0:912fb893b03c 215
hudakz 0:912fb893b03c 216 if (!net) {
hudakz 0:912fb893b03c 217 pc.printf("Error! No network inteface found.\n");
hudakz 0:912fb893b03c 218 return 0;
hudakz 0:912fb893b03c 219 }
hudakz 0:912fb893b03c 220
hudakz 0:912fb893b03c 221 //net->set_network (IP, NETMASK, GATEWAY); // include this for using static IP address
hudakz 0:912fb893b03c 222
hudakz 0:912fb893b03c 223 nsapi_size_or_error_t r = net->connect();
hudakz 0:912fb893b03c 224 if (r != 0) {
hudakz 0:912fb893b03c 225 pc.printf("Error! net->connect() returned: %d\n", r);
hudakz 0:912fb893b03c 226 return r;
hudakz 0:912fb893b03c 227 }
hudakz 0:912fb893b03c 228
hudakz 0:912fb893b03c 229 // Show the network address
hudakz 0:912fb893b03c 230 const char *ip = net->get_ip_address();
hudakz 0:912fb893b03c 231 const char *netmask = net->get_netmask();
hudakz 0:912fb893b03c 232 const char *gateway = net->get_gateway();
hudakz 0:912fb893b03c 233 pc.printf("IP address: %s\r\n", ip ? ip : "None");
hudakz 0:912fb893b03c 234 pc.printf("Netmask: %s\r\n", netmask ? netmask : "None");
hudakz 0:912fb893b03c 235 pc.printf("Gateway: %s\r\n\r\n", gateway ? gateway : "None");
hudakz 0:912fb893b03c 236 pc.printf("Usage: Type %s/%s/ into your web browser and hit ENTER\r\n\r\n", ip, PASSWORD.c_str());
hudakz 0:912fb893b03c 237
hudakz 0:912fb893b03c 238 /* Open the server on ethernet stack */
hudakz 0:912fb893b03c 239 server.open(net);
hudakz 0:912fb893b03c 240
hudakz 0:912fb893b03c 241 /* Bind the HTTP port (TCP 80) to the server */
hudakz 0:912fb893b03c 242 server.bind(ip, PORT);
hudakz 0:912fb893b03c 243
hudakz 0:912fb893b03c 244 /* Can handle 5 simultaneous connections */
hudakz 0:912fb893b03c 245 server.listen(5);
hudakz 0:912fb893b03c 246
hudakz 0:912fb893b03c 247 //listening for http GET request
hudakz 0:912fb893b03c 248 while(true) {
hudakz 0:912fb893b03c 249 pc.printf("=========================================\r\n");
hudakz 0:912fb893b03c 250 //server.accept(&clientSocket, &clientAddress);
hudakz 0:912fb893b03c 251 nsapi_error_t error;
hudakz 0:912fb893b03c 252 clientSocket = server.accept(&error);
hudakz 0:912fb893b03c 253 if (error != 0) {
hudakz 0:912fb893b03c 254 pc.printf("Connection failed!\r\n");
hudakz 0:912fb893b03c 255 continue;
hudakz 0:912fb893b03c 256 }
hudakz 0:912fb893b03c 257 clientSocket->getpeername(&clientAddress);
hudakz 0:912fb893b03c 258 pc.printf("Client with IP address %s connected.\r\n\r\n", clientAddress.get_ip_address());
hudakz 0:912fb893b03c 259 clientSocket->recv(receiveBuf, 1023);
hudakz 0:912fb893b03c 260 pc.printf("Data received:\r\n%s\n\r", receiveBuf);
hudakz 0:912fb893b03c 261
hudakz 0:912fb893b03c 262 string received(receiveBuf);
hudakz 0:912fb893b03c 263
hudakz 0:912fb893b03c 264 if(received.substr(0, 3) != "GET") {
hudakz 0:912fb893b03c 265 httpHeader = HTTP_OK;
hudakz 0:912fb893b03c 266 httpContent = "<h1>200 OK</h1>";
hudakz 0:912fb893b03c 267 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 0:912fb893b03c 268 continue;
hudakz 0:912fb893b03c 269 }
hudakz 0:912fb893b03c 270
hudakz 0:912fb893b03c 271 if(received.substr(0, 6) == "GET / ") {
hudakz 0:912fb893b03c 272 httpHeader = HTTP_OK;
hudakz 0:912fb893b03c 273 httpContent = "<p>Usage: Type http://ip_address/password/ into your web browser and hit ENTER</p>\r\n";
hudakz 0:912fb893b03c 274 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 0:912fb893b03c 275 continue;
hudakz 0:912fb893b03c 276 }
hudakz 0:912fb893b03c 277
hudakz 0:912fb893b03c 278 int cmd = analyseURL(received);
hudakz 0:912fb893b03c 279
hudakz 0:912fb893b03c 280 if(cmd == -2) {
hudakz 0:912fb893b03c 281
hudakz 0:912fb893b03c 282 // redirect to the right base url
hudakz 0:912fb893b03c 283 httpHeader = MOVED_PERM;
hudakz 0:912fb893b03c 284 sendHTTP(*clientSocket, httpHeader, movedPermanently(1));
hudakz 0:912fb893b03c 285 continue;
hudakz 0:912fb893b03c 286 }
hudakz 0:912fb893b03c 287
hudakz 0:912fb893b03c 288 if(cmd == -1) {
hudakz 0:912fb893b03c 289 httpHeader = UNAUTHORIZED;
hudakz 0:912fb893b03c 290 httpContent = "<h1>401 Unauthorized</h1>";
hudakz 0:912fb893b03c 291 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 0:912fb893b03c 292 continue;
hudakz 0:912fb893b03c 293 }
hudakz 0:912fb893b03c 294
hudakz 0:912fb893b03c 295 if(cmd == 1) {
hudakz 0:912fb893b03c 296 sw = ON; // turn the switch on
hudakz 0:912fb893b03c 297 }
hudakz 0:912fb893b03c 298
hudakz 0:912fb893b03c 299 if(cmd == 0) {
hudakz 0:912fb893b03c 300 sw = OFF; // turn the switch off
hudakz 0:912fb893b03c 301 }
hudakz 0:912fb893b03c 302
hudakz 0:912fb893b03c 303 httpHeader = HTTP_OK;
hudakz 0:912fb893b03c 304 sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
hudakz 0:912fb893b03c 305 clientSocket->close();
hudakz 0:912fb893b03c 306 }
hudakz 0:912fb893b03c 307 }