为通过IoT中心认证的设备发送Cloud-to-Device消息 [英] Sending Cloud-To-Device message for devices provisoned through IoT-central

查看:85
本文介绍了为通过IoT中心认证的设备发送Cloud-to-Device消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读有关此新SaaS产品的文档,但是我没有看到有关能够向设备发送消息的任何提及,例如:打开/关闭设备.

I have been reading the documentation of this new SaaS offering, but I do not see any mention about being able to send a message to the device, eg: to switch ON/OFF an equipment.

https://docs.microsoft.com/en-us/azure/iot-central/tutorial-add-device

我确实看到可以通过更改设备双胞胎来更改设备的设置.

I do see there is a provision to change the settings of the device, by being able to alter device-twin.

此外,我读到有一种方法可以向设备发送回声".但是,这些都不符合我的确切目的.

Also, I read there is a way to send an "echo" to the device. But, these don't serve my exact purpose.

那么,有没有一种方法可以使用连接字符串发送C2D消息,该字符串可以使用例程构建? https://docs.microsoft.com/zh-CN/azure/iot-central/tutorial-add-device#prepare-the-client-code

So, is there a way I can send a C2D message, using the connection-string, which can be built using the routine-? https://docs.microsoft.com/en-us/azure/iot-central/tutorial-add-device#prepare-the-client-code

我想通过AzureFunction发送此C2D,但最好知道是否可以以某种方式将其集成到IoT-Central UI中.

I would like to send this C2D through an AzureFunction, but it would be good to know if this can be somehow integrated into the IoT-Central UI.

任何其他符合我要求的输入(打开/关闭设备)也将有很大帮助!

Any other inputs to achieve my requirement (switch ON/OFF an equipment) would be a great help too!

推荐答案

正如我在评论中提到的那样,Azure IoT Central对内部IoT Hub面向服务的终结点具有完全控制权.但是,有一种方法,Azure IoT Central允许对此面向服务的终结点进行有限访问,并使用REST API处理设备孪生并在设备上调用直接方法.

As I mentioned in my comment, the Azure IoT Central has a full control over the internal IoT Hub service-facing endpoint. However, there is a way, where the Azure IoT Central allows a limited access to this service-facing endpoint and using a REST API to handle a device twin and invoking a Direct Method on the device.

以下是如何获取REST Api调用所需的授权标头的sas令牌的步骤:

The following are steps how to obtain a sas token for authorization header needed for REST Api calls:

  1. 从您的Azure IoT中心应用程序获取访问令牌.

  1. Get the Access Token from your Azure IoT Central application.

格式为:

SharedAccessSignature sr=appId&sig=xxxxx&skn=myTokenName&se=1577730019340

请注意, appId 显示的是您的Azure IoT中心应用程序的应用程序ID

Note, that the appId is showing an application id of your Azure IoT Central application

调用REST POST请求以获得 iothubTenantSasToken.sasToken

Call the REST POST request to obtain an iothubTenantSasToken.sasToken

POST https://api.azureiotcentral.com/v1-beta/applications/{appId}/diagnostics/sasTokens  
Authorization:SharedAccessSignature sr=appId&sig=xxxxx&skn=myTokenName&se=1577730019340

响应具有以下格式:

