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:

main.cpp

Committer:
hudakz
Date:
2019-08-27
Revision:
10:b47c7921346f
Parent:
5:0ab8292e37da
Child:
11:6c0b20227ca2

File content as of revision 10:b47c7921346f:

#include "mbed.h"
#include <string>
#include "UipEthernet.h"
#include "TcpServer.h"
#include "TcpClient.h"

using namespace std;

// To be used when static IP is needed
#define IP      "192.168.1.35"
#define GATEWAY "192.168.1.1"
#define NETMASK "255.255.255.0"
#define PORT    80

// The ENC28J60 chip doesn't have a built-in MAC address.
// It's up to us to provide one which is unique within the connected network.
// So modify the one below accordingly.
const uint8_t   MAC[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
UipEthernet     net(MAC, D11, D12, D13, D10);       // mosi, miso, sck, cs
TcpServer       server;                             // TCP server running on this mbed device
TcpClient*      client;                             // TCP client communicating with a HTTP Browser running on a PC or Mobile device
const int       OFF = 0;
const int       ON = 1;
DigitalOut      output(D3);                         // A digital output to be switched on/off
float           roomTemp = 21.8;                    // A dummy temperature sensor output
const string    PASSWORD = "secret";                // Change as you like
string          httpHeader;                         // HTTP header
string          httpContent;                        // HTTP content

/**
 * @brief   Analyses the received URL
 * @note    The string passed to this function will look like this:
 *          GET /HTTP/1.....
 *          GET /password HTTP/1.....
 *          GET /password/ HTTP/1.....
 *          GET /password/?sw=1 HTTP/1.....
 *          GET /password/?sw=0 HTTP/1.....
 * @param   url URL string
 * @retval -3 just refresh page
 *         -2 no command given but password valid
 *         -1 invalid password
 *          0 switch off
 *          1 switch on
 */
int8_t analyseURL(string& url)
{
    if (url.length() < 5 + PASSWORD.size() + 1)
        return(-1);

    if (url.substr(5, PASSWORD.size()) != PASSWORD)
        return(-1);

    uint8_t pos = 5 + PASSWORD.size();

    if (url.substr(pos, 1) != "/")
        return(-1);

    if (url.substr(pos++, 1) == " ")
        return(-2);

    string  cmd(url.substr(pos, 5));

    if (cmd == "?sw=0")
        return(0);

    if (cmd == "?sw=1")
        return(1);

    return(-3);
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
string& movedPermanently(uint8_t flag)
{
    if (flag == 1)
        httpContent = "/" + PASSWORD + "/";
    else
        httpContent = "";

    httpContent += "<h1>301 Moved Permanently</h1>\r\n";

    return(httpContent);
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
string& showWebPage(int status)
{
    char    roomTempStr[5];

    //roomTemp = ds1820.read();
    sprintf(roomTempStr, "%3.1f", roomTemp);

    /*$off*/
    httpContent  =
        "<head>"
        "<meta charset=\"utf-8\">"
        "<meta name=\"viewport\" content=\" initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=0;\"/>"
        "<title>Smart Home</title>"
        "<link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>"
        "<style>"
        ".switch {"
            "position: relative;"
            "display: inline-block;"
            "width: 60px;"
            "height: 34px;"
        "}"
        ".switch input {display:none;}"
        ".slider {"
            "position: absolute;"
            "cursor: pointer;"
            "top: 0;"
            "left: 0;"
            "right: 0;"
            "bottom: 0;"
            "border-radius: 34px;"
            "background-color: #ccc;"
            "-webkit-transition: .4s;"
            "transition: .4s;"
        "}"
        ".slider:before {"
            "position: absolute;"
            "content: \"\";"
            "height: 26px;"
            "width: 26px;"
            "left: 4px;"
            "bottom: 4px;"
            "border-radius: 50%;"
            "background-color: white;"
            "-webkit-transition: .4s;"
            "transition: .4s;"
        "}"
        "input:checked + .slider {"
            "background-color: #8ce196;"
        "}"
        "input:focus + .slider {"
            "box-shadow: 0 0 1px #8ce196;"
        "}"
        "input:checked + .slider:before {"
            "-webkit-transform: translateX(26px);"
            "-ms-transform: translateX(26px);"
            "transform: translateX(26px);"
        "}"
        "</style>"
        "</head>"

        "<body>"
        "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>"
        "<pre>Temperature:\t" + string(roomTempStr) + "&deg;C</pre>"
        "<pre>Heating:\t";

    if(status == ON) {
        httpContent +=
            "<a href=\"./?sw=0\" class=\"switch\"> "
            "<input type=\"checkbox\" checked>";
    }
    else {
        httpContent +=
            "<a href=\"./?sw=1\" class=\"switch\"> "
            "<input type=\"checkbox\">";
    }

    httpContent +=
        "<div class=\"slider\"></div>"
        "</a>"
        "</pre>"
        "<hr>"
        "<pre>2017 ARMmbed</pre>"
        "</body>";

    return httpContent;
    /*$on*/
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
void sendHTTP(TcpClient& client, string& header, string& content)
{
    /*$off*/
    char    content_length[5] = { };

    header +=
        "\r\nContent-Type: text/html\r\n"
        "Content-Length: ";
    sprintf(content_length, "%d", content.length());
    header +=
        string(content_length) + "\r\n"
        "Pragma: no-cache\r\n"
        "Connection: About to close\r\n\r\n";

    string  webpage = header + content;
    client.write((uint8_t*)webpage.c_str(), webpage.length());
    /*$on*/
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
int main(void)
{
    printf("Starting ...\r\n");

    // IP address must be unique and compatible with your network.
    //net->set_network(IP, NETMASK, GATEWAY);  // include this for using static IP address
    net.connect();

    // Show the network address
    const char*     ip = net.get_ip_address();
    const char*     netmask = net.get_netmask();
    const char*     gateway = net.get_gateway();

    printf("IP address: %s\r\n", ip ? ip : "None");
    printf("Netmask: %s\r\n", netmask ? netmask : "None");
    printf("Gateway: %s\r\n\r\n", gateway ? gateway : "None");
    printf("------------------------------------------------------\r\n");
    printf("Usage: Type %s/%s/ into your web browser and hit ENTER\r\n\r\n", net.get_ip_address(), PASSWORD.c_str());
    printf("------------------------------------------------------\r\n");

    /* Open the server on ethernet stack */
    server.open(&net);

    /* Bind the HTTP port (TCP 80) to the server */
    server.bind(PORT);

    /* Can handle 5 simultaneous connections */
    server.listen(5);

    while (1) {
        client = server.accept();

        if (client) {
            size_t  size = client->available();

            if (size > 0) {
                uint8_t*    buf = (uint8_t*)malloc(size);
                size = client->read(buf, size);

                string  received((char*)buf);
                free(buf);

                if (received.substr(0, 3) != "GET") {
                    httpHeader = "HTTP/1.0 200 OK";
                    httpContent = "<h1>200 OK</h1>";
                    sendHTTP(*client, httpHeader, httpContent);
                    client->close();
                    continue;
                }

                if (received.substr(0, 6) == "GET / ") {
                    httpHeader = "HTTP/1.0 200 OK";
                    httpContent = "<p>Usage: http://host_or_ip/password</p>\r\n";
                    sendHTTP(*client, httpHeader, httpContent);
                    client->close();
                    continue;
                }

                int cmd = analyseURL(received);

                switch (cmd) {
                    case -3:
                        // update webpage
                        httpHeader = "HTTP/1.0 200 OK";
                        sendHTTP(*client, httpHeader, showWebPage(output));
                        break;

                    case -2:
                        // redirect to the right base url
                        httpHeader = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
                        sendHTTP(*client, httpHeader, movedPermanently(1));
                        break;

                    case -1:
                        httpHeader = "HTTP/1.0 401 Unauthorized";
                        httpContent = "<h1>401 Unauthorized</h1>";
                        sendHTTP(*client, httpHeader, httpContent);
                        break;

                    case 0:
                        output = OFF;       // output off
                        httpHeader = "HTTP/1.0 200 OK";
                        sendHTTP(*client, httpHeader, showWebPage(output));
                        break;

                    case 1:
                        output = ON;        // output on
                        httpHeader = "HTTP/1.0 200 OK";
                        sendHTTP(*client, httpHeader, showWebPage(output));
                        break;
                }
            }
            client->close();
        }
    }
}