none
Update reported properties of device twin in C# RRS feed

  • Question

  • Hello,

    since today Microsoft has published a new version of the Microsoft.Azure.Devices.Client SDK (v. 1.1.3) in C#, which supports the update of the report properties of a device twin. But I wonder, how to update the TwinCollection, which is a parameter for the UpdateReportedPropertiesAsync-method, to set the report properties. Has anybody already made any experience with this?

    Thanks in advance.

    Felix


    Tuesday, December 13, 2016 10:40 AM

Answers

  • Hi Felix,

    - your primary question related to the TwinCollection has been answered, you can use the Device Explorer Twin tool to see this update.

    - the secondary question is related to the threading (yielding) process between the device and Azure IoT Hub (MQTT Broker) implemented in the Microsoft.Azure.Devices.Client SDK (v. 1.1.3). Note, that the QoS=1 is used for handshaking device - broker, and the device publisher sent the message to the MQTT Broker for update device Twin. It looks like the handling of PUBACK by device is making a "frizzing".

    Try to update your code to see this issue:

    private static DeviceClient deviceClient;
    static void Main(string[] args)
    {
      string deviceId = "myFirstDevice";
      deviceClient = DeviceClient.CreateFromConnectionString(connectionString, deviceId, TransportType.Mqtt);
      AddReportProperties().Wait(1000);
      Console.WriteLine("Twin updated");
      Console.WriteLine("Press Enter to exit.");
      Console.ReadLine();
    }
    
    public static async Task AddReportProperties()
    {
      Twin deviceTwin = await deviceClient.GetTwinAsync();
               
      string patch = "{\"type\":\"cellular\"}";
      await deviceClient.UpdateReportedPropertiesAsync(JsonConvert.DeserializeObject<TwinCollection>(patch));
    }

    I have found more issues in this library such as the Twin object is not properly populated, missing the Metadata, DeviceId, etc), or for example problem using Get/Update Twin in the delegates for method or DesiredPropertUpdate, where the all async calls must be completed before sending a response. etc. I hope so, it will be some common bug in this C# SDK library.

    Update:

    the following code snippet shows an example of the direct method with the nested GetTwinAsync call:

    deviceClient.SetMethodHandler("getTwin", OnGetTwin, null);
    
    
    ...
    
    
    private static async Task<MethodResponse> OnGetTwin(MethodRequest request, object userContext)
    {
      Console.WriteLine("Method:");
      Console.ForegroundColor = ConsoleColor.Yellow;
      Console.WriteLine("\t{0}\r\n", request.DataAsJson);
      Console.ResetColor();
    
      var twin = await deviceClient.GetTwinAsync();
      return new MethodResponse(Encoding.UTF8.GetBytes(twin.ToJson(Formatting.None)), 200);
    }

    the response can be saw in the Device Explorer Twin:

    as you can see, the deviceId and etag was not populated.

    Thanks

    Roman

        





    • Marked as answer by Felix Huber Wednesday, December 14, 2016 1:00 PM
    • Edited by Roman Kiss Wednesday, December 14, 2016 3:24 PM
    Wednesday, December 14, 2016 12:36 PM

