Models and DTDL
How Beacon Tower uses Digital Twin Definition Language (DTDL) to define asset types.
What is a Model?
A model is a digital definition that describes the structure of telemetry, properties, and commands that assets can send and receive. Think of it as a blueprint or schema for a category of physical devices or logical assets.
In Beacon Tower, models serve several purposes:
- Type definition: Define what data an asset type produces (temperature readings, pressure measurements, etc.)
- Interface contract: Specify what properties can be read or written (firmware version, sampling rate, etc.)
- Command interface: List what actions can be invoked on the asset (reboot, calibrate, etc.)
- Validation: Ensure incoming telemetry data matches the expected schema
Typically, you create one model per product type, and often specific models for different firmware versions when the telemetry interface changes between releases.
Model Types
Beacon Tower supports three model types:
- Asset: Standard model for devices sending telemetry data. This is the most common model type representing physical devices or logical entities.
- Provider: Model for provider-level configurations and metadata.
- Component: Reusable model that can be included in other models, primarily used for IoT Edge devices with modular structures.
DTDL Overview
Beacon Tower uses Digital Twin Definition Language (DTDL) v3, a JSON-LD based language originally developed by Microsoft for Azure Digital Twins. DTDL provides a standardized way to describe the capabilities of IoT devices and digital twins.
Every DTDL model is an Interface with the following key elements:
@id: A Digital Twin Model Identifier (DTMI) in the formatdtmi:domain:name;version(e.g.,dtmi:beacontower:TemperatureSensor;1)@type: Always"Interface"for top-level models@context: The DTDL version context, typically"dtmi:dtdl:context;3"displayName: A human-readable name for the modelcontents: An array of telemetry, properties, commands, components, and relationships
DTDL supports five primary content types:
- Telemetry: Read-only time-series measurements sent by devices
- Property: State values that can be read, and optionally written (desired vs. reported properties)
- Command: Actions that can be invoked on a device
- Component: Nested sub-models for complex device hierarchies
- Relationship: Links between models (e.g., "contains", "isPartOf")
For the complete DTDL v3 specification, see the DTDL v3 documentation.
Example DTDL Model
Here's a minimal DTDL model for a temperature sensor:
{
"@id": "dtmi:beacontower:TemperatureSensor;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;3",
"displayName": "Temperature Sensor",
"contents": [
{
"@type": ["Telemetry", "Temperature"],
"name": "temperature",
"displayName": "Temperature",
"schema": "double",
"unit": "degreeCelsius"
},
{
"@type": "Property",
"name": "firmwareVersion",
"displayName": "Firmware Version",
"schema": "string",
"writable": false
},
{
"@type": "Command",
"name": "reboot",
"displayName": "Reboot Device"
}
]
}
This model defines:
- One telemetry field (
temperature) with semantic typeTemperatureand unitdegreeCelsius - One read-only property (
firmwareVersion) - One command (
reboot)
Telemetry, Properties, and Commands
Telemetry
Telemetry represents read-only, time-series measurements sent by devices. Telemetry is always flowing from the device to the platform and is stored in the time-series database.
Telemetry can have semantic types (e.g., Temperature, Pressure, Humidity) and units (e.g., degreeCelsius, pascal, percent), which enable rich data visualization and unit conversions in dashboards and alarms.
Example telemetry definition:
{
"@type": ["Telemetry", "Pressure"],
"name": "pressure",
"displayName": "Pressure",
"schema": "double",
"unit": "pascal"
}
Properties
Properties represent state values that can be read from a device, and optionally written to a device. Properties come in two flavors:
- Reported properties: State reported by the device (e.g., current firmware version, battery level)
- Desired properties: State that the platform wants the device to adopt (e.g., target temperature, sampling interval)
The writable field determines whether a property is read-only (reported only) or read-write (desired + reported):
{
"@type": "Property",
"name": "targetTemperature",
"displayName": "Target Temperature",
"schema": "double",
"writable": true
}
When writable: true, the platform can send desired property updates to the device, and the device should report back the applied value.
Commands
Commands are actions that can be invoked on a device, such as rebooting, calibrating sensors, or updating firmware. Commands may optionally have request and response payloads:
{
"@type": "Command",
"name": "calibrate",
"displayName": "Calibrate Sensor",
"request": {
"name": "offset",
"schema": "double"
},
"response": {
"name": "success",
"schema": "boolean"
}
}
Commands are synchronous or asynchronous depending on the device protocol and provider implementation.
Model Lifecycle
Models in Beacon Tower follow a draft → published lifecycle. Once a model is published, it becomes immutable and cannot be edited. This ensures that assets using a published model always have a stable, predictable interface.
Drafts and Publishing
- Create a draft: Start by creating a model draft via
POST /models/drafts - Edit the draft: Modify the DTDL content as needed
- Validate: Use
POST /models/dtdl/validateto check for DTDL errors - Publish (promote): When ready, promote the draft to a published model via
POST /models/drafts/{modelDraftId}/promote
Once published, the model is available for use by assets and appears in the list returned by GET /models.
Versioning
DTDL uses semantic versioning directly in the model ID. The version number is part of the DTMI:
dtmi:beacontower:TemperatureSensor;1
dtmi:beacontower:TemperatureSensor;2
Beacon Tower supports both major and minor versions:
- Minor versions (e.g., 1.1, 1.2): Adding new telemetry, properties, or commands without removing or renaming existing ones. These are non-breaking changes.
- Major versions (e.g., 2.0, 3.0): Removing or renaming existing telemetry, properties, or commands. These are breaking changes that require updating assets.
Beacon Tower automatically detects breaking changes and suggests a major version bump when promoting a draft that removes or renames content.
Version Tolerance
Some Beacon Tower features (such as alarms and dashboards) are designed to ignore minor version differences, reducing administrative overhead when you add new telemetry points without breaking existing functionality. This means an alarm configured for dtmi:beacontower:TemperatureSensor;1 will continue to work with assets using dtmi:beacontower:TemperatureSensor;1.1 or 1.2, as long as the referenced telemetry points still exist.
Model Drafts
Model drafts allow you to iterate on a model definition before publishing it. Drafts are mutable and can be edited, validated, and tested before becoming immutable published models.
Creating a Draft
Create a new model draft by sending a DTDL Interface to the drafts endpoint:
curl -X POST https://api.beacontower.io/models/drafts \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"@id": "dtmi:beacontower:TemperatureSensor;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;3",
"displayName": "Temperature Sensor",
"contents": [
{
"@type": ["Telemetry", "Temperature"],
"name": "temperature",
"schema": "double",
"unit": "degreeCelsius"
}
]
}'
Editing and Validating
Retrieve all drafts:
curl -X GET https://api.beacontower.io/models/drafts \
-H "X-API-Key: YOUR_API_KEY"
Get a specific draft:
curl -X GET https://api.beacontower.io/models/drafts/{modelDraftId} \
-H "X-API-Key: YOUR_API_KEY"
Update a draft:
curl -X PUT https://api.beacontower.io/models/drafts/{modelDraftId} \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"@id": "dtmi:beacontower:TemperatureSensor;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;3",
"displayName": "Temperature Sensor",
"contents": [...]
}'
Validate DTDL before publishing:
curl -X POST https://api.beacontower.io/models/dtdl/validate \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"@id": "dtmi:beacontower:TemperatureSensor;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;3",
"displayName": "Temperature Sensor",
"contents": [...]
}'
Publishing (Promoting)
Once the draft is validated and ready, promote it to a published model:
curl -X POST https://api.beacontower.io/models/drafts/{modelDraftId}/promote \
-H "X-API-Key: YOUR_API_KEY"
The draft is now immutable and available for use by assets.
Deleting Drafts
If a draft is no longer needed, it can be deleted:
curl -X DELETE https://api.beacontower.io/models/drafts/{modelDraftId} \
-H "X-API-Key: YOUR_API_KEY"
Note that only draft models can be deleted. Published models are immutable and cannot be removed once promoted.
Working with Published Models
List all published models:
curl -X GET https://api.beacontower.io/models \
-H "X-API-Key: YOUR_API_KEY"
Get a specific model:
curl -X GET https://api.beacontower.io/models/{modelId} \
-H "X-API-Key: YOUR_API_KEY"
Retrieve the DTDL definition:
curl -X GET https://api.beacontower.io/models/{modelId}/dtdl \
-H "X-API-Key: YOUR_API_KEY"
Binding Descriptions
While models define the telemetry interface for assets, binding descriptions provide the metadata that maps model telemetry to provider data points. Binding descriptions are the glue between the abstract model schema and the concrete data channels provided by a specific IoT protocol or data source.
What is a Binding Description?
A binding description specifies:
- Which model telemetry field (e.g.,
temperature) - Maps to which provider endpoint and content identifier (e.g., an MQTT topic, OPC UA node ID, or HTTP endpoint)
Binding descriptions use a special BTI (Beacon Tower Identifier) format:
btbi:modelid:_e_endpoint:_c_content:name;version
For example:
btbi:dtmi:beacontower:TemperatureSensor;1:_e_mqtt/sensor123:_c_temperature:TemperatureBinding;1
This BTI maps the temperature telemetry in model dtmi:beacontower:TemperatureSensor;1 to the MQTT endpoint mqtt/sensor123 with content identifier temperature.
Working with Binding Descriptions
Binding descriptions follow a similar draft/publish lifecycle as models.
List all published binding descriptions:
curl -X GET https://api.beacontower.io/bindings \
-H "X-API-Key: YOUR_API_KEY"
Get a specific binding description:
curl -X GET https://api.beacontower.io/bindings/{bindingDescriptionId} \
-H "X-API-Key: YOUR_API_KEY"
Get binding descriptions for a specific model:
curl -X GET https://api.beacontower.io/bindings/model/{modelId} \
-H "X-API-Key: YOUR_API_KEY"
Create a new binding description:
curl -X POST https://api.beacontower.io/bindings \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modelId": "dtmi:beacontower:TemperatureSensor;1",
"endpointId": "mqtt/sensor123",
"contentId": "temperature",
"telemetryName": "temperature"
}'
Update a binding description:
curl -X PATCH https://api.beacontower.io/bindings/{bindingDescriptionId} \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{...}'
Delete a binding description:
curl -X DELETE https://api.beacontower.io/bindings/{bindingDescriptionId} \
-H "X-API-Key: YOUR_API_KEY"
Binding Description Drafts
Create a binding description draft:
curl -X POST https://api.beacontower.io/bindings/drafts \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{...}'
Get all binding description drafts:
curl -X GET https://api.beacontower.io/bindings/drafts \
-H "X-API-Key: YOUR_API_KEY"
Get a specific binding description draft:
curl -X GET https://api.beacontower.io/bindings/drafts/{bindingDescriptionDraftId} \
-H "X-API-Key: YOUR_API_KEY"
Get binding description drafts for a specific model:
curl -X GET https://api.beacontower.io/bindings/drafts/model/{modelId} \
-H "X-API-Key: YOUR_API_KEY"
Update a binding description draft:
curl -X PUT https://api.beacontower.io/bindings/drafts/{bindingDescriptionDraftId} \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{...}'
Delete a binding description draft:
curl -X DELETE https://api.beacontower.io/bindings/drafts/{bindingDescriptionDraftId} \
-H "X-API-Key: YOUR_API_KEY"
Promote a binding description draft:
curl -X POST https://api.beacontower.io/bindings/drafts/{bindingDescriptionId}/promote \
-H "X-API-Key: YOUR_API_KEY"
Note: Most users rely on Beacon Tower's autobind feature, which automatically creates binding descriptions based on provider metadata and model definitions. Manual binding descriptions are only needed for complex scenarios or custom integrations.
Next Steps
- Learn how models relate to assets in Assets, Providers, and Bindings
- Explore the full model and binding description API in the API Reference
- Understand how telemetry data flows through the platform in Telemetry and Time Series