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

Dependencies:   UIPEthernet

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 the mbed board, on/off by using a web browser. An inexpensive ENC28J60 Ethernet module is used to assure connection between the mbed board and the Ethernet network (Internet). The ENC28J60 Ethernet module is driven by the UIPEthernet library.

Needed parts:

  • mbed board
  • ENC28J60 Ethernet module
  • Wires
  • Web browser (Internet Explorer, Safari, Firefox, Chrome ...) running on Windows, Mac, Linux, iPhone or Android device.
/media/uploads/hudakz/webswitch_enc.jpg/media/uploads/hudakz/webswitch_mobile01.jpg

Notice that DHCP is turned on by default. If you prefer to use static IP address then uncomment line 234

The IP address assigned to the WebSwitch server along with an instruction how to use it is printed in the connected PC's serial terminal window during program start up.

Warning

Please notice that the 3.3V power supply chip (RT8183-B) installed on an STM32F103C8T6 board is not rated to power also the ENC28J60 board.


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

NOTE:

Committer:
hudakz
Date:
Tue Aug 27 22:10:13 2019 +0000
Revision:
11:6c0b20227ca2
Parent:
10:b47c7921346f
Child:
12:7c46dcf6f7e2
Updated to use the latest UIPEthernet library.

Who changed what in which revision?

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