首页 > 解决方案 > Azure IoT 中心 - 如何在设备孪生中获取更新的所需属性和报告属性?

问题描述

我正在使用 .NET Core 3 从 Azure IoT 中心的设备孪生中读取数据。我想获取属性 X,并且该属性一如既往地存储在所需属性和报告属性中。我想买一个更新的。此信息写入元数据中。

我的问题是,这是否可以仅通过 IoT 中心查询语言实现,还是我必须从期望和报告中获取并自己检查?

标签: azureiotazure-iot-hub

解决方案


Azure IoT 中心查询语言仅支持 SQL 语句的子集,因此以下示例(device1和双属性color)显示了缺少 CASE 语句的解决方法:

  1. 查询字符串以获取所需的属性作为 lastUpdated:

    querystring = $"SELECT devices.properties.desired.color FROM devices WHERE deviceId = 'device1' and devices.properties.desired.$metadata.color.$lastUpdated > devices.properties.reported.$metadata.color.$lastUpdated";
    
  2. 如果返回值为空,我们必须进行第二次查询以获取报告的属性,例如:

     querystring = $"SELECT devices.properties.reported.color FROM devices WHERE deviceId = 'device1' and devices.properties.reported.$metadata.color.$lastUpdated > devices.properties.desired.$metadata.color.$lastUpdated";
    
  3. 如果返回值仍然为空,则设备孪生中缺少我们想要的和/或报告的属性,或者 deviceId 错误。

以下代码片段显示了上述用法的示例:

using Microsoft.Azure.Devices;
using System.Linq;
using System;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static string connectionString = "*****";

        static async Task Main(string[] args)
        {
            RegistryManager registryManager = RegistryManager.CreateFromConnectionString(connectionString);

            string deviceId = "device1";
            string propertyName = "color";
            string querystring = $"SELECT devices.properties.desired.{propertyName} FROM devices WHERE deviceId = '{deviceId}' and devices.properties.desired.$metadata.{propertyName}.$lastUpdated > devices.properties.reported.$metadata.{propertyName}.$lastUpdated";

            dynamic prop = null;
            for (int ii = 0; ii < 2; ii++)
            {
                var query = registryManager.CreateQuery(querystring);
                {
                    prop = (await query.GetNextAsJsonAsync())?.FirstOrDefault();
                    if (prop == null)
                        querystring = $"SELECT devices.properties.reported.{propertyName} FROM devices WHERE deviceId = '{deviceId}' and devices.properties.reported.$metadata.{propertyName}.$lastUpdated > devices.properties.desired.$metadata.{propertyName}.$lastUpdated";
                    else
                        break;
                }
            }
            Console.WriteLine(prop ?? $"Not found property '{propertyName}' or device '{deviceId}'");
        }
    }
}

更新:

在多个属性的情况下,我们必须通过获取的设备孪生实体中的代码单独检查每个属性。以下代码片段显示了此检查的示例:

// multiple properties
querystring = $"SELECT devices.properties FROM devices WHERE deviceId='{deviceId}'";
var query2 = registryManager.CreateQuery(querystring);
JObject prop2 = JObject.Parse((await query2.GetNextAsJsonAsync())?.FirstOrDefault());

JToken desired = prop2.SelectToken("properties.desired");
JToken reported = prop2.SelectToken("properties.reported");

string pathLastUpdated = $"$metadata.{propertyName}.$lastUpdated";          

var color = (DateTime)desired.SelectToken(pathLastUpdated) > (DateTime)reported.SelectToken(pathLastUpdated) ?
            (string)desired[propertyName] : (string)reported[propertyName];

// more properties

Console.WriteLine(color);

另外,您可以创建一个扩展类来简化代码,请参见以下示例:

public static class JObjectExtensions
{
    public static T GetLastUpdated<T>(this JObject properties, string propertyName)
    {
        JToken desired = properties.SelectToken("properties.desired");
        JToken reported = properties.SelectToken("properties.reported");
        string pathLastUpdated = $"$metadata.{propertyName}.$lastUpdated";

        return (DateTime)desired.SelectToken(pathLastUpdated) > (DateTime)reported.SelectToken(pathLastUpdated) ?
            desired.SelectToken(propertyName).ToObject<T>() : reported.SelectToken(propertyName).ToObject<T>();
    }

    public static string GetLastUpdated(this JObject properties, string propertyName)
    {
        return GetLastUpdated<string>(properties, propertyName);
    }
}

上述扩展的以下用法显示了如何根据 lastUpdated 时间戳获得任何所需的与报告的属性:

color = prop2.GetLastUpdated(propertyName);

string color2 = prop2.GetLastUpdated("test.color");

var test = prop2.GetLastUpdated<JObject>("test");

string jsontext = prop2.GetLastUpdated<JObject>("test").ToString(Formatting.None);

var test2 = prop2.GetLastUpdated<Test>("test");

int counter = prop2.GetLastUpdated<int>("counter");

请注意,在缺少属性的情况下会引发异常。


推荐阅读