Introduction

Digital twin models help application developers work with physical-world data in a consistent way. A device might send data in one format, a gateway might reshape it, and an application might need a cleaner view of the same equipment. Without a consistent model, each application must understand the device payload, field names, data types, and meaning on its own.
Oracle Cloud Infrastructure Internet of Things Platform (OCI IoT Platform) uses digital twin models to create that shared view. A model describes the shape and semantics of a digital twin: what data the device reports, what the data is called, and how applications should interpret it. That gives developers a canonical model for physical objects, instead of forcing every application to reason directly over raw device messages.
A model can represent a machine, sensor, vehicle, appliance, room, or other real-world asset. Applications can then read and process modeled data using stable names and schemas, even when the physical devices and ingestion patterns vary behind the scenes.

Picture of a motor with an example of the JSON DTDL representation
Figure 1. A physical water pump can be represented by a DTDL model that describes its reusable components and telemetry.

DTDL as the modeling language

OCI IoT Platform digital twin models use Digital Twins Definition Language, or DTDL. DTDL is a JSON-based modeling language for describing digital twins. In OCI IoT Platform, a digital twin model is based on DTDL v3 and uses a Digital Twin Model Identifier, or DTMI, as its unique model identifier.
At the top level, a DTDL model is usually an Interface. The interface contains named content such as telemetry, properties, commands, relationships, and components. Here we will focus on modeling the telemetry from a physical device using DTDL and the components concept.
Telemetry represents data emitted by a device or digital twin. Components let a model include another model by reference. Together, those concepts let developers structure models in a way that matches the physical object they are representing.

Modeling complex objects with reusable parts

Real-world objects are rarely just flat lists of values. A device can contain sensors, subassemblies, modules, and measurements that make more sense when grouped together. DTDL gives developers flexibility to decide when a value should stand alone and when a group of values should become a reusable model.
An electric motor is a useful example. Motors appear in pumps, compressors, fans, conveyors, and many other pieces of industrial equipment. Rather than redefine the same motor telemetry in every equipment model, a developer can define a reusable ElectricMotor model once and reference it from other models.
In this example, the ElectricMotor model reports three telemetry values:

  • motorTemperature
  • vibrationLevel
  • powerConsumption

The WaterPump model then uses the reusable motor model as a component and adds pump-specific telemetry:

  • flowRate
  • dischargePressure

Example: electric motor model

The first model represents an electric motor. It contains three telemetry values: motorTemperature, vibrationLevel, and powerConsumption. Each value is marked as telemetry because it represents a measurement emitted by the physical motor or the system observing it. For illustration, motorTemperature and vibrationLevel are also marked as Historized because those values are often useful when reviewed over time.

{
  "@context": [
    "dtmi:dtdl:context;3",
    "dtmi:dtdl:extension:historization;1"
  ],
  "@id": "dtmi:com:oracle:iot:example:ElectricMotor;1",
  "@type": "Interface",
  "displayName": "Electric Motor",
  "contents": [
    {
      "@type": ["Telemetry", "Historized"],
      "name": "motorTemperature",
      "schema": "double"
    },
    {
      "@type": ["Telemetry", "Historized"],
      "name": "vibrationLevel",
      "schema": "double"
    },
    {
      "@type": "Telemetry",
      "name": "powerConsumption",
      "schema": "double"
    }
  ]
}

This model is intentionally small. It says that an electric motor has three telemetry values and gives each value a stable name and type. The model does not say whether the motor belongs to a pump, fan, compressor, or conveyor. That separation is part of the point: the model describes the reusable motor shape, and other models can include it where it fits.

Top-level DTDL fields

Before looking at the telemetry and historization annotations, it helps to understand the top-level fields in the DTDL file.

The @context section tells a DTDL processor which language context and extensions the model uses. In this example, dtmi:dtdl:context;3 identifies the model as DTDL v3. The second entry, dtmi:dtdl:extension:historization;1, adds the historization extension so model contents can use the Historized type annotation.

The @id field gives the model its Digital Twin Model Identifier, or DTMI. This identifier is the stable name for the model. Other models can reference it, as the water pump model does later when it includes the electric motor model as a component.

The @type field declares what kind of DTDL element the JSON object represents. At the top level of these examples, @type is Interface, which means the file defines a digital twin interface. The interface then uses contents to list the named elements that belong to the model, such as telemetry values and components.

