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
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
I have changed this code line and now everything works fine.
var cred = new DefaultAzureCredential(); var client = new DigitalTwinsClient(new Uri(adtServiceUrl), cred);