X10 Server - IOT device to leverage a collection of old X10 devices for home automation and lighting control.

Dependencies:   IniManager mbed HTTPClient SWUpdate mbed-rtos Watchdog X10 SW_HTTPServer SW_String EthernetInterface TimeInterface SSDP

X10 Server

See the X10 Server Nodebook page

WebPages.cpp

Committer:
WiredHome
Date:
2019-03-04
Revision:
12:67c524db9e07
Parent:
8:a45fe77efcc5

File content as of revision 12:67c524db9e07:


#include "mbed.h"

#include "EthernetInterface.h"
#include "SW_String.h"
#include "X10.h"
#include "WebPages.h"
#include "IniManager.h"         // v20

extern INI ini;
extern X10Interface cm17a;

extern EthernetInterface eth;
extern const char * BUILD_DATE;
extern const char * PROG_NAME;
extern const char * My_Name;
extern const char * My_SerialNum;
extern int Server_Port;

extern bool swUpdateCheck;

extern DigitalOut linkdata;

extern "C" void mbed_reset();


static const char hdrTypeHTML_NoCache[] = 
    "Content-Type: text/html\r\n"
    "Cache-Control: no-cache\r\n";


// The /setup.xml file
//
// sprintf(buf, SETUP_TEMPLATE, "FriendlyName", "udn_hexstring", "serialNum", "ip.ad.dr", portNum);
static const char SETUP_TEMPLATE[] =
    "<?xml version=\"1.0\"?>\n"
    "<root xmlns=\"urn:Belkin:device-1-0\">\n"
    " <specVersion>\n"
    "  <major>1</major>\n"
    "  <minor>0</minor>\n"
    " </specVersion>\n"
    " <device>\n"
    "  <deviceType>urn:Belkin:device:controllee:1</deviceType>\n"
    "  <friendlyName>%s</friendlyName>\n"
    "  <manufacturer>Belkin International Inc.</manufacturer>\n"            ///< must be "Belkin..." for Alexa discovery
    "  <manufacturerURL>http://www.smart-family.net</manufacturerURL>\n"    ///<
    "  <modelDescription>Special thing</modelDescription>\n"   ///<
    "  <modelName>Smart Node</modelName>\n"                                ///<
    "  <modelNumber>1.0.0</modelNumber>\n"
#if 1
    "  <modelURL>http://www.smart-family.net</modelURL>\n"                  ///< This causes it to fail to send completely
#endif
    "  <UDN>uuid:Socket-1_0-%s</UDN>\n"
    "  <serialNumber>%s</serialNumber>\n"
    "  <iconList>\n"
    "   <mimetype>jpg</mimetype>\n"
    "   <width>100</width>\n"
    "   <height>100</height>\n"
    "   <depth>100</depth>\n"
    "   <url>icon.jpg</url>\n"
    "  </iconList>\n"
    "  <presentationURL>http://%s:%d</presentationURL>\n"
#if 0
    "  <serviceList>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:WiFiSetup:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:WiFiSetup1</serviceId>\n"
    "    <controlURL>/upnp/control/WiFiSetup1</controlURL>\n"
    "    <eventSubURL>/upnp/event/WiFiSetup1</eventSubURL>\n"
    "    <SCPDURL>/setupservice.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:timesync:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:timesync1</serviceId>\n"
    "    <controlURL>/upnp/control/timesync1</controlURL>\n"
    "    <eventSubURL>/upnp/event/timesync1</eventSubURL>\n"
    "    <SCPDURL>/timesyncservice.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:basicevent:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:basicevent1</serviceId>\n"
    "    <controlURL>/upnp/control/basicevent1</controlURL>\n"
    "    <eventSubURL>/upnp/event/basicevent1</eventSubURL>\n"
    "    <SCPDURL>/eventservice.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:firmwareupdate:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:firmwareupdate1</serviceId>\n"
    "    <controlURL>/upnp/control/firmwareupdate1</controlURL>\n"
    "    <eventSubURL>/upnp/event/firmwareupdate1</eventSubURL>\n"
    "    <SCPDURL>/firmwareupdate.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:rules:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:rules1</serviceId>\n"
    "    <controlURL>/upnp/control/rules1</controlURL>\n"
    "    <eventSubURL>/upnp/event/rules1</eventSubURL>\n"
    "    <SCPDURL>/rulesservice.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:metainfo:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:metainfo1</serviceId>\n"
    "    <controlURL>/upnp/control/metainfo1</controlURL>\n"
    "    <eventSubURL>/upnp/event/metainfo1</eventSubURL>\n"
    "    <SCPDURL>/metainfoservice.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:remoteaccess:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:remoteaccess1</serviceId>\n"
    "    <controlURL>/upnp/control/remoteaccess1</controlURL>\n"
    "    <eventSubURL>/upnp/event/remoteaccess1</eventSubURL>\n"
    "    <SCPDURL>/remoteaccess.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:deviceinfo:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:deviceinfo1</serviceId>\n"
    "    <controlURL>/upnp/control/deviceinfo1</controlURL>\n"
    "    <eventSubURL>/upnp/event/deviceinfo1</eventSubURL>\n"
    "    <SCPDURL>/deviceinfoservice.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:smartsetup:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:smartsetup1</serviceId>\n"
    "    <controlURL>/upnp/control/smartsetup1</controlURL>\n"
    "    <eventSubURL>/upnp/event/smartsetup1</eventSubURL>\n"
    "    <SCPDURL>/smartsetup.xml</SCPDURL>\n"
    "   </service>\n"
    "   <service>\n"
    "    <serviceType>urn:Belkin:service:manufacture:1</serviceType>\n"
    "    <serviceId>urn:Belkin:serviceId:manufacture1</serviceId>\n"
    "    <controlURL>/upnp/control/manufacture1</controlURL>\n"
    "    <eventSubURL>/upnp/event/manufacture1</eventSubURL>\n"
    "    <SCPDURL>/manufacture.xml</SCPDURL>\n"
    "   </service>\n"
    "  </serviceList>\n"
#endif
    " </device>\n"
    "</root>\n";


HTTPServer::CallBackResults Setup_xml(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
                       const HTTPServer::namevalue *queryParams, int queryParamCount)
{
    char BigBuffer[sizeof(SETUP_TEMPLATE) + 150];
    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
    linkdata = true;
    switch (type) {
        case HTTPServer::SEND_PAGE:
            svr->header(HTTPServer::OK, "OK", hdrTypeHTML_NoCache);
            sprintf(BigBuffer, SETUP_TEMPLATE, 
                My_Name, eth.getMACAddress(), My_SerialNum,
                eth.getIPAddress(), Server_Port);
            svr->send(BigBuffer);
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::CONTENT_LENGTH_REQUEST:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::DATA_TRANSFER:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        default:
            ret = HTTPServer::ACCEPT_ERROR;
            break;
    }
    linkdata = false;
    return ret;
}



HTTPServer::CallBackResults RootPage(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
                       const HTTPServer::namevalue *queryParams, int queryParamCount)
{
    char smallBuf[100];
    char bigBuf[3000] = "";      // sized by test and adjust, and then round up generously.
    int count;
    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
    
    linkdata = true;
    switch (type) {
        case HTTPServer::SEND_PAGE:
            if (0 == strcmp(svr->GetParameter("SWUpdate"),"CheckNow")) {
                swUpdateCheck = true;
                svr->header(HTTPServer::Found, "Found", "Location: /\r\n");
                svr->send("\r\n");
                break;
            }
            count = svr->GetParameterCount();
            printf("Data Transfer: %d parameters\r\n", count);
            if (count) {
                //for (int i=0; i<count; i++) {
                //    const HTTPServer::namevalue * nv = svr->GetParameter(i);
                //    printf("  %d: %s => %s\r\n", i, nv->name, nv->value);
                //}
                const char * p = svr->GetParameter("House");
                if (p && strlen(p) == 1) {
                    char cmdBuf[7];     // "HUU +6"
                    strcpy_s(cmdBuf, sizeof(cmdBuf), p);
                    p = svr->GetParameter("Unit");
                    if (p && strlen(p) >= 1 && strlen(p) <= 2) {
                        strcat_s(cmdBuf, sizeof(cmdBuf), p);
                        p = svr->GetParameter("Cmd");
                        if (p && strlen(p) >= 1 && strlen(p) <= 2) {
                            strcat_s(cmdBuf, sizeof(cmdBuf), " ");
                            strcat_s(cmdBuf, sizeof(cmdBuf), p);
                            printf("Web Command: '%s'\r\n", cmdBuf);
                            cm17a.ParseCommand(cmdBuf);
                            svr->header(HTTPServer::Found, "Found", "Location: /\r\n");
                            svr->send("\r\n");
                            break;
                        }
                    }
                }
            }

            svr->header(HTTPServer::OK, "OK", "Content-Type: text/html\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<title>X10 Server Info</title>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<style>\n");
            strcat_s(bigBuf, sizeof(bigBuf), "body {\n");
            strcat_s(bigBuf, sizeof(bigBuf), "   transform: scale(1.6);\n");
            strcat_s(bigBuf, sizeof(bigBuf), "   transform-origin: 0 0;\n");
            strcat_s(bigBuf, sizeof(bigBuf), "}\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</style>\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</head>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<body>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<h1>X10 Server Info</h1>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<blockquote>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<table border='1'>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<tr><th><h2>Command</h2></th></tr>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<tr><td>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<form method='get'>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<table border='0'><tr><th>House</th><th>Unit</th><th>Cmd</th><th>&nbsp;</th></tr>\r\n");
            // House code
            strcat_s(bigBuf, sizeof(bigBuf), "<tr><td align='center'><select name='House'>\r\n");
            for (int i = 'A'; i <= 'P'; i++) {
                snprintf(smallBuf, 100, "<option value='%c'>%c</option>\r\n", i, i);
                strcat_s(bigBuf, sizeof(bigBuf), smallBuf);
            }
            strcat_s(bigBuf, sizeof(bigBuf), "</select></td>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<td><select name='Unit'>\r\n");
            for (int i = 1; i <= 16; i++) {
                snprintf(smallBuf, 100, "<option value='%d'>%d</option>\r\n", i, i);
                strcat_s(bigBuf, sizeof(bigBuf), smallBuf);
            }
            strcat_s(bigBuf, sizeof(bigBuf), "</select></td>\r\n");
            // Unit code
            strcat_s(bigBuf, sizeof(bigBuf), "<td><select name='Cmd'>\r\n");
            for (int i = -6; i <= 7; i++) {
                if (i < 0)
                    snprintf(smallBuf, 100, "<option value='%+d'>%+d</option>\r\n", i, i);
                else if (i == 0) 
                    snprintf(smallBuf, 100, "<option value='%d' selected>%d</option>\r\n", i, i);
                else if (i == 1)
                    snprintf(smallBuf, 100, "<option value='%d'>%d</option>\r\n", i, i);
                else // if (i > 1)
                    snprintf(smallBuf, 100, "<option value='%+d'>%+d</option>\r\n", i-1, i-1);
                strcat_s(bigBuf, sizeof(bigBuf), smallBuf);
            }
            strcat_s(bigBuf, sizeof(bigBuf), "</select></td>\r\n");

            strcat_s(bigBuf, sizeof(bigBuf), "<td><input type='Submit' value='Send'></td>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</tr></table>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</form>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</td></tr></table>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<br/><br/><a href='/info'>info Page</a> | <a href='/setup.xml'>setup.xml</a>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</blockquote>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "X10 Server, Copyright &copy; 2019 by Smartware Computing, all rights reserved.");
            strcat_s(bigBuf, sizeof(bigBuf), "</body></html>");
            printf("bigBuf size is %d bytes\r\n", strlen(bigBuf));
            svr->send(bigBuf);
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::CONTENT_LENGTH_REQUEST:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::DATA_TRANSFER:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        default:
            ret = HTTPServer::ACCEPT_ERROR;
            break;
    }
    linkdata = false;
    return ret;
}


HTTPServer::CallBackResults InfoPage(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
                       const HTTPServer::namevalue *queryParams, int queryParamCount)
{
    char lineBuf[60];
    char bigBuf[1000] = "";      // sized by test and adjust, and then round up generously.
    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
    FILE * fh;
    
    linkdata = true;
    switch (type) {
        case HTTPServer::SEND_PAGE:
            svr->header(HTTPServer::OK, "OK", "Content-Type: text/html\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<!DOCTYPE html>\r\n<html><head><title>X10 Server Info</title></head>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<body>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<h1>X10 Server Info</h1>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<table border='1' width='100%'>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<tr><th>Configuration</th><th>Software</th></tr>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<tr><td valign='top' width='50%'><pre>\r\n");
            fh = fopen("/local/X10svr.ini", "rt");
            if (fh) {
                char fileBuf[60];
                while(fgets(fileBuf, sizeof(fileBuf), fh)) {
                    strcat_s(bigBuf, sizeof(bigBuf), fileBuf);
                }
                fclose(fh);
            }
            strcat_s(bigBuf, sizeof(bigBuf), "</pre>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</td>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<td valign='top' width='50%'><pre>\r\n");
            if (INI::INI_SUCCESS == ini.ReadString("SWUpdate", "name", lineBuf, sizeof(lineBuf))) {
                strcat_s(bigBuf, sizeof(bigBuf), "name=");
                strcat_s(bigBuf, sizeof(bigBuf), lineBuf);
                strcat_s(bigBuf, sizeof(bigBuf), "\r\nversion=");
                lineBuf[6] = '\0';
                char fname[45];
                snprintf(fname, sizeof(fname), "/local/%s.ver", lineBuf);
                fh = fopen(fname, "rt");
                if (fh) {
                    while(fgets(lineBuf, sizeof(lineBuf), fh)) {
                        strcat_s(bigBuf, sizeof(bigBuf), lineBuf);
                    }
                    fclose(fh);
                }
            }
            strcat_s(bigBuf, sizeof(bigBuf), "</pre>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<img src='/icon.png'>");
            strcat_s(bigBuf, sizeof(bigBuf), "</td></tr>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<tr>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<td><a href='/'>Home Page</a> | <a href='/reboot'>Reboot</a></td>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "<td><a href='/software'>Software Update Check</a> | ");
            strcat_s(bigBuf, sizeof(bigBuf), "<a href='/setup.xml' target='_xml'>view setup.xml</a>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</td></tr></table>\r\n");
            strcat_s(bigBuf, sizeof(bigBuf), "</body></html>");
            printf("bigBuf size is %d bytes\r\n", strlen(bigBuf));
            svr->send(bigBuf);
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::CONTENT_LENGTH_REQUEST:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::DATA_TRANSFER:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        default:
            ret = HTTPServer::ACCEPT_ERROR;
            break;
    }
    linkdata = false;
    return ret;
}


HTTPServer::CallBackResults SoftwarePage(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
                       const HTTPServer::namevalue *queryParams, int queryParamCount)
{
    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
    
    linkdata = true;
    switch (type) {
        case HTTPServer::SEND_PAGE:
            swUpdateCheck = true;
            printf("SW Update Check scheduled.\r\n");
            svr->header(HTTPServer::Found, "Found", "Location: /\r\n");
            svr->send("\r\n");
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::CONTENT_LENGTH_REQUEST:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::DATA_TRANSFER:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        default:
            ret = HTTPServer::ACCEPT_ERROR;
            break;
    }
    linkdata = false;
    return ret;
}


HTTPServer::CallBackResults RebootPage(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
                       const HTTPServer::namevalue *queryParams, int queryParamCount)
{
    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
    
    linkdata = true;
    switch (type) {
        case HTTPServer::SEND_PAGE:
            swUpdateCheck = true;
            printf("Reboot scheduled.\r\n");
            svr->header(HTTPServer::Found, "Found", "Location: /\r\n");
            svr->send("\r\n");
            Thread::wait(500);
            mbed_reset();
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::CONTENT_LENGTH_REQUEST:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        case HTTPServer::DATA_TRANSFER:
            ret = HTTPServer::ACCEPT_COMPLETE;
            break;
        default:
            ret = HTTPServer::ACCEPT_ERROR;
            break;
    }
    linkdata = false;
    return ret;
}