Telemetry keyword

The Telemetry keyword tells DTDL and OCI IoT Platform that a named element represents data emitted by the digital twin. In the electric motor example, motorTemperature, vibrationLevel, and powerConsumption are telemetry because they are measurements reported by the physical asset or by an observing system.

Marking a value as telemetry gives the platform and application code a clear contract: this value is observed data, it has a name, and it has a schema. That contract helps the digital twin adapter normalize incoming device payloads into the model. It also helps applications read the latest modeled values without depending on every raw payload format used by every device.

In short, telemetry turns incoming measurements into named, typed parts of the digital twin model.

Historized keyword

The Historized keyword adds a second instruction: retain the value as time-series data, rather than treating it solely as the current snapshot. In the electric motor example, motorTemperature and vibrationLevel are marked as both Telemetry and Historized. That means each reading can be retained with time context, which supports later queries across time intervals.

This distinction matters because not every telemetry value needs history. Some applications need the latest value. Others need trends, comparisons, audits, or time-window analysis. Historization lets the model author identify which telemetry values should be kept as history.

Apply Historized selectively because it stores telemetry history, not just the latest value. It is useful for values where time matters, such as repeated measurements, operating conditions, or values that provide historical context. For values where current state is sufficient, telemetry without historization may be enough. Judicious use of historization can help reduce the cost of storing IoT data.

Example: water pump model

The second model represents a water pump. Instead of redefining motor telemetry directly inside the pump, it references the ElectricMotor model as a component named motor. The pump also reports its own telemetry values: flowRate and dischargePressure. In this example, flowRate uses Oracle’s validation extension to define an illustrative operating range, and dischargePressure uses the DTDL QuantitativeTypes extension to state that the reading is pressure reported in bar.

{
  "@context": [
    "dtmi:dtdl:context;3",
    "dtmi:dtdl:extension:quantitativeTypes;1",
    "dtmi:com:oracle:dtdl:extension:validation;1"
  ],
  "@id": "dtmi:com:oracle:iot:example:WaterPump;1",
  "@type": "Interface",
  "displayName": "Water Pump",
  "contents": [
    {
      "@type": "Component",
      "name": "motor",
      "schema": "dtmi:com:oracle:iot:example:ElectricMotor;1"
    },
    {
      "@type": [
        "Telemetry",
        "Validated"
      ],
      "name": "flowRate",
      "schema": "double",
      "minimum": 0,
      "maximum": 1000
    },
    {
      "@type": [
        "Telemetry",
        "Pressure"
      ],
      "name": "dischargePressure",
      "schema": "double",
      "unit": "bar"
    }
  ]
}

This structure keeps the model readable. The pump model says, “This asset includes a motor and reports pump-specific operating data.” The motor model says, “A motor reports temperature, vibration, and power consumption.” Applications can work with the pump as a whole, while still recognizing that the motor is a reusable part that may also appear in compressors, fans, conveyors, and other equipment models.

Validation extension

The validation extension lets a model author add JSON Schema validation rules to selected model contents. This is an Oracle-provided extension for OCI IoT Platform, not part of the base DTDL specification. In the water pump example, one entry in the @context section is dtmi:com:oracle:dtdl:extension:validation;1, which lets the model use the Validated annotation.
The flowRate telemetry is marked as both Telemetry and Validated. The minimum and maximum fields define the accepted numeric range for incoming flowRate values. In this example, the range is illustrative: 0 to 1000. In a real pump model, those limits should come from the pump specification, engineering standard, or operating policy.
Validation can help identify data that does not match the model’s expected shape or range before applications treat it as normal telemetry. It is especially useful when a value has clear physical limits such as pressure, flow rate, temperature, or percentage-based readings.

Quantitative types extension

The DTDL quantitativeTypes extension adds measurement semantics to numeric model contents. A telemetry value can still use a numeric schema such as double, but the model can also say what kind of quantity the number represents and which unit it uses.
In the water pump model, dischargePressure is typed as both Telemetry and Pressure. Its unit value is bar, the DTDL unit token for the Bar unit of measure. That indicates to consumers that the pressure value is not just an unlabeled number; it is a pressure measurement expressed in Bar.
This metadata is useful when different devices report similar values in different units. For example, one pump controller might send pressure in Bar while another sends pressure in pounds per square inch. The quantitative type and unit give application code a model-level indication that unit conversion may be needed before values are compared or combined.

