Entender e usar módulos gêmeos no Hub IoT

Este artigo pressupõe que você leu compreender e usar dispositivos gêmeos no IoT Hub primeiro. No Hub IoT, em cada identidade do dispositivo, você pode criar até 50 identidades de módulo. Cada identidade de módulo implicitamente gera módulo gêmeo. Semelhante aos gêmeos do dispositivo, os gêmeos do módulo são documentos JSON que armazenam informações de estado do módulo, incluindo metadados, configurações e condições. O Hub IoT do Azure mantém um módulo gêmeo para cada módulo que você conecta ao Hub IoT.

No lado do dispositivo, os SDKs do dispositivo IoT Hub permitem criar módulos em que cada um abre uma conexão independente para o IoT Hub. Essa funcionalidade permite usar namespaces separados para diferentes componentes em seu dispositivo. Por exemplo, você tem uma máquina de vendas com três sensores diferentes. Cada sensor é controlado por diferentes departamentos na sua empresa. Você pode criar um módulo para cada sensor. Dessa forma, cada departamento só é capaz de enviar trabalhos ou métodos diretos para o sensor controlado por ele, evitando conflitos e erros de usuário.

A identidade do módulo e o módulo gêmeo fornecem os mesmos recursos que a identidade do dispositivo e o dispositivo gêmeo, mas com granularidade mais precisa. Essa granularidade mais fina permite que dispositivos capazes, como dispositivos baseados em sistema operacional ou dispositivos de firmware que gerenciam vários componentes, isolem a configuração e as condições de cada um desses componentes. A identidade do módulo e os módulos gêmeos fornecem uma separação de problemas do gerenciamento ao trabalhar com dispositivos IoT que têm componentes de software modular. Nosso objetivo é dar suporte a toda a funcionalidade de dispositivos gêmeos no nível dos módulos gêmeos por meio da disponibilidade de módulos gêmeos para o público geral.

Observação

Os recursos descritos neste artigo estão disponíveis apenas na camada padrão do Hub IoT. Para saber mais sobre as camadas básica e padrão/gratuita do Hub IoT, confira Como escolher a camada certa do Hub IoT.

Este artigo descreve:

  • A estrutura do módulo gêmeo: marcas, propriedades desejadas e relatadas.
  • As operações que os módulos e back-ends de dispositivo podem executar em módulos gêmeos.

Veja as Diretrizes de comunicação do dispositivo para nuvem para obter orientação sobre o uso de propriedades reportadas, mensagens do dispositivo para nuvem ou upload do arquivo.

Veja as Diretrizes de comunicação da nuvem para dispositivo para obter orientação sobre o uso de propriedades desejadas, métodos diretos ou mensagens da nuvem para dispositivo.

Módulos gêmeos

Módulos gêmeos armazenam informações relacionadas ao módulo que:

  • Os módulos no dispositivo e o Hub IoT podem usar para sincronizar a configuração e as condições do módulo.

  • A solução que o back-end pode usar para consultar e direcionar operações de execução longa.

O ciclo de vida de um módulo gêmeo está vinculado a correspondente identidade de módulo. Os módulos gêmeos são criados e excluídos implicitamente quando uma identidade de módulo é criada ou excluída no Hub IoT.

Um módulo gêmeo é um documento JSON que inclui:

  • Marcas. Uma seção do documento JSON que o back-end de solução pode ler e na qual pode gravar. As marcações não são visíveis para os módulos no dispositivo. As marcações são definidas para fins de consulta.

  • Propriedades desejadas. Usado junto com as propriedades relatadas para sincronizar a configuração ou condições de módulo. O back-end da solução pode definir as propriedades desejadas e o aplicativo de módulo pode lê-las. O aplicativo do módulo também pode receber notificações de alterações nas propriedades desejadas.

  • Propriedades reportadas. Usado junto com as propriedades desejadas para sincronizar a configuração ou condições de módulo. O aplicativo de módulo pode definir as propriedades relatadas e o back-end da solução pode lê-las e consultá-las.

  • Propriedades de identidade do módulo. A raiz do documento JSON do módulo gêmeo contém as propriedades somente leitura da identidade de módulo correspondente armazenado na registro de identidade.

Representação de arquitetura do dispositivo gêmeo

O seguinte exemplo mostra um documento JSON de módulo gêmeo:

{
    "deviceId": "devA",
    "moduleId": "moduleA",
    "etag": "AAAAAAAAAAc=", 
    "status": "enabled",
    "statusReason": "provisioned",
    "statusUpdateTime": "0001-01-01T00:00:00",
    "connectionState": "connected",
    "lastActivityTime": "2015-02-30T16:24:48.789Z",
    "cloudToDeviceMessageCount": 0, 
    "authenticationType": "sas",
    "x509Thumbprint": {     
        "primaryThumbprint": null, 
        "secondaryThumbprint": null 
    }, 
    "version": 2, 
    "tags": {
        "deploymentLocation": {
            "building": "43",
            "floor": "1"
        }
    },
    "properties": {
        "desired": {
            "telemetryConfig": {
                "sendFrequency": "5m"
            },
            "$metadata" : {...},
            "$version": 1
        },
        "reported": {
            "telemetryConfig": {
                "sendFrequency": "5m",
                "status": "success"
            },
            "batteryLevel": 55,
            "$metadata" : {...},
            "$version": 4
        }
    }
}

No objeto raiz estão as propriedades de identidade do módulo e os objetos de contêiner para tags, além das propriedades reported e desired. O contêiner properties apresenta alguns elementos somente leitura ($metadata e $version) descritos nas seções Metadados do módulo gêmeo e Simultaneidade otimista.

Exemplo da propriedade reportada

No exemplo anterior, o módulo gêmeo contém uma propriedade batteryLevel que é reportada pelo aplicativo do módulo. Essa propriedade torna possível a consultar e operação em módulos com base no último nível da bateria reportado. Outros exemplos incluem os recursos de módulo de relatórios de aplicativo de módulo ou as opções de conectividade.

Observação

As propriedades relatadas simplificam cenários nos quais o back-end da solução está interessado no último valor conhecido de uma propriedade. Use mensagens do dispositivo para nuvem se o back-end da solução precisa processar telemetria do módulo na forma de sequências de eventos de data/hora, como uma série temporal.

Exemplo da propriedade desejada

No exemplo anterior, as propriedades relatadas e desejadas do módulo gêmeo telemetryConfig são usadas pelo aplicativo do módulo e pelo back-end da solução para sincronizar a configuração de telemetria para o módulo em questão. Por exemplo:

  1. O back-end da solução define a propriedade desejada com o valor de configuração desejado. Aqui está a parte do documento com o conjunto de propriedades desejado:

    ...
    "desired": {
        "telemetryConfig": {
            "sendFrequency": "5m"
        },
        ...
    },
    ...
    
  2. O aplicativo de módulo será notificado sobre a alteração imediatamente se o módulo estiver conectado. Se ele não estiver conectado, o aplicativo de módulo seguirá o fluxo de reconexão de módulo ao se conectar. Em seguida, o aplicativo do módulo reporta a configuração atualizada (ou uma condição de erro usando a propriedade status). Esta é a parte das propriedades reportadas:

    "reported": {
        "telemetryConfig": {
            "sendFrequency": "5m",
            "status": "success"
        }
        ...
    }
    
  3. O back-end da solução pode acompanhar os resultados da operação de configuração em vários módulos, por consultando módulos gêmeos.

Observação

Os snippets anteriores são exemplos, otimizados para facilitar a leitura, de uma forma de codificar uma configuração de módulo e seu status. O Hub IoT não impõe um esquema específico para as propriedades desejadas e reportadas do módulo gêmeo nos módulos gêmeos.

Importante

A IoT Plug and Play define um esquema que usa várias propriedades adicionais para sincronizar as alterações nas propriedades desejadas e relatadas. Se sua solução usa a IoT Plug and Play, você precisa seguir as convenções de Plug and Play ao atualizar propriedades de gêmeo. Para obter mais informações e um exemplo, confira Propriedades graváveis no IoT Plug and Play.

Operações de back-end

