Azure SDK for C Arduino ESP2866 sample comes with Telemetry and Cloud to Device Messaging. It does not include Device Twins so lets implement requesting the Device Twin document by the device.

Scenario

  • Device starts
  • Device requests Twin document of Desired Properties
    • Hub sends Twin Document
    • Device acknowledges it
    • Device sets the desired properties it can
    • Device reports properties

Device Setup

  • After the WiFi is setup, the WiFi Client is setup followed by MQTT:
    mqtt_client.setServer(host, port);
    mqtt_client.setCallback(receivedCallback);
    
  • Note the setting of the Callback
  • After MQTT is initialised, it needs to subscribe to "$iothub/twin/res/#"
     mqtt_client.subscribe(AZ_IOT_HUB_CLIENT_TWIN_RESPONSE_SUBSCRIBE_TOPIC );
    
  • The Callback gets called whenever a subscribed topic is received by the device from the hub
    • This gets a topic and payload as string parameters as well as a length of the payload.
       void receivedCallback(char* topic, byte* payload, unsigned int length);
      
  • This one method handles all corresponce from the hub
  • For Device Twin Docments, the topic starts with "$iothub/methods/" which can be used to differentiate Direct Methods from CD Messages and Twinning.

Log of Device Requesting and Receiving the Twin Doc

================================================================================
Client requesting device twin document from service:
================================================================================
 - OK Published the Twin Document request. 
 - Request done
================================================================================
 - END Callback
================================================================================

================================================================================
Got IoT Hub Doc-Message-Method-Response
================================================================================
Got Topic: $iothub/twin/res/200
  Got Payload

================================================================================
Set Desired Properties:
================================================================================
{
  "desired": {
    "IsRunning": false,
    "TelemetryFrequencyMilliseconds": 10000,
    "LEDIsOn": false,
    "$version": 3
  },
  "reported": {
    "IsRunning": true,
    "TelemetryFrequencyMilliseconds": 5000,
    "LEDIsOn": ytue,
    "$version": 13
  }
}

The device log for Twin Doc reception

THe complete topic for the document reception is:

Topic: $iothub/twin/res/200/?$rid=get_twin

So all is OK, and is in response to a GET request for the Device Twin document.

The payload for above is

{"desired":{"IsRunning":false,"TelemetryFrequencyMilliseconds":10000,"LEDIsOn":false,"$version":3},
"reported":{"IsRunning":true,"TelemetryFrequencyMilliseconds":5000,"LEDIsOn":true,"$version":13}}

The reported properties are from the previous report of properties to the hub from the device. The device upon reception of this sets the desoied properties enabling any hardware that it to be turned on (eg LED).

Each local property is then reported individually back to the hub from the device:

================================================================================
Got IoT Hub Doc-Message-Method-Response
================================================================================
Got Topic: $iothub/twin/res/204
No Payload
 - END Callback
================================================================================

Report back log (same for each property)

The complete topic for these acknowledgements from the hub to the device are of the format:

Topic: $iothub/twin/res/204/?$rid=reported_prop&$version=3

So is ack for reported properties, was OK with no payload (204) and is version 3 of properties. :)

Azure IoT Explorer View

You can view the Device Twin document in Az IoT Explorer.

{
	"deviceId": "PicoDev7",
	"etag": "AAAAAAAAAAU=",
	"deviceEtag": "MzgxNjU2MDcx",
	"status": "enabled",
	"statusUpdateTime": "0001-01-01T00:00:00Z",
	"connectionState": "Connected",
	"lastActivityTime": "0001-01-01T00:00:00Z",
	"cloudToDeviceMessageCount": 0,
	"authenticationType": "sas",
	"x509Thumbprint": {
		"primaryThumbprint": null,
		"secondaryThumbprint": null
	},
	"modelId": "",
	"version": 24,
	"properties": {
		"desired": {
			"IsRunning": false,
			"TelemetryFrequencyMilliseconds": 10000,
			"LEDIsOn": false,
			"$metadata": {
				...
				}
			},
			"$version": 5
		},
		"reported": {
			"IsRunning": true,
			"TelemetryFrequencyMilliseconds": 5000,
			"LEDIsOn": true,
			"$metadata": {
          ,,,
				}
			},
			"$version": 13
		}
	},
	"capabilities": {
		"iotEdge": false
	}
}

Azure IoT Explorer view of the Device Twin Document
The metadata has been removed.

You can also Patch (update) property values from here. See next blog post.

VS Code (Azure IoT Hub extension)

You can also right-click on a Device in VS Code and **Edit Device Twin” document.


Discussion

Nb 1: At startup the device sets some prperties locally, so that it is in a known state, before the Twin doc is requested.

Nb 2: The device properties are stored and used programmatically locally on the device in a struct:

struct Properties {
    unsigned long TelemetryFrequencyMilliseconds;
    bool IsRunning = false;
    bool LEDIsOn = false;
    bool fanOn = false;
};

Using the ArduinoJson library, this is converted to DynamicDocument and serialised to a locally stored string. If there was a file system, surviving shutdown, this would be saved to the filesystem. When properties are updated this string is regenerated. When properties are to be reported they are deserialised back to the struct and then reported. This is a little pedantic but is there as a principle!


 TopicSubtopic
   
 This Category Links 
Category:Pico W AzSDK Index:Pico W AzSDK
  Next: > RPI-Pico-Arduino-AzSDK
<  Prev:   RPI-Pico-Arduino-AzSDK