Peter Ferland / Mbed 2 deprecated Dragonfly_Cayenne_Sprint_IKS01A1

Dependencies:   Cayenne-MQTT-mbed-MTSAS X_NUCLEO_IKS01A1 mbed mtsas_lat3

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 
00003 #include "mtsas.h"
00004 
00005 #include "MQTTTimer.h"
00006 #include "CayenneMQTTClient.h"
00007 #include "MQTTNetwork.h"
00008 
00009 #include "x_nucleo_iks01a1.h"
00010 
00011 #include <string>
00012 #include <sstream>
00013 
00014 using std::string;
00015 typedef CayenneMQTT::MQTTClient<MQTTNetwork<Cellular>, MQTTTimer> MQTTClient;
00016 
00017 // Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
00018 string username = "da497640-dcce-11e6-b089-9f6bfa78ab33"; //"MQTT-Username";
00019 string password = "68e890972b6cc0fc47fcd152554db7e78ec9b29f"; //"MQTT-Password";
00020 string clientID = "dc9c10d0-ced9-11e7-98e1-8369df76aa6d"; //"MQTT-ClientID";
00021 
00022 DigitalOut Led1Out(D1);
00023 DigitalOut Led2Out(D0);
00024 DigitalOut Led3Out(D3);
00025 DigitalOut Led4Out(D6);
00026 DigitalOut Led5Out(D6);
00027 DigitalOut Led6Out(D8);
00028 DigitalOut Led7Out(D5);
00029 DigitalOut Led8Out(D4);
00030 DigitalOut Led9Out(D7);
00031 DigitalOut LedStatus(D2);
00032 
00033 // Debug serial port
00034 //static Serial debug(USBTX, USBRX);
00035 Serial pc(USBTX, USBRX);
00036 
00037 // MTSSerialFlowControl - serial link between processor and radio
00038 static MTSSerialFlowControl* io;
00039 
00040 // Cellular - radio object for cellular operations (SMS, TCP, etc)
00041 Cellular* radio;
00042 
00043 /* Instantiate the expansion board */
00044 static X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(I2C_SDA, I2C_SCL);
00045 
00046 /* Retrieve the composing elements of the expansion board */
00047 static GyroSensor *gyroscope = mems_expansion_board->GetGyroscope();
00048 static MotionSensor *accelerometer = mems_expansion_board->GetAccelerometer();
00049 static MagneticSensor *magnetometer = mems_expansion_board->magnetometer;
00050 static HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor;
00051 static PressureSensor *pressure_sensor = mems_expansion_board->pt_sensor;
00052 static TempSensor *temp_sensor1 = mems_expansion_board->ht_sensor;
00053 static TempSensor *temp_sensor2 = mems_expansion_board->pt_sensor;
00054 
00055 static const std::string apn = "b2b.tmobile.com"; //"iot.aer.net";
00056 
00057 CayenneMQTT::MessageData lastMessage;
00058 bool messageReady;
00059 bool gpsAvailable;
00060 
00061 /*
00062 * Initialize cellular radio.
00063 */
00064 bool init_mtsas()
00065 {
00066     io = new MTSSerialFlowControl(RADIO_TX, RADIO_RX, RADIO_RTS, RADIO_CTS);
00067     if (! io)
00068         return false;
00069 
00070     io->baud(115200);
00071     radio = CellularFactory::create(io);
00072     if (! radio)
00073         return false;
00074 
00075     logInfo("setting APN");
00076     if (radio->setApn(apn) != MTS_SUCCESS)
00077         logError("failed to set APN to \"%s\"", apn.c_str());
00078 
00079     Transport::setTransport(radio);
00080     while (! radio->connect()) {
00081         logError("failed to bring up PPP link");
00082         wait(2);
00083     }
00084     
00085     printf("Signal Strength: %d\n\r", radio->getSignalStrength()); 
00086     return true;
00087 }
00088 
00089 /**
00090 * Print the message info.
00091 * @param[in] message The message received from the Cayenne server.
00092 */
00093 void outputMessage(CayenneMQTT::MessageData& message)
00094 {
00095     switch (message.topic)  {
00096     case COMMAND_TOPIC:
00097         printf("topic=Command");
00098         break;
00099     case CONFIG_TOPIC:
00100         printf("topic=Config");
00101         break;
00102     default:
00103         printf("topic=%d", message.topic);
00104         break;
00105     }
00106     printf(" channel=%d", message.channel);
00107     if (message.clientID) {
00108         printf(" clientID=%s", message.clientID);
00109     }
00110     if (message.type) {
00111         printf(" type=%s", message.type);
00112     }
00113     for (size_t i = 0; i < message.valueCount; ++i) {
00114         if (message.getValue(i)) {
00115             printf(" value=%s", message.getValue(i));
00116         }
00117         if (message.getUnit(i)) {
00118             printf(" unit=%s", message.getUnit(i));
00119         }
00120     }
00121     if (message.id) {
00122         printf(" id=%s", message.id);
00123     }
00124     printf("\r\n");
00125 }
00126 
00127 /**
00128 *
00129 *
00130 */
00131 void setLEDs(bool newState)
00132 {
00133     // note: false = lit LED
00134     Led1Out = !newState;
00135     Led2Out = !newState;
00136     Led3Out = !newState;
00137     Led4Out = !newState;
00138     Led5Out = !newState;
00139     Led6Out = !newState;
00140     Led7Out = !newState;
00141     Led8Out = !newState;
00142     Led9Out = !newState;
00143 }
00144 
00145 /**
00146 * Handle messages received from the Cayenne server.
00147 * @param[in] message The message received from the Cayenne server.
00148 */
00149 void messageArrived(CayenneMQTT::MessageData& message)
00150 {
00151     int error = 0;
00152     //note: if you change this example to use mbed-os you will need a mutex
00153     lastMessage = message;
00154     messageReady = true;
00155 
00156 }
00157 
00158 /**
00159 * Connect to the Cayenne server.
00160 * @return Returns CAYENNE_SUCCESS if the connection succeeds, or an error code otherwise.
00161 */
00162 int connectClient(MQTTClient &mqttClient, MQTTNetwork<Cellular> &network)
00163 {
00164     int error = 0;
00165     // Connect to the server.
00166     printf("Connecting to %s:%d\r\n", CAYENNE_DOMAIN, CAYENNE_PORT);
00167     while ((error = network.connect(CAYENNE_DOMAIN, CAYENNE_PORT)) != 0) {
00168         printf("TCP connect failed, error: %d\r\n", error);
00169         wait(2);
00170     }
00171 
00172     if ((error = mqttClient.connect()) != MQTT::SUCCESS) {
00173         printf("MQTT connect failed, error: %d\r\n", error);
00174         return error;
00175     }
00176     printf("Connected\r\n");
00177 
00178     // Subscribe to required topics.
00179     if ((error = mqttClient.subscribe(COMMAND_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) {
00180         printf("Subscription to Command topic failed, error: %d\r\n", error);
00181     }
00182     if ((error = mqttClient.subscribe(CONFIG_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) {
00183         printf("Subscription to Config topic failed, error:%d\r\n", error);
00184     }
00185 
00186     // Send device info. Here we just send some example values for the system info. These should be changed to use actual system data, or removed if not needed.
00187     mqttClient.publishData(SYS_VERSION_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, CAYENNE_VERSION);
00188     mqttClient.publishData(SYS_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "mbedDevice");
00189     //mqttClient.publishData(SYS_CPU_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "CPU Model");
00190     //mqttClient.publishData(SYS_CPU_SPEED_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "1000000000");
00191 
00192     return CAYENNE_SUCCESS;
00193 }
00194 
00195 /**
00196 * Main loop where MQTT code is run.
00197 */
00198 void loop(MQTTClient &mqttClient, MQTTNetwork<Cellular> &network)
00199 {
00200     // Start the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval.
00201     MQTTTimer timer(1000);
00202     printf("Starting loop.\r\n");
00203     while (true) {
00204         // Yield to allow MQTT message processing.
00205         mqttClient.yield(10);
00206         if(messageReady){
00207             int error = 0;
00208             messageReady = false;
00209             // Add code to process the message. Here we just ouput the message data.
00210             outputMessage(lastMessage);
00211         
00212             if (lastMessage.topic == COMMAND_TOPIC) {
00213                 switch(lastMessage.channel) {
00214                 case 0:
00215                     // Set the onboard LED state
00216                     bool value = atoi(lastMessage.getValue());
00217                     setLEDs(value);
00218                     
00219                     // Publish the updated LED state
00220                     if ((error = mqttClient.publishData(DATA_TOPIC, lastMessage.channel, NULL, NULL, Led1Out.read()==0?1:0)) != CAYENNE_SUCCESS) {
00221                         printf("Publish LED state failure, error: %d\r\n", error);
00222                     }
00223                     break;
00224                 }
00225                 
00226                 // If this is a command message we publish a response. Here we are just sending a default 'OK' response.
00227                 // An error response should be sent if there are issues processing the message.
00228                 if ((error = mqttClient.publishResponse(lastMessage.id, NULL, lastMessage.clientID)) != CAYENNE_SUCCESS) {
00229                     printf("Response failure, error: %d\r\n", error);
00230                 }
00231             }
00232         }
00233 
00234         // Check that we are still connected, if not, reconnect.
00235         if (!network.connected() || !mqttClient.connected()) {
00236             network.disconnect();
00237             mqttClient.disconnect();
00238             LedStatus = true;
00239             printf("Reconnecting\r\n");
00240             while (connectClient(mqttClient, network) != CAYENNE_SUCCESS) {
00241                 wait(2);
00242                 printf("Reconnect failed, retrying\r\n");
00243             }
00244             LedStatus = false;
00245         }
00246 
00247         // Publish some example data every few seconds. This should be changed to send your actual data to Cayenne.
00248         if (timer.expired()) {
00249             printf("Sampling sensors\r\n");
00250             int error = 0;
00251             float temp_data;
00252             temp_sensor1->get_temperature(&temp_data);
00253             printf("Temperature was: %f \r\n", temp_data);
00254             if ((error = mqttClient.publishData(DATA_TOPIC, 1, TYPE_TEMPERATURE, UNIT_CELSIUS, temp_data)) != CAYENNE_SUCCESS) {
00255                 printf("Publish temperature failed, error: %d\r\n", error);
00256             }
00257             humidity_sensor->get_humidity(&temp_data);
00258             printf("Humidity was: %f \r\n", temp_data);
00259             if ((error = mqttClient.publishData(DATA_TOPIC, 2, TYPE_RELATIVE_HUMIDITY, UNIT_PERCENT, temp_data)) != CAYENNE_SUCCESS) {
00260                 printf("Publish luminosity failed, error: %d\r\n", error);
00261             }
00262             pressure_sensor->get_pressure(&temp_data);
00263             printf("Pressure was: %f \r\n", temp_data);
00264             if ((error = mqttClient.publishData(DATA_TOPIC, 3, TYPE_BAROMETRIC_PRESSURE, UNIT_HECTOPASCAL, temp_data)) != CAYENNE_SUCCESS) {
00265                 printf("Publish barometric pressure failed, error: %d\r\n", error);
00266             }
00267             printf("Led is: %s\r\n", Led1Out.read() > 0 ? "off" : "on");
00268              if ((error = mqttClient.publishData(DATA_TOPIC, 0, "digital_actuator", UNIT_DIGITAL, Led1Out.read()==0?1:0)) != CAYENNE_SUCCESS) {
00269                 printf("Publish LED status failed, error: %d\r\n", error);
00270             }
00271             
00272             if(gpsAvailable){
00273                 // disconnect socket so we can query GPS
00274                 mqttClient.disconnect();
00275                 network.disconnect();
00276                 
00277                 if( !radio->GPSenabled() ) {
00278                     printf("GPS: enabling");
00279                     radio->GPSenable();
00280                     while( !radio->GPSenabled() ) {
00281                         logInfo("...");
00282                         wait(5);
00283                     }
00284                 }
00285                 //collect gps data
00286                 Cellular::gpsData loc = radio->GPSgetPosition();
00287                 
00288                 LedStatus = true;
00289                 printf("Reconnecting\r\n");
00290                 while (connectClient(mqttClient, network) != CAYENNE_SUCCESS) {
00291                     wait(2);
00292                     printf("Reconnect failed, retrying\r\n");
00293                 }
00294                 
00295                 if(loc.success == false){
00296                     printf("GPSgetPosition failed\r\n");
00297                 } else {
00298                     switch(loc.fix){
00299                         case 0:
00300                         case 1:
00301                             printf("GPS - no Lock\r\n"); break;
00302                         case 2:
00303                             printf("GPS - 2d Lock\r\n"); break;
00304                         case 3:
00305                             printf("GPS - 3d Lock\r\n"); break;
00306                     }
00307                 }
00308                 if(loc.fix > 1){
00309                     std::string payload = loc.latitude + ",";
00310                     payload += loc.longitude;
00311                     payload += ",";
00312                     payload += loc.altitude;
00313                     error = mqttClient.publishData(DATA_TOPIC, 4, "gps", "m", payload.c_str());
00314                     if( error != CAYENNE_SUCCESS) {
00315                         printf("Publish GPS latitude status failed, error: %d\r\n", error);
00316                     }
00317 //                    error = mqttClient.publishData(DATA_TOPIC, 5, "location_long", NULL, loc.longitude.c_str());
00318 //                    if( error != CAYENNE_SUCCESS) {
00319 //                        printf("Publish GPS longitude status failed, error: %d\r\n", error);
00320 //                    }
00321                 }
00322             }
00323             // Restart the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval.
00324             timer.countdown_ms(5000);
00325         } else {
00326            // debug
00327            // printf("Timer: %d", timer.left_ms());
00328         }
00329     }
00330 }
00331 
00332 int main()
00333 {
00334     pc.baud(115200);
00335     setLEDs(false);
00336     LedStatus = true;
00337     mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL);
00338     // init radio, setup Cayenne connection
00339     if (!init_mtsas()) {
00340         while (true) {
00341             logError("failed to initialize cellular radio");
00342             wait(1);
00343         }
00344     }
00345         
00346     // Test with a ping
00347     if(radio->ping("www.google.com")){
00348         printf("Ping test succeeded!\r\n");
00349     } else {
00350         printf("Failed ping test!\r\n");
00351     }
00352     
00353     gpsAvailable = radio
00354     ->GPSenable();
00355     MQTTNetwork<Cellular> network(*radio);
00356     messageReady = false;
00357     MQTTClient mqttClient(network, username.c_str(), password.c_str(), clientID.c_str());
00358 
00359     // Set the default function that receives Cayenne messages.
00360     mqttClient.setDefaultMessageHandler(messageArrived);
00361 
00362     // Connect to Cayenne.
00363     if (connectClient(mqttClient, network) == CAYENNE_SUCCESS) {
00364         // Run main loop.
00365         LedStatus = false;
00366         loop(mqttClient, network);
00367     }
00368     else {
00369         printf("Connection failed, exiting\r\n");
00370     }
00371 
00372     if (mqttClient.connected())
00373         mqttClient.disconnect();
00374     if (network.connected())
00375         network.disconnect();
00376     
00377     return 0;
00378 }