Escenario: Normalización de unidades de medida mediante un adaptador gemelo digital

En este escenario se explica cómo utilizar un modelo de gemelo digital, un adaptador de gemelo digital con asignaciones de sobre y ruta para normalizar la telemetría específica en un esquema común y cómo validar el flujo mediante la publicación de cargas útiles de dispositivos de muestra.

Este escenario demuestra cómo publicar datos de telemetría automotriz con diferentes unidades de medida de millas por hora y kilómetros por hora utilizando diferentes puntos finales, dos instancias gemelas digitales y dos claves externas diferentes. Para obtener más información sobre los patrones JQ a los que se hace referencia en este escenario, consulte Referencia: Expresiones JQ para adaptadores gemelos digitales.

Un adaptador gemelo digital ruta las solicitudes por punto final y asigna cargas útiles a un único modelo. Por ejemplo, el modelo de métrica envía la velocidad en kilómetros por hora (velocity_kph), mientras que otra instancia gemela digital estándar envía millas por hora (speed).

Tareas

Comprender los archivos de este escenario:

Los fragmentos de código que puede utilizar en su modelo gemelo digital al que se hace referencia en los siguientes pasos:

  • model.json: modelo gemelo digital basado en especificaciones de DTDL v3 con una propiedad de telemetría speed en millas por hora que utiliza una extensión de validación que aplica límites en el rango de valores de 0 a 100.
  • envelope.json: configuración de sobre que declara un punto final de referencia y una unidad de carga útil de ejemplo.
  • routes.json: condiciones de ruta y asignaciones de carga útil que convierten kilómetros por hora en millas por hora.
  • script.sh: en este ejemplo, puede guardar todos los comandos de la CLI de OCI que se muestran a continuación para crear un modelo de gemelo digital, un adaptador y unas instancias, además de los comandos curl en la telemetría de ejemplo POST y, a continuación, ejecutarlo como un script de shell script.sh.
  • Para completar los pasos de este escenario, puede crear y guardar la CLI de OCI y los comandos curl que se muestran en los pasos siguientes y ejecutar este escenario como un script de shell: script.sh

Este fragmento de código model.json de modelo gemelo digital de ejemplo utiliza una extensión personalizada dtmi:com:oracle:dtdl:extension:validation;1 que aplica reglas de validación al esquema JSON para los elementos "Telemetry", "Historized", "Validated", "Velocity". Si los datos no coinciden con los valores esperados definidos en esta validación, los datos se rechazan.

Para obtener una lista completa de las reglas de propiedad de validación admitidas, consulte DTMI Validation Extension Reference (Referencia de extensión de validación deDTMI).

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

Este archivo routes.json que se muestra a continuación contiene 3 expresiones que transforman los kilómetros y normalizan la carga útil de datos en una unidad de medida, millas por hora:
  • Expresión de condición que evalúa los datos del punto final:

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

    La sintaxis ${ ... } indica una expresión que evalúa el valor del parámetro de tercer punto final o el elemento de ruta de acceso en una llamada de API endpoint(3). La condición compara el valor devuelto con metric-units. Si es verdadero, aplica estas reglas.

  • Expresión de asignación de carga útil:

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

    La sintaxis ${ ... } indica una expresión, esta expresión evalúa y realiza un cálculo aritmético para convertir la velocidad de kilómetros por hora a millas por hora (.velocity_kph / 1.609); esto divide el campo velocity_kph por 1.609 y, a continuación, aplica la función de piso, redondeando hacia abajo al entero más cercano. Este valor proviene de la conversión de kilómetros a millas que es kilómetros = millas × 1.60934,

  • "payloadMapping": {"$.speed": "$.speed"} Se trata de una expresión de asignación de valores directos, que pasa por el valor de velocidad tal cual.
[
  {
    "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" }
  }
]

Paso 1: Crear un modelo gemelo digital

Utilice este comando de la CLI oci iot digital-twin-model create para crear un modelo gemelo digital mediante el archivo model.json. Este modelo gemelo digital estandariza speed en millas por hora.

Este comando registra el modelo de gemelo digital con este URI de DTMI dtmi:com:oracle:iot:poc:testmodel;1 como se define en la mención model.json anterior.

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

Paso 2: Crear un adaptador gemelo digital con un sobre y rutas

Cree un adaptador que haga referencia a la especificación de modelo de gemelo digital DTMI y que utilice el sobre entrante y las rutas para normalizar la telemetría 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 en envelope.json es telemetry/automotive/usa-standard-units. El archivo routes.json:

  • Enruta las solicitudes al tercer segmento de ruta que es igual a metric-units, por ejemplo, /telemetry/automotive/metric-units y, a continuación, convierte velocity_kph a speed en mph y planta el resultado.
  • Utiliza una condición catch-all por defecto (*) para pasar a través de speed sin cambios para los automóviles que usan millas por hora.

Paso 3: Crear dos instancias gemelas digitales

Cree dos instancias de gemelo digital que se autentiquen mediante un secreto de almacén y compartan ambas instancias de gemelo digital que compartan el mismo adaptador de gemelo digital. Los puntos finales se definen para que cada instancia de gemelo digital pueda publicar datos en un punto final único:
  • Punto final para mph: https://device-host/telemetry/automotive/usa-standard-units
  • Punto final para kph: https://device-host/telemetry/automotive/metric-units
Sustituya el OCID del adaptador de gemelo digital por el OCID del adaptador de gemelo digital creado en el paso anterior. Sustituya los nombres mostrados y las claves externas por los valores de su entorno.
Nota

Al crear una instancia de gemelo digital con autenticación, puede utilizar un secreto de almacén o un certificado mTLS para autenticarse. Por motivos de seguridad, se recomienda crear un secreto de almacén único o un certificado mTLS para cada instancia de gemelo digital. Todos los recursos deben estar en la misma región y arrendamiento que cualquier otro recurso IoT relacionado.

Si utiliza un certificado mTLS para autenticarse, debe utilizar el nombre común del certificado como clave externa: --external-key <common-name-from-certificate-details>. Consulte Escenario: Crear una instancia de gemelo digital que utilice un certificado mTLS.

Un administrador debe agregar la política para crear secretos o certificados. Consulte el Step 3 en Prerequisites.

Instancia gemela digital para unidades estándar de EE. UU., millas por hora (mph), observe la clave externa:

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>
Instancia gemela digital para las unidades métricas europeas, kilómetros por hora (kph), observe la clave externa:

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>

Paso 4: Enviar telemetría de ejemplo para validar el enrutamiento y la asignación

Para enviar la telemetría, necesita la clave externa de la respuesta de la instancia de gemelo digital del paso 3, la contraseña del dispositivo y el punto final del host del dispositivo.

Si la instancia de gemelo digital utiliza el secreto de almacén para autenticarse, debe utilizar como valor secreto codificado base 64 como contraseña del dispositivo.

  • Clave externa: sustituya external-key por external-key de la instancia de gemelo digital con la que desea trabajar. Para evitar problemas de ofertas, se recomienda no utilizar comillas en el valor de clave externa.
  • Contraseña del dispositivo: sustituya la contraseña del dispositivo por el contenido del secreto de texto sin formato o el certificado mTLS.
  • Host de dispositivo: sustituya device-host por el host de dispositivo del dominio IoT. Para obtener la URL de punto final de host del dispositivo para el dominio IoT, consulte Obtención de detalles de un dominio IoT.

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

Nota

Según el sistema operativo o la aplicación, algunas aplicaciones o editores de código pueden agregar comillas no deseadas a los valores, lo que puede provocar un error. Consulte Solución de problemas para obtener ejemplos de comillas.
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 }'

Paso 5: Verificar el comportamiento de normalización

La condición de ruta ${endpoint(3) == "metric-units"} evalúa los datos y aplica la siguiente asignación de carga útil al punto final de datos de unidades de métrica:

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

Resultado esperado:

  • La asignación del adaptador convierte kilómetros por hora (kph) a millas por hora (mph) y, a continuación, aplica suelo para satisfacer un esquema entero:

    speed_mph = floor(velocity_kph / 1.609)

  • En este ejemplo, velocity_kph = 0: speed_mph = floor(0 / 1.609) = floor(0) = 0 mph

    Después del piso indica el paso de redondeo que obliga al resultado a un número entero, redondeando hacia abajo hacia el infinito negativo. Esto es necesario cuando el modelo DTDL declara la telemetría de velocidad como schema: "integer", de modo que el valor es un entero, no un flotante o una cadena.

  • velocity_kph = 110speed = floor(110 / 1.609) = 68 mph
  • Las publicaciones de datos estándar con speed se transfieren sin cambios, por ejemplo, los valores de este ejemplo: 0, 60

Si la validación del modelo está activada minimum: 0, maximum: 100, los valores fuera de rango se rechazan según las reglas de validación.

Utiliza la conversión de tipo flexible:

  • Transferencia (mph, esquema "integer"): {"speed": "60"} y {"speed": 60.0} se almacenan como 60. {"speed": "60.2"} se rechaza a menos que la asignación se asocie a un entero (por ejemplo, con floor).
  • Ruta métrica (kph → mph): {"velocity_kph": 110}68; {"velocity_kph": "110"}68 porque la asignación floor emite un número entero. Mantenga las entradas aritméticas numéricas para evitar errores de expresión; prefiera 110 en lugar de "110" cuando sea posible.
  • La redondeo sigue siendo explícita: la conversión flexible no redondea automáticamente 68.35 a 68. Utilice floor para el esquema entero o cambie el modelo a schema: "double" para conservar las fracciones.