O back-end da solução funciona no módulo gêmeo usando as seguintes operações atômicas, expostas por meio de HTTPS:

  • Recuperar módulo gêmeo por ID. Essa operação retorna o documento do módulo gêmeo, incluindo marcas e propriedades do sistema desejadas e reportadas.

  • Atualizar parcialmente o módulo gêmeo. Essa operação permite que o back-end da solução atualize parcialmente as marcações ou propriedades desejadas em um módulo gêmeo. A atualização parcial é expressa como um documento JSON que adiciona ou atualiza qualquer propriedade. As propriedades definidas como null foram removidas. O exemplo a seguir cria uma nova propriedade desejada com o valor {"newProperty": "newValue"}, substitui o valor existente de existingProperty por "otherNewValue" e remove otherOldProperty. Nenhuma outra alteração é feitas nas propriedades desejadas ou marcas existentes:

    {
        "properties": {
            "desired": {
                "newProperty": {
                    "nestedProperty": "newValue"
                },
                "existingProperty": "otherNewValue",
                "otherOldProperty": null
            }
        }
    }
    
  • Substituir propriedades desejadas. Esta operação permite que o back-end da solução substitua completamente todas as suas propriedades desejadas existentes e substitui um novo documento JSON por properties/desired.

  • Substituir marcas. Esta operação permite que o back-end da solução substitua completamente todas as marcas existentes e substitui um novo documento JSON por tags.

  • Receba notificações gêmeas. Esta operação permite que o back-end de solução seja notificado quando o gêmeo é modificado. Para fazer isso, sua solução de IoT precisa para criar uma rota e definir a Fonte de Dados como twinChangeEvents. Por padrão, essa rota não existe, e portanto nenhuma notificação gêmea é enviada. Se a taxa de alteração for alta demais ou então por outros motivos como falhas internas, o Hub IoT poderá enviar apenas uma notificação contendo todas as alterações. Portanto, se o aplicativo precisar de auditoria e registro em log confiável de todos os estados intermediários, será necessário usar mensagens de dispositivo para nuvem. Para saber mais sobre as propriedades e o corpo retornados na mensagem de notificação gêmea, consulte esquemas de eventos não telemétricos.

Todas as operações anteriores suportam simultaneidade otimista e exigem a permissão ServiceConnect, conforme definido no artigo Control Access to IoT Hub.

Além dessas operações, o backend da solução pode consultar os gêmeos do módulo usando a linguagem de consulta do Hub IoT semelhante a SQL.

Operações de módulo

O aplicativo do módulo opera no módulo gêmeo usando as seguintes operações atômicas:

  • Recuperar módulo gêmeo. Essa operação retorna o documento do módulo gêmeo (incluindo as propriedades do sistema desejadas e relatadas) para o módulo conectado no momento.

  • Atualizar parcialmente as propriedades reportadas. Essa operação permite a atualização parcial das propriedades reportadas do módulo conectado no momento. Esta operação usa o mesmo formato de atualização JSON que a solução de back-end usa para uma atualização parcial de propriedades desejadas.

  • Observar as propriedades desejadas. O módulo conectado no momento pode optar por ser notificado sobre atualizações para as propriedades desejadas quando elas ocorrem. O módulo recebe a mesma forma de atualização (substituição total ou parcial) executada pelo back-end da solução.

Todas as operações anteriores exigem a permissão DeviceConnect, conforme a definição no artigo Controlar o acesso ao Hub IoT.

Os SDKs do dispositivo IoT do Azure facilitam o uso das operações anteriores em várias linguagens e plataformas.

Formato de marcas e propriedades

Marcas, propriedades desejadas e propriedades reportadas são objetos JSON com as seguintes restrições:

  • Chaves: todas as chaves em objetos JSON são codificadas em UTF-8, diferenciam maiúsculas de minúsculas e têm até 1 KB. Os caracteres permitidos excluem caracteres de controle UNICODE (segmentos C0 e C1) e ., $ e SP.

  • Valores: todos os valores em objetos JSON podem ser dos seguintes tipos de JSON: booliano, número, cadeia de caracteres ou objeto. Também há suporte para matrizes.

    • Os inteiros podem ter um valor mínimo de -4503599627370496 e um valor máximo de 4503599627370495.

    • Os valores de cadeia de caracteres são codificados em UTF-8 e podem ter um comprimento máximo de 4 KB.

  • Profundidade: a profundidade máxima de objetos JSON em marcas, propriedades desejadas e propriedades relatadas é dez. Por exemplo, o seguinte objeto é válido:

    {
         ...
         "tags": {
             "one": {
                 "two": {
                     "three": {
                         "four": {
                             "five": {
                                 "six": {
                                     "seven": {
                                         "eight": {
                                             "nine": {
                                                 "ten": {
                                                     "property": "value"
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         },
         ...
    }
    

Tamanho do módulo gêmeo

O hub IoT impõe um limite de tamanho 8 KB no valor de tags e um limite de tamanho 32 KB em cada um com o valor de properties/desired e properties/reported. Esses totais são exclusivos de elementos somente leitura como $version e $metadata/$lastUpdated.

O tamanho do gêmeo é calculado da seguinte maneira:

  • Para cada propriedade no documento JSON, o hub IoT é calculado cumulativamente e adiciona o comprimento da chave e do valor da propriedade.

  • As chaves de propriedade são consideradas cadeias de caracteres codificadas em UTF-8.

  • Os valores de propriedades simples são considerados cadeias de caracteres codificadas em UTF-8, valores numéricos (8 bytes) ou valores boolianos (4 bytes).

  • O tamanho das cadeias de caracteres codificadas em UTF-8 é calculado pela contagem de todos os caracteres, exceto caracteres de controle UNICODE (segmentos C0 e C1).

  • Os valores de propriedades complexos (objetos aninhados) são calculados com base no tamanho agregado das chaves de propriedades e dos valores de propriedades que eles contêm.

O Hub IoT rejeita com erro todas as operações que podem aumentar o tamanho desses documentos acima do limite.

Metadados do módulo gêmeo

O Hub IoT mantém o carimbo de data e hora da última atualização de cada objeto JSON nas propriedades desejadas e reportadas do módulo gêmeo. Os carimbos de data e hora estão em UTC e são codificados no formato ISO8601YYYY-MM-DDTHH:MM:SS.mmmZ. Por exemplo:

{
    ...
    "properties": {
        "desired": {
            "telemetryConfig": {
                "sendFrequency": "5m"
            },
            "$metadata": {
                "telemetryConfig": {
                    "sendFrequency": {
                        "$lastUpdated": "2016-03-30T16:24:48.789Z"
                    },
                    "$lastUpdated": "2016-03-30T16:24:48.789Z"
                },
                "$lastUpdated": "2016-03-30T16:24:48.789Z"
            },
            "$version": 23
        },
        "reported": {
            "telemetryConfig": {
                "sendFrequency": "5m",
                "status": "success"
            },
            "batteryLevel": "55%",
            "$metadata": {
                "telemetryConfig": {
                    "sendFrequency": "5m",
                    "status": {
                        "$lastUpdated": "2016-03-31T16:35:48.789Z"
                    },
                    "$lastUpdated": "2016-03-31T16:35:48.789Z"
                },
                "batteryLevel": {
                    "$lastUpdated": "2016-04-01T16:35:48.789Z"
                },
                "$lastUpdated": "2016-04-01T16:24:48.789Z"
            },
            "$version": 123
        }
    }
    ...
}

Essas informações são armazenadas em cada nível (não apenas nas folhas da estrutura JSON) a fim de preservar as atualizações que removem chaves de objeto.

Simultaneidade otimista

As marcas, propriedades desejadas e propriedades reportadas oferecem suporte à simultaneidade otimista. Se você precisar garantir a ordem das atualizações de propriedades gêmeas, implemente a sincronização no nível do aplicativo aguardando o retorno de chamada das propriedades relatadas, antes de enviar a próxima atualização.

Os módulos gêmeos têm uma ETag (propriedade etag), de acordo com RFC7232, que corresponde à representação JSON do gêmeo. Você pode usar a propriedade etag em operações de atualização condicionais do back-end da solução para garantir a consistência. Essa é a única opção para garantir a consistência em operações que envolvem o contêiner tags.

As propriedades desejadas e reportadas do módulo gêmeo também têm um valor $version com garantia de ser incremental. De forma semelhante a uma ETag, a versão pode ser usada pela parte de atualização para impor a consistência das atualizações. Por exemplo, um aplicativo de módulo para uma propriedade relatada ou o back-end de solução para uma propriedade desejada.

Versões também são úteis quando um agente observador (por exemplo, o aplicativo do módulo que observa as propriedades desejadas) deve reconciliar corridas entre o resultado de uma operação de recuperação e uma notificação de atualização. A seção Fluxo de reconexão do módulo fornece mais informações.

Fluxo de reconexão do módulo

O Hub IoT não preserva as notificações de atualização de propriedades desejadas de módulos desconectados. Um módulo que está se conectando precisa recuperar o documento de propriedades desejadas completo, além de assinar notificações de atualização. Considerando a possibilidade de corridas entre notificações de atualização e recuperação completa, o seguinte fluxo deve ser garantido:

  1. O aplicativo de módulo se conecta com um hub IoT.
  2. O aplicativo de módulo assina as notificações de atualização de propriedades desejadas.
  3. O aplicativo de módulo recupera o documento completo das propriedades desejadas.

O aplicativo de módulo pode ignorar todas as notificações com $version menor ou igual à versão do documento recuperado completo. Essa abordagem é possível porque o Hub IoT garante que as versões sempre aumentam.

Próximas etapas

Para experimentar alguns dos conceitos descritos neste artigo, consulte os tutoriais do Hub IoT a seguir: