Guia de modelagem do IoT Plug and Play

No núcleo do IoT Plug and Play, há um modelo de dispositivo que descreve as funcionalidades de um aplicativo habilitado para IoT Plug and Play. Esse modelo é estruturado como um conjunto de interfaces que definem:

  • Propriedades que representam o estado somente leitura ou gravável de um dispositivo ou outra entidade. Por exemplo, um número de série do dispositivo pode ser uma propriedade somente leitura e uma temperatura de destino em um termostato pode ser uma propriedade gravável.
  • Campos de telemetria, que definem os dados emitidos por um dispositivo, sejam dados de um fluxo regular de leituras de sensor, um erro ocasional ou uma mensagem informativa.
  • Comandos que descrevem uma função ou operação que pode ser feita em um dispositivo. Por exemplo, um comando pode reinicializar um gateway ou tirar uma foto usando uma câmera remota.

Para saber mais sobre como o IoT Plug and Play usa modelos de dispositivo, consulte o Guia do desenvolvedor do dispositivo IoT Plug and Play e o Guia do desenvolvedor de serviços IoT Plug and Play.

Para definir um modelo, use DTDL (Linguagem de Definição de Gêmeos Digitais). A DTDL usa uma variante JSON chamada JSON-LD. O trecho de código a seguir mostra o modelo para um dispositivo termostato:

  • Tem uma ID de modelo exclusiva: dtmi:com:example:Thermostat;1.
  • Envia a telemetria de temperatura.
  • Tem uma propriedade gravável para definir a temperatura alvo.
  • Tem uma propriedade de somente leitura para reportar a temperatura máxima desde a última reinicialização.
  • Responde a um comando que solicita as temperaturas máximas, mínimas e médias em um período de tempo.
{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:Thermostat;1",
  "@type": "Interface",
  "displayName": "Thermostat",
  "description": "Reports current temperature and provides desired temperature control.",
  "contents": [
    {
      "@type": [
        "Telemetry",
        "Temperature"
      ],
      "name": "temperature",
      "displayName": "Temperature",
      "description": "Temperature in degrees Celsius.",
      "schema": "double",
      "unit": "degreeCelsius"
    },
    {
      "@type": [
        "Property",
        "Temperature"
      ],
      "name": "targetTemperature",
      "schema": "double",
      "displayName": "Target Temperature",
      "description": "Allows to remotely specify the desired target temperature.",
      "unit": "degreeCelsius",
      "writable": true
    },
    {
      "@type": [
        "Property",
        "Temperature"
      ],
      "name": "maxTempSinceLastReboot",
      "schema": "double",
      "unit": "degreeCelsius",
      "displayName": "Max temperature since last reboot.",
      "description": "Returns the max temperature since last device reboot."
    },
    {
      "@type": "Command",
      "name": "getMaxMinReport",
      "displayName": "Get Max-Min report.",
      "description": "This command returns the max, min and average temperature from the specified time to the current time.",
      "request": {
        "name": "since",
        "displayName": "Since",
        "description": "Period to return the max-min report.",
        "schema": "dateTime"
      },
      "response": {
        "name": "tempReport",
        "displayName": "Temperature Report",
        "schema": {
          "@type": "Object",
          "fields": [
            {
              "name": "maxTemp",
              "displayName": "Max temperature",
              "schema": "double"
            },
            {
              "name": "minTemp",
              "displayName": "Min temperature",
              "schema": "double"
            },
            {
              "name": "avgTemp",
              "displayName": "Average Temperature",
              "schema": "double"
            },
            {
              "name": "startTime",
              "displayName": "Start Time",
              "schema": "dateTime"
            },
            {
              "name": "endTime",
              "displayName": "End Time",
              "schema": "dateTime"
            }
          ]
        }
      }
    }
  ]
}

O modelo do termostato tem uma única interface. Os exemplos posteriores neste artigo mostram modelos mais complexos que usam componentes e herança.

Este artigo descreve como projetar e criar seus próprios modelos e abrange tópicos como tipos de dados, estrutura de modelo e ferramentas.

Para saber mais, confira a especificação de Linguagem de Definição de Gêmeos Digitais v2.

Observação

Atualmente, o IoT Central dá suporte ao DTDL v2 com uma extensão do IoT Central.

