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:
Sun Nov 24 18:58:57 2019 +0000
Revision:
9:3716ffcf2f27
Parent:
8:6f52a0c88bca
Child:
10:6860e839277e
Updated.

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