Connecting a Multi-Tech Systems Dragonfly™ to Twilio's Sync for IoT Quickstart. Blink a dev board LED.

Dependencies:   MQTT MbedJSONValue mbed mtsas

Fork of DragonflyMQTT by miao zhicheng

Code to connect a Multi-Tech® MultiConnect® Dragonfly™ to Twilio's Sync for IoT: https://www.twilio.com/docs/api/devices

Uses MQTT over TLS and subscribes to a topic where you can control an LED. See also our Quickstart using this code, here: https://www.twilio.com/docs/quickstart/sync-iot/mqtt-multi-tech-multiconnect-dragonfly-sync-iot

Revision:
9:2d119fbe7482
Parent:
8:f8a346582627
Child:
10:e9abab84df23
diff -r f8a346582627 -r 2d119fbe7482 main.cpp
--- a/main.cpp	Thu Sep 14 08:14:18 2017 +0000
+++ b/main.cpp	Fri Sep 15 22:41:22 2017 +0000
@@ -1,229 +1,141 @@
-#include "MTSCellularManager.hpp"
-#include "TripDataReader.hpp"
-#include "TlsMQTTClient.hpp"
-#include "Certificates.h"
-#include "config.example.hpp"
 #include <mbed.h>
 #include <mtsas.h>
 #include <ssl.h>
-
-// This line controls the regulator's battery charger.
-// BC_NCE = 0 enables the battery charger
-// BC_NCE = 1 disables the battery charger
-DigitalOut bc_nce(PB_2);
+#include <MbedJSONValue.h>
+#include <string>
+#include "MTSCellularManager.hpp"
+#include "TlsMQTTClient.hpp"
+#include "certificates.hpp"
 
-DigitalOut ledNotEntered(D7);
-DigitalOut ledCellular(D4);
-DigitalOut ledGPS(D5);
-DigitalOut ledOBD(D8);
-DigitalOut ledSendingVehicleData(D6);
-DigitalOut ledSendingVehicleDataFailed(D3);
+/* 
+ *  Sync Settings
+ *  
+ *  Enter a Sync Key & Password, your document unique name, 
+ *  and the device name
+ */
+char* sync_key                          = "KYXXXXXXXXXXXXXXXXXXXX";
+char* sync_password                     = "SECRET_HERE";
+char* sync_document                     = "sync/docs/BoardLED";
+char* sync_device_name                  = "MST Dragonfly";
+
+/* Sync server and MQTT setup; you probably don't have to change these. */
+const char* mqtt_server                 = "mqtt-sync.us1.twilio.com";
+const uint16_t mqtt_port                = 8883;
+const uint16_t maxMQTTpackageSize       = 512;
+
+TlsMQTTClient client = TlsMQTTClient();
+DigitalOut led(D7);
+DigitalOut bc_nce(PB_2);
+const uint8_t MQTT_HEARTBEAT = 15;
 
-static bool enableODB = false;
-static Ticker vehicleDataSamplingTicker;
-static const int VEHICLE_DATA_SAMPLING_PERIOD_MS = 50;
-static const int VEHICLE_DATA_REPORTING_PERIOD_MS = 3000;
-MTSSerial obd(D1, D0);
-static TripDataReader* pTripDataReader = NULL;
-static void vehicleDataSamplingCallback();
+/* 
+ * Our Twilio Connected Devices message handling callback.  This is passed as a 
+ * callback function when we subscribe to the document, and any messages will 
+ * appear here.
+ */
+void callback(MQTT::MessageData& data) 
+{
+    if (data.message.payloadlen > maxMQTTpackageSize) {
+        return;
+    }
+    char buf[maxMQTTpackageSize + 1];
+    strncpy(buf, (char*)data.message.payload, data.message.payloadlen);
+    buf[data.message.payloadlen] = '\0';
+    
+    logDebug("Received new update %s", buf);
+    /* JSON Parse 'led' */
+    MbedJSONValue parser;
+    parse(parser, buf);
+    
+    /* The parser will segfault and reset the board if "led" isn't contained. */
+    if (parser.hasMember("led")) {
+        std::string led_str;
+        led_str = parser["led"][0].get<std::string>();
+        
+        if (led_str.compare("ON") == 0) {
+            logDebug("Turning LED ON");
+            led = 0; // Active LOW
+        } else {
+            logDebug("Turning LED OFF");
+            led = 1; // Active LOW
+        }
+    }
+}
 
-static void sendVehicleData(const MTSCellularManager::GPSStatus& gpsStatus,
-                            const TripDataReader::TripData& tripData);
-
-static bool exitCmd = false;
 
