Scenario: Sending Structured Data in a Default Format using HTTPs

Use this scenario for an IoT device that sends structured data in a default format to the Internet of Things (IoT) platform.

This scenario applies to a device that can be programmed to send data in a format expected by the IoT platform. This scenario requires creating a digital twin model, a digital twin adapter, a digital twin instance, and configuring the physical device to send telemetry data in the format defined by the IoT Platform.

An administrator must add a policy to your tenancy and the compartments you want to use. For policy examples and prerequisites, see Policy Details for the Internet of Things (IoT) Platform and IoT Prerequisites.

Step 1: Create an IoT Domain Group and an IoT Domain

Use an existing IoT domain group and IoT domain or create an IoT domain group and create an IoT domain to use for this scenario.

After you have the IoT domain group and IoT domain you want to work, follow these steps to set up digital twin resources to receive structured data in a default format from a device. All IoT resources must be in the same region.

Step 2: Create a Digital Twin Model

Using the CLI

  1. Save a code snippet as a digital-twin-model.json file. Reference this file in the next step when you create a digital twin model. For more information on referencing files, see Using a JSON File for Complex Input.

    To create this file use the Digital Twins Definition Language (DTDL) to define the semantics for the digital twin model. A digital twin model uses a Digital Twin Model Identifier (DTMI) as a unique identifier.

    For example:

    {
      "@context": [
        "dtmi:dtdl:context;3",
        "dtmi:dtdl:extension:historization;1",
        "dtmi:dtdl:extension:quantitativeTypes;1",
        "dtmi:com:oracle:dtdl:extension:validation;1"
      ],
      "@id": "dtmi:com:oracle:example:hvac;1",
      "@type": "Interface",
      "displayName": "HVAC",
      "description": "A digital twin model for HVAC",
      "contents": [
        {
          "@type": [
            "Telemetry",
            "Temperature"
          ],
          "name": "temperature",
          "schema": "integer",
          "unit": "degreeFahrenheit"
        },
        {
          "@type": [
            "Telemetry",
            "Historized",
            "Validated"
          ],
          "name": "humidity",
          "schema": "integer",
          "minimum": 0,
          "maximum": 100
        },
        {
          "@type": [
            "Property",
            "Historized"
          ],
          "name": "location",
          "schema": "point",
          "writable": false
        },
        {
          "@type": [
            "Property",
            "Validated"
          ],
          "name": "serialNumber",
          "schema": "string",
          "pattern": "^([0-9]){2}([0-9]){5}([0-9]){6}$"
        }
      ]
    }

    The code snippet above shows a HVAC DTDL model interface with a specific context and extensions that describes the following:

    • dtmi:dtdl:context;3 indicates this model uses DTDL version 3.
    • dtmi:dtdl:extension:historization;1: indicates this model uses historization data, tracking how properties and telemetry data change over time.
    • dtmi:dtdl:extension:quantitativeTypes;1: indicates this model uses advanced quantitative types.
    • dtmi:com:oracle:dtdl:extension:validation;1: indicates this model uses data validation.
    • dtmi:com:oracle:example:hvac;1 is the unique identifier for the HVAC unit.
    • "@type": "Interface": indicates this model uses a single interface.
    • contents: describes the telemetry and properties for this HVAC unit.
    • This array describes that time-series temperature telemetry data sent over time. Integer is the data type and is measured in Fahrenheit degrees.
      {
        "@type": ["Telemetry", "Temperature"],
        "name": "temperature",
        "schema": "integer",
        "unit": "degreeFahrenheit"
      }
    • This array describes the humidity telemetry data historized and the system validates and enforces the minimum and maximum value range.
      {
        "@type": [
          "Telemetry",
          "Historized",
          "Validated"
        ],
        "name": "humidity",
        "schema": "integer",
        "minimum": 0,
        "maximum": 100
      }
    • This array describes the location property that's static or slowly changes over time, and is historized data. The schema type point indicates a geographic location. The writable property is false and not supported in this release:
      {
        "@type": [
          "Property",
          "Historized"
        ],
        "name": "location",
        "schema": "point",
        "writable": false
      }
    • This array describes the serial number property for the HVAC unit. If the serial number value does not match the pattern defined then the system will reject the serial number.
      {
        "@type": [
          "Property",
          "Validated"
        ],
        "name": "serialNumber",
        "schema": "string",
        "pattern": "^([0-9]){2}([0-9]){5}([0-9]){6}$"
      }
  2. Use the oci iot digital-twin-model create command with the required parameter to create a digital twin model. Replace the <iot-domain-OCID> with the OCID for the IoT domain you want to work with, reference the digital-twin-model.json file with your specifications:
    oci iot digital-twin-model create --iot-domain-id <iot-domain-OCID> --spec file://digital-twin-model.json
    This example response contains the <iot-digital-twin-model-OCID>, with the associated IoT domain, the DTMI URI for the HVAC unit, and shows it's active:
    {
      "data": {
        "defined-tags": {
          "Oracle-Tags": {
            "CreatedBy": "default/user@oracle.com",
            "CreatedOn": "2025-08-05T17:43:00.438Z"
          }
        },
        "description": "Digital-twin-model-for-HVAC",
        "display-name": "HVAC",
        "freeform-tags": {},
        "id": "<iot-digital-twin-model-OCID>",
        "iot-domain-id": "<iot-domain-OCID>",
        "lifecycle-state": "ACTIVE",
        "spec-uri": "dtmi:com:oracle:example:hvac;1",
        "system-tags": {},
        "time-created": "2025-09-10T17:43:00.508000+00:00",
        "time-updated": "2025-09-10T17:43:00.508000+00:00"
      },
      "etag": "<unique-id>"
    }
    

