azure-iot-hubazure-digital-twins

how to get telemetry data from iothub to Azure Digital Twins


I would like to send the telemetry data from the IOT hub to Azure digital twins, but I can't get it. I have tested the complete example from Microsoft (https://learn.microsoft.com/en-us/azure/digital-twins/how-to-ingest-iot-hub-data) without success. Should I add something else or what can I change? here is the integration where I think it is missing the Digital Twins as output

enter image description here

Thanks

 public static class Function1
    {
        
        private static readonly string adtInstanceUrl = Environment.GetEnvironmentVariable("ADT_SERVICE_URL");
        
        private static readonly HttpClient singletonHttpClientIntance = new HttpClient();

        [FunctionName("IOTHubtoADTwins")]
        public static async Task Run ([EventGridTrigger]EventGridEvent eventGridEvent, ILogger log)
        {
           
            if (adtInstanceUrl == null) log.LogError("Application setting \"ADT_SERVICE_URL\" not set");

            try
            {
                //log.LogInformation(eventGridEvent.Data.ToString());

                //manager für die identity
                var cred = new ManagedIdentityCredential("https://digitaltwins.azure.net");

               
                var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred,
                new DigitalTwinsClientOptions
                {
                    Transport = new HttpClientTransport(singletonHttpClientIntance)
                });

            
                log.LogInformation($" ADT service client connection created.");

            
                if (eventGridEvent != null && eventGridEvent.Data != null)
                {
                    log.LogInformation(eventGridEvent.Data.ToString());

                    JObject deviceMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());

                    string deviceId = (string)deviceMessage["systemProperties"]["iothub-connection-device-id"];
                    var Auto = deviceMessage["body"]["Auto"];

                    log.LogInformation($"Device:{deviceId} Auto is: {Auto}");

                    var updateTwinData = new JsonPatchDocument();
                    updateTwinData.AppendReplace("/Auto", Auto.Value<bool>());
                    await client.UpdateDigitalTwinAsync(deviceId, updateTwinData);
                }
            }
            catch(Exception ex)
            {
                log.LogError($"Error in ingest function: {ex.Message}"); 
            }
        }
    }
    

I receive this Error message

2023-05-18T14:41:51Z [Information] Executed 'IOTHubtoADTwins' (Succeeded, Id=e5f6558b-a2f2-4f34-8326-caea78585e4e, Duration=3430ms) 2023-05-18T14:41:53Z [Information] Executing 'IOTHubtoADTwins' (Reason='EventGrid trigger fired at 2023-05-18T14:41:52.9272358+00:00', Id=b8c6c105-03c9-47fa-a5b0-b38b2e05b4f4) 2023-05-18T14:41:53Z [Information] ADT service client connection created. 2023-05-18T14:41:53Z [Information] {"properties":{},"systemProperties":{"iothub-connection-device-id":"Modell","iothub-connection-auth-method":"{\u0022scope\u0022:\u0022device\u0022,\u0022type\u0022:\u0022sas\u0022,\u0022issuer\u0022:\u0022iothub\u0022,\u0022acceptingIpFilterRule\u0022:null}","iothub-connection-auth-generation-id":"638200132745402706","iothub-enqueuedtime":"2023-05-18T14:41:52.525Z","iothub-message-source":"Telemetry"},"body":"eyJUZW1wZXJhdHVyIiA6ICIwLjAiLCJIdW1pZGl0eSIgOiAiMC4wIix9"}

2023-05-18T14:41:56Z [Error] Error in ingest function: Cannot access child value on Newtonsoft.Json.Linq.JValue.

Thanks for the feedback, have changed everything so far but get a different error message:

2023-05-18T22:21:00Z [Error] Error in ingest function: Value cannot be null. (Parameter 'source')

to send the message user the following Python code:

import json
from opcua import Client
from time import sleep
from azure.iot.device import IoTHubDeviceClient, Message

# OPC UA Node-IDs
opc_node_ids = {
    "Auto": 'ns=3;s="Send"."Auto"'
}

# OPC UA Client initialisieren
def opcua_init():
    opcua_client = Client("x")  # OPC UA-Adresse einsetzen
    while True:
        try:
            print("Trying to connect to the OPC UA server...")
            opcua_client.connect()
            return opcua_client
        except:
            print("Connection failed. Trying again after 5 seconds...")
            sleep(5)

# IoT Hub-Client initialisieren
def iot_hub_init():
    while True:
        try:
            iot_client = IoTHubDeviceClient.create_from_connection_string("x", websockets=True)  # IoT-Verbindungszeichenfolge einsetzen
            print("Trying to connect to the IoT Hub...")
            iot_client.connect()
            return iot_client
        except:
            print("Connection failed. Trying again after 5 seconds...")
            sleep(5)

# Daten von OPC UA-Server abrufen und als JSON-String zurückgeben
def opcua_get_value(client):
    opcua_data = {}
    for node_name, node_id in opc_node_ids.items():
        ba_node = client.get_node(node_id)
        ba_value = ba_node.get_value()
        ba_displayname = ba_node.get_display_name().to_string()

        opcua_data[ba_displayname] = ba_value

    return json.dumps(opcua_data)

# Zyklisch Daten abrufen und an IoT Hub senden
def send_cycle(opcua_client, iot_client):
    try:
        while True:
            opcua_value = opcua_get_value(opcua_client)
            print(opcua_value)
            message = Message(opcua_value)
            print("Sending message to IoT Hub: {}".format(message))
            iot_client.send_message(message)
            print("Message sent successfully")
            sleep(5)
    except KeyboardInterrupt:
        print("IoT Hub client sampling stopped")
        opcua_client.disconnect()
        iot_client.disconnect()

# Hauptfunktion
if __name__ == '__main__':
    opcua_client = opcua_init()
    iot_client = iot_hub_init()
    send_cycle(opcua_client, iot_client)

then get the message that the night message was sent: Sending message to IoT Hub: {"Auto": true} Message sent successfully

and to query I get: var Auto = deviceMessage["body"]["Auto"];

should i format the data differently before i send it? or should i query it differently? can i somehow see the jsondata? Thanks


Solution

  • I have changed this code line and now everything works fine.

    var cred = new DefaultAzureCredential(); var client = new DigitalTwinsClient(new Uri(adtServiceUrl), cred);