Scenario: normalizzazione delle unità di misura mediante un adattatore Digital Twin

Questo scenario spiega come utilizzare un modello digital twin, un adattatore digital twin con mapping di envelope e instradamento per normalizzare una telemetria specifica in uno schema comune e come convalidare il flusso pubblicando payload di dispositivi di esempio.

Questo scenario dimostra come pubblicare i dati di telemetria automobilistica con diverse unità di misura per miglia all'ora e chilometri all'ora utilizzando endpoint diversi, due istanze gemelle digitali e due chiavi esterne diverse. Per ulteriori informazioni sui pattern JQ a cui viene fatto riferimento in questo scenario, vedere Riferimento: Espressioni JQ per adattatori gemelli digitali

Un adattatore digital twin installa le richieste in base all'endpoint e mappa i payload in un singolo modello. Ad esempio, il modello di metrica invia la velocità in chilometri orari (velocity_kph) mentre un'altra istanza gemella digitale standard invia miglia all'ora (speed).

Task

Comprendere i file in questo scenario:

Frammenti di codice che puoi utilizzare nel tuo modello gemello digitale a cui si fa riferimento nei passaggi seguenti:

  • model.json: modello gemello digitale basato sulle specifiche DTDL v3 con una proprietà di telemetria speed in miglia all'ora che utilizza un'estensione di convalida che applica limiti all'intervallo di valori compreso tra 0 e 100.
  • envelope.json: configurazione dell'envelope che dichiara un endpoint di riferimento e una forma di payload di esempio.
  • routes.json: condizioni di percorso e mappature del payload che convertono chilometri all'ora in miglia all'ora.
  • script.sh: in questo esempio, è possibile salvare tutti i comandi CLI OCI elencati di seguito per creare un modello gemello digitale, un adattatore e istanze, oltre ai comandi curl nella telemetria di esempio POST, quindi eseguirli come script shell script.sh.
  • Per completare i passi di questo scenario, è possibile creare e salvare l'interfaccia CLI OCI e i comandi curl elencati nei passi riportati di seguito e eseguire questo scenario come script della shell: script.sh

Questo snippet di codice model.json del modello digital twin di esempio utilizza un'estensione personalizzata dtmi:com:oracle:dtdl:extension:validation;1 che applica le regole di convalida allo schema JSON per gli elementi "Telemetry", "Historized", "Validated", "Velocity". Se i dati non corrispondono ai valori previsti definiti in questa convalida, i dati vengono rifiutati.

Per un elenco completo delle regole delle proprietà di convalida supportate, vedere Riferimento estensione convalida 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
    }
  }
}

Questo file routes.json elencato di seguito contiene 3 espressioni che trasformano i chilometri e normalizzano il payload dei dati in un'unità di misura, miglia all'ora:
  • Espressione di condizione che valuta i dati dall'endpoint:

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

    La sintassi ${ ... } indica un'espressione che valuta il valore del terzo parametro endpoint o elemento percorso in una chiamata API endpoint(3). La condizione confronta il valore restituito con metric-units. Se è vero, allora applica queste regole.

  • Espressione mapping payload:

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

    La sintassi ${ ... } indica un'espressione, questa espressione valuta ed esegue un calcolo aritmetico per convertire la velocità da chilometri all'ora a miglia all'ora (.velocity_kph / 1.609), dividendo il campo velocity_kph per 1.609 e quindi applicando la funzione floor, arrotondando per difetto all'intero più vicino. Questo valore deriva dalla conversione di chilometri in miglia che è chilometri = miglia × 1.60934,

  • "payloadMapping": {"$.speed": "$.speed"} Si tratta di un'espressione di mapping di valore diretto che passa attraverso il valore della velocità così com'è.
[
  {
    "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" }
  }
]

Passo 1: Creare un modello Digital Twin

Utilizzare questo comando CLI oci iot digital-twin-model create per creare un modello gemello digitale utilizzando il file model.json. Questo modello digital twin standardizza speed in miglia all'ora.

Questo comando registra il modello digital twin con questo URI DTMI dtmi:com:oracle:iot:poc:testmodel;1 come definito nella menzione model.json sopra riportata.

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

Passaggio 2: creare un adattatore Digital Twin con busta e percorsi

Creare un adattatore che faccia riferimento alla specifica DTMI del modello gemello digitale e che utilizzi l'inviluppo e gli instradamenti in entrata per normalizzare la telemetria in entrata.

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 in envelope.json è telemetry/automotive/usa-standard-units. Il file routes.json:

  • Esegue l'instradamento delle richieste al terzo segmento di percorso che equivale a metric-units, ad esempio /telemetry/automotive/metric-units, quindi converte velocity_kph in speed in mph e ne pianifica il risultato.
  • Utilizza una condizione predefinita di catch-all (*) per passare attraverso speed invariato per le automobili che utilizzano miglia all'ora.

Passo 3: Creare due istanze Digital Twin

Creare due istanze digital twin che si autenticano utilizzando un vault segreto e condividere entrambe le istanze digital twin condividendo lo stesso adattatore digital twin. Gli endpoint sono definiti in modo che ogni istanza digital twin possa inviare i dati a un endpoint univoco:
  • Endpoint per mph: https://device-host/telemetry/automotive/usa-standard-units
  • Endpoint per kph: https://device-host/telemetry/automotive/metric-units
Sostituire l'OCID dell'adattatore digital twin con l'OCID dell'adattatore digital twin creato nel passo precedente. Sostituire i nomi visualizzati e le chiavi esterne con i valori per l'ambiente in uso.
Nota

Quando si creano un'istanza gemella digitale con l'autenticazione, è possibile utilizzare un segreto vault o un certificato mTLS per l'autenticazione. Per motivi di sicurezza, è consigliabile creare un segreto vault o un certificato mTLS univoco per ogni istanza digital twin. Tutte le risorse devono trovarsi nella stessa area e tenancy di qualsiasi altra risorsa IoT correlata.

Se si utilizza un certificato mTLS per l'autenticazione, è necessario utilizzare il nome comune del certificato come chiave esterna: --external-key <common-name-from-certificate-details>. Vedere Scenario: Create a Digital Twin Instance that using a mTLS Certificate.

Un amministratore deve aggiungere il criterio per la creazione di segreti o certificati. Vedere il Passo 3 in Prerequisiti.

Istanza digital twin per unità standard USA, miglia all'ora (mph), nota la chiave esterna:

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>
Istanza gemella digitale per le unità metriche europee, chilometri all'ora (kph), nota la chiave esterna:

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>

Passo 4: inviare la telemetria di esempio per convalidare l'instradamento e il mapping

Per inviare la telemetria è necessaria la chiave esterna della risposta dell'istanza gemella digitale dal passo 3, dalla password del dispositivo e dall'endpoint dell'host del dispositivo.

Se l'istanza digital twin utilizza il segreto vault per l'autenticazione, è necessario utilizzare come password del dispositivo il valore segreto con codifica Base 64.

  • Chiave esterna: sostituire external-key con external-key dall'istanza gemello digitale con cui si desidera lavorare. Per evitare di citare i problemi, è consigliabile non utilizzare le virgolette nel valore della chiave esterna.
  • Password dispositivo: sostituire la password del dispositivo con il contenuto dei segreti testo semplice o il certificato mTLS.
  • Host dispositivo: sostituire device-host con l'host dispositivo dal dominio IoT. Per ottenere l'URL dell'endpoint host del dispositivo per il dominio IoT, vedere Recupero dei dettagli di un dominio IoT.

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

Nota

A seconda del sistema operativo o dell'applicazione, alcune applicazioni o editor di codice possono aggiungere preventivi indesiderati ai valori, questo può causare un errore. Per gli esempi di citazione, vedere Risoluzione dei problemi.
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 }'

Passo 5: verifica del comportamento di normalizzazione

La condizione di instradamento ${endpoint(3) == "metric-units"} valuta i dati e applica il seguente mapping di payload all'endpoint dati delle unità di metrica:

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

Risultato previsto:

  • Il mapping dell'adattatore converte i chilometri orari (kph) in miglia orarie (mph), quindi applica il piano per soddisfare uno schema di numeri interi:

    speed_mph = floor(velocity_kph / 1.609)

  • In questo esempio, velocity_kph = 0: speed_mph = floor(0 / 1.609) = floor(0) = 0 mph

    Dopo il piano indica il passo di arrotondamento che forza il risultato a un numero intero, arrotondando verso il basso verso l'infinito negativo. Questo valore è obbligatorio quando il modello DTDL dichiara la telemetria di velocità come schema: "integer", quindi il valore è un numero intero, non un float o una stringa.

  • velocity_kph = 110speed = floor(110 / 1.609) = 68 mph
  • I post dati standard con speed passano invariati, ad esempio i valori di questo esempio: 0, 60

Se la convalida del modello è abilitata per minimum: 0, maximum: 100, i valori fuori intervallo vengono rifiutati in base alle regole di convalida.

Utilizza conversione tipo flessibile:

  • Pass-through (mph, schema "integer"): {"speed": "60"} e {"speed": 60.0} vengono memorizzati come 60. {"speed": "60.2"} viene rifiutato a meno che il mapping delle coercizioni a un numero intero (ad esempio, con floor).
  • Instradamento metrica (kph → mph): {"velocity_kph": 110}68; {"velocity_kph": "110"}68 perché il mapping floor emette un numero intero. Mantenere gli input aritmetici numerici per evitare errori di espressione; preferire 110 rispetto a "110", se possibile.
  • L'arrotondamento rimane esplicito: la conversione flessibile non arrotonda automaticamente 68.35 a 68. Usare floor per lo schema di numeri interi oppure passare al modello schema: "double" per conservare le frazioni.

Procedure ottimali

  • Riferimento dei file JSON per le specifiche e gli adattatori dei modelli gemelli digitali: quando si carica un adattatore utilizzando l'interfaccia CLI, è possibile utilizzare i file JSON per specificare il mapping dei dati. Nei comandi della CLI è possibile fare riferimento ai file come file://~/name.json o fornire un percorso assoluto o relativo a seconda dell'ambiente della shell. A seconda del sistema operativo in uso, è possibile che la sintassi del file sia leggermente diversa tra virgolette, barre o posizione. Vedere Gestione dell'input e dell'output CLI e Utilizzo di un file JSON per l'input complesso.
  • I file di configurazione JSON (envelope, instradamenti) utilizzano i nomi dei campi API in camelCase (ad esempio, referenceEndpoint). L'interfaccia CLI OCI trasmette questi file tramite gli argomenti file:// invariati, pertanto è previsto l'uso di JSON camelCase con CLI e è corretto.
  • referenceEndpoint in envelope.json deve riflettere un endpoint tipico per l'adattatore.
  • La condizione di instradamento con caratteri jolly (*) viene valutata dopo condizioni specifiche; ordinare di conseguenza le definizioni di instradamento.
  • Ambito di conversione soft: le stringhe di tipo numerico e le doppie numeriche vengono accettate quando corrispondono al tipo di modello (ad esempio, numero intero). Gli aiutanti di casting come number() e toInteger rimangono non supportati nelle espressioni di instradamento; si basano sull'aritmetica e su floor o adottano schema: "double" per preservare le frazioni.

Variazione: viene utilizzato schema="double" anziché floor

Questa variazione mostra come l'impostazione dello schema delle proprietà del modello su double influisce sul mapping dell'adattatore e sui valori registrati. Con double, il validatore accetta qualsiasi valore integrale o frazionario numerico che soddisfi i vincoli di intervallo, senza arrotondamento automatico. È possibile scegliere di preservare la precisione frazionaria (raw) o di forzare numeri interi utilizzando floor. Entrambe passano la convalida finché i valori rimangono all'interno dell'intervallo definito.

Cosa fa la convalida schema=double

  • Accettazione del tipo: accetta numeri JSON con o senza parti frazionarie, ad esempio: 60, 68.35. Le stringhe come "68" rimangono non valide.
  • Intervallo: vengono applicati i valori minimo e massimo, ad esempio, in questo esempio 0–100.
  • Nessun arrotondamento automatico: la piattaforma IoT non arrotonda i valori; è possibile controllare l'arrotondamento nel mapping dell'adattatore digital twin o a valle utilizzando APEX o SQL a seconda dei sistemi configurati per visualizzare i dati.

File utilizzati in questa variazione:

  • model_double.json: modello DTDL con 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 - La mappatura conserva la precisione frazionaria: "$.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 - Mappatura delle coercizioni in mph a numero intero: "$.speed": "${(.velocity_kph / 1.609) | floor}" memorizzato come doppio.
    [
      {
        "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" }
      }
    ]
    

Passo A: Creare il modello digital twin utilizzando il doppio

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

Passo B: Creare due adattatori associati al modello doppio

Utilizzare i valori raw per mantenere la precisione frazionaria:

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 utilizza un numero intero come mph, che è un doppio:

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

Passo C: creare istanze digital twin per ogni adattatore

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

Passo D: inviare la telemetria di esempio e confrontare i risultati

Utilizzare la chiave esterna e la password del dispositivo dell'istanza gemella digitale per inviare i dati:
 -u "external-key:device-password" \
  • Se il gemello digitale utilizza il segreto del vault per l'autenticazione, utilizzare base64-secret come password del dispositivo.
  • Se l'istanza digital twin utilizza una certificazione mLTS, utilizzare certificate-ocid come password del dispositivo.

Valori non elaborati (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 }'

Risultato previsto: il secondo post produce circa 68.35… mph (frazionario) ed è accettato perché schema=double accetta numeri frazionari compresi nell'intervallo.

Piano (doppio, con pavimento):

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

Risultato previsto: il secondo post produce 68 come numero intero ed è accettato. Il valore viene memorizzato come valore doppio, ad esempio 68.0, anche se è un numero intero.

Note sulle virgolette dei nomi utente e sull'impatto a valle

  • La chiave esterna equivale al nome utente di autenticazione: se un'istanza digital twin viene creata utilizzando virgolette nel valore della chiave esterna, ad esempio "\"american-auto-standard-units\"", il nome utente di autenticazione di base nella richiesta curl deve includere le virgolette oppure si verifica una mancata corrispondenza e si verifica un errore 401 Unauthorized. Per evitare di citare i problemi, è consigliabile non utilizzare le virgolette nel valore della chiave esterna come negli esempi di questo scenario.
  • A valle in APEX o utilizzando SQL: con schema=double, i valori mph frazionari vengono conservati. Se sono necessari numeri interi nei report, applicare FLOOR e ROUND in SQL, ad esempio SELECT FLOOR(speed) FROM …. Con schema=integer, assicurarsi che il mapping emetta valori integrali, ad esempio, utilizzando floor per soddisfare la digitazione di numeri interi.
  • Supporto per le espressioni: inbound-route accetta aritmetica e floor. Funzioni come toInteger o number sono state rifiutate e non sono supportate; utilizzare floor o adottare schema: "double" per l'accettazione frazionaria.