Back to Blog
2 min read

Azure Digital Twins: Model the Physical World

Azure Digital Twins creates digital representations of physical environments. Model buildings, factories, cities—and simulate their behavior.

Digital Twin Definition Language (DTDL)

{
    "@id": "dtmi:example:Room;1",
    "@type": "Interface",
    "displayName": "Room",
    "contents": [
        {
            "@type": "Property",
            "name": "temperature",
            "schema": "double"
        },
        {
            "@type": "Property",
            "name": "humidity",
            "schema": "double"
        },
        {
            "@type": "Telemetry",
            "name": "occupancy",
            "schema": "integer"
        },
        {
            "@type": "Relationship",
            "name": "contains",
            "target": "dtmi:example:Device;1"
        }
    ],
    "@context": "dtmi:dtdl:context;2"
}

Creating Twins

from azure.digitaltwins.core import DigitalTwinsClient
from azure.identity import DefaultAzureCredential

client = DigitalTwinsClient(
    "https://mytwins.api.eus.digitaltwins.azure.net",
    DefaultAzureCredential()
)

# Upload model
with open("room.json", "r") as f:
    models = [json.load(f)]
    client.create_models(models)

# Create twin instance
room_twin = {
    "$metadata": {
        "$model": "dtmi:example:Room;1"
    },
    "temperature": 72.0,
    "humidity": 45.0
}
client.upsert_digital_twin("room-101", room_twin)

Twin Graph

Building-1
├── Floor-1
│   ├── Room-101
│   │   ├── Sensor-A (temperature)
│   │   └── Sensor-B (humidity)
│   └── Room-102
│       └── Sensor-C
└── Floor-2
    └── Room-201
        └── Sensor-D

Relationships

# Create relationship
relationship = {
    "$relationshipId": "floor1-contains-room101",
    "$sourceId": "floor-1",
    "$relationshipName": "contains",
    "$targetId": "room-101"
}
client.upsert_relationship("floor-1", "floor1-contains-room101", relationship)

Query Language

-- Find all rooms with high temperature
SELECT * FROM digitaltwins T
WHERE IS_OF_MODEL(T, 'dtmi:example:Room;1')
AND T.temperature > 75

-- Find rooms on a specific floor
SELECT Room FROM digitaltwins Floor
JOIN Room RELATED Floor.contains
WHERE Floor.$dtId = 'floor-1'

-- Get twin with relationships
SELECT T, CT FROM digitaltwins T
JOIN CT RELATED T.contains
WHERE T.$dtId = 'building-1'

Update Properties

# Update twin property
patch = [
    {
        "op": "replace",
        "path": "/temperature",
        "value": 74.5
    }
]
client.update_digital_twin("room-101", patch)

Event Routes

Route twin changes to other services:

# Create event route to Event Hubs
az dt route create \
    --dt-name mytwins \
    --route-name telemetry-route \
    --endpoint-name eventhub-endpoint \
    --filter "type = 'Microsoft.DigitalTwins.Twin.Update'"

IoT Hub Integration

# Function to process IoT telemetry and update twin
import azure.functions as func

def main(event: func.EventHubEvent):
    body = json.loads(event.get_body())
    device_id = event.iothub_metadata['connection-device-id']

    # Update corresponding twin
    patch = [
        {"op": "replace", "path": "/temperature", "value": body['temperature']}
    ]
    twins_client.update_digital_twin(device_id, patch)

3D Visualization

Integrate with Azure Maps, Power BI, or custom 3D viewers:

// Azure Digital Twins 3D Scenes Studio
const scene = new ADT3DSceneViewer({
    sceneId: "factory-floor",
    adtInstanceUrl: "https://mytwins.api.eus.digitaltwins.azure.net"
});

scene.onTwinSelected((twin) => {
    console.log(`Selected: ${twin.$dtId}, Temp: ${twin.temperature}`);
});

Digital Twins bridge the physical and digital worlds.

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.