Demo application for using the AT&T IoT Starter Kit Powered by AWS.

Dependencies:   SDFileSystem

Fork of ATT_AWS_IoT_demo by Anthony Phillips

IoT Starter Kit Powered by AWS Demo

This program demonstrates the AT&T IoT Starter Kit sending data directly into AWS IoT. It's explained and used in the Getting Started with the IoT Starter Kit Powered by AWS on starterkit.att.com.

What's required

  • AT&T IoT LTE Add-on (also known as the Cellular Shield)
  • NXP K64F - for programming
  • microSD card - used to store your AWS security credentials
  • AWS account
  • Python, locally installed

If you don't already have an IoT Starter Kit, you can purchase a kit here. The IoT Starter Kit Powered by AWS includes the LTE cellular shield, K64F, and a microSD card.

main.cpp

Committer:
ampembeng
Date:
2016-12-01
Revision:
15:6f2798e45099
Parent:
12:1ae41c231014
Child:
16:02008a2a2569

File content as of revision 15:6f2798e45099:

/*
 *  AT&T IoT Starter Kit example using Amazon Web Service 
 */
#include "mbed.h"

// Serial extension
#include "MODSERIAL.h"

// Network includes
#include "WNCInterface.h"
#include "network_interface.h"

// AWS includes
#include "aws_iot_log.h"
#include "aws_iot_version.h"
#include "aws_iot_shadow_interface.h"
#include "aws_iot_shadow_json_data.h"
#include "aws_iot_config.h"
#include "aws_iot_mqtt_interface.h"

#if DEBUG_LEVEL > 0
#include "mbedtls/debug.h"
#endif

//=====================================================================================================================
//
// Defines
//
//=====================================================================================================================
// LED Colors
#define COLOR_OFF    0x00
#define COLOR_RED    0x01
#define COLOR_GREEN  0x02
#define COLOR_BLUE   0x04
#define COLOR_WHITE  0x07
#define NUM_COLORS   5

// AWS defines
#define PATH_MAX    4096
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200 // NOTE: Be wary of this if your JSON doc grows
#define SHADOW_SYNC_INTERVAL 3.0             // How often we sync with AWS Shadow (in seconds)

// Comment out the following line if color is not supported on the terminal
//#define USE_COLOR
#ifdef USE_COLOR
 #define BLK "\033[30m"
 #define RED "\033[31m"
 #define GRN "\033[32m"
 #define YEL "\033[33m"
 #define BLU "\033[34m"
 #define MAG "\033[35m"
 #define CYN "\033[36m"
 #define WHT "\033[37m"
 #define DEF "\033[39m"
#else
 #define BLK
 #define RED
 #define GRN
 #define YEL
 #define BLU
 #define MAG
 #define CYN
 #define WHT
 #define DEF
#endif

//=====================================================================================================================
//
// Globals
//
//=====================================================================================================================
// Controls LED color
unsigned char ledColor = COLOR_OFF;

// Color cycle array (used with SW3 button presses)
unsigned char colorCycle[NUM_COLORS] = {COLOR_OFF, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE};

// Button interrupts
bool buttonOverride = false;
InterruptIn Interrupt(SW3);

// Default cert location
//char certDirectory[PATH_MAX + 1] = "../../../certs";

// Default MQTT HOST URL is pulled from the aws_iot_config.h
char HostAddress[255] = AWS_IOT_MQTT_HOST;

// Default MQTT port is pulled from the aws_iot_config.h
uint32_t port = AWS_IOT_MQTT_PORT;

//=====================================================================================================================
//
// Devices
//
//=====================================================================================================================
// GPIOs for RGB LED
DigitalOut led_green(LED_GREEN);
DigitalOut led_red(LED_RED);
DigitalOut led_blue(LED_BLUE);

// USB Serial port (to PC)
MODSERIAL pc(USBTX,USBRX,256,256);

//=====================================================================================================================
//
// Functions
//
//=====================================================================================================================
//*********************************************************************************************************************
//* Prints the given format to the PC serial port.  Exposed to all files via aws_iot_log.h
//*********************************************************************************************************************
void pc_print(const char * format, ...)
{
    va_list vl;
    va_start(vl, format);
    pc.vprintf(format, vl);
    va_end(vl);
}

