Référence : Expressions JQ pour les adaptateurs Digital Twin

Modèles d'expression JQ pratiques pour les entrées de périphérique, les enveloppes d'adaptateur, les conditions de routage et les mappages de charge utile pour normaliser la télémétrie dans ce qui est défini dans les modèles jumeaux numériques.

Concepts clés

Vous pouvez écrire des expressions JQ dans un adaptateur jumeau numérique en tant que paramètres fictifs ${ ... } pour calculer les valeurs cibles dans payload-mapping et évaluer les conditions de routage.

Méthodes courantes pour utiliser des expressions JQ :

  • Entrée de l'appareil : Données utiles brutes publiées par les appareils.
  • Enveloppe : Déclare des points d'extrémité de référence et des exemples de formes de données utiles. Par exemple, vous pouvez définir un mappage timeObserved.
  • Routes : Évaluez les conditions, notamment les points d'extrémité, les en-têtes, le corps, et sélectionnez un mappage de données utiles.
  • Mappages de données utiles : Transformer, convertir des unités, renommer des clés et normaliser le schéma de modèle DTDL.
  • Sortie : Sortie JSON normalisée qui doit satisfaire à la validation du modèle jumeau numérique, y compris les types, les intervalles et les unités.
  • Prise en charge des fonctions de mappage : Les fonctions arithmétiques et floor sont acceptées. Les fonctions telles que toInteger et number ne sont pas prises en charge.
  • Correspondance de point d'extrémité : Utilise des conditions basées sur des segments avec endpoint(n), par exemple : ${endpoint(1) == 'home' and endpoint(2) == 'sonnen' and endpoint(3) == 'status'} au lieu de modèles génériques non pris en charge.
  • Entier par rapport au schéma double :
    • Pour schema: "integer", assurez-vous que votre mappage émet des chiffres intégraux (par exemple, "${(.velocity_kph / 1.609) | floor}").
    • Pour schema: "double", les sorties fractionnaires sont acceptées; utilisez floor uniquement si vous voulez un stockage en nombre entier comme double, par exemple 68.0.
  • Type 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, un 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.
    • 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 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.
  • Traitement des enveloppes et du temps : Si timeObserved n'est pas fourni, la plate-forme peut utiliser receivedTime. Utilisez fromdateformat, todateformat et les fonctions connexes pour les conversions de temps dans les mappages d'enveloppe ou de données utiles.
Note

La validation des données est effectuée par rapport à votre modèle DTDL. Si une propriété est déclarée en tant que integer, la sortie normalisée doit être une valeur integer, et non string ou float. Voir le modèle de correction d'entier ci-dessous.

Pour plus d'informations, voir Informations de référence sur l'extension de validation DTMI.

Exemples d'entrée d'appareil

Données utiles entrantes typiques avec des schémas spécifiques à l'unité :

Unités américaines standard miles par heure :

{
  "speed": 60
}

Unités métriques européennes en kilomètres par heure :

{
  "velocity_kph": 110
}

Charge utile imbriquée à partir d'un capteur :

{
  "telemetry": { "temp_c": 22.4, "humidity": 48 }
}

Tableau d'échantillons :

{
  "samples": [ { "kph": 30 }, { "kph": 50 }, { "kph": 0 } ]
}

Ces exemples montrent un modèle DTDL où la température est un nombre entier compris entre 0 et 100 et l'humidité est facultative.

Lorsque les deux valeurs sont présentes et que la température est comprise dans l'intervalle autorisé et du type correct, elle est valide et la valeur d'entrée complète est ingérée :
{ "temperature": 60, "humidity": 45 }
Lorsqu'une valeur est absente, seules les données valides sont ingérées. Dans cet exemple, la température est manquante, de sorte que l'humidité est ingérée et que la valeur de température n'est pas mise à jour.
{
"humidity": 45
}
Lorsqu'une valeur est nul, elle est ignorée et seule la valeur valide est ingérée :
{
		“temperature”: null
 		“humidity”: 45
	}

Mappage d'enveloppe

envelope.json déclare une valeur referenceEndpoint et une valeur referencePayload. Facultativement, un mappage d'enveloppe peut définir time-observed :

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