Estrutura do modelo

Propriedades, telemetria e comandos são agrupados em interfaces. Esta seção descreve como usar interfaces para descrever modelos simples e complexos usando componentes e herança.

IDs de modelo

Cada interface tem um DTMI (Identificador de Modelo de Gêmeo Digital) exclusivo. Modelos complexos usam DTMIs para identificar componentes. Os aplicativos podem usar DTMIs que os dispositivos enviam para localizar definições de modelo em um repositório.

As DTMIs devem usar a seguinte convenção de nomenclatura:

  • O prefixo do DTMI é dtmi:.
  • O sufixo do DTMI é o número da versão do modelo, como ;2.
  • O corpo do DTMI é mapeado para a pasta e o arquivo no repositório do modelo,em que o modelo está armazenado. O número da versão é parte do nome do arquivo.

Por exemplo, o modelo identificado pelo DTMI dtmi:com:Example:Thermostat;2 é armazenado no arquivo DTMI/com/example/thermostat-2.jsno.

O trecho de código a seguir mostra o esboço de uma definição de interface com seu DTMI exclusivo:

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:Thermostat;2",
  "@type": "Interface",
  "displayName": "Thermostat",
  "description": "Reports current temperature and provides desired temperature control.",
  "contents": [
    ...
  ]
}

Sem componentes

Um modelo simples, como o termostato mostrado anteriormente, não usa componentes incorporados ou em cascata. A telemetria, propriedades e comandos são definidos no nó contents da interface.