Step 3: Create a Digital Twin Adapter

When you create a digital twin adapter, you can force the system to create a default payload and mapping by not specifying the inbound-envelope or the inbound-routes options. As a result, the response will contain the device's payload.

If the envelope mapping is not specified and contains a timeObserved then receivedTime is used as timeObserved value.

Using the CLI

Use the oci iot digital-twin-adapter create command to create a digital twin adapter. Replace the <iot-domain-OCID> with your IoT domain OCID. To associate the digital twin model, use either the DTMI URI parameter --digital-twin-model-spec-urior the digital twin OCID --digital-twin-model-id parameter to associate the digital twin model to this digital twin adapter.

This example uses the command with the --digital-twin-model-spec-uri parameter. Replace the dtmi:com:oracle:example:hvac;1 with the DTMI URI for the digital twin model you want to associate to this digital twin adapter:

oci iot digital-twin-adapter create --iot-domain-id <iot-domain-OCID> --digital-twin-model-spec-uri "dtmi:com:oracle:example:hvac;1"
Or this example shows using the command with the --digital-twin-model-id parameter. Replace the <digital-twin-model-OCID> with the digital twin OCID for the digital twin model you want to associate to this digital twin adapter:
oci iot digital-twin-adapter create --iot-domain-id <iot-domain-OCID> --digital-twin-model-id <digital-twin-model-OCID>
When you work with structured data in the default format from the device, you do not specify the --inbound-envelope <file://inbound-enevelop.json> or the --inbound-routes <file://inbound-routes.json> parameters. As a result, this example response generates the payload and mapping for the digital twin adapter:
{
  "data": {
    "defined-tags": {
      "Oracle-Tags": {
        "CreatedBy": "default/user",
        "CreatedOn": "2025-09-10T17:45:41.318Z"
      }
    },
    "description": null,
    "digital-twin-model-id": "<digital-twin-model-OCID>",
    "digital-twin-model-spec-uri": "dtmi:com:oracle:example:hvac;1",
    "display-name": "<your-digital-twin-adapter-name>",
    "freeform-tags": {},
    "id": "<digital-twin-adapter-OCID>",
    "inbound-envelope": {
      "envelope-mapping": {
        "time-observed": "$.time"
      },
      "reference-endpoint": "/",
      "reference-payload": {
        "data": {
          "humidity": 0,
          "location": {
            "coordinates": [0.0, 0.0],
            "type": "Point"
          },
          "temperature": 0,
          "time": "2025-09-10T17:45:41.387069258Z"
        },
        "data-format": "JSON"
      }
    },
    "inbound-routes": [
      {
        "condition": "*",
        "description": "Default condition",
        "payload-mapping": {
          "$.humidity": "$.humidity",
          "$.location": "$.location",
          "$.temperature": "$.temperature"
        },
        "reference-payload": null
      }
    ],
    "iot-domain-id": "<iot-domain-OCID>",
    "lifecycle-state": "ACTIVE",
    "system-tags": {},
    "time-created": "2025-09-10T17:45:41.389000+00:00",
    "time-updated": "2025-09-10T17:45:41.389000+00:00"
  },
  "etag": "<unique-id>"
}

Step 4: Create a Digital Twin Instance with a Digital Twin Adapter

Using the CLI

Use the oci iot digital-twin-instance create and the <iot-domain-OCID>, the <vault-secret-OCID>, and the <digital-twin--adapter-OCID> required parameters to create a digital twin instance for structured data.

