SmartREST client reference implementation for the u-blox C027 mbed compatible device.

Dependencies:   C027 C027_Support mbed mbed-rtos MbedSmartRest LM75B MMA7660 C12832

Fork of MbedSmartRestTest by Vincent Wochnik

program.cpp

Committer:
vwochnik
Date:
2014-07-03
Revision:
35:ee1c6289e617
Parent:
34:8a0556f39161

File content as of revision 35:ee1c6289e617:

#include "common.h"
#include "io.h"
#include "StaticData.h"
#include "ComposedRecord.h"
#include "CharValue.h"
#include "IntegerValue.h"
#include "FloatValue.h"
#include "Aggregator.h"

/************* CONFIGURATION *************/

/* Credentials for device bootstrap authentification.
 * Contact cumulocity to get credentials. */
#define DEVICEBOOTSTRAP_USERNAME ""
#define DEVICEBOOTSTRAP_PASSWORD ""

/* Uncomment and fill in credentials to turn off device bootstrapping. */
//#define CREDENTIALS_USERNAME ""
//#define CREDENTIALS_PASSWORD ""

/* Template device identifier */
#define TEMPLATE_DEVICE_IDENTIFIER "com_u-blox_C027_REV-A_0.10_Test1233123"

/*****************************************/

bool deviceBootstrap();
long existing();
long create();
bool identify(long deviceId);
bool update(long deviceId);
void loop(long deviceId);
void signalMeasurement(long deviceId, Aggregator& aggr);
void temperatureMeasurement(long deviceId, Aggregator& aggr);
void analogMeasurement(long deviceId, Aggregator& aggr);
void motionMeasurement(long deviceId, Aggregator& aggr);

credentials_t credentials = {};
char cDeviceIdentifier[48];

StaticData srtpl(
// get device by identity
// Usage: 100,<SERIAL/NR>
"10,100,GET,/identity/externalIds/c8y_Serial/%%,,application/vnd.com.nsn.cumulocity.externalId+json,%%,STRING,\r\n"
// get device id from identity
// Response: 200,<DEVICE/ID>
"11,200,\"$.managedObject\",,\"$.id\"\r\n"
// Create device
// Usage: 101,<SERIAL/NR>
"10,101,POST,/inventory/managedObjects,application/vnd.com.nsn.cumulocity.managedObject+json,application/vnd.com.nsn.cumulocity.managedObject+json,%%,STRING,\"{\"\"name\"\":\"\"Mbed Test Device\"\",\"\"type\"\":\"\"com_ublox_C027_REV-A\"\",\"\"c8y_Hardware\"\":{\"\"revision\"\":\"\"1\"\",\"\"model\"\":\"\"Ublox C027\"\",\"\"serialNumber\"\":\"\"%%\"\"},\"\"c8y_SupportedMeasurements\"\":[\"\"c8y_SignalStrength\"\",\"\"c8y_TemperatureMeasurement\"\",\"\"c8y_AnalogMeasurement\"\",\"\"c8y_MotionMeasurement\"\"],\"\"c8y_RequiredAvailability\"\":{ \"\"responseInterval\"\":15},\"\"c8y_IsDevice\"\":{}}\"\r\n"
// Get device id
// Response: 201,<DEVICE/ID>
"11,201,,\"$.c8y_IsDevice\",\"$.id\"\r\n"
// Insert global ID
// Usage: 102,<DEVICE/ID>,<SERIAL/NR>
"10,102,POST,/identity/globalIds/%%/externalIds,application/vnd.com.nsn.cumulocity.externalId+json,application/vnd.com.nsn.cumulocity.externalId+json,%%,UNSIGNED STRING,\"{\"\"type\"\":\"\"c8y_Serial\"\",\"\"externalId\"\":\"\"%%\"\"}\"\r\n"
// Update IMEI, CellId and iccid
// Usage: 103,<DEVICE/ID>,<IMEI>,<CELL/ID>,<ICCID>
"10,103,PUT,/inventory/managedObjects/%%,application/vnd.com.nsn.cumulocity.managedObject+json,application/vnd.com.nsn.cumulocity.managedObject+json,%%,UNSIGNED STRING STRING STRING,\"{\"\"c8y_Mobile\"\":{\"\"imei\"\":\"\"%%\"\",\"\"cellId\"\":\"\"%%\"\",\"\"iccid\"\":\"\"%%\"\"}}\"\r\n"
// Insert measurement
// USAGE: 104,<DEVICE/ID>,<RSSI>,<BER>
"10,104,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER UNSIGNED,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_SignalStrength\"\",\"\"c8y_SignalStrength\"\":{\"\"rssi\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"dBm\"\"},\"\"ber\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"%\"\"}}}\"\r\n"
// Insert measurement
// USAGE: 105,<DEVICE/ID>,<TEMPERATURE>
"10,105,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_TemperatureMeasurement\"\",\"\"c8y_TemperatureMeasurement\"\":{\"\"T\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"C\"\"}}}\"\r\n"
// Insert measurement
// USAGE: 105,<DEVICE/ID>,<ANALOG0>,<ANALOG1>
"10,106,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED UNSIGNED UNSIGNED,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_AnalogMeasurement\"\",\"\"c8y_AnalogMeasurement\"\":{\"\"analog0\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"%\"\"},\"\"analog1\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"%\"\"}}}\"\r\n"
// Insert measurement
// USAGE: 105,<DEVICE/ID>,<X>,<Y>,<Z>
"10,107,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER NUMBER NUMBER,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_MotionMeasurement\"\",\"\"c8y_MotionMeasurement\"\":{\"\"x\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"},\"\"y\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"},\"\"z\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"}}}\"\r\n"
);

