Scénario : normalisation des unités de mesure à l'aide d'un adaptateur jumeau numérique

Ce scénario explique comment utiliser un modèle de jumeau numérique, un adaptateur de jumeau numérique avec des mappings d'enveloppe et de routage pour normaliser une télémétrie spécifique dans un schéma commun, et comment valider le flux en publiant des exemples de charge utile de périphérique.

Ce scénario montre comment publier des données de télémétrie automobile avec différentes unités de mesure miles par heure et kilomètres par heure à l'aide d'adresses différentes, de deux instances de jumeau numérique et de deux clés externes différentes. Pour plus d'informations sur les modèles JQ référencés dans ce scénario, reportez-vous à Référence : Expressions JQ pour les adaptateurs Jumeaux numériques.

Un adaptateur de jumeau numérique achemine les demandes par adresse et mappe les données traitées vers un modèle unique. Par exemple, le modèle de mesure envoie la vitesse en kilomètres par heure (velocity_kph) tandis qu'une autre instance de jumeau numérique standard envoie des miles par heure (speed).

Tâches

Comprenez les fichiers dans ce scénario :

Extraits de code que vous pouvez utiliser dans votre modèle de jumeau numérique référencé dans les étapes ci-dessous :

  • model.json : modèle de jumeau numérique basé sur les spécifications DTDL v3 avec une propriété de télémétrie speed en miles par heure qui utilise une extension de validation qui applique des limites sur la plage de valeurs allant de 0 à 100.
  • envelope.json : configuration d'enveloppe qui déclare une adresse de référence et un exemple de forme de charge utile.
  • routes.json : conditions de routage et correspondances de charge utile qui convertissent les kilomètres par heure en kilomètres par heure.
  • script.sh : dans cet exemple, vous pouvez enregistrer toutes les commandes de l'interface de ligne de commande OCI répertoriées ci-dessous pour créer un modèle de jumeau numérique, un adaptateur et des instances, ainsi que les commandes curl pour POSTer un exemple de télémétrie, puis l'exécuter en tant que script shell script.sh.
  • Pour effectuer les étapes de ce scénario, vous pouvez créer et enregistrer l'interface de ligne de commande OCI et les commandes curl répertoriées dans les étapes ci-dessous et exécuter ce scénario en tant que script shell : script.sh

Cet exemple de fragment de code de modèle de jumeau numérique model.json utilise une extension personnalisée dtmi:com:oracle:dtdl:extension:validation;1 qui applique les règles de validation au schéma JSON pour les éléments "Telemetry", "Historized", "Validated", "Velocity". Si les données ne correspondent pas aux valeurs attendues définies dans cette validation, elles sont rejetées.

Pour obtenir la liste complète des règles de propriété de validation prises en charge, reportez-vous à Référence d'extension de validation DTMI.

model.json

{
  "@context":[
    "dtmi:dtdl:context;3",
    "dtmi:dtdl:extension:historization;1",
    "dtmi:com:oracle:dtdl:extension:validation;1",
    "dtmi:dtdl:extension:quantitativeTypes;1"
  ],
  "@id":"dtmi:com:oracle:iot:poc:testmodel;1",
  "@type":"Interface",
  "contents":[
    {
      "@type":[ "Telemetry", "Historized", "Validated", "Velocity" ],
      "displayName":"Speed",
      "name":"speed",
      "schema":"integer",
      "unit":"milePerHour",
      "minimum":0,
      "maximum":100
    }
  ]
}

envelope.json

{
  "referenceEndpoint": "telemetry/automotive/usa-standard-units",
  "referencePayload": {
    "dataFormat": "JSON",
    "data": {
      "speed": 65
    }
  }
}

