Scénario : Normalisation des unités de mesure à l'aide d'un adaptateur Digital Twin

Ce scénario explique comment utiliser un modèle de jumeau numérique, un adaptateur jumeau numérique avec des mappages d'enveloppe et de route pour normaliser une télémétrie spécifique dans un schéma commun, et comment valider le flux en reportant des données utiles d'échantillons de périphériques.

Ce scénario montre comment publier des données de télémétrie automobile avec différentes unités de mesure en milles par heure et en kilomètres par heure à l'aide de différents points d'extrémité, 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, voir Référence : Expressions JQ pour les adaptateurs de jumeaux numériques.

Un adaptateur jumeau numérique achemine les demandes par point d'extrémité et cale les données utiles vers un seul modèle. Par exemple, un modèle de mesure envoie une vitesse en kilomètres par heure (velocity_kph) tandis qu'une autre instance de jumeau numérique standard envoie des milles par heure (speed).

Tâches

Comprenez les fichiers de 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 jumeau numérique basé sur les spécifications DTDL v3 avec une propriété de télémétrie speed en milles par heure qui utilise une extension de validation qui applique des limites sur l'intervalle de valeurs de 0 à 100.
  • envelope.json — Configuration d'enveloppe qui déclare un point d'extrémité de référence et un exemple de forme de données utiles.
  • routes.json — Conditions d'acheminement et mappages de charge utile qui convertissent les kilomètres par heure en milles 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, un adaptateur et des instances de jumeau numérique, plus les commandes curl pour effectuer l'auto-test de démarrage (POST) et l'exécuter en tant que script d'interpréteur de commandes 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 listées dans les étapes ci-dessous et exécuter ce scénario en tant que script d'interpréteur de commandes : script.sh

Cet exemple d'extrait 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 des 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, les données sont rejetées.

Pour obtenir la liste complète des règles de propriété de validation prises en charge, voir Informations de référence sur l'extension de validationDTMI.

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 listé ci-dessous contient 3 expressions qui transforment les kilomètres et normalise les données utiles en une unité de mesure, miles par heure :
  • Expression de condition qui évalue les données du point d'extrémité :

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

    La syntaxe ${ ... } indique une expression qui évalue la valeur du troisième paramètre de point d'extrémité ou élément de chemin dans un appel d'API endpoint(3). La condition compare la valeur retournée à metric-units. S'il est vrai, il applique ces règles.

  • Expression de mappage de données utiles :

    "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 vélocité des kilomètres à l'heure en milles à l'heure (.velocity_kph / 1.609). Cela divise le champ velocity_kph par 1.609, puis applique la fonction plancher, en arrondissant à l'entier le plus proche. Cette valeur provient de la conversion des kilomètres en miles qui est kilomètres = miles × 1,60934,

  • "payloadMapping": {"$.speed": "$.speed"} Il s'agit d'une expression de mappage 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 numérique double 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 numérique jumelé et qui utilise l'enveloppe entrante et les itinéraires 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

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 mi/h, et stocke le résultat.
  • Utilise une condition catch-all par défaut (*) pour passer par speed inchangé pour les automobiles qui utilisent des miles par heure.

Étape 3 : Créer deux instances de jumeau numérique

Créez deux instances de jumeau numérique qui s'authentifient à l'aide d'une clé secrète de chambre forte et qui partagent les deux instances de jumeau numérique partagent le même adaptateur de jumeau numérique. Les points d'extrémité sont définis de sorte que chaque instance de jumeau numérique puisse reporter des données vers un point d'extrémité unique :
  • Point d'extrémité pour mph : https://device-host/telemetry/automotive/usa-standard-units
  • Point d'extrémité pour km/h : https://device-host/telemetry/automotive/metric-units
Remplacez l'OCID de l'adaptateur jumeau numérique par celui 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.
Note

Lorsque vous créez une instance de jumeau numérique avec authentification, vous pouvez utiliser une clé secrète de chambre forte ou un certificat mTLS pour vous authentifier. Pour des raisons de sécurité, il est recommandé de créer une clé secrète de chambre forte 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 la même location que toutes les autres ressources IoT connexes.

Si vous utilisez un certificat mTLS pour l'authentification, vous devez utiliser le nom commun du certificat comme clé externe : --external-key <common-name-from-certificate-details>, voir Scénario : Créer une instance de jumeau numérique qui utilise un certificat mTLS.

Un administrateur doit ajouter la politique pour créer des clés secrètes ou des certificats. Voir Étape 3 dans Préalables.

Instance double numérique pour les unités standard des États-Unis, 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 jumeau numérique 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>

Étape 4 : Envoyer un exemple de télémétrie pour valider le routage et le mappage

Pour envoyer de 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 du point d'extrémité de l'hôte de l'appareil.

Si l'instance de jumeau numérique utilise la clé secrète de la chambre forte pour l'authentification, vous devez l'utiliser comme valeur de clé secrète encodée de base 64 comme mot de passe de l'appareil.

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

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

Note

Selon votre système d'exploitation ou votre application, certaines applications ou certains éditeurs de code peuvent ajouter des devis indésirables à vos valeurs, ce qui peut entraîner une erreur. Pour obtenir des exemples de soumissions, voir Dépannage.
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 }'

Étape 5 : Vérifier le comportement de la normalisation

La condition de routage ${endpoint(3) == "metric-units"} évalue les données et applique le mappage de données utiles suivant au point d'extrémité de données d'unités de mesure :

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

