mqtt specific components for the impact mbed endpoint library
Dependents: mbed_mqtt_endpoint_ublox_ethernet mbed_mqtt_endpoint_ublox_cellular mbed_mqtt_endpoint_nxp
Revision 0:a3fc1c6ef150, committed 2014-03-26
- Comitter:
- ansond
- Date:
- Wed Mar 26 19:48:35 2014 +0000
- Child:
- 1:5976e067b32a
- Commit message:
- updates
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Definitions.h Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,130 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DEFINITIONS_H_ +#define _DEFINITIONS_H_ + +// platform +#include "mbed.h" + +// include common definitions +#include "CommonDefinitions.h" + +// Until we get HTTPS with BasicAuth working in MBED... +#define GW_IPADDRESS "192.168.1.220" // gateway IP address (default) +#define USE_GW_HTTP_REDIRECTOR true // true - make http calls to IOC via GW, false - make http calls directly to IOC + +// Gateway REST API URL +#define GW_REDIRECT_URL "http://%s:8888/NSP-IOC-Gateway/IOCRestAPI" + +// Memory Debug Enable/Disable +// #define ENABLE_MEMORY_DEBUG true // false - disable, true - enable + +// Hush Logging +//#define HUSH_LOG true // false - logging output, true - no logging + +// Hush LED usage +//define HUSH_LEDS true // false - enable LEDs, true - disable LEDs + +// Our Endpoint Version Annoucement +#define ENDPOINT_VERSION_ANNOUNCE "\r\nMBED IMPACT(MQTT) Endpoint v1.0" + +// Preference File Configuration +#define PREFERENCES_FILE "/local/mqtt.cfg" // preferences file for endpoint + +// our MAC address +//#define MAC_ADDRESS 0xa0,0x12,0xAB,0xE3,0x4F,0x56 + +// Light Configuration +#define LIGHT_NAME "light-mqtt-%d" // name of each light in this endpoint +#define LIGHT_BLINK_WAIT_MS 1000 // time between blinks (ms) +#define LIGHT_NAME_INDEX 1 // start index for the ID of the light name + +// Philips Light Config +#define PL_ENABLE false // true - enable for endpoint light, false - disable +#define PL_LIGHT_ID PL_LIGHT_ID_BILL // Default light for Philips Light + +// External LED Light Configuration +#define EXT_LED_ENABLE true // true - enable external LED endpoint light, false - disable +#define EXT_LED_PIN p21 // pin to use for external LED cathode + +// Endpoint GPS Coordinates/Location +#define ENDPOINT_LOCATION "Las Vegas Country Club" // Where this light/endpoint lives +#define ENDPOINT_GPS_COORDS "-115.143470 36.131916" // golf course -115.143470 36.131916 + +// MBED doesnt have a good notion of time - so we code it here +#define ENDPOINT_STARTTIME "\"STARTDATETIME\":\"2014-03-09T22:03:06-07:00\"," +#define ENDPOINT_STOPTIME "\"ENDDATETIME\":\"2015-03-10T03:35:55-07:00\"," +#define ENDPOINT_TIMEZONE "\"TIMEZONEOFFSET\":\"-07:00\"" + +// Keyword Definitions for MQTT packets +#define IOC_REQUEST_LOAD_ALL_VERB "load" +#define IOC_REQUEST_UPDATE_ALL_VERB "update" +#define IOC_ENDPOINT_VERB "Endpoint" +#define IOC_ENDPOINT_ALL_VERB "all" +#define IOC_CHANGE_VERB "Change" +#define IOC_REQUEST_VALUE_VERB "Get" +#define IOC_RESPONSE_VERB "response" +#define IOC_REPONSE_ID_KEY "id" +#define IOC_DATASOURCE_ID "229" + +// IOC REST Buffer Lengths +#define IOC_REST_URL_LEN 128 +#define IOC_RESULT_LEN 1024 +#define IOC_PAYLOAD_LEN 768 +#define IOC_IOC_ID_LEN 16 + +// IOC REST URL for Load/Updates +#define IOC_USERNAME "anson" +#define IOC_PASSWORD "savetheplanet1" +#define IOC_HOST_NAME "iocweb.bcu.ac.uk" // IOC Web - iocweb.bcu.ac.uk +#define IOC_REST_URL "https://%s/ibm/ioc/api/data-injection-service/datablocks/%s/dataitems%s" +#define IOC_RESPONSE_TEMPLATE "%s:{ENDPOINT=%s RESOURCE=%s VALUE=%s}:%s" +#define IOC_RESPONSE_OK "OK" +#define IOC_RESPONSE_FAILED "FAILED" + +// Transport Configuration +#define NUM_TRANSPORTS 2 // MQTT, HTTP +#define MQTT_TRANSPORT 0 // MQTT Transport index +#define HTTP_TRANSPORT 1 // HTTP Transport index + +// Index for Transport to use for Update/Load +#define LOAD_TRANSPORT 1 // 0 - MQTT, 1 - HTTP + +// largest MQTT message that PubSubClient will send +#define MAX_MQTT_MESSAGE_LENGTH 128 + +// MQTT connect information +#define MQTT_HOSTNAME "iocana.bcu.ac.uk" // IOC MQTT Broker Host - iocana.bcu.ac.uk +#define MQTT_HOSTPORT 1883 // IOC MQTT Broker Port +#define MQTT_ENDPOINT_ID "mbed%d%d" // IOC MQTT Endpoint ID template +#define MQTT_MAXID_VALUE 99 // IOC MQTT Endpoint ID maximum integer value +#define MQTT_ENDPOINT_IDLEN 64 // IOC MQTT Endpoint ID length (max) +#define MQTT_IOC_TOPIC "ARM/sensinode/control/%s" // IOC MQTT Topic +#define MQTT_IOC_ALL_TOPIC "ARM/sensinode/control/all" // IOC MQTT Topic (broadcast) +#define MQTT_PING_SEND_TOPIC "ARM/sensinode/ping" // IOC MQTT Ping Send Topic +#define MQTT_IOC_ALL_ENDPOINT "all" // must be the same as the last element of MATT_IOC_ANNOUNCE_TOPIC +#define MQTT_IOC_TOPIC_LEN 64 // max length for the topic string +#define MQTT_PAYLOAD_SEGMENT_LEN 64 // max length for a segment of the payload +#define MQTT_USERNAME "" // IOC MQTT Username +#define MQTT_PASSWORD "" // IOC MQTT Password +#define MQTT_PING_VERB_LEN 10 // Ping or Pong +#define MQTT_PING_COUNTDOWN 1200 // Send ping to GW every 1200'th 250ms iterations (5 minutes) +#define MQTT_MAX_COUNTER 32768 // largest Ping counter before reset back to 1 + +#endif // _DEFINITIONS_H \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EmulatedLightDimmerAction.cpp Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,41 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + #include "EmulatedLightDimmerAction.h" + + // Our instance + EmulatedLightDimmerAction *_dimmerAction = NULL; + + // static callback for Dimming operations + void emulated_light_dimming_cb() { + if (_dimmerAction != NULL) ((LightDimmerAction *)_dimmerAction)->dim(); + } + + // default constructor + EmulatedLightDimmerAction::EmulatedLightDimmerAction(ErrorHandler *error_handler,Light *light) : LightDimmerAction(error_handler,light) { + _dimmerAction = this; + } + + // destructor + EmulatedLightDimmerAction::~EmulatedLightDimmerAction() { + } + + // DIM the light + void EmulatedLightDimmerAction::dim(int value) { + if (this->light() != NULL) ((LightDimmerAction *)this)->light()->dim(value); + } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EmulatedLightDimmerAction.h Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,33 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _EMULATED_LIGHT_DIMMER_ACTION_H_ +#define _EMULATED_LIGHT_DIMMER_ACTION_H_ + +// Base class +#include "LightDimmerAction.h" + +class EmulatedLightDimmerAction : public LightDimmerAction { + public: + EmulatedLightDimmerAction(ErrorHandler *error_handler,Light *light); + virtual ~EmulatedLightDimmerAction(); + + void dim(int value); +}; + +#endif // _LIGHT_DIMMER_ACTION_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EmulatedLightSwitchAction.cpp Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,46 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + #include "EmulatedLightSwitchAction.h" + + // Our instance + EmulatedLightSwitchAction *_switchAction = NULL; + + // static callback for Switching operations + void emulated_light_switch_cb() { + if (_switchAction != NULL) ((LightSwitchAction *)_switchAction)->toggle(); + } + + // default constructor + EmulatedLightSwitchAction::EmulatedLightSwitchAction(ErrorHandler *error_handler,Light *light) : LightSwitchAction(error_handler,light) { + _switchAction = this; + } + + // destructor + EmulatedLightSwitchAction::~EmulatedLightSwitchAction() { + } + + // Light turned ON + void EmulatedLightSwitchAction::on() { + if (this->light() != NULL) ((LightSwitchAction *)this)->light()->on(); + } + + // Light turned OFF + void EmulatedLightSwitchAction::off() { + if (this->light() != NULL) ((LightSwitchAction *)this)->light()->off(); + } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EmulatedLightSwitchAction.h Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,34 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _EMULATED_LIGHT_SWITCH_ACTION_H_ +#define _EMULATED_LIGHT_SWITCH_ACTION_H_ + +// Base class +#include "LightSwitchAction.h" + +class EmulatedLightSwitchAction : public LightSwitchAction { + public: + EmulatedLightSwitchAction(ErrorHandler *error_handler,Light *light); + virtual ~EmulatedLightSwitchAction(); + + void on(); + void off(); +}; + +#endif // _LIGHT_SWITCH_ACTION_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EmulatedResourceFactory.cpp Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,148 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + // class definition + #include "EmulatedResourceFactory.h" + + // MBEDEndpoint support + #include "MBEDEndpoint.h" + + // MBED supports Battery Emulation + #include "MBEDBattery.h" + + // MBED supports Current Emulation + #include "MBEDCurrent.h" + + // MBED supports Temperature Sensing + #include "MBEDTemperature.h" + + // MBED supports GPS Emulation + #include "MBEDgps.h" + + // MBED supports RSSI Emulation + #include "MBEDrssi.h" + + // MBED supports Voltage Emulation + #include "MBEDVoltage.h" + + // MBED supports Wattage Emulation + #include "MBEDWattage.h" + + // Initializers + void init_battery(Resource *resource) { if (resource != NULL) new MBEDBattery(resource->logger(),resource); } + void init_current(Resource *resource) { if (resource != NULL) new MBEDCurrent(resource->logger(),resource); } + void init_gps(Resource *resource) { if (resource != NULL) new MBEDgps(resource->logger(),resource); } + void init_rssi(Resource *resource) { if (resource != NULL) new MBEDrssi(resource->logger(),resource); } + void init_temperature(Resource *resource) { if (resource != NULL) new MBEDTemperature(resource->logger(),resource); } + void init_voltage(Resource *resource) { if (resource != NULL) new MBEDVoltage(resource->logger(),resource); } + void init_wattage(Resource *resource) { if (resource != NULL) new MBEDWattage(resource->logger(),resource); } + + // Ethernet + #include "EthernetInterface.h" + extern EthernetInterface ethernet; + + // NSP supports Light Dimming + extern void emulated_light_dimming_cb(); + + // NSP supports Light Switch + extern void emulated_light_switch_cb(); + + // default constructor + EmulatedResourceFactory::EmulatedResourceFactory(ErrorHandler *error_handler,void *endpoint) : ResourceFactory(error_handler,endpoint) { + this->initGPSCoords(); + } + + // default destructor + EmulatedResourceFactory::~EmulatedResourceFactory() { + } + + // initialize our GPS coords + void EmulatedResourceFactory::initGPSCoords() { + memset(this->m_gps_coords,0,PREFERENCE_VALUE_LEN+1); + MBEDEndpoint *endpoint = (MBEDEndpoint *)this->m_endpoint; + endpoint->preferences()->getPreference("coords",this->m_gps_coords,PREFERENCE_VALUE_LEN,ENDPOINT_GPS_COORDS); + } + + // get our GPS coords from preferences + char *EmulatedResourceFactory::getGPSCoords() { return this->m_gps_coords; } + + // create resources + void EmulatedResourceFactory::createResources(char *endpoint_name) { + // create all of the resources we expect for this endpoint + this->createResource("/dev/addldata","id:0"); + this->createResource("/dev/location",ENDPOINT_LOCATION); + this->createResource("/fw/devtype","Light"); + this->createResource("/dev/bat","5.0V",(void *)&init_battery,NULL); + this->createResource("/sen/I","0.1A",(void *)&init_current,NULL); + this->createResource("/dev/I","0.1A",(void *)&init_current,NULL); + this->createResource("/nw/ipaddr",ethernet.getIPAddress()); + this->createResource(endpoint_name,"/lt/0/dim","25",(void *)&emulated_light_dimming_cb); // Action: dim/brighten light + this->createResource("/nw/eripaddr","N/A"); + this->createResource(endpoint_name,"/lt/0/on","1",(void *)&emulated_light_switch_cb); // Action: light on/off + this->createResource(endpoint_name,"/lt/0/ctr","1",(void *)&emulated_light_switch_cb); // Action: light on/off + this->createResource("/dev/mdl","MQTT MBED Light"); + this->createResource("/dev/mfg","NXP MBED"); + this->createResource("/gps/int","60"); + this->createResource("/gps/fix","1"); + this->createResource("/nw/pipaddr","N/A"); + this->createResource("/dev/W","0.1W",(void *)&init_wattage,NULL); + this->createResource("/nw/prssi","-75",(void *)&init_rssi,NULL); + this->createResource("/sen/temp","10.0C",(void *)&init_temperature,NULL); + this->createResource("/dev/t","10.0C",(void *)&init_temperature,NULL); + this->createResource("/sen/V","5.0V",(void *)&init_voltage,NULL); + this->createResource("/dev/V","5.0V",(void *)&init_voltage,NULL); + this->createResource("/gps/loc",this->getGPSCoords(),(void *)&init_gps,NULL); + this->createResource("/ns/nspaddr","(NA)"); + this->createResource(endpoint_name,"/dev/panic","0",(void *)&emulated_light_switch_cb); // Action: light on/off + +#ifdef MAC_ADDRESS + extern char fmt_mac[RESOURCE_VALUE_LEN+1]; + this->createResource("/nw/macaddr",fmt_mac); +#else + this->createResource("/nw/macaddr","00:00:00:00:00"); +#endif + } + + void EmulatedResourceFactory::createResource(char *name,char *value) { ResourceFactory::createResource(name,value); } + void EmulatedResourceFactory::createResource(char *ep_name,char *name,char *value,void *cb) { ResourceFactory::createResource(ep_name,name,value,cb); } + void EmulatedResourceFactory::createResource(char *name,char *value,void *io,void *notused) { + MBEDEndpoint *endpoint = (MBEDEndpoint *)this->m_endpoint; + char *ep_name = NULL; if (endpoint != NULL) ep_name = endpoint->getEndpointName(); + this->m_list[this->m_count] = new Resource(this->logger(),ep_name,name,value,NULL); + if (io != NULL && this->m_list[this->m_count] != NULL) { + resourceInitializer initializer = (resourceInitializer)io; + (initializer)(this->m_list[this->m_count]); + } + if (this->m_list[this->m_count] != NULL) ++this->m_count; + } + + // set a resource value (AND trigger the Emulated actions if registered) + bool EmulatedResourceFactory::setResourceValue(char *name, char *value) { + // set the resource value + bool success = ResourceFactory::setResourceValue(name,value); + if (success) { + // invoke an action if registered + EmulatedCallbackPointer cb = (EmulatedCallbackPointer)this->getCallbackPointer(name); + if (cb != NULL) { + // invoke the callback + this->logger()->log("Invoking Action..."); + cb(); + } + } + return success; + } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EmulatedResourceFactory.h Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,57 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _EMULATED_RESOURCE_FACTORY_H_ +#define _EMULATED_RESOURCE_FACTORY_H_ + +// Base Class +#include "ResourceFactory.h" + +// Emulated callback structure +typedef void (*EmulatedCallbackPointer)(); + +// ErrorHandler support +#include "ErrorHandler.h" + +// Resource Initializer callback structure +typedef void (*resourceInitializer)(Resource *); + +class EmulatedResourceFactory : public ResourceFactory { + private: + char m_gps_coords[PREFERENCE_VALUE_LEN+1]; + + public: + EmulatedResourceFactory(ErrorHandler *error_handler,void *endpoint); + virtual ~EmulatedResourceFactory(); + + virtual void createResources(char *endpoint_name); + + bool setResourceValue(char *name, char *value); + + protected: + virtual void createResource(char *endpoint_name,char *name,char *value,void *cb); + virtual void createResource(char *name,char *value); + void createResource(char *name,char *value,void *io,void *notused); + + private: + void initGPSCoords(); + char *getGPSCoords(); + }; + + +#endif // _EMULATED_RESOURCE_FACTORY_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IOCHTTPTransport.cpp Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,104 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + #include "IOCHTTPTransport.h" + + // default constructor + IOCHTTPTransport::IOCHTTPTransport(ErrorHandler *error_handler,void *endpoint) : HTTPTransport(error_handler,endpoint) { + memset(this->m_url_buffer,0,IOC_REST_URL_LEN+1); + } + + // default destructor + IOCHTTPTransport::~IOCHTTPTransport() { + } + + // package up data + char *IOCHTTPTransport::packageData(char *verb,char *data,int ioc_id) { + char buffer[IOC_PAYLOAD_LEN+1]; + memset(buffer,0,IOC_PAYLOAD_LEN+1); + if (USE_GW_HTTP_REDIRECTOR == false) { + // just use the data + return data; + } + else { + // repackage into format: VERB;USER;PASS;AUTHDOMAIN;CONTENTTYPE;JSON;URL + sprintf(buffer,"%s;%s;%s;_none_;%s;%s;%s ",verb,IOC_USERNAME,IOC_PASSWORD,"application/json",data,this->createIOCUpdateURL(ioc_id,false)); + memcpy(data,buffer,strlen(buffer)); + return data; + } + } + + // Load up our endpoint into the IOC + bool IOCHTTPTransport::loadEndpoint(char *data,int data_length,char *result,int result_length) { + data = this->packageData("POST",data,0); // must be first as it will first write into the common URL buffer + char *url = this->createIOCLoadURL(); // resets the common URL buffer to point to the IOC GW + return this->httpPost(url,data,strlen(data),result,result_length); + } + + // update our endpoint with the IOC + bool IOCHTTPTransport::updateEndpoint(int ioc_id,char *data,int data_length,char *result,int result_length) { + //this->logger()->log("updateEndpoint: %s",data); + data = this->packageData("PUT",data,ioc_id); + return this->httpPut(this->createIOCUpdateURL(ioc_id),data,strlen(data),result,result_length); + } + + // create the IOC load URL + char *IOCHTTPTransport::createIOCLoadURL() { return this->createIOCUpdateURL(0); } + + // create the IOC update URL + char *IOCHTTPTransport::createIOCUpdateURL(int ioc_id) { return this->createIOCUpdateURL(ioc_id,USE_GW_HTTP_REDIRECTOR); } + char *IOCHTTPTransport::createIOCUpdateURL(int ioc_id,bool useRedirector) { + if (useRedirector == false) { + // make HTTP calls directly + char ioc_id_str[IOC_IOC_ID_LEN+1]; + memset(ioc_id_str,0,IOC_IOC_ID_LEN+1); + if (ioc_id > 0) sprintf(ioc_id_str,"/%d",ioc_id); + memset(this->m_url_buffer,0,IOC_REST_URL_LEN+1); + sprintf(this->m_url_buffer,IOC_REST_URL,IOC_HOST_NAME,IOC_DATASOURCE_ID,ioc_id_str); + } + else { + // use the GW HTTP redirector + memset(this->m_url_buffer,0,IOC_REST_URL_LEN+1); + sprintf(this->m_url_buffer,GW_REDIRECT_URL,GW_IPADDRESS); + } + return this->m_url_buffer; + } + + // HTTP Get + bool IOCHTTPTransport::httpGet(char *url,char *result,int result_length) { + this->m_http->basicAuth(IOC_USERNAME,IOC_PASSWORD); + return HTTPTransport::httpGet(url,result,result_length); + } + + // HTTP Put + bool IOCHTTPTransport::httpPut(char *url,char *data,int data_length,char *result,int result_length) { + this->m_http->basicAuth(IOC_USERNAME,IOC_PASSWORD); + return HTTPTransport::httpPut(url,data,data_length,result,result_length); + } + + // HTTP Post + bool IOCHTTPTransport::httpPost(char *url,char *data,int data_length,char *result,int result_length) { + this->m_http->basicAuth(IOC_USERNAME,IOC_PASSWORD); + return HTTPTransport::httpPost(url,data,data_length,result,result_length); + } + + // HTTP Delete + bool IOCHTTPTransport::httpDelete(char *url,char *data,int data_length) { + this->m_http->basicAuth(IOC_USERNAME,IOC_PASSWORD); + return HTTPTransport::httpDelete(url,data,data_length); + } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IOCHTTPTransport.h Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,48 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _IOC_HTTP_TRANSPORT_H_ +#define _IOC_HTTP_TRANSPORT_H_ + +// Base Class +#include "HTTPTransport.h" + +class IOCHTTPTransport : public HTTPTransport { + private: + char m_url_buffer[IOC_REST_URL_LEN+1]; + + public: + IOCHTTPTransport(ErrorHandler *error_handler,void *endpoint); + virtual ~IOCHTTPTransport(); + + virtual bool httpGet(char *url,char *result,int result_length); + virtual bool httpPut(char *url,char *data,int data_length,char *result,int result_length); + virtual bool httpPost(char *url,char *data,int data_length,char *result,int result_length); + virtual bool httpDelete(char *url,char *data,int data_length); + + virtual bool loadEndpoint(char *data,int data_length,char *result,int result_length); + virtual bool updateEndpoint(int ioc_id,char *data,int data_length,char *result,int result_length); + + private: + char *createIOCLoadURL(); + char *packageData(char *verb,char *data,int ioc_id); + char *createIOCUpdateURL(int ioc_id); + char *createIOCUpdateURL(int ioc_id,bool useRedirector); + }; + +#endif // _IOC_HTTP_TRANSPORT_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MBEDEndpoint.cpp Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,494 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + #include "MQTTTransport.h" + #include "MBEDEndpoint.h" + + // MBED Light support + #include "MBEDLight.h" + + // Emulated Resource Factory + #include "EmulatedResourceFactory.h" + + // Emulated Actions we can act on + #include "EmulatedLightDimmerAction.h" + #include "EmulatedLightSwitchAction.h" + + // string support + #include <stdlib.h> + #include <string.h> + + // shutdown endpoint reference + extern void closedown(int code); + + // default constructor + MBEDEndpoint::MBEDEndpoint(ErrorHandler *error_handler,EthernetInterface *ethernet) { + bool success = true; + this->m_instance_id = 0; + this->m_preferences = NULL; + memset(this->m_lcd_status,0,TEMP_BUFFER_LEN+1); + memset(this->m_gw_address,0,PREFERENCE_VALUE_LEN+1); + for(int i=0;i<NUM_TRANSPORTS;++i) this->m_transports[i] = NULL; + this->m_error_handler = error_handler; + this->m_error_handler->setEndpoint((void *)this); + if (success) this->initPreferences(); + if (success) this->initEndpointName(); + if (success) this->logger()->turnLEDBlue(); +#ifdef MAC_ADDRESS + extern char fmt_mac[RESOURCE_VALUE_LEN+1]; + if (success)this->logger()->log("%s (MAC: %s)",ENDPOINT_VERSION_ANNOUNCE,fmt_mac); +#else + if (success)this->logger()->log(ENDPOINT_VERSION_ANNOUNCE); +#endif + if (success) this->initGWAddress(); + if (success) this->logger()->log("IOC GW IP: %s",GW_IPADDRESS); + if (PL_ENABLE && success) this->logger()->log("Philips Light ID: %d Philips Gateway IP: %s",PL_LIGHT_ID,PL_GW_ADDRESS); + if (success) success = this->initializeEthernet(ethernet); + if (success) this->logger()->turnLEDYellow(); + if (success)this->m_map = new MBEDToIOCResourceMap(error_handler); + if (success) success = this->initializeTransports(); + if (success) success = this->initializeLights(); + if (success) this->logger()->turnLEDOrange(); + this->logger()->lcdStatusOnly(true); + if (!success) closedown(2); + } + + // default destructor + MBEDEndpoint::~MBEDEndpoint() { + bool success = true; + if (success) this->logger()->turnLEDYellow(); + if (success) success = this->closeLights(); + if (success) success = this->closeTransports(); + if (success) success = this->closeEthernet(); + if (success) this->logger()->turnLEDBlue(); + if (this->m_map != NULL) delete this->m_map; + } + + // get the IOC <--> MBED resource map + MBEDToIOCResourceMap *MBEDEndpoint::getMap() { return this->m_map; } + + // initialize our preferences + void MBEDEndpoint::initPreferences() { if (this->m_preferences == NULL) this->m_preferences = new Preferences(this->logger()); if (this->m_preferences != NULL) this->m_preferences->fixCoordsForIOC(); } + + // get our preferences + Preferences *MBEDEndpoint::preferences() { return this->m_preferences; } + + // initialize the GW address from the configuration + void MBEDEndpoint::initGWAddress() { + memset(this->m_gw_address,0,PREFERENCE_VALUE_LEN+1); + this->preferences()->getPreference("gw_address",this->m_gw_address,PREFERENCE_VALUE_LEN,GW_IPADDRESS); + this->logger()->log("GW IP: %s",this->getGWAddress()); + } + + // get our GW address + char *MBEDEndpoint::getGWAddress() { return this->m_gw_address; } + + // get our LCD status + char *MBEDEndpoint::getLCDStatus() { + memset(this->m_lcd_status,0,TEMP_BUFFER_LEN+1); + + // look at Light#0 to determine the IOC linkage ID... + char *ioc = this->m_lights[0]->getResourceFactory()->getResourceValue(IOC_LINKAGE_RESOURCE); + + // color our LED depending on whether we have IOC linkage or not... + if (ioc == NULL || strcmp(ioc,IOC_LINKAGE_UNSET) == 0) this->logger()->turnLEDOrange(); + else this->logger()->turnLEDGreen(); + + sprintf(this->m_lcd_status,"Node: %s\nGW IP: %s\nIOC Link: %s",this->getEndpointName(),this->getGWAddress(),ioc); + return this->m_lcd_status; + } + + // initialize the Lights + bool MBEDEndpoint::initializeLights() { + int index = this->preferences()->getIntPreference("endpoint_id",LIGHT_NAME_INDEX); + this->logger()->log("Initializing Lights..."); + for(int i=0;i<NUM_LIGHTS;++i) { + this->m_lights[i] = new MBEDLight(this->logger(),this->m_transports,i+index,this); + this->m_lights[i]->setDimmerAction(new EmulatedLightDimmerAction(this->logger(),this->m_lights[i])); + this->m_lights[i]->setSwitchAction(new EmulatedLightSwitchAction(this->logger(),this->m_lights[i])); + } + return true; + } + + // does the input name match any of our light resources? + int MBEDEndpoint::indexOfLight(char *name) { + bool found = false; + int index = -1; + + for(int i=0;i<NUM_LIGHTS && !found;++i) { + if (strcmp(this->m_lights[i]->getName(),name) == 0) { + found = true; + index = i; + } + } + + return index; + } + + // get a specific resources + ResourceFactory *MBEDEndpoint::getResources(int index) { + if (index >= 0 && index < NUM_LIGHTS) return this->m_lights[index]->resources(); + return NULL; + } + + // initialize our ResourceFactory + ResourceFactory *MBEDEndpoint::initResourceFactory() { return new EmulatedResourceFactory(this->logger(),(void *)this); } + + // Initialize the Endpoint Name - will be the first Light resource name (and there must be one...) + void MBEDEndpoint::initEndpointName() { + this->m_instance_id = this->preferences()->getIntPreference("endpoint_id",LIGHT_NAME_INDEX); + memset(this->m_endpoint_name,0,LIGHT_NAME_LEN+1); + sprintf(this->m_endpoint_name,LIGHT_NAME,this->m_instance_id); + } + + // get our endpoint name + char *MBEDEndpoint::getEndpointName() { return this->m_endpoint_name; } + + // get our instance id + int MBEDEndpoint::getInstanceID() { return this->m_instance_id; } + + // initialize a specific transport + bool MBEDEndpoint::initializeTransport(int index,char *key,Transport *transport) { + bool success = false; + if (this->m_transports[index] == NULL) { + this->logger()->log("Initializing %s Transport...", key); + this->m_transports[index] = transport; + if (this->m_transports[index] != NULL) success = this->m_transports[index]->connect(); + if (success) this->logger()->log("Transport %s initialized and connected",key); + } + else { + this->logger()->log("%s already connected (OK)...", key); + success = true; + } + return success; + } + + // initialize our transports + bool MBEDEndpoint::initializeTransports() { + bool success = true; + + if (success == true) { + // MQTT Initialization + success = this->initializeTransport(MQTT_TRANSPORT,"MQTT",new MQTTTransport(this->m_error_handler,this,this->getMap())); + } + + if (success == true) { + // HTTP Initialization + success = this->initializeTransport(HTTP_TRANSPORT,"HTTP",new IOCHTTPTransport(this->m_error_handler,this)); + } + return success; + } + + // initialize our Ethernet + bool MBEDEndpoint::initializeEthernet(EthernetInterface *ethernet) { + bool success = false; + this->m_ethernet = ethernet; + if (this->m_ethernet != NULL) { + this->logger()->log("Initializing Ethernet..."); + + // connect up ethernet + this->m_ethernet->init(); + this->m_ethernet->connect(); + + // display our IP address + char *ipaddr = this->m_ethernet->getIPAddress(); + if (ipaddr != NULL && strlen(ipaddr) > 0) { + this->logger()->log("IPAddress: %s",this->m_ethernet->getIPAddress()); + success = true; + } + else { + this->logger()->log("Ethernet Not Connected..."); + success = false; + } + } + else { + this->logger()->log("No Ethernet instance found"); + success = false; + } + return success; + } + + // load up all endpoints into the IOC + bool MBEDEndpoint::loadEndpoints() { + bool success = true; + this->logger()->log("Loading All Endpoints to IOC..."); + for(int i=0;i<NUM_LIGHTS && success;++i) success = this->loadEndpoint(this->m_lights[i]); + return success; + } + + // load up our endpoint to the IOC + bool MBEDEndpoint::loadEndpoint(Light *light) { + bool success = false; + char result[IOC_RESULT_LEN+1]; + char payload[IOC_PAYLOAD_LEN+1]; + + // initialize + memset(result,0,IOC_RESULT_LEN+1); + memset(payload,0,IOC_PAYLOAD_LEN+1); + + // DEBUG + this->logger()->log("Building Payload for Light: %s...",light->getName()); + + // build the payload + char *data = this->buildIOCPayload(payload,IOC_PAYLOAD_LEN,light); + + // issue the request + if (data != NULL && strlen(data) > 0) { + // DEBUG + this->logger()->log("Sending Light: %s to the IOC...",light->getName()); + + // load + success = this->m_transports[LOAD_TRANSPORT]->loadEndpoint((char *)payload,strlen(payload),(char *)result,IOC_RESULT_LEN); + } + + // DEBUG + //if (success) this->logger()->log("Saving IOC ID for Light: %s...",light->getName()); + + // update the IOC ID if found + if (success) this->saveIOCID(light,result); + + // DEBUG + if (success) this->logger()->log("Light: %s IOC ID=%d sent successfully",light->getName(),light->getIOCID()); + + // DEBUG + if (!success) { + if (light != NULL) this->logger()->log("Light: %s send FAILED",light->getName()); + else this->logger()->log("Light: send FAILED (NULL LIGHT)"); + } + + // return our status + return success; + } + + // update all endpoints to the IOC + bool MBEDEndpoint::updateEndpoints() { + bool success = true; + for(int i=0;i<NUM_LIGHTS && success;++i) success = this->updateEndpoints(i); + return success; + } + + // update all endpoints to the IOC + bool MBEDEndpoint::updateEndpoints(int index) { + if (index >= 0 && index < NUM_LIGHTS) return this->updateEndpoint(this->m_lights[index]); + return false; + } + + // update our endpoint with the IOC + bool MBEDEndpoint::updateEndpoint(Light *light) { + bool success = false; + char result[IOC_RESULT_LEN+1]; + char payload[IOC_PAYLOAD_LEN+1]; + + // initialize + memset(result,0,IOC_RESULT_LEN+1); + memset(payload,0,IOC_PAYLOAD_LEN+1); + + // build the payload + char *data = this->buildIOCPayload(payload,IOC_PAYLOAD_LEN,light); + + // issue the request + if (data != NULL && strlen(data) > 0) { + // DEBUG + this->logger()->log("Updating Light: %s at the IOC...",light->getName()); + + // update + success = this->m_transports[LOAD_TRANSPORT]->updateEndpoint(light->getIOCID(),(char *)payload,strlen(payload),(char *)result,IOC_RESULT_LEN); + } + + // DEBUG + if (success) this->logger()->log("Update of Endpoint to IOC successful"); + else this->logger()->log("Update of Endpoint to IOC FAILED"); + + // return our status + return success; + } + + // build out the Payload + char *MBEDEndpoint::buildIOCPayload(char *data,int data_length,Light *light) { + char tmp[TEMP_BUFFER_LEN+1]; + + // construct the payload for Load/Updates + ResourceFactory *factory = light->getResourceFactory(); + + // start the buffer + strcat(data,"{"); + + // loop through the resources and build a JSON representation for the payload + for(int i=0;i<factory->numResources();++i) { + // get the ith resource + Resource *resource = factory->getResource(i); + if (resource != NULL) { + // add to the JSON payload + char *name = this->getMap()->endpointNameToIOCName(resource->getName()); + char *value = resource->getValue(); + + // make sure that we have a positive IOC resource match for the NSP resource + if (name != NULL && strlen(name) > 0) { + // Handle LOCATION a special way + if (strcmp(name,"LOCATION") != 0) { + // standard name,value for IOC + sprintf(tmp, "\"%s\":\"%s\",",name,value); + } + else { + // IOC expects "Point(X,Y)" for LOCATION + sprintf(tmp, "\"%s\":\"Point(%s)\",",name,value); + } + strcat(data,tmp); + + // Handle /dev/addldata + char *dev_addldata = this->getMap()->endpointNameToIOCName("/dev/addldata"); + if (dev_addldata != NULL && strcmp(name,dev_addldata) == 0 && light != NULL && light->getIOCID() > 0) { + char buf[IOC_IOC_ID_LEN+1]; memset(buf,0,IOC_IOC_ID_LEN+1); sprintf(buf,"%d",light->getIOCID()); + sprintf(tmp,"\"%s\":\"id:%s\",",name,buf); + strcat(data,tmp); + } + } + } + } + + // Special Case: STARTDATETIME + strcat(data,ENDPOINT_STARTTIME); + + // Special Case: ENDDATETIME + strcat(data,ENDPOINT_STOPTIME); + + // Special Case: NAME + sprintf(tmp,"\"NAME\":\"%s\",",light->getName()); + strcat(data,tmp); + + // Special Case: TIMEZONEOFFSET + strcat(data,ENDPOINT_TIMEZONE); + + // close + strcat(data,"}"); + + // DEBUG + //this->logger()->log("Loading Payload: %s",data); + + // return the payload + return data; + } + + // save the IOC ID + void MBEDEndpoint::saveIOCID(Light *light,char *json) { + if (json != NULL) { + //this->logger()->log("RESULT: %s",json); + + // look for "id": + char *check = "\"id\":"; + char *pos1 = strstr(json,check); + if (pos1 != NULL) { + char *pos2 = strstr(pos1,","); + if (pos1 != NULL && pos2 != NULL && pos2 > pos1) { + pos1 += strlen(check); + int length = pos2 - pos1; + char str_ioc_id[IOC_IOC_ID_LEN+1]; + memset(str_ioc_id,0,IOC_IOC_ID_LEN+1); + strncpy(str_ioc_id,pos1,length); + + // DEBUG + //this->logger()->log("IOC ID found: %s",str_ioc_id); + + // parse into int + int ioc_id = 0; + sscanf(str_ioc_id,"%d",&ioc_id); + + // save the IOC ID + if (ioc_id > 0) light->setIOCID(ioc_id); + } + else { + // cannot find the ID tag in the result JSON + this->logger()->log("Cannot find the IOC ID in the JSON result"); + this->logger()->log("JSON: %s",json); + } + } + else { + // cannot find the ID tag in the result JSON + this->logger()->log("Cannot find the IOC ID in the JSON result"); + this->logger()->log("JSON: %s",json); + } + } + } + + // close down the Lights + bool MBEDEndpoint::closeLights() { + bool success = true; + this->logger()->log("Closing down Lights..."); + for(int i=0;i<NUM_LIGHTS;++i) + if (this->m_lights[i] != NULL) delete this->m_lights[i]; + return success; + } + + // close a given transport + bool MBEDEndpoint::closeTransport(int index,char *key) { + this->logger()->log("Closing down %s Transport...", key); + if (this->m_transports[index] != NULL) delete this->m_transports[index]; + return true; + } + + // close down our transports + bool MBEDEndpoint::closeTransports() { + bool success = true; + + if (success) { + // close MQTT + success = this->closeTransport(MQTT_TRANSPORT,"MQTT"); + } + + if (success) { + // close HTTP + success = this->closeTransport(HTTP_TRANSPORT,"HTTP"); + } + + return success; + } + + // close down our Ethernet + bool MBEDEndpoint::closeEthernet() { + this->logger()->log("Closing down Ethernet..."); + if (this->m_ethernet != NULL) this->m_ethernet->disconnect(); + return true; + } + + // min function + int MBEDEndpoint::min(int value1,int value2) { + if (value1 < value2) return value1; + return value2; + } + + // get our error handler + ErrorHandler *MBEDEndpoint::logger() { return this->m_error_handler; } + + // main running loop + void MBEDEndpoint::run() { + this->logger()->log("Endpoint Main Loop"); + while(true) { + // sleep a bit + //this->logger()->log("Sleeping for a bit..."); + wait_ms(MAIN_LOOP_SLEEP); + + // check for events + //this->logger()->log("Processing Events..."); + for(int i=0;i<NUM_TRANSPORTS;++i) this->m_transports[i]->checkAndProcess(); + + // check for exit + //this->logger()->log("Checking for exit..."); + this->logger()->checkForExit(); + } +} + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MBEDEndpoint.h Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,102 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _MBED_ENDPOINT_H_ +#define _MBED_ENDPOINT_H_ + +// Ethernet Interface +#include "EthernetInterface.h" + +// ErrorHandler support +#include "ErrorHandler.h" + +// MBED to IOC Resource Map +#include "MBEDToIOCResourceMap.h" + +// Transport support +#include "MQTTTransport.h" +#include "IOCHTTPTransport.h" + +// Light Support +#include "Light.h" + +// ResourceFactory Support +#include "ResourceFactory.h" + +// Preferences Support +#include "Preferences.h" + +class MBEDEndpoint { + private: + EthernetInterface *m_ethernet; // ethernet interface + ErrorHandler *m_error_handler; // our error handler + Transport *m_transports[NUM_TRANSPORTS]; // our transport + Light *m_lights[NUM_LIGHTS]; // our lights (at least 1) + char m_endpoint_name[LIGHT_NAME_LEN+1]; // our endpoint name (light[0]) + MBEDToIOCResourceMap *m_map; // IOC <--> MBED resource mapping + Preferences *m_preferences; // preference support + char m_lcd_status[TEMP_BUFFER_LEN+1]; // LCD status buffer + char m_gw_address[PREFERENCE_VALUE_LEN+1]; // GW address buffer + int m_instance_id; // instance ID for this endpoint + + public: + MBEDEndpoint(ErrorHandler *error_handler,EthernetInterface *ethernet); + ~MBEDEndpoint(); + ResourceFactory *initResourceFactory(); + void run(); + + int indexOfLight(char *name); + ResourceFactory *getResources(int index); + + bool loadEndpoints(); + bool updateEndpoints(); + bool updateEndpoints(int index); + + char *getEndpointName(); + char *getGWAddress(); + Preferences *preferences(); + + char *getLCDStatus(); + + int getInstanceID(); + + MBEDToIOCResourceMap *getMap(); + + protected: + + private: + void initPreferences(); + void initGWAddress(); + void initEndpointName(); + bool initializeLights(); + bool initializeTransport(int index,char *key,Transport *transport); + bool initializeTransports(); + bool initializeEthernet(EthernetInterface *ethernet); + bool loadEndpoint(Light *light); + bool updateEndpoint(Light *light); + char *buildIOCPayload(char *data,int data_length,Light *light); + void saveIOCID(Light *light,char *data); + bool closeLights(); + bool closeTransport(int index,char *key); + bool closeTransports(); + bool closeEthernet(); + ErrorHandler *logger(); + int min(int value1, int value2); +}; + +#endif // _MBED_ENDPOINT_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTTransport.cpp Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,468 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + #include "mbed.h" + #include "rtos.h" + + #include "MQTTTransport.h" + + // Endpoint Support + #include "MBEDEndpoint.h" + + // EmulatedResourceFactory support + #include "EmulatedResourceFactory.h" + + // Network mutex + extern Mutex *network_mutex; + + // our transmitt instance + MQTTTransport *_mqtt_instance = NULL; + + // MQTT callback to handle received messages + void _mqtt_message_handler(char *topic,char *payload,unsigned int length) { + char buffer[MAX_MQTT_MESSAGE_LENGTH+1]; + char rcv_topic[MQTT_IOC_TOPIC_LEN+1]; + + memset(buffer,0,MAX_MQTT_MESSAGE_LENGTH+1); + memset(rcv_topic,0,MQTT_IOC_TOPIC_LEN+1); + memcpy(buffer,payload,length); + strcpy(rcv_topic,topic); + + if (_mqtt_instance != NULL) { + if (_mqtt_instance->isPongMessage(rcv_topic,buffer,length)) { + _mqtt_instance->processPongMessage(buffer,length); + } + else { + memset(buffer,0,MAX_MQTT_MESSAGE_LENGTH+1); + memset(rcv_topic,0,MQTT_IOC_TOPIC_LEN+1); + memcpy(buffer,payload,length); + strcpy(rcv_topic,topic); + _mqtt_instance->processMessage(_mqtt_instance->getEndpointNameFromTopic(rcv_topic),buffer,length); + } + } + } + + // our MQTT client endpoint + PubSubClient _mqtt(MQTT_HOSTNAME,MQTT_HOSTPORT,_mqtt_message_handler); + + // default constructor + MQTTTransport::MQTTTransport(ErrorHandler *error_handler,void *endpoint,MBEDToIOCResourceMap *map) : Transport(error_handler,endpoint) { + this->m_mqtt = NULL; + _mqtt_instance = this; + this->m_map = map; + this->m_ping_counter = 1; + this->m_ping_countdown = MQTT_PING_COUNTDOWN; + this->initTopic(); + } + + // default destructor + MQTTTransport::~MQTTTransport() { + this->disconnect(); + } + + // init our topic + void MQTTTransport::initTopic() { + MBEDEndpoint *endpoint = (MBEDEndpoint *)this->getEndpoint(); + char *endpoint_name = endpoint->getEndpointName(); + memset(this->m_topic,0,MQTT_IOC_TOPIC_LEN+1); + sprintf(this->m_topic,MQTT_IOC_TOPIC,endpoint_name); + } + + // get our topic + char *MQTTTransport::getTopic() { return this->m_topic; } + + // get the IOC <--> MBED resource map + MBEDToIOCResourceMap *MQTTTransport::getMap() { return this->m_map; } + + // pull the endpoint name from the MQTT topic + char *MQTTTransport::getEndpointNameFromTopic(char *topic) { + if (topic != NULL) { + memset(this->m_endpoint_name,0,LIGHT_NAME_LEN+1); + char trash[MQTT_IOC_TOPIC_LEN+1]; + char ep[MQTT_IOC_TOPIC_LEN+1]; + memset(trash,0,MQTT_IOC_TOPIC_LEN+1); + memset(ep,0,MQTT_IOC_TOPIC_LEN+1); + bool done = false; + int length = 0; if (topic != NULL) length = strlen(topic); + for(int i=length-1;i>=0 && !done;--i) if (topic[i] == '/') { topic[i] = ' ' ; done = true; } + sscanf(topic,"%s%s",trash,ep); + //this->logger()->log("MQTT: Topic:[%s] trash:[%s] ep:[%s]",topic,trash,ep); + if (strlen(ep) > 0) { + if (strcmp(ep,MQTT_IOC_ALL_ENDPOINT) != 0) { + // just insert the name and let the parser determine if its for us or not... + strncpy(this->m_endpoint_name,ep,strlen(ep)); + } + else { + // this is a broadcast message - so we need to process it + MBEDEndpoint *endpoint = (MBEDEndpoint *)this->getEndpoint(); + char *endpoint_name = endpoint->getEndpointName(); + strcpy(this->m_endpoint_name,endpoint_name); + } + } + //this->logger()->log("MQTT Topic (discovered): %s Original: %s",this->m_endpoint_name,topic); + return this->m_endpoint_name; + } + //this->logger()->log("MQTT Topic (discovered): NULL Original: %s",topic); + return NULL; + } + + // process a MQTT Message + void MQTTTransport::processMessage(char *message_name,char *payload, unsigned int payload_length) { + char message_type[MQTT_PAYLOAD_SEGMENT_LEN+1]; + char message_verb[MQTT_PAYLOAD_SEGMENT_LEN+1]; + char message_value[MQTT_PAYLOAD_SEGMENT_LEN+1]; + char message_opt[MQTT_PAYLOAD_SEGMENT_LEN+1]; + + // initialize + memset(message_type,0,MQTT_PAYLOAD_SEGMENT_LEN+1); + memset(message_verb,0,MQTT_PAYLOAD_SEGMENT_LEN+1); + memset(message_value,0,MQTT_PAYLOAD_SEGMENT_LEN+1); + memset(message_opt,0,MQTT_PAYLOAD_SEGMENT_LEN+1); + + // get our endpoint + MBEDEndpoint *endpoint = (MBEDEndpoint *)this->getEndpoint(); + char *endpoint_name = endpoint->getEndpointName(); + + // DEBUG + //this->logger()->log("Endpoint:[%s] Target: [%s]",endpoint_name,message_name); + + // only respond if its for our node + if (strcmp(endpoint_name,message_name) == 0) { + // format of the MQTT message: message_type:verb|Parameter_X:value|keyword:optional_data + char buffer[MAX_MQTT_MESSAGE_LENGTH+1]; + memset(buffer,0,MAX_MQTT_MESSAGE_LENGTH+1); + memcpy(buffer,payload,payload_length); + int count = 0; for(int i=0;i<payload_length;++i) if (payload[i] == ':') ++count; + for(int i=0;i<payload_length;++i) { + if (buffer[i] == ':') { + if (i < (payload_length-1)) buffer[i] = ' '; + else buffer[i] = '\0'; + } + } + if (count == 1) sscanf(buffer,"%s%s",message_type,message_verb); + if (count == 2) sscanf(buffer,"%s%s%s",message_type,message_verb,message_value); + if (count == 3) sscanf(buffer,"%s%s%s%s",message_type,message_verb,message_value,message_opt); + + // DEBUG + //this->logger()->log("Raw Payload: %s, length: %d",payload,payload_length); + //this->logger()->log("Buffer: %s, length: %d",buffer,strlen(buffer)); + //this->logger()->log("Parsed Payload: Type: [%s] Name: [%s] Verb: [%s] Value: [%s]",message_type,message_name,message_verb,message_value); + + // load endpoints + if (message_type != NULL && strcmp(message_type,IOC_ENDPOINT_VERB) == 0) { // Endpoint + if (message_verb != NULL && strcmp(message_verb,IOC_REQUEST_LOAD_ALL_VERB) == 0) { // load + if (message_value != NULL && strcmp(message_value,IOC_ENDPOINT_ALL_VERB) == 0) { // all + // load up our endpoints + endpoint->loadEndpoints(); + endpoint->updateEndpoints(); + } + else if (message_value != NULL && strcmp(message_value,this->m_endpoint_name) == 0) { + // load up our endpoints (us only) + endpoint->loadEndpoints(); + endpoint->updateEndpoints(); + } + } + + else if (message_verb != NULL && strcmp(message_verb,IOC_REQUEST_UPDATE_ALL_VERB) == 0) { // update + if (message_value != NULL && strcmp(message_value,IOC_ENDPOINT_ALL_VERB) == 0) { // all + // update our endpoints + endpoint->updateEndpoints(); + } + else { + // update just our endpoint + int index = -1; + if (message_name != NULL) { + index = endpoint->indexOfLight((char *)message_name); + if (index >= 0) { + if (message_verb != NULL && strcmp(message_verb,IOC_REQUEST_UPDATE_ALL_VERB) == 0) { + // update our endpoint + endpoint->updateEndpoints(index); + } + } + } + } + } + } + + // change a resource value + if (message_type != NULL && strcmp(message_type,IOC_CHANGE_VERB) == 0) { + if (message_name != NULL) { + // destined for our lights? + int index = endpoint->indexOfLight((char *)message_name); + if (index >= 0) { + if (message_verb != NULL) { + // map the parameter to one of ours + char *mapped_resource = this->mapIOCResourceToEndpointResource((char *)message_verb); + if (mapped_resource != NULL) { + if (message_value != NULL) { + EmulatedResourceFactory *factory = (EmulatedResourceFactory *)endpoint->getResources(index); + bool success = factory->setResourceValue(mapped_resource,message_value); + + // end the resource value back over MQTT + this->sendResult(message_name,message_verb,message_value,success); + } + } + } + } + } + } + + // get a resource value + if (message_type != NULL && strcmp(message_type,IOC_REQUEST_VALUE_VERB) == 0) { + if (message_name != NULL) { + // destined for our lights? + int index = endpoint->indexOfLight((char *)message_name); + if (index >= 0) { + if (message_verb != NULL) { + // map the parameter to one of ours + char *mapped_resource = this->mapIOCResourceToEndpointResource((char *)message_verb); + if (mapped_resource != NULL) { + EmulatedResourceFactory *factory = (EmulatedResourceFactory *)endpoint->getResources(index); + strcpy(message_value,factory->getResourceValue((char *)mapped_resource)); + bool success = false; if (message_value != NULL) success = true; + + // log resource get + if (success) this->logger()->log("Resource: %s (%s) Value: %s",message_verb,mapped_resource,message_value); + + // end the resource value back over MQTT + this->sendResult(message_name,message_verb,message_value,success); + } + } + } + } + } + } + else { + // message not bound for our node + //this->logger()->log("MQTT Message: %s not for us: %s... ignoring...",payload,endpoint_name); + ; + } + } + + // send result back to MQTT + void MQTTTransport::sendResult(char *endpoint_name,char *resource_name,char *value,bool success) { + if (this->m_connected == true) { + // send the response back to MQTT + this->logger()->log("Sending Response back to MQTT..."); + char message[MAX_MQTT_MESSAGE_LENGTH+1]; + memset(message,0,MAX_MQTT_MESSAGE_LENGTH+1); + char *str_success = IOC_RESPONSE_OK; if (!success) str_success = IOC_RESPONSE_FAILED; + sprintf(message,IOC_RESPONSE_TEMPLATE,IOC_RESPONSE_VERB,endpoint_name,resource_name,value,str_success); + if (network_mutex != NULL) network_mutex->lock(); + bool sent = this->m_mqtt->publish(this->getTopic(),message,strlen(message)); + if (network_mutex != NULL) network_mutex->unlock(); + if (sent) { + this->logger()->log("Result sent successfully"); + this->logger()->blinkTransportTxLED(); + } + else { + this->logger()->log("Result send FAILED"); + } + } + else { + // unable to send the response + this->logger()->log("Unable to send response back to MQTT. Not connected."); + } + } + + char *MQTTTransport::mapIOCResourceToEndpointResource(char *ioc_name) { return this->getMap()->iocNameToEndpointName(ioc_name); } + + char *MQTTTransport::makeID(char *id_template,char *buffer) { + MBEDEndpoint *endpoint = (MBEDEndpoint *)this->getEndpoint(); + int instance_id = rand()%100; + if (endpoint != NULL) instance_id = endpoint->getInstanceID(); + srand(time(0)); + srand(rand()); + sprintf(buffer,id_template,rand()%MQTT_MAXID_VALUE,instance_id); + return buffer; + } + + // is this message a PONG message? + bool MQTTTransport::isPongMessage(char *topic,char *payload,int payload_length) { + bool isPong = false; + char verb[MQTT_PING_VERB_LEN+1]; + char end[MQTT_PING_VERB_LEN+1]; + int counter = 0; + + // clean + memset(verb,0,MQTT_PING_VERB_LEN+1); + memset(end,0,MQTT_PING_VERB_LEN+1); + + // make sure this is for us... + char *topic_ep_name = this->getEndpointNameFromTopic(topic); + if (topic_ep_name != NULL && strcmp(topic_ep_name,this->m_endpoint_name) == 0) { + // parse the payload + for(int i=0;payload != NULL && i<payload_length;++i) if (payload[i] == ':') payload[i] = ' '; + sscanf(payload,"%s%d",verb,&counter); + + // check the contents to make sure its for us... + //this->logger()->log("isPongMessage: verb: %s counter %d ping_counter: %d",verb,counter,this->m_ping_counter); + if (strcmp(verb,"pong") == 0 && counter == this->m_ping_counter) { + // its a PONG message to our PING... + isPong = true; + } + } + + // return isPong status + return isPong; + } + + + // process this PONG message + void MQTTTransport::processPongMessage(char *payload,int payload_length) { + // DEBUG + //this->logger()->log("Received PONG: counter=%d",this->m_ping_counter); + + // simply increment the counter + ++this->m_ping_counter; + + // reset counter if maxed + if (this->m_ping_counter >= MQTT_MAX_COUNTER) this->m_ping_counter = 1; + } + + // send a PING message + bool MQTTTransport::sendPingMessage() { + bool sent = false; + char message[MAX_MQTT_MESSAGE_LENGTH+1]; + + // initialize... + memset(message,0,MAX_MQTT_MESSAGE_LENGTH+1); + + // build message + sprintf(message,"ping:%s:%d:",this->m_endpoint_name,this->m_ping_counter); + + // send the message over the ping/pong topic + //this->logger()->log("Sending PING: counter=%d",this->m_ping_counter); + if (network_mutex != NULL) network_mutex->lock(); + sent = this->m_mqtt->publish(MQTT_PING_SEND_TOPIC,message,strlen(message)); + if (network_mutex != NULL) network_mutex->unlock(); + if (sent) { + // send succeeded + //this->logger()->log("PING %d sent successfully",this->m_ping_counter); + this->logger()->blinkTransportTxLED(); + + // wait for 1 second + wait_ms(1000); + } + else { + // send failed! - reconnect + this->logger()->log("PING send %d FAILED... (re)connecting...",this->m_ping_counter); + + // attempt reconnect + this->logger()->log("PING send failed - re-connecting MQTT..."); + this->disconnect(); + sent = this->connect(); + if (sent) this->logger()->log("PING %d: MQTT reconnection successful...",this->m_ping_counter); + else this->logger()->log("PING %d: resend failed giving up...",this->m_ping_counter); + } + + // return our status + return sent; + } + + // connect up MQTT + bool MQTTTransport::connect() { + if (network_mutex != NULL) network_mutex->lock(); + char mqtt_id[MQTT_ENDPOINT_IDLEN+1]; + memset(mqtt_id,0,(MQTT_ENDPOINT_IDLEN+1)); + if (this->m_connected == false) { + this->logger()->log("MQTT Init: %s:%d...",MQTT_HOSTNAME,MQTT_HOSTPORT); + this->m_mqtt = &_mqtt; + if (this->m_mqtt != NULL) { + char *id = this->makeID(MQTT_ENDPOINT_ID,mqtt_id); + this->logger()->log("MQTT Connect: ID: %s...",id); + if (this->m_mqtt->connect(id)) { + this->logger()->log("MQTT Subscribe: Topic: %s...",this->getTopic()); + if (this->m_mqtt->subscribe(this->getTopic())) { + if (this->m_mqtt->subscribe(MQTT_IOC_ALL_TOPIC)) { + this->logger()->log("MQTT CONNECTED."); + this->m_connected = true; + } + else { + this->logger()->log("MQTT Subscribe: Topic: %s FAILED",MQTT_IOC_ALL_TOPIC); + this->logger()->turnLEDRed(); + this->m_connected = false; + } + } + else { + this->logger()->log("MQTT Subscribe: Topic: %s FAILED",this->getTopic()); + this->logger()->turnLEDRed(); + this->m_connected = false; + } + } + else { + this->logger()->log("MQTT Connect: ID: %s FAILED",id); + this->logger()->turnLEDRed(); + this->m_connected = false; + } + } + else { + this->logger()->log("MQTT Unable to allocate new instance"); + this->logger()->turnLEDRed(); + this->m_connected = false; + } + } + else { + this->logger()->log("MQTT already connected (OK)"); + } + if (network_mutex != NULL) network_mutex->unlock(); + return this->m_connected; + } + + // disconnect from MQTT + bool MQTTTransport::disconnect() { + if (this->m_mqtt != NULL) { + this->logger()->log("MQTT Unsubscribing from: %s...",this->getTopic()); + if (network_mutex != NULL) network_mutex->lock(); + this->m_mqtt->unsubscribe(this->getTopic()); + if (network_mutex != NULL) network_mutex->unlock(); + this->logger()->log("MQTT Disconnecting..."); + this->m_mqtt->disconnect(); + } + else { + this->logger()->log("MQTT already disconnected (OK)"); + } + this->m_connected = false; + return true; + } + + // check transport and process stuff + void MQTTTransport::checkAndProcess() { + // process any MQTT messages + if (this->m_mqtt != NULL && this->m_connected == true) { + if (network_mutex != NULL) network_mutex->lock(); + bool connected = this->m_mqtt->loop(); + if (network_mutex != NULL) network_mutex->unlock(); + if (connected) { + this->logger()->blinkTransportRxLED(); + } + else { + this->logger()->log("Attempting reconnection to MQTT in checkAndProcess..."); + this->disconnect(); + this->connect(); + } + } + + // send a PING if time for it + --this->m_ping_countdown; + if (this->m_ping_countdown <= 0) { + //this->logger()->log("MQTT: Sending PING..."); + this->m_ping_countdown = MQTT_PING_COUNTDOWN; + this->sendPingMessage(); + } + } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTTransport.h Wed Mar 26 19:48:35 2014 +0000 @@ -0,0 +1,67 @@ +/* Copyright C2013 Doug Anson, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files the "Software", to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___MQTTTRANSPORT_H_ +#define ___MQTTTRANSPORT_H_ + +// Base Class +#include "Transport.h" + +// MQTT Support +#include "PubSubClient.h" + +// MBED to IOC Resource Map +#include "MBEDToIOCResourceMap.h" + +class MQTTTransport : public Transport { + private: + PubSubClient *m_mqtt; + MBEDToIOCResourceMap *m_map; + char m_topic[MQTT_IOC_TOPIC_LEN+1]; + char m_endpoint_name[LIGHT_NAME_LEN+1]; + int m_ping_counter; + int m_ping_countdown; + + public: + MQTTTransport(ErrorHandler *error_handler,void *endpoint,MBEDToIOCResourceMap *map); + virtual ~MQTTTransport(); + + void processMessage(char *message_name,char *payload, unsigned int payload_length); + + virtual bool connect(); + virtual bool disconnect(); + + virtual void checkAndProcess(); + + char *getEndpointNameFromTopic(char *topic); + + bool isPongMessage(char *topic,char *payload,int payload_length); + void processPongMessage(char *payload,int payload_length); + + private: + char *makeID(char *id_template, char *buffer); + void initTopic(); + char *getTopic(); + char *mapIOCResourceToEndpointResource(char *ioc_name); + void sendResult(char *endpoint_name,char *parameter_name,char *value,bool success); + MBEDToIOCResourceMap *getMap(); + + bool sendPingMessage(); +}; + +#endif // ___MQTTTRANSPORT_H_ \ No newline at end of file