Custom allocation supports setting the initial device twin as well as the IoT Hub. The device twin does not get set.
I've configured the device provisioning service in Azure to use a custom Azure Function. In the Azure function, via custom API, we run logic to determine the best IoT Hub location for the device. In addition to the IoT Hub assignment, the code supplies the initial device twin data but It's not working.
I'm following the code sample described in this blog: https://sandervandevelde.wordpress.com/2018/12/29/custom-iot-hub-assignment-in-device-provisioning-service/
I've looked through several related custom allocation issues but haven't found anyone using the custom azure function approach as described above.
Here is a snippet of the related code from the blog article above.
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";
Below are the class definitions taken from the Blog article. Note the use of the dynamic type for desired properties. Can someone confirm this is the correct message response type to 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
After provisioning, the IoT Hub value is returned to device correctly. Then I went into the azure portal, IoT Hub and show the device twin value. None of the custom properties I added show up. The twin below is apparently some IoT Hub default as it doesn't match the twin in the DPS service either.
{
"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
}
}
How can I set the device twin default value via custom allocation?
EDIT: After trying a different response type on my function, I thought I'd also post the code that works for me to read the parameters as well as forming the response that does serialize correctly through DPS. The issue still remains how to set the desired initialTwin values. Here's the azure function code that serializes back to 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);
}