azure - 订阅 Azure IoT 中心设备事件

标签 azure azure-iot-hub azure-eventhub

我想从 Azure IoT 中心读取“Microsoft.Devices.DeviceConnected”事件 ( https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-event-grid#event-types )。我发现的唯一示例涉及 Azure 事件网格,但我宁愿使用 IoT 中心的内部端点(事件中心)。这可能吗? 当我使用 EventProcessorHost 接口(interface)订阅内部事件中心时,我收到的只是 D2C 用户遥测消息。

最佳答案

就像 @PeterBons 所说,Azure IoT 中心不支持此功能,但可以使用 Azure Function 在 Azure IoT 中心之外完成。以下屏幕片段显示了此集成,其中 EventGrid 事件被推送到 IoT 中心流:

enter image description here

如您所见,上面的 EventGridTrigger 函数是 Azure 事件网格和 Azure IoT 中心之间的集成器。该集成商有责任使用事件网格事件,映射到 D2C 消息并将其作为具有 Https 协议(protocol)的虚拟 IoT 设备(后端设备)发送到 Azure IoT 中心。

更新:

以下代码片段是 Azure Function - 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
}

关于azure - 订阅 Azure IoT 中心设备事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53467014/

相关文章:

azure - 使用 Salesforce 中的 Azure SSO 详细信息对 Azure REST API 请求进行身份验证

免费套餐中的 Azure 应用服务状态为 : QuotaExceeded

azure - 如何实现从Azure Event Hub的高速处理接收?

azure - 通过 URL 将 IoT 消息发送到 Azure 事件中心

azure - 为什么 Azure 事件中心 EventData 的 PartitionKey 字段为空?

Azure 日志查询显示空值

azure - 使用 Azure DevOps CI/CD 管道自动部署 ADF 管道

Azure 配置服务示例不适用于节点

c# - 在一个 C# Azure 函数 session 中处理来自 IoT 中心的多条消息

azure - IoT Central 到 Blob 存储数据加密遥测数据主体