Skip to content

IoT Hub Device Twins

Dave Glover edited this page Jan 31, 2022 · 9 revisions

Device Twins and Properties


Examples

Code example, working with Device Twins


Config app_manifest.json sample

  1. Set ID Scope
  2. Set Allowed connections
  3. Set DeviceAuthentication

Binding

Device twin bidning.

typedef struct _deviceTwinBinding {
    const char* propertyName;
    void* propertyValue;
    int propertyVersion;
    bool propertyUpdated;
    DX_DEVICE_TWIN_TYPE twinType;
    void (*handler)(struct _deviceTwinBinding* deviceTwinBinding);
    void *context;
} DX_DEVICE_TWIN_BINDING;

Binding Functions

bool dx_deviceTwinAckDesiredValue(DX_DEVICE_TWIN_BINDING* deviceTwinBinding, void* state, DX_DEVICE_TWIN_RESPONSE_CODE statusCode);
bool dx_deviceTwinReportValue(DX_DEVICE_TWIN_BINDING* deviceTwinBinding, void* state);
void dx_deviceTwinSubscribe(DX_DEVICE_TWIN_BINDING* deviceTwins[], size_t deviceTwinCount);
void dx_deviceTwinUnsubscribe(void);

Binding handler

void (*handler)(struct _deviceTwinBinding* deviceTwinBinding)

Example.

void device_twin_handler(DX_DEVICE_TWIN_BINDING *deviceTwinBinding);

Enums

Device twin types

typedef enum {
    DX_TYPE_UNKNOWN = 0,
    DX_DEVICE_TWIN_BOOL = 1,
    DX_DEVICE_TWIN_FLOAT = 2,
    DX_DEVICE_TWIN_DOUBLE = 3,
    DX_DEVICE_TWIN_INT = 4,
    DX_DEVICE_TWIN_STRING = 5,
    DX_DEVICE_TWIN_JSON_OBJECT = 6
} DX_DEVICE_TWIN_TYPE;

Device twin acknowledgment codes

typedef enum
{
    DX_DEVICE_TWIN_RESPONSE_COMPLETED = 200,
    DX_DEVICE_TWIN_RESPONSE_ERROR = 500,
    DX_DEVICE_TWIN_REPONSE_INVALID = 404
} DX_DEVICE_TWIN_RESPONSE_CODE;

Macros

DX_DEVICE_TWIN_HANDLER(name, deviceTwinBinding)
DX_DEVICE_TWIN_HANDLER_END
DX_DECLARE_DEVICE_TWIN_HANDLER(name)

Usage

Understanding IoT Hub device twins

Azure IoT Hub and IoT Central use device twins to represent point-in-time values. IoT Hub can use device twins to set state on a device, for example, set the desired room temperature. A device can also use device twins to report its current state, for example, report the operating mode of an HVAC (Heating, Ventilation, and Air Conditioning) unit, is it currently heating, cooling, or turned off.

Device twins are JSON documents that Azure IoT Hub keeps in the cloud for all devices and is used for storing device information, including metadata, configurations, and conditions. IoT Hub device twins are often used for long-running commands intended to put the device into a certain state and return it to that state after a device restart. For example, setting the desired room temperature.

Properties can be used in the following ways:

  • Cloud-to-device updates
  • Device-to-cloud updates
  • Querying reported properties

Controlling the heating, ventilation, and air conditioning unit (HVAC) using Azure IoT Hub device twins

From Azure IoT Explorer you can set the desired temperature twin. The device actions and acknowledges the request. Azure IoT Hub updates the device twin reported property and IoT Explorer then queries and display this reported property.

The illustration shows a cloud to device device twin configuration pattern.

Steps to controlling the HVAC unit from IoT Explorer

The following steps outline how Azure IoT Explorer uses device twins to set properties on a device:

  1. You can set the desired room temperature from Azure IoT Explorer.
  2. Azure IoT Hub updates the device twin desired property and sends a device twin message to the device.
  3. The corresponding device twin handler function is called.
  4. The device implements the desired property; in this case, turn on the heater or cooler to bring the room to the desired temperature.
  5. The device acknowledges the updated configuration to Azure IoT Hub. Azure IoT Hub updates the device twin reported property.
  6. IoT Explorer queries and displays the device twin reported property data.

Getting started with device twin bindings

A device twin binding maps a device twin property name with a handler function that will be called to implement the action.

The following example declares a Device Twin Binding to set the desired room temperature. This declaration maps the Azure IoT Hub DesiredTemperature device twin with a handler function named DeviceTwinSetTemperatureHandler.

// Forward declaration of Device Twin handler
static DX_DECLARE_DEVICE_TWIN_HANDLER(DeviceTwinSetTemperatureHandler);

static DX_DEVICE_TWIN_BINDING dt_desiredTemperature = {
        .propertyName = "DesiredTemperature",
        .twinType = DX_DEVICE_TWIN_FLOAT,
        .handler = DeviceTwinSetTemperatureHandler,
        .context = "DesiredTemperature Object"};

Setting the desired temperature

The following is the implementation of the handler function DeviceTwinSetTemperatureHandler. The handler function is called when the device receives a DesiredTemperature desired property message from Azure IoT Hub.

