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

« Back to documentation index

Show/hide line numbers shadow_sample.c Source File

shadow_sample.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 
00016 /**
00017  * @file shadow_sample.c
00018  * @brief A simple connected window example demonstrating the use of Thing Shadow
00019  */
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <ctype.h>
00024 #include <unistd.h>
00025 #include <string.h>
00026 #include <limits.h>
00027 
00028 #include "aws_iot_config.h"
00029 #include "aws_iot_log.h"
00030 #include "aws_iot_version.h"
00031 #include "aws_iot_mqtt_client_interface.h"
00032 #include "aws_iot_shadow_interface.h"
00033 
00034 /*!
00035  * The goal of this sample application is to demonstrate the capabilities of shadow.
00036  * This device(say Connected Window) will open the window of a room based on temperature
00037  * It can report to the Shadow the following parameters:
00038  *  1. temperature of the room (double)
00039  *  2. status of the window (open or close)
00040  * It can act on commands from the cloud. In this case it will open or close the window based on the json object "windowOpen" data[open/close]
00041  *
00042  * The two variables from a device's perspective are double temperature and bool windowOpen
00043  * The device needs to act on only on windowOpen variable, so we will create a primitiveJson_t object with callback
00044  The Json Document in the cloud will be
00045  {
00046  "reported": {
00047  "temperature": 0,
00048  "windowOpen": false
00049  },
00050  "desired": {
00051  "windowOpen": false
00052  }
00053  }
00054  */
00055 
00056 #define ROOMTEMPERATURE_UPPERLIMIT 32.0f
00057 #define ROOMTEMPERATURE_LOWERLIMIT 25.0f
00058 #define STARTING_ROOMTEMPERATURE ROOMTEMPERATURE_LOWERLIMIT
00059 
00060 #define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
00061 
00062 static char certDirectory[PATH_MAX + 1] = "../../../certs";
00063 #define HOST_ADDRESS_SIZE 255
00064 static char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
00065 static uint32_t port = AWS_IOT_MQTT_PORT;
00066 static uint8_t numPubs = 5;
00067 
00068 static void simulateRoomTemperature(float *pRoomTemperature) {
00069     static float deltaChange;
00070 
00071     if(*pRoomTemperature >= ROOMTEMPERATURE_UPPERLIMIT) {
00072         deltaChange = -0.5f;
00073     } else if(*pRoomTemperature <= ROOMTEMPERATURE_LOWERLIMIT) {
00074         deltaChange = 0.5f;
00075     }
00076 
00077     *pRoomTemperature += deltaChange;
00078 }
00079 
00080 void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
00081                                 const char *pReceivedJsonDocument, void *pContextData) {
00082     IOT_UNUSED(pThingName);
00083     IOT_UNUSED(action);
00084     IOT_UNUSED(pReceivedJsonDocument);
00085     IOT_UNUSED(pContextData);
00086 
00087     if(SHADOW_ACK_TIMEOUT == status) {
00088         IOT_INFO("Update Timeout--");
00089     } else if(SHADOW_ACK_REJECTED == status) {
00090         IOT_INFO("Update RejectedXX");
00091     } else if(SHADOW_ACK_ACCEPTED == status) {
00092         IOT_INFO("Update Accepted !!");
00093     }
00094 }
00095 
00096 void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
00097     IOT_UNUSED(pJsonString);
00098     IOT_UNUSED(JsonStringDataLen);
00099 
00100     if(pContext != NULL) {
00101         IOT_INFO("Delta - Window state changed to %d", *(bool *) (pContext->pData));
00102     }
00103 }
00104 
00105 void parseInputArgsForConnectParams(int argc, char **argv) {
00106     int opt;
00107 
00108     while(-1 != (opt = getopt(argc, argv, "h:p:c:n:"))) {
00109         switch(opt) {
00110             case 'h':
00111                 strncpy(HostAddress, optarg, HOST_ADDRESS_SIZE);
00112                 IOT_DEBUG("Host %s", optarg);
00113                 break;
00114             case 'p':
00115                 port = atoi(optarg);
00116                 IOT_DEBUG("arg %s", optarg);
00117                 break;
00118             case 'c':
00119                 strncpy(certDirectory, optarg, PATH_MAX + 1);
00120                 IOT_DEBUG("cert root directory %s", optarg);
00121                 break;
00122             case 'n':
00123                 numPubs = atoi(optarg);
00124                 IOT_DEBUG("num pubs %s", optarg);
00125                 break;
00126             case '?':
00127                 if(optopt == 'c') {
00128                     IOT_ERROR("Option -%c requires an argument.", optopt);
00129                 } else if(isprint(optopt)) {
00130                     IOT_WARN("Unknown option `-%c'.", optopt);
00131                 } else {
00132                     IOT_WARN("Unknown option character `\\x%x'.", optopt);
00133                 }
00134                 break;
00135             default:
00136                 IOT_ERROR("ERROR in command line argument parsing");
00137                 break;
00138         }
00139     }
00140 
00141 }
00142 
00143 int main(int argc, char **argv) {
00144     IoT_Error_t rc = FAILURE;
00145     int32_t i = 0;
00146 
00147     char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
00148     size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
00149     char *pJsonStringToUpdate;
00150     float temperature = 0.0;
00151 
00152     bool windowOpen = false;
00153     jsonStruct_t windowActuator;
00154     windowActuator.cb = windowActuate_Callback;
00155     windowActuator.pData = &windowOpen;
00156     windowActuator.dataLength = sizeof(bool);
00157     windowActuator.pKey = "windowOpen";
00158     windowActuator.type = SHADOW_JSON_BOOL;
00159 
00160     jsonStruct_t temperatureHandler;
00161     temperatureHandler.cb = NULL;
00162     temperatureHandler.pKey = "temperature";
00163     temperatureHandler.pData = &temperature;
00164     temperatureHandler.dataLength = sizeof(float);
00165     temperatureHandler.type = SHADOW_JSON_FLOAT;
00166 
00167     char rootCA[PATH_MAX + 1];
00168     char clientCRT[PATH_MAX + 1];
00169     char clientKey[PATH_MAX + 1];
00170     char CurrentWD[PATH_MAX + 1];
00171 
00172     IOT_INFO("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
00173 
00174     getcwd(CurrentWD, sizeof(CurrentWD));
00175     snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
00176     snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
00177     snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
00178 
00179     IOT_DEBUG("rootCA %s", rootCA);
00180     IOT_DEBUG("clientCRT %s", clientCRT);
00181     IOT_DEBUG("clientKey %s", clientKey);
00182 
00183     parseInputArgsForConnectParams(argc, argv);
00184 
00185     // initialize the mqtt client
00186     AWS_IoT_Client mqttClient;
00187 
00188     ShadowInitParameters_t sp = ShadowInitParametersDefault;
00189     sp.pHost = AWS_IOT_MQTT_HOST;
00190     sp.port = AWS_IOT_MQTT_PORT;
00191     sp.pClientCRT = clientCRT;
00192     sp.pClientKey = clientKey;
00193     sp.pRootCA = rootCA;
00194     sp.enableAutoReconnect = false;
00195     sp.disconnectHandler = NULL;
00196 
00197     IOT_INFO("Shadow Init");
00198     rc = aws_iot_shadow_init(&mqttClient, &sp);
00199     if(SUCCESS != rc) {
00200         IOT_ERROR("Shadow Connection Error");
00201         return rc;
00202     }
00203 
00204     ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
00205     scp.pMyThingName = AWS_IOT_MY_THING_NAME;
00206     scp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
00207     scp.mqttClientIdLen = (uint16_t) strlen(AWS_IOT_MQTT_CLIENT_ID);
00208 
00209     IOT_INFO("Shadow Connect");
00210     rc = aws_iot_shadow_connect(&mqttClient, &scp);
00211     if(SUCCESS != rc) {
00212         IOT_ERROR("Shadow Connection Error");
00213         return rc;
00214     }
00215 
00216     /*
00217      * Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
00218      *  #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
00219      *  #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
00220      */
00221     rc = aws_iot_shadow_set_autoreconnect_status(&mqttClient, true);
00222     if(SUCCESS != rc) {
00223         IOT_ERROR("Unable to set Auto Reconnect to true - %d", rc);
00224         return rc;
00225     }
00226 
00227     rc = aws_iot_shadow_register_delta(&mqttClient, &windowActuator);
00228 
00229     if(SUCCESS != rc) {
00230         IOT_ERROR("Shadow Register Delta Error");
00231     }
00232     temperature = STARTING_ROOMTEMPERATURE;
00233 
00234     // loop and publish a change in temperature
00235     while(NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) {
00236         rc = aws_iot_shadow_yield(&mqttClient, 200);
00237         if(NETWORK_ATTEMPTING_RECONNECT == rc) {
00238             sleep(1);
00239             // If the client is attempting to reconnect we will skip the rest of the loop.
00240             continue;
00241         }
00242         IOT_INFO("\n=======================================================================================\n");
00243         IOT_INFO("On Device: window state %s", windowOpen ? "true" : "false");
00244         simulateRoomTemperature(&temperature);
00245 
00246         rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
00247         if(SUCCESS == rc) {
00248             rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 2, &temperatureHandler,
00249                                              &windowActuator);
00250             if(SUCCESS == rc) {
00251                 rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
00252                 if(SUCCESS == rc) {
00253                     IOT_INFO("Update Shadow: %s", JsonDocumentBuffer);
00254                     rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, JsonDocumentBuffer,
00255                                                ShadowUpdateStatusCallback, NULL, 4, true);
00256                 }
00257             }
00258         }
00259         IOT_INFO("*****************************************************************************************\n");
00260         sleep(1);
00261     }
00262 
00263     if(SUCCESS != rc) {
00264         IOT_ERROR("An error occurred in the loop %d", rc);
00265     }
00266 
00267     IOT_INFO("Disconnecting");
00268     rc = aws_iot_shadow_disconnect(&mqttClient);
00269 
00270     if(SUCCESS != rc) {
00271         IOT_ERROR("Disconnect error %d", rc);
00272     }
00273 
00274     return rc;
00275 }