O exemplo a seguir mostra parte de um modelo simples que não usa componentes:

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:Thermostat;1",
  "@type": "Interface",
  "displayName": "Thermostat",
  "description": "Reports current temperature and provides desired temperature control.",
  "contents": [
    {
      "@type": [
        "Telemetry",
        "Temperature"
      ],
      "name": "temperature",
      "displayName": "Temperature",
      "description": "Temperature in degrees Celsius.",
      "schema": "double",
      "unit": "degreeCelsius"
    },
    {
      "@type": [
        "Property",
...

Ferramentas como o Explorer da Internet das Coisas do Azure e o designer de modelo de dispositivo IoT Central rotulam uma interface autônoma, por exemplo, o termostato como um componente padrão.

A captura de tela a seguir mostra como o modelo é exibido na ferramenta do Explorer da Internet das Coisas do Azure:

Captura de tela que mostra o componente padrão na ferramenta do Explorer da Internet das Coisas do Azure.

A captura de tela a seguir mostra como o modelo é exibido como sendo o componente padrão no designer de modelo de dispositivo IoT Central. Selecione Exibir identidade para ver o DTMI do modelo:

Captura de tela mostrando o modelo do termostato na ferramenta de designer de modelo de dispositivo IoT Central.

A ID do modelo é armazenada em uma propriedade do dispositivo gêmeo, como mostra a captura de tela a seguir:

Captura de tela da ferramenta do Explorer da Internet das Coisas do Azure que mostra a ID do modelo em uma propriedade de gêmeo digital.

Um modelo de DTDL sem componentes é uma simplificação útil para um dispositivo ou um módulo IoT Edge com um único conjunto de telemetria, propriedades e comandos. Um modelo que não usa componentes facilita a migração de um dispositivo ou módulo existente para ser um dispositivo ou módulo IoT Plug and Play. Consegue-se criar um modelo DTDL que descreve o dispositivo ou módulo sem a necessidade de definir quaisquer componentes.

Dica

Um módulo pode ser um módulo de dispositivo ou um módulo IoT Edge.

Reutilizar

Há duas maneiras de reutilizar as definições de interface.

  • Use vários componentes em um modelo para fazer referência a outras definições de interface.
  • Use a herança para estender as definições de interface existentes.

Vários componentes

Os componentes permitem criar uma interface de modelo como uma montagem de outras interfaces.

Por exemplo, a interface Termostato é definida como um modelo. Você pode incorporar essa interface como um ou mais componentes ao definir o modelo de Controlador de Temperatura. No exemplo a seguir, esses componentes são chamados thermostat1 e thermostat2.

Para um modelo DTDL com vários componentes, há duas ou mais seções de componentes. Cada seção tem um @type definido como Component, e se refere explicitamente a um esquema, conforme mostrado no trecho a seguir:

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:TemperatureController;1",
  "@type": "Interface",
  "displayName": "Temperature Controller",
  "description": "Device with two thermostats and remote reboot.",
  "contents": [
    {
      "@type": [
        "Telemetry",
        "DataSize"
      ],
      "name": "workingSet",
      "displayName": "Working Set",
      "description": "Current working set of the device memory in KiB.",
      "schema": "double",
      "unit": "kibibyte"
    },
    {
      "@type": "Property",
      "name": "serialNumber",
      "displayName": "Serial Number",
      "description": "Serial number of the device.",
      "schema": "string"
    },
    {
      "@type": "Command",
      "name": "reboot",
      "displayName": "Reboot",
      "description": "Reboots the device after waiting the number of seconds specified.",
      "request": {
        "name": "delay",
        "displayName": "Delay",
        "description": "Number of seconds to wait before rebooting the device.",
        "schema": "integer"
      }
    },
    {
      "@type" : "Component",
      "schema": "dtmi:com:example:Thermostat;1",
      "name": "thermostat1",
      "displayName": "Thermostat One",
      "description": "Thermostat One of Two."
    },
    {
      "@type" : "Component",
      "schema": "dtmi:com:example:Thermostat;1",
      "name": "thermostat2",
      "displayName": "Thermostat Two",
      "description": "Thermostat Two of Two."
    },
    {
      "@type": "Component",
      "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1",
      "name": "deviceInformation",
      "displayName": "Device Information interface",
      "description": "Optional interface with basic device hardware information."
    }
  ]
}

Este modelo tem três componentes definidos na seção conteúdo: dois componentes Thermostat e um componente DeviceInformation. A seção conteúdo também inclui propriedades, telemetria e definições de comando.

As capturas de tela a seguir mostram como esse modelo aparece no IoT Central. As propriedades, telemetria e definições de comando no controlador de temperatura aparecem no Componente padrãode nível superior. As propriedades, telemetria e definições de comando para cada termostato aparecem nas definições de componente:

Captura de tela mostrando o modelo de dispositivo do controlador de temperatura no IoT Central.

Captura de tela mostrando os componentes do termostato no modelo de dispositivo do controlador de temperatura no IoT Central.

Para saber como escrever o código do dispositivo que interage com componentes, consulte o Guia do desenvolvedor de dispositivos IoT Plug and Play.

Para saber como escrever o código de serviços que interage com os componentes em um dispositivo, consulte a Guia do desenvolvedor de serviços do IoT Plug and Play.

Herança

A herança permite a reutilização dos recursos em interfaces base para estender os recursos de uma interface. Por exemplo, vários modelos de dispositivo podem compartilhar recursos comuns, como um número de série:

Diagrama que mostra um exemplo de herança em um modelo de dispositivo. Uma interface do termostato e uma interface do Controlador de Fluxo compartilham recursos de uma interface base.

O trecho a seguir mostra um modelo DTML que usa uma extends palavra-chave para definir a relação de herança mostrada no diagrama anterior:

[
  {
    "@context": "dtmi:dtdl:context;2",
    "@id": "dtmi:com:example:Thermostat;1",
    "@type": "Interface",
    "contents": [
      {
        "@type": "Telemetry",
        "name": "temperature",
        "schema": "double",
        "unit": "degreeCelsius"
      },
      {
        "@type": "Property",
        "name": "targetTemperature",
        "schema": "double",
        "unit": "degreeCelsius",
        "writable": true
      }
    ],
    "extends": [
      "dtmi:com:example:baseDevice;1"
    ]
  },
  {
    "@context": "dtmi:dtdl:context;2",
    "@id": "dtmi:com:example:baseDevice;1",
    "@type": "Interface",
    "contents": [
      {
        "@type": "Property",
        "name": "SerialNumber",
        "schema": "double",
        "writable": false
      }
    ]
  }
]

A captura de tela a seguir mostra esse modelo no ambiente de modelo de dispositivo IoT Central:

Captura de tela mostrando a herança de interface no IoT Central.

Quando se escreve o código do dispositivo ou do serviço, o código não precisa fazer nada especial para tratar as interfaces herdadas. No exemplo mostrado nesta seção, o código do dispositivo relata o número de série como se fosse parte da interface termostato.

Dicas

Pode-se combinar componentes e herança ao criar um modelo. O diagrama a seguir mostra um modelo thermostat, herdado de uma interface baseDevice. A interface baseDevice tem um componente que, por sua vez, herda de outra interface:

Diagrama mostrando um modelo que usa componentes e herança.

O seguinte snippet mostra um modelo DTML que usa as palavras-chave extends e component para definir a relação de herança e o uso do componente mostrados no diagrama anterior:

[
  {
    "@context": "dtmi:dtdl:context;2",
    "@id": "dtmi:com:example:Thermostat;1",
    "@type": "Interface",
    "contents": [
      {
        "@type": "Telemetry",
        "name": "temperature",
        "schema": "double",
        "unit": "degreeCelsius"
      },
      {
        "@type": "Property",
        "name": "targetTemperature",
        "schema": "double",
        "unit": "degreeCelsius",
        "writable": true
      }
    ],
    "extends": [
      "dtmi:com:example:baseDevice;1"
    ]
  },
  {
    "@context": "dtmi:dtdl:context;2",
    "@id": "dtmi:com:example:baseDevice;1",
    "@type": "Interface",
    "contents": [
      {
        "@type": "Property",
        "name": "SerialNumber",
        "schema": "double",
        "writable": false
      },
      {
        "@type" : "Component",
        "schema": "dtmi:com:example:baseComponent;1",
        "name": "baseComponent"
      }
    ]
  }
]

Tipos de dados

Use tipos de dados para definir telemetria, propriedades e parâmetros de comando. Os tipos de dados podem ser primitivos ou complexos. Os tipos de dados complexos usam tipos primitivos ou outros tipos complexos. A profundidade máxima para tipos complexos é de cinco níveis.

Tipos primitivos

A tabela a seguir mostra o conjunto de tipos primitivos que podem ser usados:

Tipo primitivo Descrição
boolean Um valor booliano
date Data completa, conforme definido na seção 5.6 da RFC 3339
dateTime Data e hora conforme definido no RFC 3339
double Ponto flutuante de 8 bytes IEEE
duration Duração no formato ISO 8601
float Ponto flutuante de 4 bytes IEEE
integer Inteiro de 4 bytes com sinal
long Inteiro de 8 bytes com sinal
string String UTF8
time Data completa, conforme definido na seção 5.6 da RFC 3339

O trecho a seguir mostra um exemplo de definição de telemetria que usa o tipo double no campo schema:

{
  "@type": "Telemetry",
  "name": "temperature",
  "displayName": "Temperature",
  "schema": "double"
}

Tipos de dados complexos

Os tipos de dados complexos são de matriz, enumeração, mapa, objeto ou um dos tipos geoespaciais.

matrizes

Uma matriz é um tipo de dados Indexável em que todos os elementos são do mesmo tipo. O tipo de elemento pode ser um tipo primitivo ou complexo.

O trecho a seguir mostra um exemplo de definição de telemetria que usa o tipo Array no campo schema. Os elementos da matriz são boleanos:

{
  "@type": "Telemetry",
  "name": "ledState",
  "schema": {
    "@type": "Array",
    "elementSchema": "boolean"
  }
}

Enumerações

Uma enumeração descreve um tipo com um conjunto de rótulos nomeados que são mapeados para valores. Os valores podem ser inteiros ou strings, mas os rótulos são sempre strings.

O trecho a seguir mostra um exemplo de definição de telemetria que usa o tipo Enum no campo schema. Os valores nas enumerações são inteiros:

{
  "@type": "Telemetry",
  "name": "state",
  "schema": {
    "@type": "Enum",
    "valueSchema": "integer",
    "enumValues": [
      {
        "name": "offline",
        "displayName": "Offline",
        "enumValue": 1
      },
      {
        "name": "online",
        "displayName": "Online",
        "enumValue": 2
      }
    ]
  }
}

Mapas

Um mapa é um tipo com pares de chave-valor em que todos os valores são do mesmo tipo. A chave em um mapa deve ser string. Os valores em um mapa podem ser de qualquer tipo, incluindo outro tipo complexo.

O trecho a seguir mostra um exemplo de definição de propriedade que usa o tipo Map no campo schema. Os valores em um mapa são string:

{
  "@type": "Property",
  "name": "modules",
  "writable": true,
  "schema": {
    "@type": "Map",
    "mapKey": {
      "name": "moduleName",
      "schema": "string"
    },
    "mapValue": {
      "name": "moduleState",
      "schema": "string"
    }
  }
}

Objetos

Um tipo objeto é composto de campos nomeados. Os tipos de campos em um mapa de objeto podem ser tipos primitivos ou complexos.

O trecho a seguir mostra um exemplo de definição de telemetria que usa o tipo Object no campo schema. Os campos em um objeto são dateTime, duration e string:

{
  "@type": "Telemetry",
  "name": "monitor",
  "schema": {
    "@type": "Object",
    "fields": [
      {
        "name": "start",
        "schema": "dateTime"
      },
      {
        "name": "interval",
        "schema": "duration"
      },
      {
        "name": "status",
        "schema": "string"
      }
    ]
  }
}

Tipos geoespaciais

A DTDL fornece um conjunto de tipos geoespaciais, com base no GeoJSON, para modelagem de estruturas de dados geográficos: point, multiPoint, lineString, multiLineString, polygon e multiPolygon. Esses tipos são estruturas aninhadas predefinidas de matrizes, objetos e enumerações.

O trecho a seguir mostra um exemplo de definição de telemetria que usa o tipo point no campo schema:

{
  "@type": "Telemetry",
  "name": "location",
  "schema": "point"
}

Como os tipos geoespaciais são baseados em matriz, no momento eles não podem ser usados em definições de propriedade.

Tipos semânticos

O tipo de dado de uma definição de propriedade ou de telemetria especifica o formato dos dados que um dispositivo troca com um serviço. O tipo semântico fornece informações sobre telemetria e propriedades que um aplicativo pode usar para determinar como processar ou exibir um valor. Cada tipo semântico tem uma ou mais unidades associadas. Por exemplo, Celsius e Fahrenheit são unidades para o tipo semântico de temperatura. Os dashboards e análises do IoT Central podem usar informações do tipo semântico para determinar como representar graficamente os valores de telemetria ou de propriedade e as unidades de exibição. Para saber como usar o analisador de modelo para ler os tipos semânticos, consulte Conheça o analisador de modelo de gêmeos digitais.

O trecho a seguir mostra um exemplo da definição de telemetria que inclui informações do tipo semântico. O tipo semântico Temperature é adicionado à matriz @type, e o valor unit é uma das unidades degreeCelsius, válidas para o tipo semântico:

{
  "@type": [
    "Telemetry",
    "Temperature"
  ],
  "name": "temperature",
  "schema": "double",
  "unit": "degreeCelsius"
}

Localização

Aplicativos como IoT Central usam informações no modelo para criar dinamicamente uma IU (interface do usuário) em torno dos dados trocados com um dispositivo IoT Plug and Play. Por exemplo, blocos em um dashboard podem exibir nomes e descrições de telemetria, propriedades e comandos.

Os campos opcionais description e displayName no modelo contêm cadeias de caracteres a serem usadas em uma IU. Esses campos podem conter cadeias de caracteres localizadas que um aplicativo pode usar para renderizar uma IU localizada.

O trecho a seguir mostra um exemplo de definição de telemetria de temperatura que inclui cadeias de caracteres localizadas:

{
  "@type": [
    "Telemetry",
    "Temperature"
  ],
  "description": {
    "en": "Temperature in degrees Celsius.",
    "it": "Temperatura in gradi Celsius."
  },
  "displayName": {
    "en": "Temperature",
    "it": "Temperatura"
  },
  "name": "temperature",
  "schema": "double",
  "unit": "degreeCelsius"
}

A adição de cadeias de caracteres localizadas é opcional. O exemplo a seguir tem apenas uma única linguagem padrão:

{
  "@type": [
    "Telemetry",
    "Temperature"
  ],
  "description": "Temperature in degrees Celsius.",
  "displayName": "Temperature",
  "name": "temperature",
  "schema": "double",
  "unit": "degreeCelsius"
}

Ciclo de vida e ferramentas

Os quatro estágios do ciclo de vida de um modelo de dispositivo são criação, publicação, uso e controle de versão:

Autor

Os modelos de dispositivo DTML são documentos JSON que podem ser criados usando um editor de texto. No entanto, no IoT Central, pode-se usar o ambiente de GUI (interface gráfica do usuário) do modelo de dispositivo para criar um modelo DTML. No IoT Central se pode:

  • Criar interfaces que definem propriedades, telemetria e comandos.
  • Usar componentes para juntar várias interfaces.
  • Definir relações de herança entre interfaces.
  • Importar e exportar arquivos de modelos DTML.

Para saber mais, consulte Definir um novo tipo de dispositivo IoT em seu aplicativo do Azure IoT Central.

Há uma extensão de criação DTDL para VS Code.

Para instalar a extensão DTDL para VS Code, vá para o Editor DTDL para Visual Studio Code. Você também pode pesquisar por DTDL na exibição Extensões no VS Code.

Quando você tiver instalado a extensão, use-a como auxílio para criar arquivos de modelo DTDL no VS Code:

  • A extensão fornece validação de sintaxe em arquivos de modelo DTDL, realçando erros conforme mostrado na seguinte captura de tela:

    Captura de tela que mostra a validação do modelo DTDL no VS Code.

  • Use o IntelliSense e o preenchimento automático quando estiver editando modelos DTDL:

    Captura de tela que mostra o IntelliSense para modelos DTDL no VS Code.

  • Crie uma nova interface DTDL. O comando DTDL: Create Interface cria um arquivo JSON com uma nova interface. A interface inclui definições de telemetria, propriedade e comando de exemplo.

Usar

Aplicativos como o IoT Central usam modelos de dispositivo. No IoT Central, o modelo faz parte do modelo de dispositivo que descreve os recursos do dispositivo. O IoT Central usa o modelo de dispositivo para criar dinamicamente uma IU (interface do usuário) para o dispositivo, incluindo dashboards e análises.

Observação

O IoT Central define algumas extensões para a linguagem DTDL. Para obter mais informações, confira Extensão do IoT Central.

Uma solução personalizada pode usar o analisador de modelo de gêmeos digitais para conhecer os recursos de um dispositivo que implementa o modelo. Para saber mais, consulte Usar modelos IoT Plug and Play em uma solução IoT.

Versão

Para garantir que as soluções dos dispositivos e do servidor que usam modelos continuem a funcionar, os modelos publicados são imutáveis.

O DTMI inclui um número de versão que pode ser usado para criar várias versões de um modelo. Soluções de dispositivos e de servidor podem usar a versão específica para a qual foram projetadas.

O IoT Central implementa mais regras de controle de versão para modelos de dispositivo. Se você gerar uma versão de um modelo de dispositivo e de seu modelo no IoT Central, pode migrar os dispositivos das versões anteriores para as versões posteriores. No entanto, os dispositivos migrados não podem usar os novos recursos sem uma atualização de firmware. Para saber mais, confira Editar um modelo de dispositivo.

Publicação

A partir de fevereiro de 2024, o programa Microsoft Azure Certified para IoT foi desativado. Portanto, a Microsoft não está mais aceitando envios de modelos DTDL para o repositório de modelos de plug and play da Internet das Coisas do Azure.

Se você quiser configurar seu repositório de modelos, poderá usar o repositório de ferramentas de modelos de plug and play da Internet das Coisas do Azure. Esse repositório inclui o código para a ferramenta da CLI dmr-client que pode validar, importar e expandir modelos DTDL. Essa ferramenta também permite indexar repositórios de modelo que seguem as convenções do repositório do modelo de dispositivo.

Limites e restrições

A lista a seguir resume algumas das principais restrições e limites dos modelos:

  • No momento, a profundidade máxima para matrizes, mapas e objetos é de cinco níveis.
  • Você não pode usar matrizes em definições de propriedade.
  • Você pode estender interfaces para uma profundidade de 10 níveis.
  • Uma interface pode estender no máximo duas outras interfaces.
  • Um componente não pode conter outro componente.

Próximas etapas

Agora que você conheceu a modelagem de dispositivo, confira mais recursos interessantes: