DTDL, a Digital Twin Definition Language, é uma forma baseada em JSON de descrever do que um gêmeo digital é feito: a telemetria que ele emite, as propriedades que mantém, os comandos que aceita e como se relaciona com outros gêmeos. Neste artigo você vai aprender como os modelos DTDL são estruturados, ler um exemplo completo e ver como mapear esse modelo para topics MQTT, para que dispositivos e aplicações de gêmeo compartilhem um contrato único e claro.
Para a visão geral de onde os modelos se encaixam, veja nosso guia completo sobre gêmeo digital.
O Que É DTDL e Por Que Ela Existe
Quando dez equipes constroem gêmeos de forma independente, cada uma inventa sua própria maneira de dizer "esta bomba tem uma vazão em litros por minuto e um comando de partida". A DTDL padroniza essa descrição. Ela é uma linguagem aberta publicada pela Microsoft, baseada em JSON-LD e usada pelo Azure Digital Twins e pelo IoT Plug and Play, mas nada na linguagem em si prende você a uma nuvem. Um arquivo DTDL é apenas um documento que descreve um tipo de ativo; você pode usá-lo para gerar código, validar payloads, construir interfaces ou documentar contratos de topics.
A linguagem passou por várias versões; a DTDL v3 é a atual, e a v2 ainda aparece bastante em projetos existentes. A especificação oficial está no repositório da DTDL no GitHub.
Os Blocos de Construção de um Modelo DTDL
Tudo em DTDL é definido dentro de uma Interface. Uma interface tem um identificador e uma lista de conteúdos, cada um sendo de um destes tipos de elemento:
| Elemento | O que descreve | Exemplo |
|---|---|---|
| Telemetry | Um fluxo de medições, não armazenado como estado | Temperatura a cada segundo |
| Property | Um valor de estado, opcionalmente gravável | Versão de firmware, setpoint |
| Command | Uma operação que o gêmeo pode ser solicitado a executar | Partir, parar, zerar contador |
| Component | Reuso de outra interface dentro desta | Uma bomba contendo uma interface de motor |
| Relationship | Um vínculo com outro gêmeo | Bomba isPartOf estação |
Cada modelo e elemento tem um DTMI (Digital Twin Model Identifier), como dtmi:com:example:Pump;1. O número final é a versão. Quando você altera um modelo de forma incompatível, incrementa a versão em vez de editá-lo no lugar.
Telemetria vs Propriedade
Esta é a distinção que as equipes mais erram. Telemetria é um fluxo de eventos: cada amostra importa e não há um "valor atual" armazenado pela plataforma do gêmeo. Propriedades são estado: o gêmeo sempre tem um valor atual, e uma propriedade gravável pode ser definida a partir da nuvem (um valor desejado), com o dispositivo reportando de volta seu valor real.
Regra prática: se um novo visualizador precisa ver o dado imediatamente ao carregar, é uma propriedade; se ele só importa como série ao longo do tempo, é telemetria.
Um Exemplo Completo de DTDL
Aqui está uma interface DTDL v3 para uma bomba centrífuga:
{
"@context": "dtmi:dtdl:context;3",
"@id": "dtmi:com:example:Pump;1",
"@type": "Interface",
"displayName": "Centrifugal Pump",
"contents": [
{
"@type": ["Telemetry", "VolumeFlowRate"],
"name": "flow",
"schema": "double",
"unit": "litrePerSecond"
},
{
"@type": ["Telemetry", "Pressure"],
"name": "dischargePressure",
"schema": "double",
"unit": "bar"
},
{
"@type": "Property",
"name": "running",
"schema": "boolean"
},
{
"@type": "Property",
"name": "speedSetpoint",
"schema": "double",
"writable": true
},
{
"@type": "Property",
"name": "firmwareVersion",
"schema": "string"
},
{
"@type": "Command",
"name": "resetRunHours"
},
{
"@type": "Relationship",
"name": "isPartOf",
"target": "dtmi:com:example:PumpingStation;1"
}
]
}
Tipos semânticos como VolumeFlowRate e unidades como litrePerSecond vêm da extensão de tipos quantitativos da DTDL. Eles permitem que as ferramentas exibam as unidades corretamente sem adivinhar. Consulte a especificação para ver a lista exata de tipos semânticos e unidades válidos na versão que você usa.
Mapeando DTDL para Topics MQTT
A DTDL descreve o que um gêmeo contém; ela não diz como os dados trafegam. O MQTT é um transporte natural, e um mapeamento limpo transforma seu modelo DTDL em um contrato de topics. Uma convenção prática:
| Elemento DTDL | Topic MQTT | Retido | QoS |
|---|---|---|---|
Telemetry flow |
<asset>/telemetry (JSON com todos os campos de telemetria) |
Não | 0 |
| Property (somente leitura) | <asset>/properties/reported |
Sim | 1 |
| Valor desejado de propriedade gravável | <asset>/properties/desired |
Sim | 1 |
Command resetRunHours |
<asset>/commands/resetRunHours |
Não | 1 |
| Resposta do comando | <asset>/commands/resetRunHours/response |
Não | 1 |
| Relationship | Armazenado no modelo ou no registro, não trafega | n/a | n/a |
Sendo <asset> um caminho ISA-95 como acme/site1/water/station3/pump2 (pense na estação elevatória de uma companhia de saneamento), um visualizador pode assinar acme/site1/water/# e saber, a partir do modelo, como interpretar cada mensagem.
Por que combinar a telemetria em uma mensagem por ativo? Publicar um topic por campo de telemetria multiplica o número de mensagens sem acrescentar informação, e a maioria dos consumidores quer todos os campos com o mesmo timestamp. As propriedades se beneficiam de retained messages para que os visualizadores do gêmeo recebam o estado atual instantaneamente; o tutorial de gêmeo digital com retained MQTT mostra isso na prática.
Validando Payloads Contra um Modelo DTDL
Depois de ter um modelo, use-o. Uma pequena verificação em Python pode rejeitar telemetria que não corresponde à interface antes que ela polua seu histórico:
import json
import paho.mqtt.client as mqtt
with open("pump.json", encoding="utf-8") as f:
model = json.load(f)
TYPE_MAP = {"double": (int, float), "boolean": bool, "string": str, "integer": int}
telemetry = {
c["name"]: c["schema"]
for c in model["contents"]
if "Telemetry" in (c["@type"] if isinstance(c["@type"], list) else [c["@type"]])
}
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe("connectmq/demo/d41f/+/+/+/+/telemetry")
def on_message(client, userdata, msg):
data = json.loads(msg.payload)
for name, schema in telemetry.items():
if name not in data:
print(f"{msg.topic}: missing {name}")
elif not isinstance(data[name], TYPE_MAP[schema]):
print(f"{msg.topic}: {name} should be {schema}")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="dtdl-validator-d41f")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883)
client.loop_forever()
Teste publicando uma mensagem de exemplo no servidor MQTT público (gratuito), que serve para testes e protótipos, não para dados de produção:
mosquitto_pub -h broker.connectmq.com -p 1883 -i dtdl-pub-d41f \
-t "connectmq/demo/d41f/acme/site1/station3/pump2/telemetry" \
-m '{"flow": 12.4, "dischargePressure": "4.1"}'
O validador aponta dischargePressure como string em vez de double, o tipo de bug que, de outra forma, só aparece semanas depois como um gráfico quebrado.
Checklist de Modelagem DTDL
- Uma interface por tipo de ativo, não por instância de ativo.
- Telemetria para fluxos, propriedades para estado, comandos para ações.
- Use componentes para partes reutilizáveis, como motores ou sensores.
- Inclua unidades por meio de tipos semânticos sempre que possível.
- Versione os DTMIs e nunca quebre uma versão publicada.
- Documente o mapeamento MQTT ao lado do modelo, no mesmo repositório.
- Valide os payloads na ingestão, não apenas na interface.
DTDL Comparada com Outros Modelos de Gêmeo
A DTDL não é a única opção. A Asset Administration Shell, do universo da Indústria 4.0, foca em submodelos padronizados para ativos industriais e é comum na manufatura europeia; veja Asset Administration Shell explicada. O Eclipse Ditto usa seus próprios "things" em JSON com attributes e features. Muitas equipes também usam um JSON Schema simples por tipo de ativo. O que mais importa é ter um modelo explícito e um mapeamento documentado para o transporte, papel que a DTDL cumpre bem. Para ver como a camada de modelo se posiciona ao lado de mensageria, estado e visualização, veja arquitetura de gêmeo digital.
Rodando Seu Gêmeo Baseado em DTDL no ConnectMQ
A DTDL define o contrato; você ainda precisa de um transporte confiável. O ConnectMQ é um broker MQTT gerenciado com suporte a MQTT 3.1.1 e 5.0, retained messages para propriedades, TLS na porta 8883 para dispositivos e WSS na 8084 para gêmeos no navegador. Validação de modelos, geração de código e grafos de gêmeos rodam nas suas próprias ferramentas, conectadas ao ConnectMQ como clientes MQTT comuns. Crie um broker no plano Serverless gratuito em app.connectmq.com, sem cartão de crédito, e publique sua primeira telemetria no formato DTDL em minutos.
Perguntas frequentes
A DTDL serve apenas para o Azure?
Não. A DTDL é uma linguagem aberta baseada em JSON-LD. O Azure Digital Twins a usa nativamente, mas você pode usar modelos DTDL com qualquer transporte, incluindo MQTT em qualquer broker.
Qual é a diferença entre uma propriedade e uma telemetria em DTDL?
Uma propriedade é estado com um valor atual, opcionalmente gravável; a telemetria é um fluxo de medições em que cada amostra importa, mas nenhum valor atual é armazenado.
Como representar comandos DTDL sobre MQTT?
Publique o comando em um topic de comando não retido com QoS 1 e um correlation ID, e faça o dispositivo publicar o resultado em um topic de resposta. As propriedades response topic e correlation data do MQTT 5 suportam isso diretamente.
Qual versão de DTDL devo usar?
Use a DTDL v3 em novos projetos, a menos que alguma ferramenta da qual você depende só suporte a v2.



