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