Hi,
i'm trying to write C# code to update a digital twin object property using Azure Service Bus queue data from an Iot Central device that sends telemetry.
Azure Service Bus queue works fine and correctly receives telemetry data from an Iot Central device.
Here is the device template:
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest;1",
"@type": "Interface",
"contents": [
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemData;1",
"@type": "Telemetry",
"displayName": {
"en": "LibraryItemData"
},
"name": "LibraryItemData",
"schema": {
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemData:schema;1",
"@type": "Object",
"displayName": {
"en": "Object"
},
"fields": [
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemData:schema:ItemId;1",
"displayName": {
"en": "ItemId"
},
"name": "ItemId",
"schema": "string"
},
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemData:schema:Description;1",
"displayName": {
"en": "Description"
},
"name": "Description",
"schema": "string"
},
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemData:schema:Location;1",
"displayName": {
"en": "Location"
},
"name": "Location",
"schema": "string"
},
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemData:schema:DateTimeValue;1",
"displayName": {
"en": "DateTimeValue"
},
"name": "DateTimeValue",
"schema": "dateTime"
}
]
}
},
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemDataProperty;1",
"@type": "Property",
"displayName": {
"en": "LibraryItemDataProperty"
},
"name": "LibraryItemDataProperty",
"schema": {
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemDataProperty:schema;1",
"@type": "Object",
"displayName": {
"en": "Object"
},
"fields": [
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemDataProperty:schema:ItemId;1",
"displayName": {
"en": "ItemId"
},
"name": "ItemId",
"schema": "string"
},
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemDataProperty:schema:Description;1",
"displayName": {
"en": "Description"
},
"name": "Description",
"schema": "string"
},
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemDataProperty:schema:Location;1",
"displayName": {
"en": "Location"
},
"name": "Location",
"schema": "string"
},
{
"@id": "dtmi:digitaltwins:org:archive:download:rfidsmartlibrary:RfidSmartLibraryowl:LibraryItemGateCheckSensorTest:LibraryItemDataProperty:schema:DateTime;1",
"displayName": {
"en": "DateTime"
},
"name": "DateTime",
"schema": "dateTime"
}
]
},
"writable": false
}
],
"displayName": {
"en": "LibraryItemGateCheckSensorTest"
},
"@context": [
"dtmi:iotcentral:context;2",
"dtmi:dtdl:context;2"
]
}
I used the same template to create a digital twin named "LibraryItemGateCheckSensorTest02".
This is an example of twin LibraryItemDataProperty update using json:
[
{
"op": "add",
"path": "/LibraryItemDataProperty",
"value": {
"ItemId": "USB 2364",
"Description": "”*Re-inventare la famiglia : guida teorico-pratica per i professionisti dell'educazione / a cura di Laura Formenti Santarcangelo di Romagna : Maggioli, 2016.. XXII, 451 p. ; 21 cm",
"Location": "Main Gate",
"DateTime": "2023-05-23T14:10:00"
}
}
]
and here is the code i developed to update LibraryItemDataProperty from property using Azure Service Bus queue data from an Iot Central device that send telemetry. DigitalTwinsManager.cs
using Azure;
using Azure.Core.Pipeline;
using Azure.DigitalTwins.Core;
using Azure.Identity;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
namespace RfidSmartLibraryConsoleApp.DigitalTwins
{
//public delegate void QueryResult(BasicDigitalTwin dt);
public class DigitalTwinsManager
{
private static readonly string adtInstanceUrl = "https://xxxxx.api.weu.digitaltwins.azure.net";
private DigitalTwinsClient client;
public DigitalTwinsManager()
{
Connect();
}
public void Connect()
{
var cred = new DefaultAzureCredential();
client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred);
}
public void UpdateDigitalTwinProperty(string twinId, string property, object value)
{
JsonPatchDocument patch = null;
try
{
patch = new JsonPatchDocument();
patch.AppendAdd("/" + property, value);
client.UpdateDigitalTwin(twinId, patch);
}
catch (RequestFailedException)
{
}
}
public void ManagedConnect(string appId)
{
HttpClient httpclient = new HttpClient();
var cred = new ManagedIdentityCredential(appId);
client = new DigitalTwinsClient(new Uri(adtInstanceUrl),
cred, new DigitalTwinsClientOptions { Transport = new HttpClientTransport(httpclient) });
}
public DigitalTwinsManager(string AppId)
{
ManagedConnect(AppId);
}
}
}
and IoTCentralTrigger.cs
using Microsoft.Azure.ServiceBus;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RfidSmartLibraryConsoleApp.DigitalTwins;
using Azure.DigitalTwins.Core;
using Azure;
namespace SmartBuildingSensorUpdater
{
public class IoTCentralTrigger
{
const string adtAppId = "https://digitaltwins.azure.net";
const string queueName = "iotcentral";
[FunctionName("IoTCentralTriggerTest")]
public void Run([ServiceBusTrigger(queueName,
Connection ="ServiceBusConnection")]
Message message,
ILogger log)
{
/*
Data Example to update
"LibraryItemData": {
"ItemId": "Eum suscipit accusantium aut porro.",
"Description": "Pariatur autem laborum.",
"Location": "Architecto necessitatibus exercitationem ut similique.",
"DateTimeValue": "2024-03-03T19:01:43.522Z"
},
Message body Example:
Received twinId: LibraryItemGateCheckSensorTest02
Received iotcentral-message-source: telemetry
Received message body: {
"applicationId": "xxx-34bf-x150-9ax4-fcxxxe86f84",
"deviceId": "LibraryItemGateCheckSensorTest02",
"enqueuedTime": "2023-05-22T16:56:35.12Z",
"enrichments": {},
"messageProperties": {
"iothub-creation-time-utc": "2023-05-22T16:56:35.096Z"
},
"messageSource": "telemetry",
"schema": "default@v1",
"telemetry": {
"LibraryItemData": {
"DateTimeValue": "2024-02-13T01:11:52.592Z",
"Description": "Quo temporibus vero totam.",
"ItemId": "Nisi quas temporibus doloribus id.",
"Location": "Impedit porro quidem omnis ex et in et voluptatem."
}
},
"templateId": "dtmi:hwzomnev:mt5wwsum"
}
Json example to update twin LibraryItemDataProperty :
[
{
"op": "add",
"path": "/LibraryItemDataProperty",
"value": {
"ItemId": "USB 2364",
"Description": "”*Re-inventare la famiglia : guida teorico-pratica per i professionisti dell'educazione / a cura di Laura Formenti Santarcangelo di Romagna : Maggioli, 2016.. XXII, 451 p. ; 21 cm",
"Location": "Main Gate",
"DateTime": "2023-05-23T14:10:00"
}
}
]
*/
Console.WriteLine("*********************************************************");
string twinId = message.UserProperties["iotcentral-device-id"].ToString();
//Console.WriteLine($"Received twinId: {twinId}");
string iotcentralMessageSource = message.UserProperties["iotcentral-message-source"].ToString();
//Console.WriteLine($"Received iotcentral-message-source: {iotcentralMessageSource}");
var body = message.Body;
var text = Encoding.UTF8.GetString(body);
var messagebody = JsonConvert.DeserializeObject(text);
//Console.WriteLine($"Received message body: {messagebody}");
string value = Encoding.ASCII.GetString(message.Body, 0, message.Body.Length);
//Console.WriteLine($"Received value: {value}");
var bodyProperties = (JObject)JsonConvert.DeserializeObject(value);
//Console.WriteLine($"Received bodyProperties: {bodyProperties}");
JToken LibraryItemDataToken = bodyProperties["telemetry"]["LibraryItemData"];
Console.WriteLine($"Received LibraryItemDataToken: {LibraryItemDataToken}");
JToken LibraryItemDataItemIdToken = bodyProperties["telemetry"]["LibraryItemData"]["ItemId"];
string ItemId = LibraryItemDataItemIdToken.Value<string>();
//Console.WriteLine($"Received ItemId: {ItemId}");
JToken LibraryItemDataDescriptionToken = bodyProperties["telemetry"]["LibraryItemData"] ["Description"];
string Description = LibraryItemDataDescriptionToken.Value<string>();
//Console.WriteLine($"Received Description: {Description}");
JToken LibraryItemLocationToken = bodyProperties["telemetry"]["LibraryItemData"]["Location"];
string Location = LibraryItemLocationToken.Value<string>();
//Console.WriteLine($"Received Location: {Location}");
JToken LibraryItemDateTimeToken = bodyProperties["telemetry"]["LibraryItemData"]["DateTimeValue"];
string DateTimeValue = LibraryItemDateTimeToken.Value<string>();
//Console.WriteLine($"Received DateTimeValue: {DateTimeValue}");
Console.WriteLine("*********************************************************");
log.LogInformation(string.Format("Sensor ItemID:{0}", ItemId));
log.LogInformation(string.Format("Sensor Description:{0}", Description));
log.LogInformation(string.Format("Sensor Location:{0}", Location));
log.LogInformation(string.Format("Sensor DateTime:{0}", DateTimeValue));
DigitalTwinsManager manager = new DigitalTwinsManager(adtAppId);
Console.WriteLine($"Twin {twinId} property updating..");
manager.UpdateDigitalTwinProperty(twinId, "LibraryItemDataProperty", LibraryItemDataDescriptionToken);
}
}
}
it's not clear to me how to manage object property "LibraryItemDataProperty" in UpdateDigitalTwinProperty function as indicated in json file. Look at the following snapshot about running:
So my code doesn't update the twin object property.
I think the issue is in value of patch.AppendAdd("/" + property, value) but i can't manage value that should be like this:
"value": {
"ItemId": "USB 2364",
"Description": "”*Re-inventare la famiglia : guida teorico-pratica per i professionisti dell'educazione / a cura di Laura Formenti Santarcangelo di Romagna : Maggioli, 2016.. XXII, 451 p. ; 21 cm",
"Location": "Main Gate",
"DateTime": "2023-05-23T14:10:00"
}
i haven't found an example like this one in https://learn.microsoft.com/en-us/azure/digital-twins/how-to-manage-twin.
Any help is welcome.
Thanks in advance.
Guido