-int main() {
-    // Disable the battery charger unless a battery is attached.
-    bc_nce = 1;
+/* 
+ * This function connects to Sync via MQTT. We connect using the key, password, 
+ * and device name defined as constants above, and checks the server
+ * certificate.
+ * 
+ * If everything works, we subscribe to the document topic and return.
+ */
+void connect_mqtt()
+{
+    MQTTPacket_connectData conn_data = MQTTPacket_connectData_initializer;
+    conn_data.clientID.cstring = sync_device_name;
+    conn_data.username.cstring = sync_key;
+    conn_data.password.cstring = sync_password;
+    int rc = client.connect(
+        mqtt_server, 
+        mqtt_port, 
+        MQTT_GATEWAY_PROD_ROOT_CA_PEM, 
+        conn_data
+    );
+    logInfo("MQTT connect result: %d", rc);
+    
+    rc = client.subscribe(
+        "sync/docs/BoardLED", 
+        MQTT::QOS1, 
+        callback
+    );
+    logInfo("MQTT subscription result: %d", rc);
+}
 
-    ledNotEntered = 1;
-    ledCellular = 1;
-    ledGPS = 1;
-    ledOBD = 1;
-    ledSendingVehicleData = 1;
-    ledSendingVehicleDataFailed = 1;
 
-    // Change the baud rate of the debug port from the default 9600 to 115200.
+/* 
+ * Very basic device loop - all we do is reconnect when disconnected
+ */
+void loop()
+{
+    if (client.isConnected()) {
+        client.yield(MQTT_HEARTBEAT/2.0);
+        wait(MQTT_HEARTBEAT);
+    } else {
+        wait(MQTT_HEARTBEAT*10);
+        connect_mqtt();
+    }
+}
+
+
+/* 
+ * In main, we configure our LEDs, connect to Twilio Programmable Wireless,
+ * and initialize CyaSSL. We then connect our MQTT client for the first time.
+ *
+ * When done, we pass control to the MQTT loop, which handles yield()s.
+ */
+int main() 
+{
+    led = 1;  // Active LOW
+    bc_nce = 1;
     Serial debug(USBTX, USBRX);
     debug.baud(115200);
-    
-    //Sets the log level to INFO, higher log levels produce more log output.
-    //Possible levels: NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE
     mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL);
 
-    logInfo("Program started");
-
-    logInfo("Vehicle ID: %s, TYPE: %s", VEHICLE_ID, VEHICLE_TYPE);
-    if (0 == strcmp(VEHICLE_TYPE, "CAR")) {
-        logInfo("Enable OBD for it is a car");
-        enableODB = true;
-    }
-
-    logInfo("Initializing cellular");
+    // Be sure your SIM is registered in the Twilio console.
+    // https://www.twilio.com/console/wireless/sims/
+    logInfo("Initializing Twilio Programmable Wireless");
     MTSCellularManager cellularManager("wireless.twilio.com");   
     if (! cellularManager.init()) {
         while (true) {
-            logError("failed to initialize cellular radio");
-            wait(1);
-        }
-    }
-    ledCellular = 0;
-
-    {
-        logInfo("Initializing GPS");
-        cellularManager.enableGps();
-        logInfo("GPS Initialized");
-    }
-
-    TripDataReader tripDataReader(obd, ledOBD);
-    pTripDataReader = &tripDataReader;
-    while (enableODB) {
-        logInfo("Initializing OBD");
-        int r = tripDataReader.init();
-        logInfo("OBD Initialization result: %d", r);
-        if (0 == r) {
-            logInfo("Initializing OBD sampling ticker");
-            vehicleDataSamplingTicker.attach(
-                        &vehicleDataSamplingCallback,
-                        VEHICLE_DATA_SAMPLING_PERIOD_MS / 1000.);
-            logInfo("OBD sampling ticker initialized");
-            break;
-        }
-        wait_ms(100);
-    }
-
-    logInfo("Initializing CyaSSL");
-    CyaSSL_Init();
-
-    while (!exitCmd) {
-        wait_ms(VEHICLE_DATA_REPORTING_PERIOD_MS);
-        TripDataReader::TripData tripData;
-        if (enableODB) {
-            tripData = tripDataReader.getTripData();
-            tripDataReader.resetAverageWindow();
-        }
-        MTSCellularManager::GPSStatus gpsStatus = cellularManager.gpsPollStatus();
-        if (gpsStatus.success) {
-            ledGPS = 0;
-            sendVehicleData(gpsStatus, tripData);
-        } else {
-            ledGPS = 1;
+            logError("failed to initialize cellular radio"); wait(10);  
         }
     }
-
-    logInfo("Cleaning up CyaSSL");
-    CyaSSL_Cleanup();
-
-    logInfo("Shutting down cellular");
-    cellularManager.uninit();
-
-    logInfo("Program finished");
-    wait(1E12);
-    return 0;
-}
-
-static void vehicleDataSamplingCallback() {
-    pTripDataReader->sample();
-}
-
-static void sendVehicleData(const MTSCellularManager::GPSStatus& gpsStatus,
-                            const TripDataReader::TripData& tripData) {
-    ledSendingVehicleDataFailed = 1;
-    ledSendingVehicleData = 0;
-
-    logInfo("Connecting MQTT Client");
-    TlsMQTTClient client = TlsMQTTClient();
-    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
-    data.clientID.cstring = VEHICLE_ID;
-    data.username.cstring = VEHICLE_KEY;
-    data.password.cstring = VEHICLE_SECRET;
-    int result = client.connect(MQTT_GATEWAY_HOST, MQTT_GATEWAY_PORT, MQTT_GATEWAY_PROD_ROOT_CA_PEM, data);
-    if (MQTT::SUCCESS == result) {
-        MQTT::Message message;
-        char buf[512];
-
-        logInfo("MQTT connected");
+    CyaSSL_Init();
+    connect_mqtt();
 
-        if (enableODB) {
-            sprintf(buf, "{"
-                "\"runtime\": %d,"
-                "\"miles\": %d,"
-                "\"speed\": %f,"
-                "\"minT\": %f,"
-                "\"maxT\": %f,"
-                "\"avgT\": %f,"
-                "\"fuel\": %d,"
-                "\"brake\": %d,"
-                "\"lat\": %lf,"
-                "\"lon\": %lf"
-                "}",
-                tripData.runtime,
-                tripData.distance,
-                tripData.averageSpeed,
-                tripData.minimumThrottle,
-                tripData.maximumThrottle,
-                tripData.averageThrottle,
-                tripData.fuel,
-                tripData.hardBrakeCount,
-                gpsStatus.latitudeVal,
-                gpsStatus.longitudeVal);
-        } else {
-            sprintf(buf, "{"
-                "\"speed\": %f,"
-                "\"lat\": %lf,"
-                "\"lon\": %lf"
-                "}",
-                gpsStatus.speedVal,
-                gpsStatus.latitudeVal,
-                gpsStatus.longitudeVal);
-        }
-
-        message.qos = MQTT::QOS1;
-        message.payload = (void*)buf;
-        message.payloadlen = strlen(buf) + 1;
-        logInfo("MQTT message publishing buf: %s", buf);
-        int rc = client.publish("sync/lists/vehicle-" VEHICLE_ID "-data", message);
-        logInfo("MQTT message publish result: %d", rc);
-
-        logInfo("MQTT disconnecting");
-        client.disconnect();
-    } else {
-        ledSendingVehicleDataFailed = 0;
-        logError("MQTT connection failed %d", result);
+    /* We're done; pass off control to the loop */
+    while (1) {
+       loop();
     }
-    ledSendingVehicleData = 1;
-}
-
-/*
-static void subscribeToTest2() {
-    rc = client.subscribe("sync/lists/test2", MQTT::QOS1, test2Handler);
-    logInfo("MQTT subscription result: %d", rc);
-}
-
-static void test2Handler(MQTT::MessageData& data) {
-    static const size_t MAX_DISPLAY_MESSAGE_SIZE = 30;
-    char buf[MAX_DISPLAY_MESSAGE_SIZE + 1];
-    if (data.message.payloadlen <= MAX_DISPLAY_MESSAGE_SIZE) {
-        strncpy(buf, (char*)data.message.payload, data.message.payloadlen);
-        buf[data.message.payloadlen] = '\0';
-    } else {
-        strncpy(buf, (char*)data.message.payload, MAX_DISPLAY_MESSAGE_SIZE - 3);
-        buf[MAX_DISPLAY_MESSAGE_SIZE-3] = '.';
-        buf[MAX_DISPLAY_MESSAGE_SIZE-2] = '.';
-        buf[MAX_DISPLAY_MESSAGE_SIZE-1] = '.';
-        buf[MAX_DISPLAY_MESSAGE_SIZE] = '\0';
-    }
-    logDebug("topic %s payload received len %d data %s", data.topicName.lenstring.data, data.message.payloadlen, buf);
-
-    // sync client can send binary data using payload format:
-    // {
-    //    "payload": "ZXhpdA==", # base64 encoded "exit"
-    //    "_iot_meta": {
-    //        "payload_encoding": "base64",
-    //        "payload_type": "application/octet-stream",
-    //    }
-    // }
-    if (0 == strncmp((char*)data.message.payload, "exit", data.message.payloadlen)) {
-        exitCmd = true;
-    }
-}*/
+}
\ No newline at end of file