英文:
how to get telemetry data from iothub to Azure Digital Twins
问题
要将遥测数据从IOT中心发送到Azure数字孪生,但我无法成功。我已经尝试了Microsoft的完整示例(https://learn.microsoft.com/en-us/azure/digital-twins/how-to-ingest-iot-hub-data)。我应该添加其他内容吗?或者我可以更改什么?
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
{
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)
{
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}");
}
}
}
我收到以下错误消息:
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":"{"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":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.
谢谢反馈,迄今为止我已经更改了一切,但是收到不同的错误消息:
2023-05-18T22:21:00Z [Error] Error in ingest function: Value cannot be null. (Parameter 'source')
要发送消息,请使用以下Python代码:
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初始化
def opcua_init():
opcua_client = Client("x") # 插入OPC UA地址
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客户端初始化
def iot_hub_init():
while True:
try:
iot_client = IoTHubDeviceClient.create_from_connection_string("x", websockets=True) # 插入IoT连接字符串
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)
# 获取OPC UA服务器的数据并返回为JSON字符串
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)
# 周期性获取数据并发送到IoT Hub
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()
# 主函数
if __name__ == '__main__':
opcua_client = opcua_init()
iot_client = iot_hub_init()
send_cycle(opcua_client, iot_client)
然后得到夜间消息已发送的消息:
Sending message to IoT Hub: {"Auto": true}
Message sent successfully
并且在查询时获得:
var Auto = deviceMessage["body"]["Auto"];
我应该在发送之前以不同的方式格式化数据吗?还是应该以不同的方式查询?我是否可以在发送之前以某种方式查看JSON数据?谢谢
英文:
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
答案1
得分: 1
以下是要翻译的内容:
"the code sample provided in the [Tutorial] works as expected in pushing the data from IoT Hub to Azure Digital Twin. Looks like you are trying to retrieve a property from the Telemetry data which does not exist. That is likely the cause of the error you are facing.
To get a better understanding of the issue, inspect the following elements-
-
The section Test with simulated IoT data uses Device Simulator project. Open
AzureIoTHub.cs
file under the project and inspect the line 54 of the sample where the telemetry data being simulated is set. -
The above highlighted property is the telemetry being transmitted by IoT Hub and it should match with the field we are trying to retrieve from
IOTHubtoADTwins
function through the line of codevar Auto = deviceMessage["body"]["Auto"];
. Looks like you are trying to fetch a property called "Auto" from the message. Make sure that it being sent by the device simulator code. -
The following line of code
updateTwinData.AppendReplace("/Auto", Auto.Value<bool>());
is used to set the property value of the Azure Digital Twin. Inspecting the model you have provided in the comments, there is no Property on your Azure Digital Twin with a nameAuto
. Fix it to make sure the data can be transferred. -
The following line of code
await client.UpdateDigitalTwinAsync(deviceId, updateTwinData);
is used to update the corresponding digital Twin that matches the digital twin with the deviceId. Note that the deviceId can be different from your Azure IoTHub device ID. Make sure you set the same device ID in your code to the value which you have used for--twin-id
property while creation using a similar statement like thisaz dt twin create --dt-name <instance-hostname-or-name> --dtmi "dtmi:contosocom:DigitalTwins:Thermostat;1" --twin-id thermostat67 --properties '{"Temperature": 0.0}'
If you are using a Python SDK, you can formulate the message structure as follows to make sure the telemetry data sent is in JSON format.
MSG_TXT = '{{"temperature": {temperature},"humidity": {humidity}, "timesent": {timesent}}}'
temperature = TEMPERATURE + (random.random() * 15)
humidity = HUMIDITY + (random.random() * 20)
x = datetime.now().isoformat()
timesent = dumps(datetime now(), default=json_serial)
msg_txt_formatted = MSG_TXT.format(
temperature=temperature, humidity=humidity, timesent=timesent)
message = Message(msg_txt_formatted, content_encoding="utf-8", content_type="application/json")
client.send_message(message)
Once you have addressed all there parameters, you should push the data to Azure Digital Twin without any issues. Please refer the below image showing the data received on Azure Digital Twin using the same piece of code.
Please also refer to the thread Telemetry Data from IOT hub not pushing to azure function and not reflecting to Digital Twin? where a similar issue has been discussed.
英文:
the code sample provided in the [Tutorial] works as expected in pushing the data from IoT Hub to Azure Digital Twin. Looks like you are trying to retrieve a property from the Telemetry data which does not exist. That is likely the cause of the error you are facing.
To get a better understanding of the issue, inspect the following elements-
- The section Test with simulated IoT data uses Device Simulator project. Open
AzureIoTHub.cs
file under the project and inspect the line 54 of the sample where the telemetry data being simulated is set.
- The above highlighted property is the telemetry being transmitted by IoT Hub and it should match with the field we are trying to retrieve from
IOTHubtoADTwins
function through the line of codevar Auto = deviceMessage["body"]["Auto"];
. Looks like you are trying to fetch a property called "Auto" from the message. Make sure that it being sent by the device simulator code. - The following line of code
updateTwinData.AppendReplace("/Auto", Auto.Value<bool>());
is used to set the property value of the Azure Digital Twin. Inspecting the model you have provided in the comments, there is no Property on your Azure Digital Twin with a nameAuto
. Fix it to make sure the data can be transferred. - The following line of code
await client.UpdateDigitalTwinAsync(deviceId, updateTwinData);
is used to update the corresponding digital Twin that matches the digital twin with the deviceId. Note that the deviceId can be different from your Azure IoTHub device ID. Make sure you set the same device ID in your code to the value which you have used for--twin-id
property while creation using a similar statement like thisaz dt twin create --dt-name <instance-hostname-or-name> --dtmi "dtmi:contosocom:DigitalTwins:Thermostat;1" --twin-id thermostat67 --properties '{"Temperature": 0.0}'
If you are using a Python SDK, you can formulate the message structure as follows to make sure the telemetry data sent is in JSON format.
MSG_TXT = '{{"temperature": {temperature},"humidity": {humidity}, "timesent": {timesent}}}'
temperature = TEMPERATURE + (random.random() * 15)
humidity = HUMIDITY + (random.random() * 20)
x = datetime.now().isoformat()
timesent = dumps(datetime.now(), default=json_serial)
msg_txt_formatted = MSG_TXT.format(
temperature=temperature, humidity=humidity, timesent=timesent)
message = Message(msg_txt_formatted, content_encoding="utf-8", content_type="application/json")
client.send_message(message)
Once you have addressed all there parameters, you should push the data to Azure Digital Twin without any issues. Please refer the below image showing the data received on Azure Digital Twin using the same piece of code.
Please also refer to the thread Telemetry Data from IOT hub not pushing to azure function and not reflecting to Digital Twin? where a similar issue has been discussed.
答案2
得分: 0
我已更改此代码行,现在一切正常。
var cred = new DefaultAzureCredential();
var client = new DigitalTwinsClient(new Uri(adtServiceUrl), cred);
英文:
I have changed this code line and now everything works fine.
var cred = new DefaultAzureCredential();
var client = new DigitalTwinsClient(new Uri(adtServiceUrl), cred);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论