mqtt specific components for the impact mbed endpoint library
Dependents: mbed_mqtt_endpoint_ublox_ethernet mbed_mqtt_endpoint_ublox_cellular mbed_mqtt_endpoint_nxp
MBEDEndpoint.cpp
- Committer:
- ansond
- Date:
- 2014-03-26
- Revision:
- 0:a3fc1c6ef150
- Child:
- 5:1ba6e68bf50e
File content as of revision 0:a3fc1c6ef150:
/* 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(); } }