//*********************************************************************************************************************
//* Set the RGB LED's Color
//* LED Color 0=Off to 7=White.  3 bits represent BGR (bit0=Red, bit1=Green, bit2=Blue) 
//*********************************************************************************************************************
void SetLedColor(unsigned char ucColor)
{
    //Note that when an LED is on, you write a 0 to it:
    led_red = !(ucColor & 0x1); //bit 0
    led_green = !(ucColor & 0x2); //bit 1
    led_blue = !(ucColor & 0x4); //bit 2
}

//*********************************************************************************************************************
//* SW3 Button handler.  Finds the current LED color and sets the button to the next color in colorCycle[]
//*********************************************************************************************************************
void sw3ButtonHandler()
{
    int i;
    for(i=0; i < NUM_COLORS; i++) {
        if (ledColor == colorCycle[i])
            break;
    }
    
    // (circular-queue)
    if (++i == NUM_COLORS)
        i = 0;
        
    ledColor = colorCycle[i];
    SetLedColor(ledColor);
    buttonOverride = true;
}

//=====================================================================================================================
//
// AWS Shadow Callbacks
//
//=====================================================================================================================
//*********************************************************************************************************************
//* This is the callback function that fires when an update is sent.  It will print the update response status.
//*********************************************************************************************************************
void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
        const char *pReceivedJsonDocument, void *pContextData) {

    INFO("Shadow Update Status Callback");
    
    if (status == SHADOW_ACK_TIMEOUT) {
        INFO("Update Timeout--");
    } else if (status == SHADOW_ACK_REJECTED) {
        INFO("Update RejectedXX");
    } else if (status == SHADOW_ACK_ACCEPTED) {
        INFO("Update Accepted!!"); // Good
    }
}

//*********************************************************************************************************************
//* This is the callback function that fires when AWS has sends out a shadow update. 
//*********************************************************************************************************************
void ledControl_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
    
    INFO("LED Callback Detected.");
    
    if (pContext != NULL) {
        switch (*(unsigned char *)(pContext->pData)){   
            case COLOR_OFF:
                INFO("LED -> OFF (%d)", *(unsigned char *)(pContext->pData));
                break;
            case COLOR_RED:
                INFO("LED -> RED (%d)", *(unsigned char *)(pContext->pData));
                break;
            case COLOR_GREEN:
                INFO("LED -> GREEN (%d)", *(unsigned char *)(pContext->pData));
                break;
            case COLOR_BLUE:
                INFO("LED -> BLUE (%d)", *(unsigned char *)(pContext->pData));
                break;
            case COLOR_WHITE:
                INFO("LED -> WHITE (%d)", *(unsigned char *)(pContext->pData));
                break;    
        }
    }
    else {
        INFO("pContext was detected as NULL");
    }
}

//=====================================================================================================================
//
// Main
//
//=====================================================================================================================
int main() {
    
    // Set baud rate for PC Serial
    pc.baud(115200);
    INFO("Hello World from AT&T IoT Start Kit demo!");
                        
    IoT_Error_t rc = NONE_ERROR;  
    char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
    size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);

    // JSON struct for LED control
    jsonStruct_t ledController;
    ledController.cb = ledControl_Callback;
    ledController.pData = &ledColor;
    ledController.pKey = "ledColor";
    ledController.type = SHADOW_JSON_UINT8;

    // TODO Add FRDM temperature reading
    /*
    float temperature = 0.0;
    jsonStruct_t temperatureHandler;
    temperatureHandler.cb = NULL;
    temperatureHandler.pKey = "temperature";
    temperatureHandler.pData = &temperature;
    temperatureHandler.type = SHADOW_JSON_FLOAT;
    */
    
    INFO("AWS IoT SDK Version(dev) %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);

    // TODO: We could try to pull the certs from an SD card
    /*
    char rootCA[PATH_MAX + 1];
    char clientCRT[PATH_MAX + 1];
    char clientKey[PATH_MAX + 1];
    char CurrentWD[PATH_MAX + 1];
    char cafileName[] = AWS_IOT_ROOT_CA_FILENAME;
    char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME;
    char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME;
  
    getcwd(CurrentWD, sizeof(CurrentWD));
    sprintf(rootCA, "%s/%s/%s", CurrentWD, certDirectory, cafileName);
    sprintf(clientCRT, "%s/%s/%s", CurrentWD, certDirectory, clientCRTName);
    sprintf(clientKey, "%s/%s/%s", CurrentWD, certDirectory, clientKeyName);

    DEBUG("Using rootCA %s", rootCA);
    DEBUG("Using clientCRT %s", clientCRT);
    DEBUG("Using clientKey %s", clientKey);
    */
    
    // Blinks through RGB then turns off
    SetLedColor(COLOR_RED);
    wait(.5);
    SetLedColor(COLOR_GREEN);
    wait(.5);
    SetLedColor(COLOR_BLUE);
    wait(.5);
    SetLedColor(COLOR_OFF); 
    
    // Setup SW3 button to falling edge interrupt
    Interrupt.fall(&sw3ButtonHandler);
      
    // Boot the Avnet Shield before any other operations
    net_modem_boot();
      
    INFO("Initialize the MQTT client...");
    MQTTClient_t mqttClient;
    aws_iot_mqtt_init(&mqttClient);

    ShadowParameters_t sp = ShadowParametersDefault;
    sp.pMyThingName = AWS_IOT_MY_THING_NAME;
    sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
    sp.pHost = HostAddress;
    sp.port = port;
    //sp.pClientCRT = clientCRT;
    //sp.pClientKey = clientKey;
    //sp.pRootCA = rootCA;
    sp.pClientCRT = AWS_IOT_CERTIFICATE_FILENAME;
    sp.pClientKey = AWS_IOT_PRIVATE_KEY_FILENAME;
    sp.pRootCA = AWS_IOT_ROOT_CA_FILENAME;

    INFO("Shadow Init...");
    rc = aws_iot_shadow_init(&mqttClient);
    if (NONE_ERROR != rc) {
        ERROR("Shadow Init Error %d", rc);
        return rc;
    }
    
    INFO("Shadow Connect...");   
    rc = aws_iot_shadow_connect(&mqttClient, &sp);
    if (NONE_ERROR != rc) {
        ERROR("Shadow Connection Error %d", rc);
        return rc;
    }

    // Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
    // #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
    // #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
    rc = mqttClient.setAutoReconnectStatus(true);
    if (NONE_ERROR != rc) {
        ERROR("Unable to set Auto Reconnect to true - %d", rc);
        return rc;
    }
    
    // Example line of how to delete a shadow (not used in this demo)
    //aws_iot_shadow_delete(&mqttClient, AWS_IOT_MY_THING_NAME, ShadowUpdateStatusCallback, NULL, 8, true);

    INFO("Shadow Register Delta...");
    rc = aws_iot_shadow_register_delta(&mqttClient, &ledController);
    if (NONE_ERROR != rc) {
        ERROR("Shadow Register Delta Error");
        return rc;
    }
    
    INFO("Will attempt to sync with device shadow every %f seconds.", SHADOW_SYNC_INTERVAL);
    // Loop and publish changes from the FRDM board
    while (NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc) {
        
        // Looks for incoming socket messages
        rc = aws_iot_shadow_yield(&mqttClient, 200);
        if (NETWORK_ATTEMPTING_RECONNECT == rc) {
            // If the client is attempting to reconnect we will skip the rest of the loop.
            INFO("Attempting to reconnect...");
            wait(1);
            continue;
        }
                          
        INFO("\n=======================================================================================\n");             
        // Initialize JSON shadow document          
        rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
        if (rc == NONE_ERROR) {
            
            // If there has been a SW3 button press update the 'desired' color
            if (buttonOverride) {
                rc = aws_iot_shadow_add_desired(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 1, &ledController);
                buttonOverride = false;
            }
                  
            // Updates the 'reported' color
            rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 1, &ledController);
                
            // TODO: format for adding temperature
            //rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 2, &ledController, &temperatureHandler);
                 
            if (rc == NONE_ERROR) {               
                rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);   
                            
                if (rc == NONE_ERROR) {
                    INFO("Update Shadow: %s", JsonDocumentBuffer);
                    rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, JsonDocumentBuffer,
                            ShadowUpdateStatusCallback, NULL, 8, true);
                }
            }
        }      
        INFO("*****************************************************************************************\n");
         
        // Set LED color then wait an loop again     
        SetLedColor(ledColor);
        wait(SHADOW_SYNC_INTERVAL);
    }

    if (NONE_ERROR != rc) {
        ERROR("An error occurred in the loop %d", rc);
    }

    INFO("Disconnecting");
    rc = aws_iot_shadow_disconnect(&mqttClient);

    if (NONE_ERROR != rc) {
        ERROR("Disconnect error %d", rc);
    }

    return rc;   
}