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.

Dependencies:   W5500Interface mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* 
00002  * In this example LED1 on the mbed board is turned on/off using a web browser.
00003  * However, you can easily modify the project to remotely switch on/off any external device.
00004  * The HTTP server is built from an mbed board and a WIZ550io board.
00005  * The example is based on the Tuxgraphics Web Switch <http://www.tuxgraphics.org/>.
00006  * For more details see <https://developer.mbed.org/users/hudakz/code/WebSwitch_WIZ550io/wiki/Homepage>
00007  * Thanks to Jozsef Voros it works now also with the W5500 modules without a built-in MAC
00008  * See below how to enable that.
00009  */
00010 #include "mbed.h"
00011 #include "EthernetInterface.h"
00012 #include <string>
00013 
00014 using namespace     std;
00015 
00016 const int OFF = 0;
00017 const int ON  = 1;
00018 
00019 Serial              serial(USBTX, USBRX);
00020 
00021 #if defined(TARGET_LPC1768)
00022 EthernetInterface   eth(p11, p12, p13, p8, p14);        // MOSI, MISO, SCK, CS, RESET
00023 #elif defined(TARGET_LPC11U24)
00024 EthernetInterface   eth(P16, P15, P13, P17, P18);       // MOSI, MISO, SCK, CS, RESET
00025 #elif defined(TARGET_NUCLEO_F103RB) || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_F030R8)  \
00026    || defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F302R8) || defined(TARGET_NUCLEO_L053R8)  \
00027    || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F334R8) || defined(TARGET_NUCLEO_F072RB)  \
00028    || defined(TARGET_NUCLEO_F091RC) || defined(TARGET_NUCLEO_F303RE) || defined(TARGET_NUCLEO_F070RB)  \
00029    || defined(TARGET_KL25Z ) || defined(TARGET_KL46Z) || defined(TARGET_K64F) || defined(TARGET_KL05Z) \
00030    || defined(TARGET_K20D50M) || defined(TARGET_K22F) \
00031    || defined(TARGET_NRF51822) \
00032    || defined(TARGET_RZ_A1H)
00033 EthernetInterface   eth(D4, D5, D3, D6, D7); // MOSI, MISO, SCK, CS, RESET
00034 
00035 // If your board/plaform is not present yet then uncomment
00036 // the following two lines and replace modify as appropriate.
00037 
00038 //#elif defined(TARGET_YOUR_BOARD)
00039 //EthernetInterface   eth(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS, RESET); // MOSI, MISO, SCK, CS, RESET
00040 #endif
00041 
00042 // Note:
00043 // If it happends that any of the SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS or RESET pins collide with LED1 pin
00044 // then either use different SPI port (if available on the board) and change the pin names
00045 // in the constructor spi(...) accordingly or instead of using LED1 pin, select
00046 // a free pin (not used by SPI port) and connect to it an external LED which is connected
00047 // to a 220 Ohm resitor that is connected to the groud.
00048 // In the second case remember to replace LED1 in sw(LED1) constructor (see below).
00049 // IP address must be also unique and compatible with your network. Change as appropriate.
00050 
00051 // If instead of WIZ550io you'd like to use a W5500 module without a built-in MAC please uncommend the following line
00052 //#define W5500   1
00053 
00054 #if defined(W5500)
00055 // The MAC number must be unique within the connected network. Modify as appropriate.
00056 uint8_t       MY_MAC[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
00057 #endif
00058 
00059 const char          MY_IP[] = "192.168.1.181";
00060 const char          MY_NETMASK[] = "255.255.255.0";
00061 const char          MY_GATEWAY[] = "192.168.1.1";
00062 int                 MY_PORT = 80;
00063 
00064 TCPSocketServer     server;
00065 TCPSocketConnection client;
00066 bool                serverIsListening = false;
00067 
00068 DigitalOut          sw(LED1);   // Change LED1 to a pin of your choice.
00069                                 // However, make sure that it does not collide with any of the SPI pins
00070 float               roomTemp = 21.8;    // A temperature sensor output
00071 
00072 const string        PASSWORD = "secret";    // change as you like
00073 const string        HTTP_OK = "HTTP/1.0 200 OK";
00074 const string        MOVED_PERM = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
00075 const string        UNAUTHORIZED = "HTTP/1.0 401 Unauthorized";
00076 
00077 string              httpHeader;     // HTTP header
00078 string              httpContent;    // HTTP content
00079 
00080 /**
00081  * @brief   Analyses the received URL
00082  * @note    The string passed to this function will look like this:
00083  *          GET /password HTTP/1.....
00084  *          GET /password/ HTTP/1.....
00085  *          GET /password/?sw=1 HTTP/1.....
00086  *          GET /password/?sw=0 HTTP/1.....
00087  * @param   url URL string
00088  * @retval -1 invalid password
00089  *         -2 no command given but password valid
00090  *         -3 just refresh page
00091  *          0 switch off
00092  *          1 switch on
00093  */
00094 int8_t analyseURL(string& url) {
00095     if(url.substr(5, PASSWORD.size()) != PASSWORD)
00096         return(-1);
00097 
00098     uint8_t pos = 5 + PASSWORD.size();
00099 
00100     if(url.substr(pos, 1) == " ")
00101         return(-2);
00102 
00103     if(url.substr(pos++, 1) != "/")
00104         return(-1);
00105 
00106     string  cmd(url.substr(pos, 5));
00107 
00108     if(cmd == "?sw=0")
00109         return(OFF);
00110 
00111     if(cmd == "?sw=1")
00112         return(ON);
00113 
00114     return(-3);
00115 }
00116 
00117 /**
00118  * @brief
00119  * @note
00120  * @param
00121  * @retval
00122  */
00123 string& movedPermanently(uint8_t flag) {
00124     if(flag == 1)
00125         httpContent = "/" + PASSWORD + "/";
00126     else
00127         httpContent = "";
00128 
00129     httpContent += "<h1>301 Moved Permanently</h1>\r\n";
00130 
00131     return(httpContent);
00132 }
00133 
00134 /**
00135  * @brief
00136  * @note
00137  * @param
00138  * @retval
00139  */
00140 string& showWebPage(uint8_t status) {
00141     char roomTempStr[5];
00142 
00143     //roomTemp = ds1820.read();
00144     sprintf(roomTempStr, "%3.1f", roomTemp);
00145 
00146     httpContent = "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>"; 
00147     httpContent += "<pre>Temperature:\t" + string(roomTempStr) + "&deg;C\r\n</pre>";
00148 
00149     if(status == ON) {
00150         httpContent += "<pre>\r\nHeating:\t<font color=#FF0000>On </font>";
00151         httpContent += " <a href=\"./?sw=0\"><button>Turn off</button></a>\r\n";
00152     }
00153     else {
00154         httpContent += "<pre>\r\nHeating:\t<font color=#999999>Off</font>";
00155         httpContent += " <a href=\"./?sw=1\"><button>Turn on</button></a>\r\n";
00156     }
00157 
00158     httpContent += "</pre>\r\n";
00159     httpContent += "<hr>\r\n";
00160     httpContent += "<pre>2017 ARMmbed</pre>";
00161     return httpContent;
00162 }
00163 
00164 /**
00165  * @brief
00166  * @note
00167  * @param
00168  * @retval
00169  */
00170 void sendHTTP(TCPSocketConnection& client, string& header, string& content) {
00171     char    contentLeght[5] = {};
00172 
00173     header += "\r\nContent-Type: text/html\r\n";
00174     header += "Content-Length: ";
00175     sprintf(contentLeght, "%d", content.length());
00176     header += string(contentLeght) + "\r\n";
00177     header += "Pragma: no-cache\r\n";
00178     header += "Connection: About to close\r\n";
00179     header += "\r\n";
00180 
00181     string  webpage = header + content;
00182     client.send(const_cast<char*>(webpage.c_str()), webpage.length());
00183 }
00184 
00185 /**
00186  * @brief
00187  * @note
00188  * @param
00189  * @retval
00190  */
00191 void closeClient(void) {
00192     client.close();
00193     serial.printf("Connection closed.\n\rTCP server is listening...\n\r");
00194 }
00195 
00196 /**
00197  * @brief
00198  * @note
00199  * @param
00200  * @retval
00201  */
00202 int main(void) {
00203 #if defined(W5500)
00204     int     ret = eth.init(MY_MAC, MY_IP, MY_NETMASK, MY_GATEWAY);
00205 #else
00206     int     ret = eth.init(MY_IP, MY_NETMASK, MY_GATEWAY);
00207 #endif
00208     if(!ret) {
00209         serial.printf("Initialized, MY_MAC: %s\n", eth.getMACAddress());
00210         serial.printf
00211             (
00212                 "Connected, MY_IP: %s, MY_NETMASK: %s, MY_GATEWAY: %s\n",
00213                 eth.getIPAddress(),
00214                 eth.getNetworkMask(),
00215                 eth.getGateway()
00216             );
00217     }
00218     else {
00219         serial.printf("Error eth.init() - ret = %d\n", ret);
00220         return -1;
00221     }
00222 
00223     //setup tcp socket
00224     if(server.bind(MY_PORT) < 0) {
00225         serial.printf("TCP server bind failed.\n\r");
00226         return -1;
00227     }
00228     else {
00229         serial.printf("TCP server bind succeeded.\n\r");
00230         serverIsListening = true;
00231     }
00232 
00233     if(server.listen(1) < 0) {
00234         serial.printf("TCP server listen failed.\n\r");
00235         return -1;
00236     }
00237     else {
00238         serial.printf("TCP server is listening...\n\r");
00239     }
00240 
00241     while(serverIsListening) {
00242         if(server.accept(client) >= 0) {
00243             char    buf[1024] = { };
00244             
00245             serial.printf("Client connected!\n\rIP: %s\n\r", client.get_address());
00246             
00247             switch(client.receive(buf, 1023)) {
00248             case 0:
00249                 serial.printf("Recieved buffer is empty.\n\r");
00250                 break;
00251 
00252             case -1:
00253                 serial.printf("Failed to read data from client.\n\r");
00254                 break;
00255 
00256             default:
00257                 string  received((char*)buf);
00258 
00259                 if(received.substr(0, 3) != "GET") {
00260                     httpHeader = HTTP_OK;
00261                     httpContent = "<h1>200 OK</h1>";
00262                     sendHTTP(client, httpHeader, httpContent);
00263                     closeClient();
00264                     continue;
00265                 }
00266 
00267                 if(received.substr(0, 6) == "GET / ") {
00268                     httpHeader = HTTP_OK;
00269                     httpContent = "<p>Usage: http://host_or_ip/password</p>\r\n";
00270                     sendHTTP(client, httpHeader, httpContent);
00271                     closeClient();
00272                     continue;
00273                 }
00274 
00275                 int cmd = analyseURL(received);
00276 
00277                 if(cmd == -2) {
00278 
00279                     // redirect to the right base url
00280                     httpHeader = MOVED_PERM;
00281                     sendHTTP(client, httpHeader, movedPermanently(1));
00282                     closeClient();
00283                     continue;
00284                 }
00285 
00286                 if(cmd == -1) {
00287                     httpHeader = UNAUTHORIZED;
00288                     httpContent = "<h1>401 Unauthorized</h1>";
00289                     sendHTTP(client, httpHeader, httpContent);
00290                     closeClient();
00291                     continue;
00292                 }
00293 
00294                 if(cmd == ON) {
00295                     sw = ON;    // turn the switch on
00296                 }
00297 
00298                 if(cmd == OFF) {
00299                     sw = OFF;   // turn the switch off
00300                 }
00301 
00302                 httpHeader = HTTP_OK;
00303                 sendHTTP(client, httpHeader, showWebPage(sw));
00304             }
00305             closeClient();
00306         }
00307     }
00308 }