Mejores prácticas

  • Archivos JSON de referencia para adaptadores y especificaciones de modelo gemelo digital: al cargar un adaptador mediante la CLI, puede utilizar archivos JSON para especificar la asignación de datos. En los comandos de la CLI, puede hacer referencia a los archivos como file://~/name.json o proporcionar una ruta de acceso absoluta o relativa según el entorno de shell. Según el sistema operativo, puede que tenga una sintaxis ligeramente diferente con comillas, barras diagonales o la ubicación del archivo de forma predeterminada. Consulte Gestión de entrada y salida de la CLI y Uso de un archivo JSON para entrada compleja.
  • Los archivos de configuración JSON (sobre, rutas) utilizan nombres de campo de API en camelCase (por ejemplo, referenceEndpoint). La CLI de OCI transfiere estos archivos a través de argumentos file:// sin cambios, por lo que se espera y se corrige el uso de JSON camelCase con CLI.
  • referenceEndpoint en envelope.json debe reflejar un punto final típico para el adaptador.
  • La condición de ruta comodín (*) se evalúa después de condiciones específicas; ordene las definiciones de ruta según corresponda.
  • Ámbito de conversión flexible: las cadenas de tipo numérico y los dobles de números enteros se aceptan cuando coinciden con el tipo de modelo (por ejemplo, entero). Los ayudantes de fundición como number() y toInteger siguen sin estar soportados en las expresiones de ruta; confíen en la aritmética y floor, o adopten schema: "double" para conservar fracciones.

Variación: uso de schema="double" en lugar de floor

Esta variación muestra cómo la definición del esquema de propiedad de modelo en double afecta a la asignación del adaptador y a los valores registrados. Con double, el validador acepta cualquier valor numérico integral o fraccional que cumpla con las restricciones de rango, sin redondeo automático. Puede elegir conservar la precisión fraccional (cruda) o obligar a los números enteros mediante floor. Ambas pasan la validación siempre que los valores permanezcan dentro del rango definido.

Qué hace la validación schema=double

  • Aceptación de tipo: acepta números JSON con o sin partes fraccionadas, por ejemplo: 60, 68.35. Las cadenas como "68" siguen siendo no válidas.
  • Rango: mínimo y máximo, por ejemplo, en este ejemplo, se aplican 0–100.
  • Sin redondeo automático: la plataforma IoT no redondea los valores; puede controlar el redondeo en la asignación o descendente del adaptador de gemelos digitales mediante APEX o SQL en función de los sistemas configurados para ver los datos.

Archivos utilizados en esta variación:

  • model_double.json: modelo 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 asignación conserva la precisión fraccional: "$.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: la asignación de coerces a mph de número entero: "$.speed": "${(.velocity_kph / 1.609) | floor}" se almacena como un doble.
    [
      {
        "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" }
      }
    ]
    

Paso A: Crear el modelo gemelo digital con doble

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

Paso B: Crear dos adaptadores asociados al modelo doble

Utilice valores raw para conservar la precisión fraccionada:

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 utiliza un número entero como mph, que es un doble:

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

Paso C: Crear dos instancias digitales para cada adaptador

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

Paso D: Postear la telemetría de la muestra y comparar los resultados

Utilice la clave externa y la contraseña del dispositivo de la instancia gemela digital para enviar datos:
 -u "external-key:device-password" \
  • Si el gemelo digital utiliza el secreto de almacén para autenticarse, utilice base64-secret como contraseña del dispositivo.
  • Si la instancia de gemelo digital utiliza una certificación mLTS, utilice certificate-ocid como contraseña del dispositivo.

Valores raw (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 }'

Resultado esperado: la segunda publicación produce aproximadamente 68.35… mph (fraccional) y aceptado porque schema=double acepta números fraccionarios dentro del rango.

Piso (doble, con suelo):

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

Resultado esperado: la segunda publicación produce 68 en un número entero y es aceptado. El valor se almacena como un doble, por ejemplo, 68.0, aunque sea un número entero.

Notas sobre las comillas del nombre de usuario y el impacto descendente

  • La clave externa es igual al nombre de usuario de autenticación: si se crea una instancia de gemelo digital mediante comillas en el valor de clave externa, por ejemplo, "\"american-auto-standard-units\"", el nombre de usuario de autenticación básica en la solicitud curl debe incluir las comillas, o si se produce una discrepancia y se produce un error 401 Unauthorized. Para evitar problemas de ofertas, se recomienda no utilizar comillas en el valor de clave externa como en los ejemplos de este escenario.
  • Descendente en APEX o mediante SQL: con schema=double, se conservan los valores de mph fraccionarios. Si necesita números enteros en los informes, aplique FLOOR y ROUND en SQL, por ejemplo, SELECT FLOOR(speed) FROM …. Con schema=integer, asegúrese de que la asignación emita valores integrales, por ejemplo, mediante floor para cumplir con la escritura de enteros.
  • Soporte de expresión: inbound-route acepta aritmética y floor. Las funciones como toInteger o number se han rechazado y no están soportadas; utilice floor o adopte schema: "double" para la aceptación fraccionada.