This commit is contained in:
Dane Walton 2022-11-08 20:34:12 -05:00 коммит произвёл GitHub
Родитель 0caad4db6a
Коммит 7a67bacf20
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
23 изменённых файлов: 2514 добавлений и 1710 удалений

19
.clang-format Normal file
Просмотреть файл

@ -0,0 +1,19 @@
---
# We'll use defaults from the LLVM style, but with the following differences.
# This mirrors the Azure SDK for C
BasedOnStyle: LLVM
AlignAfterOpenBracket: AlwaysBreak
AlignEscapedNewlines: Left
AlignOperands: false
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Allman
ColumnLimit: 100
Cpp11BracedListStyle: false
IndentCaseLabels: true
PenaltyReturnTypeOnItsOwnLine: 300
PointerAlignment: Left
...

25
.github/workflows/main.yml поставляемый
Просмотреть файл

@ -17,6 +17,31 @@ jobs:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Fetch Needed Libs
run: |
apt install -y libncurses5
wget https://releases.llvm.org/9.0.0/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz
tar -xvf clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz
mv clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/clang-format /usr/local/bin/
- name: Style Check
run: |
# Run clang-format recursively on each source and header file within the repo.
clang-format --version
find ./examples \( -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' -o -iname '*.ino' \) -exec clang-format -i {} \;
git status --untracked-files=no --porcelain
if [[ `git status --untracked-files=no --porcelain` ]]; then
echo Some files were not formatted correctly according to the .clang-format file.
echo Please run clang-format version 9.0.0 to fix the issue by using this bash command at the root of the repo:
echo "find ./examples \( -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' -o -iname '*.ino' \) -exec clang-format -i {} \;"
exit 1
fi
echo Success, all files are formatted correctly according to the .clang-format file.
exit 0
- name: Install dependent Arduino libraries
run: |
arduino --install-library "PubSubClient",

Просмотреть файл

@ -33,6 +33,16 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
### Fix Code Formatting
Run the following command from the root of the sdk with `clang-format` version 9.0.0.
```bash
find ./examples \( -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' -o -iname '*.ino' \) -exec clang-format -i {} \;
```
Commit the resulting code formatting changes if there are any.
### Reporting Security Issues and Security Bugs
Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) <secure@microsoft.com>. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the [Security TechCenter](https://www.microsoft.com/msrc/faqs-report-an-issue).

Просмотреть файл

@ -55,7 +55,9 @@
// please follow the format '(ard;<platform>)'.
#define AZURE_SDK_CLIENT_USER_AGENT "c%2f" AZ_SDK_VERSION_STRING "(ard;esp32)"
#define ADU_UPDATE_ID "{\"provider\":\"" ADU_UPDATE_PROVIDER "\",\"name\":\"" ADU_UPDATE_NAME "\",\"version\":\"" ADU_DEVICE_VERSION "\"}"
#define ADU_UPDATE_ID \
"{\"provider\":\"" ADU_UPDATE_PROVIDER "\",\"name\":\"" ADU_UPDATE_NAME \
"\",\"version\":\"" ADU_DEVICE_VERSION "\"}"
#define SAMPLE_MQTT_TOPIC_LENGTH 128
#define SAMPLE_MQTT_PAYLOAD_LENGTH 1024
@ -138,87 +140,78 @@ static AzIoTSasToken sasToken(
/* Azure Device Update root keys used to verify the signed deployment */
/* ADU.200702.R */
static uint8_t ucAzureIoTADURootKeyId200702[ 13 ] = "ADU.200702.R";
static uint8_t ucAzureIoTADURootKeyN200702[ 385 ]
=
{
0x00, 0xd5, 0x42, 0x2e, 0xaf, 0x11, 0x54, 0xa3, 0x50, 0x65, 0x87, 0xa2, 0x4d, 0x5b, 0xba,
0x1a, 0xfb, 0xa9, 0x32, 0xdf, 0xe9, 0x99, 0x5f, 0x05, 0x45, 0xc8, 0xaf, 0xbd, 0x35, 0x1d,
0x89, 0xe8, 0x27, 0x27, 0x58, 0xa3, 0xa8, 0xee, 0xc5, 0xc5, 0x1e, 0x4f, 0xf7, 0x92, 0xa6,
0x12, 0x06, 0x7d, 0x3d, 0x7d, 0xb0, 0x07, 0xf6, 0x2c, 0x7f, 0xde, 0x6d, 0x2a, 0xf5, 0xbc,
0x49, 0xbc, 0x15, 0xef, 0xf0, 0x81, 0xcb, 0x3f, 0x88, 0x4f, 0x27, 0x1d, 0x88, 0x71, 0x28,
0x60, 0x08, 0xb6, 0x19, 0xd2, 0xd2, 0x39, 0xd0, 0x05, 0x1f, 0x3c, 0x76, 0x86, 0x71, 0xbb,
0x59, 0x58, 0xbc, 0xb1, 0x88, 0x7b, 0xab, 0x56, 0x28, 0xbf, 0x31, 0x73, 0x44, 0x32, 0x10,
0xfd, 0x3d, 0xd3, 0x96, 0x5c, 0xff, 0x4e, 0x5c, 0xb3, 0x6b, 0xff, 0x8b, 0x84, 0x9b, 0x8b,
0x80, 0xb8, 0x49, 0xd0, 0x7d, 0xfa, 0xd6, 0x40, 0x58, 0x76, 0x4d, 0xc0, 0x72, 0x27, 0x75,
0xcb, 0x9a, 0x2f, 0x9b, 0xb4, 0x9f, 0x0f, 0x25, 0xf1, 0x1c, 0xc5, 0x1b, 0x0b, 0x5a, 0x30,
0x7d, 0x2f, 0xb8, 0xef, 0xa7, 0x26, 0x58, 0x53, 0xaf, 0xd5, 0x1d, 0x55, 0x01, 0x51, 0x0d,
0xe9, 0x1b, 0xa2, 0x0f, 0x3f, 0xd7, 0xe9, 0x1d, 0x20, 0x41, 0xa6, 0xe6, 0x14, 0x0a, 0xae,
0xfe, 0xf2, 0x1c, 0x2a, 0xd6, 0xe4, 0x04, 0x7b, 0xf6, 0x14, 0x7e, 0xec, 0x0f, 0x97, 0x83,
0xfa, 0x58, 0xfa, 0x81, 0x36, 0x21, 0xb9, 0xa3, 0x2b, 0xfa, 0xd9, 0x61, 0x0b, 0x1a, 0x94,
0xf7, 0xc1, 0xbe, 0x7f, 0x40, 0x14, 0x4a, 0xc9, 0xfa, 0x35, 0x7f, 0xef, 0x66, 0x70, 0x00,
0xb1, 0xfd, 0xdb, 0xd7, 0x61, 0x0d, 0x3b, 0x58, 0x74, 0x67, 0x94, 0x89, 0x75, 0x76, 0x96,
0x7c, 0x91, 0x87, 0xd2, 0x8e, 0x11, 0x97, 0xee, 0x7b, 0x87, 0x6c, 0x9a, 0x2f, 0x45, 0xd8,
0x65, 0x3f, 0x52, 0x70, 0x98, 0x2a, 0xcb, 0xc8, 0x04, 0x63, 0xf5, 0xc9, 0x47, 0xcf, 0x70,
0xf4, 0xed, 0x64, 0xa7, 0x74, 0xa5, 0x23, 0x8f, 0xb6, 0xed, 0xf7, 0x1c, 0xd3, 0xb0, 0x1c,
0x64, 0x57, 0x12, 0x5a, 0xa9, 0x81, 0x84, 0x1f, 0xa0, 0xe7, 0x50, 0x19, 0x96, 0xb4, 0x82,
0xb1, 0xac, 0x48, 0xe3, 0xe1, 0x32, 0x82, 0xcb, 0x40, 0x1f, 0xac, 0xc4, 0x59, 0xbc, 0x10,
0x34, 0x51, 0x82, 0xf9, 0x28, 0x8d, 0xa8, 0x1e, 0x9b, 0xf5, 0x79, 0x45, 0x75, 0xb2, 0xdc,
0x9a, 0x11, 0x43, 0x08, 0xbe, 0x61, 0xcc, 0x9a, 0xc4, 0xcb, 0x77, 0x36, 0xff, 0x83, 0xdd,
0xa8, 0x71, 0x4f, 0x51, 0x8e, 0x0e, 0x7b, 0x4d, 0xfa, 0x79, 0x98, 0x8d, 0xbe, 0xfc, 0x82,
0x7e, 0x40, 0x48, 0xa9, 0x12, 0x01, 0xa8, 0xd9, 0x7e, 0xf3, 0xa5, 0x1b, 0xf1, 0xfb, 0x90,
0x77, 0x3e, 0x40, 0x87, 0x18, 0xc9, 0xab, 0xd9, 0xf7, 0x79
};
static uint8_t ucAzureIoTADURootKeyE200702[ 3 ] = { 0x01, 0x00, 0x01 };
static uint8_t ucAzureIoTADURootKeyId200702[13] = "ADU.200702.R";
static uint8_t ucAzureIoTADURootKeyN200702[385]
= { 0x00, 0xd5, 0x42, 0x2e, 0xaf, 0x11, 0x54, 0xa3, 0x50, 0x65, 0x87, 0xa2, 0x4d, 0x5b, 0xba,
0x1a, 0xfb, 0xa9, 0x32, 0xdf, 0xe9, 0x99, 0x5f, 0x05, 0x45, 0xc8, 0xaf, 0xbd, 0x35, 0x1d,
0x89, 0xe8, 0x27, 0x27, 0x58, 0xa3, 0xa8, 0xee, 0xc5, 0xc5, 0x1e, 0x4f, 0xf7, 0x92, 0xa6,
0x12, 0x06, 0x7d, 0x3d, 0x7d, 0xb0, 0x07, 0xf6, 0x2c, 0x7f, 0xde, 0x6d, 0x2a, 0xf5, 0xbc,
0x49, 0xbc, 0x15, 0xef, 0xf0, 0x81, 0xcb, 0x3f, 0x88, 0x4f, 0x27, 0x1d, 0x88, 0x71, 0x28,
0x60, 0x08, 0xb6, 0x19, 0xd2, 0xd2, 0x39, 0xd0, 0x05, 0x1f, 0x3c, 0x76, 0x86, 0x71, 0xbb,
0x59, 0x58, 0xbc, 0xb1, 0x88, 0x7b, 0xab, 0x56, 0x28, 0xbf, 0x31, 0x73, 0x44, 0x32, 0x10,
0xfd, 0x3d, 0xd3, 0x96, 0x5c, 0xff, 0x4e, 0x5c, 0xb3, 0x6b, 0xff, 0x8b, 0x84, 0x9b, 0x8b,
0x80, 0xb8, 0x49, 0xd0, 0x7d, 0xfa, 0xd6, 0x40, 0x58, 0x76, 0x4d, 0xc0, 0x72, 0x27, 0x75,
0xcb, 0x9a, 0x2f, 0x9b, 0xb4, 0x9f, 0x0f, 0x25, 0xf1, 0x1c, 0xc5, 0x1b, 0x0b, 0x5a, 0x30,
0x7d, 0x2f, 0xb8, 0xef, 0xa7, 0x26, 0x58, 0x53, 0xaf, 0xd5, 0x1d, 0x55, 0x01, 0x51, 0x0d,
0xe9, 0x1b, 0xa2, 0x0f, 0x3f, 0xd7, 0xe9, 0x1d, 0x20, 0x41, 0xa6, 0xe6, 0x14, 0x0a, 0xae,
0xfe, 0xf2, 0x1c, 0x2a, 0xd6, 0xe4, 0x04, 0x7b, 0xf6, 0x14, 0x7e, 0xec, 0x0f, 0x97, 0x83,
0xfa, 0x58, 0xfa, 0x81, 0x36, 0x21, 0xb9, 0xa3, 0x2b, 0xfa, 0xd9, 0x61, 0x0b, 0x1a, 0x94,
0xf7, 0xc1, 0xbe, 0x7f, 0x40, 0x14, 0x4a, 0xc9, 0xfa, 0x35, 0x7f, 0xef, 0x66, 0x70, 0x00,
0xb1, 0xfd, 0xdb, 0xd7, 0x61, 0x0d, 0x3b, 0x58, 0x74, 0x67, 0x94, 0x89, 0x75, 0x76, 0x96,
0x7c, 0x91, 0x87, 0xd2, 0x8e, 0x11, 0x97, 0xee, 0x7b, 0x87, 0x6c, 0x9a, 0x2f, 0x45, 0xd8,
0x65, 0x3f, 0x52, 0x70, 0x98, 0x2a, 0xcb, 0xc8, 0x04, 0x63, 0xf5, 0xc9, 0x47, 0xcf, 0x70,
0xf4, 0xed, 0x64, 0xa7, 0x74, 0xa5, 0x23, 0x8f, 0xb6, 0xed, 0xf7, 0x1c, 0xd3, 0xb0, 0x1c,
0x64, 0x57, 0x12, 0x5a, 0xa9, 0x81, 0x84, 0x1f, 0xa0, 0xe7, 0x50, 0x19, 0x96, 0xb4, 0x82,
0xb1, 0xac, 0x48, 0xe3, 0xe1, 0x32, 0x82, 0xcb, 0x40, 0x1f, 0xac, 0xc4, 0x59, 0xbc, 0x10,
0x34, 0x51, 0x82, 0xf9, 0x28, 0x8d, 0xa8, 0x1e, 0x9b, 0xf5, 0x79, 0x45, 0x75, 0xb2, 0xdc,
0x9a, 0x11, 0x43, 0x08, 0xbe, 0x61, 0xcc, 0x9a, 0xc4, 0xcb, 0x77, 0x36, 0xff, 0x83, 0xdd,
0xa8, 0x71, 0x4f, 0x51, 0x8e, 0x0e, 0x7b, 0x4d, 0xfa, 0x79, 0x98, 0x8d, 0xbe, 0xfc, 0x82,
0x7e, 0x40, 0x48, 0xa9, 0x12, 0x01, 0xa8, 0xd9, 0x7e, 0xf3, 0xa5, 0x1b, 0xf1, 0xfb, 0x90,
0x77, 0x3e, 0x40, 0x87, 0x18, 0xc9, 0xab, 0xd9, 0xf7, 0x79 };
static uint8_t ucAzureIoTADURootKeyE200702[3] = { 0x01, 0x00, 0x01 };
/* ADU.200703.R */
static uint8_t ucAzureIoTADURootKeyId200703[ 13 ] = "ADU.200703.R";
static uint8_t ucAzureIoTADURootKeyN200703[ 385 ] =
{
0x00, 0xb2, 0xa3, 0xb2, 0x74, 0x16, 0xfa, 0xbb, 0x20, 0xf9, 0x52, 0x76, 0xe6, 0x27, 0x3e,
0x80, 0x41, 0xc6, 0xfe, 0xcf, 0x30, 0xf9, 0xc8, 0x96, 0xf5, 0x59, 0x0a, 0xaa, 0x81, 0xe7,
0x51, 0x83, 0x8a, 0xc4, 0xf5, 0x17, 0x3a, 0x2f, 0x2a, 0xe6, 0x57, 0xd4, 0x71, 0xce, 0x8a,
0x3d, 0xef, 0x9a, 0x55, 0x76, 0x3e, 0x99, 0xe2, 0xc2, 0xae, 0x4c, 0xee, 0x2d, 0xb8, 0x78,
0xf5, 0xa2, 0x4e, 0x28, 0xf2, 0x9c, 0x4e, 0x39, 0x65, 0xbc, 0xec, 0xe4, 0x0d, 0xe5, 0xe3,
0x38, 0xa8, 0x59, 0xab, 0x08, 0xa4, 0x1b, 0xb4, 0xf4, 0xa0, 0x52, 0xa3, 0x38, 0xb3, 0x46,
0x21, 0x13, 0xcc, 0x3c, 0x68, 0x06, 0xde, 0xfe, 0x00, 0xa6, 0x92, 0x6e, 0xde, 0x4c, 0x47,
0x10, 0xd6, 0x1c, 0x9c, 0x24, 0xf5, 0xcd, 0x70, 0xe1, 0xf5, 0x6a, 0x7c, 0x68, 0x13, 0x1d,
0xe1, 0xc5, 0xf6, 0xa8, 0x4f, 0x21, 0x9f, 0x86, 0x7c, 0x44, 0xc5, 0x8a, 0x99, 0x1c, 0xc5,
0xd3, 0x06, 0x9b, 0x5a, 0x71, 0x9d, 0x09, 0x1c, 0xc3, 0x64, 0x31, 0x6a, 0xc5, 0x17, 0x95,
0x1d, 0x5d, 0x2a, 0xf1, 0x55, 0xc7, 0x66, 0xd4, 0xe8, 0xf5, 0xd9, 0xa9, 0x5b, 0x8c, 0xa2,
0x6c, 0x62, 0x60, 0x05, 0x37, 0xd7, 0x32, 0xb0, 0x73, 0xcb, 0xf7, 0x4b, 0x36, 0x27, 0x24,
0x21, 0x8c, 0x38, 0x0a, 0xb8, 0x18, 0xfe, 0xf5, 0x15, 0x60, 0x35, 0x8b, 0x35, 0xef, 0x1e,
0x0f, 0x88, 0xa6, 0x13, 0x8d, 0x7b, 0x7d, 0xef, 0xb3, 0xe7, 0xb0, 0xc9, 0xa6, 0x1c, 0x70,
0x7b, 0xcc, 0xf2, 0x29, 0x8b, 0x87, 0xf7, 0xbd, 0x9d, 0xb6, 0x88, 0x6f, 0xac, 0x73, 0xff,
0x72, 0xf2, 0xef, 0x48, 0x27, 0x96, 0x72, 0x86, 0x06, 0xa2, 0x5c, 0xe3, 0x7d, 0xce, 0xb0,
0x9e, 0xe5, 0xc2, 0xd9, 0x4e, 0xc4, 0xf3, 0x7f, 0x78, 0x07, 0x4b, 0x65, 0x88, 0x45, 0x0c,
0x11, 0xe5, 0x96, 0x56, 0x34, 0x88, 0x2d, 0x16, 0x0e, 0x59, 0x42, 0xd2, 0xf7, 0xd9, 0xed,
0x1d, 0xed, 0xc9, 0x37, 0x77, 0x44, 0x7e, 0xe3, 0x84, 0x36, 0x9f, 0x58, 0x13, 0xef, 0x6f,
0xe4, 0xc3, 0x44, 0xd4, 0x77, 0x06, 0x8a, 0xcf, 0x5b, 0xc8, 0x80, 0x1c, 0xa2, 0x98, 0x65,
0x0b, 0x35, 0xdc, 0x73, 0xc8, 0x69, 0xd0, 0x5e, 0xe8, 0x25, 0x43, 0x9e, 0xf6, 0xd8, 0xab,
0x05, 0xaf, 0x51, 0x29, 0x23, 0x55, 0x40, 0x58, 0x10, 0xea, 0xb8, 0xe2, 0xcd, 0x5d, 0x79,
0xcc, 0xec, 0xdf, 0xb4, 0x5b, 0x98, 0xc7, 0xfa, 0xe3, 0xd2, 0x6c, 0x26, 0xce, 0x2e, 0x2c,
0x56, 0xe0, 0xcf, 0x8d, 0xee, 0xfd, 0x93, 0x12, 0x2f, 0x00, 0x49, 0x8d, 0x1c, 0x82, 0x38,
0x56, 0xa6, 0x5d, 0x79, 0x44, 0x4a, 0x1a, 0xf3, 0xdc, 0x16, 0x10, 0xb3, 0xc1, 0x2d, 0x27,
0x11, 0xfe, 0x1b, 0x98, 0x05, 0xe4, 0xa3, 0x60, 0x31, 0x99
};
static uint8_t ucAzureIoTADURootKeyE200703[ 3 ] = { 0x01, 0x00, 0x01 };
static uint8_t ucAzureIoTADURootKeyId200703[13] = "ADU.200703.R";
static uint8_t ucAzureIoTADURootKeyN200703[385]
= { 0x00, 0xb2, 0xa3, 0xb2, 0x74, 0x16, 0xfa, 0xbb, 0x20, 0xf9, 0x52, 0x76, 0xe6, 0x27, 0x3e,
0x80, 0x41, 0xc6, 0xfe, 0xcf, 0x30, 0xf9, 0xc8, 0x96, 0xf5, 0x59, 0x0a, 0xaa, 0x81, 0xe7,
0x51, 0x83, 0x8a, 0xc4, 0xf5, 0x17, 0x3a, 0x2f, 0x2a, 0xe6, 0x57, 0xd4, 0x71, 0xce, 0x8a,
0x3d, 0xef, 0x9a, 0x55, 0x76, 0x3e, 0x99, 0xe2, 0xc2, 0xae, 0x4c, 0xee, 0x2d, 0xb8, 0x78,
0xf5, 0xa2, 0x4e, 0x28, 0xf2, 0x9c, 0x4e, 0x39, 0x65, 0xbc, 0xec, 0xe4, 0x0d, 0xe5, 0xe3,
0x38, 0xa8, 0x59, 0xab, 0x08, 0xa4, 0x1b, 0xb4, 0xf4, 0xa0, 0x52, 0xa3, 0x38, 0xb3, 0x46,
0x21, 0x13, 0xcc, 0x3c, 0x68, 0x06, 0xde, 0xfe, 0x00, 0xa6, 0x92, 0x6e, 0xde, 0x4c, 0x47,
0x10, 0xd6, 0x1c, 0x9c, 0x24, 0xf5, 0xcd, 0x70, 0xe1, 0xf5, 0x6a, 0x7c, 0x68, 0x13, 0x1d,
0xe1, 0xc5, 0xf6, 0xa8, 0x4f, 0x21, 0x9f, 0x86, 0x7c, 0x44, 0xc5, 0x8a, 0x99, 0x1c, 0xc5,
0xd3, 0x06, 0x9b, 0x5a, 0x71, 0x9d, 0x09, 0x1c, 0xc3, 0x64, 0x31, 0x6a, 0xc5, 0x17, 0x95,
0x1d, 0x5d, 0x2a, 0xf1, 0x55, 0xc7, 0x66, 0xd4, 0xe8, 0xf5, 0xd9, 0xa9, 0x5b, 0x8c, 0xa2,
0x6c, 0x62, 0x60, 0x05, 0x37, 0xd7, 0x32, 0xb0, 0x73, 0xcb, 0xf7, 0x4b, 0x36, 0x27, 0x24,
0x21, 0x8c, 0x38, 0x0a, 0xb8, 0x18, 0xfe, 0xf5, 0x15, 0x60, 0x35, 0x8b, 0x35, 0xef, 0x1e,
0x0f, 0x88, 0xa6, 0x13, 0x8d, 0x7b, 0x7d, 0xef, 0xb3, 0xe7, 0xb0, 0xc9, 0xa6, 0x1c, 0x70,
0x7b, 0xcc, 0xf2, 0x29, 0x8b, 0x87, 0xf7, 0xbd, 0x9d, 0xb6, 0x88, 0x6f, 0xac, 0x73, 0xff,
0x72, 0xf2, 0xef, 0x48, 0x27, 0x96, 0x72, 0x86, 0x06, 0xa2, 0x5c, 0xe3, 0x7d, 0xce, 0xb0,
0x9e, 0xe5, 0xc2, 0xd9, 0x4e, 0xc4, 0xf3, 0x7f, 0x78, 0x07, 0x4b, 0x65, 0x88, 0x45, 0x0c,
0x11, 0xe5, 0x96, 0x56, 0x34, 0x88, 0x2d, 0x16, 0x0e, 0x59, 0x42, 0xd2, 0xf7, 0xd9, 0xed,
0x1d, 0xed, 0xc9, 0x37, 0x77, 0x44, 0x7e, 0xe3, 0x84, 0x36, 0x9f, 0x58, 0x13, 0xef, 0x6f,
0xe4, 0xc3, 0x44, 0xd4, 0x77, 0x06, 0x8a, 0xcf, 0x5b, 0xc8, 0x80, 0x1c, 0xa2, 0x98, 0x65,
0x0b, 0x35, 0xdc, 0x73, 0xc8, 0x69, 0xd0, 0x5e, 0xe8, 0x25, 0x43, 0x9e, 0xf6, 0xd8, 0xab,
0x05, 0xaf, 0x51, 0x29, 0x23, 0x55, 0x40, 0x58, 0x10, 0xea, 0xb8, 0xe2, 0xcd, 0x5d, 0x79,
0xcc, 0xec, 0xdf, 0xb4, 0x5b, 0x98, 0xc7, 0xfa, 0xe3, 0xd2, 0x6c, 0x26, 0xce, 0x2e, 0x2c,
0x56, 0xe0, 0xcf, 0x8d, 0xee, 0xfd, 0x93, 0x12, 0x2f, 0x00, 0x49, 0x8d, 0x1c, 0x82, 0x38,
0x56, 0xa6, 0x5d, 0x79, 0x44, 0x4a, 0x1a, 0xf3, 0xdc, 0x16, 0x10, 0xb3, 0xc1, 0x2d, 0x27,
0x11, 0xfe, 0x1b, 0x98, 0x05, 0xe4, 0xa3, 0x60, 0x31, 0x99 };
static uint8_t ucAzureIoTADURootKeyE200703[3] = { 0x01, 0x00, 0x01 };
static SampleJWS::RootKey xADURootKeys[] =
{
{
// Minus one on id to not count NULL
.root_key_id = az_span_create(ucAzureIoTADURootKeyId200703, sizeof(ucAzureIoTADURootKeyId200703) - 1),
.root_key_n = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyN200703),
.root_key_exponent = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyE200703)
},
{
// Minus one on id to not count NULL
.root_key_id = az_span_create(ucAzureIoTADURootKeyId200702, sizeof(ucAzureIoTADURootKeyId200702) - 1),
.root_key_n = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyN200702),
.root_key_exponent = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyE200702)
}
};
static SampleJWS::RootKey xADURootKeys[]
= { { // Minus one on id to not count NULL
.root_key_id
= az_span_create(ucAzureIoTADURootKeyId200703, sizeof(ucAzureIoTADURootKeyId200703) - 1),
.root_key_n = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyN200703),
.root_key_exponent = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyE200703) },
{ // Minus one on id to not count NULL
.root_key_id
= az_span_create(ucAzureIoTADURootKeyId200702, sizeof(ucAzureIoTADURootKeyId200702) - 1),
.root_key_n = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyN200702),
.root_key_exponent = AZ_SPAN_FROM_BUFFER(ucAzureIoTADURootKeyE200702) } };
static void connect_to_wifi()
{
@ -438,7 +431,9 @@ static void request_all_properties(void)
// send_adu_device_reported_property writes a property payload reporting device
// state and then sends it to Azure IoT Hub.
static void send_adu_device_information_property(az_iot_adu_client_agent_state agent_state, az_iot_adu_client_workflow * workflow)
static void send_adu_device_information_property(
az_iot_adu_client_agent_state agent_state,
az_iot_adu_client_workflow* workflow)
{
az_result rc;
@ -467,12 +462,7 @@ static void send_adu_device_information_property(az_iot_adu_client_agent_state a
}
rc = az_iot_adu_client_get_agent_state_payload(
&adu_client,
&adu_device_information,
agent_state,
workflow,
NULL,
&adu_payload);
&adu_client, &adu_device_information, agent_state, workflow, NULL, &adu_payload);
if (az_result_failed(rc))
{
Logger.Error("Failed to get the adu device information payload");
@ -500,8 +490,9 @@ static void send_adu_device_information_property(az_iot_adu_client_agent_state a
}
}
static void send_adu_accept_manifest_property(int32_t version_number,
az_iot_adu_client_request_decision response_code)
static void send_adu_accept_manifest_property(
int32_t version_number,
az_iot_adu_client_request_decision response_code)
{
az_result rc;
@ -639,8 +630,7 @@ static void process_device_property_message(
if (az_iot_adu_client_is_component_device_update(&adu_client, component_name))
{
// ADU Component
rc = az_iot_adu_client_parse_service_properties(
&adu_client, &jr, &adu_update_request);
rc = az_iot_adu_client_parse_service_properties(&adu_client, &jr, &adu_update_request);
if (az_result_failed(rc))
{
@ -649,9 +639,13 @@ static void process_device_property_message(
}
else
{
if(adu_update_request.workflow.action == AZ_IOT_ADU_CLIENT_SERVICE_ACTION_APPLY_DEPLOYMENT)
if (adu_update_request.workflow.action == AZ_IOT_ADU_CLIENT_SERVICE_ACTION_APPLY_DEPLOYMENT)
{
rc = az_json_string_unescape(adu_update_request.update_manifest, (char*)adu_manifest_unescape_buffer, sizeof(adu_manifest_unescape_buffer), &out_manifest_size);
rc = az_json_string_unescape(
adu_update_request.update_manifest,
(char*)adu_manifest_unescape_buffer,
sizeof(adu_manifest_unescape_buffer),
&out_manifest_size);
if (az_result_failed(rc))
{
@ -659,7 +653,8 @@ static void process_device_property_message(
return;
}
az_span manifest_unescaped = az_span_create((uint8_t*)adu_manifest_unescape_buffer, out_manifest_size);
az_span manifest_unescaped
= az_span_create((uint8_t*)adu_manifest_unescape_buffer, out_manifest_size);
rc = az_json_reader_init(&jr_adu_manifest, manifest_unescaped, NULL);
@ -683,7 +678,8 @@ static void process_device_property_message(
rc = SampleJWS::ManifestAuthenticate(
manifest_unescaped,
adu_update_request.update_manifest_signature,
&xADURootKeys[0], sizeof(xADURootKeys) / sizeof(xADURootKeys[0]),
&xADURootKeys[0],
sizeof(xADURootKeys) / sizeof(xADURootKeys[0]),
AZ_SPAN_FROM_BUFFER(adu_verification_buffer));
if (az_result_failed(rc))
{
@ -697,7 +693,8 @@ static void process_device_property_message(
if (is_update_already_applied())
{
Logger.Info("Update already applied");
send_adu_accept_manifest_property(version_number, AZ_IOT_ADU_CLIENT_REQUEST_DECISION_REJECT);
send_adu_accept_manifest_property(
version_number, AZ_IOT_ADU_CLIENT_REQUEST_DECISION_REJECT);
process_update_request = false;
}
else if (is_update_too_big(adu_update_manifest.files[0].size_in_bytes))
@ -710,7 +707,8 @@ static void process_device_property_message(
else
{
Logger.Info("Sending manifest property accept");
send_adu_accept_manifest_property(version_number, AZ_IOT_ADU_CLIENT_REQUEST_DECISION_ACCEPT);
send_adu_accept_manifest_property(
version_number, AZ_IOT_ADU_CLIENT_REQUEST_DECISION_ACCEPT);
process_update_request = true;
}
@ -723,9 +721,11 @@ static void process_device_property_message(
}
else
{
Logger.Error("Unknown workflow action received: " + String(adu_update_request.workflow.action));
Logger.Error(
"Unknown workflow action received: " + String(adu_update_request.workflow.action));
send_adu_device_information_property(AZ_IOT_ADU_CLIENT_AGENT_STATE_FAILED, &adu_update_request.workflow);
send_adu_device_information_property(
AZ_IOT_ADU_CLIENT_AGENT_STATE_FAILED, &adu_update_request.workflow);
process_update_request = false;
}
@ -1106,7 +1106,8 @@ static void send_telemetry()
// Arduino setup and loop main functions.
void setup() {
void setup()
{
adu_device_information = az_iot_adu_client_device_properties_default();
adu_device_information.manufacturer = AZ_SPAN_FROM_STR(ADU_DEVICE_MANUFACTURER);
adu_device_information.model = AZ_SPAN_FROM_STR(ADU_DEVICE_MODEL);
@ -1138,7 +1139,7 @@ void loop()
#endif
else if (millis() > next_telemetry_send_time_ms)
{
if(send_init_state)
if (send_init_state)
{
Logger.Info("Requesting all device properties");
request_all_properties();
@ -1150,9 +1151,10 @@ void loop()
send_telemetry();
next_telemetry_send_time_ms = millis() + TELEMETRY_FREQUENCY_MILLISECS;
if(process_update_request)
if (process_update_request)
{
send_adu_device_information_property(AZ_IOT_ADU_CLIENT_AGENT_STATE_DEPLOYMENT_IN_PROGRESS, &adu_update_request.workflow);
send_adu_device_information_property(
AZ_IOT_ADU_CLIENT_AGENT_STATE_DEPLOYMENT_IN_PROGRESS, &adu_update_request.workflow);
result = download_and_write_to_flash();
@ -1165,13 +1167,14 @@ void loop()
send_adu_device_information_property(AZ_IOT_ADU_CLIENT_AGENT_STATE_IDLE, NULL);
process_update_request = false;
}
else if (adu_update_request.workflow.action == AZ_IOT_ADU_CLIENT_SERVICE_ACTION_APPLY_DEPLOYMENT)
else if (
adu_update_request.workflow.action == AZ_IOT_ADU_CLIENT_SERVICE_ACTION_APPLY_DEPLOYMENT)
{
result = verify_image(
adu_update_manifest.files[0].hashes->hash_value,
adu_update_manifest.files[0].size_in_bytes);
// Clean shutdown of MQTT
// Clean shutdown of MQTT
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_stop(mqtt_client);
@ -1183,9 +1186,11 @@ void loop()
}
else
{
Logger.Error("Unknown workflow action received: " + String(adu_update_request.workflow.action));
Logger.Error(
"Unknown workflow action received: " + String(adu_update_request.workflow.action));
send_adu_device_information_property(AZ_IOT_ADU_CLIENT_AGENT_STATE_FAILED, &adu_update_request.workflow);
send_adu_device_information_property(
AZ_IOT_ADU_CLIENT_AGENT_STATE_FAILED, &adu_update_request.workflow);
process_update_request = false;
}

Просмотреть файл

@ -637,10 +637,11 @@ static az_result base64_decode_jws_header_and_payload(jws_validation_context* ma
return AZ_OK;
}
static az_result validate_root_key(jws_validation_context* manifest_context,
SampleJWS::RootKey * root_keys,
uint32_t root_keys_length,
int32_t * adu_root_key_index)
static az_result validate_root_key(
jws_validation_context* manifest_context,
SampleJWS::RootKey* root_keys,
uint32_t root_keys_length,
int32_t* adu_root_key_index)
{
az_result result;
az_json_reader json_reader;
@ -659,13 +660,13 @@ static az_result validate_root_key(jws_validation_context* manifest_context,
return AZ_ERROR_ITEM_NOT_FOUND;
}
for( int i = 0; i < root_keys_length; i++ )
for (int i = 0; i < root_keys_length; i++)
{
if( az_span_is_content_equal( root_keys[ i ].root_key_id, manifest_context->kid_span ) )
{
*adu_root_key_index = i;
return AZ_OK;
}
if (az_span_is_content_equal(root_keys[i].root_key_id, manifest_context->kid_span))
{
*adu_root_key_index = i;
return AZ_OK;
}
}
return AZ_ERROR_NOT_SUPPORTED;
@ -751,7 +752,7 @@ static az_result verify_sha_match(jws_validation_context* manifest_context, az_s
az_result SampleJWS::ManifestAuthenticate(
az_span manifest_span,
az_span jws_span,
SampleJWS::RootKey * root_keys,
SampleJWS::RootKey* root_keys,
uint32_t root_keys_length,
az_span scratch_buffer_span)
{
@ -856,7 +857,7 @@ az_result SampleJWS::ManifestAuthenticate(
/*------------------- Parse root key id ------------------------*/
result = validate_root_key(&manifest_context, root_keys, root_keys_length, &root_key_index );
result = validate_root_key(&manifest_context, root_keys, root_keys_length, &root_key_index);
if (az_result_failed(result))
{
Logger.Error("[JWS] validate_root_key failed: result " + String(result, HEX));

Просмотреть файл

@ -43,9 +43,9 @@ namespace SampleJWS
*/
typedef struct RootKey
{
az_span root_key_id;
az_span root_key_n;
az_span root_key_exponent;
az_span root_key_id;
az_span root_key_n;
az_span root_key_exponent;
} RootKey;
/**
@ -64,7 +64,7 @@ typedef struct RootKey
az_result ManifestAuthenticate(
az_span manifest_span,
az_span jws_span,
RootKey * root_keys,
RootKey* root_keys,
uint32_t root_keys_length,
az_span scratch_buffer_span);
}; // namespace SampleJWS

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -15,8 +15,8 @@
#ifndef AZURE_IOT_H
#define AZURE_IOT_H
#include <stdlib.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <az_core.h>
@ -38,8 +38,7 @@ typedef enum log_level_t_enum
{
log_level_info,
log_level_error
}
log_level_t;
} log_level_t;
typedef void (*log_function_t)(log_level_t log_level, char const* const format, ...);
@ -48,45 +47,43 @@ extern log_function_t default_logging_function;
#define set_logging_function(custom_logging_function) \
default_logging_function = custom_logging_function;
#define Log(level, message, ...) default_logging_function(level, message, ##__VA_ARGS__ )
#define LogInfo(message, ...) Log(log_level_info, message, ##__VA_ARGS__ )
#define LogError(message, ...) Log(log_level_error, message, ##__VA_ARGS__ )
#define Log(level, message, ...) default_logging_function(level, message, ##__VA_ARGS__)
#define LogInfo(message, ...) Log(log_level_info, message, ##__VA_ARGS__)
#define LogError(message, ...) Log(log_level_error, message, ##__VA_ARGS__)
#else
#define set_logging_function(custom_logging_function)
#define Log(level, message, ...)
#define set_logging_function(custom_logging_function)
#define Log(level, message, ...)
#define LogInfo(message, ...)
#define LogError(message, ...)
#endif // DISABLE_LOGGING
/* --- Azure Definitions --- */
#define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net"
#define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net"
#define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES 60
#define SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS 30
#define SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS 30
/*
* The structures below define a generic interface to abstract the interaction of this module,
* with any MQTT client used in the user application.
* The structures below define a generic interface to abstract the interaction of this module,
* with any MQTT client used in the user application.
*/
#define MQTT_QOS_AT_MOST_ONCE 0
#define MQTT_QOS_AT_MOST_ONCE 0
#define MQTT_QOS_AT_LEAST_ONCE 1
#define MQTT_QOS_EXACTLY_ONCE 2
#define MQTT_QOS_EXACTLY_ONCE 2
typedef enum mqtt_qos_t_enum
{
mqtt_qos_at_most_once = MQTT_QOS_AT_MOST_ONCE,
mqtt_qos_at_least_once = MQTT_QOS_AT_LEAST_ONCE,
mqtt_qos_exactly_once = MQTT_QOS_EXACTLY_ONCE
}
mqtt_qos_t;
} mqtt_qos_t;
/*
* @brief Defines a generic MQTT message to be exchanged between the AzureIoT layer
* and the user application.
* and the user application.
* @remark It uses azure-sdk-for-c's az_span construct, which is merely a structure that
* has a pointer to a buffer and its size. Messages without a payload will have
* the `payload` member set to AZ_SPAN_EMPTY.
@ -98,8 +95,7 @@ typedef struct mqtt_message_t_struct
az_span topic;
az_span payload;
mqtt_qos_t qos;
}
mqtt_message_t;
} mqtt_message_t;
/*
* @brief Configuration structure passed by `mqtt_client_init_function_t` to the user
@ -131,8 +127,7 @@ typedef struct mqtt_client_config_t_struct
* @brief Password to be provided in the CONNECT sent by the MQTT client.
*/
az_span password;
}
mqtt_client_config_t;
} mqtt_client_config_t;
/*
* @brief Generic pointer to the actual instance of the application MQTT client.
@ -142,70 +137,79 @@ typedef void* mqtt_client_handle_t;
/*
* @brief Function to initialize and connect an MQTT client.
* @remark When this function is called, it provides the information necessary to initialize a
* specific MQTT client (whichever is used by the user application). In this callback
* it is expected that the MQTT client will be created/initialized, started and that it
* start sending a CONNECT to the provided server.
* @remark When this function is called, it provides the information necessary to initialize
* a specific MQTT client (whichever is used by the user application). In this callback it is
* expected that the MQTT client will be created/initialized, started and that it start sending a
* CONNECT to the provided server.
*
* @param[in] mqtt_client_config An instance of mqtt_client_config_t containing all the
* information needed by the MQTT client to connect to the target server. Please see
* `mqtt_client_config_t` documentation for details.
* @param[out] mqtt_client_handle A pointer to the resulting "instance" of the MQTT client
* shall be saved in `mqtt_client_handle` for later use by the calling layer.
*
* @param[in] mqtt_client_config An instance of mqtt_client_config_t containing all the information
* needed by the MQTT client to connect to the target server.
* Please see `mqtt_client_config_t` documentation for details.
* @param[out] mqtt_client_handle A pointer to the resulting "instance" of the MQTT client shall
* be saved in `mqtt_client_handle` for later use by the calling layer.
*
* @return int 0 on success, non-zero if any failure occurs.
*/
typedef int (*mqtt_client_init_function_t)(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t* mqtt_client_handle);
typedef int (*mqtt_client_init_function_t)(
mqtt_client_config_t* mqtt_client_config,
mqtt_client_handle_t* mqtt_client_handle);
/*
* @brief Function to disconnect and deinitialize an MQTT client.
* @remark When this function is called the MQTT client instance referenced by `mqtt_client_handle` shall disconnect
* from the server and any functions of the MQTT client API that destroy the instance shall be called
* (so any allocated memory resources can be released).
* @remark When this function is called the MQTT client instance referenced by
* `mqtt_client_handle` shall disconnect from the server and any functions of the MQTT client API
* that destroy the instance shall be called (so any allocated memory resources can be released).
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously
* created with `mqtt_client_init_function_t` function.
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously created with
* `mqtt_client_init_function_t` function.
*
* @return int 0 on success, non-zero if any failure occurs.
* Returning non-zero results in the Azure IoT Client going into error state.
* Returning non-zero results in the Azure IoT Client going into
* error state.
*/
typedef int (*mqtt_client_deinit_function_t)(mqtt_client_handle_t mqtt_client_handle);
/*
* @brief Function to send an MQTT PUBLISH.
* @remark When this function is invoked, the caller expects the actual MQTT client (referenced by `mqtt_client_handle`)
* to invoke the appropriate function in the MQTT client API to publish an MQTT message.
* @remark When this function is invoked, the caller expects the actual MQTT client
* (referenced by `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to
* publish an MQTT message.
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously
* created with `mqtt_client_init_function_t` function.
* @param[in] mqtt_message A structure containing the topic name, payload and QoS to be
* used to publish an actual MQTT message.
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously created with
* `mqtt_client_init_function_t` function.
* @param[in] mqtt_message A structure containing the topic name, payload and QoS to be used to publish
* an actual MQTT message.
*
* @return int The packet ID on success, or NEGATIVE if any failure occurs.
* If the QoS in `mqtt_message` is:
* - AT LEAST ONCE, the Azure IoT client expects `azure_iot_mqtt_client_connected`
* to be called once the MQTT client receives a PUBACK.
* - AT MOST ONCE, there should be no PUBACK, so no further action is
* needed for this PUBLISH.
* - AT LEAST ONCE, the Azure IoT client expects
* `azure_iot_mqtt_client_connected` to be called once the MQTT client receives a PUBACK.
* - AT MOST ONCE, there should be no PUBACK, so no further
* action is needed for this PUBLISH.
*/
typedef int (*mqtt_client_publish_function_t)(mqtt_client_handle_t mqtt_client_handle, mqtt_message_t* mqtt_message);
typedef int (*mqtt_client_publish_function_t)(
mqtt_client_handle_t mqtt_client_handle,
mqtt_message_t* mqtt_message);
/*
* @brief Function to send an MQTT SUBSCRIBE.
* @remark When this function is invoked, Azure IoT client expects the actual MQTT client (referenced by
* `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to subscribe to
* an MQTT topic.
* @remark When this function is invoked, Azure IoT client expects the actual MQTT client
* (referenced by `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to
* subscribe to an MQTT topic.
*
* @param[in] topic The az_span with the string containing the complete MQTT topic name to subscribed to.
* This string is always NULL-terminated.
* @param[in] topic The az_span with the string containing the complete MQTT topic name
* to subscribed to. This string is always NULL-terminated.
* @param[in] qos MQTT QoS to be used for the topic subscription.
*
*
* @return int The packet ID of the subscription on success, or NEGATIVE if any failure occurs.
* Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called once the
* MQTT client receives a SUBACK.
*
* @return int The packet ID of the subscription on success, or NEGATIVE if any
* failure occurs. Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called
* once the MQTT client receives a SUBACK.
*/
typedef int (*mqtt_client_subscribe_function_t)(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos);
typedef int (*mqtt_client_subscribe_function_t)(
mqtt_client_handle_t mqtt_client_handle,
az_span topic,
mqtt_qos_t qos);
/*
* @brief Structure that consolidates all the abstracted MQTT functions.
@ -216,53 +220,69 @@ typedef struct mqtt_client_interface_t_struct
mqtt_client_deinit_function_t mqtt_client_deinit;
mqtt_client_publish_function_t mqtt_client_publish;
mqtt_client_subscribe_function_t mqtt_client_subscribe;
}
mqtt_client_interface_t;
} mqtt_client_interface_t;
/*
* @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords.
*
*
* @param[in] data Buffer containing the Base64-encoded content.
* @param[in] data_length Length of `data`.
* @param[in] decoded Buffer where to write the Base64-decoded content of `data`.
* @param[in] decoded_size Size of `decoded`.
* @param[out] decoded_length The final length of the Base64-decoded content written in
* @param[out] decoded_length The final length of the Base64-decoded content written in
* the `decoded` buffer.
*
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length);
typedef int (*base64_decode_function_t)(
uint8_t* data,
size_t data_length,
uint8_t* decoded,
size_t decoded_size,
size_t* decoded_length);
/*
* @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords.
*
*
* @param[in] data Buffer containing the Base64-decoded content.
* @param[in] data_length Length of `data`.
* @param[in] encoded Buffer where to write the Base64-encoded content of `data`.
* @param[in] encoded_size Size of `encoded`.
* @param[out] encoded_length The final length of the Base64-encoded content written in
* @param[out] encoded_length The final length of the Base64-encoded content written in
* the `encoded` buffer.
*
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
typedef int (*base64_encode_function_t)(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length);
typedef int (*base64_encode_function_t)(
uint8_t* data,
size_t data_length,
uint8_t* encoded,
size_t encoded_size,
size_t* encoded_length);
/*
* @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords.
*
*
* @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm.
* @param[in] key_length Length of `key`.
* @param[in] payload Buffer containing the data to be encrypted.
* @param[in] payload_size Size of `payload`.
* @param[in] encrypted_payload Buffer where to write the HMAC-SHA256 encrypted content of `payload`.
* @param[in] encrypted_payload Buffer where to write the HMAC-SHA256 encrypted content
* of `payload`.
* @param[in] encrypted_payload_size The size of the `encrypted_payload` buffer.
*
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
typedef int (*hmac_sha256_encryption_function_t)(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* encrypted_payload, size_t encrypted_payload_size);
typedef int (*hmac_sha256_encryption_function_t)(
const uint8_t* key,
size_t key_length,
const uint8_t* payload,
size_t payload_length,
uint8_t* encrypted_payload,
size_t encrypted_payload_size);
/*
* @brief Structure that consolidates all the data manipulation functions.
@ -272,14 +292,15 @@ typedef struct data_manipulation_functions_t_struct
base64_decode_function_t base64_decode;
base64_encode_function_t base64_encode;
hmac_sha256_encryption_function_t hmac_sha256_encrypt;
}
data_manipulation_functions_t;
} data_manipulation_functions_t;
/*
* @brief Defines the callback for notifying the completion of a reported properties update.
*
* @param[in] request_id Request ID provided by the caller when sending the reported properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code semantics).
*
* @param[in] request_id Request ID provided by the caller when sending the reported
* properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code
* semantics).
*
* @return Nothing.
*/
@ -287,9 +308,11 @@ typedef void (*properties_update_completed_t)(uint32_t request_id, az_iot_status
/*
* @brief Defines the callback for receiving a writable-properties update.
*
* @param[in] request_id Request ID provided by the caller when sending the reported properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code semantics).
*
* @param[in] request_id Request ID provided by the caller when sending the reported
* properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code
* semantics).
*
* @return Nothing.
*/
@ -320,14 +343,13 @@ typedef struct command_request_t_struct
* @brief Optional payload sent by the caller for this command.
*/
az_span payload;
}
command_request_t;
} command_request_t;
/*
* @brief Defines the callback for receiving an IoT Plug and Play Command.
* @remark A response for this command MUST be provided to Azure by calling
* @remark A response for this command MUST be provided to Azure by calling
* `azure_iot_send_command_response`.
*
*
* @param[in] command An instance of `command_request_t` containing all the details of
* of the command received.
*
@ -347,7 +369,7 @@ typedef enum azure_iot_status_t_struct
/*
* @brief The client is in an intermediate state between disconnected and connected.
* @remark When using SAS-based authentication (default for Azure IoT Central), the client
* will automatically perform a reconnection with a new SAS token after the previous
* will automatically perform a reconnection with a new SAS token after the previous
* one expires, going back into `azure_iot_connecting` state briefly.
*/
azure_iot_connecting,
@ -358,19 +380,19 @@ typedef enum azure_iot_status_t_struct
/*
* @brief The Azure IoT client encountered some internal error and is no longer active.
* @remark This can be caused by:
* - Memory issues (not enough memory provided in `azure_iot_config_t`'s `data_buffer`);
* - Memory issues (not enough memory provided in `azure_iot_config_t`'s
* `data_buffer`);
* - Any failures reported by the application's MQTT client
* (through the abstracted interface) return values;
* - Any protocol errors returned by Azure IoT services.
* If not enough memory has been provided in `azure_iot_config_t`'s `data_buffer,
* please expand the size of that memory space.`
* Once the possible mitigations are applied stop the Azure IoT client
* Once the possible mitigations are applied stop the Azure IoT client
* by calling `azure_iot_stop` (which resets the client state) and restart it
* using `azure_iot_start`.
*/
azure_iot_error
}
azure_iot_status_t;
} azure_iot_status_t;
/*
* @brief Internal states of the Azure IoT client.
@ -398,8 +420,7 @@ typedef enum azure_iot_client_state_t_struct
azure_iot_state_ready,
azure_iot_state_refreshing_sas,
azure_iot_state_error
}
azure_iot_client_state_t;
} azure_iot_client_state_t;
/*
* @brief Structure that holds the configuration for the Azure IoT client.
@ -408,7 +429,7 @@ azure_iot_client_state_t;
* Also make sure that the instance of `azure_iot_config_t` (and its members) do not
* lose scope throughout the lifetime of the Azure IoT client.
* Most of the members of this structure use az_span for encapsulating a buffer and
* its size. For more details on az_span, please explore the code at
* its size. For more details on az_span, please explore the code at
* https://github.com/azure/azure-sdk-for-c.
*/
typedef struct azure_iot_config_t_struct
@ -498,29 +519,29 @@ typedef struct azure_iot_config_t_struct
* @brief Buffer with memory space to be used internally by Azure IoT client for its
* internal functions.
* @remark This buffer MUST be large enough to perform all the string manipulations done
* internally by the Azure IoT client, like MQTT client client id, username and password
* generation, as well as storing Azure IoT Hub fqdn and device id after device-provisioning
* is completed (if device-provisioning is used).
* The maximum size required depends on which services and authentication mode are used.
* If using device-provisioning with SAS-token authentication (as used with Azure IoT Central),
* this size must be at least:
* internally by the Azure IoT client, like MQTT client client id, username and
* password generation, as well as storing Azure IoT Hub fqdn and device id after
* device-provisioning is completed (if device-provisioning is used). The maximum size required
* depends on which services and authentication mode are used. If using device-provisioning with
* SAS-token authentication (as used with Azure IoT Central), this size must be at least:
* sizeof(data_buffer) >= ( lengthof(<iot-hub-fqdn>) + lengthof(<device-id>) +
* lengthof(<MQTT-clientid>) + lengthof(<MQTT-username>) +
* 2 * lengthof(<MQTT-password>) )
*
*
* Where:
* <MQTT-clientid> = <device-id> + '\0'
* <MQTT-username> = <iot-hub-fqdn> + '/' + lengthof(<device-id>) + '/' + '?' + <api-version> +
* "&DeviceClientType=" + urlenc(<user-agent>) + "&model-id=" + urlenc(<pnp-model-id>) + '\0'
* <api-version> = "api-version=<YYYY-MM-DD>"
* <MQTT-password>) = "SharedAccessSignature sr=" + <iot-hub-fqdn> + "%2Fdevices%2F" + <device-id> +
* "&sig=" + urlenc(<sha256-string>) + "&se=" + <expiration-time> + '\0'
* lengthof(<sha256-string>) <= lengthof(<64-char-string>)
* <expiration-time> = <10-digit-unix-time>
*
* Note: We use two times the length of <MQTT-password> given the internal operations needed to
* generate it.
*
* <MQTT-username> = <iot-hub-fqdn> + '/' + lengthof(<device-id>) + '/' + '?' +
* <api-version> +
* "&DeviceClientType=" + urlenc(<user-agent>) + "&model-id=" +
* urlenc(<pnp-model-id>) + '\0' <api-version> = "api-version=<YYYY-MM-DD>" <MQTT-password>) =
* "SharedAccessSignature sr=" + <iot-hub-fqdn> + "%2Fdevices%2F" + <device-id> +
* "&sig=" + urlenc(<sha256-string>) + "&se=" + <expiration-time>
* + '\0' lengthof(<sha256-string>) <= lengthof(<64-char-string>) <expiration-time> =
* <10-digit-unix-time>
*
* Note: We use two times the length of <MQTT-password> given the internal operations
* needed to generate it.
*
* Example:
* <iot-hub-fqdn> = "iotc-1a430cf3-6f05-4b84-965d-cb1385077966.azure-devices.net"
* <device-id> = "d1"
@ -529,13 +550,15 @@ typedef struct azure_iot_config_t_struct
* <api-version> = "api-version=2020-09-30"
* <expiration-time> = "1641251566"
* <user-agent> = "c%2F1.1.0-beta.1(FreeRTOS)"
*
* sizeof(data_buffer) >= 592 bytes (59 bytes + 2 bytes + 3 bytes + 190 bytes + 338 bytes, respectively)
*
* sizeof(data_buffer) >= 592 bytes (59 bytes + 2 bytes + 3 bytes + 190 bytes + 338
* bytes, respectively)
*/
az_span data_buffer;
/*
* @brief Set of functions to serve as interface between Azure IoT client and the user-application MQTT client.
* @brief Set of functions to serve as interface between Azure IoT client and the
* user-application MQTT client.
*/
mqtt_client_interface_t mqtt_client_interface;
@ -576,8 +599,7 @@ typedef struct azure_iot_config_t_struct
* `azure_iot_send_command_response`.
*/
command_request_received_t on_command_request_received;
}
azure_iot_config_t;
} azure_iot_config_t;
/*
* @brief Structure that holds the state of the Azure IoT client.
@ -599,15 +621,15 @@ typedef struct azure_iot_t_struct
uint32_t dps_retry_after_seconds;
uint32_t dps_last_query_time;
az_span dps_operation_id;
}
azure_iot_t;
} azure_iot_t;
/*
* @brief Initializes the azure_iot_t structure that holds the Azure IoT client state.
* @remark This function must be called only once per `azure_iot_t` instance,
* before any other function can be called using it.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the caller.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the
* caller.
* @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the
* configuration neeeded for the client to connect and work with
* the Azure IoT services.
@ -625,11 +647,12 @@ void azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config
* be called first, followed by a call to `azure_iot_start` so it can reconnect to
* the Azure IoT Hub again.
* Note: if device-provisioning is used, the device is provisioned only the first
* time a given `azure_iot_t` instance is started. Subsequent calls to
* time a given `azure_iot_t` instance is started. Subsequent calls to
* `azure_iot_start` will re-use the Azure IoT Hub FQDN and device ID previously
* provisioned.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the caller.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the
* caller.
* @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the
* configuration neeeded for the client to connect and work with
* the Azure IoT services.
@ -642,8 +665,9 @@ int azure_iot_start(azure_iot_t* azure_iot);
* @remark This function must be called once the user application wants to stop working and
* disconnect from the Azure IoT services. The same instance of `azure_iot_t` can be
* used again by the user application by calling `azure_iot_start`.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the caller.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the
* caller.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -653,23 +677,26 @@ int azure_iot_stop(azure_iot_t* azure_iot);
* @brief Gets the current state of the Azure IoT client.
* @remark The states informed are simplified for ease-of-use of this client, not reflecting
* all the detailed internal states possible within the Azure IoT client.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
*
* @return azure_iot_status_t One of four possible states as defined by `azure_iot_status_t`.
* Please see the `azure_iot_status_t` documentation above for details.
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously
* initialized by the caller.
*
* @return azure_iot_status_t One of four possible states as defined by
* `azure_iot_status_t`. Please see the `azure_iot_status_t` documentation above for details.
*/
azure_iot_status_t azure_iot_get_status(azure_iot_t* azure_iot);
/*
* @brief Causes the Azure IoT client to perform its tasks for connecting and working with Azure IoT services.
* @remark This function must be called frequently enough for the Azure IoT client to work properly.
* That frequency should be enough to respect the timeouts implemented by the Azure IoT services for
* its TCP connection and MQTT-protocol traffic with the client application.
* Calling it once within a main loop() function of most embedded implementations should be enough.
* The recommended minimum frequency is no less than once every 100 milliseconds.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @brief Causes the Azure IoT client to perform its tasks for connecting and working with
* Azure IoT services.
* @remark This function must be called frequently enough for the Azure IoT client to work
* properly. That frequency should be enough to respect the timeouts implemented by the Azure IoT
* services for its TCP connection and MQTT-protocol traffic with the client application. Calling it
* once within a main loop() function of most embedded implementations should be enough. The
* recommended minimum frequency is no less than once every 100 milliseconds.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously
* initialized by the caller.
*
* @return Nothing.
*/
@ -677,9 +704,11 @@ void azure_iot_do_work(azure_iot_t* azure_iot);
/*
* @brief Sends a telemetry payload to the Azure IoT Hub.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @param[in] message An az_span instance containing the buffer and size of the actual message to be sent.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
* @param[in] message An az_span instance containing the buffer and size of the actual
* message to be sent.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -688,14 +717,15 @@ int azure_iot_send_telemetry(azure_iot_t* azure_iot, az_span message);
/**
* @brief Sends a property update message to Azure IoT Hub.
*
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the
* Azure IoT client.
* @param[in] request_id An unique identification number to correlate the response with when
* @param[in] message An `az_span` with the message with the reported properties update
* (a JSON document formatted according to the DTDL specification).
* `message` gets passed as-is to the MQTT client publish function as the payload, so if
* your MQTT client expects a null-terminated string for payload, make sure `message` is
* a null-terminated string.
* `on_properties_update_completed` (set in azure_iot_config_t) is invoked.
* `message` gets passed as-is to the MQTT client publish function as
* the payload, so if your MQTT client expects a null-terminated string for payload, make sure
* `message` is a null-terminated string. `on_properties_update_completed` (set in
* azure_iot_config_t) is invoked.
*
* @return int 0 if the function succeeds, or non-zero if any failure occurs.
*/
@ -704,27 +734,33 @@ int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id
/**
* @brief Sends a property update message to Azure IoT Hub.
*
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] request_id The same `request_id` of the device command received from Azure IoT Hub.
* @param[in] response_status An HTTP-like code informing the success or failure of the command.
* A 202 will inform the command was accepted and succeeded.
* A 404 will inform the command received does not match the commands supported by
* this device application.
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of
* the Azure IoT client.
* @param[in] request_id The same `request_id` of the device command received from Azure
* IoT Hub.
* @param[in] response_status An HTTP-like code informing the success or failure of the
* command. A 202 will inform the command was accepted and succeeded. A 404 will inform the command
* received does not match the commands supported by this device application.
* @param[in] payload A custom payload to be sent in the device command response.
* This is expected to be a json content.
* If no payload is to be sent, please set it as AZ_SPAN_EMPTY.
*
* @return int 0 if the function succeeds, or non-zero if any failure occurs.
*/
int azure_iot_send_command_response(azure_iot_t* azure_iot, az_span request_id, uint16_t response_status, az_span payload);
int azure_iot_send_command_response(
azure_iot_t* azure_iot,
az_span request_id,
uint16_t response_status,
az_span payload);
/*
* @brief Informs the Azure IoT client that the MQTT client is connected.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_init` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has received
* a CONNACK from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* received a CONNACK from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -732,11 +768,12 @@ int azure_iot_mqtt_client_connected(azure_iot_t* azure_iot);
/*
* @brief Informs the Azure IoT client that the MQTT client is disconnected.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has disconnected
* from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit`
* callback (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* disconnected from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -744,11 +781,12 @@ int azure_iot_mqtt_client_disconnected(azure_iot_t* azure_iot);
/*
* @brief Informs the Azure IoT client that the MQTT client has subscribed to a topic.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_subscribe` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* received a SUBACK for a topic subscription.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_subscribe`
* callback (provided in the azure_iot_config_t instance) so it knows the MQTT client has received a
* SUBACK for a topic subscription.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
* @param[in] packet_id The ID of the subscription performed previous by the Azure IoT client.
*
* @return int 0 on success, or non-zero if any failure occurs.
@ -757,13 +795,14 @@ int azure_iot_mqtt_client_subscribe_completed(azure_iot_t* azure_iot, int packet
/*
* @brief Informs the Azure IoT client that the MQTT client has completed a PUBLISH.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_publish` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* completed an MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by
* the user application right after `mqtt_client_publish` is invoked. If the QoS of
* is 1 (AT LEAST ONCE), this shall be called whenever a PUBACK is received.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_publish`
* callback (provided in the azure_iot_config_t instance) so it knows the MQTT client has completed
* an MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by the user application
* right after `mqtt_client_publish` is invoked. If the QoS of is 1 (AT LEAST ONCE), this shall be
* called whenever a PUBACK is received.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
* @param[in] packet_id The ID of the subscription performed previous by the Azure IoT client.
*
* @return int 0 on success, or non-zero if any failure occurs.
@ -771,42 +810,48 @@ int azure_iot_mqtt_client_subscribe_completed(azure_iot_t* azure_iot, int packet
int azure_iot_mqtt_client_publish_completed(azure_iot_t* azure_iot, int packet_id);
/*
* @brief Informs the Azure IoT client that a new message has been received by the Azure IoT service.
* @brief Informs the Azure IoT client that a new message has been received by the Azure IoT
* service.
* @remark This must be called whenever an MQTT message is received from an Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @param[in] mqtt_message A `mqtt_message_t` instance containing all the details of the MQTT message
* received (topic name, qos and payload).
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized
* by the caller.
* @param[in] mqtt_message A `mqtt_message_t` instance containing all the details of the MQTT
* message received (topic name, qos and payload).
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_t* mqtt_message);
/* --- az_core extensions --- */
/*
* These functions are used internally by the Azure IoT client code and its extensions.
*/
/**
* @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to `remainder`.
* @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to
* `remainder`.
*
* @param[in] span A span to be sliced.
* @param[in] source The span to copy the contents from.
* @param[out] remainder The pointer where to store the remainder of `span` after it is sliced.
* @param[out] remainder The pointer where to store the remainder of `span` after it is
* sliced.
*
* @return az_span A slice of `span` from position zero to `size`.
*/
az_span split_az_span(az_span span, int32_t size, az_span* remainder);
/**
* @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the second through `remainder`.
* @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the
* second through `remainder`.
*
* @param[in] destination A span large enough to contain the copy of the contents of `source`.
* @param[in] source The span to copy the contents from.
* @param[out] remainder The pointer where to store the remainder of `destination` after `source` is copied.
* @param[out] remainder The pointer where to store the remainder of `destination` after
* `source` is copied.
*
* @return az_span A slice of `destination` with the same size as `source`, with `source`'s content copied over.
* @return az_span A slice of `destination` with the same size as `source`, with
* `source`'s content copied over.
*/
static az_span slice_and_copy_az_span(az_span destination, az_span source, az_span* remainder);

Просмотреть файл

@ -4,34 +4,36 @@
/*
* This is an Arduino-based Azure IoT Central sample specific for Espressif ESP32.
* It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c and https://azureiotcentral.com/.
*
* For reference, please visit https://github.com/azure/azure-sdk-for-c and
* https://azureiotcentral.com/.
*
* To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is an MQTT client support library, helping composing and parsing the
* MQTT topic names and messages exchanged with the Azure IoT Hub.
*
*
* The additional layers in this sketch provide a structured use of azure-sdk-for-c and
* the MQTT client of your choice to perform all the steps needed to connect and interact with
* the MQTT client of your choice to perform all the steps needed to connect and interact with
* Azure IoT Central.
*
*
* AzureIoT.cpp contains a state machine that implements those steps, plus abstractions to simplify
* its overall use. Besides the basic configuration needed to access the Azure IoT services,
* all that is needed is to provide the functions required by that layer to:
* - Interact with your MQTT client,
* - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding),
* - Receive the callbacks for Plug and Play properties and commands.
*
*
* Azure_IoT_PnP_Template.cpp contains the actual implementation of the IoT Plug and Play template
* specific for the Espressif ESP32 board.
*
* To properly connect to your Azure IoT services, please fill the information in the `iot_configs.h` file.
*
* To properly connect to your Azure IoT services, please fill the information in the
* `iot_configs.h` file.
*/
/* --- Dependencies --- */
// C99 libraries
#include <cstdlib>
#include <cstdarg>
#include <cstdlib>
#include <string.h>
#include <time.h>
@ -49,20 +51,20 @@
#include <az_iot.h>
#include <azure_ca.h>
// Additional sample headers
// Additional sample headers
#include "AzureIoT.h"
#include "Azure_IoT_PnP_Template.h"
#include "iot_configs.h"
/* --- Sample-specific Settings --- */
#define SERIAL_LOGGER_BAUD_RATE 115200
#define MQTT_DO_NOT_RETAIN_MSG 0
#define MQTT_DO_NOT_RETAIN_MSG 0
/* --- Time and NTP Settings --- */
#define NTP_SERVERS "pool.ntp.org", "time.nist.gov"
#define PST_TIME_ZONE -8
#define PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF 1
#define PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF 1
#define GMT_OFFSET_SECS (PST_TIME_ZONE * 3600)
#define GMT_OFFSET_SECS_DST ((PST_TIME_ZONE + PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF) * 3600)
@ -71,8 +73,8 @@
#define UNIX_EPOCH_START_YEAR 1900
/* --- Function Returns --- */
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
/* --- Handling iot_config.h Settings --- */
static const char* wifi_ssid = IOT_CONFIG_WIFI_SSID;
@ -101,21 +103,23 @@ static uint8_t az_iot_data_buffer[AZ_IOT_DATA_BUFFER_SIZE];
static uint32_t properties_request_id = 0;
static bool send_device_info = true;
/* --- MQTT Interface Functions --- */
/*
* These functions are used by Azure IoT to interact with whatever MQTT client used by the sample
* (in this case, Espressif's ESP MQTT). Please see the documentation in AzureIoT.h for more details.
* (in this case, Espressif's ESP MQTT). Please see the documentation in AzureIoT.h for more
* details.
*/
/*
* See the documentation of `mqtt_client_init_function_t` in AzureIoT.h for details.
*/
static int mqtt_client_init_function(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t *mqtt_client_handle)
static int mqtt_client_init_function(
mqtt_client_config_t* mqtt_client_config,
mqtt_client_handle_t* mqtt_client_handle)
{
int result;
esp_mqtt_client_config_t mqtt_config;
memset(&mqtt_config, 0, sizeof(mqtt_config));
memset(&mqtt_config, 0, sizeof(mqtt_config));
az_span mqtt_broker_uri_span = AZ_SPAN_FROM_BUFFER(mqtt_broker_uri);
mqtt_broker_uri_span = az_span_copy(mqtt_broker_uri_span, AZ_SPAN_FROM_STR(MQTT_PROTOCOL_PREFIX));
@ -127,13 +131,13 @@ static int mqtt_client_init_function(mqtt_client_config_t* mqtt_client_config, m
mqtt_config.client_id = (const char*)az_span_ptr(mqtt_client_config->client_id);
mqtt_config.username = (const char*)az_span_ptr(mqtt_client_config->username);
#ifdef IOT_CONFIG_USE_X509_CERT
LogInfo("MQTT client using X509 Certificate authentication");
mqtt_config.client_cert_pem = IOT_CONFIG_DEVICE_CERT;
mqtt_config.client_key_pem = IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY;
#else // Using SAS key
mqtt_config.password = (const char*)az_span_ptr(mqtt_client_config->password);
#endif
#ifdef IOT_CONFIG_USE_X509_CERT
LogInfo("MQTT client using X509 Certificate authentication");
mqtt_config.client_cert_pem = IOT_CONFIG_DEVICE_CERT;
mqtt_config.client_key_pem = IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY;
#else // Using SAS key
mqtt_config.password = (const char*)az_span_ptr(mqtt_client_config->password);
#endif
mqtt_config.keepalive = 30;
mqtt_config.disable_clean_session = 0;
@ -154,7 +158,7 @@ static int mqtt_client_init_function(mqtt_client_config_t* mqtt_client_config, m
else
{
esp_err_t start_result = esp_mqtt_client_start(mqtt_client);
if (start_result != ESP_OK)
{
LogError("esp_mqtt_client_start failed (error code: 0x%08x).", start_result);
@ -179,7 +183,7 @@ static int mqtt_client_deinit_function(mqtt_client_handle_t mqtt_client_handle)
esp_mqtt_client_handle_t esp_mqtt_client_handle = (esp_mqtt_client_handle_t)mqtt_client_handle;
LogInfo("MQTT client being disconnected.");
if (esp_mqtt_client_stop(esp_mqtt_client_handle) != ESP_OK)
{
LogError("Failed stopping MQTT client.");
@ -192,7 +196,7 @@ static int mqtt_client_deinit_function(mqtt_client_handle_t mqtt_client_handle)
if (azure_iot_mqtt_client_disconnected(&azure_iot) != 0)
{
LogError("Failed updating azure iot client of MQTT disconnection.");
LogError("Failed updating azure iot client of MQTT disconnection.");
}
return 0;
@ -201,13 +205,18 @@ static int mqtt_client_deinit_function(mqtt_client_handle_t mqtt_client_handle)
/*
* See the documentation of `mqtt_client_subscribe_function_t` in AzureIoT.h for details.
*/
static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos)
static int mqtt_client_subscribe_function(
mqtt_client_handle_t mqtt_client_handle,
az_span topic,
mqtt_qos_t qos)
{
LogInfo("MQTT client subscribing to '%.*s'", az_span_size(topic), az_span_ptr(topic));
// As per documentation, `topic` always ends with a null-terminator.
// esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion is needed.
int packet_id = esp_mqtt_client_subscribe((esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)az_span_ptr(topic), (int)qos);
// esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion
// is needed.
int packet_id = esp_mqtt_client_subscribe(
(esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)az_span_ptr(topic), (int)qos);
return packet_id;
}
@ -215,18 +224,20 @@ static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handl
/*
* See the documentation of `mqtt_client_publish_function_t` in AzureIoT.h for details.
*/
static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle, mqtt_message_t* mqtt_message)
static int mqtt_client_publish_function(
mqtt_client_handle_t mqtt_client_handle,
mqtt_message_t* mqtt_message)
{
LogInfo("MQTT client publishing to '%s'", az_span_ptr(mqtt_message->topic));
int mqtt_result = esp_mqtt_client_publish(
(esp_mqtt_client_handle_t)mqtt_client_handle,
(const char*)az_span_ptr(mqtt_message->topic), // topic is always null-terminated.
(const char*)az_span_ptr(mqtt_message->payload),
az_span_size(mqtt_message->payload),
(int)mqtt_message->qos,
MQTT_DO_NOT_RETAIN_MSG);
(esp_mqtt_client_handle_t)mqtt_client_handle,
(const char*)az_span_ptr(mqtt_message->topic), // topic is always null-terminated.
(const char*)az_span_ptr(mqtt_message->payload),
az_span_size(mqtt_message->payload),
(int)mqtt_message->qos,
MQTT_DO_NOT_RETAIN_MSG);
if (mqtt_result == -1)
{
return RESULT_ERROR;
@ -242,7 +253,13 @@ static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle,
/*
* See the documentation of `hmac_sha256_encryption_function_t` in AzureIoT.h for details.
*/
static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* signed_payload, size_t signed_payload_size)
static int mbedtls_hmac_sha256(
const uint8_t* key,
size_t key_length,
const uint8_t* payload,
size_t payload_length,
uint8_t* signed_payload,
size_t signed_payload_size)
{
(void)signed_payload_size;
mbedtls_md_context_t ctx;
@ -261,7 +278,12 @@ static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint
/*
* See the documentation of `base64_decode_function_t` in AzureIoT.h for details.
*/
static int base64_decode(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length)
static int base64_decode(
uint8_t* data,
size_t data_length,
uint8_t* decoded,
size_t decoded_size,
size_t* decoded_length)
{
return mbedtls_base64_decode(decoded, decoded_size, decoded_length, data, data_length);
}
@ -269,7 +291,12 @@ static int base64_decode(uint8_t* data, size_t data_length, uint8_t* decoded, si
/*
* See the documentation of `base64_encode_function_t` in AzureIoT.h for details.
*/
static int base64_encode(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length)
static int base64_encode(
uint8_t* data,
size_t data_length,
uint8_t* encoded,
size_t encoded_size,
size_t* encoded_length)
{
return mbedtls_base64_encode(encoded, encoded_size, encoded_length, data, data_length);
}
@ -301,17 +328,22 @@ void on_properties_received(az_span properties)
* See the documentation of `command_request_received_t` in AzureIoT.h for details.
*/
static void on_command_request_received(command_request_t command)
{
az_span component_name = az_span_size(command.component_name) == 0 ? AZ_SPAN_FROM_STR("") : command.component_name;
LogInfo("Command request received (id=%.*s, component=%.*s, name=%.*s)",
az_span_size(command.request_id), az_span_ptr(command.request_id),
az_span_size(component_name), az_span_ptr(component_name),
az_span_size(command.command_name), az_span_ptr(command.command_name));
{
az_span component_name
= az_span_size(command.component_name) == 0 ? AZ_SPAN_FROM_STR("") : command.component_name;
LogInfo(
"Command request received (id=%.*s, component=%.*s, name=%.*s)",
az_span_size(command.request_id),
az_span_ptr(command.request_id),
az_span_size(component_name),
az_span_ptr(component_name),
az_span_size(command.command_name),
az_span_ptr(command.command_name));
// Here the request is being processed within the callback that delivers the command request.
// However, for production application the recommendation is to save `command` and process it outside
// this callback, usually inside the main thread/task/loop.
// However, for production application the recommendation is to save `command` and process it
// outside this callback, usually inside the main thread/task/loop.
(void)azure_pnp_handle_command_request(&azure_iot, command);
}
@ -326,8 +358,8 @@ void setup()
azure_pnp_init();
/*
* The configuration structure used by Azure IoT must remain unchanged (including data buffer)
/*
* The configuration structure used by Azure IoT must remain unchanged (including data buffer)
* throughout the lifetime of the sample. This variable must also not lose context so other
* components do not overwrite any information within this structure.
*/
@ -336,19 +368,21 @@ void setup()
azure_iot_config.use_device_provisioning = true; // Required for Azure IoT Central.
azure_iot_config.iot_hub_fqdn = AZ_SPAN_EMPTY;
azure_iot_config.device_id = AZ_SPAN_EMPTY;
#ifdef IOT_CONFIG_USE_X509_CERT
azure_iot_config.device_certificate = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT);
azure_iot_config.device_certificate_private_key = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY);
azure_iot_config.device_key = AZ_SPAN_EMPTY;
#else
azure_iot_config.device_certificate = AZ_SPAN_EMPTY;
azure_iot_config.device_certificate_private_key = AZ_SPAN_EMPTY;
azure_iot_config.device_key = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_KEY);
#endif // IOT_CONFIG_USE_X509_CERT
#ifdef IOT_CONFIG_USE_X509_CERT
azure_iot_config.device_certificate = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT);
azure_iot_config.device_certificate_private_key
= AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY);
azure_iot_config.device_key = AZ_SPAN_EMPTY;
#else
azure_iot_config.device_certificate = AZ_SPAN_EMPTY;
azure_iot_config.device_certificate_private_key = AZ_SPAN_EMPTY;
azure_iot_config.device_key = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_KEY);
#endif // IOT_CONFIG_USE_X509_CERT
azure_iot_config.dps_id_scope = AZ_SPAN_FROM_STR(DPS_ID_SCOPE);
azure_iot_config.dps_registration_id = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_ID); // Use Device ID for Azure IoT Central.
azure_iot_config.dps_registration_id
= AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_ID); // Use Device ID for Azure IoT Central.
azure_iot_config.data_buffer = AZ_SPAN_FROM_BUFFER(az_iot_data_buffer);
azure_iot_config.sas_token_lifetime_in_minutes = MQTT_PASSWORD_LIFETIME_IN_MINUTES;
azure_iot_config.mqtt_client_interface.mqtt_client_init = mqtt_client_init_function;
@ -377,22 +411,22 @@ void loop()
}
else
{
switch(azure_iot_get_status(&azure_iot))
switch (azure_iot_get_status(&azure_iot))
{
case azure_iot_connected:
if (send_device_info)
{
(void)azure_pnp_send_device_info(&azure_iot, properties_request_id++);
send_device_info = false; // Only need to send once.
send_device_info = false; // Only need to send once.
}
else if (azure_pnp_send_telemetry(&azure_iot) != 0)
{
LogError("Failed sending telemetry.");
LogError("Failed sending telemetry.");
}
break;
case azure_iot_error:
LogError("Azure IoT client is in error state." );
LogError("Azure IoT client is in error state.");
azure_iot_stop(&azure_iot);
WiFi.disconnect();
break;
@ -404,12 +438,11 @@ void loop()
}
}
/* === Function Implementations === */
/*
* These are support functions used by the sample itself to perform its basic tasks
* of connecting to the internet, syncing the board clock, ESP MQTT client event handler
* of connecting to the internet, syncing the board clock, ESP MQTT client event handler
* and logging.
*/
@ -455,37 +488,39 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
case MQTT_EVENT_ERROR:
LogError("MQTT client in ERROR state.");
LogError(
"esp_tls_stack_err=%d; esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_code=%d",
event->error_handle->esp_tls_stack_err,
event->error_handle->esp_tls_cert_verify_flags,
event->error_handle->esp_transport_sock_errno,
event->error_handle->error_type,
event->error_handle->connect_return_code);
LogError(
"esp_tls_stack_err=%d; "
"esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_"
"code=%d",
event->error_handle->esp_tls_stack_err,
event->error_handle->esp_tls_cert_verify_flags,
event->error_handle->esp_transport_sock_errno,
event->error_handle->error_type,
event->error_handle->connect_return_code);
switch (event->error_handle->connect_return_code)
switch (event->error_handle->connect_return_code)
{
case MQTT_CONNECTION_ACCEPTED:
LogError("connect_return_code=MQTT_CONNECTION_ACCEPTED");
break;
case MQTT_CONNECTION_REFUSE_PROTOCOL:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_PROTOCOL");
break;
case MQTT_CONNECTION_REFUSE_ID_REJECTED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_ID_REJECTED");
break;
case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE");
break;
case MQTT_CONNECTION_REFUSE_BAD_USERNAME:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_BAD_USERNAME");
break;
case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED");
break;
default:
LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code);
break;
case MQTT_CONNECTION_ACCEPTED:
LogError("connect_return_code=MQTT_CONNECTION_ACCEPTED");
break;
case MQTT_CONNECTION_REFUSE_PROTOCOL:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_PROTOCOL");
break;
case MQTT_CONNECTION_REFUSE_ID_REJECTED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_ID_REJECTED");
break;
case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE");
break;
case MQTT_CONNECTION_REFUSE_BAD_USERNAME:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_BAD_USERNAME");
break;
case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED");
break;
default:
LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code);
break;
};
break;
@ -534,11 +569,15 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
mqtt_message_t mqtt_message;
mqtt_message.topic = az_span_create((uint8_t*)event->topic, event->topic_len);
mqtt_message.payload = az_span_create((uint8_t*)event->data, event->data_len);
mqtt_message.qos = mqtt_qos_at_most_once; // QoS is unused by azure_iot_mqtt_client_message_received.
mqtt_message.qos
= mqtt_qos_at_most_once; // QoS is unused by azure_iot_mqtt_client_message_received.
if (azure_iot_mqtt_client_message_received(&azure_iot, &mqtt_message) != 0)
{
LogError("azure_iot_mqtt_client_message_received failed (topic=%.*s).", event->topic_len, event->topic);
LogError(
"azure_iot_mqtt_client_message_received failed (topic=%.*s).",
event->topic_len,
event->topic);
}
break;

Просмотреть файл

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include <stdlib.h>
#include <stdarg.h>
#include <stdlib.h>
#include <az_core.h>
#include <az_iot.h>
@ -15,67 +15,67 @@
/* --- Defines --- */
#define AZURE_PNP_MODEL_ID "dtmi:azureiot:devkit:freertos:Esp32AzureIotKit;1"
#define SAMPLE_DEVICE_INFORMATION_NAME "deviceInformation"
#define SAMPLE_MANUFACTURER_PROPERTY_NAME "manufacturer"
#define SAMPLE_MODEL_PROPERTY_NAME "model"
#define SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME "swVersion"
#define SAMPLE_OS_NAME_PROPERTY_NAME "osName"
#define SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME "processorArchitecture"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME "processorManufacturer"
#define SAMPLE_TOTAL_STORAGE_PROPERTY_NAME "totalStorage"
#define SAMPLE_TOTAL_MEMORY_PROPERTY_NAME "totalMemory"
#define SAMPLE_DEVICE_INFORMATION_NAME "deviceInformation"
#define SAMPLE_MANUFACTURER_PROPERTY_NAME "manufacturer"
#define SAMPLE_MODEL_PROPERTY_NAME "model"
#define SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME "swVersion"
#define SAMPLE_OS_NAME_PROPERTY_NAME "osName"
#define SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME "processorArchitecture"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME "processorManufacturer"
#define SAMPLE_TOTAL_STORAGE_PROPERTY_NAME "totalStorage"
#define SAMPLE_TOTAL_MEMORY_PROPERTY_NAME "totalMemory"
#define SAMPLE_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
#define SAMPLE_MODEL_PROPERTY_VALUE "ESP32 Azure IoT Kit"
#define SAMPLE_VERSION_PROPERTY_VALUE "1.0.0"
#define SAMPLE_OS_NAME_PROPERTY_VALUE "FreeRTOS"
#define SAMPLE_ARCHITECTURE_PROPERTY_VALUE "ESP32 WROVER-B"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
#define SAMPLE_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
#define SAMPLE_MODEL_PROPERTY_VALUE "ESP32 Azure IoT Kit"
#define SAMPLE_VERSION_PROPERTY_VALUE "1.0.0"
#define SAMPLE_OS_NAME_PROPERTY_VALUE "FreeRTOS"
#define SAMPLE_ARCHITECTURE_PROPERTY_VALUE "ESP32 WROVER-B"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
// The next couple properties are in KiloBytes.
#define SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE 4096
#define SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE 8192
#define SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE 4096
#define SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE 8192
#define TELEMETRY_PROP_NAME_TEMPERATURE "temperature"
#define TELEMETRY_PROP_NAME_HUMIDITY "humidity"
#define TELEMETRY_PROP_NAME_LIGHT "light"
#define TELEMETRY_PROP_NAME_PRESSURE "pressure"
#define TELEMETRY_PROP_NAME_ALTITUDE "altitude"
#define TELEMETRY_PROP_NAME_MAGNETOMETERX "magnetometerX"
#define TELEMETRY_PROP_NAME_MAGNETOMETERY "magnetometerY"
#define TELEMETRY_PROP_NAME_MAGNETOMETERZ "magnetometerZ"
#define TELEMETRY_PROP_NAME_PITCH "pitch"
#define TELEMETRY_PROP_NAME_ROLL "roll"
#define TELEMETRY_PROP_NAME_ACCELEROMETERX "accelerometerX"
#define TELEMETRY_PROP_NAME_ACCELEROMETERY "accelerometerY"
#define TELEMETRY_PROP_NAME_ACCELEROMETERZ "accelerometerZ"
#define TELEMETRY_PROP_NAME_TEMPERATURE "temperature"
#define TELEMETRY_PROP_NAME_HUMIDITY "humidity"
#define TELEMETRY_PROP_NAME_LIGHT "light"
#define TELEMETRY_PROP_NAME_PRESSURE "pressure"
#define TELEMETRY_PROP_NAME_ALTITUDE "altitude"
#define TELEMETRY_PROP_NAME_MAGNETOMETERX "magnetometerX"
#define TELEMETRY_PROP_NAME_MAGNETOMETERY "magnetometerY"
#define TELEMETRY_PROP_NAME_MAGNETOMETERZ "magnetometerZ"
#define TELEMETRY_PROP_NAME_PITCH "pitch"
#define TELEMETRY_PROP_NAME_ROLL "roll"
#define TELEMETRY_PROP_NAME_ACCELEROMETERX "accelerometerX"
#define TELEMETRY_PROP_NAME_ACCELEROMETERY "accelerometerY"
#define TELEMETRY_PROP_NAME_ACCELEROMETERZ "accelerometerZ"
static az_span COMMAND_NAME_TOGGLE_LED_1 = AZ_SPAN_FROM_STR("ToggleLed1");
static az_span COMMAND_NAME_TOGGLE_LED_2 = AZ_SPAN_FROM_STR("ToggleLed2");
static az_span COMMAND_NAME_DISPLAY_TEXT = AZ_SPAN_FROM_STR("DisplayText");
#define COMMAND_RESPONSE_CODE_ACCEPTED 202
#define COMMAND_RESPONSE_CODE_REJECTED 404
#define COMMAND_RESPONSE_CODE_ACCEPTED 202
#define COMMAND_RESPONSE_CODE_REJECTED 404
#define WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS "telemetryFrequencySecs"
#define WRITABLE_PROPERTY_RESPONSE_SUCCESS "success"
#define WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS "telemetryFrequencySecs"
#define WRITABLE_PROPERTY_RESPONSE_SUCCESS "success"
#define DOUBLE_DECIMAL_PLACE_DIGITS 2
/* --- Function Checks and Returns --- */
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
#define EXIT_IF_TRUE(condition, retcode, message, ...) \
do \
{ \
if (condition) \
{ \
LogError(message, ##__VA_ARGS__ ); \
return retcode; \
} \
#define EXIT_IF_TRUE(condition, retcode, message, ...) \
do \
{ \
if (condition) \
{ \
LogError(message, ##__VA_ARGS__); \
return retcode; \
} \
} while (0)
#define EXIT_IF_AZ_FAILED(azresult, retcode, message, ...) \
EXIT_IF_TRUE(az_result_failed(azresult), retcode, message, ##__VA_ARGS__ )
#define EXIT_IF_AZ_FAILED(azresult, retcode, message, ...) \
EXIT_IF_TRUE(az_result_failed(azresult), retcode, message, ##__VA_ARGS__)
/* --- Data --- */
#define DATA_BUFFER_SIZE 1024
@ -91,23 +91,25 @@ static bool led2_on = false;
/* --- Function Prototypes --- */
/* Please find the function implementations at the bottom of this file */
static int generate_telemetry_payload(
uint8_t* payload_buffer, size_t payload_buffer_size, size_t* payload_buffer_length);
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length);
static int generate_device_info_payload(
az_iot_hub_client const* hub_client, uint8_t* payload_buffer,
size_t payload_buffer_size, size_t* payload_buffer_length);
az_iot_hub_client const* hub_client,
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length);
static int consume_properties_and_generate_response(
azure_iot_t* azure_iot, az_span properties,
uint8_t* buffer, size_t buffer_size, size_t* response_length);
azure_iot_t* azure_iot,
az_span properties,
uint8_t* buffer,
size_t buffer_size,
size_t* response_length);
/* --- Public Functions --- */
void azure_pnp_init()
{
}
void azure_pnp_init() {}
const az_span azure_pnp_get_model_id()
{
return AZ_SPAN_FROM_STR(AZURE_PNP_MODEL_ID);
}
const az_span azure_pnp_get_model_id() { return AZ_SPAN_FROM_STR(AZURE_PNP_MODEL_ID); }
void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds)
{
@ -128,8 +130,9 @@ int azure_pnp_send_telemetry(azure_iot_t* azure_iot)
LogError("Failed getting current time for controlling telemetry.");
return RESULT_ERROR;
}
else if (last_telemetry_send_time == INDEFINITE_TIME ||
difftime(now, last_telemetry_send_time) >= telemetry_frequency_in_seconds)
else if (
last_telemetry_send_time == INDEFINITE_TIME
|| difftime(now, last_telemetry_send_time) >= telemetry_frequency_in_seconds)
{
size_t payload_size;
@ -156,12 +159,14 @@ int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id)
_az_PRECONDITION_NOT_NULL(azure_iot);
int result;
size_t length;
result = generate_device_info_payload(&azure_iot->iot_hub_client, data_buffer, DATA_BUFFER_SIZE, &length);
size_t length;
result = generate_device_info_payload(
&azure_iot->iot_hub_client, data_buffer, DATA_BUFFER_SIZE, &length);
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed generating telemetry payload.");
result = azure_iot_send_properties_update(azure_iot, request_id, az_span_create(data_buffer, length));
result = azure_iot_send_properties_update(
azure_iot, request_id, az_span_create(data_buffer, length));
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed sending reported properties update.");
return RESULT_OK;
@ -187,20 +192,29 @@ int azure_pnp_handle_command_request(azure_iot_t* azure_iot, command_request_t c
}
else if (az_span_is_content_equal(command.command_name, COMMAND_NAME_DISPLAY_TEXT))
{
// The payload comes surrounded by quotes, so to remove them we offset the payload by 1 and its size by 2.
LogInfo("OLED display: %.*s", az_span_size(command.payload) - 2, az_span_ptr(command.payload) + 1);
// The payload comes surrounded by quotes, so to remove them we offset the payload by 1 and its
// size by 2.
LogInfo(
"OLED display: %.*s", az_span_size(command.payload) - 2, az_span_ptr(command.payload) + 1);
response_code = COMMAND_RESPONSE_CODE_ACCEPTED;
}
else
{
LogError("Command not recognized (%.*s).", az_span_size(command.command_name), az_span_ptr(command.command_name));
LogError(
"Command not recognized (%.*s).",
az_span_size(command.command_name),
az_span_ptr(command.command_name));
response_code = COMMAND_RESPONSE_CODE_REJECTED;
}
return azure_iot_send_command_response(azure_iot, command.request_id, response_code, AZ_SPAN_EMPTY);
return azure_iot_send_command_response(
azure_iot, command.request_id, response_code, AZ_SPAN_EMPTY);
}
int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span properties, uint32_t request_id)
int azure_pnp_handle_properties_update(
azure_iot_t* azure_iot,
az_span properties,
uint32_t request_id)
{
_az_PRECONDITION_NOT_NULL(azure_iot);
_az_PRECONDITION_VALID_SPAN(properties, 1, false);
@ -208,30 +222,23 @@ int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span propertie
int result;
size_t length;
result = consume_properties_and_generate_response(azure_iot, properties, data_buffer, DATA_BUFFER_SIZE, &length);
result = consume_properties_and_generate_response(
azure_iot, properties, data_buffer, DATA_BUFFER_SIZE, &length);
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed generating properties ack payload.");
result = azure_iot_send_properties_update(azure_iot, request_id, az_span_create(data_buffer, length));
result = azure_iot_send_properties_update(
azure_iot, request_id, az_span_create(data_buffer, length));
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed sending reported properties update.");
return RESULT_OK;
}
/* --- Internal Functions --- */
static float simulated_get_temperature()
{
return 21.0;
}
static float simulated_get_temperature() { return 21.0; }
static float simulated_get_humidity()
{
return 88.0;
}
static float simulated_get_humidity() { return 88.0; }
static float simulated_get_ambientLight()
{
return 700.0;
}
static float simulated_get_ambientLight() { return 700.0; }
static void simulated_get_pressure_altitude(float* pressure, float* altitude)
{
@ -239,14 +246,22 @@ static void simulated_get_pressure_altitude(float* pressure, float* altitude)
*altitude = 700.0;
}
static void simulated_get_magnetometer(int32_t* magneticFieldX, int32_t* magneticFieldY, int32_t* magneticFieldZ)
static void simulated_get_magnetometer(
int32_t* magneticFieldX,
int32_t* magneticFieldY,
int32_t* magneticFieldZ)
{
*magneticFieldX = 2000;
*magneticFieldY = 3000;
*magneticFieldZ = 4000;
}
static void simulated_get_pitch_roll_accel(int32_t* pitch, int32_t* roll, int32_t* accelerationX, int32_t* accelerationY, int32_t* accelerationZ)
static void simulated_get_pitch_roll_accel(
int32_t* pitch,
int32_t* roll,
int32_t* accelerationX,
int32_t* accelerationY,
int32_t* accelerationZ)
{
*pitch = 30;
*roll = 90;
@ -255,7 +270,10 @@ static void simulated_get_pitch_roll_accel(int32_t* pitch, int32_t* roll, int32_
*accelerationZ = 55;
}
static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_buffer_size, size_t* payload_buffer_length)
static int generate_telemetry_payload(
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length)
{
az_json_writer jw;
az_result rc;
@ -280,14 +298,17 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed setting telemetry json root.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_TEMPERATURE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding temperature property name to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding temperature property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, temperature, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding temperature property value to telemetry payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding temperature property value to telemetry payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_HUMIDITY));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding humidity property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, humidity, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding humidity property value to telemetry payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding humidity property value to telemetry payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_LIGHT));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding light property name to telemetry payload.");
@ -297,27 +318,38 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_PRESSURE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding pressure property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, pressure, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding pressure property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding pressure property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ALTITUDE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding altitude property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, altitude, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding altitude property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding altitude property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERX));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(X) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERX));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(X) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, magneticFieldX);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(X) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(X) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERY));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Y) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERY));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Y) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, magneticFieldY);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Y) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Y) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERZ));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Z) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERZ));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Z) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, magneticFieldZ);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Z) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Z) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_PITCH));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding pitch property name to telemetry payload.");
@ -329,20 +361,29 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
rc = az_json_writer_append_int32(&jw, roll);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding roll property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERX));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(X) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERX));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(X) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, accelerationX);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(X) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(X) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERY));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Y) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERY));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Y) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, accelerationY);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Y) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Y) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERZ));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Z) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERZ));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Z) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, accelerationZ);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Z) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Z) property value to telemetry payload.");
rc = az_json_writer_append_end_object(&jw);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed closing telemetry json payload.");
@ -357,11 +398,15 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
payload_buffer[az_span_size(payload_buffer_span)] = null_terminator;
*payload_buffer_length = az_span_size(payload_buffer_span);
return RESULT_OK;
}
static int generate_device_info_payload(az_iot_hub_client const* hub_client, uint8_t* payload_buffer, size_t payload_buffer_size, size_t* payload_buffer_length)
static int generate_device_info_payload(
az_iot_hub_client const* hub_client,
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length)
{
az_json_writer jw;
az_result rc;
@ -373,23 +418,28 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
rc = az_json_writer_append_begin_object(&jw);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed setting telemetry json root.");
rc = az_iot_hub_client_properties_writer_begin_component(
hub_client, &jw, AZ_SPAN_FROM_STR(SAMPLE_DEVICE_INFORMATION_NAME));
hub_client, &jw, AZ_SPAN_FROM_STR(SAMPLE_DEVICE_INFORMATION_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed writting component name.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_MANUFACTURER_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_VALUE to payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_MODEL_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MODEL_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_MODEL_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MODEL_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME to payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_VERSION_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_VERSION_PROPERTY_VALUE to payload. ");
@ -398,25 +448,40 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_OS_NAME_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_OS_NAME_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_ARCHITECTURE_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_ARCHITECTURE_PROPERTY_VALUE to payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_ARCHITECTURE_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(
&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_STORAGE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(&jw, SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_STORAGE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(
&jw, SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_MEMORY_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(&jw, SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_MEMORY_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(
&jw, SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE to payload. ");
rc = az_iot_hub_client_properties_writer_end_component(hub_client, &jw);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed closing component object.");
@ -434,21 +499,26 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
payload_buffer[az_span_size(payload_buffer_span)] = null_terminator;
*payload_buffer_length = az_span_size(payload_buffer_span);
return RESULT_OK;
}
static int generate_properties_update_response(
azure_iot_t* azure_iot,
az_span component_name, int32_t frequency, int32_t version,
uint8_t* buffer, size_t buffer_size, size_t* response_length)
azure_iot_t* azure_iot,
az_span component_name,
int32_t frequency,
int32_t version,
uint8_t* buffer,
size_t buffer_size,
size_t* response_length)
{
az_result azrc;
az_json_writer jw;
az_span response = az_span_create(buffer, buffer_size);
azrc = az_json_writer_init(&jw, response, NULL);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed initializing json writer for properties update response.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed initializing json writer for properties update response.");
azrc = az_json_writer_append_begin_object(&jw);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed opening json in properties update response.");
@ -457,19 +527,21 @@ static int generate_properties_update_response(
// so az_iot_hub_client_properties_writer_begin_component is not needed.
azrc = az_iot_hub_client_properties_writer_begin_response_status(
&azure_iot->iot_hub_client,
&jw,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS),
(int32_t)AZ_IOT_STATUS_OK,
version,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_RESPONSE_SUCCESS));
&azure_iot->iot_hub_client,
&jw,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS),
(int32_t)AZ_IOT_STATUS_OK,
version,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_RESPONSE_SUCCESS));
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed appending status to properties update response.");
azrc = az_json_writer_append_int32(&jw, frequency);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed appending frequency value to properties update response.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed appending frequency value to properties update response.");
azrc = az_iot_hub_client_properties_writer_end_response_status(&azure_iot->iot_hub_client, &jw);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed closing status section in properties update response.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed closing status section in properties update response.");
// This Azure PnP Template does not have a named component,
// so az_iot_hub_client_properties_writer_end_component is not needed.
@ -483,8 +555,11 @@ static int generate_properties_update_response(
}
static int consume_properties_and_generate_response(
azure_iot_t* azure_iot, az_span properties,
uint8_t* buffer, size_t buffer_size, size_t* response_length)
azure_iot_t* azure_iot,
az_span properties,
uint8_t* buffer,
size_t buffer_size,
size_t* response_length)
{
int result;
az_json_reader jr;
@ -494,22 +569,27 @@ static int consume_properties_and_generate_response(
az_result azrc = az_json_reader_init(&jr, properties, NULL);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed initializing json reader for properties update.");
const az_iot_hub_client_properties_message_type message_type =
AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_WRITABLE_UPDATED;
const az_iot_hub_client_properties_message_type message_type
= AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_WRITABLE_UPDATED;
azrc = az_iot_hub_client_properties_get_properties_version(
&azure_iot->iot_hub_client, &jr, message_type, &version);
&azure_iot->iot_hub_client, &jr, message_type, &version);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed writable properties version.");
azrc = az_json_reader_init(&jr, properties, NULL);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed re-initializing json reader for properties update.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed re-initializing json reader for properties update.");
while (az_result_succeeded(
azrc = az_iot_hub_client_properties_get_next_component_property(
&azure_iot->iot_hub_client, &jr, message_type,
AZ_IOT_HUB_CLIENT_PROPERTY_WRITABLE, &component_name)))
azrc = az_iot_hub_client_properties_get_next_component_property(
&azure_iot->iot_hub_client,
&jr,
message_type,
AZ_IOT_HUB_CLIENT_PROPERTY_WRITABLE,
&component_name)))
{
if (az_json_token_is_text_equal(&jr.token, AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS)))
if (az_json_token_is_text_equal(
&jr.token, AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS)))
{
int32_t value;
azrc = az_json_reader_next_token(&jr);
@ -521,23 +601,28 @@ static int consume_properties_and_generate_response(
azure_pnp_set_telemetry_frequency((size_t)value);
result = generate_properties_update_response(
azure_iot, component_name, value, version, buffer, buffer_size, response_length);
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "generate_properties_update_response failed.");
azure_iot, component_name, value, version, buffer, buffer_size, response_length);
EXIT_IF_TRUE(
result != RESULT_OK, RESULT_ERROR, "generate_properties_update_response failed.");
}
else
{
LogError("Unexpected property received (%.*s).",
az_span_size(jr.token.slice), az_span_ptr(jr.token.slice));
LogError(
"Unexpected property received (%.*s).",
az_span_size(jr.token.slice),
az_span_ptr(jr.token.slice));
}
azrc = az_json_reader_next_token(&jr);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed moving to next json token of writable properties.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed moving to next json token of writable properties.");
azrc = az_json_reader_skip_children(&jr);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed skipping children of writable properties.");
azrc = az_json_reader_next_token(&jr);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed moving to next json token of writable properties (again).");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed moving to next json token of writable properties (again).");
}
return RESULT_OK;

