设备配置自定义分配-在Azure功能中设置初始Device Twin

时间:2019-04-26 16:50:27

标签: azure-functions azure-iot-hub

自定义分配支持设置初始设备对以及IoT中心。孪生设备未设置。

我已在Azure中配置设备供应服务以使用自定义Azure功能。在Azure功能中,通过自定义API,我们运行逻辑以确定设备的最佳IoT中心位置。除了分配IoT Hub之外,该代码还提供了初始设备孪生数据,但它不起作用。

我正在跟踪此博客中描述的代码示例: https://sandervandevelde.wordpress.com/2018/12/29/custom-iot-hub-assignment-in-device-provisioning-service/

我已经研究了几个相关的自定义分配问题,但没有发现有人使用如上所述的自定义azure函数方法。

这是上面博客文章中的相关代码的片段。

var response = new Response(savefileresponse.AssignedHub);
//loading an instance of the initiTwin didn't work, try typing device twin values in manually
//response.initialTwin = savefileresponse.initialTwin;
response.initialTwin.properties.desired = new JObject();
response.initialTwin.properties.desired.PropOne = "2345";
response.initialTwin.properties.desired.PropTwo = "6789";

下面是来自Blog文章的类定义。请注意将动态类型用于所需的属性。有人可以确认这是对DPS的正确消息响应类型吗?

public class AssignDeviceResponse
{
    public AssignDeviceResponse()
    {
        this.initialTwin = new ResponseTwin();
    }

    public ProvisioningRegistrationStatusType Status { get; set; }
    public string DeviceId { get; set; }
    public string AssignedHub { get; set; }
    public ResponseTwin initialTwin { get; set; }
}

#endregion

#region Microsoft DPS response contracts
public class Response
{
    public Response(string hostName)
    {
        iotHubHostName = hostName;
        initialTwin = new ResponseTwin();
    }

    public string iotHubHostName { get; set; }
    public ResponseTwin initialTwin { get; set; }
}

public class ResponseTwin
{
    public ResponseTwin()
    {
        properties = new ResponseProperties();
    }

    public dynamic tags { get; set; }
    public ResponseProperties properties { get; set; } // contains desired properties
}

public class ResponseProperties
{
    public dynamic desired { get; set; }
}
#endregion

设置后,IoT中心值将正确返回到设备。然后,我进入了Azure门户IoT Hub,并展示了设备的双重价值。我添加的所有自定义属性均未显示。下面的孪生兄弟显然是IoT中心的默认设置,因为它也不符合DPS服务中的孪生兄弟。

{
"deviceId": "cde5d316-9c01-3961-b850-8f5c17cea937",
"etag": "AAAAAAAAAAE=",
"deviceEtag": "NzA1OTc5MzE1",
"status": "enabled",
"statusUpdateTime": "0001-01-01T00:00:00",
"connectionState": "Disconnected",
"lastActivityTime": "2019-04-26T16:41:11.6618195",
"cloudToDeviceMessageCount": 0,
"authenticationType": "selfSigned",
"x509Thumbprint": {
"primaryThumbprint": 
  "xxx",
"secondaryThumbprint": 
  "xxx"
},
"version": 2,
"properties": {
  "desired": {
    "$metadata": {
      "$lastUpdated": "2019-04-26T16:41:09.4381992Z"
   },
   "$version": 1
},
"reported": {
  "$metadata": {
    "$lastUpdated": "2019-04-26T16:41:09.4381992Z"
  },
  "$version": 1
 }
},
"capabilities": {
"iotEdge": false
}
}

如何通过自定义分配设置设备孪生默认值?

编辑:在我的函数上尝试了不同的响应类型之后,我认为我还将发布对我有用的代码,以读取参数以及形成通过DPS正确序列化的响应。问题仍然在于如何设置所需的initialTwin值。这是天蓝色的功能代码,可序列化回DPS。

public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
                                                      HttpRequestMessage req, TraceWriter log)
    {
        string requestBody = await req.Content.ReadAsStringAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);

        //Read out key information
        string deviceId = data.deviceRuntimeContext.registrationId;
        string certificate = data.deviceRuntimeContext.x509.clientCertificate;
        var response = new Response(data.linkedHubs?[0]);

        //Can't get initialTwin data back to DPS
        //response.initialTwin = new ResponseTwin() { }

        return req.CreateResponse<Response>(HttpStatusCode.OK, response);
    }

4 个答案:

答案 0 :(得分:0)

以下代码段是单个注册中的 bypass 自定义功能的示例:

#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");
    //log.LogInformation($"\nHeaders:\n\t{string.Join("\n\t", req.Headers.Select(i => $"{i.Key}={i.Value.First()}"))}");

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    string iotHub = data?.individualEnrollment?.iotHubs?[0];

    dynamic result = new { iotHubHostName = $"{iotHub}" };
    return (ActionResult)new OkObjectResult(result);
}

在初始化设备双胞胎的情况下,我们需要添加一个 initialTwin 属性对象,如以下示例所示:

dynamic result = new { 
    iotHubHostName = $"{iotHub}", 
    initialTwin = new { 
        tags = new { abcd = 12345}, 
        properties = new { 
            desired = new { 
                PropOne = "2345",
                PropTwo = "6789"
                }
            }
        }
    };

答案 1 :(得分:0)

根据该陈述,在您的问题中“我添加的所有自定义属性均未显示”,我认为该设备已被供应,并且您正在重新供应该设备。在这种情况下,DPS假定客户的解决方案已经具有配置状态,我们不想覆盖它。根据情况,您可以采取措施来满足您的需求。如果这是测试,并且您不担心与该设备相关的现有数据,则可以从集线器中删除该设备并进行重新配置。现在,新的双胞胎数据将从DPS中显示。

答案 2 :(得分:0)

我怀疑这会帮助其他人,下面的代码可以正常工作,但几乎没有。我一直无法修改动态结果而没有得到序列化错误,但至少此Azure Function代码(而非脚本)可以正常工作。关键是响应中的演员。

   public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
                                                      HttpRequestMessage req, TraceWriter log)
    {
        log.Info("C# HTTP trigger function processed a request.");
        //log.LogInformation($"\nHeaders:\n\t{string.Join("\n\t", req.Headers.Select(i => $"{i.Key}={i.Value.First()}"))}");

        string requestBody = await req.Content.ReadAsStringAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
        string iotHub = data.linkedHubs[0];

        dynamic result = new
        {
            iotHubHostName = $"{iotHub}",
            initialTwin = new
            {
                tags = new { abcd = 12345 },
                properties = new
                {
                    desired = new
                    {
                        PropOne = "2345",
                        PropTwo = "6789"
                    }
                }
            }
        };
        log.Info($"Sending back result: {Convert.ToString(result)}");

        return req.CreateResponse<dynamic>(HttpStatusCode.OK, (Object)result);
    }

答案 3 :(得分:0)

好吧,在Microsoft的帮助下解决此问题之后,这里是问题的答案。

1。)在Azure Functions的V2实例中实现Azure Function

2。)添加对Microsoft.Azure.Devices.Shared的引用

DPS代码需要一个TwinState实例,如下所示

public class ResponseObj
{
    public string iotHubHostName { get; set; }
    public TwinState initialTwin { get; set; }
}

然后通过此返回类型处理序列化

return (ActionResult)new OkObjectResult(response);

Java中的TwinState类: https://github.com/Azure/azure-iot-sdk-java/blob/a9c1487bede6463a6d67aadd68588cdaf92fd905/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/twin/TwinState.java#L123