Conventions IoT Plug-and-Play

Les appareils IoT Plug-and-Play doivent suivre un ensemble de conventions lorsqu’ils échangent des messages avec un hub IoT. Les appareils IoT Plug-and-Play utilisent le protocole MQTT pour communiquer avec IoT Hub. IoT Hub prend également en charge le protocole AMQP disponible dans certains kits SDK d’appareil IoT.

Un appareil peut inclure des modules ou être implémentés dans un module IoT Edge hébergé par le runtime IoT Edge.

Vous décrivez les données de télémétrie, les propriétés et les commandes qu’un appareil IoT Plug-and-Play implémente avec un modèle DTDL (Digital Twins Definition Language). Il existe deux types de modèles auxquels il est fait référence dans cet article :

  • Aucun composant : modèle sans composants. Le modèle déclare la télémétrie, les propriétés et les commandes comme des éléments de haut niveau dans la section Contenus de l’interface principale. Dans l’outil Explorateur Azure IoT, ce modèle apparaît comme un seul composant par défaut.
  • Plusieurs composants : modèle composé d’au moins deux interfaces. Une interface principale, qui apparaît comme le composant par défaut, avec la télémétrie, les propriétés et les commandes. Une ou plusieurs interfaces déclarées comme des composants avec plus de télémétrie, des propriétés et des commandes supplémentaires.

Pour plus d’informations, consultez le Guide de modélisation d’IoT Plug-and-Play.

identification du modèle

Pour annoncer le modèle qu’il implémente, un appareil ou module IoT Plug-and-Play inclut l’ID de modèle dans le paquet de connexion MQTT en ajoutant model-id au champ USERNAME.

Pour découvrir le modèle implémenté par un appareil ou un module, un service peut récupérer l’ID de modèle à partir :

  • du champ modelId du jumeau d’appareil ;
  • du champ $metadata.$model du jumeau numérique ;
  • d’une notification de modification du jumeau numérique.

Télémétrie

  • La télémétrie envoyée à partir d’un appareil sans composant ne nécessite aucune métadonnée supplémentaire. Le système ajoute la propriété dt-dataschema.
  • Les données de télémétrie envoyées depuis un appareil à l’aide de composants doivent ajouter le nom du composant au message de télémétrie.
  • Lorsque vous utilisez MQTT, ajoutez la $.sub propriété avec le nom du composant à la rubrique de télémétrie, le système ajoute la dt-subject propriété.
  • Lorsque vous utilisez AMQP, ajoutez la dt-subject propriété avec le nom du composant en tant qu’annotation de message.

Remarque

La télémétrie fournie par des composants nécessite un message par composant.

Pour plus d’exemples de télémétrie, consultez La télémétrie des > charges utiles

Propriétés en lecture seule

Un appareil définit une propriété en lecture seule qu’il signale ensuite à l’application back-end.

Exemple de propriété en lecture seule sans composant

Un appareil ou un module peut envoyer n’importe quel JSON valide qui suit les règles DTDL.

DTDL qui définit une propriété sur une interface :

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:example: Thermostat;1",
  "@type": "Interface",
  "contents": [
    {
      "@type": "Property",
      "name": "temperature",
      "schema": "double"
    }
  ]
}

Exemple de charge utile de propriété rapportée :

"reported" :
{
  "temperature" : 21.3
}

Exemple de propriété en lecture seule avec plusieurs composants

L’appareil ou le module doit ajouter le marqueur {"__t": "c"} pour indiquer que l’élément fait référence à un composant.

DTDL qui fait référence à un composant :

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:TemperatureController;1",
  "@type": "Interface",
  "displayName": "Temperature Controller",
  "contents": [
    {
      "@type" : "Component",
      "schema": "dtmi:com:example:Thermostat;1",
      "name": "thermostat1"
    }
  ]
}

DTDL qui définit le composant :

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:Thermostat;1",
  "@type": "Interface",
  "contents": [
    {
      "@type": "Property",
      "name": "temperature",
      "schema": "double"
    }
  ]
}

Exemple de charge utile de propriété rapportée :

"reported": {
  "thermostat1": {
    "__t": "c",
    "temperature": 21.3
  }
}

Pour plus d’exemples de propriétés en lecture seule, consultez Propriétés des charges utiles>.

Propriétés accessibles en écriture

Une application back-end définit une propriété accessible en écriture que IoT Hub envoie ensuite à l’appareil.

