我正在尝试向IoT中心查询所报告的属性和所需属性不同的设备。这样做的目的是在给定时间段内设备更新失败时能够通知用户。运行此查询
SELECT * FROM c WHERE properties.desired != properties.reported
生成大量误报,因为期望的和报告的都包含$ metadata属性,且时间戳始终不同。
为了清楚起见,我想列出所有“真实”值(不是元数据)与期望报告值不同的所有设备。
答案 0 :(得分:0)
避免“ $”属性用于在期望和报告的属性之间进行比较的简单解决方法是在期望和报告的属性内创建一个单独的复杂对象。这个复杂的对象将代表真实设备与阴影设备之间的状态。
示例:
"Config": {
"abc": 123,
"status": "inprocess",
"battery": {
"level": 90
}
}
在这种情况下,用于查询其 Config 与期望属性和报告属性不同的所有设备的查询字符串如下:
SELECT deviceId FROM devices WHERE is_defined(properties.desired.Config) and is_defined(properties.reported.Config) and properties.desired.Config != properties.reported.Config
更新:
另一个选项(解决方法)是使用Azure IoT中心事件触发设备孪生中的更改。这些通知更改可以路由到自定义端点,例如事件中心,由EventHubTrigger函数使用。路由查询:
is_object($body.properties.reported) OR is_object($body.properties.desired)
该功能可以轻松获得一对孪生设备,并比较其属性,例如所需的属性以及清除它们的元数据部分后的报告。
比较属性的结果可以存储在设备孪生标签中,例如:
"tags": {
"Watchdog": {
"timestamp": "2019-08-12T14:24:36.1805155Z",
"status": "inprocess"
}
}
请注意,标签属性对设备不可见。
一旦设备标签中具有看门狗状态,我们就可以查询设备的状态,例如:
"query": "SELECT deviceId FROM devices WHERE is_defined(devices.tags.Watchdog) and devices.tags.Watchdog.status='inprocess' "
以下代码片段显示了该函数的示例:
using Microsoft.Azure.Devices;
using Microsoft.Azure.EventHubs;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Text;
using System.Threading.Tasks;
namespace FunctionApp14
{
public static class Function2
{
static RegistryManager registryManager = RegistryManager.CreateFromConnectionString(Environment.GetEnvironmentVariable("AzureIoTHubShariedAccessPolicy"));
[FunctionName("Function2")]
public static async Task Run([EventHubTrigger("%myTwinChanges%", Connection = "myTwinChangesEventHubConnectionString", ConsumerGroup = "local")]EventData message, ILogger log)
{
var msg = Encoding.UTF8.GetString(message.Body.Array);
log.LogInformation($"C# IoT Hub trigger function processed a message: {msg}");
if (message.SystemProperties["iothub-message-source"]?.ToString() == "twinChangeEvents")
{
var twinChnages = JsonConvert.DeserializeAnonymousType(msg, new { properties = new JObject() });
if (twinChnages?.properties != null)
{
// deviceId
var connectionDeviceId = message.SystemProperties["iothub-connection-device-id"].ToString();
// device twin
var twin = await registryManager.GetTwinAsync(connectionDeviceId);
// cleanup and compare the twin properties
twin.Properties.Desired.ClearMetadata();
twin.Properties.Reported.ClearMetadata();
var desired = JObject.Parse(twin.Properties.Desired.ToJson());
var reported = JObject.Parse(twin.Properties.Reported.ToJson());
var status = JToken.DeepEquals(desired, reported) ? "ok" : "inprocess";
log.LogWarning($"desired-reported status = {status}");
// put the state on the tags
var twinPatch = JsonConvert.SerializeObject(new { tags = new { Watchdog = new { timestamp = DateTime.UtcNow, status = status } } });
await registryManager.UpdateTwinAsync(connectionDeviceId, twinPatch, twin.ETag);
}
}
await Task.CompletedTask;
}
}
}
答案 1 :(得分:0)
您可能需要在代码中执行此操作。我有一段类似的代码,放在GitHub repo for this question中。
该代码非常幼稚,它比较属性的字符串值(不包括元数据)。如果需要的话,更改它来检查属性键/值应该很容易。