HTTP Server serving a simple webpage which enables to remotely turn LED1 on/off. Compile, download, run and type 'IP_address/secret/' (don't forget the last '/') into your web browser and hit ENTER.

Fork of WebSwitch_mbed-os by Zoltan Hudak

Turn LED1, or other digital output, on/off using a web browser.

In this example we create a HTTP server 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.

The project was inspired by the Tuxgraphics Web Switch. Thank you Guido!

For a Web Switch using

Committer:
hudakz
Date:
Mon Jul 01 17:23:49 2019 +0000
Revision:
9:161bed13b17e
Parent:
8:47b0cb4b5b7d
Child:
11:101be77aa5db
Tiny web server controlling a DigitalOut.

Who changed what in which revision?

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