Using relationships instead of components

DTDL also supports relationships. A relationship describes a named connection from one digital twin to another. It does not embed one model inside another model. Instead, it lets separate twin instances stay independent while still expressing how they are connected.
That distinction matters for asset modeling. In the water pump example above, the motor is represented as a component because the article treats the motor as part of the pump’s modeled data shape. The pump twin contains a nested motor component, and applications can read telemetry such as motor.motorTemperature, motor.vibrationLevel, and motor.powerConsumption as part of the pump twin.
A relationship would be a better fit if the motor should exist as its own digital twin instance. For example, a pump twin could have a drivenBy relationship to an electric motor twin. That motor twin could have its own identity, serial number, maintenance history, telemetry, location, or replacement lifecycle. If a technician replaces the motor, the relationship can change without redefining the pump model.

A comparison of the structure when using a component vs. when using a relationship in DTDL.
Figure 2. A visual comparison of structuring a digital twin using Component vs. Relationship.

Use a component when the part belongs inside the parent asset’s data shape. Components work well when the part follows the parent lifecycle, does not need to be queried as a separate asset, and gives the parent model a clearer structure. In this article, ElectricMotor works as a component because it groups reusable motor telemetry inside WaterPump.
Use a relationship when both things should be modeled as separate twins. Relationships work well when each asset has its own lifecycle, maintenance process, ownership, location, or graph query value. They also help answer questions such as, “Which pumps are driven by this motor?” or “Which assets are installed in this room?”
When authoring the DTDL for these two options, the primary difference is how the motor is defined. It is either a Component or a Relationship. When using a Component, specify the schema:

 "contents": [
    {
      "@type": "Component",
      "name": "motor",
      "schema": "dtmi:com:oracle:iot:example:ElectricMotor;1"
    },
When using a Relationship, you may optionally specify the target: 
"contents": [
    {
      "@type": "Relationship",
      "name": "drivenBy",
      "target": "dtmi:com:oracle:iot:example:ElectricMotor;1"
    },

In short, components organize data inside a twin, and relationships connect twins to other twins.

How adapters map device payloads

The model defines the canonical shape that applications should use, but real devices often send data in device-specific formats. A pump controller might report motorTempC, motorVibrationMmSec, motorPowerKw, pumpFlowGpm, and pumpOutletPressurePsi. Another controller might use different names, different units, or a different nesting structure. Without a mapping layer, every application would need to understand those device-specific details.
An OCI IoT Platform digital twin adapter performs that mapping. The adapter reads the inbound device payload, extracts envelope data such as the observation timestamp, and maps source fields into the digital twin model paths. For this example, the adapter can map motorTempC to motor.motorTemperature, motorVibrationMmSec to motor.vibrationLevel, motorPowerKw to motor.powerConsumption, pumpFlowGpm to flowRate, and pumpOutletPressurePsi to dischargePressure.
This keeps the digital twin model stable even when device payloads vary. Device teams can adjust adapters for each payload format, while application teams continue to read the same WaterPump model. That separation is what makes the model canonical: it represents the asset in business and application terms, while the adapter absorbs the device-specific translation work.

The image depicts how an adapter is used to transform telemetry from a device to the canonical DTDL model using JQL formulas.
Figure 3. Device-specific telemetry is mapped through an adapter into the canonical digital twin model used by applications.

Summary

Digital twin models give developers a consistent way to represent physical assets in OCI IoT Platform. In this example, the reusable ElectricMotor model captures motor telemetry once, and the WaterPump model composes that motor component with pump-specific telemetry such as flowRate and dischargePressure.
DTDL provides the base modeling language for interfaces, telemetry, and components. OCI IoT Platform extensions, such as historization and validation, add platform-specific behavior where it is needed. Adapters complete the pattern by translating real device payloads into the canonical model shape, so applications can work with stable digital twin data instead of raw device formats.

Resources

OCI Internet of Things Platform overview
OCI Internet of Things Platform documentation
Creating a Digital Twin Model
Oracle JSON Schema Validation Extension
Digital Twins Definition Language v3
DTDL QuantitativeTypes extension v1
Digital Twin Relationships