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:
Fri Jun 05 15:23:09 2020 +0000
Revision:
16:f348413be13e
Parent:
15:9beb9b99695d
Tiny HTTP server to remotely turn a DigitalOut on/off.

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