Просмотреть файл

@ -5,7 +5,7 @@
* Azure_IoT_PnP_Template.cpp implements the IoT Plug and Play template
* specific for the Espressif ESP32 Azure IoT Kit board.
*/
#ifndef AZURE_IOT_PNP_TEMPLATE_H
#define AZURE_IOT_PNP_TEMPLATE_H
@ -20,7 +20,7 @@ void azure_pnp_init();
/*
* @brief Returns the model id of the IoT Plug and Play template implemented by this device.
* @remark Every IoT Plug and Play template has a model id that must be informed by the
* @remark Every IoT Plug and Play template has a model id that must be informed by the
* device during Azure IoT provisioning and connection with the Azure IoT Hub.
* @return az_span An `az_span` containing the model id implemented by this module.
*/
@ -28,19 +28,22 @@ const az_span azure_pnp_get_model_id();
/*
* @brief Sends the device description to Azure IoT Central.
* @remark Azure IoT Central expects the application to send a description of device and its capabilities.
* This function generates a description of the Espressif ESP32 Azure IoT Kit and sends it to
* Azure IoT Central.
* @remark Azure IoT Central expects the application to send a description of device and its
* capabilities. This function generates a description of the Espressif ESP32 Azure IoT Kit and
* sends it to Azure IoT Central.
*
* @param[in] azure_iot A pointer the azure_iot_t instance with the state of the Azure IoT client.
* @param[in] azure_iot A pointer the azure_iot_t instance with the state of the Azure IoT
* client.
* @param[in] request_id An unique identification number to correlate the response with when
* `on_properties_update_completed` (set in azure_iot_config_t) is invoked.
* `on_properties_update_completed` (set in azure_iot_config_t) is
* invoked.
* @return int 0 if the function succeeds, non-zero if any error occurs.
*/
int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id);
/*
* @brief Sets with which minimum frequency this module should send telemetry to Azure IoT Central.
* @brief Sets with which minimum frequency this module should send telemetry to Azure IoT
* Central.
* @remark `azure_pnp_send_telemetry` is used to send telemetry, but it will not send anything
* unless enough time has passed since the last telemetry has been published.
* This delay is defined internally by `telemetry_frequency_in_seconds`,
@ -52,32 +55,33 @@ int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id);
void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds);
/*
* @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT Central.
* @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT
* Central.
* @remark The IoT Plug and Play template implemented by this device is specific to the
* Espressif ESP32 Azure IoT Kit board, which contains several sensors.
* The template defines telemetry data points for temperature, humidity,
* pressure, altitude, luminosity, magnetic field, rolling and pitch angles,
* as well as acceleration. All of these data are read from the board sensors and sent to
* The template defines telemetry data points for temperature, humidity,
* pressure, altitude, luminosity, magnetic field, rolling and pitch angles,
* as well as acceleration. All of these data are read from the board sensors and sent to
* Azure IoT Central when `azure_pnp_send_telemetry` is called.
* This function must be called frequently enough, no slower than the frequency set
* with `azure_pnp_set_telemetry_frequency` (or the default frequency of 10 seconds).
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* with `azure_iot_init`.
*
*
* return int 0 on success, non-zero if any failure occurs.
*/
int azure_pnp_send_telemetry(azure_iot_t* azure_iot);
/*
* @brief Handles a command when it is received from Azure IoT Central.
* @remark This function will perform the task requested by the command received
* (if the command matches the expected name) and sends back a response to
* @remark This function will perform the task requested by the command received
* (if the command matches the expected name) and sends back a response to
* Azure IoT Central.
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* with `azure_iot_init`.
* @param[in] command_request The `command_request_t` instance containing the details of the
* @param[in] command_request The `command_request_t` instance containing the details of the
* device command.
*
* return int 0 on success, non-zero if any failure occurs.
@ -86,19 +90,22 @@ int azure_pnp_handle_command_request(azure_iot_t* azure_iot, command_request_t c
/*
* @brief Handles a payload with writable properties received from Azure IoT Central.
* @remark This function will consume the writable properties update received
* @remark This function will consume the writable properties update received
* and send back a response to Azure IoT Central.
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* with `azure_iot_init`.
* @param[in] properties Raw properties writable-properties payload received from Azure.
* @param[in] request_id The request ID of the response that is sent to the Azure IoT Central.
* In Azure IoT Plug and Play, a response to a writable-property update is
* itself a reported-property (device-side property) update, so it gets a
* a response from Azure with the same request ID provided here as argument.
* In Azure IoT Plug and Play, a response to a writable-property update
* is itself a reported-property (device-side property) update, so it gets a a response from Azure
* with the same request ID provided here as argument.
*
* return int 0 on success, non-zero if any failure occurs.
*/
int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span properties, uint32_t request_id);
int azure_pnp_handle_properties_update(
azure_iot_t* azure_iot,
az_span properties,
uint32_t request_id);
#endif // AZURE_IOT_PNP_TEMPLATE_H

