diff --git a/examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino b/examples/Azure_IoT_Hub_ESP8266/Arduino IDE/Azure_IoT_Hub_ESP8266.ino similarity index 100% rename from examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino rename to examples/Azure_IoT_Hub_ESP8266/Arduino IDE/Azure_IoT_Hub_ESP8266.ino diff --git a/examples/Azure_IoT_Hub_ESP8266/iot_configs.h b/examples/Azure_IoT_Hub_ESP8266/Arduino IDE/iot_configs.h similarity index 100% rename from examples/Azure_IoT_Hub_ESP8266/iot_configs.h rename to examples/Azure_IoT_Hub_ESP8266/Arduino IDE/iot_configs.h diff --git a/examples/Azure_IoT_Hub_ESP8266/readme.md b/examples/Azure_IoT_Hub_ESP8266/Arduino IDE/readme.md similarity index 100% rename from examples/Azure_IoT_Hub_ESP8266/readme.md rename to examples/Azure_IoT_Hub_ESP8266/Arduino IDE/readme.md diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/.gitignore b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/.gitignore new file mode 100644 index 00000000..d455a42e --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/.gitignore @@ -0,0 +1,9 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch +.vscode/ +iot_configs_current.h +ca.h +edgeRootCA.pem \ No newline at end of file diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/create_trusted_cert_header.sh b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/create_trusted_cert_header.sh new file mode 100644 index 00000000..9a19bdc3 --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/create_trusted_cert_header.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +set -x # Set trace on +set -o errexit # Exit if command failed +set -o nounset # Exit if variable not set +set -o pipefail # Exit if pipe failed + +command -v xxd >/dev/null 2>&1 || { echo >&2 "Please install xxd."; exit 1; } + +echo -n -e '\0' >> edgeRootCA.pem +xxd -i edgeRootCA.pem ca.h + +mv ca.h include \ No newline at end of file diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/include/README b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/include/README new file mode 100644 index 00000000..194dcd43 --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/include/iot_configs.h b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/include/iot_configs.h new file mode 100644 index 00000000..e32cd4a2 --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/include/iot_configs.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +// Wifi +#define IOT_CONFIG_WIFI_SSID "" +#define IOT_CONFIG_WIFI_PASSWORD "" + +// Azure IoT +#define IOT_CONFIG_IOTHUB_FQDN "[HubName].azure-devices.net" +#define IOT_CONFIG_DEVICE_ID "" +#define IOT_CONFIG_DEVICE_KEY "" + +//Azure IoT Edge - only use if you are connecting to an IoT Edge Gateway +//#define IOT_EDGE_GATEWAY "hostnameofgateway" + +// Publish 1 message every 2 seconds +#define TELEMETRY_FREQUENCY_MILLISECS 2000 diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/lib/README b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/lib/README new file mode 100644 index 00000000..6debab1e --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/platformio.ini b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/platformio.ini new file mode 100644 index 00000000..8db67b37 --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/platformio.ini @@ -0,0 +1,18 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 +framework = arduino +lib_deps = + azure/Azure SDK for C@^1.0.0-beta.3 + knolleary/PubSubClient@^2.8 +monitor_speed = 115200 diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/readme.md b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/readme.md new file mode 100644 index 00000000..efab3e4a --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/readme.md @@ -0,0 +1,180 @@ +--- +page_type: sample +description: Connecting an ESP8266 device to Azure IoT using the Azure SDK for Embedded C +languages: +- c +products: +- azure-iot +- azure-iot-pnp +- azure-iot-dps +- azure-iot-hub +--- + +# How to Setup and Run Azure SDK for Embedded C IoT Hub Client on Espressif ESP8266 NodeMCU + +- [How to Setup and Run Azure SDK for Embedded C IoT Hub Client on Espressif ESP8266 NodeMCU](#how-to-setup-and-run-azure-sdk-for-embedded-c-iot-hub-client-on-espressif-esp8266-nodemcu) + - [Introduction](#introduction) + - [What is Covered](#what-is-covered) + - [Prerequisites](#prerequisites) + - [Setup and Run Instructions](#setup-and-run-instructions) + - [Certificates - Important to know](#certificates---important-to-know) + - [Additional Information](#additional-information) + - [Troubleshooting](#troubleshooting) + - [Contributing](#contributing) + - [License](#license) + +## Introduction + +This is a "to-the-point" guide outlining how to run an Azure SDK for Embedded C IoT Hub telemetry sample on an Esp8266 NodeMCU microcontroller. The command line examples are tailored to Debian/Ubuntu environments. + +### What is Covered + +- Configuration instructions for the PlatformIO IDE to compile a sample using the Azure SDK for Embedded C. +- Configuration, build, and run instructions for the IoT Hub telemetry sample. + +_The following was run on Windows 10, Ubuntu Desktop 20.04, and macOS Monterey 12 environments, with Platform IO Core/Home 5.2.4/3.4.0 and platform Espressif 8266 3.2.0._ + +## Prerequisites + +- Have an [Azure account](https://azure.microsoft.com/) created. +- Have an [Azure IoT Hub](https://docs.microsoft.com/azure/iot-hub/iot-hub-create-through-portal) created. +- Have a [logical device](https://docs.microsoft.com/azure/iot-hub/iot-hub-create-through-portal#register-a-new-device-in-the-iot-hub) created in your Azure IoT Hub using the authentication type "Symmetric Key". + + NOTE: Device keys are used to automatically generate a SAS token for authentication, which is only valid for one hour. + +- Have the latest [Visual Studio Code](https://code.visualstudio.com/download) installed. + +- Have the latest [PlatformIO IDE](https://docs.platformio.org/en/latest/integration/ide/vscode.html) installed in Visual Studio Code. + +- Have one of the following interfaces to your Azure IoT Hub set up: + - [Azure Command Line Interface](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest) (Azure CLI) utility installed, along with the [Azure IoT CLI extension](https://github.com/Azure/azure-iot-cli-extension). + + On Windows: + + Download and install: https://aka.ms/installazurecliwindows + + ```powershell + PS C:\>az extension add --name azure-iot + ``` + + On Linux: + + ```bash + $ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + $ az extension add --name azure-iot + ``` + + On Mac: + + ```bash + $ brew update && brew install azure-cli + ``` + + A list of all the Azure IoT CLI extension commands can be found [here](https://docs.microsoft.com/cli/azure/iot?view=azure-cli-latest). + + - The most recent version of [Azure IoT Explorer](https://github.com/Azure/azure-iot-explorer/releases) installed. More instruction on its usage can be found [here](https://docs.microsoft.com/azure/iot-pnp/howto-use-iot-explorer). + + NOTE: This guide demonstrates use of the Azure CLI and does NOT demonstrate use of Azure IoT Explorer. + +## Setup and Run Instructions + +1. Open Visial Studio Code and select the PlatformIO icon on the left side of the screen. + +2. Click `PIO Home` -> `Open`-> `Open Project` and select this project (the PlatformIO IDE folder). + +3. Once the project is opened, select the PlatformIO icon on the left side of the screen and under `PROJECT TASKS`, click `Build`. + +4. Ensure the build completes with a status of `[SUCCESS]`. + +5. Under the `include` folder, create a copy of `iot_configs.h` and name it `iot_configs_current.h`. + +6. In `iot_configs_current.h`, enter your Azure IoT Hub and device information. + - NOTE: `IOT_EDGE_GATEWAY` is the only macro that is optional and should only be used if you are connecting to an Edge Gateway, such as Azure IoT Edge, and not directly to Azure IoT Hub. If you want this sample to send telemetry to an Azure IoT Edge Gateway, uncomment and set this macro to the hostname of your gateway, copy your IoT Edge's root CA certificate to this project, name the certificate `edgeRootCA.pem`, and run the script `create_trusted_cert_header.sh`. For more details on this script and certificate usage, please review [Certificates - Important to know](#certificates---important-to-know) + +7. Connect the Esp8266 NodeMCU microcontroller to your USB port. + - If you need to change the default COM port, board, serial monitor speed, or any other project configurations please review this [link](https://docs.platformio.org/en/latest/projectconf/index.html) on configuring the platform.ini file. + +8. Select the PlatformIO icon on the left side of the screen and under `PROJECT TASKS`, click `Upload and Monitor`. This project will now be uploaded to your Esp8266 and a terminal window will open at the bottom of Visual Studio Code, where you can monitor the serial output. + +9. Monitor the telemetry messages sent to Azure IoT Hub using the connection string for the policy name `iothubowner` found under "Shared access policies" on your IoT Hub in the Azure portal. + + ```bash + $ az iot hub monitor-events --login --device-id + ``` + +
Expected telemetry output: +