L'identificateur spécial receivedTime peut être fourni par la plate-forme lorsque l'appareil omet time. Si le mappage d'enveloppe est spécifié et contient une valeur timeObserved, receivedTime est utilisé en tant que valeur timeObserved.

Modèles de condition de routage

Les conditions de routage sont des règles ou expressions utilisées pour déterminer quelle règle de mappage ou de traitement doit être appliquée à un message ou à une demande entrant. Si une condition de routage est vraie, la règle de mappage ou de transformation associée est déclenchée et appliquée.

Dans cet exemple, la condition de routage de l'adaptateur jumeau numérique définit deux routes pour le traitement des messages d'appareil entrants, en fonction du format des données, par exemple si des unités de mesure sont reçues sur le 3e segment du chemin du point d'extrémité, /vehicle/speed/metric-units/, puis

[
  {
    "description": "European metric to mph; convert then floor (no explicit cast).",
    "condition": "${endpoint(3) == \"metric-units\"}",
    "payloadMapping": {
      "$.speed": "${(.velocity_kph / 1.609) | floor}"
    },
    "referencePayload": {
      "dataFormat": "JSON",
      "data": { "velocity_kph": 104 }
    }
  },
  {
    "description": "USA standard units passthrough.",
    "condition": "*",
    "payloadMapping": { "$.speed": "$.speed" }
  }
]
  • endpoint(n) sélectionne le segment de chemin n-th (basé sur 0 ou 1 selon l'adaptateur). Dans le scénario de normalisation des unités de mesure, endpoint(3) est utilisé pour que /vehicle/speed/metric-units/ corresponde au troisième segment metric-units.
  • Placez des conditions plus spécifiques avant le "*" catch-all.
  • payloadMapping:
    • Prend le champ velocity_kph vitesse en kilomètres par heure de la charge utile, et le convertit en miles par heure : .velocity_kph / 1.609
    • Applique floor pour arrondir à l'entier inférieur le plus proche floor n'est pas lancé. Le résultat peut donc être un nombre à virgule flottante.
    • Le résultat est affecté au champ de sortie speed.
  • referencePayload:
    • Indique l'entrée attendue pour cette route : {"velocity_kph": 104}
  • Point d'extrémité d'entrée : /vehicle/speed/metric-units/device123
  • Données utiles d'entrée : { "velocity_kph": 104 } Mappage de sortie : { "speed": 64 } (since 104 / 1.609 = 64.64, floor is 64)

Exemples de mappage de données utiles

Expressions JQ communes pour les mappages de données utiles :

  • Transmission directe : "$.speed": "$.speed"
  • Renommer la clé : "$.speed": "${.velocity_kph}"
  • Conversion d'unité : "$.mph": "${.kph / 1.609}"
  • Plancher/plafond/rond : "${.x | floor}", "${.x | ceil}", "${.x | round}"
  • Coalesce/par défaut (dépendant de la version) : "${ if .value? then .value else 0 end }"
  • Conversion de type :
    • À numéro : "${.value | tonumber}" (prend en charge tonumber dans la plupart des versions)
    • À la chaîne : "${.value | tostring}"
    Note

    Dans un adaptateur jumeau numérique IoT, les fonctions de casting telles que toInteger ou number ne sont pas acceptées dans inbound-routes. Vous pouvez utiliser l'arithmétique avec floor défini pour un schéma entier ou utiliser schema: "double" et les formats d'arrondissement pour l'ingestion de données en aval. inbound-routes doit être un format JSON valide; les expressions appartiennent aux chaînes entre guillemets "${ ... }".
  • Extraction imbriquée : "${.telemetry.temp_c}"
  • Mappage de tableau : "${[ .samples[] | .kph / 1.609 | floor ]}"
  • Conditionnel : "${ if .kph > 0 then .kph / 1.609 else 0 end }"
Note

Selon l'intégration de votre adaptateur, les expressions entre guillemets "${...}" peuvent être sérialisées en tant que chaînes. Lorsque le moteur prend en charge les expressions sans guillemets, par exemple ${...} en tant que valeur brute, il est recommandé que le formulaire émette un nombre JSON plutôt qu'une chaîne.

Nuances : Types d'entiers, chaînes et nombres calculés

Lorsqu'une propriété DTDL est schema: "integer", la sortie normalisée doit être de type entier. Deux modes de défaillance courants lors du calcul des valeurs :

  1. Stringification : Une expression encapsulée entre guillemets peut générer "68" (chaîne), échec de la validation d'entiers.
  2. Nombres de type flottant : L'arithmétique produit 68.0; certains valideurs traitent cela comme un non-entier, même s'il est mathématiquement intégral.

Corriger les modèles :

  • Utiliser l'étage seulement pour le schéma de nombres entiers : "${(.velocity_kph / 1.609) | floor}" pour produire une valeur numérique intégrale qui satisfait le type de nombre entier.
  • Autre : Remplacez la propriété de modèle par schema: "double" pour conserver la précision fractionnelle, ou appliquez floor au mappage tout en stockant un nombre entier en tant que double. Arrondir/formater dans APEX/SQL, si nécessaire.

Exemples de mappage d'adaptateur de jumeau numérique

Cet exemple normalise les kilomètres par heure (KPH) en miles par heure (MPH) à l'aide de floor (pas de distribution).

{
  "description": "European auto uses metric units; convert to mph and floor to whole number.",
  "condition": "${endpoint(3) == \"metric-units\"}",
  "payloadMapping": {
    "$.speed": "${(.velocity_kph / 1.609) | floor}"
  },
  "referencePayload": {
    "dataFormat": "JSON",
    "data": { "velocity_kph": 104 }
  }
}

Exemple : Passage par rattrapage par défaut

{
  "description": "English units passthrough.",
  "condition": "*",
  "payloadMapping": {
    "$.speed": "$.speed"
  }
}

Exemple : télémétrie imbriquée et coalescence par défaut

{
  "description": "Extract nested temp; default to 0 when missing.",
  "condition": "${endpoint(2) == \"env\"}",
  "payload-mapping": {
    "$.room_temp_c": "${ if .telemetry.temp_c? then .telemetry.temp_c else 0 end }"
  }
}

Exemple : normalisation d'un tableau

{
  "description": "Normalize kph samples to mph (whole-number mph via floor).",
  "condition": "${.samples?}",
  "payload-mapping": {
    "$.speeds": "${ [ .samples[] | .kph / 1.609 | floor ] }"
  }
}

Attentes de sortie par rapport à la validation de modèle

Les sorties doivent satisfaire les schémas et contraintes du modèle jumeau numérique. Pour le modèle d'unité automobile dans model.json, voir Scénario : Normalisation des unités de mesure à l'aide d'un adaptateur de jumeau numérique :

  • name: speed
  • schema: integer
  • unit: milePerHour
  • minimum: 0, maximum: 100

speed normalisé doit être un nombre entier compris dans 0,100. La validation d'une chaîne calculée "68" ou d'un nombre à virgule flottante 68.0 échouera.

Limites et conseils

  • La disponibilité du filtre varie : Filtres jq les plus importants (floor, ceil, round, tonumber, tostring, map, select, add)
  • Type émission : Les expressions intégrées dans des chaînes entre guillemets peuvent sérialiser en tant que chaînes. Préférez les expressions brutes sans guillemets si elles sont prises en charge pour émettre des types numériques.
  • Traitement nul : Les opérations sur null peuvent produire null. Utilisez if .x? then ... else ... end pour les valeurs par défaut.
  • Précision : L'arithmétique de point flottant peut introduire des artefacts d'arrondissement; appliquez round et floor selon les besoins avant le moulage.
  • Entier coulé : Dans les tests observés, toInteger et number n'ont pas été acceptés dans inbound-routes lors de la création de l'adaptateur. Préférez arithmétique + floor pour le schéma entier ou utilisez schema: "double" et arrondissez le format en aval.

Application du correctif de nombre entier au scénario automobile

Le scénario crée un modèle avec un nombre entier speed et achemine les données utiles d'unité de mesure vers le même modèle jumeau numérique. Sans casting explicite, la valeur calculée peut être rejetée par validation en raison de la dérive de type (chaîne ou nombre flottant).

Correctif utilisé dans le scénario :

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

Pourquoi il est nécessaire :

  • Le plancher garantit que la valeur est entièrement numérique, d'après le type de nombre entier.
  • Alternative : utilisez schema: "double" pour préserver la précision fractionnaire et arrondir et formater en aval si nécessaire.
Note

Lors de l'utilisation d'un schéma entier, préférez arithmétique plus floor. Pour le double schéma, vous pouvez omettre floor pour conserver le MPH fractionnaire ou l'inclure pour stocker un nombre entier MPH en tant que double.

Extraits de référence rapides

Exemples pris en charge :

  • Condition : Correspondance de point d'extrémité : "condition": "${endpoint(3) == \"metric-units\"}"
  • Mappage : Transfert : "$.speed": "$.speed"
  • Mappage : kph → mph (schéma entier) : "$.speed": "${(.kph / 1.609) | floor}"
  • Mappage : imbriqué : "$.room_temp_c": "${.telemetry.temp_c}"
  • Mappage : Par défaut : "$.value": "${ if .value? then .value else 0 end }"
  • Transformation Tableau : "$.list": "${ [ .arr[] | .x | tonumber ] }"

Comportement des nombres entiers par rapport aux modèles doubles

La présente section résume l'incidence du type de schéma de modèle sur le mappage et la validation des adaptateurs.

  • schéma : "entier"
    • Type : Doit être un nombre entier JSON intégral. Les chaînes telles que 68 ou les résultats de type flottant 68.0 peuvent échouer la validation des nombres entiers.
    • Mappage : L'arithmétique est autorisée; floor est pris en charge. Les fonctions telles que toInteger et number ne sont pas prises en charge.
    • Modèle : Utilisez "${(.velocity_kph / 1.609) | floor}" pour forcer l'intégration de MPH. Cette validation et cette télémétrie réussies ont été acceptées HTTP 202.
    • Intervalle : Les valeurs minimale et maximale sont appliquées, par exemple 0–100
  • schema: "double"
    • Type : Tout nombre entier ou fractionnaire JSON est accepté dans l'intervalle; aucun arrondissement automatique n'est effectué par la plate-forme.
    • Mappage : Vous pouvez conserver la précision fractionnelle, par exemple "${.velocity_kph / 1.609}", ou appliquer également floor pour produire un nombre entier MPH stocké en tant que double, par exemple : 68.0
    • Intervalle : S'il est défini, minimum et maximum appliqués, par exemple : 0–100

Résultats de télémétrie observés

Les combinaisons suivantes ont été validées de bout en bout (HTTP/1.1 202 Accepted) :

  • Modèle entier + mappage d'étage : "${(.velocity_kph / 1.609) | floor}" → accepté
  • Modèle double + mappage brut : "${.velocity_kph / 1.609}" → mph fractionnaire accepté
  • Mappage double modèle + plancher : "${(.velocity_kph / 1.609) | floor}" → nombre entier mph accepté et stocké en tant que double

Exemple de boucle (paramètres fictifs)

Modèle double, valeur brute qui est fractionnaire mi/h comme prévu :

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

Double modèle, plancher un nombre entier MPH, qui est stocké comme double :

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

Réponse HTTP attendue pour chaque cas :

HTTP/1.1 202 Accepted
content-type: text/plain

Accepted

En aval dans APEX ou considérations SQL

  • Avec le double, la vitesse fractionnelle est conservée. Utilisez SQL FLOOR/ROUND pour l'affichage des nombres entiers :
    SELECT FLOOR(speed) AS speed_mph FROM ...
  • Avec un entier, assurez-vous que le mappage retourne des valeurs intégrales (par exemple, au moyen de floor) pour satisfaire la validation.

Nom d'utilisateur et devis de l'autorisation

Dans OCI IoT, l'utilisation du nom d'utilisateur d'authentification de base est égale à l'instance external-key. Si l'instance est créée avec des guillemets intégrés dans la clé externe, ces guillemets font partie du nom d'utilisateur requis et doivent être envoyés littéralement. Cela provoque souvent des problèmes de citation de shell.

Meilleure pratique : Créez des instances de jumeau numérique avec des clés externes qui ne contiennent pas de guillemets. Par exemple, american-auto Lorsque vous devez vous authentifier avec des noms d'utilisateur entre guillemets, créez un en-tête Authorization: Basic ... au lieu d'utiliser -u pour éviter les erreurs de soumission.