Просмотреть файл

@ -2,12 +2,13 @@
// SPDX-License-Identifier: MIT
// Wifi
#define IOT_CONFIG_WIFI_SSID "SSID"
#define IOT_CONFIG_WIFI_PASSWORD "PWD"
#define IOT_CONFIG_WIFI_SSID "SSID"
#define IOT_CONFIG_WIFI_PASSWORD "PWD"
// Enable macro IOT_CONFIG_USE_X509_CERT to use an x509 certificate to authenticate the IoT device.
// The two main modes of authentication are through SAS tokens (automatically generated by the sample using the provided device symmetric key) or through x509 certificates.
// Please choose the appropriate option according to your device authentication mode.
// The two main modes of authentication are through SAS tokens (automatically generated by the
// sample using the provided device symmetric key) or through x509 certificates. Please choose the
// appropriate option according to your device authentication mode.
// #define IOT_CONFIG_USE_X509_CERT
@ -16,7 +17,7 @@
/*
* Please set the define IOT_CONFIG_DEVICE_CERT below with
* the content of your device x509 certificate.
*
*
* Example:
* #define IOT_CONFIG_DEVICE_CERT "-----BEGIN CERTIFICATE-----\r\n" \
* "MIIBJDCBywIUfeHrebBVa2eZAbouBgACp9R3BncwCgYIKoZIzj0EAwIwETEPMA0G\r\n" \
@ -26,7 +27,7 @@
* "YmGzdaHTb6P1W+p+jmc+jJn1MAoGCXqGSM49BAMCA0gAMEUCIEnbEMsAdGFroMwl\r\n" \
* "vTfQahwsxN3xink9z1gtirrjQlqDAiEAyU+6TUJcG6d9JF+uJqsLFpsbbF3IzGAw\r\n" \
* "yC+koNRC0MU=\r\n" \
* "-----END CERTIFICATE-----"
* "-----END CERTIFICATE-----"
*
*/
#define IOT_CONFIG_DEVICE_CERT "Device Certificate"
@ -34,7 +35,7 @@
/*
* Please set the define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY below with
* the content of your device x509 private key.
*
*
* Example:
*
* #define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY "-----BEGIN EC PRIVATE KEY-----\r\n" \
@ -42,31 +43,30 @@
* "AwEHoUQDQgAEU6nQoYbjgJvBwaeD6MyAYmOSDg0QhEdyyV337qrlIbDEKvFsn1El\r\n" \
* "yRabc4dNp2Jhs3Xh02+j9Vvqfo5nPoyZ9Q==\r\n" \
* "-----END EC PRIVATE KEY-----"
*
*
* Note the type of key may different in your case. Such as BEGIN PRIVATE KEY
* or BEGIN RSA PRIVATE KEY.
*
*/
*
*/
#define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY "Device Certificate Private Key"
#endif // IOT_CONFIG_USE_X509_CERT
// Azure IoT Central
#define DPS_ID_SCOPE "ID Scope"
#define IOT_CONFIG_DEVICE_ID "Device ID"
#define DPS_ID_SCOPE "ID Scope"
#define IOT_CONFIG_DEVICE_ID "Device ID"
// Use device key if not using certificates
#ifndef IOT_CONFIG_USE_X509_CERT
#define IOT_CONFIG_DEVICE_KEY "Device Key"
#define IOT_CONFIG_DEVICE_KEY "Device Key"
#endif // IOT_CONFIG_USE_X509_CERT
// User-agent (url-encoded) provided by the MQTT client to Azure IoT Services.
// When developing for your own Arduino-based platform,
// please update the suffix with the format '(ard;<platform>)' as an url-encoded string.
#define AZURE_SDK_CLIENT_USER_AGENT "c%2F" AZ_SDK_VERSION_STRING "(ard%3Besp32)"
#define AZURE_SDK_CLIENT_USER_AGENT "c%2F" AZ_SDK_VERSION_STRING "(ard%3Besp32)"
// Publish 1 message every 2 seconds.
#define TELEMETRY_FREQUENCY_IN_SECONDS 2
#define TELEMETRY_FREQUENCY_IN_SECONDS 2
// For how long the MQTT password (SAS token) is valid, in minutes.
// After that, the sample automatically generates a new password and re-connects.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -15,8 +15,8 @@
#ifndef AZURE_IOT_H
#define AZURE_IOT_H
#include <stdlib.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <az_core.h>
@ -38,8 +38,7 @@ typedef enum log_level_t_enum
{
log_level_info,
log_level_error
}
log_level_t;
} log_level_t;
typedef void (*log_function_t)(log_level_t log_level, char const* const format, ...);
@ -48,45 +47,43 @@ extern log_function_t default_logging_function;
#define set_logging_function(custom_logging_function) \
default_logging_function = custom_logging_function;
#define Log(level, message, ...) default_logging_function(level, message, ##__VA_ARGS__ )
#define LogInfo(message, ...) Log(log_level_info, message, ##__VA_ARGS__ )
#define LogError(message, ...) Log(log_level_error, message, ##__VA_ARGS__ )
#define Log(level, message, ...) default_logging_function(level, message, ##__VA_ARGS__)
#define LogInfo(message, ...) Log(log_level_info, message, ##__VA_ARGS__)
#define LogError(message, ...) Log(log_level_error, message, ##__VA_ARGS__)
#else
#define set_logging_function(custom_logging_function)
#define Log(level, message, ...)
#define set_logging_function(custom_logging_function)
#define Log(level, message, ...)
#define LogInfo(message, ...)
#define LogError(message, ...)
#endif // DISABLE_LOGGING
/* --- Azure Definitions --- */
#define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net"
#define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net"
#define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES 60
#define SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS 30
#define SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS 30
/*
* The structures below define a generic interface to abstract the interaction of this module,
* with any MQTT client used in the user application.
* The structures below define a generic interface to abstract the interaction of this module,
* with any MQTT client used in the user application.
*/
#define MQTT_QOS_AT_MOST_ONCE 0
#define MQTT_QOS_AT_MOST_ONCE 0
#define MQTT_QOS_AT_LEAST_ONCE 1
#define MQTT_QOS_EXACTLY_ONCE 2
#define MQTT_QOS_EXACTLY_ONCE 2
typedef enum mqtt_qos_t_enum
{
mqtt_qos_at_most_once = MQTT_QOS_AT_MOST_ONCE,
mqtt_qos_at_least_once = MQTT_QOS_AT_LEAST_ONCE,
mqtt_qos_exactly_once = MQTT_QOS_EXACTLY_ONCE
}
mqtt_qos_t;
} mqtt_qos_t;
/*
* @brief Defines a generic MQTT message to be exchanged between the AzureIoT layer
* and the user application.
* and the user application.
* @remark It uses azure-sdk-for-c's az_span construct, which is merely a structure that
* has a pointer to a buffer and its size. Messages without a payload will have
* the `payload` member set to AZ_SPAN_EMPTY.
@ -98,8 +95,7 @@ typedef struct mqtt_message_t_struct
az_span topic;
az_span payload;
mqtt_qos_t qos;
}
mqtt_message_t;
} mqtt_message_t;
/*
* @brief Configuration structure passed by `mqtt_client_init_function_t` to the user
@ -131,8 +127,7 @@ typedef struct mqtt_client_config_t_struct
* @brief Password to be provided in the CONNECT sent by the MQTT client.
*/
az_span password;
}
mqtt_client_config_t;
} mqtt_client_config_t;
/*
* @brief Generic pointer to the actual instance of the application MQTT client.
@ -142,70 +137,79 @@ typedef void* mqtt_client_handle_t;
/*
* @brief Function to initialize and connect an MQTT client.
* @remark When this function is called, it provides the information necessary to initialize a
* specific MQTT client (whichever is used by the user application). In this callback
* it is expected that the MQTT client will be created/initialized, started and that it
* start sending a CONNECT to the provided server.
* @remark When this function is called, it provides the information necessary to initialize
* a specific MQTT client (whichever is used by the user application). In this callback it is
* expected that the MQTT client will be created/initialized, started and that it start sending a
* CONNECT to the provided server.
*
* @param[in] mqtt_client_config An instance of mqtt_client_config_t containing all the
* information needed by the MQTT client to connect to the target server. Please see
* `mqtt_client_config_t` documentation for details.
* @param[out] mqtt_client_handle A pointer to the resulting "instance" of the MQTT client
* shall be saved in `mqtt_client_handle` for later use by the calling layer.
*
* @param[in] mqtt_client_config An instance of mqtt_client_config_t containing all the information
* needed by the MQTT client to connect to the target server.
* Please see `mqtt_client_config_t` documentation for details.
* @param[out] mqtt_client_handle A pointer to the resulting "instance" of the MQTT client shall
* be saved in `mqtt_client_handle` for later use by the calling layer.
*
* @return int 0 on success, non-zero if any failure occurs.
*/
typedef int (*mqtt_client_init_function_t)(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t* mqtt_client_handle);
typedef int (*mqtt_client_init_function_t)(
mqtt_client_config_t* mqtt_client_config,
mqtt_client_handle_t* mqtt_client_handle);
/*
* @brief Function to disconnect and deinitialize an MQTT client.
* @remark When this function is called the MQTT client instance referenced by `mqtt_client_handle` shall disconnect
* from the server and any functions of the MQTT client API that destroy the instance shall be called
* (so any allocated memory resources can be released).
* @remark When this function is called the MQTT client instance referenced by
* `mqtt_client_handle` shall disconnect from the server and any functions of the MQTT client API
* that destroy the instance shall be called (so any allocated memory resources can be released).
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously
* created with `mqtt_client_init_function_t` function.
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously created with
* `mqtt_client_init_function_t` function.
*
* @return int 0 on success, non-zero if any failure occurs.
* Returning non-zero results in the Azure IoT Client going into error state.
* Returning non-zero results in the Azure IoT Client going into
* error state.
*/
typedef int (*mqtt_client_deinit_function_t)(mqtt_client_handle_t mqtt_client_handle);
/*
* @brief Function to send an MQTT PUBLISH.
* @remark When this function is invoked, the caller expects the actual MQTT client (referenced by `mqtt_client_handle`)
* to invoke the appropriate function in the MQTT client API to publish an MQTT message.
* @remark When this function is invoked, the caller expects the actual MQTT client
* (referenced by `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to
* publish an MQTT message.
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously
* created with `mqtt_client_init_function_t` function.
* @param[in] mqtt_message A structure containing the topic name, payload and QoS to be
* used to publish an actual MQTT message.
*
* @param[in] mqtt_client_handle A pointer to the instance of the MQTT client previously created with
* `mqtt_client_init_function_t` function.
* @param[in] mqtt_message A structure containing the topic name, payload and QoS to be used to publish
* an actual MQTT message.
*
* @return int The packet ID on success, or NEGATIVE if any failure occurs.
* If the QoS in `mqtt_message` is:
* - AT LEAST ONCE, the Azure IoT client expects `azure_iot_mqtt_client_connected`
* to be called once the MQTT client receives a PUBACK.
* - AT MOST ONCE, there should be no PUBACK, so no further action is
* needed for this PUBLISH.
* - AT LEAST ONCE, the Azure IoT client expects
* `azure_iot_mqtt_client_connected` to be called once the MQTT client receives a PUBACK.
* - AT MOST ONCE, there should be no PUBACK, so no further
* action is needed for this PUBLISH.
*/
typedef int (*mqtt_client_publish_function_t)(mqtt_client_handle_t mqtt_client_handle, mqtt_message_t* mqtt_message);
typedef int (*mqtt_client_publish_function_t)(
mqtt_client_handle_t mqtt_client_handle,
mqtt_message_t* mqtt_message);
/*
* @brief Function to send an MQTT SUBSCRIBE.
* @remark When this function is invoked, Azure IoT client expects the actual MQTT client (referenced by
* `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to subscribe to
* an MQTT topic.
* @remark When this function is invoked, Azure IoT client expects the actual MQTT client
* (referenced by `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to
* subscribe to an MQTT topic.
*
* @param[in] topic The az_span with the string containing the complete MQTT topic name to subscribed to.
* This string is always NULL-terminated.
* @param[in] topic The az_span with the string containing the complete MQTT topic name
* to subscribed to. This string is always NULL-terminated.
* @param[in] qos MQTT QoS to be used for the topic subscription.
*
*
* @return int The packet ID of the subscription on success, or NEGATIVE if any failure occurs.
* Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called once the
* MQTT client receives a SUBACK.
*
* @return int The packet ID of the subscription on success, or NEGATIVE if any
* failure occurs. Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called
* once the MQTT client receives a SUBACK.
*/
typedef int (*mqtt_client_subscribe_function_t)(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos);
typedef int (*mqtt_client_subscribe_function_t)(
mqtt_client_handle_t mqtt_client_handle,
az_span topic,
mqtt_qos_t qos);
/*
* @brief Structure that consolidates all the abstracted MQTT functions.
@ -216,53 +220,69 @@ typedef struct mqtt_client_interface_t_struct
mqtt_client_deinit_function_t mqtt_client_deinit;
mqtt_client_publish_function_t mqtt_client_publish;
mqtt_client_subscribe_function_t mqtt_client_subscribe;
}
mqtt_client_interface_t;
} mqtt_client_interface_t;
/*
* @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords.
*
*
* @param[in] data Buffer containing the Base64-encoded content.
* @param[in] data_length Length of `data`.
* @param[in] decoded Buffer where to write the Base64-decoded content of `data`.
* @param[in] decoded_size Size of `decoded`.
* @param[out] decoded_length The final length of the Base64-decoded content written in
* @param[out] decoded_length The final length of the Base64-decoded content written in
* the `decoded` buffer.
*
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length);
typedef int (*base64_decode_function_t)(
uint8_t* data,
size_t data_length,
uint8_t* decoded,
size_t decoded_size,
size_t* decoded_length);
/*
* @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords.
*
*
* @param[in] data Buffer containing the Base64-decoded content.
* @param[in] data_length Length of `data`.
* @param[in] encoded Buffer where to write the Base64-encoded content of `data`.
* @param[in] encoded_size Size of `encoded`.
* @param[out] encoded_length The final length of the Base64-encoded content written in
* @param[out] encoded_length The final length of the Base64-encoded content written in
* the `encoded` buffer.
*
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
typedef int (*base64_encode_function_t)(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length);
typedef int (*base64_encode_function_t)(
uint8_t* data,
size_t data_length,
uint8_t* encoded,
size_t encoded_size,
size_t* encoded_length);
/*
* @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords.
*
*
* @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm.
* @param[in] key_length Length of `key`.
* @param[in] payload Buffer containing the data to be encrypted.
* @param[in] payload_size Size of `payload`.
* @param[in] encrypted_payload Buffer where to write the HMAC-SHA256 encrypted content of `payload`.
* @param[in] encrypted_payload Buffer where to write the HMAC-SHA256 encrypted content
* of `payload`.
* @param[in] encrypted_payload_size The size of the `encrypted_payload` buffer.
*
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
typedef int (*hmac_sha256_encryption_function_t)(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* encrypted_payload, size_t encrypted_payload_size);
typedef int (*hmac_sha256_encryption_function_t)(
const uint8_t* key,
size_t key_length,
const uint8_t* payload,
size_t payload_length,
uint8_t* encrypted_payload,
size_t encrypted_payload_size);
/*
* @brief Structure that consolidates all the data manipulation functions.
@ -272,14 +292,15 @@ typedef struct data_manipulation_functions_t_struct
base64_decode_function_t base64_decode;
base64_encode_function_t base64_encode;
hmac_sha256_encryption_function_t hmac_sha256_encrypt;
}
data_manipulation_functions_t;
} data_manipulation_functions_t;
/*
* @brief Defines the callback for notifying the completion of a reported properties update.
*
* @param[in] request_id Request ID provided by the caller when sending the reported properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code semantics).
*
* @param[in] request_id Request ID provided by the caller when sending the reported
* properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code
* semantics).
*
* @return Nothing.
*/
@ -287,9 +308,11 @@ typedef void (*properties_update_completed_t)(uint32_t request_id, az_iot_status
/*
* @brief Defines the callback for receiving a writable-properties update.
*
* @param[in] request_id Request ID provided by the caller when sending the reported properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code semantics).
*
* @param[in] request_id Request ID provided by the caller when sending the reported
* properties update.
* @param[in] status_code Result of the reported properties update (uses HTTP status code
* semantics).
*
* @return Nothing.
*/
@ -320,14 +343,13 @@ typedef struct command_request_t_struct
* @brief Optional payload sent by the caller for this command.
*/
az_span payload;
}
command_request_t;
} command_request_t;
/*
* @brief Defines the callback for receiving an IoT Plug and Play Command.
* @remark A response for this command MUST be provided to Azure by calling
* @remark A response for this command MUST be provided to Azure by calling
* `azure_iot_send_command_response`.
*
*
* @param[in] command An instance of `command_request_t` containing all the details of
* of the command received.
*
@ -347,7 +369,7 @@ typedef enum azure_iot_status_t_struct
/*
* @brief The client is in an intermediate state between disconnected and connected.
* @remark When using SAS-based authentication (default for Azure IoT Central), the client
* will automatically perform a reconnection with a new SAS token after the previous
* will automatically perform a reconnection with a new SAS token after the previous
* one expires, going back into `azure_iot_connecting` state briefly.
*/
azure_iot_connecting,
@ -358,19 +380,19 @@ typedef enum azure_iot_status_t_struct
/*
* @brief The Azure IoT client encountered some internal error and is no longer active.
* @remark This can be caused by:
* - Memory issues (not enough memory provided in `azure_iot_config_t`'s `data_buffer`);
* - Memory issues (not enough memory provided in `azure_iot_config_t`'s
* `data_buffer`);
* - Any failures reported by the application's MQTT client
* (through the abstracted interface) return values;
* - Any protocol errors returned by Azure IoT services.
* If not enough memory has been provided in `azure_iot_config_t`'s `data_buffer,
* please expand the size of that memory space.`
* Once the possible mitigations are applied stop the Azure IoT client
* Once the possible mitigations are applied stop the Azure IoT client
* by calling `azure_iot_stop` (which resets the client state) and restart it
* using `azure_iot_start`.
*/
azure_iot_error
}
azure_iot_status_t;
} azure_iot_status_t;
/*
* @brief Internal states of the Azure IoT client.
@ -398,8 +420,7 @@ typedef enum azure_iot_client_state_t_struct
azure_iot_state_ready,
azure_iot_state_refreshing_sas,
azure_iot_state_error
}
azure_iot_client_state_t;
} azure_iot_client_state_t;
/*
* @brief Structure that holds the configuration for the Azure IoT client.
@ -408,7 +429,7 @@ azure_iot_client_state_t;
* Also make sure that the instance of `azure_iot_config_t` (and its members) do not
* lose scope throughout the lifetime of the Azure IoT client.
* Most of the members of this structure use az_span for encapsulating a buffer and
* its size. For more details on az_span, please explore the code at
* its size. For more details on az_span, please explore the code at
* https://github.com/azure/azure-sdk-for-c.
*/
typedef struct azure_iot_config_t_struct
@ -498,29 +519,29 @@ typedef struct azure_iot_config_t_struct
* @brief Buffer with memory space to be used internally by Azure IoT client for its
* internal functions.
* @remark This buffer MUST be large enough to perform all the string manipulations done
* internally by the Azure IoT client, like MQTT client client id, username and password
* generation, as well as storing Azure IoT Hub fqdn and device id after device-provisioning
* is completed (if device-provisioning is used).
* The maximum size required depends on which services and authentication mode are used.
* If using device-provisioning with SAS-token authentication (as used with Azure IoT Central),
* this size must be at least:
* internally by the Azure IoT client, like MQTT client client id, username and
* password generation, as well as storing Azure IoT Hub fqdn and device id after
* device-provisioning is completed (if device-provisioning is used). The maximum size required
* depends on which services and authentication mode are used. If using device-provisioning with
* SAS-token authentication (as used with Azure IoT Central), this size must be at least:
* sizeof(data_buffer) >= ( lengthof(<iot-hub-fqdn>) + lengthof(<device-id>) +
* lengthof(<MQTT-clientid>) + lengthof(<MQTT-username>) +
* 2 * lengthof(<MQTT-password>) )
*
*
* Where:
* <MQTT-clientid> = <device-id> + '\0'
* <MQTT-username> = <iot-hub-fqdn> + '/' + lengthof(<device-id>) + '/' + '?' + <api-version> +
* "&DeviceClientType=" + urlenc(<user-agent>) + "&model-id=" + urlenc(<pnp-model-id>) + '\0'
* <api-version> = "api-version=<YYYY-MM-DD>"
* <MQTT-password>) = "SharedAccessSignature sr=" + <iot-hub-fqdn> + "%2Fdevices%2F" + <device-id> +
* "&sig=" + urlenc(<sha256-string>) + "&se=" + <expiration-time> + '\0'
* lengthof(<sha256-string>) <= lengthof(<64-char-string>)
* <expiration-time> = <10-digit-unix-time>
*
* Note: We use two times the length of <MQTT-password> given the internal operations needed to
* generate it.
*
* <MQTT-username> = <iot-hub-fqdn> + '/' + lengthof(<device-id>) + '/' + '?' +
* <api-version> +
* "&DeviceClientType=" + urlenc(<user-agent>) + "&model-id=" +
* urlenc(<pnp-model-id>) + '\0' <api-version> = "api-version=<YYYY-MM-DD>" <MQTT-password>) =
* "SharedAccessSignature sr=" + <iot-hub-fqdn> + "%2Fdevices%2F" + <device-id> +
* "&sig=" + urlenc(<sha256-string>) + "&se=" + <expiration-time>
* + '\0' lengthof(<sha256-string>) <= lengthof(<64-char-string>) <expiration-time> =
* <10-digit-unix-time>
*
* Note: We use two times the length of <MQTT-password> given the internal operations
* needed to generate it.
*
* Example:
* <iot-hub-fqdn> = "iotc-1a430cf3-6f05-4b84-965d-cb1385077966.azure-devices.net"
* <device-id> = "d1"
@ -529,13 +550,15 @@ typedef struct azure_iot_config_t_struct
* <api-version> = "api-version=2020-09-30"
* <expiration-time> = "1641251566"
* <user-agent> = "c%2F1.1.0-beta.1(FreeRTOS)"
*
* sizeof(data_buffer) >= 592 bytes (59 bytes + 2 bytes + 3 bytes + 190 bytes + 338 bytes, respectively)
*
* sizeof(data_buffer) >= 592 bytes (59 bytes + 2 bytes + 3 bytes + 190 bytes + 338
* bytes, respectively)
*/
az_span data_buffer;
/*
* @brief Set of functions to serve as interface between Azure IoT client and the user-application MQTT client.
* @brief Set of functions to serve as interface between Azure IoT client and the
* user-application MQTT client.
*/
mqtt_client_interface_t mqtt_client_interface;
@ -576,8 +599,7 @@ typedef struct azure_iot_config_t_struct
* `azure_iot_send_command_response`.
*/
command_request_received_t on_command_request_received;
}
azure_iot_config_t;
} azure_iot_config_t;
/*
* @brief Structure that holds the state of the Azure IoT client.
@ -599,15 +621,15 @@ typedef struct azure_iot_t_struct
uint32_t dps_retry_after_seconds;
uint32_t dps_last_query_time;
az_span dps_operation_id;
}
azure_iot_t;
} azure_iot_t;
/*
* @brief Initializes the azure_iot_t structure that holds the Azure IoT client state.
* @remark This function must be called only once per `azure_iot_t` instance,
* before any other function can be called using it.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the caller.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the
* caller.
* @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the
* configuration neeeded for the client to connect and work with
* the Azure IoT services.
@ -625,11 +647,12 @@ void azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config
* be called first, followed by a call to `azure_iot_start` so it can reconnect to
* the Azure IoT Hub again.
* Note: if device-provisioning is used, the device is provisioned only the first
* time a given `azure_iot_t` instance is started. Subsequent calls to
* time a given `azure_iot_t` instance is started. Subsequent calls to
* `azure_iot_start` will re-use the Azure IoT Hub FQDN and device ID previously
* provisioned.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the caller.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the
* caller.
* @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the
* configuration neeeded for the client to connect and work with
* the Azure IoT services.
@ -642,8 +665,9 @@ int azure_iot_start(azure_iot_t* azure_iot);
* @remark This function must be called once the user application wants to stop working and
* disconnect from the Azure IoT services. The same instance of `azure_iot_t` can be
* used again by the user application by calling `azure_iot_start`.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the caller.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` defined by the
* caller.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -653,23 +677,26 @@ int azure_iot_stop(azure_iot_t* azure_iot);
* @brief Gets the current state of the Azure IoT client.
* @remark The states informed are simplified for ease-of-use of this client, not reflecting
* all the detailed internal states possible within the Azure IoT client.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
*
* @return azure_iot_status_t One of four possible states as defined by `azure_iot_status_t`.
* Please see the `azure_iot_status_t` documentation above for details.
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously
* initialized by the caller.
*
* @return azure_iot_status_t One of four possible states as defined by
* `azure_iot_status_t`. Please see the `azure_iot_status_t` documentation above for details.
*/
azure_iot_status_t azure_iot_get_status(azure_iot_t* azure_iot);
/*
* @brief Causes the Azure IoT client to perform its tasks for connecting and working with Azure IoT services.
* @remark This function must be called frequently enough for the Azure IoT client to work properly.
* That frequency should be enough to respect the timeouts implemented by the Azure IoT services for
* its TCP connection and MQTT-protocol traffic with the client application.
* Calling it once within a main loop() function of most embedded implementations should be enough.
* The recommended minimum frequency is no less than once every 100 milliseconds.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @brief Causes the Azure IoT client to perform its tasks for connecting and working with
* Azure IoT services.
* @remark This function must be called frequently enough for the Azure IoT client to work
* properly. That frequency should be enough to respect the timeouts implemented by the Azure IoT
* services for its TCP connection and MQTT-protocol traffic with the client application. Calling it
* once within a main loop() function of most embedded implementations should be enough. The
* recommended minimum frequency is no less than once every 100 milliseconds.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously
* initialized by the caller.
*
* @return Nothing.
*/
@ -677,9 +704,11 @@ void azure_iot_do_work(azure_iot_t* azure_iot);
/*
* @brief Sends a telemetry payload to the Azure IoT Hub.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @param[in] message An az_span instance containing the buffer and size of the actual message to be sent.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
* @param[in] message An az_span instance containing the buffer and size of the actual
* message to be sent.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -688,14 +717,15 @@ int azure_iot_send_telemetry(azure_iot_t* azure_iot, az_span message);
/**
* @brief Sends a property update message to Azure IoT Hub.
*
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the
* Azure IoT client.
* @param[in] request_id An unique identification number to correlate the response with when
* @param[in] message An `az_span` with the message with the reported properties update
* (a JSON document formatted according to the DTDL specification).
* `message` gets passed as-is to the MQTT client publish function as the payload, so if
* your MQTT client expects a null-terminated string for payload, make sure `message` is
* a null-terminated string.
* `on_properties_update_completed` (set in azure_iot_config_t) is invoked.
* `message` gets passed as-is to the MQTT client publish function as
* the payload, so if your MQTT client expects a null-terminated string for payload, make sure
* `message` is a null-terminated string. `on_properties_update_completed` (set in
* azure_iot_config_t) is invoked.
*
* @return int 0 if the function succeeds, or non-zero if any failure occurs.
*/
@ -704,27 +734,33 @@ int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id
/**
* @brief Sends a property update message to Azure IoT Hub.
*
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] request_id The same `request_id` of the device command received from Azure IoT Hub.
* @param[in] response_status An HTTP-like code informing the success or failure of the command.
* A 202 will inform the command was accepted and succeeded.
* A 404 will inform the command received does not match the commands supported by
* this device application.
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of
* the Azure IoT client.
* @param[in] request_id The same `request_id` of the device command received from Azure
* IoT Hub.
* @param[in] response_status An HTTP-like code informing the success or failure of the
* command. A 202 will inform the command was accepted and succeeded. A 404 will inform the command
* received does not match the commands supported by this device application.
* @param[in] payload A custom payload to be sent in the device command response.
* This is expected to be a json content.
* If no payload is to be sent, please set it as AZ_SPAN_EMPTY.
*
* @return int 0 if the function succeeds, or non-zero if any failure occurs.
*/
int azure_iot_send_command_response(azure_iot_t* azure_iot, az_span request_id, uint16_t response_status, az_span payload);
int azure_iot_send_command_response(
azure_iot_t* azure_iot,
az_span request_id,
uint16_t response_status,
az_span payload);
/*
* @brief Informs the Azure IoT client that the MQTT client is connected.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_init` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has received
* a CONNACK from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* received a CONNACK from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -732,11 +768,12 @@ int azure_iot_mqtt_client_connected(azure_iot_t* azure_iot);
/*
* @brief Informs the Azure IoT client that the MQTT client is disconnected.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has disconnected
* from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit`
* callback (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* disconnected from the Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
@ -744,11 +781,12 @@ int azure_iot_mqtt_client_disconnected(azure_iot_t* azure_iot);
/*
* @brief Informs the Azure IoT client that the MQTT client has subscribed to a topic.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_subscribe` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* received a SUBACK for a topic subscription.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_subscribe`
* callback (provided in the azure_iot_config_t instance) so it knows the MQTT client has received a
* SUBACK for a topic subscription.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
* @param[in] packet_id The ID of the subscription performed previous by the Azure IoT client.
*
* @return int 0 on success, or non-zero if any failure occurs.
@ -757,13 +795,14 @@ int azure_iot_mqtt_client_subscribe_completed(azure_iot_t* azure_iot, int packet
/*
* @brief Informs the Azure IoT client that the MQTT client has completed a PUBLISH.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_publish` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* completed an MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by
* the user application right after `mqtt_client_publish` is invoked. If the QoS of
* is 1 (AT LEAST ONCE), this shall be called whenever a PUBACK is received.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_publish`
* callback (provided in the azure_iot_config_t instance) so it knows the MQTT client has completed
* an MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by the user application
* right after `mqtt_client_publish` is invoked. If the QoS of is 1 (AT LEAST ONCE), this shall be
* called whenever a PUBACK is received.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by
* the caller.
* @param[in] packet_id The ID of the subscription performed previous by the Azure IoT client.
*
* @return int 0 on success, or non-zero if any failure occurs.
@ -771,42 +810,48 @@ int azure_iot_mqtt_client_subscribe_completed(azure_iot_t* azure_iot, int packet
int azure_iot_mqtt_client_publish_completed(azure_iot_t* azure_iot, int packet_id);
/*
* @brief Informs the Azure IoT client that a new message has been received by the Azure IoT service.
* @brief Informs the Azure IoT client that a new message has been received by the Azure IoT
* service.
* @remark This must be called whenever an MQTT message is received from an Azure IoT service.
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
* @param[in] mqtt_message A `mqtt_message_t` instance containing all the details of the MQTT message
* received (topic name, qos and payload).
*
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized
* by the caller.
* @param[in] mqtt_message A `mqtt_message_t` instance containing all the details of the MQTT
* message received (topic name, qos and payload).
*
* @return int 0 on success, or non-zero if any failure occurs.
*/
int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_t* mqtt_message);
/* --- az_core extensions --- */
/*
* These functions are used internally by the Azure IoT client code and its extensions.
*/
/**
* @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to `remainder`.
* @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to
* `remainder`.
*
* @param[in] span A span to be sliced.
* @param[in] source The span to copy the contents from.
* @param[out] remainder The pointer where to store the remainder of `span` after it is sliced.
* @param[out] remainder The pointer where to store the remainder of `span` after it is
* sliced.
*
* @return az_span A slice of `span` from position zero to `size`.
*/
az_span split_az_span(az_span span, int32_t size, az_span* remainder);
/**
* @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the second through `remainder`.
* @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the
* second through `remainder`.
*
* @param[in] destination A span large enough to contain the copy of the contents of `source`.
* @param[in] source The span to copy the contents from.
* @param[out] remainder The pointer where to store the remainder of `destination` after `source` is copied.
* @param[out] remainder The pointer where to store the remainder of `destination` after
* `source` is copied.
*
* @return az_span A slice of `destination` with the same size as `source`, with `source`'s content copied over.
* @return az_span A slice of `destination` with the same size as `source`, with
* `source`'s content copied over.
*/
static az_span slice_and_copy_az_span(az_span destination, az_span source, az_span* remainder);

Просмотреть файл

@ -6,38 +6,39 @@
* This sample depends on the following Arduino library:
* "Espressif ESP32 Azure IoT Kit Sensors" (by Ewerton Scaboro da Silva).
* Please install it before proceeding.
*
*
* This is an Arduino-based Azure IoT Central sample specific for the Espressif ESP32 Azure IoT Kit board.
* It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c and https://azureiotcentral.com/.
*
*
*
* This is an Arduino-based Azure IoT Central sample specific for the Espressif ESP32 Azure IoT Kit
* board. It uses our Azure Embedded SDK for C to help interact with Azure IoT. For reference,
* please visit https://github.com/azure/azure-sdk-for-c and https://azureiotcentral.com/.
*
* To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is an MQTT client support library, helping composing and parsing the
* MQTT topic names and messages exchanged with the Azure IoT Hub.
*
*
* The additional layers in this sketch provide a structured use of azure-sdk-for-c and
* the MQTT client of your choice to perform all the steps needed to connect and interact with
* the MQTT client of your choice to perform all the steps needed to connect and interact with
* Azure IoT Central.
*
*
* AzureIoT.cpp contains a state machine that implements those steps, plus abstractions to simplify
* its overall use. Besides the basic configuration needed to access the Azure IoT services,
* all that is needed is to provide the functions required by that layer to:
* - Interact with your MQTT client,
* - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding),
* - Receive the callbacks for Plug and Play properties and commands.
*
*
* Azure_IoT_PnP_Template.cpp contains the actual implementation of the IoT Plug and Play template
* specific for the Espressif ESP32 Azure IoT Kit board.
*
* To properly connect to your Azure IoT services, please fill the information in the `iot_configs.h` file.
*
* To properly connect to your Azure IoT services, please fill the information in the
* `iot_configs.h` file.
*/
/* --- Dependencies --- */
// C99 libraries
#include <cstdlib>
#include <cstdarg>
#include <cstdlib>
#include <string.h>
#include <time.h>
@ -55,20 +56,20 @@
#include <az_iot.h>
#include <azure_ca.h>
// Additional sample headers
// Additional sample headers
#include "AzureIoT.h"
#include "Azure_IoT_PnP_Template.h"
#include "iot_configs.h"
/* --- Sample-specific Settings --- */
#define SERIAL_LOGGER_BAUD_RATE 115200
#define MQTT_DO_NOT_RETAIN_MSG 0
#define MQTT_DO_NOT_RETAIN_MSG 0
/* --- Time and NTP Settings --- */
#define NTP_SERVERS "pool.ntp.org", "time.nist.gov"
#define PST_TIME_ZONE -8
#define PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF 1
#define PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF 1
#define GMT_OFFSET_SECS (PST_TIME_ZONE * 3600)
#define GMT_OFFSET_SECS_DST ((PST_TIME_ZONE + PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF) * 3600)
@ -77,8 +78,8 @@
#define UNIX_EPOCH_START_YEAR 1900
/* --- Function Returns --- */
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
/* --- Handling iot_config.h Settings --- */
static const char* wifi_ssid = IOT_CONFIG_WIFI_SSID;
@ -107,21 +108,23 @@ static uint8_t az_iot_data_buffer[AZ_IOT_DATA_BUFFER_SIZE];
static uint32_t properties_request_id = 0;
static bool send_device_info = true;
/* --- MQTT Interface Functions --- */
/*
* These functions are used by Azure IoT to interact with whatever MQTT client used by the sample
* (in this case, Espressif's ESP MQTT). Please see the documentation in AzureIoT.h for more details.
* (in this case, Espressif's ESP MQTT). Please see the documentation in AzureIoT.h for more
* details.
*/
/*
* See the documentation of `mqtt_client_init_function_t` in AzureIoT.h for details.
*/
static int mqtt_client_init_function(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t *mqtt_client_handle)
static int mqtt_client_init_function(
mqtt_client_config_t* mqtt_client_config,
mqtt_client_handle_t* mqtt_client_handle)
{
int result;
esp_mqtt_client_config_t mqtt_config;
memset(&mqtt_config, 0, sizeof(mqtt_config));
memset(&mqtt_config, 0, sizeof(mqtt_config));
az_span mqtt_broker_uri_span = AZ_SPAN_FROM_BUFFER(mqtt_broker_uri);
mqtt_broker_uri_span = az_span_copy(mqtt_broker_uri_span, AZ_SPAN_FROM_STR(MQTT_PROTOCOL_PREFIX));
@ -133,13 +136,13 @@ static int mqtt_client_init_function(mqtt_client_config_t* mqtt_client_config, m
mqtt_config.client_id = (const char*)az_span_ptr(mqtt_client_config->client_id);
mqtt_config.username = (const char*)az_span_ptr(mqtt_client_config->username);
#ifdef IOT_CONFIG_USE_X509_CERT
LogInfo("MQTT client using X509 Certificate authentication");
mqtt_config.client_cert_pem = IOT_CONFIG_DEVICE_CERT;
mqtt_config.client_key_pem = IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY;
#else // Using SAS key
mqtt_config.password = (const char*)az_span_ptr(mqtt_client_config->password);
#endif
#ifdef IOT_CONFIG_USE_X509_CERT
LogInfo("MQTT client using X509 Certificate authentication");
mqtt_config.client_cert_pem = IOT_CONFIG_DEVICE_CERT;
mqtt_config.client_key_pem = IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY;
#else // Using SAS key
mqtt_config.password = (const char*)az_span_ptr(mqtt_client_config->password);
#endif
mqtt_config.keepalive = 30;
mqtt_config.disable_clean_session = 0;
@ -159,7 +162,7 @@ static int mqtt_client_init_function(mqtt_client_config_t* mqtt_client_config, m
else
{
esp_err_t start_result = esp_mqtt_client_start(mqtt_client);
if (start_result != ESP_OK)
{
LogError("esp_mqtt_client_start failed (error code: 0x%08x).", start_result);
@ -197,7 +200,7 @@ static int mqtt_client_deinit_function(mqtt_client_handle_t mqtt_client_handle)
if (azure_iot_mqtt_client_disconnected(&azure_iot) != 0)
{
LogError("Failed updating azure iot client of MQTT disconnection.");
LogError("Failed updating azure iot client of MQTT disconnection.");
}
return 0;
@ -206,13 +209,18 @@ static int mqtt_client_deinit_function(mqtt_client_handle_t mqtt_client_handle)
/*
* See the documentation of `mqtt_client_subscribe_function_t` in AzureIoT.h for details.
*/
static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos)
static int mqtt_client_subscribe_function(
mqtt_client_handle_t mqtt_client_handle,
az_span topic,
mqtt_qos_t qos)
{
LogInfo("MQTT client subscribing to '%.*s'", az_span_size(topic), az_span_ptr(topic));
// As per documentation, `topic` always ends with a null-terminator.
// esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion is needed.
int packet_id = esp_mqtt_client_subscribe((esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)az_span_ptr(topic), (int)qos);
// esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion
// is needed.
int packet_id = esp_mqtt_client_subscribe(
(esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)az_span_ptr(topic), (int)qos);
return packet_id;
}
@ -220,18 +228,20 @@ static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handl
/*
* See the documentation of `mqtt_client_publish_function_t` in AzureIoT.h for details.
*/
static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle, mqtt_message_t* mqtt_message)
static int mqtt_client_publish_function(
mqtt_client_handle_t mqtt_client_handle,
mqtt_message_t* mqtt_message)
{
LogInfo("MQTT client publishing to '%s'", az_span_ptr(mqtt_message->topic));
int mqtt_result = esp_mqtt_client_publish(
(esp_mqtt_client_handle_t)mqtt_client_handle,
(const char*)az_span_ptr(mqtt_message->topic), // topic is always null-terminated.
(const char*)az_span_ptr(mqtt_message->payload),
az_span_size(mqtt_message->payload),
(int)mqtt_message->qos,
MQTT_DO_NOT_RETAIN_MSG);
(esp_mqtt_client_handle_t)mqtt_client_handle,
(const char*)az_span_ptr(mqtt_message->topic), // topic is always null-terminated.
(const char*)az_span_ptr(mqtt_message->payload),
az_span_size(mqtt_message->payload),
(int)mqtt_message->qos,
MQTT_DO_NOT_RETAIN_MSG);
if (mqtt_result == -1)
{
return RESULT_ERROR;
@ -247,7 +257,13 @@ static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle,
/*
* See the documentation of `hmac_sha256_encryption_function_t` in AzureIoT.h for details.
*/
static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* signed_payload, size_t signed_payload_size)
static int mbedtls_hmac_sha256(
const uint8_t* key,
size_t key_length,
const uint8_t* payload,
size_t payload_length,
uint8_t* signed_payload,
size_t signed_payload_size)
{
(void)signed_payload_size;
mbedtls_md_context_t ctx;
@ -266,7 +282,12 @@ static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint
/*
* See the documentation of `base64_decode_function_t` in AzureIoT.h for details.
*/
static int base64_decode(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length)
static int base64_decode(
uint8_t* data,
size_t data_length,
uint8_t* decoded,
size_t decoded_size,
size_t* decoded_length)
{
return mbedtls_base64_decode(decoded, decoded_size, decoded_length, data, data_length);
}
@ -274,7 +295,12 @@ static int base64_decode(uint8_t* data, size_t data_length, uint8_t* decoded, si
/*
* See the documentation of `base64_encode_function_t` in AzureIoT.h for details.
*/
static int base64_encode(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length)
static int base64_encode(
uint8_t* data,
size_t data_length,
uint8_t* encoded,
size_t encoded_size,
size_t* encoded_length)
{
return mbedtls_base64_encode(encoded, encoded_size, encoded_length, data, data_length);
}
@ -306,17 +332,22 @@ void on_properties_received(az_span properties)
* See the documentation of `command_request_received_t` in AzureIoT.h for details.
*/
static void on_command_request_received(command_request_t command)
{
az_span component_name = az_span_size(command.component_name) == 0 ? AZ_SPAN_FROM_STR("") : command.component_name;
LogInfo("Command request received (id=%.*s, component=%.*s, name=%.*s)",
az_span_size(command.request_id), az_span_ptr(command.request_id),
az_span_size(component_name), az_span_ptr(component_name),
az_span_size(command.command_name), az_span_ptr(command.command_name));
{
az_span component_name
= az_span_size(command.component_name) == 0 ? AZ_SPAN_FROM_STR("") : command.component_name;
LogInfo(
"Command request received (id=%.*s, component=%.*s, name=%.*s)",
az_span_size(command.request_id),
az_span_ptr(command.request_id),
az_span_size(component_name),
az_span_ptr(component_name),
az_span_size(command.command_name),
az_span_ptr(command.command_name));
// Here the request is being processed within the callback that delivers the command request.
// However, for production application the recommendation is to save `command` and process it outside
// this callback, usually inside the main thread/task/loop.
// However, for production application the recommendation is to save `command` and process it
// outside this callback, usually inside the main thread/task/loop.
(void)azure_pnp_handle_command_request(&azure_iot, command);
}
@ -331,8 +362,8 @@ void setup()
azure_pnp_init();
/*
* The configuration structure used by Azure IoT must remain unchanged (including data buffer)
/*
* The configuration structure used by Azure IoT must remain unchanged (including data buffer)
* throughout the lifetime of the sample. This variable must also not lose context so other
* components do not overwrite any information within this structure.
*/
@ -342,18 +373,20 @@ void setup()
azure_iot_config.iot_hub_fqdn = AZ_SPAN_EMPTY;
azure_iot_config.device_id = AZ_SPAN_EMPTY;
#ifdef IOT_CONFIG_USE_X509_CERT
azure_iot_config.device_certificate = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT);
azure_iot_config.device_certificate_private_key = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY);
azure_iot_config.device_key = AZ_SPAN_EMPTY;
#else
azure_iot_config.device_certificate = AZ_SPAN_EMPTY;
azure_iot_config.device_certificate_private_key = AZ_SPAN_EMPTY;
azure_iot_config.device_key = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_KEY);
#endif // IOT_CONFIG_USE_X509_CERT
#ifdef IOT_CONFIG_USE_X509_CERT
azure_iot_config.device_certificate = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT);
azure_iot_config.device_certificate_private_key
= AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY);
azure_iot_config.device_key = AZ_SPAN_EMPTY;
#else
azure_iot_config.device_certificate = AZ_SPAN_EMPTY;
azure_iot_config.device_certificate_private_key = AZ_SPAN_EMPTY;
azure_iot_config.device_key = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_KEY);
#endif // IOT_CONFIG_USE_X509_CERT
azure_iot_config.dps_id_scope = AZ_SPAN_FROM_STR(DPS_ID_SCOPE);
azure_iot_config.dps_registration_id = AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_ID); // Use Device ID for Azure IoT Central.
azure_iot_config.dps_registration_id
= AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_ID); // Use Device ID for Azure IoT Central.
azure_iot_config.data_buffer = AZ_SPAN_FROM_BUFFER(az_iot_data_buffer);
azure_iot_config.sas_token_lifetime_in_minutes = MQTT_PASSWORD_LIFETIME_IN_MINUTES;
azure_iot_config.mqtt_client_interface.mqtt_client_init = mqtt_client_init_function;
@ -382,22 +415,22 @@ void loop()
}
else
{
switch(azure_iot_get_status(&azure_iot))
switch (azure_iot_get_status(&azure_iot))
{
case azure_iot_connected:
if (send_device_info)
{
(void)azure_pnp_send_device_info(&azure_iot, properties_request_id++);
send_device_info = false; // Only need to send once.
send_device_info = false; // Only need to send once.
}
else if (azure_pnp_send_telemetry(&azure_iot) != 0)
{
LogError("Failed sending telemetry.");
LogError("Failed sending telemetry.");
}
break;
case azure_iot_error:
LogError("Azure IoT client is in error state." );
LogError("Azure IoT client is in error state.");
azure_iot_stop(&azure_iot);
WiFi.disconnect();
break;
@ -409,12 +442,11 @@ void loop()
}
}
/* === Function Implementations === */
/*
* These are support functions used by the sample itself to perform its basic tasks
* of connecting to the internet, syncing the board clock, ESP MQTT client event handler
* of connecting to the internet, syncing the board clock, ESP MQTT client event handler
* and logging.
*/
@ -460,37 +492,39 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
case MQTT_EVENT_ERROR:
LogError("MQTT client in ERROR state.");
LogError(
"esp_tls_stack_err=%d; esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_code=%d",
event->error_handle->esp_tls_stack_err,
event->error_handle->esp_tls_cert_verify_flags,
event->error_handle->esp_transport_sock_errno,
event->error_handle->error_type,
event->error_handle->connect_return_code);
LogError(
"esp_tls_stack_err=%d; "
"esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_"
"code=%d",
event->error_handle->esp_tls_stack_err,
event->error_handle->esp_tls_cert_verify_flags,
event->error_handle->esp_transport_sock_errno,
event->error_handle->error_type,
event->error_handle->connect_return_code);
switch (event->error_handle->connect_return_code)
switch (event->error_handle->connect_return_code)
{
case MQTT_CONNECTION_ACCEPTED:
LogError("connect_return_code=MQTT_CONNECTION_ACCEPTED");
break;
case MQTT_CONNECTION_REFUSE_PROTOCOL:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_PROTOCOL");
break;
case MQTT_CONNECTION_REFUSE_ID_REJECTED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_ID_REJECTED");
break;
case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE");
break;
case MQTT_CONNECTION_REFUSE_BAD_USERNAME:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_BAD_USERNAME");
break;
case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED");
break;
default:
LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code);
break;
case MQTT_CONNECTION_ACCEPTED:
LogError("connect_return_code=MQTT_CONNECTION_ACCEPTED");
break;
case MQTT_CONNECTION_REFUSE_PROTOCOL:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_PROTOCOL");
break;
case MQTT_CONNECTION_REFUSE_ID_REJECTED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_ID_REJECTED");
break;
case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE");
break;
case MQTT_CONNECTION_REFUSE_BAD_USERNAME:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_BAD_USERNAME");
break;
case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED:
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED");
break;
default:
LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code);
break;
};
break;
@ -539,11 +573,15 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
mqtt_message_t mqtt_message;
mqtt_message.topic = az_span_create((uint8_t*)event->topic, event->topic_len);
mqtt_message.payload = az_span_create((uint8_t*)event->data, event->data_len);
mqtt_message.qos = mqtt_qos_at_most_once; // QoS is unused by azure_iot_mqtt_client_message_received.
mqtt_message.qos
= mqtt_qos_at_most_once; // QoS is unused by azure_iot_mqtt_client_message_received.
if (azure_iot_mqtt_client_message_received(&azure_iot, &mqtt_message) != 0)
{
LogError("azure_iot_mqtt_client_message_received failed (topic=%.*s).", event->topic_len, event->topic);
LogError(
"azure_iot_mqtt_client_message_received failed (topic=%.*s).",
event->topic_len,
event->topic);
}
break;

