1
votes

I want to report to report an exact 8-byte number as reported property via the device twin to the IoT Hub. However, when viewing the values in the azure portal, I only see floating point numbers in scientific format. The Azure doc on the page here https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-device-twins says: All values in JSON objects can be of the following JSON types: boolean, number, string, object.

When I convert the numbers from Azure portal back, e.g. with python: print(format(int(float("7.26238597903829E+16")), "016x")) the number is incorrect, due to imprecise float format, I guess.

I read here https://www.w3schools.com/js/js_json_datatypes.asp that JSON numbers can be either integers or floating point numbers. Hence I assume int numbers should not be a problem.

The struct declaration for the serializer in my C-code looks like this:

DECLARE_STRUCT(NodeType,
int64_t, addr,
uint8_t, status
);

Is it possible to retrieve EXACT 64 bit numbers from a device twin reported property?

EDIT: for reproducing the issue, I created a new device on the IoT hub with device id "car". I downloaded the current azure-iot-c-sdk and modified the devicetwin_simplesample from the serializer samples. Here is the diff:

diff --git a/serializer/samples/devicetwin_simplesample/devicetwin_simplesample.c b/serializer/samples/devicetwin_simplesample/devicetwin_simplesample.c
index 7da717c..4f9e28d 100644
--- a/serializer/samples/devicetwin_simplesample/devicetwin_simplesample.c
+++ b/serializer/samples/devicetwin_simplesample/devicetwin_simplesample.c
@@ -14,7 +14,7 @@

 /*String containing Hostname, Device Id & Device Key in the format:             */
 /*  "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"    */
-static const char* connectionString = "HostName=...";
+static const char* connectionString = "HostName=XXX.azure-devices.net;DeviceId=car;SharedAccessKey=XXXX";

 // Define the Model - it is a car.
 BEGIN_NAMESPACE(Contoso);
@@ -31,7 +31,7 @@ DECLARE_STRUCT(Geo,
 );

 DECLARE_MODEL(CarState,
-    WITH_REPORTED_PROPERTY(int32_t, softwareVersion),
+    WITH_REPORTED_PROPERTY(int64_t, softwareVersion),
     WITH_REPORTED_PROPERTY(uint8_t, reported_maxSpeed),
     WITH_REPORTED_PROPERTY(ascii_char_ptr, vanityPlate)
 );
@@ -125,7 +125,7 @@ void device_twin_simple_sample_run(void)
                     car->maker.style = "sedan";
                     car->maker.year = 2014;
                     car->state.reported_maxSpeed = 100;
-                    car->state.softwareVersion = 1;
+                    car->state.softwareVersion = 0x0102030405060708;
                     car->state.vanityPlate = "1I1";

                     /*sending the values to IoTHub*/

After I start this sample, I get a flaoting point number for the SW version number in the device twin (partially shown here) in my Azure portal:

{
  "deviceId": "car",
  "etag": "AAAAAAAAAAE=",
  "properties": {
    "desired": {
      "$metadata": {
        "$lastUpdated": "2017-08-14T14:03:24.5887488Z"
      },
      "$version": 1
    },
    "reported": {
      "state": {
        "softwareVersion": 72623859790382848.0,
        "reported_maxSpeed": 100,
        "vanityPlate": "1I1"
      },
      ...
1
Can you show us a sample code that how you updated reported property? I test with C# and the 8-byte number doesn't be automatically converted. It is the same in the azure portal with in my code.Rita Han
Please find my edits with a diff above. I'm using the C SDK. This test was done with Ubuntu 16.04 and their gcc.StrawHat

1 Answers

0
votes

This issue caused by representing your int64 value with JSON type: number and number type is double- precision floating-point format in JavaScript.

For double- precision floating-point:

  • Sign bit: 1 bit
  • Exponent: 11 bits
  • Significand precision: 53 bits (52 explicitly stored)

So the max integer it can represent is 2^52, for Hexadecimal is 0xFFFFFFFFFFFFF, for decimal is 4503599627370495.

Because your softwareVersion value extends the range it can represent so it cut redundant bits, then you get the wrong value.

For your case, you can split the 64-bit value into two 32-bit values at the sender side and recombine two 32-bit values to a 64-bit value at the receiver side.