As part of the IoT Plug and Play conventions, the device should acknowledge the device twin update with a call to dx_deviceTwinAckDesiredState.

/// <summary>
/// Device Twin Handler to set the desired temperature value
/// </summary>
static DX_DEVICE_TWIN_HANDLER(DeviceTwinSetTemperatureHandler, deviceTwinBinding)
{
    // validate data is sensible range before applying
    char* context = (char*)deviceTwinBinding->context;
    Log_Debug("%s\n", context);

    if (deviceTwinBinding->twinType == DX_DEVICE_TWIN_FLOAT  && *(float*)deviceTwinBinding->propertyValue >= -20.0f && *(float*)deviceTwinBinding->propertyValue <= 80.0f)
    {
        dx_deviceTwinAckDesiredValue(deviceTwinBinding, deviceTwinBinding->propertyValue,
                                     DX_DEVICE_TWIN_RESPONSE_COMPLETED);
        // SetHvacStatusColour((int)previous_temperature);
    }
    else {
        dx_deviceTwinAckDesiredValue(deviceTwinBinding, deviceTwinBinding->propertyValue, DX_DEVICE_TWIN_RESPONSE_ERROR);
    }
}
DX_DEVICE_TWIN_HANDLER_END

Set a HVAC panel message

static char display_panel_message[64];
// Forward declaration of Device Twin handler
static DX_DECLARE_DEVICE_TWIN_HANDLER(dt_set_panel_message_handler);

static DX_DEVICE_TWIN_BINDING dt_hvac_panel_message = {
    .propertyName = "HvacPanelMessage",
    .twinType = DX_DEVICE_TWIN_STRING,
    .handler = dt_set_panel_message_handler
};

A reference to the device twin string is only available for the lifetime of the callback.

// This device twin callback demonstrates how to manage device twins of type string.
// A reference to the device twin string is only available for the lifetime of the callback.
// You must copy to a global char array to preserve the string outside of the callback.
// As strings are arbitrary length on a constrained device this gives you, the developer, control of memory allocation.
static DX_DEVICE_TWIN_HANDLER(dt_set_panel_message_handler, deviceTwinBinding)
{
    char *panel_message = (char *)deviceTwinBinding->propertyValue;

    // Is the message size less than the destination buffer size and printable characters
    if (strlen(panel_message) < sizeof(display_panel_message) && dx_isStringPrintable(panel_message))
    {
        strncpy(display_panel_message, panel_message, sizeof(display_panel_message));
        dx_Log_Debug("Virtual HVAC Display Panel Message: %s\n", display_panel_message);
        // IoT Plug and Play acknowledge completed
        dx_deviceTwinAckDesiredValue(deviceTwinBinding, deviceTwinBinding->propertyValue, DX_DEVICE_TWIN_RESPONSE_COMPLETED);
    }
    else
    {
        dx_Log_Debug("Local copy failed. String too long or invalid data\n");
        // IoT Plug and Play acknowledge error
        dx_deviceTwinAckDesiredValue(deviceTwinBinding, deviceTwinBinding->propertyValue, DX_DEVICE_TWIN_RESPONSE_ERROR);
    }
}
DX_DEVICE_TWIN_HANDLER_END

Reporting the current HVAC operating mode

The HVAC operating mode depends on the room temperature, it can be heating, or cooling, or turned off. We can use a device-to-cloud device twin update to report the current operating mode of the HVAC unit.

Device-to-cloud updates

The illustration shows a device to cloud device twin configuration pattern.

  1. The Azure Sphere detects the HVAC operating mode has changed.
  2. The Azure Sphere sends a device twin message to report the new operating mode of the HVAC to Azure IoT Hub.
  3. IoT Explorer queries and displays the updated operating mode of the HVAC unit.

The following example declares a ReportedHvacState device twin property of type string. A handler function is not required as this is a one-way device-to-cloud binding.

static DX_DEVICE_TWIN_BINDING dt_reportedHvacState = {
    .propertyName = "ReportedHvacState",
    .twinType = DX_DEVICE_TWIN_STRING };

The device updates the ReportedHvacState property by calling the dx_deviceTwinReportState function. You must pass a property of the correct type.

dx_deviceTwinReportValue(&dt_reportedHvacState, (void*)hvacState[(int)current_led]);

How device twin messages are mapped to handlers

All declared device twin bindings must be added by reference to the deviceTwinBindingSet array. When a device twin message is received by the device, it is checked for a matching twinProperty name in the deviceTwinBindingSet array. When a match is found, the corresponding handler function is called.

DX_DEVICE_TWIN_BINDING* deviceTwinBindingSet[] = { &dt_desiredTemperature, &dt_reportedTemperature, &dt_reportedHvacState };

Opening the device twin binding set

The device twin binding set is initialized in the InitPeripheralsAndHandlers function in main.c.

dx_deviceTwinSubscribe(device_twin_bindings, NELEMS(device_twin_bindings));

Closing the device twin binding set

The device twin bindings set is closed in the ClosePeripheralsAndHandlers function in main.c.

dx_deviceTwinUnsubscribe();

Working Examples

Direct methods example

Direct methods example Json Object

Clone this wiki locally