mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-08-06 15:15:15 +08:00
feat(examples): add examples for aws iot
IDF: release/v3.1, commit: 66dad0c5
This commit is contained in:
131
examples/protocols/aws_iot/README.md
Normal file
131
examples/protocols/aws_iot/README.md
Normal file
@ -0,0 +1,131 @@
|
||||
# Amazon Web Services IoT Examples
|
||||
|
||||
These examples are adaptations of some of the [AWS IoT C SDK](https://github.com/aws/aws-iot-device-sdk-embedded-C) examples.
|
||||
|
||||
The provisioning/configuration steps for these examples are the same, and are given in this README.
|
||||
|
||||
This README also contains some troubleshooting information for common problems found when connecting to AWS IoT.
|
||||
|
||||
# Provisioning/Configuration
|
||||
|
||||
There are some additional steps that need to be run before you can build this example.
|
||||
|
||||
The [Getting Started section of the AWS IoT Developer Guide](http://docs.aws.amazon.com/iot/latest/developerguide/iot-gs.html) lays out the steps to get started with AWS IoT.
|
||||
|
||||
To build and use this example, follow all the AWS IoT Getting Started steps from the beginning ("Sign in to the AWS Iot Console") up until "Configuring Your Device". For configuring the device, these are the steps:
|
||||
|
||||
## Configuring Your Device
|
||||
|
||||
### Installing Private Key & Certificate
|
||||
|
||||
As part of creating a device certificate, you downloaded a Private Key (`xxx-private.pem.key`) and a Certificate file (`xxx-certificate.pem.crt`). These keys need to be loaded by the ESP32 to identify itself.
|
||||
|
||||
There are currently two options for how to load the key & cert.
|
||||
|
||||
* Embed the files into the app binary (default)
|
||||
* Load the files from SD card
|
||||
|
||||
### Option 1: Embedded Key & Cert into App Binary
|
||||
|
||||
Copy the `.pem.key` and `.pem.crt` files to the `main/certs` subdirectory of the example. Rename them by removing the device-specific prefix - the new names are `private.pem.key` and `certificate.pem.crt`.
|
||||
|
||||
As these files are bound to your AWS IoT account, take care not to accidentally commit them to public source control. In a commercial IoT device these files would be flashed to the device via a provisioning step, but for these examples they are compiled in.
|
||||
|
||||
### Option 2: Loading Key & Cert from SD Card
|
||||
|
||||
The alternative to embedding the key and certificate is to load them from a FAT filesystem on an SD card.
|
||||
|
||||
Before loading data from SD, format your SD card as FAT and run the `examples/storage/sd_card` example on it to verify that it's working as expected in ESP-IDF. This helps cut down the possible causes of errors in the more complex AWS IoT examples!
|
||||
|
||||
Run `make menuconfig`, navigate to "Example Configuration" and change "AWS IoT Certificate Source" to "Load from SD card".
|
||||
|
||||
Three new prompts will appear for filenames for the device key, device certificate and root CA certificate path. These paths start with `/sdcard/` as this is where the example mounts the (FAT formatted) SD card.
|
||||
|
||||
Copy the certificate and key files to the SD card, and make sure the file names match the names given in the example configuration (either rename the files, or change the config). For the Root CA certificate file (which is not device-specific), you can find the file in the `main/certs` directory or download it from AWS.
|
||||
|
||||
*Note: By default, esp-idf's FATFS support only allows 8.3 character filenames. However, the AWS IoT examples pre-configure the sdkconfig to enable long filenames. If you're setting up your projects, you will probably want to enable these options as well (under Component Config -> FAT Filesystem Support). You can also consider configure the FAT filesystem for read-only support, if you don't need to write to the SD card.*
|
||||
|
||||
## Find & Set AWS Endpoint Hostname
|
||||
|
||||
Your AWS IoT account has a unique endpoint hostname to connect to. To find it, open the AWS IoT Console and click the "Settings" button on the bottom left side. The endpoint hostname is shown under the "Custom Endpoint" heading on this page.
|
||||
|
||||
Run `make menuconfig` and navigate to `Component Config` -> `Amazon Web Service IoT Config` -> `AWS IoT MQTT Hostname`. Enter the host name here.
|
||||
|
||||
*Note: It may seem odd that you have to configure parts of the AWS settings under Component Config and some under Example Configuration.* The IoT MQTT Hostname and Port are set as part of the component because when using the AWS IoT SDK's Thing Shadow API (in examples or in other projects) the `ShadowInitParametersDefault` structure means the Thing Shadow connection will default to that host & port. You're not forced to use these config values in your own projects, you can set the values in code via the AWS IoT SDK's init parameter structures - `ShadowInitParameters_t` for Thing Shadow API or `IoT_Client_Init_Params` for MQTT API.
|
||||
|
||||
### (Optional) Set Client ID
|
||||
|
||||
Run `make menuconfig`. Under `Example Configuration`, set the `AWS IoT Client ID` to a unique value.
|
||||
|
||||
The Client ID is used in the MQTT protocol used to send messages to/from AWS IoT. AWS IoT requires that each connected device within a single AWS account uses a unique Client ID. Other than this restriction, the Client ID can be any value that you like. The example default should be fine if you're only connecting one ESP32 at a time.
|
||||
|
||||
In a production IoT app this ID would be set dynamically, but for these examples it is compiled in via menuconfig.
|
||||
|
||||
### (Optional) Locally Check The Root Certificate
|
||||
|
||||
The Root CA certificate provides a root-of-trust when the ESP32 connects to AWS IoT. We have supplied the root CA certificate already (in PEM format) in the file `main/certs/aws-root-ca.pem`.
|
||||
|
||||
If you want to locally verify that this Root CA certificate hasn't changed, you can run the following command against your AWS MQTT Host:
|
||||
|
||||
```
|
||||
openssl s_client -showcerts -connect hostname:8883 < /dev/null
|
||||
```
|
||||
|
||||
(Replace hostname with your AWS MQTT endpoint host.) The Root CA certificate is the last certificate in the list of certificates printed. You can copy-paste this in place of the existing `aws-root-ca.pem` file.
|
||||
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
## Tips
|
||||
|
||||
* Raise the ESP debug log level to Debug in order to see messages about the connection to AWS, certificate contents, etc.
|
||||
|
||||
* Enable mbedTLS debugging (under Components -> mbedTLS -> mbedTLS Debug) in order to see even more low-level debug output from the mbedTLS layer.
|
||||
|
||||
* To create a successful AWS IoT connection, the following factors must all be present:
|
||||
- Endpoint hostname is correct for your AWS account.
|
||||
- Certificate & private key are both attached to correct Thing in AWS IoT Console.
|
||||
- Certificate is activated.
|
||||
- Policy is attached to the Certificate in AWS IoT Console.
|
||||
- Policy contains sufficient permissions to authorize AWS IoT connection.
|
||||
|
||||
## TLS connection fails
|
||||
|
||||
If connecting fails entirely (handshake doesn't complete), this usually indicates a problem with certification configuration. The error usually looks like this:
|
||||
|
||||
```
|
||||
aws_iot: failed! mbedtls_ssl_handshake returned -0x7780
|
||||
```
|
||||
|
||||
(0x7780 is the mbedTLS error code when the server sends an alert message and closes the connection.)
|
||||
|
||||
* Check your client private key and certificate file match a Certificate registered and **activated** in AWS IoT console. You can find the Certificate in IoT Console in one of two ways, via the Thing or via Certificates:
|
||||
- To find the Certificate directly, click on "Registry" -> "Security Certificates". Then click on the Certificate itself to view it.
|
||||
- To find the Certificate via the Thing, click on "Registry" -> "Things", then click on the particular Thing you are using. Click "Certificates" in the sidebar to view all Certificates attached to that Thing. Then click on the Certificate itself to view it.
|
||||
|
||||
Verify the Certificate is activated (when viewing the Certificate, it will say "ACTIVE" or "INACTIVE" near the top under the certificate name).
|
||||
|
||||
If the Certificate appears correct and activated, verify that you are connecting to the correct AWS IoT endpoint (see above.)
|
||||
|
||||
## TLS connection closes immediately
|
||||
|
||||
Sometimes connecting is successful (the handshake completes) but as soon as the client sends its `MQTT CONNECT` message the server sends back a TLS alert and closes the connection, without anything else happening.
|
||||
|
||||
The error returned from AWS IoT is usually -28 (`MQTT_REQUEST_TIMEOUT_ERROR`). You may also see mbedtls error `-0x7780` (server alert), although if this error comes during `mbedtls_ssl_handshake` then it's usually a different problem (see above).
|
||||
|
||||
In the subscribe_publish example, the error may look like this in the log:
|
||||
|
||||
```
|
||||
subpub: Error(-28) connecting to (endpoint)...
|
||||
```
|
||||
|
||||
In the thing_shadow example, the error may look like this in the log:
|
||||
|
||||
```
|
||||
shadow: aws_iot_shadow_connect returned error -28, aborting...
|
||||
```
|
||||
|
||||
This error implies the Certificate is recognised, but the Certificate is either missing the correct Thing or the correct Policy attached to it.
|
||||
|
||||
* Check in the AWS IoT console that your certificate is activated and has both a **security policy** and a **Thing** attached to it. You can find this in IoT Console by clicking "Registry" -> "Security Certificates", then click the Certificate. Once viewing the Certificate, you can click the "Policies" and "Things" links in the sidebar.
|
||||
|
9
examples/protocols/aws_iot/subscribe_publish/Makefile
Normal file
9
examples/protocols/aws_iot/subscribe_publish/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := aws_iot_subpub
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
32
examples/protocols/aws_iot/subscribe_publish/README.md
Normal file
32
examples/protocols/aws_iot/subscribe_publish/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Amazon Web Services IoT MQTT Subscribe/Publish Example
|
||||
|
||||
This is an adaptation of the [AWS IoT C SDK](https://github.com/aws/aws-iot-device-sdk-embedded-C) "subscribe_publish" example for ESP-IDF.
|
||||
|
||||
# Configuration
|
||||
|
||||
See the README.md in the parent directory for information about configuring the AWS IoT examples.
|
||||
|
||||
# Monitoring MQTT Data from the device
|
||||
|
||||
After flashing the example to your ESP32, it should connect to Amazon and start subscribing/publishing MQTT data.
|
||||
|
||||
The example code publishes MQTT data to the topic `test_topic/esp32`. Amazon provides a web interface to subscribe to MQTT topics for testing:
|
||||
|
||||
* On the AWS IoT console, click "MQTT Client" near the top-right.
|
||||
* Click "Generate Client ID" to generate a random client ID.
|
||||
* Click "Connect"
|
||||
|
||||
One connection succeeds, you can subscribe to the data published by the ESP32:
|
||||
|
||||
* Click "Subscribe to Topic"
|
||||
* Enter "Subscription Topic" `test_topic/esp32`
|
||||
* Click "Subscribe"
|
||||
|
||||
... you should see MQTT data published from the running example.
|
||||
|
||||
To publish data back to the device:
|
||||
|
||||
* Click "Publish to Topic"
|
||||
* Enter "Publish Topic" `test_topic/esp32`
|
||||
* Enter a message in the payload field
|
||||
* Click Publish
|
@ -0,0 +1,60 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
|
||||
Can be left blank if the network has no security set.
|
||||
|
||||
config AWS_EXAMPLE_CLIENT_ID
|
||||
string "AWS IoT Client ID"
|
||||
default "myesp32"
|
||||
help
|
||||
AWS IoT Client ID for the example. Should be unique for every device.
|
||||
|
||||
choice EXAMPLE_CERT_SOURCE
|
||||
prompt "AWS IoT Certificate Source"
|
||||
default EXAMPLE_EMBEDDED_CERTS
|
||||
help
|
||||
AWS IoT requires loading of a device-specific certificate and private key,
|
||||
and a common Root CA Certificate. These can be compiled into the example
|
||||
app, or they can be loaded via the filesystem from an SD card.
|
||||
|
||||
config EXAMPLE_EMBEDDED_CERTS
|
||||
bool "Embed into app"
|
||||
config EXAMPLE_SDCARD_CERTS
|
||||
bool "Load from SD card"
|
||||
select EXAMPLE_FILESYSTEM_CERTS
|
||||
endchoice
|
||||
|
||||
# Currently this is equivalent to EXAMPLE_SDCARD_CERTS,
|
||||
# however eventually we want to support more filesystem
|
||||
# sources (SPIFFS, etc.) So this hidden config item
|
||||
# is selected whenever the item should load from filesystem.
|
||||
config EXAMPLE_FILESYSTEM_CERTS
|
||||
bool
|
||||
|
||||
config EXAMPLE_CERTIFICATE_PATH
|
||||
string "Device Certificate Path"
|
||||
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||
default "/sdcard/certificate.pem.crt"
|
||||
|
||||
config EXAMPLE_PRIVATE_KEY_PATH
|
||||
string "Device Private Key Path"
|
||||
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||
default "/sdcard/private.pem.key"
|
||||
|
||||
config EXAMPLE_ROOT_CA_PATH
|
||||
string "Root CA Certificate Path"
|
||||
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||
default "/sdcard/aws-root-ca.pem"
|
||||
|
||||
endmenu
|
@ -0,0 +1,3 @@
|
||||
Copy certificate files for AWS IoT SDK example here
|
||||
|
||||
See README.md in main example directory for details.
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,22 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
|
||||
ifdef CONFIG_EXAMPLE_EMBEDDED_CERTS
|
||||
# Certificate files. certificate.pem.crt & private.pem.key must be downloaded
|
||||
# from AWS, see README for details.
|
||||
COMPONENT_EMBED_TXTFILES := certs/aws-root-ca.pem certs/certificate.pem.crt certs/private.pem.key
|
||||
|
||||
ifndef IDF_CI_BUILD
|
||||
# Print an error if the certificate/key files are missing
|
||||
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||
@echo "Missing PEM file $@. This file identifies the ESP32 to AWS for the example, see README for details."
|
||||
exit 1
|
||||
else # IDF_CI_BUILD
|
||||
# this case is for the internal Continuous Integration build which
|
||||
# compiles all examples. Add some dummy certs so the example can
|
||||
# compile (even though it won't work)
|
||||
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||
echo "Dummy certificate data for continuous integration" > $@
|
||||
endif
|
||||
endif
|
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* 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 subscribe_publish_sample.c
|
||||
* @brief simple MQTT publish and subscribe on the same topic
|
||||
*
|
||||
* This example takes the parameters from the build configuration and establishes a connection to the AWS IoT MQTT Platform.
|
||||
* It subscribes and publishes to the same topic - "test_topic/esp32"
|
||||
*
|
||||
* Some setup is required. See example README for details.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event_loop.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "aws_iot_config.h"
|
||||
#include "aws_iot_log.h"
|
||||
#include "aws_iot_version.h"
|
||||
#include "aws_iot_mqtt_client_interface.h"
|
||||
|
||||
static const char *TAG = "subpub";
|
||||
|
||||
/* The examples use simple WiFi configuration that you can set via
|
||||
'make menuconfig'.
|
||||
|
||||
If you'd rather not, just change the below entries to strings with
|
||||
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
|
||||
*/
|
||||
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
|
||||
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event,
|
||||
but we only care about one event - are we connected
|
||||
to the AP with an IP? */
|
||||
const int CONNECTED_BIT = BIT0;
|
||||
|
||||
|
||||
/* CA Root certificate, device ("Thing") certificate and device
|
||||
* ("Thing") key.
|
||||
|
||||
Example can be configured one of two ways:
|
||||
|
||||
"Embedded Certs" are loaded from files in "certs/" and embedded into the app binary.
|
||||
|
||||
"Filesystem Certs" are loaded from the filesystem (SD card, etc.)
|
||||
|
||||
See example README for more details.
|
||||
*/
|
||||
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||
|
||||
extern const uint8_t aws_root_ca_pem_start[] asm("_binary_aws_root_ca_pem_start");
|
||||
extern const uint8_t aws_root_ca_pem_end[] asm("_binary_aws_root_ca_pem_end");
|
||||
extern const uint8_t certificate_pem_crt_start[] asm("_binary_certificate_pem_crt_start");
|
||||
extern const uint8_t certificate_pem_crt_end[] asm("_binary_certificate_pem_crt_end");
|
||||
extern const uint8_t private_pem_key_start[] asm("_binary_private_pem_key_start");
|
||||
extern const uint8_t private_pem_key_end[] asm("_binary_private_pem_key_end");
|
||||
|
||||
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||
|
||||
static const char * DEVICE_CERTIFICATE_PATH = CONFIG_EXAMPLE_CERTIFICATE_PATH;
|
||||
static const char * DEVICE_PRIVATE_KEY_PATH = CONFIG_EXAMPLE_PRIVATE_KEY_PATH;
|
||||
static const char * ROOT_CA_PATH = CONFIG_EXAMPLE_ROOT_CA_PATH;
|
||||
|
||||
#else
|
||||
#error "Invalid method for loading certs"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default MQTT HOST URL is pulled from the aws_iot_config.h
|
||||
*/
|
||||
char HostAddress[255] = AWS_IOT_MQTT_HOST;
|
||||
|
||||
/**
|
||||
* @brief Default MQTT port is pulled from the aws_iot_config.h
|
||||
*/
|
||||
uint32_t port = AWS_IOT_MQTT_PORT;
|
||||
|
||||
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||
{
|
||||
switch(event->event_id) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
esp_wifi_connect();
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
/* This is a workaround as ESP32 WiFi libs don't currently
|
||||
auto-reassociate. */
|
||||
esp_wifi_connect();
|
||||
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
|
||||
IoT_Publish_Message_Params *params, void *pData) {
|
||||
ESP_LOGI(TAG, "Subscribe callback");
|
||||
ESP_LOGI(TAG, "%.*s\t%.*s", topicNameLen, topicName, (int) params->payloadLen, (char *)params->payload);
|
||||
}
|
||||
|
||||
void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
|
||||
ESP_LOGW(TAG, "MQTT Disconnect");
|
||||
IoT_Error_t rc = FAILURE;
|
||||
|
||||
if(NULL == pClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(aws_iot_is_autoreconnect_enabled(pClient)) {
|
||||
ESP_LOGI(TAG, "Auto Reconnect is enabled, Reconnecting attempt will start now");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Auto Reconnect not enabled. Starting manual reconnect...");
|
||||
rc = aws_iot_mqtt_attempt_reconnect(pClient);
|
||||
if(NETWORK_RECONNECTED == rc) {
|
||||
ESP_LOGW(TAG, "Manual Reconnect Successful");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Manual Reconnect Failed - %d", rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void aws_iot_task(void *param) {
|
||||
char cPayload[100];
|
||||
|
||||
int32_t i = 0;
|
||||
|
||||
IoT_Error_t rc = FAILURE;
|
||||
|
||||
AWS_IoT_Client client;
|
||||
IoT_Client_Init_Params mqttInitParams = iotClientInitParamsDefault;
|
||||
IoT_Client_Connect_Params connectParams = iotClientConnectParamsDefault;
|
||||
|
||||
IoT_Publish_Message_Params paramsQOS0;
|
||||
IoT_Publish_Message_Params paramsQOS1;
|
||||
|
||||
ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
|
||||
|
||||
mqttInitParams.enableAutoReconnect = false; // We enable this later below
|
||||
mqttInitParams.pHostURL = HostAddress;
|
||||
mqttInitParams.port = port;
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||
mqttInitParams.pRootCALocation = (const char *)aws_root_ca_pem_start;
|
||||
mqttInitParams.pDeviceCertLocation = (const char *)certificate_pem_crt_start;
|
||||
mqttInitParams.pDevicePrivateKeyLocation = (const char *)private_pem_key_start;
|
||||
|
||||
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||
mqttInitParams.pRootCALocation = ROOT_CA_PATH;
|
||||
mqttInitParams.pDeviceCertLocation = DEVICE_CERTIFICATE_PATH;
|
||||
mqttInitParams.pDevicePrivateKeyLocation = DEVICE_PRIVATE_KEY_PATH;
|
||||
#endif
|
||||
|
||||
mqttInitParams.mqttCommandTimeout_ms = 20000;
|
||||
mqttInitParams.tlsHandshakeTimeout_ms = 5000;
|
||||
mqttInitParams.isSSLHostnameVerify = true;
|
||||
mqttInitParams.disconnectHandler = disconnectCallbackHandler;
|
||||
mqttInitParams.disconnectHandlerData = NULL;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_SDCARD_CERTS
|
||||
ESP_LOGI(TAG, "Mounting SD card...");
|
||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||
.format_if_mount_failed = false,
|
||||
.max_files = 3,
|
||||
};
|
||||
sdmmc_card_t* card;
|
||||
esp_err_t ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mount SD card VFAT filesystem. Error: %s", esp_err_to_name(ret));
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = aws_iot_mqtt_init(&client, &mqttInitParams);
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "aws_iot_mqtt_init returned error : %d ", rc);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Wait for WiFI to show as connected */
|
||||
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||
false, true, portMAX_DELAY);
|
||||
|
||||
connectParams.keepAliveIntervalInSec = 10;
|
||||
connectParams.isCleanSession = true;
|
||||
connectParams.MQTTVersion = MQTT_3_1_1;
|
||||
/* Client ID is set in the menuconfig of the example */
|
||||
connectParams.pClientID = CONFIG_AWS_EXAMPLE_CLIENT_ID;
|
||||
connectParams.clientIDLen = (uint16_t) strlen(CONFIG_AWS_EXAMPLE_CLIENT_ID);
|
||||
connectParams.isWillMsgPresent = false;
|
||||
|
||||
ESP_LOGI(TAG, "Connecting to AWS...");
|
||||
do {
|
||||
rc = aws_iot_mqtt_connect(&client, &connectParams);
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "Error(%d) connecting to %s:%d", rc, mqttInitParams.pHostURL, mqttInitParams.port);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
}
|
||||
} while(SUCCESS != 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_mqtt_autoreconnect_set_status(&client, true);
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d", rc);
|
||||
abort();
|
||||
}
|
||||
|
||||
const char *TOPIC = "test_topic/esp32";
|
||||
const int TOPIC_LEN = strlen(TOPIC);
|
||||
|
||||
ESP_LOGI(TAG, "Subscribing...");
|
||||
rc = aws_iot_mqtt_subscribe(&client, TOPIC, TOPIC_LEN, QOS0, iot_subscribe_callback_handler, NULL);
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "Error subscribing : %d ", rc);
|
||||
abort();
|
||||
}
|
||||
|
||||
sprintf(cPayload, "%s : %d ", "hello from SDK", i);
|
||||
|
||||
paramsQOS0.qos = QOS0;
|
||||
paramsQOS0.payload = (void *) cPayload;
|
||||
paramsQOS0.isRetained = 0;
|
||||
|
||||
paramsQOS1.qos = QOS1;
|
||||
paramsQOS1.payload = (void *) cPayload;
|
||||
paramsQOS1.isRetained = 0;
|
||||
|
||||
while((NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc)) {
|
||||
|
||||
//Max time the yield function will wait for read messages
|
||||
rc = aws_iot_mqtt_yield(&client, 100);
|
||||
if(NETWORK_ATTEMPTING_RECONNECT == rc) {
|
||||
// If the client is attempting to reconnect we will skip the rest of the loop.
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Stack remaining for task '%s' is %d bytes", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL));
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
sprintf(cPayload, "%s : %d ", "hello from ESP32 (QOS0)", i++);
|
||||
paramsQOS0.payloadLen = strlen(cPayload);
|
||||
rc = aws_iot_mqtt_publish(&client, TOPIC, TOPIC_LEN, ¶msQOS0);
|
||||
|
||||
sprintf(cPayload, "%s : %d ", "hello from ESP32 (QOS1)", i++);
|
||||
paramsQOS1.payloadLen = strlen(cPayload);
|
||||
rc = aws_iot_mqtt_publish(&client, TOPIC, TOPIC_LEN, ¶msQOS1);
|
||||
if (rc == MQTT_REQUEST_TIMEOUT_ERROR) {
|
||||
ESP_LOGW(TAG, "QOS1 publish ack not received.");
|
||||
rc = SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "An error occurred in the main loop.");
|
||||
abort();
|
||||
}
|
||||
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
tcpip_adapter_init();
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = EXAMPLE_WIFI_SSID,
|
||||
.password = EXAMPLE_WIFI_PASS,
|
||||
},
|
||||
};
|
||||
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
|
||||
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||
}
|
||||
|
||||
|
||||
void app_main()
|
||||
{
|
||||
// Initialize NVS.
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( err );
|
||||
|
||||
initialise_wifi();
|
||||
xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", 9216, NULL, 5, NULL, 1);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
# Enable AWS IoT SDK support
|
||||
CONFIG_AWS_IOT_SDK=y
|
||||
|
||||
# Enable FATFS read only with long filename support
|
||||
# for loading Cert/CA/etc from filesystem
|
||||
# (if enabled in config)
|
||||
CONFIG_FATFS_READONLY=y
|
||||
CONFIG_FATFS_CODEPAGE_437=y
|
||||
CONFIG_FATFS_LFN_HEAP=y
|
9
examples/protocols/aws_iot/thing_shadow/Makefile
Normal file
9
examples/protocols/aws_iot/thing_shadow/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := aws_iot_thing_shadow
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
34
examples/protocols/aws_iot/thing_shadow/README.md
Normal file
34
examples/protocols/aws_iot/thing_shadow/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Amazon Web Services IoT Thing Shadow Example
|
||||
|
||||
This is an adaptation of the [AWS IoT C SDK](https://github.com/aws/aws-iot-device-sdk-embedded-C) "shadow_sample" example for ESP-IDF.
|
||||
|
||||
# Provisioning/Configuration
|
||||
|
||||
See the README.md in the parent directory for information about configuring the AWS IoT examples.
|
||||
|
||||
After following those steps, there is one additional step for this exmaple:
|
||||
|
||||
## Set Thing Name
|
||||
|
||||
For this example, you will need to set a Thing Name under `make menuconfig` -> `Example Configuration` -> `AWS IoT Thing Name`.
|
||||
|
||||
The Thing Name should match a Thing that you created while following the Getting Started guide (to check the Things you have registered, go t othe AWS IoT console web interface, click Registry and then click Things).
|
||||
|
||||
# Monitoring Thing Status
|
||||
|
||||
After flashing the example to your ESP32, it should connect to Amazon and start updating the example Thing's shadow.
|
||||
|
||||
In the ESP32's serial output, you should see the message "Update accepted" logged every couple of seconds.
|
||||
|
||||
You can monitor the Thing status from the AWS IoT console web interface:
|
||||
|
||||
* On the left-hand toolbar, click Registry and then click Things.
|
||||
* Click on the "Thing" you set up for the example.
|
||||
* Click on the "Shadow" sidebar link. You should see the Thing Shadow updating regularly.
|
||||
* Click on the "Activity" sidebar link to see all Thing Shadow updates in a list. You can examine each update individually.
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
If you're having problems with the AWS IoT connection itself, check the Troubleshooting section of the README in the parent directory.
|
||||
|
||||
* If your Thing is connecting and appears to be successfully updating, but you don't see any updates in the AWS IoT console, then check that the Thing Name in the Example Configuration under menuconfig matches exactly the thing name in AWS IoT console (including case).
|
@ -0,0 +1,66 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
|
||||
Can be left blank if the network has no security set.
|
||||
|
||||
config AWS_EXAMPLE_CLIENT_ID
|
||||
string "AWS IoT Client ID"
|
||||
default "myesp32"
|
||||
help
|
||||
AWS IoT Client ID for the example. Should be unique for every device.
|
||||
|
||||
config AWS_EXAMPLE_THING_NAME
|
||||
string "AWS IoT Thing Name"
|
||||
default "myesp32"
|
||||
help
|
||||
AWS IoT Thing Name for the example. Should be unique for every device.
|
||||
|
||||
choice EXAMPLE_CERT_SOURCE
|
||||
prompt "AWS IoT Certificate Source"
|
||||
default EXAMPLE_EMBEDDED_CERTS
|
||||
help
|
||||
AWS IoT requires loading of a device-specific certificate and private key,
|
||||
and a common Root CA Certificate. These can be compiled into the example
|
||||
app, or they can be loaded via the filesystem from an SD card.
|
||||
|
||||
config EXAMPLE_EMBEDDED_CERTS
|
||||
bool "Embed into app"
|
||||
config EXAMPLE_SDCARD_CERTS
|
||||
bool "Load from SD card"
|
||||
select EXAMPLE_FILESYSTEM_CERTS
|
||||
endchoice
|
||||
|
||||
# Currently this is equivalent to EXAMPLE_SDCARD_CERTS,
|
||||
# however eventually we want to support more filesystem
|
||||
# sources (SPIFFS, etc.) So this hidden config item
|
||||
# is selected whenever the item should load from filesystem.
|
||||
config EXAMPLE_FILESYSTEM_CERTS
|
||||
bool
|
||||
|
||||
config EXAMPLE_CERTIFICATE_PATH
|
||||
string "Device Certificate Path"
|
||||
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||
default "/sdcard/certificate.pem.crt"
|
||||
|
||||
config EXAMPLE_PRIVATE_KEY_PATH
|
||||
string "Device Private Key Path"
|
||||
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||
default "/sdcard/private.pem.key"
|
||||
|
||||
config EXAMPLE_ROOT_CA_PATH
|
||||
string "Root CA Certificate Path"
|
||||
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||
default "/sdcard/aws-root-ca.pem"
|
||||
|
||||
endmenu
|
@ -0,0 +1,3 @@
|
||||
Copy certificate files for AWS IoT SDK example here
|
||||
|
||||
See README.md in main example directory for details.
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||
-----END CERTIFICATE-----
|
22
examples/protocols/aws_iot/thing_shadow/main/component.mk
Normal file
22
examples/protocols/aws_iot/thing_shadow/main/component.mk
Normal file
@ -0,0 +1,22 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
|
||||
ifdef CONFIG_EXAMPLE_EMBEDDED_CERTS
|
||||
# Certificate files. certificate.pem.crt & private.pem.key must be downloaded
|
||||
# from AWS, see README for details.
|
||||
COMPONENT_EMBED_TXTFILES := certs/aws-root-ca.pem certs/certificate.pem.crt certs/private.pem.key
|
||||
|
||||
ifndef IDF_CI_BUILD
|
||||
# Print an error if the certificate/key files are missing
|
||||
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||
@echo "Missing PEM file $@. This file identifies the ESP32 to AWS for the example, see README for details."
|
||||
exit 1
|
||||
else # IDF_CI_BUILD
|
||||
# this case is for the internal Continuous Integration build which
|
||||
# compiles all examples. Add some dummy certs so the example can
|
||||
# compile (even though it won't work)
|
||||
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||
echo "Dummy certificate data for continuous integration" > $@
|
||||
endif
|
||||
endif
|
@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
*
|
||||
* 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 thing_shadow_sample.c
|
||||
* @brief A simple connected window example demonstrating the use of Thing Shadow
|
||||
*
|
||||
* See example README for more details.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event_loop.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.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
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static const char *TAG = "shadow";
|
||||
|
||||
#define ROOMTEMPERATURE_UPPERLIMIT 32.0f
|
||||
#define ROOMTEMPERATURE_LOWERLIMIT 25.0f
|
||||
#define STARTING_ROOMTEMPERATURE ROOMTEMPERATURE_LOWERLIMIT
|
||||
|
||||
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
|
||||
|
||||
/* The examples use simple WiFi configuration that you can set via
|
||||
'make menuconfig'.
|
||||
|
||||
If you'd rather not, just change the below entries to strings with
|
||||
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
|
||||
*/
|
||||
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
|
||||
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
|
||||
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event,
|
||||
but we only care about one event - are we connected
|
||||
to the AP with an IP? */
|
||||
const int CONNECTED_BIT = BIT0;
|
||||
|
||||
|
||||
/* CA Root certificate, device ("Thing") certificate and device
|
||||
* ("Thing") key.
|
||||
|
||||
Example can be configured one of two ways:
|
||||
|
||||
"Embedded Certs" are loaded from files in "certs/" and embedded into the app binary.
|
||||
|
||||
"Filesystem Certs" are loaded from the filesystem (SD card, etc.)
|
||||
|
||||
See example README for more details.
|
||||
*/
|
||||
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||
|
||||
extern const uint8_t aws_root_ca_pem_start[] asm("_binary_aws_root_ca_pem_start");
|
||||
extern const uint8_t aws_root_ca_pem_end[] asm("_binary_aws_root_ca_pem_end");
|
||||
extern const uint8_t certificate_pem_crt_start[] asm("_binary_certificate_pem_crt_start");
|
||||
extern const uint8_t certificate_pem_crt_end[] asm("_binary_certificate_pem_crt_end");
|
||||
extern const uint8_t private_pem_key_start[] asm("_binary_private_pem_key_start");
|
||||
extern const uint8_t private_pem_key_end[] asm("_binary_private_pem_key_end");
|
||||
|
||||
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||
|
||||
static const char * DEVICE_CERTIFICATE_PATH = CONFIG_EXAMPLE_CERTIFICATE_PATH;
|
||||
static const char * DEVICE_PRIVATE_KEY_PATH = CONFIG_EXAMPLE_PRIVATE_KEY_PATH;
|
||||
static const char * ROOT_CA_PATH = CONFIG_EXAMPLE_ROOT_CA_PATH;
|
||||
|
||||
#else
|
||||
#error "Invalid method for loading certs"
|
||||
#endif
|
||||
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||
{
|
||||
switch(event->event_id) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
esp_wifi_connect();
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
/* This is a workaround as ESP32 WiFi libs don't currently
|
||||
auto-reassociate. */
|
||||
esp_wifi_connect();
|
||||
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static bool shadowUpdateInProgress;
|
||||
|
||||
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);
|
||||
|
||||
shadowUpdateInProgress = false;
|
||||
|
||||
if(SHADOW_ACK_TIMEOUT == status) {
|
||||
ESP_LOGE(TAG, "Update timed out");
|
||||
} else if(SHADOW_ACK_REJECTED == status) {
|
||||
ESP_LOGE(TAG, "Update rejected");
|
||||
} else if(SHADOW_ACK_ACCEPTED == status) {
|
||||
ESP_LOGI(TAG, "Update accepted");
|
||||
}
|
||||
}
|
||||
|
||||
void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
|
||||
IOT_UNUSED(pJsonString);
|
||||
IOT_UNUSED(JsonStringDataLen);
|
||||
|
||||
if(pContext != NULL) {
|
||||
ESP_LOGI(TAG, "Delta - Window state changed to %d", *(bool *) (pContext->pData));
|
||||
}
|
||||
}
|
||||
|
||||
void aws_iot_task(void *param) {
|
||||
IoT_Error_t rc = FAILURE;
|
||||
|
||||
char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
|
||||
size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
|
||||
float temperature = 0.0;
|
||||
|
||||
bool windowOpen = false;
|
||||
jsonStruct_t windowActuator;
|
||||
windowActuator.cb = windowActuate_Callback;
|
||||
windowActuator.pData = &windowOpen;
|
||||
windowActuator.pKey = "windowOpen";
|
||||
windowActuator.type = SHADOW_JSON_BOOL;
|
||||
|
||||
jsonStruct_t temperatureHandler;
|
||||
temperatureHandler.cb = NULL;
|
||||
temperatureHandler.pKey = "temperature";
|
||||
temperatureHandler.pData = &temperature;
|
||||
temperatureHandler.type = SHADOW_JSON_FLOAT;
|
||||
|
||||
ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
|
||||
|
||||
// initialize the mqtt client
|
||||
AWS_IoT_Client mqttClient;
|
||||
|
||||
ShadowInitParameters_t sp = ShadowInitParametersDefault;
|
||||
sp.pHost = AWS_IOT_MQTT_HOST;
|
||||
sp.port = AWS_IOT_MQTT_PORT;
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||
sp.pClientCRT = (const char *)certificate_pem_crt_start;
|
||||
sp.pClientKey = (const char *)private_pem_key_start;
|
||||
sp.pRootCA = (const char *)aws_root_ca_pem_start;
|
||||
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||
sp.pClientCRT = DEVICE_CERTIFICATE_PATH;
|
||||
sp.pClientKey = DEVICE_PRIVATE_KEY_PATH;
|
||||
sp.pRootCA = ROOT_CA_PATH;
|
||||
#endif
|
||||
sp.enableAutoReconnect = false;
|
||||
sp.disconnectHandler = NULL;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_SDCARD_CERTS
|
||||
ESP_LOGI(TAG, "Mounting SD card...");
|
||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||
.format_if_mount_failed = false,
|
||||
.max_files = 3,
|
||||
};
|
||||
sdmmc_card_t* card;
|
||||
esp_err_t ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mount SD card VFAT filesystem. Error: %s", esp_err_to_name(ret));
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wait for WiFI to show as connected */
|
||||
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||
false, true, portMAX_DELAY);
|
||||
|
||||
ESP_LOGI(TAG, "Shadow Init");
|
||||
rc = aws_iot_shadow_init(&mqttClient, &sp);
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "aws_iot_shadow_init returned error %d, aborting...", rc);
|
||||
abort();
|
||||
}
|
||||
|
||||
ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
|
||||
scp.pMyThingName = CONFIG_AWS_EXAMPLE_THING_NAME;
|
||||
scp.pMqttClientId = CONFIG_AWS_EXAMPLE_CLIENT_ID;
|
||||
scp.mqttClientIdLen = (uint16_t) strlen(CONFIG_AWS_EXAMPLE_CLIENT_ID);
|
||||
|
||||
ESP_LOGI(TAG, "Shadow Connect");
|
||||
rc = aws_iot_shadow_connect(&mqttClient, &scp);
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "aws_iot_shadow_connect returned error %d, aborting...", rc);
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d, aborting...", rc);
|
||||
abort();
|
||||
}
|
||||
|
||||
rc = aws_iot_shadow_register_delta(&mqttClient, &windowActuator);
|
||||
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "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 || shadowUpdateInProgress) {
|
||||
rc = aws_iot_shadow_yield(&mqttClient, 1000);
|
||||
// If the client is attempting to reconnect, or already waiting on a shadow update,
|
||||
// we will skip the rest of the loop.
|
||||
continue;
|
||||
}
|
||||
ESP_LOGI(TAG, "=======================================================================================");
|
||||
ESP_LOGI(TAG, "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) {
|
||||
ESP_LOGI(TAG, "Update Shadow: %s", JsonDocumentBuffer);
|
||||
rc = aws_iot_shadow_update(&mqttClient, CONFIG_AWS_EXAMPLE_THING_NAME, JsonDocumentBuffer,
|
||||
ShadowUpdateStatusCallback, NULL, 4, true);
|
||||
shadowUpdateInProgress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "*****************************************************************************************");
|
||||
ESP_LOGI(TAG, "Stack remaining for task '%s' is %d bytes", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL));
|
||||
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "An error occurred in the loop %d", rc);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Disconnecting");
|
||||
rc = aws_iot_shadow_disconnect(&mqttClient);
|
||||
|
||||
if(SUCCESS != rc) {
|
||||
ESP_LOGE(TAG, "Disconnect error %d", rc);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
tcpip_adapter_init();
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = EXAMPLE_WIFI_SSID,
|
||||
.password = EXAMPLE_WIFI_PASS,
|
||||
},
|
||||
};
|
||||
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
|
||||
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||
}
|
||||
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( err );
|
||||
|
||||
initialise_wifi();
|
||||
/* Temporarily pin task to core, due to FPU uncertainty */
|
||||
xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", 9216, NULL, 5, NULL, 1);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
# Enable AWS IoT SDK support
|
||||
CONFIG_AWS_IOT_SDK=y
|
||||
|
||||
# Enable FATFS read only with long filename support
|
||||
# for loading Cert/CA/etc from filesystem
|
||||
# (if enabled in config)
|
||||
CONFIG_FATFS_CODEPAGE_437=y
|
||||
CONFIG_FATFS_LFN_HEAP=y
|
Reference in New Issue
Block a user