float interval = 120.0; // send measurements every two minutes

MbedSmartRest client("developer.cumulocity.com", 80, credentials.username, credentials.password, cDeviceIdentifier);

int program(void)
{
    long deviceId = 0; Timer timer;

#ifndef CREDENTIALS_USERNAME
    // read credentials from modem or make a device bootstrapping
    if (!credentials_read(&credentials)) {
        puts("Could not read credentials. Starting bootstrapping process.");
        if (!deviceBootstrap()) {
            puts("Device bootstrap failed.");
            return 1;
        }
    }
#else
    // copy hardcoded credentials
    strcpy(credentials.username, CREDENTIALS_USERNAME);
    strcpy(credentials.password, CREDENTIALS_PASSWORD);
#endif
    
    // copy identifier into variable
    strcpy(cDeviceIdentifier, TEMPLATE_DEVICE_IDENTIFIER);

    lcd_tenant(credentials.username);
    puts("Hello!");
    
    puts("Bootstrapping");
    lcd_status("Bootstrapping");
    if (client.bootstrap(srtpl) != SMARTREST_SUCCESS) {
        puts("Bootstrapping failed.");
        lcd_status("Bootstrapping failed.");
        return 2;
    }
   
    puts("Starting action...");
    
    if ((deviceId = existing()) == 0) {
        if (((deviceId = create()) == 0) || (!identify(deviceId))) {
            lcd_status("Device creation failed.");
            return 1;
        }
    }
    update(deviceId);
    printf("Device ID: %ld\r\n", deviceId);

    timer.start();
    while (true) {
        timer.reset();
        loop(deviceId);

        lcd_status("Sleeping...");
        // block remaining number of seconds
        while (timer.read() < interval) {
            Thread::yield();
        }
    }
}

bool deviceBootstrap()
{
    uint8_t ret;
    
    ComposedRecord record(false);
    ParsedRecord received;
    CharValue deviceId(imei());
    IntegerValue connectMsgId(60);
    IntegerValue pollMsgId(61);

    // copy credentials
    strcpy(credentials.username, DEVICEBOOTSTRAP_USERNAME);
    strcpy(credentials.password, DEVICEBOOTSTRAP_PASSWORD);
    
    record.add(connectMsgId);
    record.add(deviceId);
    
    if (client.send(record) != SMARTREST_SUCCESS) {
        puts("Could not connect to platform.");
        client.stop();
        return false;
    }
    client.stop();
    
    ret = client.receive(received);
    if (ret == SMARTREST_SUCCESS) {
        if ((received.values() > 0) && (received.value(0).integerValue() == 50))
            puts("Server error. Make sure to register the device before attempting a device bootstrap.");
        else
            puts("Unknown error.");
        return false;
    }
    record.clear();
    
    record.add(pollMsgId);
    record.add(deviceId);
    
    while (true) {
        if (client.send(record) != SMARTREST_SUCCESS) {
            puts("Connection unsuccessful. Retrying.");
            client.stop();
            Thread::wait(2000);
            continue;
        }
        
        if (client.receive(received) != SMARTREST_SUCCESS) {
            puts("Not received anything. Retrying.");
            client.stop();
            Thread::wait(2000);
            continue;
        }
        client.stop();
        
        if (received.values() < 1) {
            puts("Bad received values. Retrying.");
            Thread::wait(2000);
            continue;
        }
        
        if (received.value(0).integerValue() == 50) {
            puts("No values. Retrying.");
            Thread::wait(2000);
            continue;
        }
        
        if (received.value(0).integerValue() != 70) {
            puts("Unknown received message identifier.");
            return false;
        }
        
        if (received.values() != 6) {
            puts("Bad credentials received.");
            return false;
        }
        
        credentials_set(&credentials, received.value(3).characterValue(), received.value(4).characterValue(), received.value(5).characterValue());
        
        printf("Username: %s\nPassword: %s\n", credentials.username, credentials.password);
        
        credentials_write(&credentials);
        
        return true;
    }
}

