Using MQTT on Dragonfly

Dependencies:   MQTT mbed mtsas

main.cpp

Committer:
miaotwilio
Date:
2017-09-14
Revision:
8:f8a346582627
Parent:
6:4a25f3b9caef

File content as of revision 8:f8a346582627:

#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);

DigitalOut ledNotEntered(D7);
DigitalOut ledCellular(D4);
DigitalOut ledGPS(D5);
DigitalOut ledOBD(D8);
DigitalOut ledSendingVehicleData(D6);
DigitalOut ledSendingVehicleDataFailed(D3);

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();

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;

    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.
    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");
    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;
        }
    }

    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");

        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);
    }
    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;
    }
}*/