.. _lib_azure_iot_hub: Azure IoT Hub ############# .. contents:: :local: :depth: 2 The Azure IoT Hub library provides an API to connect to an `Azure IoT Hub`_ instance and interact with it. It connects to Azure IoT Hub using MQTT over TLS. Optionally, the library supports `Azure IoT Hub Device Provisioning Service (DPS)`_. DPS can be enabled at compile time to make use of the device provisioning services for onboarding of devices to Azure IoT Hub. When the device provisioning is complete, the library automatically connects to the assigned Azure IoT Hub. The library also has integrated support for a proprietary FOTA solution. For more information on Azure FOTA, see the documentation on :ref:`lib_azure_fota` library and :ref:`azure_fota_sample` sample. The library uses `Azure SDK for Embedded C`_ for message processing and other operations. For more information on how Azure SDK for Embedded C is integrated in this library, see :module_file:`Azure SDK for Embedded C IoT client libraries`. .. important:: If the server sends a device-bound message when the device is unavailable for a period of time, for instance while in LTE Power Saving Mode, the server will most likely terminate the TCP connection. This will result in additional data traffic as the device has to reconnect to the server, which in turn requires a new TLS handshake and MQTT connection establishment. .. _prereq_connect_to_azure_iot_hub: Prerequisites for connecting to Azure IoT Hub ********************************************* In order to connect to Azure IoT Hub, an Azure account and an Azure IoT Hub instance must first be created and configured. See `Creating an Azure IoT Hub instance using the Azure portal`_ for more information. .. note:: If you do not use DPS to provision devices to your IoT Hub, make sure that you select ``X.509 CA Signed`` as the *Authentication type* while `Registering the device with Azure IoT Hub`_. The connection to Azure IoT Hub with MQTT is secured using TLS. For testing purposes, see `Creating Azure IoT Hub certificates`_ for the steps to create certificates and a private key for the leaf device, and to register the generated test root certificate to be used with an IoT hub. The Azure IoT Hub library requires provisioning of the following certificates and a private key for a successful TLS connection: 1. `Baltimore CyberTrust Root Certificate`_ - Server certificate, used to verify the server's certificate while connecting. #. Public device certificate - generated by the procedures described in `Creating Azure IoT Hub certificates`_ , used by Azure IoT Hub to authenticate the device. #. Private key of the device. .. important:: Azure has started the process of migrating their IoT Hub and DPS server certificates from `Baltimore CyberTrust Root Certificate`_ to `DigiCert Global Root G2`_. Azure advises to have both Baltimore CyberTrust Root and DigiCert Global Root G2 certificates for all devices to avoid disruption of service during the transition. Refer to `Azure IoT TLS: Critical changes`_ for updated information and timeline. Due to this, it is recommended to provision the DigiCert Root G2 certificate to a secondary security tag set by the :kconfig:option:`CONFIG_AZURE_IOT_HUB_SECONDARY_SEC_TAG` option. This ensures that the device can connect after the transition. .. note:: The location and name of the generated public device certificate and private key files vary depending on the method you use for the credential generation. For PowerShell scripts, the device certificate is called :file:`mydevice-public.pem` and the private key is :file:`mydevice-private.pem`. These files are located in the working directory with the other generated files. For bash scripts, the public device certificate is called :file:`new-device.cert.pem` and is located in a directory called :file:`certs` within the :file:`script` directory. The private key is called :file:`new-device.key.pem` and located in a directory called :file:`private` within the :file:`script` directory. The file and directory names may change if Azure changes their scripts. .. _azure_iot_hub_flash_certs: Provisioning of the certificates ================================ .. include:: /includes/cert-flashing.txt .. note:: The chosen security tag while provisioning the certificates must be same as the security tag configured by the :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEC_TAG` option. .. note:: If more than one root server certificate is used, the second one can be provisioned to a different security tag and configured in the application using the :kconfig:option:`CONFIG_AZURE_IOT_HUB_SECONDARY_SEC_TAG` Kconfig option. The modem will check both security tags if necessary when verifying the server's certificate. Configuring the library ======================= You can configure the library to connect to Azure IoT Hub with or without using DPS. Configuration without using DPS +++++++++++++++++++++++++++++++ To connect to Azure IoT Hub without using DPS, complete the following minimum required configuration: 1. In the `Azure Portal`_, navigate to :guilabel:`IoT Hub` and select the desired IoT hub. #. In the overview page, locate and copy the ``Hostname`` and configure :kconfig:option:`CONFIG_AZURE_IOT_HUB_HOSTNAME` to this address. The hostname can also be set at run time. #. Set the option :kconfig:option:`CONFIG_AZURE_IOT_HUB_DEVICE_ID` to the device ID. The device ID must match with the one used while creating the certificates. You can also set the device ID at run time by populating the ``device_id`` member of the :c:struct:`azure_iot_hub_config` structure passed to the :c:func:`azure_iot_hub_connect` function when connecting. If the ``device_id.size`` buffer size is zero, the compile-time option :kconfig:option:`CONFIG_AZURE_IOT_HUB_DEVICE_ID`` is used. #. Make sure that the device is already registered with your Azure IoT Hub, or follow the instructions in `Registering the device with Azure IoT Hub`_. #. Set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEC_TAG` option to the security tag used in :ref:`azure_iot_hub_flash_certs`. Optionally, set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEC_TAG` option if multiple server certificates are provisioned. .. _dps_config: Configuration using DPS +++++++++++++++++++++++ To connect to Azure IoT Hub using DPS, complete the following steps: 1. `Set up an Azure IoT Hub Device Provisioning Service (DPS) instance`_ and obtain the ID scope. #. `Add certificates to the DPS instance`_. #. Create an *enrollment group* as described in `Device enrollments with Azure Portal`_ and link it to your IoT hub. Select the certificate added in the previous step as the *Primary certificate​​​​​​​*. #. Enable :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS`. #. In the `Azure Portal`_, click :guilabel:`Device Provisioning Services` and select the DPS instance to use. #. In the overview page, locate and copy the ``ID Scope`` and set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_ID_SCOPE` option to this string. Alternatively, you can set the registration ID at run time. #. Set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_REG_ID` option to the registration ID. You can also set the registration ID at run time. #. Set :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEC_TAG` to the security tag used while :ref:`azure_iot_hub_flash_certs`. Optionally, set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEC_TAG` option if multiple server certificates are provisioned. Application integration *********************** Initializing the library ======================== The library is initialized by calling the :c:func:`azure_iot_hub_init` function. The initialization must be successful to make the other APIs in the library available for the application. An event handler is passed as the only argument to the :c:func:`azure_iot_hub_init` function. The library calls this function with data associated to the application, such as incoming data and other events. For an exhaustive list of event types and associated data, see :c:enum:`azure_iot_hub_evt_type`. Using the Device Provisioning Service ===================================== You can use the Azure IoT Hub Device Provisioning Service to provision the device to an IoT Hub. When the registration process has completed successfully, the device receives its assigned hostname and device ID to use when connecting to Azure IoT Hub. The assigned hostname and device ID are stored to the non-volatile memory on the device and are available also after a reset and power outage. This code example shows how to configure and use DPS: .. code-block:: c static void dps_handler(enum azure_iot_hub_dps_reg_status state) { switch (state) { case AZURE_IOT_HUB_DPS_REG_STATUS_NOT_STARTED: LOG_INF("AZURE_IOT_HUB_DPS_REG_STATUS_NOT_STARTED"); break; case AZURE_IOT_HUB_DPS_REG_STATUS_ASSIGNING: LOG_INF("AZURE_IOT_HUB_DPS_REG_STATUS_ASSIGNING"); break; case AZURE_IOT_HUB_DPS_REG_STATUS_ASSIGNED: LOG_INF("AZURE_IOT_HUB_DPS_REG_STATUS_ASSIGNED"); /* Act on assignment */ k_sem_give(&dps_assigned_sem); break; case AZURE_IOT_HUB_DPS_REG_STATUS_FAILED: LOG_INF("ZURE_IOT_HUB_DPS_REG_STATUS_FAILED"); /* Act on registration failure */ k_sem_give(&dps_registration_failed_sem); break; default: LOG_WRN("Unhandled DPS registration status: %d", state); break; } } ... int err; struct azure_iot_hub_buf assigned_hostname; struct azure_iot_hub_buf assigned_device_id; struct azure_iot_hub_dps_config dps_cfg = { .handler = dps_handler, /* Can be left out to use CONFIG_AZURE_IOT_HUB_DPS_REG_ID instead. */ .reg_id = { .ptr = device_id_buf, .size = device_id_len, }, /* Can be left out to use CONFIG_AZURE_IOT_HUB_DPS_ID_SCOPE instead. */ .id_scope = { .ptr = id_scope_buf, .size = id_scope_len, }, }; err = azure_iot_hub_dps_init(&dps_cfg); /* Error handling */ err = azure_iot_hub_dps_start(); if (err == 0) { LOG_INF("The DPS process has started"); /* Wait for the registration process to complete. */ err = k_sem_take(&dps_done_sem, K_SECONDS(SOME_TIMEOUT)); /* Error handling */ } else if (err == -EALREADY) { LOG_INF("Already assigned to an IoT hub, skipping DPS"); } else { /* Error handling */ } err = azure_iot_hub_dps_hostname_get(assigned_hostname); /* Error handling */ err = azure_iot_hub_dps_device_id_get(assigned_device_id); /* Error handling */ /* Use the hostname and device ID to connect to IoT Hub. */ After successfully registering the device, the application can proceed to connect to the assigned IoT Hub using the obtained device ID. When a device has been assigned to an IoT Hub and the information is stored to the non-volatile memory, the DPS APIs always return the stored information and do not trigger a new registration. To delete the stored assignment information, call the :c:func:`azure_iot_hub_dps_reset` function. Alternatively, you can call the functions :c:func:`azure_iot_hub_dps_hostname_delete` or :c:func:`azure_iot_hub_dps_device_id_delete` to delete specific information. After calling the :c:func:`azure_iot_hub_dps_reset` function, the library must be initialized again. After the initialization, a new registration with the DPS can be started by calling the :c:func:`azure_iot_hub_dps_start` function. The DPS APIs are documented in the :ref:`azure_iot_hub_dps_api` section. Connecting to Azure IoT Hub =========================== After the initialization, calling the :c:func:`azure_iot_hub_connect` function connects the device to the configured IoT hub or DPS instance, depending on the configuration. The initial TLS handshake takes a few seconds to complete, depending on the network conditions and the TLS cipher suite used. During the TLS handshake, the :c:func:`azure_iot_hub_connect` function blocks. Consider this when deciding the context from which the API is called. Optionally, DPS registration can be run automatically as part of the call to the :c:func:`azure_iot_hub_connect` function. Note that the :c:func:`azure_iot_hub_connect` function blocks when DPS registration is pending. Running DPS as part of the :c:func:`azure_iot_hub_connect` function also limits the DPS configuration options as follows: * The device ID is used as registration ID when registering with the DPS server. * The ID scope is set in the :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_ID_SCOPE` option. Use the DPS APIs directly if you need more control over the DPS registration process. When using the :c:func:`azure_iot_hub_connect` function, you can choose to provide the hostname to the IoT Hub and device ID at run time, or let the library use Kconfig options. Here is an example for setting the hostname and device ID at run time: .. code-block:: c struct azure_iot_hub_config cfg = { .hostname = { .ptr = hostname_buffer, .size = hostname_length, }, .device_id = { .ptr = device_id_buffer, .size = device_id_length, }, .use_dps = false, }; err = azure_iot_hub_connect(&cfg); /* Error handling */ You can pass ``NULL`` or a zeroed out configuration to the :c:func:`azure_iot_hub_connect` function. The library uses the values for hostname and device ID from the Kconfig options :kconfig:option:`CONFIG_AZURE_IOT_HUB_HOSTNAME` and :kconfig:option:`CONFIG_AZURE_IOT_HUB_DEVICE_ID`, respectively. This code example uses a Kconfig value for the device ID (and by extension DPS registration ID) and runs DPS to acquire the assigned IoT Hub hostname and assigned device ID. .. code-block:: c struct azure_iot_hub_config cfg = { .use_dps = true, }; err = azure_iot_hub_connect(&cfg); /* Error handling */ After a successful connection, the library automatically subscribes to the following standard Azure IoT Hub MQTT topics (See `Azure IoT Hub MQTT protocol support`_ for details): * ``devices//messages/devicebound/#`` (cloud-to-device messages) * ``$iothub/twin/PATCH/properties/desired/#`` (desired properties update notifications) * ``$iothub/twin/res/#`` (operation responses) * ``$iothub/methods/POST/#`` (direct method requests) Currently, the library does not support persistent MQTT sessions. Hence subscriptions are requested for each connection to the IoT hub. For more information about the available APIs, see the :ref:`azure_iot_hub_api` section. Configuration ************* To use the Azure IoT Hub library, you must enable the :kconfig:option:`CONFIG_AZURE_IOT_HUB` Kconfig option. You can configure the following options when using this library: * :kconfig:option:`CONFIG_AZURE_IOT_HUB_HOSTNAME` - Sets the Azure IoT Hub host name. Note that the hostname can also be provided at run time. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DEVICE_ID` - Configures the device ID. The device ID can also be set at run time. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEND_TIMEOUT` - Enables timeout when sending data to an IoT Hub. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEND_TIMEOUT_SEC` - The send timeout (in seconds) to use when sending data. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_USER_NAME_BUF_SIZE` - Set the user name buffer size. You can adjust the buffer size to reduce stack usage, if you know the approximate size of your device ID. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_SEC_TAG` - Security tag where the Azure IoT Hub certificates are stored. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_SECONDARY_SEC_TAG` - Secondary security tag that can be used for a second CA root certificate. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_PORT` - TCP port number to connect to. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_MQTT_RX_TX_BUFFER_LEN` - Size of the MQTT RX and TX buffer that limits the message size, excluding the payload size. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_MQTT_PAYLOAD_BUFFER_LEN` - MQTT payload buffer size. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_STACK_SIZE` - Stack size for the internal thread in the library. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_AUTO_DEVICE_TWIN_REQUEST` - Automatically request the device twin upon connection to an IoT Hub. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_TOPIC_MAX_LEN` - The maximum topic length. The topic buffers are allocated on the stack. You may have to adjust this option to match with your device ID length. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_MSG_PROPERTY_RECV_MAX_COUNT` - The maximum number of message properties that can be parsed from an incoming message's topic. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_MSG_PROPERTY_BUFFER_SIZE` - The size of the internal message property buffer used when sending messages with message properties, allocated on the stack. You can adjust this to fit your needs. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_NATIVE_TLS` - Configures the socket to be native for TLS instead of offloading TLS operations to the modem. DPS-specific configuration: * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS` - Enables Azure IoT Hub DPS. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_HOSTNAME` - Hostname of the DPS server. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_REG_ID` - Registration ID to use in the registration request to DPS. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_HOSTNAME_MAX_LEN` - Maximum length of the assigned hostname received from DPS. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_DEVICE_ID_MAX_LEN` - Maximum length of the assigned device ID received from DPS. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_TOPIC_BUFFER_SIZE` - Size of the internal topic buffers in the DPS library. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_USER_NAME_BUFFER_SIZE` - User name buffer size. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_ID_SCOPE` - Sets the Azure IoT Hub DPS ID scope that is used while provisioning the device. * :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_OPERATION_ID_BUFFER_SIZE` - Size of the operation ID buffer. The operation ID is received from the IoT Hub during registration. API documentation ***************** .. _azure_iot_hub_api: Azure IoT Hub API ================= | Header file: :file:`include/net/azure_iot_hub.h` | Source files: :file:`subsys/net/lib/azure_iot_hub/src/azure_iot_hub.c` .. _azure_iot_hub_dps_api: Azure IoT Hub DPS API ===================== | Header file: :file:`include/net/azure_iot_hub_dps.h` | Source files: :file:`subsys/net/lib/azure_iot_hub/src/azure_iot_hub_dps.c` .. doxygengroup:: azure_iot_hub :project: nrf :members: