首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用HTTP请求向Azure IoT中心设备发送遥测消息

使用HTTP请求向Azure IoT中心设备发送遥测消息
EN

Stack Overflow用户
提问于 2022-03-16 10:20:35
回答 2查看 797关注 0票数 0

我试图用HTTP请求将遥测发送到Azure IoT Central中的一个设备。

类似的Rest也适用于Azure IoT集线器- https://learn.microsoft.com/en-us/rest/api/iothub/device/send-device-event

我能够使用这个网站- IoT - https://dpsgen.z8.web.core.windows.net/提取Azure IoT Central后面的https://dpsgen.z8.web.core.windows.net/集线器资源URL。

它获取从Azure IoT Central获得的范围Id、设备Id和设备主键。它为您提供IoT集线器连接字符串,

HostName=iotc-<<unique-iot-hub-id>>.azure-devices.net;DeviceId=<<device-id>>;SharedAccessKey=<<device-primary-key>>

使用上面的IoT集线器主机名,我尝试了IoT集线器发送设备事件Rest .它由于一个未经授权的错误而失败。

我正在使用Azure IoT中心应用程序中从下面的路径生成的SAS令牌

Azure IoT中央->权限-> API令牌->“Administrator”角色

任何帮助都是有用的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-03-18 12:39:56

看看我的answer,其中详细描述了如何生成一个连接信息,用于使用REST请求将遥测数据发送到Azure IoT中央应用程序。

下面是一个更新的azure函数,用于生成所请求的设备连接信息:

代码语言:javascript
复制
#r "Newtonsoft.Json"

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;


public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    int retryCounter = 10;
    int pollingTimeInSeconds = 3;

    string deviceId = req.Query["deviceid"];
    string mid = req.Query["modelid"];
               
    log.LogInformation($"DeviceId = {deviceId}, ModelId = {mid}");

    if (!Regex.IsMatch(deviceId, @"^[a-z0-9\-]+$"))
        throw new Exception($"Invalid format: DeviceID must be alphanumeric, lowercase, and may contain hyphens");

    string iotcScopeId = System.Environment.GetEnvironmentVariable("AzureIoTC_scopeId");      
    string iotcSasToken = System.Environment.GetEnvironmentVariable("AzureIoTC_sasToken");    
            
    if(string.IsNullOrEmpty(iotcScopeId) || string.IsNullOrEmpty(iotcSasToken))
        throw new ArgumentNullException($"Missing the scopeId and/or sasToken of the IoT Central App");

    string deviceKey = SharedAccessSignatureBuilder.ComputeSignature(iotcSasToken, deviceId);
 
    string address = $"https://global.azure-devices-provisioning.net/{iotcScopeId}/registrations/{deviceId}/register?api-version=2021-06-01";
    string sas = SharedAccessSignatureBuilder.GetSASToken($"{iotcScopeId}/registrations/{deviceId}", deviceKey, "registration");
 
    log.LogInformation($"sas_token: {sas}");

    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("Authorization", sas);
        client.DefaultRequestHeaders.Add("accept", "application/json");
        string jsontext = string.IsNullOrEmpty(mid) ? null : $"{{ \"modelId\": \"{mid}\" }}";
        var response = await client.PutAsync(address, new StringContent(JsonConvert.SerializeObject(new { registrationId = deviceId, payload = jsontext }), Encoding.UTF8, "application/json"));

        var atype = new { errorCode = "", message = "", operationId = "", status = "", registrationState = new JObject() };
        do
        {
            dynamic operationStatus = JsonConvert.DeserializeAnonymousType(await response.Content.ReadAsStringAsync(), atype);
            if (!string.IsNullOrEmpty(operationStatus.errorCode))
            {
                throw new Exception($"{operationStatus.errorCode} - {operationStatus.message}");
            }
            response.EnsureSuccessStatusCode();
            if (operationStatus.status == "assigning")
            {
                Task.Delay(TimeSpan.FromSeconds(pollingTimeInSeconds)).Wait();
                address = $"https://global.azure-devices-provisioning.net/{iotcScopeId}/registrations/{deviceId}/operations/{operationStatus.operationId}?api-version=2021-06-01";
                response = await client.GetAsync(address);
            }
            else if (operationStatus.status == "assigned")
            {
                log.LogInformation($"{JsonConvert.SerializeObject(operationStatus, Formatting.Indented)}");
                string assignedHub = operationStatus.registrationState.assignedHub;
                string cstr = $"HostName={assignedHub};DeviceId={operationStatus.registrationState.deviceId};SharedAccessKey={deviceKey}"; // + (string.IsNullOrEmpty(mid) ? "" : $";modelId={mid.Replace(";","#")}"); 
                string requestUrl = $"https://{assignedHub}/devices/{operationStatus.registrationState.deviceId}/messages/events?api-version=2021-04-12";
                string deviceSasToken = SharedAccessSignatureBuilder.GetSASToken($"{assignedHub}/{operationStatus.registrationState.deviceId}", deviceKey);

                log.LogInformation($"IoTC DeviceConnectionString:\n\t{cstr}");
                return new OkObjectResult(JObject.FromObject(new { iotHub = assignedHub, iotFireUrl = requestUrl, deviceSasToken = deviceSasToken, deviceConnectionString = cstr }));
            }
            else
            {
                throw new Exception($"{operationStatus.registrationState.status}: {operationStatus.registrationState.errorCode} - {operationStatus.registrationState.errorMessage}");
            }
        } while (--retryCounter > 0);

        throw new Exception("Registration device status retry timeout exprired, try again.");
    } 
}