long existing()
{
    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
    ParsedRecord received;

    lcd_status("Checking device existance...");
    puts("Checking for device existance...");

    if ((!newMoRec.add(IntegerValue(100))) || (!newMoRec.add(CharValue(imei()))))
        return 0;

    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
        puts("Send failed.");
        client.stop();
        return 0;
    }

    if (client.receive(received) != SMARTREST_SUCCESS) {
        puts("No device found.");
        client.stop();
        return 0;
    }

    if (received.values() == 0) {
        puts("Received no values.");
        client.stop();
        return 0;
    }

    if (received.value(0).integerValue() == 50) {
        client.stop();
        return 0;
    }
    
    if (received.value(0).integerValue() != 200) {
        puts("Bad response.");
        client.stop();
        return 0;
    }

    client.stop();
    return received.value(2).integerValue();
}

long create()
{
    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
    ParsedRecord received;

    lcd_status("Creating device...");
    puts("Creating device...");

    if ((!newMoRec.add(IntegerValue(101))) || (!newMoRec.add(CharValue(imei()))))
        return 0;

    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
        puts("Send failed.");
        client.stop();
        return 0;
    }

    if (client.receive(received) != SMARTREST_SUCCESS) {
        puts("No device found.");
        client.stop();
        return 0;
    }

    if (received.values() != 3) {
        puts("Bad received data.");
        client.stop();
        return 0;
    }
    
    if (received.value(0).integerValue() != 201) {
        puts("Bad received data.");
        client.stop();
        return 0;
    }

    client.stop();
    return received.value(2).integerValue();
}

bool identify(long deviceId)
{
    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
    ParsedRecord received;

    puts("Adding global identifier...");

    if ((!newMoRec.add(IntegerValue(102))) || (!newMoRec.add(IntegerValue(deviceId))) || (!newMoRec.add(CharValue(imei()))))
        return 0;

    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
        puts("Sending failed.");
        client.stop();
        return false;
    }

    if (client.receive(received) != SMARTREST_SUCCESS) {
        puts("Failed.");
        client.stop();
        return false;
    }

    if (received.values() != 3) {
        puts("Received bad data.");
        client.stop();
        return false;
    }
    
    if (received.value(0).integerValue() != 200) {
        puts("Received bad data.");
        client.stop();
        return false;
    }

    client.stop();
    return true;
}

bool update(long deviceId)
{
    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
    ParsedRecord received;

    lcd_status("Updating device object...");
    puts("Updating device data...");

    if ((!newMoRec.add(IntegerValue(103))) || (!newMoRec.add(IntegerValue(deviceId))) || (!newMoRec.add(CharValue(imei()))) || (!newMoRec.add(CharValue(cellId()))) || (!newMoRec.add(CharValue(iccid()))))
        return false;

    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
        puts("Send failed.");
        client.stop();
        return false;
    }

    if (client.receive(received) != SMARTREST_SUCCESS) {
        puts("Update failed.");
        client.stop();
        return false;
    }

    if (received.values() != 3) {
        puts("Bad received data.");
        client.stop();
        return false;
    }
    
    if (received.value(0).integerValue() != 201) {
        puts("Bad received data.");
        client.stop();
        return false;
    }

    client.stop();
    
    return true;
}

void loop(long deviceId)
{
    Aggregator aggr(true);

    lcd_status("Sending measurements...");
    temperatureMeasurement(deviceId, aggr);
    signalMeasurement(deviceId, aggr);
    analogMeasurement(deviceId, aggr);
    motionMeasurement(deviceId, aggr);

    if (client.send(aggr) != SMARTREST_SUCCESS) {
        puts("Loop send failed.");
    }
    client.stop();
}

void signalMeasurement(long deviceId, Aggregator& aggr)
{
    sigq_t *sq = signalQuality();
    
    if ((sq->rssi == 0) || (sq->ber == 0))
        return;
    
    ComposedRecord measurement;
    IntegerValue msgId(104);
    IntegerValue devId(deviceId);
    FloatValue rssi(sq->rssi, 0);
    IntegerValue ber(sq->ber);
    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(rssi)) || (!measurement.add(ber)))
        return;
    aggr.add(measurement);
}

void temperatureMeasurement(long deviceId, Aggregator& aggr)
{
    ComposedRecord measurement;
    IntegerValue msgId(105);
    IntegerValue devId(deviceId);
    FloatValue temp(temperature(), 1);
    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(temp)))
        return;
    aggr.add(measurement);
}

void analogMeasurement(long deviceId, Aggregator& aggr)
{
    long analog0 = (long)(potentiometer(0) * 100.0);
    long analog1 = (long)(potentiometer(1) * 100.0);
    ComposedRecord measurement;
    IntegerValue msgId(106);
    IntegerValue devId(deviceId);
    IntegerValue an0(analog0);
    IntegerValue an1(analog1);
    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(an0)) || (!measurement.add(an1)))
        return;
    aggr.add(measurement);
}

void motionMeasurement(long deviceId, Aggregator& aggr)
{
    acceleration_t acc = acceleration();
    ComposedRecord measurement;
    IntegerValue msgId(107);
    IntegerValue devId(deviceId);
    FloatValue x(acc.x, 2);
    FloatValue y(acc.y, 2);
    FloatValue z(acc.z, 2);
    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(x)) || (!measurement.add(y)) || (!measurement.add(z)))
        return;
    aggr.add(measurement);
}