aws / aws-iot-device-sdk-cpp

SDK for connecting to AWS IoT from a device using C++
http://aws-iot-device-sdk-cpp-docs.s3-website-us-east-1.amazonaws.com
Apache License 2.0
123 stars 111 forks source link

New Version Available

A new AWS IoT Device SDK is now available. It is a complete rework, built to improve reliability, performance, and security. We invite your feedback!

This SDK will no longer receive feature updates, but will receive security updates.

AWS IoT C++ Device SDK

Overview

This document provides information about the AWS IoT device SDK for C++.

Features

The Device SDK simplifies access to the Pub/Sub functionality of the AWS IoT broker via MQTT and provides APIs to interact with Thing Shadows. The SDK has been tested to work with the AWS IoT platform to ensure best interoperability of a device with the AWS IoT platform.

MQTT Connection

The Device SDK provides functionality to create and maintain a MQTT Connection. It expects to be provided with a Network Connection class that connects and authenticates to AWS IoT using either direct TLS or WebSocket over TLS. This connection is used for any further publish operations. It also allows for subscribing to MQTT topics which will call a configurable callback function when these messages are received on these topics.

Thing Shadow

This SDK implements the specific protocol for Thing Shadows to retrieve, update and delete Thing Shadows adhering to the protocol that is implemented to ensure correct versioning and support for client tokens. It abstracts the necessary MQTT topic subscriptions by automatically subscribing to and unsubscribing from the reserved topics as needed for each API call. Inbound state change requests are automatically signalled via a configurable callback.

Jobs

This SDK also implements the Jobs protocol to interact with the AWS IoT Jobs service. The IoT Job service manages deployment of IoT fleet wide tasks such as device software/firmware deployments and updates, rotation of security certificates, device reboots, and custom device specific management tasks. For additional information please see the Jobs developer guide.

Design Goals of this SDK

The C++ SDK was specifically designed for devices that are not resource constrained and required advanced features such as Message queueing, multi-threading support and the latest language features

Primary aspects are:

How to get started ?

Ensure you understand the AWS IoT platform and create the necessary certificates and policies. For more information on the AWS IoT platform please visit the AWS IoT developer guide.

Installation

This section explains the individual steps to retrieve the necessary files and be able to build your first application using the AWS IoT C++ SDK. The SDK uses CMake to generate the necessary Makefile. CMake version 3.2 and above is required.

Prerequisites:

Build Targets:

Steps:

Porting to different platforms

The SDK has been written to adhere to C++11 standard without any additional compiler specific features enabled. It should compile on any platform that has a modern C++11 enabled compiler without issue. The platform should be able to provide a C++11 compatible threading implementation (eg. pthread on linux). TLS libraries can be added by simply implementing a derived class of NetworkConnection and providing an instance to the Client. We provide the following reference implementations for the Network layer:

Cross-compiling the SDK for other platforms

The included ToolchainFile.cmake file can be used to cross-compile the SDK for other platforms. Procedure for testing cross compiling (if using OpenSSL):

  1. build/download toolchain for specific platform

  2. modify the ToolchainFile.cmake with location and target of toolchain.

    # specify toolchain directory
    SET(TOOLCHAIN_DIR /home/toolchain/dir/here/bin)
    
    # specify cross compilation target
    SET(TARGET_CROSS target-here)`
  3. Cross-compile OpenSSL using the same toolchain

  4. modify network/CMakeLists.txt.in and change OpenSSL library location to cross-compiled OpenSSL

  5. cd build
    cmake ../. -DCMAKE_TOOLCHAIN_FILE=../ToolchainFile.cmake
    make
  6. Scp the application binary, certs and config for the application into the platform you're testing

  7. Run ./<application>

For MbedTLS, you don't need to cross-compile MbedTLS as it gets compiled when you run make with the same compiler as pointed to by the toolchain file.

Also included is a simple example 'toolchain' which is used for setting the default compiler as clang++ instead of g++ as an example to show how the toolchain file can be modified.

Quick Links

Sample APIs

Sync

Creating a basic MQTT Client requires a NetworkConnection instance and MQTT Command timeout in milliseconds for any internal blocking operations.

std::shared_ptr<NetworkConnection> p_network_connection = <Create Instance>;
std::shared_ptr<MqttClient> p_client = MqttClient::Create(p_network_connection, std::chrono::milliseconds(30000));

Connecting to the AWS IoT MQTT platform

rc = p_client->Connect(std::chrono::milliseconds(30000), false, mqtt::Version::MQTT_3_1_1, std::chrono::seconds(60), Utf8String::Create("<client_id>"), nullptr, nullptr, nullptr);

Subscribe to a topic

util::String p_topic_name_str = <topic>;
std::unique_ptr<Utf8String> p_topic_name = Utf8String::Create(p_topic_name_str);
mqtt::Subscription::ApplicationCallbackHandlerPtr p_sub_handler = std::bind(&<handler>, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
std::shared_ptr<mqtt::Subscription> p_subscription = mqtt::Subscription::Create(std::move(p_topic_name), mqtt::QoS::QOS0, p_sub_handler, nullptr);
util::Vector<std::shared_ptr<mqtt::Subscription>> topic_vector;
topic_vector.push_back(p_subscription);
rc = p_client->Subscribe(topic_vector, std::chrono::milliseconds(30000));

Publish to a topic

util::String p_topic_name_str = <topic>;
std::unique_ptr<Utf8String> p_topic_name = Utf8String::Create(p_topic_name_str);
rc = p_client->Publish(std::move(p_topic_name), false, false, mqtt::QoS::QOS1, payload, std::chrono::milliseconds(30000));

Unsubscribe from a topic

util::String p_topic_name_str = <topic>;
std::unique_ptr<Utf8String> p_topic_name = Utf8String::Create(p_topic_name_str);
util::Vector<std::unique_ptr<Utf8String>> topic_vector;
topic_vector.push_back(std::move(p_topic_name));
rc = p_client->Subscribe(topic_vector, std::chrono::milliseconds(30000));

Async

Connect is a sync only API in this version of the SDK. Subscribe to a topic

uint16_t packet_id_out;
util::String p_topic_name_str = <topic>;
std::unique_ptr<Utf8String> p_topic_name = Utf8String::Create(p_topic_name_str);
mqtt::Subscription::ApplicationCallbackHandlerPtr p_sub_handler = std::bind(&<handler>, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
std::shared_ptr<mqtt::Subscription> p_subscription = mqtt::Subscription::Create(std::move(p_topic_name), mqtt::QoS::QOS0, p_sub_handler, nullptr);
util::Vector<std::shared_ptr<mqtt::Subscription>> topic_vector;
topic_vector.push_back(p_subscription);
rc = p_client->SubscribeAsync(topic_vector, nullptr, packet_id_out);

Publish to a topic

uint16_t packet_id_out;
util::String p_topic_name_str = <topic>;
std::unique_ptr<Utf8String> p_topic_name = Utf8String::Create(p_topic_name_str);
rc = p_client->PublishAsync(std::move(p_topic_name), false, false, mqtt::QoS::QOS1, payload, packet_id_out);

Unsubscribe from a topic

uint16_t packet_id_out;
util::String p_topic_name_str = <topic>;
std::unique_ptr<Utf8String> p_topic_name = Utf8String::Create(p_topic_name_str);
util::Vector<std::unique_ptr<Utf8String>> topic_vector;
topic_vector.push_back(std::move(p_topic_name));
rc = p_client->Subscribe(topic_vector, packet_id_out);

Logging

To enable logging, create an instance of the ConsoleLogSystem in the main() of your application as shown below:

std::shared_ptr<awsiotsdk::util::Logging::ConsoleLogSystem> p_log_system =
    std::make_shared<awsiotsdk::util::Logging::ConsoleLogSystem>(awsiotsdk::util::Logging::LogLevel::Info);
awsiotsdk::util::Logging::InitializeAWSLogging(p_log_system);

Create a log tag for your application to distinguish it from the SDK logs:

#define LOG_TAG_APPLICATION "[Application]"

You can now add logging to any part of your application using AWS_LOG_ERROR or AWS_LOG_INFO as shown below:

AWS_LOG_ERROR(LOG_TAG_APPLICATION, "Failed to perform action. %s",
              ResponseHelper::ToString(rc).c_str());

License

This SDK is distributed under the Apache License, Version 2.0, see LICENSE and NOTICE.txt for more information.

Support

If you have any technical questions about AWS IoT C++ SDK, use the AWS IoT forum. For any other questions on AWS IoT, contact AWS Support.

A list of known issues is maintained in KnownIssues.md.

Note: customers have reported deadlocks while using the AWS IoT Device SDK for C++. If you are affected, a fix is available in the locking-fixes branch. This issue is also resolved in the new AWS IoT Device SDK for C++, which is currently in Developer Preview.