Ce fichier routes.json répertorié ci-dessous contient 3 expressions qui transforment les kilomètres et normalisent la charge utile des données en une unité de mesure, miles par heure :
  • Expression de condition qui évalue les données de l'adresse :

    "condition" : "${endpoint(3) == \"metric-units\"}"

    La syntaxe ${ ... } indique une expression qui évalue la valeur du troisième paramètre d'adresse ou élément de chemin dans un appel d'API endpoint(3). La condition compare la valeur renvoyée à metric-units. Si la valeur est True, ces règles sont appliquées.

  • Expression de mapping de charge utile :

    "payloadMapping" : { "$.speed": "${(.velocity_kph / 1.609) | floor}"}

    La syntaxe ${ ... } indique une expression. Cette expression évalue et effectue un calcul arithmétique pour convertir la vitesse ou la vitesse de kilomètres à l'heure en miles à l'heure. (.velocity_kph / 1.609) divise le champ velocity_kph par 1.609, puis applique la fonction de plancher, en arrondissant à l'entier le plus proche. Cette valeur provient de la conversion de kilomètres en miles qui est kilomètres = miles × 1.60934,

  • "payloadMapping": {"$.speed": "$.speed"} Il s'agit d'une expression de mise en correspondance de valeur directe, passant par la valeur de vitesse telle quelle.
[
  {
    "description" : "Automotive data using metric units (kilometers) that's converted to miles, with a different external key in the digital twin instance",
    "condition" : "${endpoint(3) == \"metric-units\"}",
    "payloadMapping" : { 
      "$.speed": "${(.velocity_kph / 1.609) | floor}"

    },
    "referencePayload" : {
      "dataFormat" : "JSON",
      "data" : { "velocity_kph": 104 }
    }
  },
  {
    "description" : "Auto 1 and Auto 2 use USA standard units, shows speed as is.", 
    "condition" : "*",
    "payloadMapping" : { "$.speed": "$.speed" }
  }
]

Étape 1 : Créer un modèle de jumeau numérique

Utilisez cette commande d'interface de ligne de commande oci iot digital-twin-model create pour créer un modèle de jumeau numérique à l'aide du fichier model.json. Ce modèle de jumeau numérique standardise speed en miles par heure.

Cette commande enregistre le modèle de jumeau numérique avec cet URI DTMI dtmi:com:oracle:iot:poc:testmodel;1 tel que défini dans la mention model.json ci-dessus.

oci iot digital-twin-model create \
  --iot-domain-id <iot-domain-ocid> \
  --display-name "Test Digital Twin Model" \
  --description "Model for testing automotive telemetry routing and unit normalization" \
  --spec file://~/model.json

Étape 2 : Créer un adaptateur jumeau numérique avec une enveloppe et des itinéraires

Créez un adaptateur qui référence la spécification DTMI du modèle jumeau numérique et qui utilise l'enveloppe entrante et les routages pour normaliser la télémétrie entrante.

oci iot digital-twin-adapter create \
  --iot-domain-id <iot-domain-ocid> \
  --display-name "automotive-speed-adapter" \
  --description "Routes by units" \
  --digital-twin-model-spec-uri "dtmi:com:oracle:iot:poc:testmodel;1" \
  --inbound-envelope file://~/envelope.json \
  --inbound-routes file://~/routes.json

La valeur referenceEndpoint dans envelope.json est telemetry/automotive/usa-standard-units. Le fichier routes.json :

  • Achemine les demandes vers le troisième segment de chemin qui est égal à metric-units, par exemple, /telemetry/automotive/metric-units, puis convertit velocity_kph en speed en mph et planifie le résultat.
  • Utilise une condition générique par défaut (*) pour transmettre speed sans modification pour les automobiles qui utilisent des miles par heure.

Etape 3 : création de deux instances de jumeau numérique

Créez deux instances de jumeau numérique qui s'authentifient à l'aide d'un coffre secret et partagez les deux instances de jumeau numérique qui partagent le même adaptateur de jumeau numérique. Les adresses sont définies de sorte que chaque instance de jumeau numérique puisse publier des données vers une adresse unique :
  • Adresse pour mph : https://device-host/telemetry/automotive/usa-standard-units
  • Adresse pour kph : https://device-host/telemetry/automotive/metric-units
Remplacez l'OCID de l'adaptateur jumeau numérique par l'OCID de l'adaptateur jumeau numérique créé à l'étape précédente. Remplacez les noms d'affichage et les clés externes par les valeurs de votre environnement.
Remarque

Lorsque vous créez une instance de jumeau numérique avec authentification, vous pouvez utiliser une clé secrète de coffre ou un certificat mTLS pour l'authentification. Pour des raisons de sécurité, il est recommandé de créer une clé secrète de coffre ou un certificat mTLS unique pour chaque instance de jumeau numérique. Toutes les ressources doivent se trouver dans la même région et dans la même location que toutes les autres ressources IoT associées.

Si vous utilisez un certificat mTLS pour vous authentifier, vous devez utiliser le nom commun du certificat comme clé externe : --external-key <common-name-from-certificate-details>. Reportez-vous à Scénario : création d'une instance de jumeau numérique qui utilise un certificat mTLS.

Un administrateur doit ajouter la stratégie de création de clés secrètes ou de certificats. Reportez-vous à l'Step 3 in Prerequisites.

Instance de jumeau numérique pour les unités standard américaines, miles par heure (mph), notez la clé externe :

american-auto-standard-units
oci iot digital-twin-instance create \
  --iot-domain-id <IoT-domain-ocid> \
  --display-name "auto using miles per hour" \
  --external-key american-auto-standard-units \
  --digital-twin-adapter-id <same-digital-twin-adapter-ocid> \
  --auth-id <secret-ocid-or-certificate-ocid>
Instance de jumeaux numériques pour les unités métriques européennes, kilomètres par heure (kph), notez la clé externe :

european-auto-metric-units

oci iot digital-twin-instance create \
  --iot-domain-id <IoT-domain-ocid> \
  --display-name "auto using kilometers per hour" \
  --external-key european-auto-metric-units \
  --digital-twin-adapter-id <same-digital-twin-adapter-ocid> \
  --auth-id <secret-ocid-or-certificate-ocid>

Etape 4 : envoyer un exemple de télémétrie pour valider le routage et le mappage

Pour envoyer la télémétrie, vous avez besoin de la clé externe de la réponse de l'instance de jumeau numérique de l'étape 3, du mot de passe de l'appareil et de l'adresse de l'hôte de l'appareil.

Si l'instance de jumeau numérique utilise la clé secrète du coffre pour s'authentifier, vous devez l'utiliser comme valeur de clé secrète encodée en base 64 en tant que mot de passe de l'appareil.

  • Clé externe : remplacez external-key par external-key de l'instance de jumeau numérique avec laquelle vous voulez travailler. Pour éviter les problèmes de citation, il est recommandé de ne pas utiliser de guillemets dans la valeur de clé externe.
  • Mot de passe du périphérique : remplacez le mot de passe du périphérique par le contenu de clé secrète en texte brut ou le certificat MTLS.
  • Hôte de périphérique : remplacez device-host par l'hôte de périphérique de votre domaine IoT. Afin d'obtenir l'URL d'adresse d'hôte de périphérique pour le domaine IoT, reportez-vous à Obtention des détails d'un domaine IoT.

-u "external-key:device-password-secret-contents-or-certificate"

Remarque

En fonction de votre système d'exploitation ou de votre application, certaines applications ou certains éditeurs de code peuvent ajouter des guillemets indésirables à vos valeurs, ce qui peut entraîner une erreur. Reportez-vous à la section Troubleshooting pour obtenir des exemples de devis.
curl -i -X POST \
  -u "european-auto-metric-units:device-password-secret-or-certificate" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/metric-units" \
  -d '{ "velocity_kph": 0 }'
curl -i -X POST \
  -u "european-auto-metric-units:device-password-secret-or-certificate" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/metric-units" \
  -d '{ "velocity_kph": 110 }'

curl -i -X POST \
  -u "american-auto-standard-units:device-password-secret-or-certificate" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/usa-standard-units" \
  -d '{ "speed": 0 }'

curl -i -X POST \
  -u "american-auto-standard-units:device-password-vault-secret-base-64-or-certificate-OCID" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/usa-standard-units" \
  -d '{ "speed": 60 }'

Etape 5 : vérification du comportement de normalisation

