Jim Flynn / Mbed OS aws-iot-device-sdk-mbed-c
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers shadow_console_echo.c Source File

shadow_console_echo.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License").
00005  * You may not use this file except in compliance with the License.
00006  * A copy of the License is located at
00007  *
00008  *  http://aws.amazon.com/apache2.0
00009  *
00010  * or in the "license" file accompanying this file. This file is distributed
00011  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
00012  * express or implied. See the License for the specific language governing
00013  * permissions and limitations under the License.
00014  */
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <ctype.h>
00019 #include <unistd.h>
00020 #include <limits.h>
00021 
00022 #include "aws_iot_config.h"
00023 #include "aws_iot_log.h"
00024 #include "aws_iot_version.h"
00025 #include "aws_iot_mqtt_client_interface.h"
00026 #include "aws_iot_shadow_interface.h"
00027 
00028 /**
00029  * @file shadow_console_echo.c
00030  * @brief  Echo received Delta message
00031  *
00032  * This application will echo the message received in delta, as reported.
00033  * for example:
00034  * Received Delta message
00035  * {
00036  *    "state": {
00037  *       "switch": "on"
00038  *   }
00039  * }
00040  * This delta message means the desired switch position has changed to "on"
00041  *
00042  * This application will take this delta message and publish it back as the reported message from the device.
00043  * {
00044  *    "state": {
00045  *     "reported": {
00046  *       "switch": "on"
00047  *      }
00048  *    }
00049  * }
00050  *
00051  * This update message will remove the delta that was created. If this message was not removed then the AWS IoT Thing Shadow is going to always have a delta and keep sending delta any time an update is applied to the Shadow
00052  * This example will not use any of the json builder/helper functions provided in the aws_iot_shadow_json_data.h.
00053  * @note Ensure the buffer sizes in aws_iot_config.h are big enough to receive the delta message. The delta message will also contain the metadata with the timestamps
00054  */
00055 
00056 char certDirectory[PATH_MAX + 1] = "../../../certs";
00057 #define HOST_ADDRESS_SIZE 255
00058 char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
00059 uint32_t port = AWS_IOT_MQTT_PORT;
00060 bool messageArrivedOnDelta = false;
00061 
00062 /*
00063  * @note The delta message is always sent on the "state" key in the json
00064  * @note Any time messages are bigger than AWS_IOT_MQTT_RX_BUF_LEN the underlying MQTT library will ignore it. The maximum size of the message that can be received is limited to the AWS_IOT_MQTT_RX_BUF_LEN
00065  */
00066 char stringToEchoDelta[SHADOW_MAX_SIZE_OF_RX_BUFFER];
00067 
00068 // Helper functions
00069 void parseInputArgsForConnectParams(int argc, char** argv);
00070 
00071 // Shadow Callback for receiving the delta
00072 void DeltaCallback(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t);
00073 
00074 void UpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
00075         const char *pReceivedJsonDocument, void *pContextData);
00076 
00077 int main(int argc, char** argv) {
00078     IoT_Error_t rc = SUCCESS;
00079     int32_t i = 0;
00080 
00081     char rootCA[PATH_MAX + 1];
00082     char clientCRT[PATH_MAX + 1];
00083     char clientKey[PATH_MAX + 1];
00084     char CurrentWD[PATH_MAX + 1];
00085 
00086     IOT_INFO("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
00087 
00088     getcwd(CurrentWD, sizeof(CurrentWD));
00089     snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
00090     snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
00091     snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
00092 
00093     IOT_DEBUG("rootCA %s", rootCA);
00094     IOT_DEBUG("clientCRT %s", clientCRT);
00095     IOT_DEBUG("clientKey %s", clientKey);
00096 
00097     parseInputArgsForConnectParams(argc, argv);
00098 
00099     // initialize the mqtt client
00100     AWS_IoT_Client mqttClient;
00101 
00102     ShadowInitParameters_t sp = ShadowInitParametersDefault;
00103     sp.pHost = AWS_IOT_MQTT_HOST;
00104     sp.port = AWS_IOT_MQTT_PORT;
00105     sp.pClientCRT = clientCRT;
00106     sp.pClientKey = clientKey;
00107     sp.pRootCA = rootCA;
00108     sp.enableAutoReconnect = false;
00109     sp.disconnectHandler = NULL;
00110 
00111     IOT_INFO("Shadow Init");
00112     rc = aws_iot_shadow_init(&mqttClient, &sp);
00113     if (SUCCESS != rc) {
00114         IOT_ERROR("Shadow Connection Error");
00115         return rc;
00116     }
00117 
00118     ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
00119     scp.pMyThingName = AWS_IOT_MY_THING_NAME;
00120     scp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
00121     scp.mqttClientIdLen = (uint16_t) strlen(AWS_IOT_MQTT_CLIENT_ID);
00122 
00123     IOT_INFO("Shadow Connect");
00124     rc = aws_iot_shadow_connect(&mqttClient, &scp);
00125     if (SUCCESS != rc) {
00126         IOT_ERROR("Shadow Connection Error");
00127         return rc;
00128     }
00129 
00130     /*
00131      * Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
00132      *  #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
00133      *  #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
00134      */
00135     rc = aws_iot_shadow_set_autoreconnect_status(&mqttClient, true);
00136     if(SUCCESS != rc){
00137         IOT_ERROR("Unable to set Auto Reconnect to true - %d", rc);
00138         return rc;
00139     }
00140 
00141     jsonStruct_t deltaObject;
00142     deltaObject.pData = stringToEchoDelta;
00143     deltaObject.dataLength = SHADOW_MAX_SIZE_OF_RX_BUFFER;
00144     deltaObject.pKey = "state";
00145     deltaObject.type = SHADOW_JSON_OBJECT;
00146     deltaObject.cb = DeltaCallback;
00147 
00148     /*
00149      * Register the jsonStruct object
00150      */
00151     rc = aws_iot_shadow_register_delta(&mqttClient, &deltaObject);
00152 
00153     // Now wait in the loop to receive any message sent from the console
00154     while (NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) {
00155         /*
00156          * Lets check for the incoming messages for 200 ms.
00157          */
00158         rc = aws_iot_shadow_yield(&mqttClient, 200);
00159 
00160         if (NETWORK_ATTEMPTING_RECONNECT == rc) {
00161             sleep(1);
00162             // If the client is attempting to reconnect we will skip the rest of the loop.
00163             continue;
00164         }
00165 
00166         if (messageArrivedOnDelta) {
00167             IOT_INFO("\nSending delta message back %s\n", stringToEchoDelta);
00168             rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, stringToEchoDelta, UpdateStatusCallback, NULL, 2, true);
00169             messageArrivedOnDelta = false;
00170         }
00171 
00172         // sleep for some time in seconds
00173         sleep(1);
00174     }
00175 
00176     if (SUCCESS != rc) {
00177         IOT_ERROR("An error occurred in the loop %d", rc);
00178     }
00179 
00180     IOT_INFO("Disconnecting");
00181     rc = aws_iot_shadow_disconnect(&mqttClient);
00182 
00183     if (SUCCESS != rc) {
00184         IOT_ERROR("Disconnect error %d", rc);
00185     }
00186 
00187     return rc;
00188 }
00189 /**
00190  * @brief This function builds a full Shadow expected JSON document by putting the data in the reported section
00191  *
00192  * @param pJsonDocument Buffer to be filled up with the JSON data
00193  * @param maxSizeOfJsonDocument maximum size of the buffer that could be used to fill
00194  * @param pReceivedDeltaData This is the data that will be embedded in the reported section of the JSON document
00195  * @param lengthDelta Length of the data
00196  */
00197 bool buildJSONForReported(char *pJsonDocument, size_t maxSizeOfJsonDocument, const char *pReceivedDeltaData, uint32_t lengthDelta) {
00198     int32_t ret;
00199 
00200     if (NULL == pJsonDocument) {
00201         return false;
00202     }
00203 
00204     char tempClientTokenBuffer[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
00205 
00206     if(aws_iot_fill_with_client_token(tempClientTokenBuffer, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE) != SUCCESS){
00207         return false;
00208     }
00209 
00210     ret = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{\"reported\":%.*s}, \"clientToken\":\"%s\"}", lengthDelta, pReceivedDeltaData, tempClientTokenBuffer);
00211 
00212     if (ret >= maxSizeOfJsonDocument || ret < 0) {
00213         return false;
00214     }
00215 
00216     return true;
00217 }
00218 
00219 void parseInputArgsForConnectParams(int argc, char** argv) {
00220     int opt;
00221 
00222     while (-1 != (opt = getopt(argc, argv, "h:p:c:"))) {
00223         switch (opt) {
00224         case 'h':
00225             strncpy(HostAddress, optarg, HOST_ADDRESS_SIZE);
00226             IOT_DEBUG("Host %s", optarg);
00227             break;
00228         case 'p':
00229             port = atoi(optarg);
00230             IOT_DEBUG("arg %s", optarg);
00231             break;
00232         case 'c':
00233             strncpy(certDirectory, optarg, PATH_MAX + 1);
00234             IOT_DEBUG("cert root directory %s", optarg);
00235             break;
00236         case '?':
00237             if (optopt == 'c') {
00238                 IOT_ERROR("Option -%c requires an argument.", optopt);
00239             } else if (isprint(optopt)) {
00240                 IOT_WARN("Unknown option `-%c'.", optopt);
00241             } else {
00242                 IOT_WARN("Unknown option character `\\x%x'.", optopt);
00243             }
00244             break;
00245         default:
00246             IOT_ERROR("ERROR in command line argument parsing");
00247             break;
00248         }
00249     }
00250 
00251 }
00252 
00253 
00254 void DeltaCallback(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t) {
00255     IOT_UNUSED(pJsonStruct_t);
00256 
00257     IOT_DEBUG("Received Delta message %.*s", valueLength, pJsonValueBuffer);
00258 
00259     if (buildJSONForReported(stringToEchoDelta, SHADOW_MAX_SIZE_OF_RX_BUFFER, pJsonValueBuffer, valueLength)) {
00260         messageArrivedOnDelta = true;
00261     }
00262 }
00263 
00264 void UpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
00265         const char *pReceivedJsonDocument, void *pContextData) {
00266     IOT_UNUSED(pThingName);
00267     IOT_UNUSED(action);
00268     IOT_UNUSED(pReceivedJsonDocument);
00269     IOT_UNUSED(pContextData);
00270 
00271     if(SHADOW_ACK_TIMEOUT == status) {
00272         IOT_INFO("Update Timeout--");
00273     } else if(SHADOW_ACK_REJECTED == status) {
00274         IOT_INFO("Update RejectedXX");
00275     } else if(SHADOW_ACK_ACCEPTED == status) {
00276         IOT_INFO("Update Accepted !!");
00277     }
00278 }