L’appareil ou le module doit confirmer qu’il a reçu la propriété en envoyant une propriété rapportée. La propriété rapportée doit inclure :

  • value : valeur réelle de la propriété (en général, la valeur reçue, mais l’appareil peut décider de signaler une autre valeur).
  • ac : code d’accusé de réception qui utilise un code d’état HTTP.
  • av : version d’accusé de réception qui fait référence à la $version de la propriété souhaitée. Vous pouvez trouver cette valeur dans la charge utile JSON de la propriété souhaitée.
  • ad : description facultative de l’accusé de réception.

Réponses d’accusé de réception

Lorsque vous signalez des propriétés accessibles en écriture, l’appareil doit composer le message d’accusé de réception, en utilisant les quatre champs de la liste précédente, pour indiquer l’état réel de l’appareil, comme décrit dans le tableau suivant :

Status(ac) Version(av) Value(value) Description(av)
200 Version souhaitée Valeur souhaitée Valeur de propriété souhaitée acceptée
202 Version souhaitée Valeur acceptée par l’appareil Valeur de propriété souhaitée acceptée, mise à jour en cours (doit se terminer par 200)
203 0 Valeur définie par l’appareil Propriété définie à partir de l’appareil, sans refléter les valeurs souhaités
400 Version souhaitée Valeur réelle utilisée par l’appareil Valeur de propriété souhaitée non acceptée
500 Version souhaitée Valeur réelle utilisée par l’appareil Exception lors de l’application de la propriété

Quand un appareil démarre, il doit demander le jumeau de l’appareil et vérifier s’il existe des mises à jour de propriétés accessibles en écriture. Si la version d’une propriété accessible en écriture a augmenté pendant que l’appareil était hors connexion, l’appareil doit envoyer une réponse de propriété rapportée pour confirmer qu’il a reçu la mise à jour.

Quand un appareil démarre pour la première fois, il peut envoyer une valeur initiale pour une propriété rapportée s’il ne reçoit pas de propriété souhaitée initiale du hub IoT. Dans ce cas, l’appareil peut envoyer la valeur par défaut avec av pour 0 et ac pour 203. Par exemple :

"reported": {
  "targetTemperature": {
    "value": 20.0,
    "ac": 203,
    "av": 0,
    "ad": "initialize"
  }
}

Un appareil peut utiliser la propriété rapportée pour fournir d’autres informations au hub. Par exemple, l’appareil peut répondre avec une série de messages en cours de traitement tels que :

"reported": {
  "targetTemperature": {
    "value": 35.0,
    "ac": 202,
    "av": 3,
    "ad": "In-progress - reporting current temperature"
  }
}

Lorsque l’appareil atteint la température cible, il envoie le message suivant :

"reported": {
  "targetTemperature": {
    "value": 20.0,
    "ac": 200,
    "av": 4,
    "ad": "Reached target temperature"
  }
}

Un appareil peut signaler une erreur telle que :

"reported": {
  "targetTemperature": {
    "value": 120.0,
    "ac": 500,
    "av": 3,
    "ad": "Target temperature out of range. Valid range is 10 to 99."
  }
}

Type d'objet

Si une propriété accessible en écriture est définie en tant qu’objet, le service doit envoyer un objet complet à l’appareil. L’appareil doit accuser réception de la mise à jour en renvoyant suffisamment d’informations au service pour que celui-ci comprenne comment l’appareil a agi en réponse à la mise à jour. Cette réponse peut inclure ce qui suit :

  • L’objet entier
  • Uniquement les champs que l’appareil a mis à jour
  • Un sous-ensemble des champs

Pour les objets volumineux, pensez à réduire la taille de l’objet que vous incluez dans l’accusé de réception.

L’exemple suivant montre une propriété accessible en écriture définie comme Object avec quatre champs :

DTDL :

{
  "@type": "Property",
  "name": "samplingRange",
  "schema": {
    "@type": "Object",
    "fields": [
      {
        "name": "startTime",
        "schema": "dateTime"
      },
      {
        "name": "lastTime",
        "schema": "dateTime"
      },
      {
        "name": "count",
        "schema": "integer"
      },
      {
        "name": "errorCount",
        "schema": "integer"
      }
    ]
  },
  "displayName": "Sampling range"
  "writable": true
}

Pour mettre à jour cette propriété accessible en écriture, envoyez un objet complet à partir du service qui ressemble à l’exemple suivant :

{
  "samplingRange": {
    "startTime": "2021-08-17T12:53:00.000Z",
    "lastTime": "2021-08-17T14:54:00.000Z",
    "count": 100,
    "errorCount": 5
  }
}

L’appareil répond avec un accusé de réception ressemblant à l’exemple suivant :

{
  "samplingRange": {
    "ac": 200,
    "av": 5,
    "ad": "Weighing status updated",
    "value": {
      "startTime": "2021-08-17T12:53:00.000Z",
      "lastTime": "2021-08-17T14:54:00.000Z",
      "count": 100,
      "errorCount": 5
    }
  }
}

Exemple de propriété accessible en écriture sans composant

Quand un appareil reçoit plusieurs propriétés souhaitées dans une seule charge utile, il peut envoyer les réponses de propriétés rapportées dans plusieurs charges utiles ou combiner les réponses dans une charge utile unique.

Un appareil ou un module peut envoyer n’importe quel JSON valide qui suit les règles DTDL.

DTDL :

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:example: Thermostat;1",
  "@type": "Interface",
  "contents": [
    {
      "@type": "Property",
      "name": "targetTemperature",
      "schema": "double",
      "writable": true
    },
    {
      "@type": "Property",
      "name": "targetHumidity",
      "schema": "double",
      "writable": true
    }
  ]
}

Exemple de charge utile de propriété souhaitée :

"desired" :
{
  "targetTemperature" : 21.3,
  "targetHumidity" : 80,
  "$version" : 3
}

Exemple de première charge utile de propriété rapportée :

"reported": {
  "targetTemperature": {
    "value": 21.3,
    "ac": 200,
    "av": 3,
    "ad": "complete"
  }
}

Exemple de deuxième charge utile de propriété rapportée :

"reported": {
  "targetHumidity": {
    "value": 80,
    "ac": 200,
    "av": 3,
    "ad": "complete"
  }
}

Remarque

Vous pouvez choisir de combiner ces deux charges utiles de propriétés rapportées dans une charge utile unique.

Exemple de propriété accessible en écriture avec plusieurs composants

L’appareil ou le module doit ajouter le marqueur {"__t": "c"} pour indiquer que l’élément fait référence à un composant.

Le marqueur est envoyé uniquement pour les mises à jour des propriétés définies dans un composant. Les mises à jour des propriétés définies dans le composant par défaut n’incluent pas le marqueur. Voir Exemple de propriété accessible en écriture sans composant.

Lorsqu’un appareil reçoit plusieurs propriétés rapportées dans une seule charge utile, il peut envoyer les réponses de propriétés rapportées dans plusieurs charges utiles ou combiner les réponses dans une charge utile unique.

L’appareil ou le module doit confirmer qu’il a reçu les propriétés en envoyant des propriétés rapportées :

DTDL qui fait référence à un composant :

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:TemperatureController;1",
  "@type": "Interface",
  "displayName": "Temperature Controller",
  "contents": [
    {
      "@type" : "Component",
      "schema": "dtmi:com:example:Thermostat;1",
      "name": "thermostat1"
    }
  ]
}

DTDL qui définit le composant :

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:Thermostat;1",
  "@type": "Interface",
  "contents": [
    {
      "@type": "Property",
      "name": "targetTemperature",
      "schema": "double",
      "writable": true
    }
  ]
}

Exemple de charge utile de propriété souhaitée :

"desired": {
  "thermostat1": {
    "__t": "c",
    "targetTemperature": 21.3,
    "targetHumidity": 80,
    "$version" : 3
  }
}

Exemple de première charge utile de propriété rapportée :

"reported": {
  "thermostat1": {
    "__t": "c",
    "targetTemperature": {
      "value": 23,
      "ac": 200,
      "av": 3,
      "ad": "complete"
    }
  }
}

Exemple de deuxième charge utile de propriété rapportée :

"reported": {
  "thermostat1": {
    "__t": "c",
    "targetHumidity": {
      "value": 80,
      "ac": 200,
      "av": 3,
      "ad": "complete"
    }
  }
}

Remarque

Vous pouvez choisir de combiner ces deux charges utiles de propriétés rapportées dans une charge utile unique.

Pour obtenir des exemples de propriétés accessibles en écriture, consultez Propriétés des charges utiles>.

Commandes

Les interfaces sans composant utilisent le nom de commande sans préfixe.

Sur un appareil ou un module, les interfaces avec plusieurs composants utilisent des noms de commande au format suivant : componentName*commandName.

Pour plus d’exemples de commandes, consultez Commandes >de charge utile.

Conseil

IoT Central a ses propres conventions pour implémenter des commandes longues et des commandes hors connexion.

Étapes suivantes

À présent que vous connaissez les conventions IoT Plug-and-Play, voici quelques autres ressources :