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.
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.
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:
- For a Web Switch using a WIZ550io or W5500 Ethernet module see WebSwitch_Wiz550io.
- For a Web Switch using mbed's built in Ethernet PHY see WebSwitch_mbed-dev or WebSwitch_mbed-os .
main.cpp@0:68a0003c4cb8, 2014-09-15 (annotated)
- Committer:
- hudakz
- Date:
- Mon Sep 15 11:17:50 2014 +0000
- Revision:
- 0:68a0003c4cb8
- Child:
- 1:3d9c83af7246
rev. 00
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:68a0003c4cb8 | 1 | /* In this example LED1 is switched on/off using a web browser connected to this HTTP server. |
hudakz | 0:68a0003c4cb8 | 2 | * The example is based on the Tuxgraphics Web Switch <tuxgraphics.org>. |
hudakz | 0:68a0003c4cb8 | 3 | * This HTTP server is built around the UIPEthernet library for the ENC28J60 chip <https://github.com/ntruchsess/arduino_uip> |
hudakz | 0:68a0003c4cb8 | 4 | * ported to mbed. |
hudakz | 0:68a0003c4cb8 | 5 | */ |
hudakz | 0:68a0003c4cb8 | 6 | |
hudakz | 0:68a0003c4cb8 | 7 | #include <mbed.h> |
hudakz | 0:68a0003c4cb8 | 8 | #include <UIPEthernet.h> |
hudakz | 0:68a0003c4cb8 | 9 | #include <UIPServer.h> |
hudakz | 0:68a0003c4cb8 | 10 | #include <UIPClient.h> |
hudakz | 0:68a0003c4cb8 | 11 | #include <string> |
hudakz | 0:68a0003c4cb8 | 12 | |
hudakz | 0:68a0003c4cb8 | 13 | using namespace std; |
hudakz | 0:68a0003c4cb8 | 14 | |
hudakz | 0:68a0003c4cb8 | 15 | // UIPEthernet is the name of a global instance of UIPEthernetClass. |
hudakz | 0:68a0003c4cb8 | 16 | // Do not change the name! It is used within the UIPEthernet library. |
hudakz | 0:68a0003c4cb8 | 17 | // Adapt the SPI pin names to your mbed platform/board if not present yet. |
hudakz | 0:68a0003c4cb8 | 18 | #if defined(TARGET_LPC1768) |
hudakz | 0:68a0003c4cb8 | 19 | UIPEthernetClass UIPEthernet(p11, p12, p13, p8); // mosi, miso, sck, cs |
hudakz | 0:68a0003c4cb8 | 20 | #elif defined(TARGET_LPC1114) |
hudakz | 0:68a0003c4cb8 | 21 | UIPEthernetClass UIPEthernet(dp2, dp1, dp6, dp25); // mosi, miso, sck, cs |
hudakz | 0:68a0003c4cb8 | 22 | #elif defined(TARGET_LPC11U68) |
hudakz | 0:68a0003c4cb8 | 23 | UIPEthernetClass UIPEthernet(P0_9, P0_8, P1_29, P0_2); // mosi, miso, sck, cs |
hudakz | 0:68a0003c4cb8 | 24 | #elif defined (TARGET_NUCLEO_F103RB) |
hudakz | 0:68a0003c4cb8 | 25 | UIPEthernetClass UIPEthernet(PB_5, PB_4, PB_3, PB_6); // mosi, miso, sck, cs |
hudakz | 0:68a0003c4cb8 | 26 | #endif |
hudakz | 0:68a0003c4cb8 | 27 | |
hudakz | 0:68a0003c4cb8 | 28 | |
hudakz | 0:68a0003c4cb8 | 29 | // MAC number must be unique within the connected network. Modify as appropriate. |
hudakz | 0:68a0003c4cb8 | 30 | const uint8_t MY_MAC[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; |
hudakz | 0:68a0003c4cb8 | 31 | // IP address must be also unique and compatible with your network. Change as appropriate. |
hudakz | 0:68a0003c4cb8 | 32 | const IPAddress MY_IP(192,168,1,181); |
hudakz | 0:68a0003c4cb8 | 33 | const uint16_t MY_PORT = 80; // for HTTP connection |
hudakz | 0:68a0003c4cb8 | 34 | EthernetServer myServer = EthernetServer(MY_PORT); |
hudakz | 0:68a0003c4cb8 | 35 | // In this example we are turning on/off LED1. |
hudakz | 0:68a0003c4cb8 | 36 | // Change the pin name if you would like to switch on/off something else. |
hudakz | 0:68a0003c4cb8 | 37 | // However, make sure you avoid SPI pin names used already for UIPEthernet. |
hudakz | 0:68a0003c4cb8 | 38 | DigitalOut sw(LED1); |
hudakz | 0:68a0003c4cb8 | 39 | |
hudakz | 0:68a0003c4cb8 | 40 | const string PASSWORD = "secret"; // change as you like |
hudakz | 0:68a0003c4cb8 | 41 | const string HTTP_OK = "HTTP/1.0 200 OK"; |
hudakz | 0:68a0003c4cb8 | 42 | const string MOVED_PERM = "HTTP/1.0 301 Moved Permanently\r\nLocation: "; |
hudakz | 0:68a0003c4cb8 | 43 | const string UNAUTHORIZED = "HTTP/1.0 401 Unauthorized"; |
hudakz | 0:68a0003c4cb8 | 44 | string httpHeader; // HTTP header |
hudakz | 0:68a0003c4cb8 | 45 | string httpContent; // HTTP content |
hudakz | 0:68a0003c4cb8 | 46 | |
hudakz | 0:68a0003c4cb8 | 47 | |
hudakz | 0:68a0003c4cb8 | 48 | // analyse the url given |
hudakz | 0:68a0003c4cb8 | 49 | // return values: -1 invalid password |
hudakz | 0:68a0003c4cb8 | 50 | // -2 no command given but password valid |
hudakz | 0:68a0003c4cb8 | 51 | // -3 just refresh page |
hudakz | 0:68a0003c4cb8 | 52 | // 0 switch off |
hudakz | 0:68a0003c4cb8 | 53 | // 1 switch on |
hudakz | 0:68a0003c4cb8 | 54 | // |
hudakz | 0:68a0003c4cb8 | 55 | // The string passed to this function will look like this: |
hudakz | 0:68a0003c4cb8 | 56 | // GET /password HTTP/1..... |
hudakz | 0:68a0003c4cb8 | 57 | // GET /password/ HTTP/1..... |
hudakz | 0:68a0003c4cb8 | 58 | // GET /password/?sw=1 HTTP/1..... |
hudakz | 0:68a0003c4cb8 | 59 | // GET /password/?sw=0 HTTP/1..... |
hudakz | 0:68a0003c4cb8 | 60 | |
hudakz | 0:68a0003c4cb8 | 61 | int8_t analyse_get_url(string& str) |
hudakz | 0:68a0003c4cb8 | 62 | { |
hudakz | 0:68a0003c4cb8 | 63 | if(str.substr(5, PASSWORD.size()) != PASSWORD) |
hudakz | 0:68a0003c4cb8 | 64 | return(-1); |
hudakz | 0:68a0003c4cb8 | 65 | |
hudakz | 0:68a0003c4cb8 | 66 | uint8_t pos = 5 + PASSWORD.size(); |
hudakz | 0:68a0003c4cb8 | 67 | |
hudakz | 0:68a0003c4cb8 | 68 | if(str.substr(pos, 1) == " ") |
hudakz | 0:68a0003c4cb8 | 69 | return(-2); |
hudakz | 0:68a0003c4cb8 | 70 | |
hudakz | 0:68a0003c4cb8 | 71 | if(str.substr(pos, 1) != "/") |
hudakz | 0:68a0003c4cb8 | 72 | return(-1); |
hudakz | 0:68a0003c4cb8 | 73 | |
hudakz | 0:68a0003c4cb8 | 74 | pos++; |
hudakz | 0:68a0003c4cb8 | 75 | |
hudakz | 0:68a0003c4cb8 | 76 | string cmd(str.substr(pos, 5)); |
hudakz | 0:68a0003c4cb8 | 77 | |
hudakz | 0:68a0003c4cb8 | 78 | if(cmd == "?sw=0") |
hudakz | 0:68a0003c4cb8 | 79 | return(0); |
hudakz | 0:68a0003c4cb8 | 80 | |
hudakz | 0:68a0003c4cb8 | 81 | if(cmd == "?sw=1") |
hudakz | 0:68a0003c4cb8 | 82 | return(1); |
hudakz | 0:68a0003c4cb8 | 83 | |
hudakz | 0:68a0003c4cb8 | 84 | return(-3); |
hudakz | 0:68a0003c4cb8 | 85 | } |
hudakz | 0:68a0003c4cb8 | 86 | |
hudakz | 0:68a0003c4cb8 | 87 | string& moved_perm(uint8_t flag) |
hudakz | 0:68a0003c4cb8 | 88 | { |
hudakz | 0:68a0003c4cb8 | 89 | if(flag == 1) |
hudakz | 0:68a0003c4cb8 | 90 | httpContent = "/" + PASSWORD + "/"; |
hudakz | 0:68a0003c4cb8 | 91 | else |
hudakz | 0:68a0003c4cb8 | 92 | httpContent = ""; |
hudakz | 0:68a0003c4cb8 | 93 | |
hudakz | 0:68a0003c4cb8 | 94 | httpContent += "<h1>301 Moved Permanently</h1>\r\n"; |
hudakz | 0:68a0003c4cb8 | 95 | |
hudakz | 0:68a0003c4cb8 | 96 | return (httpContent); |
hudakz | 0:68a0003c4cb8 | 97 | } |
hudakz | 0:68a0003c4cb8 | 98 | |
hudakz | 0:68a0003c4cb8 | 99 | string& page(uint8_t status) |
hudakz | 0:68a0003c4cb8 | 100 | { |
hudakz | 0:68a0003c4cb8 | 101 | httpContent = "<h2>Web Switch</h2>\r\n"; |
hudakz | 0:68a0003c4cb8 | 102 | |
hudakz | 0:68a0003c4cb8 | 103 | if(status == 1) { |
hudakz | 0:68a0003c4cb8 | 104 | httpContent += "<pre>\r\n <font color=#FF0000>ON</font>"; |
hudakz | 0:68a0003c4cb8 | 105 | httpContent += " <a href=\"./?sw=0\">[switch off]</a>\r\n"; |
hudakz | 0:68a0003c4cb8 | 106 | } else { |
hudakz | 0:68a0003c4cb8 | 107 | httpContent += "<pre>\r\n <font color=#00FF00>OFF</font>"; |
hudakz | 0:68a0003c4cb8 | 108 | httpContent += " <a href=\"./?sw=1\">[switch on]</a>\r\n"; |
hudakz | 0:68a0003c4cb8 | 109 | } |
hudakz | 0:68a0003c4cb8 | 110 | |
hudakz | 0:68a0003c4cb8 | 111 | httpContent += " <a href=\".\">[refresh status]</a>\r\n"; |
hudakz | 0:68a0003c4cb8 | 112 | httpContent += "</pre>\r\n"; |
hudakz | 0:68a0003c4cb8 | 113 | httpContent += "<hr>\r\n"; |
hudakz | 0:68a0003c4cb8 | 114 | return httpContent; |
hudakz | 0:68a0003c4cb8 | 115 | } |
hudakz | 0:68a0003c4cb8 | 116 | |
hudakz | 0:68a0003c4cb8 | 117 | void http_send(EthernetClient& client, string& header, string& content) |
hudakz | 0:68a0003c4cb8 | 118 | { |
hudakz | 0:68a0003c4cb8 | 119 | char content_length[5] = {}; |
hudakz | 0:68a0003c4cb8 | 120 | |
hudakz | 0:68a0003c4cb8 | 121 | header += "\r\nContent-Type: text\r\n"; |
hudakz | 0:68a0003c4cb8 | 122 | header += "Content-Length: "; |
hudakz | 0:68a0003c4cb8 | 123 | sprintf(content_length, "%d", content.length()); |
hudakz | 0:68a0003c4cb8 | 124 | header += string(content_length) + "\r\n"; |
hudakz | 0:68a0003c4cb8 | 125 | header += "Pragma: no-cache\r\n"; |
hudakz | 0:68a0003c4cb8 | 126 | header += "Connection: About to close\r\n"; |
hudakz | 0:68a0003c4cb8 | 127 | header += "\r\n"; |
hudakz | 0:68a0003c4cb8 | 128 | string webpage = header + content; |
hudakz | 0:68a0003c4cb8 | 129 | client.write((uint8_t*)webpage.c_str(),webpage.length()); |
hudakz | 0:68a0003c4cb8 | 130 | } |
hudakz | 0:68a0003c4cb8 | 131 | |
hudakz | 0:68a0003c4cb8 | 132 | int main() |
hudakz | 0:68a0003c4cb8 | 133 | { |
hudakz | 0:68a0003c4cb8 | 134 | Ethernet.begin(MY_MAC,MY_IP); |
hudakz | 0:68a0003c4cb8 | 135 | myServer.begin(); |
hudakz | 0:68a0003c4cb8 | 136 | while(1) { |
hudakz | 0:68a0003c4cb8 | 137 | EthernetClient client = myServer.available(); |
hudakz | 0:68a0003c4cb8 | 138 | if (client) { |
hudakz | 0:68a0003c4cb8 | 139 | size_t size = client.available(); |
hudakz | 0:68a0003c4cb8 | 140 | if(size > 0) { |
hudakz | 0:68a0003c4cb8 | 141 | uint8_t* buf = (uint8_t*)malloc(size); |
hudakz | 0:68a0003c4cb8 | 142 | size = client.read(buf, size); |
hudakz | 0:68a0003c4cb8 | 143 | string received((char*)buf); |
hudakz | 0:68a0003c4cb8 | 144 | free(buf); |
hudakz | 0:68a0003c4cb8 | 145 | if(received.substr(0, 3) != "GET") { |
hudakz | 0:68a0003c4cb8 | 146 | // head, post or other method |
hudakz | 0:68a0003c4cb8 | 147 | // for possible status codes see: |
hudakz | 0:68a0003c4cb8 | 148 | // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html |
hudakz | 0:68a0003c4cb8 | 149 | httpHeader = HTTP_OK; |
hudakz | 0:68a0003c4cb8 | 150 | httpContent = "<h1>200 OK</h1>"; |
hudakz | 0:68a0003c4cb8 | 151 | http_send(client, httpHeader, httpContent); |
hudakz | 0:68a0003c4cb8 | 152 | continue; |
hudakz | 0:68a0003c4cb8 | 153 | } |
hudakz | 0:68a0003c4cb8 | 154 | |
hudakz | 0:68a0003c4cb8 | 155 | if(received.substr(0, 6) == "GET / ") { |
hudakz | 0:68a0003c4cb8 | 156 | httpHeader = HTTP_OK; |
hudakz | 0:68a0003c4cb8 | 157 | httpContent = "<p>Usage: http://host_or_ip/password</p>\r\n"; |
hudakz | 0:68a0003c4cb8 | 158 | http_send(client, httpHeader, httpContent); |
hudakz | 0:68a0003c4cb8 | 159 | continue; |
hudakz | 0:68a0003c4cb8 | 160 | } |
hudakz | 0:68a0003c4cb8 | 161 | |
hudakz | 0:68a0003c4cb8 | 162 | int cmd = analyse_get_url(received); |
hudakz | 0:68a0003c4cb8 | 163 | |
hudakz | 0:68a0003c4cb8 | 164 | if(cmd == -2) { |
hudakz | 0:68a0003c4cb8 | 165 | // redirect to the right base url |
hudakz | 0:68a0003c4cb8 | 166 | httpHeader = MOVED_PERM; |
hudakz | 0:68a0003c4cb8 | 167 | http_send(client, httpHeader, moved_perm(1)); |
hudakz | 0:68a0003c4cb8 | 168 | continue; |
hudakz | 0:68a0003c4cb8 | 169 | } |
hudakz | 0:68a0003c4cb8 | 170 | |
hudakz | 0:68a0003c4cb8 | 171 | if(cmd == -1) { |
hudakz | 0:68a0003c4cb8 | 172 | httpHeader = UNAUTHORIZED; |
hudakz | 0:68a0003c4cb8 | 173 | httpContent = "<h1>401 Unauthorized</h1>"; |
hudakz | 0:68a0003c4cb8 | 174 | http_send(client, httpHeader, httpContent); |
hudakz | 0:68a0003c4cb8 | 175 | continue; |
hudakz | 0:68a0003c4cb8 | 176 | } |
hudakz | 0:68a0003c4cb8 | 177 | |
hudakz | 0:68a0003c4cb8 | 178 | if(cmd == 1) { |
hudakz | 0:68a0003c4cb8 | 179 | sw = 1; // switch on |
hudakz | 0:68a0003c4cb8 | 180 | } |
hudakz | 0:68a0003c4cb8 | 181 | |
hudakz | 0:68a0003c4cb8 | 182 | if(cmd == 0) { |
hudakz | 0:68a0003c4cb8 | 183 | sw = 0; // switch off |
hudakz | 0:68a0003c4cb8 | 184 | } |
hudakz | 0:68a0003c4cb8 | 185 | |
hudakz | 0:68a0003c4cb8 | 186 | httpHeader = HTTP_OK; |
hudakz | 0:68a0003c4cb8 | 187 | http_send(client, httpHeader, page(sw)); |
hudakz | 0:68a0003c4cb8 | 188 | } |
hudakz | 0:68a0003c4cb8 | 189 | } |
hudakz | 0:68a0003c4cb8 | 190 | } |
hudakz | 0:68a0003c4cb8 | 191 | } |
hudakz | 0:68a0003c4cb8 | 192 |