La condition de routage ${endpoint(3) == "metric-units"} évalue les données et applique la mise en correspondance de charge utile suivante à l'adresse de données des unités de mesure :

"$.speed": "${(.velocity_kph / 1.609) | floor}"

Résultat attendu :

  • Le mapping de l'adaptateur convertit les kilomètres par heure (kph) en miles par heure (mph), puis applique le plancher pour satisfaire un schéma entier :

    speed_mph = floor(velocity_kph / 1.609)

  • Dans cet exemple, velocity_kph = 0: speed_mph = floor(0 / 1.609) = floor(0) = 0 mph

    Après plancher indique l'étape d'arrondi qui force le résultat à un nombre entier, arrondi vers le bas vers l'infini négatif. Cela est requis lorsque votre modèle DTDL déclare la télémétrie de vitesse comme schema: "integer", de sorte que la valeur est un entier, et non une virgule flottante ou une chaîne.

  • velocity_kph = 110speed = floor(110 / 1.609) = 68 mph
  • Les publications de données standard avec speed passent sans modification. Par exemple, les valeurs de cet exemple : 0, 60

Si la validation de modèle est activée minimum: 0, maximum: 100, les valeurs hors plage sont rejetées conformément aux règles de validation.

Utilise la conversion de type modifiable :

  • Pass-through (mph, schéma "integer") : {"speed": "60"} et {"speed": 60.0} sont stockés en tant que 60. {"speed": "60.2"} est rejeté sauf si la mise en correspondance est contrainte sur un entier (par exemple, avec floor).
  • Route de mesure (kph → mph) : {"velocity_kph": 110}68 ; {"velocity_kph": "110"}68 car le mapping floor émet un entier. Conservez des entrées arithmétiques numériques pour éviter les erreurs d'expression. Dans la mesure du possible, préférez 110 à "110".
  • L'arrondi reste explicite : la conversion temporaire n'arrondi pas automatiquement 68.35 à 68. Utilisez floor pour le schéma d'entiers ou basculez le modèle sur schema: "double" pour conserver les fractions.

Meilleures pratiques

  • Fichiers JSON de référence pour les spécifications et les adaptateurs de modèle de jumeau numérique : lorsque vous téléchargez un adaptateur à l'aide de l'interface de ligne de commande, vous pouvez utiliser des fichiers JSON pour indiquer la mise en correspondance des données. Dans les commandes de l'interface de ligne de commande, vous pouvez référencer les fichiers en tant que file://~/name.json ou fournir un chemin absolu ou relatif en fonction de votre environnement shell. Selon votre système d'exploitation, vous pouvez avoir une syntaxe légèrement différente avec des guillemets, des barres obliques ou l'emplacement du fichier par défaut. Reportez-vous à Gestion des entrées et sorties de l'interface de ligne de commande et à Utilisation d'un fichier JSON pour les entrées complexes.
  • Les fichiers de configuration JSON (enveloppe, routages) utilisent des noms de champ d'API dans camelCase (par exemple, referenceEndpoint). L'interface de ligne de commande OCI transmet ces fichiers sans modification via des arguments file://. L'utilisation du format JSON camelCase avec l'interface de ligne de commande est donc attendue et correcte.
  • La valeur referenceEndpoint dans envelope.json doit refléter une adresse standard pour votre adaptateur.
  • La condition de routage avec caractères génériques (*) est évaluée après des conditions spécifiques. Triez les définitions de routage en conséquence.
  • Portée de la conversion douce : les chaînes de type numérique et les doubles de nombre entier sont acceptées lorsqu'elles correspondent au type de modèle (par exemple, entier). Les aides de conversion de type telles que number() et toInteger ne sont pas prises en charge dans les expressions de routage. Utilisez l'arithmétique et floor ou adoptez schema: "double" pour préserver les fractions.

Variation : utilisation de schema="double" au lieu de floor