Replace the <iot-domain-OCID> with the OCID for your IoT domain you want to update. Optionally, you can include the display parameter and replace the <display-name> with a user friendly name for the digital twin instance.

Replace the <digital-twin--adapter-OCID> with the digital twin adapter OCID created in the previous step. Replace the <vault-secret-OCID> with a secret that's in the same region as your other digital twin resources. Oracle recommends using a unique secret for each digital twin instance. For more information, see Creating a Secret.

oci iot digital-twin-instance create --iot-domain-id <iot-domain-OCID> --display-name <display_name> --auth-id <vault-secret-OCID> --digital-twin-adapter-id <digital-twin-adapter-OCID>

This example response shows the digital twin model, adapter, instance OCIDs, and the external key ID for the digital twin instance:
{
  "data": {
    "auth-id": "<vault-secret-OCID>",
    "defined-tags": {
      "Oracle-Tags": {
        "CreatedBy": "default/user@oracle.com",
        "CreatedOn": "2025-09-11T06:12:43.393Z"
      }
    },
    "description": null,
    "digital-twin-adapter-id": "<iot-digital-twin-adapter-OCID>",
    "digital-twin-model-id": "<iot-digital-twin-model-OCID>",
    "digital-twin-model-spec-uri": "dtmi:com:oracle:example:hvac;1",
    "display-name": "your display name",
    "external-key": "<unique-id>",
    "freeform-tags": {},
    "id": "<iot-digital-twin-instance-OCID>",
    "iot-domain-id": "<iot-domain-OCID>",
    "lifecycle-state": "ACTIVE",
    "system-tags": {},
    "time-created": "2025-09-11T06:12:44.178000+00:00",
    "time-updated": "2025-09-11T06:12:44.178000+00:00"
  },
  "etag": "<unique-id>"
}

Step 5: Send Telemetry Data

This example uses HTTP to post data, alternatively you can use MQTT and MQTT over WebSockets. For specific examples, see Scenarios.

HTTP POST data
curl -i -X POST -u '<digital-twin-external-key>:<vault-secret>' -H "Content-Type:application/json" 'https://<domain-short-id-from-device-host>.device-iot.<region>.oci.oraclecloud.com/telemetry' -d '{
            "temperature": 72,
            "humidity": 60,
            "location": {
                "type": "point",
                "coordinates": [40.759010, -73.984474]
            },
            "serialNumber": "5099627036043"
        }'

Step 6: View Telemetry Data

Depending on where you want to view your IoT data, each system requires specific configuration to connect your and view your IoT data.

Use the IoT Data API to View Your Data

If you want to view your IoT data use the Internet of Things (IoT) Data API to do that, you must complete the steps to configure access to your data in ORDS. After you complete the configuration, you can use the Data API to get the data you want to monitor. The supported data types include: raw, rejected, or historized data.

For more information, see the Internet of Things (IoT) Data API documentation.

This example request shows how to get raw telemetry data from the domain group data host.
curl -H "Authorization: Bearer <token>" \
              -X GET "https://<domain-group-short-id>.data.iot.<region>.oci.oraclecloud.com/ords/<domain-short-id>/20250531/rawData?q={\"$and\":[{\"digital_twin_instance_id\":\"<iot-digital-twin-OCID>\"}]}"

This example uses HTTPs. Alternatively, you can use MQTT and MQTT over WebSockets. For specific examples, see Scenarios.

Use SQL Statements to View Your Data in APEX or the Database

If you configured access your view your data directly in the database or if you configured access to view your data in APEX, then you can use this SQL statements directly in the database or in APEX to view your data.

Use this SQL statement to view the rejected telemetry data. Replace the <domain-short-id-from-device-host> with the domain short id from your device host, and replace the <digital-twin-OCID> with the digital twin's OCID that you want to view the rejected data from:

select * from <domain-short-id-from-device-host>__IOT.REJECTED_DATA where digital_twin_instance_id = '<digital-twin-instance-OCID>';
Note

Notice the schema name contain two underscores: __IOT
Or use this SQL statement to view the historized telemetry data. Replace the <domain-short-id-from-device-host> with the domain short id and replace the <digital-twin-instance-OCID> with the OCID for the digital twin instance you want to view the rejected data for:
select * from <domain-short-id-from-device-host>__IOT.DIGITAL_TWIN_HISTORIZED_DATA where digital_twin_instance_id = '<digital-twin-instance-OCID>';

Use this SQL statement to consume raw telemetry data:
select * from <domain-short-id-from-device-host>__IOT.RAW_DATA where digital_twin_instance_id = '<digital-twin-instance-OCID>';

To get the <domain-short-id-from-device-host> for the IoT domain, get the details for the IoT domain you want to work with.