public sealed class SharedAccessSignatureBuilder
{
    public static string GetHostNameNamespaceFromConnectionString(string connectionString)
    {
        return GetPartsFromConnectionString(connectionString)["HostName"].Split('.').FirstOrDefault();
    }
    public static string GetSASTokenFromConnectionString(string connectionString, uint hours = 24)
    {
        var parts = GetPartsFromConnectionString(connectionString);
        if (parts.ContainsKey("HostName") && parts.ContainsKey("SharedAccessKey"))
            return GetSASToken(parts["HostName"], parts["SharedAccessKey"], parts.Keys.Contains("SharedAccessKeyName") ? parts["SharedAccessKeyName"] : null, hours);
        else
            return string.Empty;
    }
    public static string GetSASToken(string resourceUri, string key, string keyName = null, uint hours = 24)
    {
        try
        {
            var expiry = GetExpiry(hours);
            string stringToSign = System.Web.HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
            var signature = SharedAccessSignatureBuilder.ComputeSignature(key, stringToSign);
            var sasToken = keyName == null ?
                String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry) :
                String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
            return sasToken;
        }
        catch
        {
            return string.Empty;
        }
    }

    #region Helpers
    public static string ComputeSignature(string key, string stringToSign)
    {
        using (HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key)))
        {
            return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
        }
    }

    public static Dictionary<string, string> GetPartsFromConnectionString(string connectionString)
    {
        return connectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { '=' }, 2)).ToDictionary(x => x[0].Trim(), x => x[1].Trim(), StringComparer.OrdinalIgnoreCase);
    }

    // default expiring = 24 hours
    private static string GetExpiry(uint hours = 24)
    {
        TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
        return Convert.ToString((ulong)sinceEpoch.TotalSeconds + 3600 * hours);
    }

    public static DateTime GetDateTimeUtcFromExpiry(ulong expiry)
    {
        return (new DateTime(1970, 1, 1)).AddSeconds(expiry);
    }
    public static bool IsValidExpiry(ulong expiry, ulong toleranceInSeconds = 0)
    {
        return GetDateTimeUtcFromExpiry(expiry) - TimeSpan.FromSeconds(toleranceInSeconds) > DateTime.UtcNow;
    }

    public static string CreateSHA256Key(string secret)
    {
        using (var provider = new SHA256CryptoServiceProvider())
        {
            byte[] keyArray = provider.ComputeHash(UTF8Encoding.UTF8.GetBytes(secret));
            provider.Clear();
            return Convert.ToBase64String(keyArray);
        }
    }

    public static string CreateRNGKey(int keySize = 32)
    {
        byte[] keyArray = new byte[keySize];
        using (var provider = new RNGCryptoServiceProvider())
        {
            provider.GetNonZeroBytes(keyArray);
        }
        return Convert.ToBase64String(keyArray);
    }
    #endregion
}
票数 0
EN

Stack Overflow用户

发布于 2022-03-17 01:28:12

IoT中心API令牌用于管理应用程序功能,设备不能使用该令牌。选择IoT Central中的设备并单击顶部的"Connect“菜单,使用该设备显示的主键。

另外,尽管为设备提供了https支持,但由于其轮询性质,它并不适合IoT,并且不支持设备双期望或报告的属性。https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-d2c-guidance

IoT Central提供内置的高可用性,底层IoTHub名称可以更改,因此不建议手动获取IoTHub名称。始终调用DPS检索IoTHub名称,第一次和定期或错误条件。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71495317

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档