azure - 订阅 Azure IoT 中心设备事件
问题描述
我想从 Azure IoT 中心阅读“Microsoft.Devices.DeviceConnected”事件( https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-event-grid#event-types ) . 我发现的唯一示例涉及 Azure 事件网格,但我更愿意使用 IoT 中心的内部端点(事件中心)。这甚至可能吗?当我使用EventProcessorHost接口订阅内部事件中心时,我得到的只是 D2C 用户遥测消息。
解决方案
就像@PeterBons 所说,Azure IoT Hub 不支持此功能,但是可以使用 Azure Function 在 Azure IoT Hub 之外完成。以下屏幕片段显示了此集成,其中 EventGrid 事件被推送到 IoT 中心流:
如您所见,上面的EventGridTrigger函数是Azure Event Grid 和 Azure IoT Hub 之间的集成器。此集成器负责使用事件网格事件,映射到 D2C 消息并将其作为具有 Https 协议的虚拟 IoT 设备(后端设备)发送到 Azure IoT 中心。
更新:
以下代码片段是 Azure 函数 - 集成到 Azure IoT 中心的示例:
#r "Microsoft.Azure.EventGrid"
#r "Newtonsoft.Json"
using System.Configuration;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Web;
using System.Net.Http;
using System.Text;
using System.Globalization;
using Newtonsoft.Json;
using Microsoft.Azure.EventGrid.Models;
// reusable client proxy
static HttpClientHelper iothub = new HttpClientHelper(Environment.GetEnvironmentVariable("AzureIoTHubShariedAccessPolicy"));
public static async Task Run(EventGridEvent eventGridEvent, ILogger log)
{
log.LogInformation(eventGridEvent.Data.ToString());
// my virtual backend iot device
string deviceId = "Device13";
var content = new StringContent(JsonConvert.SerializeObject(eventGridEvent), Encoding.UTF8, "application/json");
await iothub.Client.PostAsync($"/devices/{deviceId}/messages/events?api-version=2018-06-30", content);
}
// helpers
class HttpClientHelper
{
HttpClient client;
DateTime expiringSaS;
(string hostname, string keyname, string key) config;
public HttpClientHelper(string connectionString)
{
config = GetPartsFromConnectionString(connectionString);
client = new HttpClient() { BaseAddress = new Uri($"https://{config.hostname}")};
SetAuthorizationHeader();
}
public HttpClient Client
{
get
{
if (expiringSaS < DateTime.UtcNow.AddMinutes(-1))
{
SetAuthorizationHeader();
}
return client;
}
}
internal void SetAuthorizationHeader()
{
lock (client)
{
if (expiringSaS < DateTime.UtcNow.AddMinutes(-1))
{
string sasToken = GetSASToken(config.hostname, config.key, config.keyname, 1);
if (client.DefaultRequestHeaders.Contains("Authorization"))
client.DefaultRequestHeaders.Remove("Authorization");
client.DefaultRequestHeaders.Add("Authorization", sasToken);
expiringSaS = DateTime.UtcNow.AddHours(1);
}
}
}
internal (string hostname, string keyname, string key) GetPartsFromConnectionString(string connectionString)
{
var parts = connectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { '=' }, 2)).ToDictionary(x => x[0].Trim(), x => x[1].Trim());
return (parts["HostName"] ?? "", parts["SharedAccessKeyName"] ?? "", parts["SharedAccessKey"] ?? "");
}
internal string GetSASToken(string resourceUri, string key, string keyName = null, uint hours = 24)
{
var expiry = GetExpiry(hours);
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture, $"SharedAccessSignature sr={HttpUtility.UrlEncode(resourceUri)}&sig={HttpUtility.UrlEncode(signature)}&se={expiry}");
if (!string.IsNullOrEmpty(keyName))
sasToken += $"&skn={keyName}";
return sasToken;
}
internal string GetExpiry(uint hours = 24)
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
return Convert.ToString((int)sinceEpoch.TotalSeconds + 3600 * hours);
}
}
和function.json:
{
"bindings": [
{
"type": "eventGridTrigger",
"name": "eventGridEvent",
"direction": "in"
}
],
"disabled": false
}
推荐阅读
- javascript - 如何转发 ref 函数声明而不是箭头函数?
- amazon-web-services - Route53 和 ElasticBeanstalk,如何使 DNS 记录对应用程序更新具有持久性?
- c - lang-c 使用嵌套的for循环和函数打印两个中间有空格的金字塔?
- python - Python 在 C++ 中崛起 ** 运算符
- java - 为什么我的android应用程序循环时不会增加时间?
- c++ - 令人沮丧的数学问题,结果不如预期(EDQ)
- tomcat - 使用 Pentaho 用户控制台 9.0 生成 PDF 报告
- python - 使用上下文管理器重构 if-else 块 python?
- python - seaborn点图可视化
- python - 如何运行模型而无需再次运行训练数据