Просмотреть файл

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include <stdlib.h>
#include <stdarg.h>
#include <stdlib.h>
#include <az_core.h>
#include <az_iot.h>
@ -16,67 +16,67 @@
/* --- Defines --- */
#define AZURE_PNP_MODEL_ID "dtmi:azureiot:devkit:freertos:Esp32AzureIotKit;1"
#define SAMPLE_DEVICE_INFORMATION_NAME "deviceInformation"
#define SAMPLE_MANUFACTURER_PROPERTY_NAME "manufacturer"
#define SAMPLE_MODEL_PROPERTY_NAME "model"
#define SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME "swVersion"
#define SAMPLE_OS_NAME_PROPERTY_NAME "osName"
#define SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME "processorArchitecture"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME "processorManufacturer"
#define SAMPLE_TOTAL_STORAGE_PROPERTY_NAME "totalStorage"
#define SAMPLE_TOTAL_MEMORY_PROPERTY_NAME "totalMemory"
#define SAMPLE_DEVICE_INFORMATION_NAME "deviceInformation"
#define SAMPLE_MANUFACTURER_PROPERTY_NAME "manufacturer"
#define SAMPLE_MODEL_PROPERTY_NAME "model"
#define SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME "swVersion"
#define SAMPLE_OS_NAME_PROPERTY_NAME "osName"
#define SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME "processorArchitecture"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME "processorManufacturer"
#define SAMPLE_TOTAL_STORAGE_PROPERTY_NAME "totalStorage"
#define SAMPLE_TOTAL_MEMORY_PROPERTY_NAME "totalMemory"
#define SAMPLE_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
#define SAMPLE_MODEL_PROPERTY_VALUE "ESP32 Azure IoT Kit"
#define SAMPLE_VERSION_PROPERTY_VALUE "1.0.0"
#define SAMPLE_OS_NAME_PROPERTY_VALUE "FreeRTOS"
#define SAMPLE_ARCHITECTURE_PROPERTY_VALUE "ESP32 WROVER-B"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
#define SAMPLE_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
#define SAMPLE_MODEL_PROPERTY_VALUE "ESP32 Azure IoT Kit"
#define SAMPLE_VERSION_PROPERTY_VALUE "1.0.0"
#define SAMPLE_OS_NAME_PROPERTY_VALUE "FreeRTOS"
#define SAMPLE_ARCHITECTURE_PROPERTY_VALUE "ESP32 WROVER-B"
#define SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE "ESPRESSIF"
// The next couple properties are in KiloBytes.
#define SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE 4096
#define SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE 8192
#define SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE 4096
#define SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE 8192
#define TELEMETRY_PROP_NAME_TEMPERATURE "temperature"
#define TELEMETRY_PROP_NAME_HUMIDITY "humidity"
#define TELEMETRY_PROP_NAME_LIGHT "light"
#define TELEMETRY_PROP_NAME_PRESSURE "pressure"
#define TELEMETRY_PROP_NAME_ALTITUDE "altitude"
#define TELEMETRY_PROP_NAME_MAGNETOMETERX "magnetometerX"
#define TELEMETRY_PROP_NAME_MAGNETOMETERY "magnetometerY"
#define TELEMETRY_PROP_NAME_MAGNETOMETERZ "magnetometerZ"
#define TELEMETRY_PROP_NAME_PITCH "pitch"
#define TELEMETRY_PROP_NAME_ROLL "roll"
#define TELEMETRY_PROP_NAME_ACCELEROMETERX "accelerometerX"
#define TELEMETRY_PROP_NAME_ACCELEROMETERY "accelerometerY"
#define TELEMETRY_PROP_NAME_ACCELEROMETERZ "accelerometerZ"
#define TELEMETRY_PROP_NAME_TEMPERATURE "temperature"
#define TELEMETRY_PROP_NAME_HUMIDITY "humidity"
#define TELEMETRY_PROP_NAME_LIGHT "light"
#define TELEMETRY_PROP_NAME_PRESSURE "pressure"
#define TELEMETRY_PROP_NAME_ALTITUDE "altitude"
#define TELEMETRY_PROP_NAME_MAGNETOMETERX "magnetometerX"
#define TELEMETRY_PROP_NAME_MAGNETOMETERY "magnetometerY"
#define TELEMETRY_PROP_NAME_MAGNETOMETERZ "magnetometerZ"
#define TELEMETRY_PROP_NAME_PITCH "pitch"
#define TELEMETRY_PROP_NAME_ROLL "roll"
#define TELEMETRY_PROP_NAME_ACCELEROMETERX "accelerometerX"
#define TELEMETRY_PROP_NAME_ACCELEROMETERY "accelerometerY"
#define TELEMETRY_PROP_NAME_ACCELEROMETERZ "accelerometerZ"
static az_span COMMAND_NAME_TOGGLE_LED_1 = AZ_SPAN_FROM_STR("ToggleLed1");
static az_span COMMAND_NAME_TOGGLE_LED_2 = AZ_SPAN_FROM_STR("ToggleLed2");
static az_span COMMAND_NAME_DISPLAY_TEXT = AZ_SPAN_FROM_STR("DisplayText");
#define COMMAND_RESPONSE_CODE_ACCEPTED 202
#define COMMAND_RESPONSE_CODE_REJECTED 404
#define COMMAND_RESPONSE_CODE_ACCEPTED 202
#define COMMAND_RESPONSE_CODE_REJECTED 404
#define WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS "telemetryFrequencySecs"
#define WRITABLE_PROPERTY_RESPONSE_SUCCESS "success"
#define WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS "telemetryFrequencySecs"
#define WRITABLE_PROPERTY_RESPONSE_SUCCESS "success"
#define DOUBLE_DECIMAL_PLACE_DIGITS 2
/* --- Function Checks and Returns --- */
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
#define RESULT_OK 0
#define RESULT_ERROR __LINE__
#define EXIT_IF_TRUE(condition, retcode, message, ...) \
do \
{ \
if (condition) \
{ \
LogError(message, ##__VA_ARGS__ ); \
return retcode; \
} \
#define EXIT_IF_TRUE(condition, retcode, message, ...) \
do \
{ \
if (condition) \
{ \
LogError(message, ##__VA_ARGS__); \
return retcode; \
} \
} while (0)
#define EXIT_IF_AZ_FAILED(azresult, retcode, message, ...) \
EXIT_IF_TRUE(az_result_failed(azresult), retcode, message, ##__VA_ARGS__ )
#define EXIT_IF_AZ_FAILED(azresult, retcode, message, ...) \
EXIT_IF_TRUE(az_result_failed(azresult), retcode, message, ##__VA_ARGS__)
/* --- Data --- */
#define DATA_BUFFER_SIZE 1024
@ -86,7 +86,7 @@ static uint32_t telemetry_send_count = 0;
static size_t telemetry_frequency_in_seconds = 10; // With default frequency of once in 10 seconds.
static time_t last_telemetry_send_time = INDEFINITE_TIME;
#define OLED_SPLASH_MESSAGE "Espressif ESP32 Azure IoT Kit + Central"
#define OLED_SPLASH_MESSAGE "Espressif ESP32 Azure IoT Kit + Central"
static bool led1_on = false;
static bool led2_on = false;
@ -94,13 +94,20 @@ static bool led2_on = false;
/* --- Function Prototypes --- */
/* Please find the function implementations at the bottom of this file */
static int generate_telemetry_payload(
uint8_t* payload_buffer, size_t payload_buffer_size, size_t* payload_buffer_length);
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length);
static int generate_device_info_payload(
az_iot_hub_client const* hub_client, uint8_t* payload_buffer,
size_t payload_buffer_size, size_t* payload_buffer_length);
az_iot_hub_client const* hub_client,
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length);
static int consume_properties_and_generate_response(
azure_iot_t* azure_iot, az_span properties,
uint8_t* buffer, size_t buffer_size, size_t* response_length);
azure_iot_t* azure_iot,
az_span properties,
uint8_t* buffer,
size_t buffer_size,
size_t* response_length);
/* --- Public Functions --- */
void azure_pnp_init()
@ -114,10 +121,7 @@ void azure_pnp_init()
esp32_azureiotkit_led2_set_state(LED_STATE_OFF);
}
const az_span azure_pnp_get_model_id()
{
return AZ_SPAN_FROM_STR(AZURE_PNP_MODEL_ID);
}
const az_span azure_pnp_get_model_id() { return AZ_SPAN_FROM_STR(AZURE_PNP_MODEL_ID); }
void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds)
{
@ -138,8 +142,9 @@ int azure_pnp_send_telemetry(azure_iot_t* azure_iot)
LogError("Failed getting current time for controlling telemetry.");
return RESULT_ERROR;
}
else if (last_telemetry_send_time == INDEFINITE_TIME ||
difftime(now, last_telemetry_send_time) >= telemetry_frequency_in_seconds)
else if (
last_telemetry_send_time == INDEFINITE_TIME
|| difftime(now, last_telemetry_send_time) >= telemetry_frequency_in_seconds)
{
size_t payload_size;
@ -166,12 +171,14 @@ int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id)
_az_PRECONDITION_NOT_NULL(azure_iot);
int result;
size_t length;
result = generate_device_info_payload(&azure_iot->iot_hub_client, data_buffer, DATA_BUFFER_SIZE, &length);
size_t length;
result = generate_device_info_payload(
&azure_iot->iot_hub_client, data_buffer, DATA_BUFFER_SIZE, &length);
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed generating telemetry payload.");
result = azure_iot_send_properties_update(azure_iot, request_id, az_span_create(data_buffer, length));
result = azure_iot_send_properties_update(
azure_iot, request_id, az_span_create(data_buffer, length));
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed sending reported properties update.");
return RESULT_OK;
@ -197,20 +204,29 @@ int azure_pnp_handle_command_request(azure_iot_t* azure_iot, command_request_t c
}
else if (az_span_is_content_equal(command.command_name, COMMAND_NAME_DISPLAY_TEXT))
{
// The payload comes surrounded by quotes, so to remove them we offset the payload by 1 and its size by 2.
esp32_azureiotkit_oled_show_message(az_span_ptr(command.payload) + 1, az_span_size(command.payload) - 2);
// The payload comes surrounded by quotes, so to remove them we offset the payload by 1 and its
// size by 2.
esp32_azureiotkit_oled_show_message(
az_span_ptr(command.payload) + 1, az_span_size(command.payload) - 2);
response_code = COMMAND_RESPONSE_CODE_ACCEPTED;
}
else
{
LogError("Command not recognized (%.*s).", az_span_size(command.command_name), az_span_ptr(command.command_name));
LogError(
"Command not recognized (%.*s).",
az_span_size(command.command_name),
az_span_ptr(command.command_name));
response_code = COMMAND_RESPONSE_CODE_REJECTED;
}
return azure_iot_send_command_response(azure_iot, command.request_id, response_code, AZ_SPAN_EMPTY);
return azure_iot_send_command_response(
azure_iot, command.request_id, response_code, AZ_SPAN_EMPTY);
}
int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span properties, uint32_t request_id)
int azure_pnp_handle_properties_update(
azure_iot_t* azure_iot,
az_span properties,
uint32_t request_id)
{
_az_PRECONDITION_NOT_NULL(azure_iot);
_az_PRECONDITION_VALID_SPAN(properties, 1, false);
@ -218,10 +234,13 @@ int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span propertie
int result;
size_t length;
result = consume_properties_and_generate_response(azure_iot, properties, data_buffer, DATA_BUFFER_SIZE, &length);
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed consuming/generating properties ack payload.");
result = consume_properties_and_generate_response(
azure_iot, properties, data_buffer, DATA_BUFFER_SIZE, &length);
EXIT_IF_TRUE(
result != RESULT_OK, RESULT_ERROR, "Failed consuming/generating properties ack payload.");
result = azure_iot_send_properties_update(azure_iot, request_id, az_span_create(data_buffer, length));
result = azure_iot_send_properties_update(
azure_iot, request_id, az_span_create(data_buffer, length));
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed sending reported properties update.");
return RESULT_OK;
@ -229,7 +248,10 @@ int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span propertie
/* --- Internal Functions --- */
static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_buffer_size, size_t* payload_buffer_length)
static int generate_telemetry_payload(
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length)
{
az_json_writer jw;
az_result rc;
@ -245,7 +267,8 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
light = esp32_azureiotkit_get_ambientLight();
esp32_azureiotkit_get_pressure_altitude(&pressure, &altitude);
esp32_azureiotkit_get_magnetometer(&magneticFieldX, &magneticFieldY, &magneticFieldZ);
esp32_azureiotkit_get_pitch_roll_accel(&pitch, &roll, &accelerationX, &accelerationY, &accelerationZ);
esp32_azureiotkit_get_pitch_roll_accel(
&pitch, &roll, &accelerationX, &accelerationY, &accelerationZ);
rc = az_json_writer_init(&jw, payload_buffer_span, NULL);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed initializing json writer for telemetry.");
@ -254,14 +277,17 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed setting telemetry json root.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_TEMPERATURE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding temperature property name to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding temperature property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, temperature, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding temperature property value to telemetry payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding temperature property value to telemetry payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_HUMIDITY));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding humidity property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, humidity, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding humidity property value to telemetry payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding humidity property value to telemetry payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_LIGHT));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding light property name to telemetry payload.");
@ -271,27 +297,38 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_PRESSURE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding pressure property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, pressure, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding pressure property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding pressure property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ALTITUDE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding altitude property name to telemetry payload.");
rc = az_json_writer_append_double(&jw, altitude, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding altitude property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding altitude property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERX));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(X) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERX));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(X) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, magneticFieldX);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(X) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(X) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERY));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Y) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERY));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Y) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, magneticFieldY);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Y) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Y) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERZ));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Z) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_MAGNETOMETERZ));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Z) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, magneticFieldZ);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding magnetometer(Z) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding magnetometer(Z) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_PITCH));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding pitch property name to telemetry payload.");
@ -303,20 +340,29 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
rc = az_json_writer_append_int32(&jw, roll);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding roll property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERX));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(X) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERX));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(X) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, accelerationX);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(X) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(X) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERY));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Y) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERY));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Y) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, accelerationY);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Y) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Y) property value to telemetry payload.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERZ));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Z) property name to telemetry payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(TELEMETRY_PROP_NAME_ACCELEROMETERZ));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Z) property name to telemetry payload.");
rc = az_json_writer_append_int32(&jw, accelerationZ);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding acceleration(Z) property value to telemetry payload.");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding acceleration(Z) property value to telemetry payload.");
rc = az_json_writer_append_end_object(&jw);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed closing telemetry json payload.");
@ -331,11 +377,15 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
payload_buffer[az_span_size(payload_buffer_span)] = null_terminator;
*payload_buffer_length = az_span_size(payload_buffer_span);
return RESULT_OK;
}
static int generate_device_info_payload(az_iot_hub_client const* hub_client, uint8_t* payload_buffer, size_t payload_buffer_size, size_t* payload_buffer_length)
static int generate_device_info_payload(
az_iot_hub_client const* hub_client,
uint8_t* payload_buffer,
size_t payload_buffer_size,
size_t* payload_buffer_length)
{
az_json_writer jw;
az_result rc;
@ -347,23 +397,28 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
rc = az_json_writer_append_begin_object(&jw);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed setting telemetry json root.");
rc = az_iot_hub_client_properties_writer_begin_component(
hub_client, &jw, AZ_SPAN_FROM_STR(SAMPLE_DEVICE_INFORMATION_NAME));
hub_client, &jw, AZ_SPAN_FROM_STR(SAMPLE_DEVICE_INFORMATION_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed writting component name.");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_MANUFACTURER_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_VALUE to payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_MANUFACTURER_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_MODEL_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MODEL_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_MODEL_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_MODEL_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME to payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_SOFTWARE_VERSION_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_VERSION_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_VERSION_PROPERTY_VALUE to payload. ");
@ -372,25 +427,40 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_OS_NAME_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_OS_NAME_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_ARCHITECTURE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_ARCHITECTURE_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_ARCHITECTURE_PROPERTY_VALUE to payload. ");
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_ARCHITECTURE_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_NAME to payload.");
rc = az_json_writer_append_string(
&jw, AZ_SPAN_FROM_STR(SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_PROCESSOR_MANUFACTURER_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_STORAGE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(&jw, SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_STORAGE_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(
&jw, SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_STORAGE_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_MEMORY_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(&jw, SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE to payload. ");
rc = az_json_writer_append_property_name(
&jw, AZ_SPAN_FROM_STR(SAMPLE_TOTAL_MEMORY_PROPERTY_NAME));
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_NAME to payload.");
rc = az_json_writer_append_double(
&jw, SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE, DOUBLE_DECIMAL_PLACE_DIGITS);
EXIT_IF_AZ_FAILED(
rc, RESULT_ERROR, "Failed adding SAMPLE_TOTAL_MEMORY_PROPERTY_VALUE to payload. ");
rc = az_iot_hub_client_properties_writer_end_component(hub_client, &jw);
EXIT_IF_AZ_FAILED(rc, RESULT_ERROR, "Failed closing component object.");
@ -408,21 +478,26 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
payload_buffer[az_span_size(payload_buffer_span)] = null_terminator;
*payload_buffer_length = az_span_size(payload_buffer_span);
return RESULT_OK;
}
static int generate_properties_update_response(
azure_iot_t* azure_iot,
az_span component_name, int32_t frequency, int32_t version,
uint8_t* buffer, size_t buffer_size, size_t* response_length)
azure_iot_t* azure_iot,
az_span component_name,
int32_t frequency,
int32_t version,
uint8_t* buffer,
size_t buffer_size,
size_t* response_length)
{
az_result azrc;
az_json_writer jw;
az_span response = az_span_create(buffer, buffer_size);
azrc = az_json_writer_init(&jw, response, NULL);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed initializing json writer for properties update response.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed initializing json writer for properties update response.");
azrc = az_json_writer_append_begin_object(&jw);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed opening json in properties update response.");
@ -431,19 +506,21 @@ static int generate_properties_update_response(
// so az_iot_hub_client_properties_writer_begin_component is not needed.
azrc = az_iot_hub_client_properties_writer_begin_response_status(
&azure_iot->iot_hub_client,
&jw,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS),
(int32_t)AZ_IOT_STATUS_OK,
version,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_RESPONSE_SUCCESS));
&azure_iot->iot_hub_client,
&jw,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS),
(int32_t)AZ_IOT_STATUS_OK,
version,
AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_RESPONSE_SUCCESS));
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed appending status to properties update response.");
azrc = az_json_writer_append_int32(&jw, frequency);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed appending frequency value to properties update response.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed appending frequency value to properties update response.");
azrc = az_iot_hub_client_properties_writer_end_response_status(&azure_iot->iot_hub_client, &jw);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed closing status section in properties update response.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed closing status section in properties update response.");
// This Azure PnP Template does not have a named component,
// so az_iot_hub_client_properties_writer_end_component is not needed.
@ -457,8 +534,11 @@ static int generate_properties_update_response(
}
static int consume_properties_and_generate_response(
azure_iot_t* azure_iot, az_span properties,
uint8_t* buffer, size_t buffer_size, size_t* response_length)
azure_iot_t* azure_iot,
az_span properties,
uint8_t* buffer,
size_t buffer_size,
size_t* response_length)
{
int result;
az_json_reader jr;
@ -468,22 +548,27 @@ static int consume_properties_and_generate_response(
az_result azrc = az_json_reader_init(&jr, properties, NULL);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed initializing json reader for properties update.");
const az_iot_hub_client_properties_message_type message_type =
AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_WRITABLE_UPDATED;
const az_iot_hub_client_properties_message_type message_type
= AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_WRITABLE_UPDATED;
azrc = az_iot_hub_client_properties_get_properties_version(
&azure_iot->iot_hub_client, &jr, message_type, &version);
&azure_iot->iot_hub_client, &jr, message_type, &version);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed writable properties version.");
azrc = az_json_reader_init(&jr, properties, NULL);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed re-initializing json reader for properties update.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed re-initializing json reader for properties update.");
while (az_result_succeeded(
azrc = az_iot_hub_client_properties_get_next_component_property(
&azure_iot->iot_hub_client, &jr, message_type,
AZ_IOT_HUB_CLIENT_PROPERTY_WRITABLE, &component_name)))
azrc = az_iot_hub_client_properties_get_next_component_property(
&azure_iot->iot_hub_client,
&jr,
message_type,
AZ_IOT_HUB_CLIENT_PROPERTY_WRITABLE,
&component_name)))
{
if (az_json_token_is_text_equal(&jr.token, AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS)))
if (az_json_token_is_text_equal(
&jr.token, AZ_SPAN_FROM_STR(WRITABLE_PROPERTY_TELEMETRY_FREQ_SECS)))
{
int32_t value;
azrc = az_json_reader_next_token(&jr);
@ -495,24 +580,29 @@ static int consume_properties_and_generate_response(
azure_pnp_set_telemetry_frequency((size_t)value);
result = generate_properties_update_response(
azure_iot, component_name, value, version, buffer, buffer_size, response_length);
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "generate_properties_update_response failed.");
azure_iot, component_name, value, version, buffer, buffer_size, response_length);
EXIT_IF_TRUE(
result != RESULT_OK, RESULT_ERROR, "generate_properties_update_response failed.");
}
else
{
LogError("Unexpected property received (%.*s).",
az_span_size(jr.token.slice), az_span_ptr(jr.token.slice));
return RESULT_ERROR;
LogError(
"Unexpected property received (%.*s).",
az_span_size(jr.token.slice),
az_span_ptr(jr.token.slice));
return RESULT_ERROR;
}
azrc = az_json_reader_next_token(&jr);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed moving to next json token of writable properties.");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed moving to next json token of writable properties.");
azrc = az_json_reader_skip_children(&jr);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed skipping children of writable properties.");
azrc = az_json_reader_next_token(&jr);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed moving to next json token of writable properties (again).");
EXIT_IF_AZ_FAILED(
azrc, RESULT_ERROR, "Failed moving to next json token of writable properties (again).");
}
return RESULT_OK;