Cette variation montre comment la définition du schéma de propriété de modèle sur double affecte le mapping d'adaptateur et les valeurs enregistrées. Avec double, le valideur accepte toute valeur entière ou fractionnelle numérique qui respecte les contraintes de plage, sans arrondi automatique. Vous pouvez choisir de conserver une précision fractionnée (brute) ou de forcer des nombres entiers à l'aide de floor. Les deux réussissent la validation tant que les valeurs restent dans la plage définie.

Fonctionnement de la validation schema=double

  • Acceptation du type : accepte les nombres JSON avec ou sans parties fractionnaires, par exemple : 60, 68,35. Les chaînes telles que "68" ne sont pas valides.
  • Plage : les valeurs minimale et maximale, par exemple, dans cet exemple, 0–100 sont appliquées.
  • Aucune arrondi automatique : la plate-forme IoT n'arrondit pas les valeurs. Vous contrôlez l'arrondi dans le mapping de votre adaptateur jumeau numérique ou en aval à l'aide d'APEX ou de SQL en fonction des systèmes configurés pour visualiser vos données.

Fichiers utilisés dans cette variante :

  • model_double.json : modèle DTDL avec schema: "double".
    {
      "@context": [
        "dtmi:dtdl:context;3",
        "dtmi:dtdl:extension:historization;1",
        "dtmi:com:oracle:dtdl:extension:validation;1",
        "dtmi:dtdl:extension:quantitativeTypes;1"
      ],
      "@id": "dtmi:com:oracle:iot:poc:testmodeldouble;1",
      "@type": "Interface",
      "contents": [
        {
          "@type": [
            "Telemetry",
            "Historized",
            "Validated",
            "Velocity"
          ],
          "displayName": "Speed",
          "name": "speed",
          "schema": "double",
          "unit": "milePerHour",
          "minimum": 0,
          "maximum": 100
        }
      ]
    }
  • routes_double_raw.json : le mapping conserve la précision des fractions : "$.speed": "${.velocity_kph / 1.609}".
    [
      {
        "description": "Double model: European metric units to miles per hour (mph); preserving fractional precision (no floor).",
        "condition": "${endpoint(3) == \"metric-units\"}",
        "payloadMapping": {
          "$.speed": "${.velocity_kph / 1.609}"
        },
        "referencePayload": {
          "dataFormat": "JSON",
          "data": { "velocity_kph": 110 }
        }
      },
      {
        "description": "Double model: USA standard units passthrough.",
        "condition": "*",
        "payloadMapping": { "$.speed": "$.speed" }
      }
    ]
  • routes_double_floor.json : le mapping se termine par un nombre entier de mph : "$.speed": "${(.velocity_kph / 1.609) | floor}" est stocké en tant que double.
    [
      {
        "description": "Double model: European metric units to miles per hour (mph); floor to whole number (stored as double).",
        "condition": "${endpoint(3) == \"metric-units\"}",
        "payloadMapping": {
          "$.speed": "${(.velocity_kph / 1.609) | floor}"
        },
        "referencePayload": {
          "dataFormat": "JSON",
          "data": { "velocity_kph": 110 }
        }
      },
      {
        "description": "Double model: USA standard units passthrough.",
        "condition": "*",
        "payloadMapping": { "$.speed": "$.speed" }
      }
    ]
    

Étape A : Créer le modèle de jumeau numérique en utilisant double

oci iot digital-twin-model create \
  --iot-domain-id iot-domain-ocid \
  --display-name "TestModelSpeedDouble" \
  --spec file://model_double.json

Etape B : création de deux adaptateurs associés au modèle double

Utilisez des valeurs brutes pour préserver la précision des fractions :

oci iot digital-twin-adapter create \
  --iot-domain-id iot-domain-ocid \
  --display-name "auto-adapter-double-raw" \
  --digital-twin-model-id double-model-ocid \
  --inbound-envelope file://envelope.json \
  --inbound-routes file://routes_double_raw.json

Floor utilise un nombre entier comme mph, c'est-à-dire un double :

oci iot digital-twin-adapter create \
  --iot-domain-id iot-domain-ocid \
  --display-name "auto-adapter-double-floor" \
  --digital-twin-model-id double-model-ocid \
  --inbound-envelope file://envelope.json \
  --inbound-routes file://routes_double_floor.json

Etape C : création d'instances de jumeaux numériques pour chaque adaptateur

oci iot digital-twin-instance create \
  --iot-domain-id iot-domain-ocid \
  --display-name "american-auto-raw" \
  --external-key american-auto-raw \
  --digital-twin-adapter-id adapter-double-raw-ocid \
  --auth-id vault-secret-ocid

oci iot digital-twin-instance create \
  --iot-domain-id iot-domain-ocid \
  --display-name "european-auto-raw" \
  --external-key european-auto-raw \
  --digital-twin-adapter-id adapter-double-raw-ocid \
  --auth-id vault-secret-ocid
oci iot digital-twin-instance create \
  --iot-domain-id iot-domain-ocid \
  --display-name "american-auto-dfloor" \
  --external-key american-auto-dfloor \
  --digital-twin-adapter-id adapter-double-floor-ocid \
  --auth-id vault-secret-ocid

oci iot digital-twin-instance create \
  --iot-domain-id iot-domain-ocid \
  --display-name "european-auto-dfloor" \
  --external-key european-auto-dfloor \
  --digital-twin-adapter-id adapter-double-floor-ocid \
  --auth-id vault-secret-ocid

Étape D : Post-échantillonnage de télémétrie et comparaison des résultats

Utilisez la clé externe et le mot de passe de l'appareil à partir de l'instance de jumeau numérique pour envoyer des données :
 -u "external-key:device-password" \
  • Si le jumeau numérique utilise une clé secrète de coffre pour s'authentifier, utilisez base64-secret comme mot de passe d'appareil.
  • Si l'instance de jumeau numérique utilise une certification mLTS, utilisez certificate-ocid comme mot de passe d'appareil.

Valeurs brutes (double, no floor) :

curl -i -X POST \
  -u "american-auto-raw:device-password" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/usa-standard-units" \
  -d '{ "speed": 60 }'

curl -i -X POST \
  -u "european-auto-raw:device-password" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/metric-units" \
  -d '{ "velocity_kph": 110 }'

Résultat attendu : le second message produit environ 68.35… mph (fractionnaire) et est accepté car schema=double accepte les nombres fractionnaires compris dans la plage.

Etage (double, avec étage) :

curl -i -X POST \
  -u "american-auto-dfloor:device-password" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/usa-standard-units" \
  -d '{ "speed": 60 }'

curl -i -X POST \
  -u "european-auto-dfloor:device-password" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/metric-units" \
  -d '{ "velocity_kph": 110 }'

Résultat attendu : le second message génère un nombre entier pour 68 et est accepté. La valeur est stockée en tant que valeur double, par exemple 68.0, même s'il s'agit d'un nombre entier.

Remarques sur les devis de nom d'utilisateur et leur impact en aval

  • La clé externe est égale au nom utilisateur d'authentification : si une instance de jumeau numérique est créée à l'aide de guillemets dans la valeur de clé externe, par exemple, "\"american-auto-standard-units\"", le nom utilisateur d'authentification de base dans votre demande curl doit inclure les guillemets, ou une non-concordance se produit et entraîne une erreur 401 Unauthorized. Pour éviter les problèmes de citation, il est recommandé de ne pas utiliser de guillemets dans votre valeur de clé externe comme dans les exemples de ce scénario.
  • En aval dans APEX ou à l'aide de SQL : avec schema=double, les valeurs mph fractionnaires sont conservées. Si vous avez besoin de nombres entiers dans les rapports, appliquez FLOOR et ROUND dans SQL, par exemple, SELECT FLOOR(speed) FROM …. Avec schema=integer, assurez-vous que le mapping émet des valeurs entières, par exemple, en utilisant floor pour satisfaire la saisie d'entiers.
  • Prise en charge de l'expression : inbound-route accepte l'arithmétique et floor. Les fonctions telles que toInteger ou number ont été rejetées et ne sont pas prises en charge. Utilisez floor ou adoptez schema: "double" pour une acceptation fractionnée.