Azure / opendigitaltwins-dtdl

Digital Twins Definition Language
Creative Commons Attribution 4.0 International
470 stars 160 forks source link

How to handle commands with multiple arguments? #53

Closed FreddieChopin closed 4 years ago

FreddieChopin commented 4 years ago

My preference for a command with multiple arguments is just to have them as a top-level object in the JSON. Let's say that I have a command named "configuration-set-boolean" which should get 2 arguments - the name of the configuration to set and the new value for the given configuration. In such scenario the IoTHub device just gets a following payload:

{
    "name": "feature-5-enable",
    "value": true
}

This works perfectly fine via direct communication using Azure's portal or when executing direct method directly from Visual Studio Code.

However - in my understanding - it is impossible to describe such thing in DTDL, as the specs seems to suggest that command request (as well as the response) can have only ONE argument which has to be named. It seems logical to use an Object schema type in that case - then the multiple arguments are just fields of the object. However to actually describe such a thing in DTDL it seems that the payload must no longer be "flat", but it actually has to contain a named object like this:

{
    "arguments": {
        "name": "feature-5-enable",
        "value": true
    }
}

A description for such a thing would then have to look more-or-less like this:

{
          "@type": "Command",
          "name": "configuration-set-boolean",
          "commandType": "asynchronous",
          "request": {
            "name": "arguments",
            "schema": {
              "@type": "Object",
              "fields": [
                {
                  "name": "name",
                  "schema": "string"
                },
                {
                  "name": "value",
                  "schema": "boolean"
                }
              ]
            }
          }
        },

Having this "arguments":{...} wrapper is completely pointless from my perspective and it's just a waste of bandwidth (the device uses an LTE modem) and memory (it's just an ARM Cortex-M microcontroller).

Is this really the case? Maybe this should be handled some other way (e.g. maybe "request" can actually be an array with multiple elements, each corresponding to one argument)? Maybe the specs could be changed somehow to allow a scenario of multiple arguments?

briancr-ms commented 4 years ago

When using Azure IoT Hub and device twin direct methods (https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-direct-methods), the request schema describes the "payload" field in the direct method JSON body. If the command takes a single value, the schema can be a primitive (e.g. integer, etc.). If the command takes a complex object (or array, etc.), a complex schema can be used. In your example, the direct method JSON body would look like: { ..., "payload": { "name": "your-name", "value": true }.

FreddieChopin commented 4 years ago

If the command takes a complex object (or array, etc.), a complex schema can be used. In your example, the direct method JSON body would look like: { ..., "payload": { "name": "your-name", "value": true }.

But how do you describe that in the DTDL? That was the main issue here, because I know that I can send such payload and it works perfectly fine, I just have no idea how to describe such structure in the DTDL, which is required when you want to have the device certified for Azure Central.

If possible, I would be grateful for some more details, as the comment above does not solve our problem.

briancr-ms commented 4 years ago

An Azure IoT Hub direct method that takes a JSON body like this:

{
  ...,
  "payload": {
    "name": "your-name",
    "value": true
  }
}

Is described by a command request in DTDL like you had above:

{
  "@type": "Command",
  "name": "configuration-set-boolean",
  "request": {
    "name": "arguments",
    "schema": {
      "@type": "Object",
      "fields": [
        {
          "name": "name",
          "schema": "string"
        },
        {
          "name": "value",
          "schema": "boolean"
        }
      ]
    }
  }
}

The request name ("arguments") is not used in the direct method payload. In this binding (Command to Azure IoT Hub direct method) it's just metadata.

FreddieChopin commented 4 years ago

Thanks for your explanation.