1. Digital Twin Definition Model
This chapter will look at the Digital Twin Definition Language in depth. The Digital Twin Definition
Language is used to describe the meta models we use to create custom models to instantiate Digital
Twins. First, we will explain the different meta models such as interfaces, properties, and components.
Then, we will learn about the Digital Twin Model identifier, its available schemas, and its semantic types.
Some examples will be used to explain it more thoroughly.
While this chapter is more theoretical than the other chapters, it will pave the way for building Digital
Twins using the Azure Digital Twins service. You will use each of these definitions in the upcoming
chapters to understand their examples, which allow you to start building Digital Twins using the service.
In this chapter, we'll cover the following topics:
Digital Twins Definition Language
Interface content
Schemas
Primitive schemas
Complex schemas
Geospatial schemas
Semantic type
Validating a
model Technical
requirements
This chapter will talk
about validating models
using the DTDL Validator
tool, which can be found
at https://docs.microsoft.com/en-us/samples/azure-samples/dtdl-validator/dtdl-validator/. We will also
be using some of the tools that we installed and configured in the previous chapter.
Digital Twins Definition Language
The models in the Azure Digital Twins service are based on the Digital Twins Definition
Language (DTDL). DTDL is a language that's used to describe models. These models are used with IoT
plug and play devices and Digital Twins. DTDL allows us to use semantics and definitions uniformly to
define these models, which are used across IoT platforms and IoT solutions. DTDL enables us to define
several elements, behaviors, and abilities of a Digital Twin. Digital Twins' behaviors are modeled using
meta model classes with DTDL. Several examples of these meta models are listed here and will be
explained in more detail in the next part of this chapter:
Interfaces: A descriptive language for describing models.
Properties: The simple types of metadata of a model.
Telemetry: The telemetry data that comes from a sensor. It can be used as metadata in a
model.
2. Relationships: Relationship definitions between models.
Components: A way of grouping the properties in models as part of a Digital Twin.
Data Types such as Array, Enum, Map, Object, and Field: Complex types of metadata in a
model.
Some SDKs and API libraries, such as the .NET SDK, implement these behaviors to allow you to create
models based on these meta models with ease. This allows you to create your own custom models.
These custom models are then used to create Digital Twins, which represent instances of these custom
models. The JavaScript Object Notation (JSON) payload can be used to load these custom models into
the Azure Digital Twins service using Azure Digital Twins Explorer.
JSON-LD
DTDL is based on JavaScript Object Notation for Linked Data (JSON-LD). JSON-LD is a way of formatting
data into a uniform structure. JSON-LD is based on JSON, which makes it easy to read for everyone.
JSON-LD allows you to structure data analogously by using a list of pairs of attributes and values on top
of what you can normally do with JSON. It can be compared to multi-dimensional arrays.
JSON-LD was selected by Microsoft because it can be used as JSON and can be used in Resource
Description Framework (RDF) systems. RDF is a widely known standard that is used to describe data in a
distributed and extensible way. This framework also provides semantic annotations. Semantic
annotations allow us to give meaning to the behavior of a model. JSON-LD allows us to use semantic
annotations without having to understand RDF.
Versioning
The current Azure Digital Twins service is based on version 2 of DTDL. DTDL has been extended
thoroughly in version 2 and now has several new model elements and semantic changes made to it.
Several elements have been removed. In some cases, elements have been deprecated to prevent
regression errors.
In this section, we learned what the DTDL is and how it can be used to create Digital Twins. In the next
section, we will learn about the Digital Twin interface and describe several meta models.
Digital Twin interface
Each digital twin is described by an interface. This interface contains a description of the content of a
digital twin. Let's explain this better with an example. Here, we will create an interface describing a
room. This room contains several sensors, such as temperature, light, and movement. In this case, the
interface describes the room and defines the content of that room by its sensors. This interface is shown
here in JSON:
{
"@id": "dtmi:com:contoso:room;1",
"@type": "Interface",
3. "displayName": "Room",
"contents": [
{
"@type": "Telemetry",
"name": "temperature",
"schema": "double"
},
{
"@type": "Telemetry",
"name": "lights",
"schema": "boolean"
}, {
"@type": "Telemetry",
"name": "hasmovement",
"schema": "boolean"
},
{
"@type": "Property",
"name": "setlight",
"writable": true,
"schema": "boolean"
}
],
"@context":
"dtmi:dtdl:context;2"
}
There are several parts in this example. The first part is the @id property. This property is the digital
twin model identifier (DTMI). Each element, such as interfaces, properties, telemetry, commands,
components, relationships, and even complex schemas within a digital twin model, must have a DTMI.
A DTMI consists of the following parts:
4. [scheme]:[path];[version]
Note the second semicolon between [path] and [version] instead of a colon. The following table
explains the different parts more thoroughly:
DTMIs are case-sensitive. Be aware of making mistakes when using lowercase and uppercase letters. My
recommendation would be to always use lowercase letter so that you don't make any mistakes.
TIP
The best approach for creating a DTMI is looking at your organization. As an example, we will use the
organization Contoso, which has adomain of www.contoso.com, and department analytics as an
example. As a best practice, the domain of the organization is used in the path, which creates a path
such as com:contoso:analytics:Room. This makes the complete
DTMI dtmi:com:contoso:analytics:Room;1.
The next required property is called @type and needs to be set to Interface. The final required property
is called @context. @context determines how the interface is being processed by the system. This also
contains the version that must be used by the DTDL. In this example, it is defined as dtmi:dtdl:context;2,
which specifies version 2.
An interface does not necessarily need to contain content. An Interface could just be a description of a
digital twin within the model, as shown here:
{
"@id": "dtmi:com:contoso:door;1",
"@type": "Interface",
"displayName": "Door",
"@context": "dtmi:dtdl:context;2"
}
5. For that reason, the contents property is optional. The contents property allows you to use a collection
containing up to 300 different object types based on Property, Telemetry, Relationship,
and Component.
In this section, we learned that each digital twin is described by an interface. Then, we looked at the
structure of an interface. In the next section, we will learn about different object types, which are used
as the content of the interface.
Interface content
Interface content is all about defining the digital twin. We can identify the following object types, which
can be used as content:
Property
Telemetry
Relationship
Component
Let's look at each of these object types.
Properties
Properties define values within a digital twin. These values can be read-only or have read and write
states. Properties have a backing storage. This allows us to read the value of the property at any time.
However, the property can also be writable if we set the writable property to true. This allows us to
store a value in the property.
As you already know, each digital twin has a representation in the real world. This means that the
property describes the following:
State: This property describes a part of the state of a digital twin.
Synchronization: This property describes the synchronization between the digital twin and the
real-world object.
Every property contains synchronization information that facilitates the connection between the digital
twin and the real-world object. Since this is the same for all properties, it is not included in the definition
of the digital twin.
The following properties are required:
6. The following example shows a property called settemperature. This property has its read/write state
enabled. This means that it can synchronize with a real-world object:
{
"@type": "Property",
"name": "settemperature",
"schema": "double",
"writable": true
}
You will be using properties in most cases when you're designing a model in Azure Digital Twins. This
allows you to use its backing storage and gives you the ability to read and query values.
Telemetry
Telemetry is a stream of events and can be compared to events in C#. Since telemetry is mostly used in
combination with IoT devices, it can be compared to a stream of measurement values floating from the
IoT device. The reason for this is that most IoT devices are not capable of storing their measurement
values. Due to this, these measurement values will be lost. Telemetry allows us to view the latest value
of that measurement.
Data ingress, which is done through APIs, is mostly handled by combining properties and telemetry. This
allows us to real-time connect to the IoT device and provides its measurements, which we can then
store in the Azure Digital Twin.
Telemetry has the following required properties:
7. The following example shows the definition of telemetry for a IoT temperature device:
{
"@type": "Telemetry",
"name": "temperature",
"unit": "degreeCelcius",
"schema": "double"
}
Relationships
A relationship describes the link between two digital twins. This relationship can be used to build a
graph of digital twins. This is something you can see happening in the Azure Digital Twins Explorer tool.
Relationships have the following required properties:
The best way of explaining relationships is by looking at an example. In the following example, we have
two relationships defined to other interfaces:
{
"@id": "dtmi:com:contoso:room;1",
"@type": "Interface",
"displayName": "Room",
"contents": [
{
"@type": "Relationship",
"name": "floor",
"target":
"dtmi:com:contoso:floor;
1"
},
{
"@type": "Relationship",
"name": "inspectedby",
8. "target": "dtmi:com:contoso:employee;1"
}
],
"@context": "dtmi:dtdl:context;2"
}
The interface represents a room. A room belongs to a certain floor. Therefore, we have defined a
relationship called floor that targets the floor interface. The target is the digital win model
identifier property of the floor interface.
It is important to use a name that describes the relationship. The second relationship is a good example
of this. This relationship is called inspectedby and describes that the room is inspected by a facility
employee. These describing names will also help us quickly identify relationships when we're using the
Azure Digital Twins Explorer tool.
A relationship can also have properties. In the following example, we have specified a property that
describes the relationship between the facilitator employee and room with regards to the inspection
that was carried out:
{
"@type": "Relationship",
"name": "cleanedby",
"target":
"dtmi:com:contoso:empl
oyee;1",
"properties" : [
{
"@type":
"Property",
"name": "lastchecked",
"schema": "dateTime"
}
]
}
Component
Components allow us to group a set of related properties. While components reference an interface
that contains the relevant grouping, the interface does not require a separate identity. In other words,
the interface that's referenced by the component does not need to be instantiated or deleted
separately, since it only has meaning in the interface where the component is used.
9. In the following example, we have defined two interfaces. The first interface, Ceiling, is used to describe
the ceiling of a room. The second interface, Room, is used to describe a room and contains a component
that references the ceiling interface:
[{
"@id": "dtmi:com:contoso:ceiling;1",
"@type": "Interface",
"displayName": "Ceiling",
"contents": [
{
"@type": "Property",
"name": "height",
"schema": "float"
}
],
"@context":
"dtmi:dtdl:context;2"
},
{
"@id": "dtmi:com:contoso:room;1",
"@type": "Interface",
"displayName": "Room",
"contents": [
{
"@type": "Component",
"name": "ceiling",
"schema":
"dtmi:com:contoso:ceili
ng;1"
}
],
"@context":
"dtmi:dtdl:context;2"
}]
10. In principle, you will never instantiate a digital twin based on the ceiling interface. As soon as
we instantiate a digital twin based on the room, it will instantiate the ceiling as part of
the Room interface. Therefore, the ceiling is also deleted when the digital twin for the room
is deleted.
Here, we learned about the different object types we can use to define content in an interface. Content
is defined by schemas. In the next section, you will learn what a schema is.
Schemas
Schemas are used to describe the format of the data in a digital twin interface. This format can be
serialized using JSON. We can identify the following schema types:
In this section, you learned what a schema is, and which different types of schemas are used. In the
next section, we will discuss primitive schemas.
Primitive schemas
There is a clear list of available primitive schemas. These schemas can be directly applied as values. This
allows you to define values in all formats within the digital twin interface. The following table shows a
list of all the available primitives for version 2 of the DTDL:
RFC 3339 is a widely used standard for date-time formats. All primitive schemas related to date and time
use this standard. The exception is duration. duration uses the ISO 8601 standard, which represents the
format of dates and time in the Gregorian calendar.
11. The IEEE Standard for Floating-Point Arithmetic is used with
the double and float primitive schemas. UTF-8 is used for string. This is a widely used standard for
variable width encoded character formats.
With that, you have learned about primitive schemas. In the next section, you will learn about complex
schemas and their underlaying data types.
Complex schemas
Complex schemas allow us to model more complex data types that are based on primitive data types, as
mentioned by the primitive schemas. These complex data types support recursive up to five levels deep.
The following complex schemas are available:
Object
Enum
Array
Map
Complex schemas have required and optional properties. Required properties are properties that
define, in most cases, the purpose of the complex schema, while optional properties provide additional
information that describes the complex schema in more detail:
Each of these complex schemas will be described here, and their required properties will be explained.
Field
Fields are the basic data types for building a meta model using the complex Object schema type. A field
data type describes a named field in an Object. A field has required properties called name and schema.
The name property describes the name of the field, while the schema property describes the field type.
There are several other properties available.
A field type is always described by a primitive schema or a complex schema. Both were discussed earlier
in this chapter. Fields are always part of an object and are never used separately.
Object
An Object data type is used to describe a data type based on named fields. It contains
the @type and fields required properties. @type is set to Object, while fields contains the named fields
12. of the object. It allows up to 30 fields with a maximum depth of 5 levels. An example of an Object is as
follows:
{
"@type":"Object",
"name":"temperature",
"field":[
{
"name":"temperature",
"schema":"double"
}
]
}
Map
A Map is a complex schema that can be best compared to a dictionary in C#. It represents a list of key-
value pairs. Map contains two required properties that refer to the following schemas:
The following example defines a property in an interface called rooms. The property is using a complex
schema based on a Map that defines the room name as the key and the room temperature as the value:
{
"@type": "Property",
"name": "rooms",
"writable": true,
"schema": {
"@type":
"Map",
13. "mapKey": {
"name": "roomname",
"schema": "string"
},
"mapValue": {
"name": "roomtemperature",
"schema": "float"
}
}
}
This example could become even more complex if the value is a complex Object schema type with
multiple layers of values represented by primitive and complex schema types.
Array
This complex schema type can be compared to an array in C#. It represents an indexable data type. Each
value in the array is of the same primitive or complex schema. The required @type property needs to be
set to Array. The required elementSchema property contains the schema type that represents the value
definition.
The following example describes a property in a digital twin interface called EquipmentState. It is based
on an array of equipment that describes their state. The value of the array is based on a complex
schema, which describes the name, state, and the active radius of the equipment:
{
"@type": "Property",
"name": "equipmentstate",
"schema": {
"@type": "Array",
"elementSchema": {
"@type":"Object"
,
"name":"equipmentstate",
"field":[
{
"name":"name",
14. "schema":"string"
},
{
"name":"active",
"schema":"boolean"
},
{
"name":"radius",
"schema":"long"
}
]
}
}
}
This example can also be modeled in a different way. We could treat all the equipment as separate
digital twin instances in our digital twin. However, this completely depends on your data and model
requirements.
Enum
This complex schema type represents an enum, similar to what you would use in C#. It is a data type
with named labels mapped to values. An enum has a required @type property that needs to be set
to Enum. There are two more required properties that describe these labels and values:
15. In the following example, we have a property defined in the interface that describes a state. This
property is based on the complex Enum schema type and contains three labels, each of which are
represented by an integer value. These labels are inactive, active, and onhold:
{
"@type": "Property",
"name": "state",
"schema": {
"@type": "Enum",
"valueSchema": "integer",
"enumValues": [
{
"name": "inactive",
"enumValue": 1
},
{
"name": "active",
"enumValue": 2
},
{
"name": "onhold",
"enumValue": 3
}
]
}
}
In this section, we learned about complex schemas and their underlaying data types. In the next section,
we will learn about a special schema called the geospatial schema.
Geospatial schemas
16. Geospatial schemas allow us to model several different geographic types. These geospatial schemas are
based on GeoJSON. GeoJSON is a standard format for encoding several geographical data structures
using JSON.
The following geometry types are available:
The DTDL geospatial schema's DTMI can be derived from the DTDL term:
dtmi:standard:schema:geospatial:[DTDL term];2
The following example shows a Telemetry that defines the location of a vehicle. The location is defined
by a point:
{
"@type": "Telemetry",
"name": "vehiclelocation",
"schema": "point"
}
This allows us to send a message containing the longitude and latitude coordinates of the vehicle to a
digital twin instance using a model containing this object type.
IMPORTANT NOTE
Geospatial types cannot be used in Property schemas. The reason for this is that geospatial types are
based on arrays, which are can't be used in a Property schema. However, you can use geospatial types in
the Telemetry schema.
In this section, we learned about geospatial schemas. In the next section, we will learn about semantic
types.
Semantic types
Semantic types are specific types of annotations that give meaning to a behavior. This allows machine
learning and other computational systems to understand and reason about this behavior. This reasoning
allows these systems to interpret semantic types into something meaningful. Think of using
the Distance semantic type in a meta model called Silo. Instead of handling the behavior as a schema, it
can be reasoned as the distance to that Silo.
17. The list of semantic types is rather large and can be found via one of the links in the Further
reading section of this chapter.
With that, you have learned what semantic types are and how they are used. In the last part of
this chapter, we will learn about how to validate a model.
Validating a model
It is important to prevent failures by validating a model upfront before the model is uploaded to the
Azure Digital Twins instance via an API, or via the Azure Digital Twins Explorer tool. Microsoft provides a
.NET client-side DTDL parser library to support this process.
There are two ways to use the validator. Since the parser library is available as a NuGet package
called Microsoft.Azure.DigitalTwins.Parser, you can create your own custom parser or make it part of a
service that dynamically uploads models to your Azure Digital Twins instance.
Microsoft also provides a command-line parser example as a .NET project. This project can be
downloaded from https://docs.microsoft.com/en-us/samples/azure-samples/dtdl-validator/dtdl-
validator/.
Download the ZIP file and extract the contents of it to c:githubDTDL_Validator. Start Visual Studio, as
shown in the following screenshot:
1. Open the DTDLValidator.sln solution, which can be found in
the C:GithubDTDL_ValidatorDTDLValidator-Sample folder.
2. Set the build to Release.
3. Right-click the solution and select Build Solution:
Figure 3.1 – Creating the command-line validator executable
We want to use this DTDL parser in our command line in any folder. Therefore, we need to add the path
to the DTDL parser in the Path environment variable.
Open the window settings of your computer. Search for system environment variables. This will
open SystemProperties with the Advanced tab selected. Execute the following steps, as shown in the
following screenshot:
1. Select Environment Variables. This will open a new dialog for Environment Variables.
18. 2. Double-click on the Path user variable. This will open a new dialog for Edit environment
variable.
3. Select New.
4. Add the path to the validator in the new row. The path to the validator is the folder that
the DTDLValidator.exe file can found be. In my case, this
is C:GithubDTDL_ValidatorDTDLValidator- Sample
DTDLValidatorbinReleasenetcoreapp3.1.
5. Click OK to close Environment Variables.
6. Click OK to close Edit environment variable.
7. Click OK to close System Properties:
Figure 3.2 – Adding the path of the validator to the environment variables
Next, we will test a DTDL file. Perform the following steps:
Open File Explorer and create a folder. In my case, I created a folder
called DTDL under C:GitHub.
Create a file with a json extension that contains the JSON payload of the Digital Twin Interface
example, called dtmi:com:contoso:room;1, and place it in that folder.
19. Open a command line. Make sure to run it as Administrator.
Change the folder in the command line to C:GithubDTDL using the cd
C:githubdtdl command.
Run the DTDLValidator command. This will validate all the DTDL files that are found in that
folder:
Figure 3.3 – Testing the validator to validate a DTDL file
20. The result of DTDLValidator can be seen in the preceding screenshot. We can see that it has validated a
single file in the directory. The file has been validated.
Summary
In this chapter, we explored the Digital Twins Definition Language and how it is structured. We looked at
its interface and its content, such as its properties, telemetry, relationships, and components. This
content relies heavily on schemas. Due to this, you learned about primitive and complex schemas and
viewed examples that show how to use them. In the upcoming chapters, we will start using this basic
understanding to create our first models, digital twins, and many other examples around the Azure
Digital Twins service.
In the next chapter, we will learn how to manage models with Azure Digital Twins. These models are
based on the Digital Twins Definition Language, which we learned about in this chapter.
Questions
1. What is the maximum depth allowed for a field in an Object?
A. One level
B. Three levels
C. Five levels
2. What specific data types can be used to allow machine learning to reason about a type?
D. Property
E. Semantic
F. Telemetry
3. Why is it important to validate a model?
G. You can prevent failures when uploading the model
H.It makes it easier to upload the model
I.The validation process creates an overview of your
model Further reading
The Digital Twins Definition Language is still something that will change in the future. New versions of
DTDL will arise. The following links provide more information about DTDL, along with Azure Digital
Twins:
Understanding twin models in Azure Digital Twins: https://docs.microsoft.com/en-
us/azure/digital-twins/concepts-models
Digital Twins Definition Language (DTDL): https://github.com/Azure/opendigitaltwins-
dtdl/blob/master/DTDL/v2/dtdlv2.md
21. Parsing and validating models using the DTDL parser library: https://docs.microsoft.com/en-
us/azure/digital-twins/how-to-parse-models