Référence : JQ Expressions for Digital Twin Adapters
Modèles d'expression JQ pratiques pour les entrées d'appareil, les enveloppes d'adaptateur, les conditions de routage et les mappages de charge utile afin de normaliser la télémétrie dans ce qui est défini dans les modèles de jumeaux numériques.
Concepts-clés
Vous pouvez écrire des expressions JQ dans un adaptateur jumeau numérique en tant qu'espaces réservés ${ ... } pour calculer les valeurs cible dans payload-mapping et évaluer les conditions de routage.
Méthodes courantes d'utilisation des expressions JQ :
- Entrée de périphérique : charges utiles brutes publiées par les périphériques.
- Enveloppe : déclare des adresses de référence et des exemples de formes de charge utile, par exemple, vous pouvez définir un mapping
timeObserved. - Routages : évaluez les conditions, notamment les adresses, les en-têtes et le corps, et sélectionnez un mapping de charge utile.
- Mappages de charge utile : transformez, convertissez des unités, renommez des clés et normalisez-les dans 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 plages et les unités.
- Prise en charge des fonctions de mise en correspondance : les fonctions arithmétiques et
floorsont acceptées. Les fonctions telles quetoIntegeretnumberne sont pas prises en charge. - Correspondance d'adresse : utilise des conditions basées sur les 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. - Schéma entier ou double :
- Pour
schema: "integer", assurez-vous que le mapping émet des chiffres entiers (par exemple,"${(.velocity_kph / 1.609) | floor}"). - Pour
schema: "double", les sorties fractionnées sont acceptées. Utilisezflooruniquement si vous voulez que le stockage en nombre entier soit double, par exemple 68.0.
- Pour
- Type de conversion standard : les chaînes de type numérique et les doubles de nombres entiers sont acceptées lorsqu'elles correspondent au type de modèle (par exemple, entier). Les aides de conversion de type telles que
number()ettoIntegerne sont pas prises en charge dans les expressions de routage. Utilisez l'arithmétique etfloorou adoptezschema: "double"pour préserver les fractions.- Pass-through (mph, schéma "integer") :
{"speed": "60"}et{"speed": 60.0}sont stockés en tant que60.{"speed": "60.2"}est rejeté sauf si la mise en correspondance est contrainte à un entier, par exemple, avecfloor. - Route de mesure (kph → mph) :
{"velocity_kph": 110}→68;{"velocity_kph": "110"}→68car le mappingfloorémet un entier. Conservez des entrées arithmétiques numériques pour éviter les erreurs d'expression. Dans la mesure du possible, préférez110à"110". - L'arrondi reste explicite : la conversion temporaire n'arrondi pas automatiquement
68.35à68. Utilisezfloorpour le schéma d'entiers ou basculez le modèle surschema: "double"pour conserver les fractions.
- Pass-through (mph, schéma "integer") :
- Gestion de l'enveloppe et du temps : si
timeObservedn'est pas fourni, la plate-forme peut utiliserreceivedTime. Utilisezfromdateformat,todateformatet les fonctions associées pour les conversions de temps dans les mappings d'enveloppe ou de charge utile.
La validation des données se produit par rapport à votre modèle DTDL. Si une propriété est déclarée comme
integer, la sortie normalisée doit être une valeur integer, et non une valeur string ou float. Voir le modèle de correction d'entier ci-dessous.Pour plus d'informations, voir Référence d'extension de validation DTMI
Exemples d'entrée de périphérique
Charge utile entrante standard avec des schémas spécifiques à une unité :
Unités américaines standard miles par heure :
{
"speed": 60
}Unités métriques européennes kilomètres par heure :
{
"velocity_kph": 110
}
Charge utile imbriquée 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 où l'humidité est facultative.
{ "temperature": 60, "humidity": 45 }{
"humidity": 45
}{
“temperature”: null
“humidity”: 45
}Mappage d'enveloppe
La valeur envelope.json déclare une valeur referenceEndpoint et une valeur referencePayload. Un mapping d'enveloppe peut éventuellement définir time-observed :
{
"referenceEndpoint": "telemetry/automotive/standard",
"referencePayload": {
"dataFormat": "JSON",
"data": { "speed": 65 }
}
}
L'identificateur spécial
receivedTime peut être fourni par la plate-forme lorsque le périphérique omet time. Si le mapping d'enveloppe est spécifié et contient une valeur timeObserved, receivedTime est utilisé comme valeur timeObserved. Modèles de condition de routage
Les conditions de routage sont des règles ou des expressions utilisées pour déterminer quelle règle de mapping ou de traitement doit être appliquée à un message ou une demande entrant. Si une condition de routage renvoie la valeur True, la règle de mapping ou de transformation associée est déclenchée et appliquée.
Dans cet exemple, la condition de routage digital twin adapter définit deux routes pour le traitement des messages de périphérique 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 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 cheminn-th(basé sur 0 ou 1 en fonction de l'adaptateur). Dans le scénario de normalisation des unités de mesure,endpoint(3)est utilisé de sorte que/vehicle/speed/metric-units/corresponde au troisième segmentmetric-units.- Placez des conditions plus spécifiques avant le processus catch-all
"*". payloadMapping:- Prend la vitesse du champ
velocity_kphen kilomètres par heure à partir de la charge utile et la convertit en miles par heure :.velocity_kph / 1.609 - Applique
floorpour arrondir à l'entier inférieur le plus proche ;floorn'est pas converti. Le résultat peut donc être une virgule flottante. - Le résultat est affecté au champ de sortie
speed.
- Prend la vitesse du champ
referencePayload:- Présente l'entrée attendue pour ce routage :
{"velocity_kph": 104}
- Présente l'entrée attendue pour ce routage :
- Adresse d'entrée :
/vehicle/speed/metric-units/device123 - Charge utile d'entrée :
{ "velocity_kph": 104 }Mapping de sortie :{ "speed": 64 } (since 104 / 1.609 = 64.64, floor is 64)
Exemples de mappage de charge utile
Expressions JQ courantes pour les mappings de charge utile :
- Transmission :
"$.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/default (dépendant de la version) :
"${ if .value? then .value else 0 end }" - Conversion de type:
- Pour numéroter :
"${.value | tonumber}"(prend en chargetonumberdans la plupart des builds) - Chaîne de destination :
"${.value | tostring}"
Remarque
Dans un adaptateur jumeau numérique IoT, les fonctions de conversion de typetoIntegerounumberne sont pas acceptées dansinbound-routes. Vous pouvez utiliser l'arithmétique avecfloordéfini pour un schéma d'entier ou utiliserschema: "double"et les formats d'arrondi pour l'inclusion de données en aval.inbound-routesdoit être un format JSON valide ; les expressions appartiennent à des chaînes entre guillemets"${ ... }". - Pour numéroter :
- Extraction imbriquée :
"${.telemetry.temp_c}" - Carte de tableau :
"${[ .samples[] | .kph / 1.609 | floor ]}" - Conditionnel :
"${ if .kph > 0 then .kph / 1.609 else 0 end }"
Selon l'intégration de l'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 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 :
- Stringification : une expression encapsulée entre guillemets peut produire
"68"(chaîne), échec de la validation d'entier. - Nombre flottant : l'arithmétique produit
68.0; certains validateurs le considèrent comme non entier, même s'il est mathématiquement entier.
Corriger les modèles :
- Utiliser le plancher uniquement pour le schéma d'entiers :
"${(.velocity_kph / 1.609) | floor}"pour produire une valeur numérique intégrale qui satisfait à la saisie d'entiers. - Autre : basculez la propriété de modèle sur
schema: "double"pour préserver la précision des fractions, ou appliquezfloordans le mapping tout en stockant un nombre entier sous forme de double. Arrondir/format dans APEX/SQL si nécessaire.
Exemples de mapping 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 conversion).
{
"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 : Passthrough catch-all par défaut
{
"description": "English units passthrough.",
"condition": "*",
"payloadMapping": {
"$.speed": "$.speed"
}
}
Exemple : télémétrie imbriquée et fusion 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 de 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 du modèle
Les sorties doivent satisfaire les schémas et les contraintes du modèle jumeau numérique. Pour le modèle d'unité automobile dans model.json, reportez-vous à Scénario : normalisation des unités de mesure à l'aide d'un adaptateur jumeau numérique :
name:speedschema:integerunit:milePerHourminimum:0,maximum:100
La valeur speed normalisée doit être un entier compris dans 0,100. La validation d'une chaîne calculée "68" ou d'un nombre flottant 68.0 échouera.
Limites et conseils
- La disponibilité des filtres varie : la plupart des filtres jq principaux (
floor,ceil,round,tonumber,tostring,map,select,add) - Emission de type : les expressions imbriquées dans des chaînes entre guillemets peuvent être sérialisées 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.
- Gestion nulle : les opérations effectuées sur
nullpeuvent produirenull. Utilisezif .x? then ... else ... endpour les valeurs défensives par défaut. - Précision : l'arithmétique à virgule flottante peut introduire des artefacts d'arrondi ; appliquez
roundetfloorselon vos besoins avant la conversion. - Entier converti : dans les tests observés,
toIntegeretnumbern'ont pas été acceptés dansinbound-routesau moment de la création de l'adaptateur. Préférez arithmétique +floorpour le schéma d'entiers ou utilisezschema: "double"et arrondissez le format en aval.
Application de la correction d'entier au scénario automobile
Le scénario crée un modèle avec un entier speed et achemine les charges utiles d'unité de mesure vers le même modèle de jumeau numérique. Sans conversion explicite, la valeur calculée peut être rejetée par la validation en raison d'une dérive de type (chaîne ou nombre de type float).
Correctif utilisé dans le scénario :
"$.speed": "${(.velocity_kph / 1.609) | floor}"
Pourquoi est-ce nécessaire ?
- floor garantit que la valeur est entièrement numérotée, en respectant la saisie d'entiers.
- Alternative : utilisez
schema: "double"pour préserver la précision fractionnée et arrondir et formater en aval si nécessaire.
Lors de l'utilisation d'un schéma d'entiers, préférez l'arithmétique plus
floor. Pour le schéma double, vous pouvez omettre floor pour conserver la MPH fractionnaire ou l'inclure pour stocker un nombre entier MPH en tant que double.Extraits de référence rapide
Exemples pris en charge :
- Condition : correspondance d'adresse :
"condition": "${endpoint(3) == \"metric-units\"}" - Mise en correspondance : transmission :
"$.speed": "$.speed" - Mappage : kph → mph (schéma entier) :
"$.speed": "${(.kph / 1.609) | floor}" - Mise en correspondance : imbriquée :
"$.room_temp_c": "${.telemetry.temp_c}" - Mappage : valeur par défaut :
"$.value": "${ if .value? then .value else 0 end }" - Transformation de tableau :
"$.list": "${ [ .arr[] | .x | tonumber ] }"
Comportement d'entier ou de modèle double
Cette section récapitule l'impact du type de schéma de modèle sur la mise en correspondance et la validation des adaptateurs.
- schéma : "entier"
- Type : doit être un nombre entier JSON entier. Les chaînes telles que
68ou les résultats de type float68.0peuvent échouer à la validation des entiers. - Mise en correspondance : l'arithmétique est autorisée ;
floorest pris en charge. Les fonctions telles quetoIntegeretnumberne sont pas prises en charge. - Modèle : utilisez
"${(.velocity_kph / 1.609) | floor}"pour forcer la MPH intégrale. La validation a réussi et la télémétrie a été acceptéeHTTP 202. - Plage : les valeurs minimum et maximum sont appliquées, par exemple,
0–100
- Type : doit être un nombre entier JSON entier. Les chaînes telles que
schema: "double"- Type : tout entier ou fractionnaire de nombre JSON est accepté s'il est compris dans la plage ; aucun arrondi automatique n'est effectué par la plate-forme.
- Correspondance : vous pouvez conserver une précision fractionnée, par exemple
"${.velocity_kph / 1.609}", ou appliquer égalementfloorpour produire un nombre entier de MPH stocké en double, par exemple :68.0 - Plage : si défini, minimum et maximum appliqué, 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 d'entier + mappage du plancher :
"${(.velocity_kph / 1.609) | floor}"→ accepté - Modèle double + mappage brut :
"${.velocity_kph / 1.609}"→ mph fractionnaire accepté - Mappage du double modèle + du plancher :
"${(.velocity_kph / 1.609) | floor}"→ nombre entier mph accepté et stocké en double
Exemple de boucle (espaces réservés)
Modèle double, valeur brute correspondant à la valeur mph fractionnaire attendue :
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
Considérations en aval dans APEX ou SQL
- Avec double, la vitesse fractionnaire est préservée. Utilisez SQL
FLOOR/ROUNDpour l'affichage des nombres entiers :SELECT FLOOR(speed) AS speed_mph FROM ... - Avec integer, assurez-vous que la mise en correspondance génère des valeurs entières (par exemple, via
floor) pour satisfaire la validation.
Nom utilisateur et devis d'autorisation
Dans OCI IoT, l'utilisation du nom 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 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 n'incluent pas de guillemets, par exemple, american-auto. Lorsque vous devez vous authentifier avec des noms utilisateur entre guillemets, créez un en-tête Authorization: Basic ... plutôt que d'utiliser -u pour éviter les erreurs de citation.