Jim Flynn
/
aws-iot-device-sdk-mbed-c
Changes to enabled on-line compiler
Diff: examples/shadow_sample/shadow_sample.c
- Revision:
- 0:082731ede69f
diff -r 000000000000 -r 082731ede69f examples/shadow_sample/shadow_sample.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/shadow_sample/shadow_sample.c Wed May 30 20:59:51 2018 +0000 @@ -0,0 +1,275 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +/** + * @file shadow_sample.c + * @brief A simple connected window example demonstrating the use of Thing Shadow + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> + +#include "aws_iot_config.h" +#include "aws_iot_log.h" +#include "aws_iot_version.h" +#include "aws_iot_mqtt_client_interface.h" +#include "aws_iot_shadow_interface.h" + +/*! + * The goal of this sample application is to demonstrate the capabilities of shadow. + * This device(say Connected Window) will open the window of a room based on temperature + * It can report to the Shadow the following parameters: + * 1. temperature of the room (double) + * 2. status of the window (open or close) + * 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] + * + * The two variables from a device's perspective are double temperature and bool windowOpen + * The device needs to act on only on windowOpen variable, so we will create a primitiveJson_t object with callback + The Json Document in the cloud will be + { + "reported": { + "temperature": 0, + "windowOpen": false + }, + "desired": { + "windowOpen": false + } + } + */ + +#define ROOMTEMPERATURE_UPPERLIMIT 32.0f +#define ROOMTEMPERATURE_LOWERLIMIT 25.0f +#define STARTING_ROOMTEMPERATURE ROOMTEMPERATURE_LOWERLIMIT + +#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200 + +static char certDirectory[PATH_MAX + 1] = "../../../certs"; +#define HOST_ADDRESS_SIZE 255 +static char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST; +static uint32_t port = AWS_IOT_MQTT_PORT; +static uint8_t numPubs = 5; + +static void simulateRoomTemperature(float *pRoomTemperature) { + static float deltaChange; + + if(*pRoomTemperature >= ROOMTEMPERATURE_UPPERLIMIT) { + deltaChange = -0.5f; + } else if(*pRoomTemperature <= ROOMTEMPERATURE_LOWERLIMIT) { + deltaChange = 0.5f; + } + + *pRoomTemperature += deltaChange; +} + +void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status, + const char *pReceivedJsonDocument, void *pContextData) { + IOT_UNUSED(pThingName); + IOT_UNUSED(action); + IOT_UNUSED(pReceivedJsonDocument); + IOT_UNUSED(pContextData); + + if(SHADOW_ACK_TIMEOUT == status) { + IOT_INFO("Update Timeout--"); + } else if(SHADOW_ACK_REJECTED == status) { + IOT_INFO("Update RejectedXX"); + } else if(SHADOW_ACK_ACCEPTED == status) { + IOT_INFO("Update Accepted !!"); + } +} + +void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) { + IOT_UNUSED(pJsonString); + IOT_UNUSED(JsonStringDataLen); + + if(pContext != NULL) { + IOT_INFO("Delta - Window state changed to %d", *(bool *) (pContext->pData)); + } +} + +void parseInputArgsForConnectParams(int argc, char **argv) { + int opt; + + while(-1 != (opt = getopt(argc, argv, "h:p:c:n:"))) { + switch(opt) { + case 'h': + strncpy(HostAddress, optarg, HOST_ADDRESS_SIZE); + IOT_DEBUG("Host %s", optarg); + break; + case 'p': + port = atoi(optarg); + IOT_DEBUG("arg %s", optarg); + break; + case 'c': + strncpy(certDirectory, optarg, PATH_MAX + 1); + IOT_DEBUG("cert root directory %s", optarg); + break; + case 'n': + numPubs = atoi(optarg); + IOT_DEBUG("num pubs %s", optarg); + break; + case '?': + if(optopt == 'c') { + IOT_ERROR("Option -%c requires an argument.", optopt); + } else if(isprint(optopt)) { + IOT_WARN("Unknown option `-%c'.", optopt); + } else { + IOT_WARN("Unknown option character `\\x%x'.", optopt); + } + break; + default: + IOT_ERROR("ERROR in command line argument parsing"); + break; + } + } + +} + +int main(int argc, char **argv) { + IoT_Error_t rc = FAILURE; + int32_t i = 0; + + char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER]; + size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]); + char *pJsonStringToUpdate; + float temperature = 0.0; + + bool windowOpen = false; + jsonStruct_t windowActuator; + windowActuator.cb = windowActuate_Callback; + windowActuator.pData = &windowOpen; + windowActuator.dataLength = sizeof(bool); + windowActuator.pKey = "windowOpen"; + windowActuator.type = SHADOW_JSON_BOOL; + + jsonStruct_t temperatureHandler; + temperatureHandler.cb = NULL; + temperatureHandler.pKey = "temperature"; + temperatureHandler.pData = &temperature; + temperatureHandler.dataLength = sizeof(float); + temperatureHandler.type = SHADOW_JSON_FLOAT; + + char rootCA[PATH_MAX + 1]; + char clientCRT[PATH_MAX + 1]; + char clientKey[PATH_MAX + 1]; + char CurrentWD[PATH_MAX + 1]; + + IOT_INFO("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG); + + getcwd(CurrentWD, sizeof(CurrentWD)); + snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME); + snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME); + snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME); + + IOT_DEBUG("rootCA %s", rootCA); + IOT_DEBUG("clientCRT %s", clientCRT); + IOT_DEBUG("clientKey %s", clientKey); + + parseInputArgsForConnectParams(argc, argv); + + // initialize the mqtt client + AWS_IoT_Client mqttClient; + + ShadowInitParameters_t sp = ShadowInitParametersDefault; + sp.pHost = AWS_IOT_MQTT_HOST; + sp.port = AWS_IOT_MQTT_PORT; + sp.pClientCRT = clientCRT; + sp.pClientKey = clientKey; + sp.pRootCA = rootCA; + sp.enableAutoReconnect = false; + sp.disconnectHandler = NULL; + + IOT_INFO("Shadow Init"); + rc = aws_iot_shadow_init(&mqttClient, &sp); + if(SUCCESS != rc) { + IOT_ERROR("Shadow Connection Error"); + return rc; + } + + ShadowConnectParameters_t scp = ShadowConnectParametersDefault; + scp.pMyThingName = AWS_IOT_MY_THING_NAME; + scp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID; + scp.mqttClientIdLen = (uint16_t) strlen(AWS_IOT_MQTT_CLIENT_ID); + + IOT_INFO("Shadow Connect"); + rc = aws_iot_shadow_connect(&mqttClient, &scp); + if(SUCCESS != rc) { + IOT_ERROR("Shadow Connection Error"); + 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 = aws_iot_shadow_set_autoreconnect_status(&mqttClient, true); + if(SUCCESS != rc) { + IOT_ERROR("Unable to set Auto Reconnect to true - %d", rc); + return rc; + } + + rc = aws_iot_shadow_register_delta(&mqttClient, &windowActuator); + + if(SUCCESS != rc) { + IOT_ERROR("Shadow Register Delta Error"); + } + temperature = STARTING_ROOMTEMPERATURE; + + // loop and publish a change in temperature + while(NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) { + rc = aws_iot_shadow_yield(&mqttClient, 200); + if(NETWORK_ATTEMPTING_RECONNECT == rc) { + sleep(1); + // If the client is attempting to reconnect we will skip the rest of the loop. + continue; + } + IOT_INFO("\n=======================================================================================\n"); + IOT_INFO("On Device: window state %s", windowOpen ? "true" : "false"); + simulateRoomTemperature(&temperature); + + rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer); + if(SUCCESS == rc) { + rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 2, &temperatureHandler, + &windowActuator); + if(SUCCESS == rc) { + rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer); + if(SUCCESS == rc) { + IOT_INFO("Update Shadow: %s", JsonDocumentBuffer); + rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, JsonDocumentBuffer, + ShadowUpdateStatusCallback, NULL, 4, true); + } + } + } + IOT_INFO("*****************************************************************************************\n"); + sleep(1); + } + + if(SUCCESS != rc) { + IOT_ERROR("An error occurred in the loop %d", rc); + } + + IOT_INFO("Disconnecting"); + rc = aws_iot_shadow_disconnect(&mqttClient); + + if(SUCCESS != rc) { + IOT_ERROR("Disconnect error %d", rc); + } + + return rc; +}