Résultat prévu :

  • Le mappage 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'arrondissement qui force le résultat à un nombre entier, arrondi vers l'infini négatif. Ceci 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, pas un float ou une chaîne.

  • velocity_kph = 110speed = floor(110 / 1.609) = 68 mi/h
  • Les publications de données standard avec speed passent inchangées, par exemple les valeurs de cet exemple : 0, 60

Si la validation du modèle est activée minimum: 0, maximum: 100, les valeurs hors limites sont rejetées en fonction des règles de validation.

Utilise la conversion de type flexible :

  • Pass-through (mph, schéma "integer") : {"speed": "60"} et {"speed": 60.0} sont stockés comme 60. {"speed": "60.2"} est rejeté sauf si le mappage est forcé à un entier (par exemple, avec floor).
  • Route de mesure (kph → mph) : {"velocity_kph": 110}68; {"velocity_kph": "110"}68 car le mappage floor émet un nombre entier. Gardez les entrées arithmétiques numériques pour éviter les erreurs d'expression; préférez 110 à "110" dans la mesure du possible.
  • L'arrondissement reste explicite : La conversion temporaire n'arrondit pas automatiquement 68.35 à 68. Utilisez floor pour le schéma entier ou passez au modèle schema: "double" pour conserver les fractions.

Meilleures pratiques

  • Fichiers JSON de référence pour les spécifications et les adaptateurs de modèle jumeau numérique : Lorsque vous chargez un adaptateur à l'aide de l'interface de ligne de commande, vous pouvez utiliser des fichiers JSON pour spécifier le mappage de données. Dans les commandes de l'interface de ligne de commande, vous pouvez référencer des fichiers en tant que file://~/name.json ou fournir un chemin absolu ou relatif en fonction de votre environnement d'interpréteur de commandes. 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. Voir Gestion de l'entrée et de la sortie de l'interface de ligne de commande et Utilisation d'un fichier JSON pour une entrée complexe.
  • Les fichiers de configuration JSON (enveloppe, routes) utilisent des noms de champ d'API dans camelCase (par exemple, referenceEndpoint). L'interface de ligne de commande OCI transmet ces fichiers sans modification au moyen des arguments file://. L'utilisation du JSON camelCase avec l'interface de ligne de commande est donc attendue et correcte.
  • referenceEndpoint dans envelope.json doit refléter un point d'extrémité standard pour votre adaptateur.
  • La condition de routage générique (*) est évaluée après des conditions spécifiques; commandez vos définitions de routage en conséquence.
  • Portée de conversion flexible : Les chaînes de type numérique et les doubles en nombres entiers sont acceptées lorsqu'elles correspondent au type de modèle (par exemple, entier). Les assistants de moulage tels que number() et toInteger ne sont pas pris en charge dans les expressions de routage; utilisez arithmétique et floor, ou adoptez schema: "double" pour conserver les fractions.

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

Cette variante montre comment le réglage du schéma de propriété de modèle à double affecte le mappage d'adaptateur et les valeurs enregistrées. Avec double, le valideur accepte toute valeur entière ou fractionnée numérique qui répond aux contraintes d'intervalle, sans arrondissement automatique. Vous pouvez choisir de conserver la précision fractionnelle (brut) ou de forcer les nombres entiers à l'aide de floor. Validation des deux réussites tant que les valeurs restent dans l'intervalle défini.

Ce que fait la validation schema=double

  • Acceptation de 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.
  • Intervalle : Les valeurs minimale et maximale, par exemple, 0–100 dans cet exemple, sont appliquées.
  • Aucun arrondissement automatique : La plate-forme IoT n'arrondit pas les valeurs. Vous contrôlez l'arrondissement dans le mappage d'adaptateur jumeau numérique ou en aval à l'aide d'APEX ou SQL, selon les systèmes configurés pour voir 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 mappage conserve la précision fractionnelle : "$.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 mappage est forcé au nombre entier mph : "$.speed": "${(.velocity_kph / 1.609) | floor}" 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 un modèle 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

Étape B : Créer deux adaptateurs associés au modèle double

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

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 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

Étape C : Créer des instances de jumeau numérique 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 échantillon de télémétrie et comparer les résultats

Utilisez la clé externe et le mot de passe de l'appareil de l'instance jumeau numérique pour envoyer des données :
 -u "external-key:device-password" \
  • Si le jumeau numérique utilise une clé secrète de chambre forte pour l'authentification, utilisez base64-secret comme mot de passe de l'appareil.
  • Si l'instance de jumeau numérique utilise une certification mLTS, utilisez certificate-ocid comme mot de passe de l'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 : La deuxième publication produit environ 68.35… mph (fractionnel) et est acceptée car schema=double accepte les nombres fractionnaires dans l'intervalle.

Étage (double, avec plancher) :

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 : La deuxième publication produit 68 un nombre entier et est accepté. La valeur est stockée en tant que double, par exemple 68.0, même s'il s'agit d'un nombre entier.

Notes sur les soumissions de nom d'utilisateur et l'incidence en aval

  • La clé externe est égale au nom d'utilisateur d'authentification : Si une instance de jumeau numérique est créée à l'aide de guillemets dans la valeur de la clé externe, par exemple "\"american-auto-standard-units\"", le nom d'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 soumission de devis, 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 MP fractionnaires sont conservées. Si vous avez besoin de nombres entiers dans les rapports, appliquez FLOOR et ROUND en SQL, par exemple SELECT FLOOR(speed) FROM …. Avec schema=integer, assurez-vous que le mappage émet des valeurs intégrales, par exemple, en utilisant floor pour satisfaire la saisie de nombres entiers.
  • Prise en charge des expressions : 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 fractionnaire.