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 la télémétrie, les propriétés et les commandes qu’un appareil IoT Plug-and-Play implémente à l’aide d’un modèle Digital Twins Definition Language (DTDL). 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 propriété
$.sub
avec le nom du composant à la rubrique de télémétrie. Le système ajoute la propriétédt-subject
. - Lorsque vous utilisez AMQP, ajoutez la propriété
dt-subject
avec le nom du composant comme 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 tout JSON valide qui respecte 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
Lorsqu'il signale des propriétés inscriptibles, le dispositif doit composer le message d'accusé de réception en utilisant les quatre champs de la liste précédente, afin d'indiquer l'état réel du dispositif, 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 tout JSON valide qui respecte 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 :