{
  "iothubTenantSasToken": {
    "sasToken": "SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service"
    },
  "eventhubSasToken": {
    "sasToken": "SharedAccessSignature sr=sb%3A%2F%2Fep-ns-saas-ep-15-262-xxxxxxxxxx.servicebus.windows.net%2Fep-ehub-saas-iothu-1044564-xxxxxxxxxx&sig=xxxxxx&se=1546197703&skn=service",
    "entityPath": "ep-ehub-saas-iothu-1044564-xxxxxxxxxx",
    "hostname": "sb://ep-ns-saas-ep-15-262-xxxxxxxxxx.servicebus.windows.net/"
    },
  "expiry": 1546197703
}

  • 面向服务的端点调用的sasToken为:

  • The sasToken for our service-facing endpoint calls is:

    SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service
    

  • 现在,我们可以使用一些Azure IoT中心REST API,基本上是在uri路径中使用 twins 进行的调用,例如:

    Now, we can use some Azure IoT Hub REST APIs, basically the calls with the twins in the uri path, such as:

    https://docs.microsoft.com/en -us/rest/api/iothub/service/gettwin

    https://docs.microsoft.com/en -us/rest/api/iothub/service/updatetwin

    https://docs.microsoft.com/en -us/rest/api/iothub/service/replacetwin

    https://docs.microsoft.com/en -us/rest/api/iothub/service/invokedevicemethod

    在设备1上调用直接方法的示例:

    Example for invoking a Direct Method on the device1:

    POST https://saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net/twins/device1/methods?api-version=2018-06-30
    Authorization:SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service
    
    body:
        {
          "methodName": "writeLine",
          "timeoutInSeconds": 20,
          "payload": {
             "input1": 12345,
             "input2": "HelloDevice"
             }
        }
    

    更新设备孪生标签属性的示例:

    Example of updating a device twin tags property:

    PATCH https://saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net/twins/device1?api-version=2018-06-30
    Authorization:SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service
    
    body:
        {
          "tags": {
            "test":12345
            }
        }
    

    请注意,sasToken 到期时间为60分钟.我确实建议缓存第2步中的响应对象,并根据到期时间进行刷新.

    Note, that the sasToken expiry time is 60 minutes. I do recommend to cache the response object from the step 2. and refreshing based on the expiry time.

    更新:

    以下是使用IoT Central访问令牌在azure函数中处理设备孪生和设备直接方法的步骤.

    The following are steps for using an IoT Central access token for handling a device twins and device direct method within the azure function.

    1. 在IoT Central应用程序中生成访问令牌,请参见以下屏幕片段:

    1. 将此访问令牌添加到功能应用程序设置中.在此示例中,使用 App设置名称 AzureIoTCAccessToken .请注意,此访问令牌可以存储在Azure密钥保管库中,请参阅更多详细信息

    1. Add this access token to your function application settings. In this example, the App Setting Name is used AzureIoTCAccessToken. Note, that this access token can be stored in the Azure Key Vault, see more details here.

    在您的Function App中创建HttpTrigger函数.

    Create HttpTrigger function in your Function App.

    用以下代码替换run.csx:

    Replace run.csx with the following code:

    #r "Newtonsoft.Json"
    #r "Microsoft.Azure.WebJobs.Extensions.Http"
    
    using System.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System.Linq;
    using System.Text;
    
    // reusable client proxy
    static HttpClientHelper iothub = new HttpClientHelper(Environment.GetEnvironmentVariable("AzureIoTCAccessToken"));
    
    public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");
    
        var atype = new { device = new { deviceId = "", properties = new JObject(), measurements = new JObject() } };
        var iotcobj = JsonConvert.DeserializeAnonymousType(await req.ReadAsStringAsync(), atype);
    
        // get deviceId, for test puspose use the device1
        string deviceId = iotcobj?.device?.deviceId ?? "device1";
    
        // get a device twins
        var response = await iothub.Client.GetAsync($"/twins/{deviceId}?api-version=2018-06-30");
        string jsontext = await response.Content.ReadAsStringAsync();
        log.LogInformation($"DeviceTwin: {JsonConvert.DeserializeObject(jsontext)}");
    
       // patch on desired property
       var patch = JsonConvert.SerializeObject(new { properties = new { desired = new { ping = DateTime.UtcNow } } });
       response = await iothub.Client.PatchAsync($"/twins/{deviceId}?api-version=2018-06-30", new StringContent(patch, Encoding.UTF8, "application/json"));
       jsontext = await response.Content.ReadAsStringAsync();
       log.LogInformation($"Patch: {JsonConvert.DeserializeObject(jsontext)}");
    
       // invoke a device method
       var method = new { methodName = "writeLine", timeoutInSeconds = 30, payload = new {input1 = 12345, input2 = "HelloDevice" } };
       response = await iothub.Client.PostAsJsonAsync($"/twins/{deviceId}/methods?api-version=2018-06-30", method );
       jsontext = await response.Content.ReadAsStringAsync();
       log.LogInformation($"DirectMethod: {JsonConvert.DeserializeObject(jsontext)}");
    
       return new OkObjectResult(jsontext);      
    }
    
    class HttpClientHelper
    {
        HttpClient client;
        string accessToken;
        dynamic iothub;
        long toleranceInSeconds = 60;
    
        public HttpClientHelper(string accessToken)
        {
            this.accessToken = accessToken;
            this.iothub = GetIoTHubTenant(accessToken);
            string hostname = GetHostNameFromSaSToken(this.iothub.iothubTenantSasToken.sasToken);
            client = new HttpClient() { BaseAddress = new Uri($"https://{hostname}") };
            client.DefaultRequestHeaders.Add("Authorization", iothub.iothubTenantSasToken.sasToken);
        }
        public HttpClient Client
        {
            get
            {
                if((new DateTime(1970, 1, 1)).AddSeconds(this.iothub.expiry - toleranceInSeconds) < DateTime.UtcNow)
                    SetAuthorizationHeader();
                return client;
            }
        }
        private void SetAuthorizationHeader()
        {
            lock (client)
            {
                if ((new DateTime(1970, 1, 1)).AddSeconds(this.iothub.expiry - toleranceInSeconds) < DateTime.UtcNow)
                {
                    if (client.DefaultRequestHeaders.Contains("Authorization"))
                        client.DefaultRequestHeaders.Remove("Authorization");
                    this.iothub = GetIoTHubTenant(this.accessToken);
                    client.DefaultRequestHeaders.Add("Authorization", this.iothub.iothubTenantSasToken.sasToken);
                }
            }
        }
        private string GetHostNameFromSaSToken(string sastoken)
        {
            var parts = sastoken.Replace("SharedAccessSignature", "").Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { '=' }, 2)).ToDictionary(x => x[0].Trim(), x => x[1].Trim());
            return parts["sr"] ?? "";
        }
    
        private dynamic GetIoTHubTenant(string iotcAccessToken)
        {
            string appId = GetHostNameFromSaSToken(iotcAccessToken);
            using (var hc = new HttpClient())
            {
                hc.DefaultRequestHeaders.Add("Authorization", accessToken);
                string address = $"https://api.azureiotcentral.com/v1-beta/applications/{appId}/diagnostics/sasTokens";
                var response = hc.PostAsync(address, new StringContent("{}", Encoding.UTF8, "application/json")).Result;
                return JsonConvert.DeserializeAnonymousType(response.Content.ReadAsStringAsync().Result, new { iothubTenantSasToken = new { sasToken = "" }, expiry = 0L });
            }
        }
    }
    

    注意:,以上实现基于您的IoT Central应用程序生成的访问令牌,就像它最近已发布以提供一般可用性一样,请参阅

    Note:, The above implementation is based on the generated access token by your IoT Central application like it has been recently released for general availability, see here. In the case of the changing a format, etc. all clients, testers, etc. included the above solution will be impacted.

    这篇关于为通过IoT中心认证的设备发送Cloud-to-Device消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