A simple client that allows the user to send Json data to Axeda's IoT cloud using an SSL socket (with certificate verification).

Dependencies:   mbed

Only allows use of URLs, not IP addresses. Most CyaSSL errors are caused by incorrect certificates or failed certificate verification (188, 151, 155).

main.cpp

Committer:
Vanger
Date:
2015-03-25
Revision:
3:677bdaf965ac
Parent:
2:cdfc629d20fa

File content as of revision 3:677bdaf965ac:

#include "mbed.h"
#include "mtsas.h"
#include "certs.h"

//Simple function that converts the HTTP result to a string
//Ex: Result is 0, the string result will be "HTTP_OK"
char * httpResToStr(HTTPResult res);

/**Write the model for your device here. 
 * Can be located on the axeda developer toolbox device info page.
 */
const string Modelstr = "";

/**Write the serial for your device here
 * Can be located on the axeda developer toolbox device info page.
 */
const string Serialstr = "";

//Size of the http receive and send buffers
const int BUFFER_SIZE = 2000;

//Destination url to send data to the axeda cloud from the device
const string base_url = "https://nucleus-connect.axeda.com/ammp/data/1/";

int main(){
    
    //Sets the log level to INFO, higher log levels produce more log output.
    //Possible levels: NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE
    MTSLog::setLogLevel(MTSLog::INFO_LEVEL);
    
    /**Root Certificate(s) of the remote server you want to connect to are listed in "certs.h"
    * Make sure the certificates are in PEM format, contain \r\n to end each line,
    * and if using multiple root CA certificates, just make multiple calls to the addRootCACertificate
    * function for each root certificate you wish to add, or add them all as one concatenated string.
    *
    * Example certificate formatted correctly (length not to scale):
    * -----BEGIN CERTIFICATE-----\r\n
    * aosdfijaaosdfijaaosdfijaaosdfijaaosdfijaaosdfijaaosdfijaaosdfija\r\n
    * afjklewijafliefhiszelifhlsfhilasihflihsalifhalhifliahlfihaslihfl\r\n
    * fawefaewf==\r\n
    * -----END CERTIFICATE-----\r\n
    */
    
    //Modify to match your apn if you are using an HSPA radio with a SIM card
    const char APN[] = "";
    
    /** STMicro Nucelo F401RE
    * The supported jumper configurations of the MTSAS do not line up with
    * the pin mapping of the Nucleo F401RE. Therefore, the MTSAS serial TX
    * pin (JP8 Pin 2) must be manually jumped to Serial1 RX (Shield pin D2)
    * and the MTSAS serial RX pin (JP9 Pin 2) pin must be manually jumped to
    * Serial1 TX (Shield pin D8).
    * Uncomment the following line to use the STMicro Nuceleo F401RE
    */
    MTSSerialFlowControl* io = new MTSSerialFlowControl(D8, D2, D3, D6);
    
    /** Freescale KL46Z
    * To configure the serial pins for the Freescale KL46Z board, use MTSAS jumper
    * configuration B. Uncomment the following line to use the Freescale KL46Z board
    */
    //MTSSerialFlowControl* io = new MTSSerialFlowControl(D2, D9, D3, D6);
    
    /** Freescale K64F
    * To configure the serial pins for the Freescale K64F board, use MTSAS jumper
    * configuration A. Uncomment the following line to use the Freescale K64F board
    */
    //MTSSerialFlowControl* io = new MTSSerialFlowControl(D1, D0, D3, D6);
    
    //Sets the baud rate for communicating with the radio
    io->baud(115200); 
    
    //Initialize radio configurations
    Cellular* radio = CellularFactory::create(io);
    if( ! radio) {
        logFatal("Radio initialization failed");
        return 1;
    }
    
    Transport::setTransport(radio);
    
    //Set radio APN
    for (int i = 0; i < 10; i++) {
        if (i >= 10) {
            logError("Failed to set APN to %s", APN);
        }
        if (radio->setApn(APN) == MTS_SUCCESS) {
            logInfo("Successfully set APN to %s", APN);
            break;
        } else {
            wait(1);
        }
    }
    
    //Establish PPP link
    for (int i = 0; i < 10; i++) {
        if (i >= 10) {
            logError("Failed to establish PPP link");
        }
        if (radio->connect() == true) {
            logInfo("Successfully established PPP link");
            break;
        } else {
            wait(1);
        }
    }
    
    //Create receive interface and buffer
    char rbuf[BUFFER_SIZE];
    HTTPText* receive = new HTTPText(rbuf, sizeof(rbuf));
    
    //Json output object, data must be in Json format, example data is input already:
    //HTTPJson type merely sets the HTTP header to JSON type, nothing else is different from the HTTPText type
    char sbuf[BUFFER_SIZE] = "{\"data\":[{\"dataItems\":{\"mental_trauma\":1,\"physical_trauma\":2,\"emotional_trauma\":3}}]}\0";
    HTTPJson* send = new HTTPJson(sbuf);
    
    //Create HTTP Client Instance
    HTTPClient* http = new HTTPClient();
    if( !http || !receive || !send) {
        logFatal("Failed to instantiate client, send, or receive");
        return 1;
    }
    
    /**Certificates can all be loaded concurrently as one string with the certificates
     * concatenated after one another if so desired. Otherwise, the example here shows
     * loading the certificates one by one.
     */
    logTrace("Loading certificate(s)");
    HTTPResult res = http->addRootCACertificate(CERTIFICATE1);
    if(res != HTTP_OK) {
        logError("Failed to load CERTIFICATE1");
    }
    
    res = http->addRootCACertificate(CERTIFICATE2);
    if(res != HTTP_OK) {
        logError("Failed to load CERTIFICATE2");
    }
    
    res = http->addRootCACertificate(CERTIFICATE3);
    if(res != HTTP_OK) {
        logError("Failed to load CERTIFICATE3");
    }
    
    /**Set whether or not to verify the remote server's certificate
     * VERIFY_NONE Sets the connection to be made using SSL protocol, 
     * but without remot peer verification using the loaded certificates.
     * VERIFY_PEER Sets the connection to be made using SSL protocol,
     * and to verify the peer using the loaded root certificates.
     */
    http->setPeerVerification(VERIFY_PEER);
    
    //URL for axeda.com device connection (includes path)
    //Format: https://nucleus-connect.axeda.com/ammp/data/1/<MODEL_STRING_HERE>!<SERIAL_NUMBER_HERE>
    string url = base_url + Modelstr + '!' + Serialstr;
        
    logTrace("HTTPS POST Request with Certificate");
    res = http->post(url.c_str(), *send, receive);
        if(res == HTTP_OK) {
            logInfo("HTTPS POST succeeded");
        } else {
            logInfo("HTTPS POST failed [%s]", httpResToStr(res));
        }
    
    return 0;
}

//Simple error code to string function
char * httpResToStr(HTTPResult res) {
    switch(res) {
        case HTTP_PROCESSING:
            return "HTTP_PROCESSING";
        case HTTP_PARSE:
            return "HTTP_PARSE";
        case HTTP_DNS:
            return "HTTP_DNS";
        case HTTP_PRTCL:
            return "HTTP_PRTCL";
        case HTTP_NOTFOUND:
            return "HTTP_NOTFOUND";
        case HTTP_REFUSED:
            return "HTTP_REFUSED";
        case HTTP_ERROR:
            return "HTTP_ERROR";
        case HTTP_TIMEOUT:
            return "HTTP_TIMEOUT";
        case HTTP_CONN:
            return "HTTP_CONN";
        case HTTP_CLOSED:
            return "HTTP_CLOSED";
        case HTTP_REDIRECT:
            return "HTTP_REDIRECT";
        case HTTP_OK:
            return "HTTP_OK";
        default:
            return "HTTP Result unknown";
    }
}