All replies

  • Hi Felix,

    - the TwinCollection class is attributed by  [JsonConverter(typeof(TwinCollectionJsonConverter))], so try the following:

    var patch = JsonConvert.DeserializeObject<TwinCollection>("{\"status\":\"done\"}");
    deviceClient.UpdateReportedPropertiesAsync(patch);

    Thanks

    Roman



    • Edited by Roman Kiss Tuesday, December 13, 2016 2:36 PM
    Tuesday, December 13, 2016 2:34 PM
  • Hi Roman,

    thanks for your answer. But it doesn't quite work for some reason. I have a console application for testing the update of reported properties. But at the UpdateReportedPropertiesAsync-method it gets stuck.

            private static DeviceClient deviceClient;
            static void Main(string[] args)
            {
                string deviceId = "myFirstDevice";
                deviceClient = DeviceClient.CreateFromConnectionString(connectionString, deviceId, TransportType.Mqtt);
                AddReportProperties().Wait();
                Console.WriteLine("Twin updated");
                Console.WriteLine("Press Enter to exit.");
                Console.ReadLine();
            }
    
            public static async Task AddReportProperties()
            {
                Twin deviceTwin = await deviceClient.GetTwinAsync();
               
                string patch = "{\"type\":\"cellular\"}"
                deviceClient.UpdateReportedPropertiesAsync(JsonConvert.DeserializeObject<TwinCollection>(patch));
            }

    It shouldn't be a problem with the async method (e.g. deadlock etc.) because the GetTwinAsync-method, which I call earlier, is processed.

    Thanks.

    Felix

    Wednesday, December 14, 2016 9:19 AM
  • Hi Felix,

    - your primary question related to the TwinCollection has been answered, you can use the Device Explorer Twin tool to see this update.

    - the secondary question is related to the threading (yielding) process between the device and Azure IoT Hub (MQTT Broker) implemented in the Microsoft.Azure.Devices.Client SDK (v. 1.1.3). Note, that the QoS=1 is used for handshaking device - broker, and the device publisher sent the message to the MQTT Broker for update device Twin. It looks like the handling of PUBACK by device is making a "frizzing".

    Try to update your code to see this issue:

    private static DeviceClient deviceClient;
    static void Main(string[] args)
    {
      string deviceId = "myFirstDevice";
      deviceClient = DeviceClient.CreateFromConnectionString(connectionString, deviceId, TransportType.Mqtt);
      AddReportProperties().Wait(1000);
      Console.WriteLine("Twin updated");
      Console.WriteLine("Press Enter to exit.");
      Console.ReadLine();
    }
    
    public static async Task AddReportProperties()
    {
      Twin deviceTwin = await deviceClient.GetTwinAsync();
               
      string patch = "{\"type\":\"cellular\"}";
      await deviceClient.UpdateReportedPropertiesAsync(JsonConvert.DeserializeObject<TwinCollection>(patch));
    }

    I have found more issues in this library such as the Twin object is not properly populated, missing the Metadata, DeviceId, etc), or for example problem using Get/Update Twin in the delegates for method or DesiredPropertUpdate, where the all async calls must be completed before sending a response. etc. I hope so, it will be some common bug in this C# SDK library.

    Update:

    the following code snippet shows an example of the direct method with the nested GetTwinAsync call:

    deviceClient.SetMethodHandler("getTwin", OnGetTwin, null);
    
    
    ...
    
    
    private static async Task<MethodResponse> OnGetTwin(MethodRequest request, object userContext)
    {
      Console.WriteLine("Method:");
      Console.ForegroundColor = ConsoleColor.Yellow;
      Console.WriteLine("\t{0}\r\n", request.DataAsJson);
      Console.ResetColor();
    
      var twin = await deviceClient.GetTwinAsync();
      return new MethodResponse(Encoding.UTF8.GetBytes(twin.ToJson(Formatting.None)), 200);
    }

    the response can be saw in the Device Explorer Twin:

    as you can see, the deviceId and etag was not populated.

    Thanks

    Roman

        





    • Marked as answer by Felix Huber Wednesday, December 14, 2016 1:00 PM
    • Edited by Roman Kiss Wednesday, December 14, 2016 3:24 PM
    Wednesday, December 14, 2016 12:36 PM
  • Hi Felix,

    I have a good news, thanks for Microsoft guys for really quick fixing this issue in the Microsoft.Azure.Devices.Client SDK (v. 1.1.4). I have tested it and its working very well, therefore you don't need to use a waiting time for expiring state.

    in addition, the following is my example for handler of the direct method in the async manner, where are the multiple nested async calls such as Get/Update/Get device twin before sending the async response message to the invoker:

    private static async Task<MethodResponse> OnWriteLine(MethodRequest request, object userContext)
    {
        var req = new { input1 = 1, input2 = "" };
    
        Console.WriteLine("Method:");
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine("\t{0}\r\n", request.DataAsJson);
        Console.ResetColor();
    
        var twin = await deviceClient.GetTwinAsync();
    
        string patch = "{\"type\":\"xxxxCellular\"}";
        await deviceClient.UpdateReportedPropertiesAsync(JsonConvert.DeserializeObject<TwinCollection>(patch));
    
        twin = await deviceClient.GetTwinAsync();
        Console.WriteLine(twin.ToJson(Formatting.Indented));
    
        req = JsonConvert.DeserializeAnonymousType(request.DataAsJson, req);
        var response = JsonConvert.SerializeObject(new {result = "Done", id=req.input1});
       return new MethodResponse(Encoding.UTF8.GetBytes(response), 200);
    }

    Note, that still there is an issue in the Twin class, where are not populated some properties such as metadata, deviceId, etc.

    Thanks

    Roman




    • Edited by Roman Kiss Thursday, December 15, 2016 8:17 AM
    Thursday, December 15, 2016 8:11 AM
  • Hi Roman,

    thank you very much for your help and the code snippet. Works smoothly ;-).

    Felix

    Thursday, December 15, 2016 1:49 PM