Просмотреть файл

@ -5,7 +5,7 @@
* Azure_IoT_PnP_Template.cpp implements the IoT Plug and Play template
* specific for the Espressif ESP32 Azure IoT Kit board.
*/
#ifndef AZURE_IOT_PNP_TEMPLATE_H
#define AZURE_IOT_PNP_TEMPLATE_H
@ -20,7 +20,7 @@ void azure_pnp_init();
/*
* @brief Returns the model id of the IoT Plug and Play template implemented by this device.
* @remark Every IoT Plug and Play template has a model id that must be informed by the
* @remark Every IoT Plug and Play template has a model id that must be informed by the
* device during Azure IoT provisioning and connection with the Azure IoT Hub.
* @return az_span An `az_span` containing the model id implemented by this module.
*/
@ -28,19 +28,22 @@ const az_span azure_pnp_get_model_id();
/*
* @brief Sends the device description to Azure IoT Central.
* @remark Azure IoT Central expects the application to send a description of device and its capabilities.
* This function generates a description of the Espressif ESP32 Azure IoT Kit and sends it to
* Azure IoT Central.
* @remark Azure IoT Central expects the application to send a description of device and its
* capabilities. This function generates a description of the Espressif ESP32 Azure IoT Kit and
* sends it to Azure IoT Central.
*
* @param[in] azure_iot A pointer the azure_iot_t instance with the state of the Azure IoT client.
* @param[in] azure_iot A pointer the azure_iot_t instance with the state of the Azure IoT
* client.
* @param[in] request_id An unique identification number to correlate the response with when
* `on_properties_update_completed` (set in azure_iot_config_t) is invoked.
* `on_properties_update_completed` (set in azure_iot_config_t) is
* invoked.
* @return int 0 if the function succeeds, non-zero if any error occurs.
*/
int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id);
/*
* @brief Sets with which minimum frequency this module should send telemetry to Azure IoT Central.
* @brief Sets with which minimum frequency this module should send telemetry to Azure IoT
* Central.
* @remark `azure_pnp_send_telemetry` is used to send telemetry, but it will not send anything
* unless enough time has passed since the last telemetry has been published.
* This delay is defined internally by `telemetry_frequency_in_seconds`,
@ -52,32 +55,33 @@ int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id);
void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds);
/*
* @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT Central.
* @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT
* Central.
* @remark The IoT Plug and Play template implemented by this device is specific to the
* Espressif ESP32 Azure IoT Kit board, which contains several sensors.
* The template defines telemetry data points for temperature, humidity,
* pressure, altitude, luminosity, magnetic field, rolling and pitch angles,
* as well as acceleration. All of these data are read from the board sensors and sent to
* The template defines telemetry data points for temperature, humidity,
* pressure, altitude, luminosity, magnetic field, rolling and pitch angles,
* as well as acceleration. All of these data are read from the board sensors and sent to
* Azure IoT Central when `azure_pnp_send_telemetry` is called.
* This function must be called frequently enough, no slower than the frequency set
* with `azure_pnp_set_telemetry_frequency` (or the default frequency of 10 seconds).
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* with `azure_iot_init`.
*
*
* return int 0 on success, non-zero if any failure occurs.
*/
int azure_pnp_send_telemetry(azure_iot_t* azure_iot);
/*
* @brief Handles a command when it is received from Azure IoT Central.
* @remark This function will perform the task requested by the command received
* (if the command matches the expected name) and sends back a response to
* @remark This function will perform the task requested by the command received
* (if the command matches the expected name) and sends back a response to
* Azure IoT Central.
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* with `azure_iot_init`.
* @param[in] command_request The `command_request_t` instance containing the details of the
* @param[in] command_request The `command_request_t` instance containing the details of the
* device command.
*
* return int 0 on success, non-zero if any failure occurs.
@ -86,19 +90,22 @@ int azure_pnp_handle_command_request(azure_iot_t* azure_iot, command_request_t c
/*
* @brief Handles a payload with writable properties received from Azure IoT Central.
* @remark This function will consume the writable properties update received
* @remark This function will consume the writable properties update received
* and send back a response to Azure IoT Central.
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
*
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized
* with `azure_iot_init`.
* @param[in] properties Raw properties writable-properties payload received from Azure.
* @param[in] request_id The request ID of the response that is sent to the Azure IoT Central.
* In Azure IoT Plug and Play, a response to a writable-property update is
* itself a reported-property (device-side property) update, so it gets a
* a response from Azure with the same request ID provided here as argument.
* In Azure IoT Plug and Play, a response to a writable-property update
* is itself a reported-property (device-side property) update, so it gets a a response from Azure
* with the same request ID provided here as argument.
*
* return int 0 on success, non-zero if any failure occurs.
*/
int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span properties, uint32_t request_id);
int azure_pnp_handle_properties_update(
azure_iot_t* azure_iot,
az_span properties,
uint32_t request_id);
#endif // AZURE_IOT_PNP_TEMPLATE_H

Просмотреть файл

@ -2,12 +2,13 @@
// SPDX-License-Identifier: MIT
// Wifi
#define IOT_CONFIG_WIFI_SSID "SSID"
#define IOT_CONFIG_WIFI_PASSWORD "PWD"
#define IOT_CONFIG_WIFI_SSID "SSID"
#define IOT_CONFIG_WIFI_PASSWORD "PWD"
// Enable macro IOT_CONFIG_USE_X509_CERT to use an x509 certificate to authenticate the IoT device.
// The two main modes of authentication are through SAS tokens (automatically generated by the sample using the provided device symmetric key) or through x509 certificates.
// Please choose the appropriate option according to your device authentication mode.
// The two main modes of authentication are through SAS tokens (automatically generated by the
// sample using the provided device symmetric key) or through x509 certificates. Please choose the
// appropriate option according to your device authentication mode.
// #define IOT_CONFIG_USE_X509_CERT
@ -16,7 +17,7 @@
/*
* Please set the define IOT_CONFIG_DEVICE_CERT below with
* the content of your device x509 certificate.
*
*
* Example:
* #define IOT_CONFIG_DEVICE_CERT "-----BEGIN CERTIFICATE-----\r\n" \
* "MIIBJDCBywIUfeHrebBVa2eZAbouBgACp9R3BncwCgYIKoZIzj0EAwIwETEPMA0G\r\n" \
@ -26,7 +27,7 @@
* "YmGzdaHTb6P1W+p+jmc+jJn1MAoGCXqGSM49BAMCA0gAMEUCIEnbEMsAdGFroMwl\r\n" \
* "vTfQahwsxN3xink9z1gtirrjQlqDAiEAyU+6TUJcG6d9JF+uJqsLFpsbbF3IzGAw\r\n" \
* "yC+koNRC0MU=\r\n" \
* "-----END CERTIFICATE-----"
* "-----END CERTIFICATE-----"
*
*/
#define IOT_CONFIG_DEVICE_CERT "Device Certificate"
@ -34,7 +35,7 @@
/*
* Please set the define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY below with
* the content of your device x509 private key.
*
*
* Example:
*
* #define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY "-----BEGIN EC PRIVATE KEY-----\r\n" \
@ -42,31 +43,30 @@
* "AwEHoUQDQgAEU6nQoYbjgJvBwaeD6MyAYmOSDg0QhEdyyV337qrlIbDEKvFsn1El\r\n" \
* "yRabc4dNp2Jhs3Xh02+j9Vvqfo5nPoyZ9Q==\r\n" \
* "-----END EC PRIVATE KEY-----"
*
*
* Note the type of key may different in your case. Such as BEGIN PRIVATE KEY
* or BEGIN RSA PRIVATE KEY.
*
*/
*
*/
#define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY "Device Certificate Private Key"
#endif // IOT_CONFIG_USE_X509_CERT
// Azure IoT Central
#define DPS_ID_SCOPE "ID Scope"
#define IOT_CONFIG_DEVICE_ID "Device ID"
#define DPS_ID_SCOPE "ID Scope"
#define IOT_CONFIG_DEVICE_ID "Device ID"
// Use device key if not using certificates
#ifndef IOT_CONFIG_USE_X509_CERT
#define IOT_CONFIG_DEVICE_KEY "Device Key"
#endif // IOT_CONFIG_USE_X509_CERT
#define IOT_CONFIG_DEVICE_KEY "Device Key"
#endif // IOT_CONFIG_USE_X509_CERT
// User-agent (url-encoded) provided by the MQTT client to Azure IoT Services.
// When developing for your own Arduino-based platform,
// please update the suffix with the format '(ard;<platform>)' as an url-encoded string.
#define AZURE_SDK_CLIENT_USER_AGENT "c%2F" AZ_SDK_VERSION_STRING "(ard%3Besp32)"
#define AZURE_SDK_CLIENT_USER_AGENT "c%2F" AZ_SDK_VERSION_STRING "(ard%3Besp32)"
// Publish 1 message every 2 seconds.
#define TELEMETRY_FREQUENCY_IN_SECONDS 2
#define TELEMETRY_FREQUENCY_IN_SECONDS 2
// For how long the MQTT password (SAS token) is valid, in minutes.
// After that, the sample automatically generates a new password and re-connects.

Просмотреть файл

@ -12,7 +12,8 @@
#define INDEFINITE_TIME ((time_t)-1)
#define az_span_is_content_equal(x, AZ_SPAN_EMPTY) (az_span_size(x) == az_span_size(AZ_SPAN_EMPTY) && az_span_ptr(x) == az_span_ptr(AZ_SPAN_EMPTY))
#define az_span_is_content_equal(x, AZ_SPAN_EMPTY) \
(az_span_size(x) == az_span_size(AZ_SPAN_EMPTY) && az_span_ptr(x) == az_span_ptr(AZ_SPAN_EMPTY))
static uint32_t getSasTokenExpiration(const char* sasToken)
{
@ -44,8 +45,11 @@ static uint32_t getSasTokenExpiration(const char* sasToken)
}
else
{
int k = i;
while (sasToken[k] != '\0' && sasToken[k] != '&') { k++; }
int k = i;
while (sasToken[k] != '\0' && sasToken[k] != '&')
{
k++;
}
if (az_result_failed(
az_span_atou32(az_span_create((uint8_t*)sasToken + i, k - i), &se_as_unix_time)))
@ -135,7 +139,7 @@ static int iot_sample_generate_sas_base64_encoded_signed_signature(
// Decode the sas base64 encoded key to use for HMAC signing.
char sas_decoded_key_buffer[32];
az_span sas_decoded_key = AZ_SPAN_FROM_BUFFER(sas_decoded_key_buffer);
if (decode_base64_bytes(sas_base64_encoded_key, sas_decoded_key, &sas_decoded_key) != 0)
{
Logger.Error("Failed generating encoded signed signature");
@ -186,12 +190,13 @@ az_span generate_sas_token(
// Generate the encoded, signed signature (b64 encoded, HMAC-SHA256 signing).
char b64enc_hmacsha256_signature[64];
az_span sas_base64_encoded_signed_signature = AZ_SPAN_FROM_BUFFER(b64enc_hmacsha256_signature);
if (iot_sample_generate_sas_base64_encoded_signed_signature(
device_key,
sas_signature,
sas_base64_encoded_signed_signature,
&sas_base64_encoded_signed_signature) != 0)
device_key,
sas_signature,
sas_base64_encoded_signed_signature,
&sas_base64_encoded_signed_signature)
!= 0)
{
Logger.Error("Failed generating SAS token signed signature");
return AZ_SPAN_EMPTY;
@ -215,7 +220,7 @@ az_span generate_sas_token(
}
else
{
return az_span_slice(sas_token, 0, mqtt_password_length);
return az_span_slice(sas_token, 0, mqtt_password_length);
}
}
@ -241,7 +246,7 @@ int AzIoTSasToken::Generate(unsigned int expiryTimeInMinutes)
this->signatureBuffer,
expiryTimeInMinutes,
this->sasTokenBuffer);
if (az_span_is_content_equal(this->sasToken, AZ_SPAN_EMPTY))
{
Logger.Error("Failed generating SAS token");
@ -259,7 +264,7 @@ int AzIoTSasToken::Generate(unsigned int expiryTimeInMinutes)
}
else
{
return 0;
return 0;
}
}
}

Просмотреть файл

@ -5,7 +5,7 @@
* This is an Arduino-based Azure IoT Hub sample for ESPRESSIF ESP32 boards.
* It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c.
*
*
* To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is an MQTT client support library, helping composing and parsing the
@ -14,11 +14,14 @@
* This sample performs the following tasks:
* - Synchronize the device clock with a NTP server;
* - Initialize our "az_iot_hub_client" (struct for data, part of our azure-sdk-for-c);
* - Initialize the MQTT client (here we use ESPRESSIF's esp_mqtt_client, which also handle the tcp connection and TLS);
* - Connect the MQTT client (using server-certificate validation, SAS-tokens for client authentication);
* - Initialize the MQTT client (here we use ESPRESSIF's esp_mqtt_client, which also handle the tcp
* connection and TLS);
* - Connect the MQTT client (using server-certificate validation, SAS-tokens for client
* authentication);
* - Periodically send telemetry data to the Azure IoT Hub.
*
* To properly connect to your Azure IoT Hub, please fill the information in the `iot_configs.h` file.
*
* To properly connect to your Azure IoT Hub, please fill the information in the `iot_configs.h`
* file.
*/
// C99 libraries
@ -35,13 +38,13 @@
#include <az_iot.h>
#include <azure_ca.h>
// Additional sample headers
// Additional sample headers
#include "AzIoTSasToken.h"
#include "SerialLogger.h"
#include "iot_configs.h"
// When developing for your own Arduino-based platform,
// please follow the format '(ard;<platform>)'.
// please follow the format '(ard;<platform>)'.
#define AZURE_SDK_CLIENT_USER_AGENT "c%2F" AZ_SDK_VERSION_STRING "(ard;esp32)"
// Utility macros and defines
@ -53,7 +56,7 @@
#define UNIX_TIME_NOV_13_2017 1510592825
#define PST_TIME_ZONE -8
#define PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF 1
#define PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF 1
#define GMT_OFFSET_SECS (PST_TIME_ZONE * 3600)
#define GMT_OFFSET_SECS_DST ((PST_TIME_ZONE + PST_TIME_ZONE_DAYLIGHT_SAVINGS_DIFF) * 3600)
@ -155,7 +158,7 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
}
else
{
Logger.Info("Subscribed for cloud-to-device messages; message id:" + String(r));
Logger.Info("Subscribed for cloud-to-device messages; message id:" + String(r));
}
break;
@ -176,14 +179,14 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
for (i = 0; i < (INCOMING_DATA_BUFFER_SIZE - 1) && i < event->topic_len; i++)
{
incoming_data[i] = event->topic[i];
incoming_data[i] = event->topic[i];
}
incoming_data[i] = '\0';
Logger.Info("Topic: " + String(incoming_data));
for (i = 0; i < (INCOMING_DATA_BUFFER_SIZE - 1) && i < event->data_len; i++)
{
incoming_data[i] = event->data[i];
incoming_data[i] = event->data[i];
}
incoming_data[i] = '\0';
Logger.Info("Data: " + String(incoming_data));
@ -236,13 +239,13 @@ static void initializeIoTHubClient()
static int initializeMqttClient()
{
#ifndef IOT_CONFIG_USE_X509_CERT
#ifndef IOT_CONFIG_USE_X509_CERT
if (sasToken.Generate(SAS_TOKEN_DURATION_IN_MINUTES) != 0)
{
Logger.Error("Failed generating SAS token");
return 1;
}
#endif
#endif
esp_mqtt_client_config_t mqtt_config;
memset(&mqtt_config, 0, sizeof(mqtt_config));
@ -251,13 +254,13 @@ static int initializeMqttClient()
mqtt_config.client_id = mqtt_client_id;
mqtt_config.username = mqtt_username;
#ifdef IOT_CONFIG_USE_X509_CERT
Logger.Info("MQTT client using X509 Certificate authentication");
mqtt_config.client_cert_pem = IOT_CONFIG_DEVICE_CERT;
mqtt_config.client_key_pem = IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY;
#else // Using SAS key
mqtt_config.password = (const char*)az_span_ptr(sasToken.Get());
#endif
#ifdef IOT_CONFIG_USE_X509_CERT
Logger.Info("MQTT client using X509 Certificate authentication");
mqtt_config.client_cert_pem = IOT_CONFIG_DEVICE_CERT;
mqtt_config.client_key_pem = IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY;
#else // Using SAS key
mqtt_config.password = (const char*)az_span_ptr(sasToken.Get());
#endif
mqtt_config.keepalive = 30;
mqtt_config.disable_clean_session = 0;
@ -292,10 +295,7 @@ static int initializeMqttClient()
* @brief Gets the number of seconds since UNIX epoch until now.
* @return uint32_t Number of seconds.
*/
static uint32_t getEpochTimeInSecs()
{
return (uint32_t)time(NULL);
}
static uint32_t getEpochTimeInSecs() { return (uint32_t)time(NULL); }
static void establishConnection()
{
@ -309,13 +309,13 @@ static void getTelemetryPayload(az_span payload, az_span* out_payload)
{
az_span original_payload = payload;
payload = az_span_copy(
payload, AZ_SPAN_FROM_STR("{ \"msgCount\": "));
payload = az_span_copy(payload, AZ_SPAN_FROM_STR("{ \"msgCount\": "));
(void)az_span_u32toa(payload, telemetry_send_count++, &payload);
payload = az_span_copy(payload, AZ_SPAN_FROM_STR(" }"));
payload = az_span_copy_u8(payload, '\0');
*out_payload = az_span_slice(original_payload, 0, az_span_size(original_payload) - az_span_size(payload) - 1);
*out_payload = az_span_slice(
original_payload, 0, az_span_size(original_payload) - az_span_size(payload) - 1);
}
static void sendTelemetry()
@ -355,10 +355,7 @@ static void sendTelemetry()
// Arduino setup and loop main functions.
void setup()
{
establishConnection();
}
void setup() { establishConnection(); }
void loop()
{
@ -366,14 +363,14 @@ void loop()
{
connectToWiFi();
}
#ifndef IOT_CONFIG_USE_X509_CERT
#ifndef IOT_CONFIG_USE_X509_CERT
else if (sasToken.IsExpired())
{
Logger.Info("SAS token expired; reconnecting with a new one.");
(void)esp_mqtt_client_destroy(mqtt_client);
initializeMqttClient();
}
#endif
#endif
else if (millis() > next_telemetry_send_time_ms)
{
sendTelemetry();

Просмотреть файл

@ -2,12 +2,13 @@
// SPDX-License-Identifier: MIT
// Wifi
#define IOT_CONFIG_WIFI_SSID "SSID"
#define IOT_CONFIG_WIFI_PASSWORD "PWD"
#define IOT_CONFIG_WIFI_SSID "SSID"
#define IOT_CONFIG_WIFI_PASSWORD "PWD"
// Enable macro IOT_CONFIG_USE_X509_CERT to use an x509 certificate to authenticate the IoT device.
// The two main modes of authentication are through SAS tokens (automatically generated by the sample using the provided device symmetric key) or through x509 certificates.
// Please choose the appropriate option according to your device authentication mode.
// The two main modes of authentication are through SAS tokens (automatically generated by the
// sample using the provided device symmetric key) or through x509 certificates. Please choose the
// appropriate option according to your device authentication mode.
// #define IOT_CONFIG_USE_X509_CERT
@ -16,7 +17,7 @@
/*
* Please set the define IOT_CONFIG_DEVICE_CERT below with
* the content of your device x509 certificate.
*
*
* Example:
* #define IOT_CONFIG_DEVICE_CERT "-----BEGIN CERTIFICATE-----\r\n" \
* "MIIBJDCBywIUfeHrebBVa2eZAbouBgACp9R3BncwCgYIKoZIzj0EAwIwETEPMA0G\r\n" \
@ -26,7 +27,7 @@
* "YmGzdaHTb6P1W+p+jmc+jJn1MAoGCXqGSM49BAMCA0gAMEUCIEnbEMsAdGFroMwl\r\n" \
* "vTfQahwsxN3xink9z1gtirrjQlqDAiEAyU+6TUJcG6d9JF+uJqsLFpsbbF3IzGAw\r\n" \
* "yC+koNRC0MU=\r\n" \
* "-----END CERTIFICATE-----"
* "-----END CERTIFICATE-----"
*
*/
#define IOT_CONFIG_DEVICE_CERT "Device Certificate"
@ -34,7 +35,7 @@
/*
* Please set the define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY below with
* the content of your device x509 private key.
*
*
* Example:
*
* #define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY "-----BEGIN EC PRIVATE KEY-----\r\n" \
@ -42,11 +43,11 @@
* "AwEHoUQDQgAEU6nQoYbjgJvBwaeD6MyAYmOSDg0QhEdyyV337qrlIbDEKvFsn1El\r\n" \
* "yRabc4dNp2Jhs3Xh02+j9Vvqfo5nPoyZ9Q==\r\n" \
* "-----END EC PRIVATE KEY-----"
*
*
* Note the type of key may different in your case. Such as BEGIN PRIVATE KEY
* or BEGIN RSA PRIVATE KEY.
*
*/
*
*/
#define IOT_CONFIG_DEVICE_CERT_PRIVATE_KEY "Device Certificate Private Key"
#endif // IOT_CONFIG_USE_X509_CERT
@ -56,8 +57,8 @@
#define IOT_CONFIG_DEVICE_ID "Device ID"
// Use device key if not using certificates
#ifndef IOT_CONFIG_USE_X509_CERT
#define IOT_CONFIG_DEVICE_KEY "Device Key"
#endif // IOT_CONFIG_USE_X509_CERT
#define IOT_CONFIG_DEVICE_KEY "Device Key"
#endif // IOT_CONFIG_USE_X509_CERT
// Publish 1 message every 2 seconds
#define TELEMETRY_FREQUENCY_MILLISECS 2000

Просмотреть файл

@ -5,7 +5,7 @@
* This is an Arduino-based Azure IoT Hub sample for ESPRESSIF ESP8266 board.
* It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c.
*
*
* To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is an MQTT client support library, helping to compose and parse the
@ -14,18 +14,21 @@
* This sample performs the following tasks:
* - Synchronize the device clock with a NTP server;
* - Initialize our "az_iot_hub_client" (struct for data, part of our azure-sdk-for-c);
* - Initialize the MQTT client (here we use Nick Oleary's PubSubClient, which also handle the tcp connection and TLS);
* - Connect the MQTT client (using server-certificate validation, SAS-tokens for client authentication);
* - Initialize the MQTT client (here we use Nick Oleary's PubSubClient, which also handle the tcp
* connection and TLS);
* - Connect the MQTT client (using server-certificate validation, SAS-tokens for client
* authentication);
* - Periodically send telemetry data to the Azure IoT Hub.
*
* To properly connect to your Azure IoT Hub, please fill the information in the `iot_configs.h` file.
*
* To properly connect to your Azure IoT Hub, please fill the information in the `iot_configs.h`
* file.
*/
// C99 libraries
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <cstdlib>
#include <stdbool.h>
#include <string.h>
#include <time.h>
// Libraries for MQTT client, WiFi connection and SAS-token generation.
#include <ESP8266WiFi.h>
@ -41,11 +44,11 @@
#include <az_iot.h>
#include <azure_ca.h>
// Additional sample headers
// Additional sample headers
#include "iot_configs.h"
// When developing for your own Arduino-based platform,
// please follow the format '(ard;<platform>)'.
// please follow the format '(ard;<platform>)'.
#define AZURE_SDK_CLIENT_USER_AGENT "c%2F" AZ_SDK_VERSION_STRING "(ard;esp8266)"
// Utility macros and defines
@ -77,7 +80,6 @@ static char telemetry_topic[128];
static uint8_t telemetry_payload[100];
static uint32_t telemetry_send_count = 0;
// Auxiliary functions
static void connectToWiFi()
@ -162,10 +164,7 @@ static void initializeClients()
* @brief Gets the number of seconds since UNIX epoch until now.
* @return uint32_t Number of seconds.
*/
static uint32_t getSecondsSinceEpoch()
{
return (uint32_t)time(NULL);
}
static uint32_t getSecondsSinceEpoch() { return (uint32_t)time(NULL); }
static int generateSasToken(char* sas_token, size_t size)
{
@ -282,7 +281,7 @@ static int connectToAzureIoTHub()
return 0;
}
static void establishConnection()
static void establishConnection()
{
connectToWiFi();
initializeTime();
@ -308,7 +307,7 @@ static char* getTelemetryPayload()
{
az_span temp_span = az_span_create(telemetry_payload, sizeof(telemetry_payload));
temp_span = az_span_copy(temp_span, AZ_SPAN_FROM_STR("{ \"msgCount\": "));
(void)az_span_u32toa(temp_span, telemetry_send_count++, &temp_span);
(void)az_span_u32toa(temp_span, telemetry_send_count++, &temp_span);
temp_span = az_span_copy(temp_span, AZ_SPAN_FROM_STR(" }"));
temp_span = az_span_copy_u8(temp_span, '\0');
@ -333,7 +332,6 @@ static void sendTelemetry()
digitalWrite(LED_PIN, LOW);
}
// Arduino setup and loop main functions.
void setup()
@ -348,7 +346,7 @@ void loop()
if (millis() > next_telemetry_send_time_ms)
{
// Check if connected, reconnect if needed.
if(!mqtt_client.connected())
if (!mqtt_client.connected())
{
establishConnection();
}

Просмотреть файл

@ -2,28 +2,28 @@
// SPDX-License-Identifier: MIT
// C99 libraries
#include <string.h>
#include <stdbool.h>
#include <cstdlib>
#include <stdbool.h>
#include <string.h>
// Libraries for NTP, MQTT client, WiFi connection and SAS-token generation.
#include <NTPClient.h>
#include <sntp/sntp.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <mbedtls/base64.h>
#include <mbedtls/sha256.h>
#include <sntp/sntp.h>
// Azure IoT SDK for C includes
#include <az_core.h>
#include <az_iot.h>
#include <azure_ca.h>
// Additional sample headers
// Additional sample headers
#include "iot_configs.h"
// When developing for your own Arduino-based platform,
// please follow the format '(ard;<platform>)'.
// please follow the format '(ard;<platform>)'.
#define AZURE_SDK_CLIENT_USER_AGENT "c%2F" AZ_SDK_VERSION_STRING "(ard;amebaD)"
// Utility macros and defines
@ -54,10 +54,26 @@ static uint32_t telemetry_send_count = 0;
static unsigned char* ca_pem_nullterm;
// Auxiliary functions
extern "C"{
extern int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
extern int rom_hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac);
extern int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
extern "C"
{
extern int mbedtls_base64_decode(
unsigned char* dst,
size_t dlen,
size_t* olen,
const unsigned char* src,
size_t slen);
extern int rom_hmac_sha256(
const u8* key,
size_t key_len,
const u8* data,
size_t data_len,
u8* mac);
extern int mbedtls_base64_encode(
unsigned char* dst,
size_t dlen,
size_t* olen,
const unsigned char* src,
size_t slen);
}
static void createNullTerminatedRootCert()
{
@ -74,7 +90,6 @@ static void createNullTerminatedRootCert()
}
}
static void connectToWiFi()
{
Serial.begin(115200);
@ -139,15 +154,16 @@ int64_t iot_sample_get_epoch_expiration_time_from_minutes(uint32_t minutes)
long tus = 0;
unsigned int ttk = 0;
//it should be ok to do init more than one time. It'll handle inside sntp_init().
// it should be ok to do init more than one time. It'll handle inside sntp_init().
sntp_init();
sntp_get_lasttime(&ts, &tus, &ttk);
while(ts == 0){
while (ts == 0)
{
vTaskDelay(1000 / portTICK_RATE_MS);
sntp_get_lasttime(&ts, &tus, &ttk);
}
}
return (int64_t)ts + minutes * 60;
}
@ -157,13 +173,14 @@ static void hmac_sha256_sign_signature(
az_span signature,
az_span signed_signature,
az_span* out_signed_signature)
{
if(rom_hmac_sha256(
az_span_ptr(decoded_key),
(size_t)az_span_size(decoded_key),
az_span_ptr(signature),
(size_t)az_span_size(signature),
az_span_ptr(signed_signature)) != 0)
{
if (rom_hmac_sha256(
az_span_ptr(decoded_key),
(size_t)az_span_size(decoded_key),
az_span_ptr(signature),
(size_t)az_span_size(signature),
az_span_ptr(signed_signature))
!= 0)
{
Serial.println("[ERROR] rom_hmac_sha256 failed");
@ -178,12 +195,17 @@ static void base64_encode_bytes(
az_span* out_base64_encoded_bytes)
{
size_t len;
if(mbedtls_base64_encode(az_span_ptr(base64_encoded_bytes), (size_t)az_span_size(base64_encoded_bytes),
&len, az_span_ptr(decoded_bytes), (size_t)az_span_size(decoded_bytes)) != 0)
if (mbedtls_base64_encode(
az_span_ptr(base64_encoded_bytes),
(size_t)az_span_size(base64_encoded_bytes),
&len,
az_span_ptr(decoded_bytes),
(size_t)az_span_size(decoded_bytes))
!= 0)
{
Serial.println("[ERROR] mbedtls_base64_encode fail");
}
*out_base64_encoded_bytes = az_span_create(az_span_ptr(base64_encoded_bytes), (int32_t)len);
}
@ -192,16 +214,21 @@ static void decode_base64_bytes(
az_span decoded_bytes,
az_span* out_decoded_bytes)
{
memset(az_span_ptr(decoded_bytes), 0, (size_t)az_span_size(decoded_bytes));
size_t len;
if( mbedtls_base64_decode( az_span_ptr(decoded_bytes), (size_t)az_span_size(decoded_bytes),
&len, az_span_ptr(base64_encoded_bytes), (size_t)az_span_size(base64_encoded_bytes)) != 0)
if (mbedtls_base64_decode(
az_span_ptr(decoded_bytes),
(size_t)az_span_size(decoded_bytes),
&len,
az_span_ptr(base64_encoded_bytes),
(size_t)az_span_size(base64_encoded_bytes))
!= 0)
{
Serial.println("[ERROR] mbedtls_base64_decode fail");
}
*out_decoded_bytes = az_span_create(az_span_ptr(decoded_bytes), (int32_t)len);
}
@ -219,26 +246,27 @@ static void iot_sample_generate_sas_base64_encoded_signed_signature(
// HMAC-SHA256 sign the signature with the decoded key.
char sas_hmac256_signed_signature_buffer[32];
az_span sas_hmac256_signed_signature = AZ_SPAN_FROM_BUFFER(sas_hmac256_signed_signature_buffer);
hmac_sha256_sign_signature(sas_decoded_key, sas_signature, sas_hmac256_signed_signature, &sas_hmac256_signed_signature);
hmac_sha256_sign_signature(
sas_decoded_key, sas_signature, sas_hmac256_signed_signature, &sas_hmac256_signed_signature);
// Base64 encode the result of the HMAC signing.
base64_encode_bytes(
sas_hmac256_signed_signature,
sas_base64_encoded_signed_signature,
out_sas_base64_encoded_signed_signature);
sas_hmac256_signed_signature,
sas_base64_encoded_signed_signature,
out_sas_base64_encoded_signed_signature);
}
static void generate_sas_key(void)
{
az_result rc;
// Create the POSIX expiration time from input minutes.
uint64_t sas_duration = iot_sample_get_epoch_expiration_time_from_minutes(SAS_TOKEN_EXPIRY_IN_MINUTES);
uint64_t sas_duration
= iot_sample_get_epoch_expiration_time_from_minutes(SAS_TOKEN_EXPIRY_IN_MINUTES);
// Get the signature that will later be signed with the decoded key.
az_span sas_signature = AZ_SPAN_FROM_BUFFER(signature);
rc = az_iot_hub_client_sas_get_signature(
&hub_client, sas_duration, sas_signature, &sas_signature);
&hub_client, sas_duration, sas_signature, &sas_signature);
if (az_result_failed(rc))
{
Serial.print("Could not get the signature for SAS key: az_result return code ");
@ -249,21 +277,21 @@ static void generate_sas_key(void)
char b64enc_hmacsha256_signature[64];
az_span sas_base64_encoded_signed_signature = AZ_SPAN_FROM_BUFFER(b64enc_hmacsha256_signature);
iot_sample_generate_sas_base64_encoded_signed_signature(
AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_KEY),
sas_signature,
sas_base64_encoded_signed_signature,
&sas_base64_encoded_signed_signature);
AZ_SPAN_FROM_STR(IOT_CONFIG_DEVICE_KEY),
sas_signature,
sas_base64_encoded_signed_signature,
&sas_base64_encoded_signed_signature);
// Get the resulting MQTT password, passing the base64 encoded, HMAC signed bytes.
size_t mqtt_password_length;
rc = az_iot_hub_client_sas_get_password(
&hub_client,
sas_duration,
sas_base64_encoded_signed_signature,
AZ_SPAN_EMPTY,
sas_token,
sizeof(sas_token),
&sas_token_length);
&hub_client,
sas_duration,
sas_base64_encoded_signed_signature,
AZ_SPAN_EMPTY,
sas_token,
sizeof(sas_token),
&sas_token_length);
if (az_result_failed(rc))
{
Serial.print("Could not get the password: az_result return code ");
@ -320,7 +348,7 @@ static int connect_to_azure_iot_hub()
return 0;
}
void establishConnection()
void establishConnection()
{
connectToWiFi();
@ -337,7 +365,7 @@ static char* get_telemetry_payload()
{
az_span temp_span = az_span_create(telemetry_payload, sizeof(telemetry_payload));
temp_span = az_span_copy(temp_span, AZ_SPAN_FROM_STR("{ \"msgCount\": "));
(void)az_span_u32toa(temp_span, telemetry_send_count++, &temp_span);
(void)az_span_u32toa(temp_span, telemetry_send_count++, &temp_span);
temp_span = az_span_copy(temp_span, AZ_SPAN_FROM_STR(" }"));
temp_span = az_span_copy_u8(temp_span, '\0');
@ -362,7 +390,6 @@ static void send_telemetry()
digitalWrite(LED_PIN, LOW);
}
// Arduino setup and loop main functions.
void setup()
@ -378,7 +405,7 @@ void loop()
if (millis() > next_telemetry_send_time_ms)
{
// Check if connected, reconnect if needed.
if(!mqtt_client.connected())
if (!mqtt_client.connected())
{
establishConnection();
}