+ + ```bash + Starting event monitor, filtering on device: mydeviceid, use ctrl-c to stop... + { + "event": { + "origin": "mydeviceid", + "payload": "payload" + } + } + { + "event": { + "origin": "mydeviceid", + "payload": "payload" + } + } + { + "event": { + "origin": "mydeviceid", + "payload": "payload" + } + } + { + "event": { + "origin": "mydeviceid", + "payload": "payload" + } + } + { + "event": { + "origin": "mydeviceid", + "payload": "payload" + } + } + { + "event": { + "origin": "mydeviceid", + "payload": "payload" + } + } + ^CStopping event monitor... + ``` + +

+
+ +## Certificates - Important to know + +The Azure IoT service certificates presented during TLS negotiation shall be always validated, on the device, using the appropriate trusted root CA certificate(s). + +For the Node MCU ESP8266 sample, our script `generate_arduino_zip_library.sh` automatically downloads the root certificate used in the United States regions (Baltimore CA certificate) and adds it to the Arduino sketch project. + +If you would like to change what certificate is used, our script `create_trusted_cert_header.sh` demonstrates how to create a cerfiticate header file. This new cerfiticate header can be used instead of the default trusted root CA certificate header. At the moment, the script only looks for and creates a certificate header file for an Azure IoT Edge root CA certificate named `edgeRootCA.pem`, but it can be modified to use any root CA certificate of choice. + +For other regions (and private cloud environments), please use the appropriate root CA certificate. + +### Additional Information + +For important information and additional guidance about certificates, please refer to [this blog post](https://techcommunity.microsoft.com/t5/internet-of-things/azure-iot-tls-changes-are-coming-and-why-you-should-care/ba-p/1658456) from the security team. + +## Troubleshooting + +- The error policy for the Embedded C SDK client library is documented [here](https://github.com/Azure/azure-sdk-for-c/blob/main/sdk/docs/iot/mqtt_state_machine.md#error-policy). +- File an issue via [GitHub Issues](https://github.com/Azure/azure-sdk-for-c/issues/new/choose). +- Check [previous questions](https://stackoverflow.com/questions/tagged/azure+c) or ask new ones on StackOverflow using the `azure` and `c` tags. + +## Contributing + +This project welcomes contributions and suggestions. Find more contributing details [here](https://github.com/Azure/azure-sdk-for-c/blob/main/CONTRIBUTING.md). + +### License + +This Azure SDK for C Arduino library is licensed under [MIT](https://github.com/Azure/azure-sdk-for-c-arduino/blob/main/LICENSE) license. + +Azure SDK for Embedded C is licensed under the [MIT](https://github.com/Azure/azure-sdk-for-c/blob/main/LICENSE) license. diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/src/main.cpp b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/src/main.cpp new file mode 100644 index 00000000..4dee53d9 --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/src/main.cpp @@ -0,0 +1,378 @@ +#include + +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/* + * 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 + * MQTT topic names and messages exchanged with the Azure IoT Hub. + * + * 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); + * - 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. + */ + +// C99 libraries +#include +#include +#include +#include + +// Libraries for MQTT client, WiFi connection and SAS-token generation. +#include +#include +#include +#include +#include +#include +#include + +// Azure IoT SDK for C includes +#include +#include +#include + +// Additional sample headers +#include "iot_configs_current.h" + +#if defined(IOT_EDGE_GATEWAY) + + // Certificate header (Only needed for scenarios where custom TLS certificates are used, like an IoT Edge Gateway) + #include "ca.h" + + static const char* host = IOT_EDGE_GATEWAY; + static X509List cert((const char*)edgeRootCA_pem); +#else + static const char* host = IOT_CONFIG_IOTHUB_FQDN; + static X509List cert((const char*)ca_pem); +#endif + + +// When developing for your own Arduino-based platform, +// please follow the format '(ard;)'. +#define AZURE_SDK_CLIENT_USER_AGENT "DeviceClientType=iothubclient%2f" AZ_SDK_VERSION_STRING "(ard;esp8266)" + +// Utility macros and defines +#define LED_PIN 2 +#define sizeofarray(a) (sizeof(a) / sizeof(a[0])) +#define ONE_HOUR_IN_SECS 3600 +#define NTP_SERVERS "pool.ntp.org", "time.nist.gov" +#define MQTT_PACKET_SIZE 1024 + +// Translate iot_configs.h defines into variables used by the sample +static const char* ssid = IOT_CONFIG_WIFI_SSID; +static const char* password = IOT_CONFIG_WIFI_PASSWORD; +static const char* device_id = IOT_CONFIG_DEVICE_ID; +static const char* device_key = IOT_CONFIG_DEVICE_KEY; +static const int port = 8883; + +// Memory allocated for the sample's variables and structures. +static WiFiClientSecure wifi_client; +static PubSubClient mqtt_client(wifi_client); +static az_iot_hub_client client; +static char sas_token[200]; +static uint8_t signature[512]; +static unsigned char encrypted_signature[32]; +static char base64_decoded_device_key[32]; +static unsigned long next_telemetry_send_time_ms = 0; +static char telemetry_topic[128]; +static uint8_t telemetry_payload[100]; +static uint32_t telemetry_send_count = 0; + + +// Auxiliary functions + +static void connectToWiFi() +{ + Serial.begin(115200); + Serial.println(); + Serial.print("Connecting to WIFI SSID "); + Serial.println(ssid); + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) + { + delay(500); + Serial.print("."); + } + + Serial.print("WiFi connected, IP address: "); + Serial.println(WiFi.localIP()); +} + +static void initializeTime() +{ + Serial.print("Setting time using SNTP"); + + configTime(-5 * 3600, 0, NTP_SERVERS); + time_t now = time(NULL); + while (now < 1510592825) + { + delay(500); + Serial.print("."); + now = time(NULL); + } + Serial.println("done!"); +} + +static char* getCurrentLocalTimeString() +{ + time_t now = time(NULL); + return ctime(&now); +} + +static void printCurrentTime() +{ + Serial.print("Current time: "); + Serial.print(getCurrentLocalTimeString()); +} + +void receivedCallback(char* topic, byte* payload, unsigned int length) +{ + Serial.print("Received ["); + Serial.print(topic); + Serial.print("]: "); + for (int i = 0; i < length; i++) + { + Serial.print((char)payload[i]); + } + Serial.println(""); +} + +static void initializeClients() +{ + az_iot_hub_client_options options = az_iot_hub_client_options_default(); + options.user_agent = AZ_SPAN_FROM_STR(AZURE_SDK_CLIENT_USER_AGENT); + + wifi_client.setSSLVersion(BR_TLS12); + wifi_client.setTrustAnchors(&cert); + if (az_result_failed(az_iot_hub_client_init( + &client, + az_span_create((uint8_t*)host, strlen(host)), + az_span_create((uint8_t*)device_id, strlen(device_id)), + &options))) + { + Serial.println("Failed initializing Azure IoT Hub client"); + return; + } + + mqtt_client.setServer(host, port); + mqtt_client.setCallback(receivedCallback); +} + +/* + * @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 int generateSasToken(char* sas_token, size_t size) +{ + az_span signature_span = az_span_create((uint8_t*)signature, sizeofarray(signature)); + az_span out_signature_span; + az_span encrypted_signature_span + = az_span_create((uint8_t*)encrypted_signature, sizeofarray(encrypted_signature)); + + uint32_t expiration = getSecondsSinceEpoch() + ONE_HOUR_IN_SECS; + + // Get signature + if (az_result_failed(az_iot_hub_client_sas_get_signature( + &client, expiration, signature_span, &out_signature_span))) + { + Serial.println("Failed getting SAS signature"); + return 1; + } + + // Base64-decode device key + int base64_decoded_device_key_length + = base64_decode_chars(device_key, strlen(device_key), base64_decoded_device_key); + + if (base64_decoded_device_key_length == 0) + { + Serial.println("Failed base64 decoding device key"); + return 1; + } + + // SHA-256 encrypt + br_hmac_key_context kc; + br_hmac_key_init( + &kc, &br_sha256_vtable, base64_decoded_device_key, base64_decoded_device_key_length); + + br_hmac_context hmac_ctx; + br_hmac_init(&hmac_ctx, &kc, 32); + br_hmac_update(&hmac_ctx, az_span_ptr(out_signature_span), az_span_size(out_signature_span)); + br_hmac_out(&hmac_ctx, encrypted_signature); + + // Base64 encode encrypted signature + String b64enc_hmacsha256_signature = base64::encode(encrypted_signature, br_hmac_size(&hmac_ctx)); + + az_span b64enc_hmacsha256_signature_span = az_span_create( + (uint8_t*)b64enc_hmacsha256_signature.c_str(), b64enc_hmacsha256_signature.length()); + + // URl-encode base64 encoded encrypted signature + if (az_result_failed(az_iot_hub_client_sas_get_password( + &client, + expiration, + b64enc_hmacsha256_signature_span, + AZ_SPAN_EMPTY, + sas_token, + size, + NULL))) + { + Serial.println("Failed getting SAS token"); + return 1; + } + + return 0; +} + +static int connectToAzureIoTHub() +{ + size_t client_id_length; + char mqtt_client_id[128]; + if (az_result_failed(az_iot_hub_client_get_client_id( + &client, mqtt_client_id, sizeof(mqtt_client_id) - 1, &client_id_length))) + { + Serial.println("Failed getting client id"); + return 1; + } + + mqtt_client_id[client_id_length] = '\0'; + + char mqtt_username[128]; + // Get the MQTT user name used to connect to IoT Hub + if (az_result_failed(az_iot_hub_client_get_user_name( + &client, mqtt_username, sizeofarray(mqtt_username), NULL))) + { + printf("Failed to get MQTT clientId, return code\n"); + return 1; + } + + Serial.print("Client ID: "); + Serial.println(mqtt_client_id); + + Serial.print("Username: "); + Serial.println(mqtt_username); + + mqtt_client.setBufferSize(MQTT_PACKET_SIZE); + + while (!mqtt_client.connected()) + { + time_t now = time(NULL); + + Serial.print("MQTT connecting ... "); + + + if (mqtt_client.connect(mqtt_client_id, mqtt_username, sas_token)) + { + Serial.println("connected."); + } + else + { + Serial.print("failed, status code ="); + Serial.print(mqtt_client.state()); + Serial.println(". Trying again in 5 seconds."); + // Wait 5 seconds before retrying + delay(5000); + } + } + + mqtt_client.subscribe(AZ_IOT_HUB_CLIENT_C2D_SUBSCRIBE_TOPIC); + + return 0; +} + +static void establishConnection() +{ + connectToWiFi(); + initializeTime(); + printCurrentTime(); + initializeClients(); + + // The SAS token is valid for 1 hour by default in this sample. + // After one hour the sample must be restarted, or the client won't be able + // to connect/stay connected to the Azure IoT Hub. + if (generateSasToken(sas_token, sizeofarray(sas_token)) != 0) + { + Serial.println("Failed generating MQTT password"); + } + else + { + connectToAzureIoTHub(); + } + + digitalWrite(LED_PIN, LOW); +} + +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); + temp_span = az_span_copy(temp_span, AZ_SPAN_FROM_STR(" }")); + temp_span = az_span_copy_u8(temp_span, '\0'); + + return (char*)telemetry_payload; +} + +static void sendTelemetry() +{ + digitalWrite(LED_PIN, HIGH); + Serial.print(millis()); + Serial.print(" ESP8266 Sending telemetry . . . "); + if (az_result_failed(az_iot_hub_client_telemetry_get_publish_topic( + &client, NULL, telemetry_topic, sizeof(telemetry_topic), NULL))) + { + Serial.println("Failed az_iot_hub_client_telemetry_get_publish_topic"); + return; + } + + mqtt_client.publish(telemetry_topic, getTelemetryPayload(), false); + Serial.println("OK"); + delay(100); + digitalWrite(LED_PIN, LOW); +} + + +// Arduino setup and loop main functions. + +void setup() +{ + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + establishConnection(); +} + +void loop() +{ + if (millis() > next_telemetry_send_time_ms) + { + // Check if connected, reconnect if needed. + if(!mqtt_client.connected()) + { + establishConnection(); + } + + sendTelemetry(); + next_telemetry_send_time_ms = millis() + TELEMETRY_FREQUENCY_MILLISECS; + } + + // MQTT loop must be called to process Device-to-Cloud and Cloud-to-Device. + mqtt_client.loop(); + delay(500); +} diff --git a/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/test/README b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/test/README new file mode 100644 index 00000000..b94d0890 --- /dev/null +++ b/examples/Azure_IoT_Hub_ESP8266/PlatformIO IDE/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html