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

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Tue Jul 03 02:10:23 2018 +0000
Child:
1:016d4400254b
Commit message:
An example program demonstrating the SSDP-based discovery and a companion Web Server to interact with the mbed device. Scan the network (e.g. in Windows Explorer) to identify the node. Click to open its web page to interact with it.

Changed in this revision

EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
SSDP.lib Show annotated file Show diff for this revision Revisions of this file
SW_HTTPServer.lib Show annotated file Show diff for this revision Revisions of this file
SW_String.lib Show annotated file Show diff for this revision Revisions of this file
TimeInterface.lib Show annotated file Show diff for this revision Revisions of this file
Watchdog.lib Show annotated file Show diff for this revision Revisions of this file
WebPages.cpp Show annotated file Show diff for this revision Revisions of this file
WebPages.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetInterface.lib	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/WiredHome/code/EthernetInterface/#fc5d4611c70e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SSDP.lib	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/WiredHome/code/SSDP/#def15d0b2fae
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SW_HTTPServer.lib	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/SW_HTTPServer/#238dd90b6fb3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SW_String.lib	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/WiredHome/code/SW_String/#65bc379d8cd0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TimeInterface.lib	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/TimeInterface/#a89b319b552c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Watchdog.lib	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/Watchdog/#e0f547e22dd5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebPages.cpp	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,249 @@
+
+#include "mbed.h"
+
+#include "EthernetInterface.h"
+#include "WebPages.h"
+
+extern EthernetInterface eth;
+extern const char * BUILD_DATE;
+extern const char * PROG_NAME;
+extern const char * My_Name;
+extern const char * My_SerialNum;
+const int Server_Port = 80;
+
+
+// ##########################################
+// This test version controls the LEDs
+//
+DigitalOut leds[4] = { LED1, LED2, LED3, LED4 };
+
+
+static const char hdrTypeHTML_NoCache[] = 
+    "Content-Type: text/html\r\n"
+    "Cache-Control: no-cache\r\n";
+
+
+// sprintf(buf, ROOTPAGE, "NodeName", "NodeName", "BuildDate", 
+static const char * ROOTPAGE =
+    "<!DOCTYPE html>\r\n"
+    "<html><head><title>%s</title>\r\n"
+    "</head>\r\n"
+    "<body>\r\n"
+    "<h1>%s</h1>"
+    "This project demonstrates the Smartware web server and the Smartware SSDP discovery server.\n"
+    "You should be able to scan the network (e.g. in Windows Explorer) and find this device.\n"
+    "Then you can click on it to open this web page to interact with it.\n"
+    "<br/><br/>\n"
+    "<form method='get'>\n"
+    "<table>\n"
+    "<tr><td>Build</td><td>%s</td></tr>\n"
+    "<tr><td>Set LED</td>\n"
+    "<td><select name='LED'>\n"
+    "   <option value='1'>1</option>\n"
+    "   <option value='2'>2</option>\n"
+    "   <option value='3'>3</option>\n"
+    "   <option value='4'>4</option>\n"
+    " </select>\n"
+    " \n"
+    " <select name='CMD'>\n"
+    "   <option value='0'>Off</option>\n"
+    "   <option value='1'>On</option>\n"
+    " </select>\n"
+    "</td></tr>\n"
+    "<tr><td>&nbsp;</td><td><input type='submit' value='Apply'></td></tr>\n"
+    "</table>\n"
+    "</form>\n"
+    "</body>\n"
+    "</html>\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 0
+    "  <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[1000];
+    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
+    printf("Setup.xml responder\n");
+    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;
+    }
+    return ret;
+}
+
+
+
+HTTPServer::CallBackResults RootPage(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
+                       const HTTPServer::namevalue *queryParams, int queryParamCount)
+{
+    char BigBuffer[1000];
+    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
+    printf("RootPage responder\n");
+    
+    int led, cmd;
+    int mask = 0;
+    for (int i=0; i<queryParamCount; i++) {
+        if (strcmp(queryParams[i].name, "LED") == 0) {
+            led = atoi(queryParams[i].value);
+            mask |= 1;
+        } else if (strcmp(queryParams[i].name, "CMD") == 0) {
+            cmd = atoi(queryParams[i].value);
+            mask |= 2;
+        }
+    }
+    if (mask == 3) {
+        switch (led) {
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+                leds[led - 1] = cmd;
+                break;
+            default:
+                break;
+        }
+    }
+    
+    switch (type) {
+        case HTTPServer::SEND_PAGE:
+            svr->header(HTTPServer::OK, "OK", hdrTypeHTML_NoCache);
+            sprintf(BigBuffer, ROOTPAGE, PROG_NAME, PROG_NAME, BUILD_DATE);            
+            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;
+    }
+    return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebPages.h	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,14 @@
+
+#ifndef WEBPAGES_H
+#define WEBPAGES_H
+
+#include "SW_HTTPServer.h"
+
+
+HTTPServer::CallBackResults Setup_xml(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
+                       const HTTPServer::namevalue *queryParams, int queryParamCount);
+                       
+HTTPServer::CallBackResults RootPage(HTTPServer *svr, HTTPServer::CallBackType type, char * path,
+                       const HTTPServer::namevalue *queryParams, int queryParamCount);
+                       
+#endif // WEBPAGES_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,58 @@
+//
+// A simple SSDP example
+//
+#include "mbed.h"               // ver 120; mbed-rtos ver 111
+#include "EthernetInterface.h"  // ver 55
+#include "SW_HTTPServer.h"      // ver 50
+#include "TimeInterface.h"      // ver 23
+#include "Watchdog.h"           // ver 6
+#include "SW_String.h"          // ver 1
+#include "SSDP.h"               // ver 0
+
+#include "WebPages.h"           // Private handler for web queries
+
+RawSerial pc(USBTX, USBRX);
+
+EthernetInterface eth;
+TimeInterface ntp(&eth);
+Watchdog wd;
+time_t lastboottime;
+
+//FlashFileSystem flash("flash");             // static files here for reliability and speed
+LocalFileSystem local("local");             // some place to hold settings and maybe the static web pages
+
+const char * Server_Root = "/local";
+
+// public for the WebPages handler to see
+//
+const char * BUILD_DATE = __DATE__ " " __TIME__;
+const char * PROG_NAME = "SSDP Server";
+const char * My_Name = "MBED SSDP Node";
+const char * My_SerialNum = "0000001";
+const int Server_Port = 80;
+// end public information
+
+
+int main() {
+    pc.baud(460800);
+    pc.printf("\r\n%s Build %s\r\n", PROG_NAME, BUILD_DATE);
+    if (wd.WatchdogCausedReset()) {
+        pc.printf("**** Watchdog Event caused reset at %s ****\r\n", ntp.ctime(&lastboottime));
+    }
+    wd.Configure(45);       // very generous, but this is a network appliance, so a bit less deterministic.
+
+    eth.init(); //Use DHCP
+    eth.connect();
+    printf("IP: %s\n", eth.getIPAddress());
+    //Thread thr(SSDPListener, NULL, osPriorityLow);
+    HTTPServer svr(Server_Port, Server_Root, 15, 30, 20, 50, &pc);
+    svr.RegisterHandler("/", RootPage);
+    svr.RegisterHandler("/setup.xml", Setup_xml);
+    SSDP ssdp("Friendly Node", eth.getMACAddress(), eth.getIPAddress(), Server_Port);
+    
+    while (1) {
+        wd.Service();
+        svr.Poll();         // non-blocking, but also not deterministic
+        Thread::yield();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#162b12aea5f2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jul 03 02:10:23 2018 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/mbed_official/code/mbed/builds/7c328cabac7e
\ No newline at end of file