Compartilhar via


Registrar componentes com a Atualização de Dispositivo

Este artigo mostra um exemplo de implementação de um enumerador de componentes da Atualização de Dispositivo para Hub IoT. Você pode fazer referência a este exemplo para implementar um enumerador de componentes personalizado para os seus dispositivos IoT. Um componente é uma identidade de nível de subdispositivo que tem uma relação de composição com o dispositivo de host.

Este artigo demonstra um enumerador de componentes usando um dispositivo IoT virtual chamado Vácuo Virtual da Contoso. Os enumeradores de componentes são usados para implementar a funcionalidade de atualização de proxy.

A atualização de proxy permite a atualização de vários componentes no mesmo dispositivo IoT ou vários sensores conectados ao dispositivo IoT com uma única implantação over-the-air. A atualização de proxy dá suporte a uma ordem de instalação para atualizar componentes. Ele também dá suporte à atualização em várias etapas com recursos de pré-instalação, instalação e pós-instalação.

Os casos de uso em que as atualizações de proxy são aplicáveis incluem:

  • Direcionar arquivos de atualização específicos para partições no dispositivo.
  • Direcionar arquivos de atualização específicos para aplicativos/componentes no dispositivo
  • Direcionar arquivos de atualização específicos para sensores conectados a dispositivos IoT por meio de um protocolo de rede (por exemplo, USB ou CANbus)

Para obter mais informações, confira Atualizações de proxy e atualização de vários componentes.

O agente da Atualização de Dispositivo é executado no dispositivo host. Ele pode enviar cada atualização para um componente específico ou para um grupo de componentes da mesma classe de hardware (ou seja, exigindo a mesma atualização de software ou firmware).

O que é um Enumerador de Componentes?

Um enumerador de componentes é uma extensão do agente da Atualização de Dispositivo que fornece informações sobre cada componente de que você precisa para a atualização over-the-air por meio da conexão do Hub IoT do Azure de um dispositivo host.

O agente da Atualização de Dispositivo é independente de dispositivos e componentes. Por si só, o Agente de Atualização de Dispositivos não sabe nada sobre componentes em (ou conectado a) um dispositivo de host no momento da atualização.

Para habilitar as atualizações de proxy, os criadores de dispositivos devem identificar todos os componentes no dispositivo que podem ser atualizados e atribuir um nome exclusivo a cada componente. Além disso, o nome do grupo pode ser atribuído a componentes da mesma classe de hardware, de modo que a mesma atualização possa ser instalada em todos os componentes no mesmo grupo. O manipulador de conteúdo de atualização pode então instalar e aplicar a atualização aos componentes corretos.

Diagrama que mostra o fluxo de atualização do proxy.

Aqui estão as responsabilidades de cada parte do fluxo de atualização de proxy:

  • Construtor de dispositivos

    • Projete e crie o dispositivo.

    • Integrar o agente da Atualização de Dispositivo e as respectivas dependências.

    • Implementar uma extensão do enumerador de componentes específica do dispositivo e registre-se com o agente da Atualização de Dispositivo.

      O enumerador de componente usa as informações de um inventário de componentes ou um arquivo de configuração para aumentar os dados estáticos do componente (atualização de dispositivo necessária) com dados dinâmicos (por exemplo, versão de firmware, status de conexão e identidade de hardware).

    • Crie uma atualização de proxy que contenha uma ou mais atualizações filho destinadas a um ou mais componentes no dispositivo (ou conectados a ele).

    • Enviou a atualização para o operador de solução

  • Operador de solução

    • Importar a atualização e o manifesto para o serviço da Atualização de Dispositivo.

    • Implantar a atualização em um grupo de dispositivos

  • Agente da Atualização de Dispositivo

    • Receber informações de atualização do Hub IoT por meio do dispositivo gêmeo ou do módulo gêmeo.

    • Invoca o Manipulador de Etapas para processar a atualização de proxy destinada a um ou mais componentes no dispositivo

      O exemplo neste artigo tem duas atualizações: host-fw-1.1 e motors-fw-1.1. Para cada atualização filho, o manipulador de etapas pai invoca um manipulador de etapas filho para enumerar todos os componentes que corresponderem às propriedades especificadas no arquivo de manifesto Compatibilities da atualização filho. Em seguida, o manipulador baixa, instala e aplica a atualização filho a todos os componentes de destino.

      Para obter os componentes correspondentes, a atualização filho chamará uma API SelectComponents fornecida pelo enumerador de componentes. Se não houver nenhum componente correspondente, a atualização filho será ignorada.

    • Colete todos os resultados da atualização de atualizações pai e filho e reporte esses resultados para o Hub IoT.

  • Manipulador de etapas filho

    • Itere em uma lista de instâncias do componente que são compatíveis com o conteúdo da atualização filho. Para obter mais informações, confira Manipulador de etapas.

Em produção, os integradores de dispositivos podem usar manipuladores existentes ou implementar um manipulador personalizado que invoca qualquer instalador necessário para uma atualização over-the-air. Para obter mais informações, confira Implementar um manipulador de conteúdo de atualização personalizado.

Componentes do Virtual Vacuum

Para este artigo, usamos um dispositivo IoT virtual para demonstrar os principais conceitos e funcionalidades. O dispositivo de Vácuo Virtual da Contoso consiste em cinco componentes lógicos:

  • Firmware do host
  • Sistema de arquivos de inicialização do host
  • Sistema de arquivos raiz do host
  • Três motores (roda esquerda, roda direita e vácuo)
  • Duas câmeras (frontal e traseira)

Diagrama que mostra os componentes do Vácuo Virtual da Contoso.

A seguinte estrutura de diretório simula os componentes:

/usr/local/contoso-devices/vacuum-1/hostfw
/usr/local/contoso-devices/vacuum-1/bootfs
/usr/local/contoso-devices/vacuum-1/rootfs
/usr/local/contoso-devices/vacuum-1/motors/0   /* left motor */
/usr/local/contoso-devices/vacuum-1/motors/1   /* right motor */
/usr/local/contoso-devices/vacuum-1/motors/2   /* vacuum motor */
/usr/local/contoso-devices/vacuum-1/cameras/0  /* front camera */
/usr/local/contoso-devices/vacuum-1/cameras/1  /* rear camera */

O diretório de cada componente contém um arquivo JSON que armazena um número de versão de software fictício de cada componente. Os arquivos JSON de exemplo são firmware.json e diskimage.json.

Para esta demonstração, para atualizar o firmware dos componentes, copiaremos firmware.json ou diskimage.json (conteúdo de atualização) para o diretório dos componentes de alvo.

Veja um exemplo de arquivo firmware.json:

{
    "version": "0.5",
    "description": "This component is generated for testing purposes."
}

Observação

O Vácuo Virtual da Contoso contém versões de software ou firmware para demonstrar a atualização de proxy. Ele não fornece nenhuma outra funcionalidade.

Implemente um enumerador de componentes (linguagem C)

Requisitos

Implementar todas as APIs declaradas em component_enumerator_extension.hpp:

Função Argumentos Retornos
char* GetAllComponents() Nenhum Uma cadeia de caracteres JSON que contém uma matriz de todos ComponentInfo valores. Para obter mais informações, veja o exemplo de regra a seguir.
char* SelectComponents(char* selector) Uma cadeia de caracteres JSON que contém um ou mais usos de pares nome-valor para selecionar atualizações de componente(s) de destino Uma cadeia de caracteres JSON contém uma matriz de todos os valores ComponentInfo. Para obter mais informações, veja o Exemplo de regra a seguir.
void FreeComponentsDataString(char* string) Um ponteiro para o buffer de cadeia de caracteres retornado anteriormente pelas funções GetAllComponents ou SelectComponents. Nenhum

ComponentInfo

A cadeia de caracteres JSON ComponentInfo também DEVE incluir as seguintes propriedades de cadeia de caracteres:

Nome Tipo Descrição
id string A identidade exclusiva de um componente (escopo do dispositivo). Por exemplo, número de série do hardware, ID de partição de disco, caminho de arquivo exclusivo do componente, etc.
name string Nome lógico de um componente. Esta propriedade é o nome que um construtor de dispositivos atribui a um componente que está disponível em cada dispositivo da mesma classe device.

Por exemplo, cada dispositivo Contoso Virtual Vacuum contém um motor que conduz a roda para a esquerda. A Contoso atribuiu motor esquerdo como um nome (lógico) comum para esse motor, para se referir a esse componente com facilidade, em vez de ID de hardware, que pode ser globalmente exclusivo.
group string Um grupo ao qual este componente pertence.

Por exemplo, todos os motores podem pertencer a um grupo de motores.
manufacturer string Para um componente de hardware físico, essa propriedade é um nome de fabricante ou fornecedor.

Para o componente lógico, como partição de disco ou diretório, pode ser qualquer valor definido do construtor do dispositivo.
model string Para um componente de hardware físico, essa propriedade é um nome de modelo.

Para um componente lógico, como partição de disco ou diretório, essa propriedade pode ser qualquer valor definido do construtor do dispositivo.
properties objeto Um objeto JSON contém todas as propriedades opcionais específicas do dispositivo.

Aqui está um exemplo de código ComponentInfo com base nos componentes do Vácuo Virtual da Contoso:

{
    "id": "contoso-motor-serial-00000",
    "name": "left-motor",
    "group": "motors",
    "manufacturer": "contoso",
    "model": "virtual-motor",
    "properties": {
        "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
        "firmwareDataFile": "firmware.json",
        "status": "connected",
        "version" : "motor-fw-1.0"
    }
}

Exemplo de valores retornados

A seguir está um documento JSON retornado da função GetAllComponents. Ele se baseia na implementação de exemplo do enumerador de componente do Vácuo Virtual da Contoso.

{
    "components": [
        {
            "id": "hostfw",
            "name": "hostfw",
            "group": "firmware",
            "manufacturer": "contoso",
            "model": "virtual-firmware",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "host-fw-1.0"
            }
        },
        {
            "id": "bootfs",
            "name": "bootfs",
            "group": "boot-image",
            "manufacturer": "contoso",
            "model": "virtual-disk",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/bootfs",
                "firmwareDataFile": "diskimage.json",
                "status": "ok",
                "version" : "boot-fs-1.0"
            }
        },
        {
            "id": "rootfs",
            "name": "rootfs",
            "group": "os-image",
            "manufacturer": "contoso",
            "model": "virtual-os",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/rootfs",
                "firmwareDataFile": "diskimage.json",
                "status": "ok",
                "version" : "root-fs-1.0"
            }
        },
        {
            "id": "contoso-motor-serial-00000",
            "name": "left-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "motor-fw-1.0"
            }
        },
        {
            "id": "contoso-motor-serial-00001",
            "name": "right-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "motor-fw-1.0"
            }
        },
        {
            "id": "contoso-motor-serial-00002",
            "name": "vacuum-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "motor-fw-1.0"
            }
        },
        {
            "id": "contoso-camera-serial-00000",
            "name": "front-camera",
            "group": "cameras",
            "manufacturer": "contoso",
            "model": "virtual-camera",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/0",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "camera-fw-1.0"
            }
        },
        {
            "id": "contoso-camera-serial-00001",
            "name": "rear-camera",
            "group": "cameras",
            "manufacturer": "contoso",
            "model": "virtual-camera",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/1",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "camera-fw-1.0"
            }
        }
    ]
}

A seguir está um documento JSON retornado da função SelectComponents. Ele se baseia na implementação de exemplo do enumerador de componente Contoso.

Este é o parâmetro de entrada para selecionar o grupo de componentes motores:

{
    "group" : "motors"
}

Aqui está a saída do parâmetro . Todos os componentes pertencem ao grupo motores.

{
    "components": [
        {
            "id": "contoso-motor-serial-00000",
            "name": "left-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "motor-fw-1.0"
            }
        },
        {
            "id": "contoso-motor-serial-00001",
            "name": "right-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "motor-fw-1.0"
            }
        },
        {
            "id": "contoso-motor-serial-00002",
            "name": "vacuum-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "motor-fw-1.0"
            }
        }
    ]
}

Parâmetro de entrada para selecionar um único componente chamado hostfw:

{
    "name" : "hostfw"
}

Esta é a saída do parâmetro para o componente hostfw:

{
    "components": [
        {
            "id": "hostfw",
            "name": "hostfw",
            "group": "firmware",
            "manufacturer": "contoso",
            "model": "virtual-firmware",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
                "firmwareDataFile": "firmware.json",
                "status": "ok",
                "version" : "host-fw-1.0"
            }
        }
    ]
}

Observação

O exemplo acima demonstrou que, se necessário, é possível enviar uma atualização mais recente para qualquer instância de um componente quando selecionado por propriedade name. Por exemplo, implante a atualização motor-fw-2.0 no motor de vácuo enquanto continua a usar motor-fw-1.0 no motor esquerdo e no motor direito.

Filtros de inventário

A implementação de exemplo mostrada acima para o enumerador de componentes do Vácuo Virtual da Contoso lerá as informações de componentes específicos do dispositivo do arquivo component-inventory.json. Esta implementação de exemplo é apenas para fins de demonstração.

No cenário de produção, algumas propriedades devem ser recuperadas diretamente dos componentes reais. Essas propriedades incluem id, manufacturer, e model.

As propriedades name e group são definidas pelo construtor de dispositivos. Esses valores nunca devem ser alterados depois de definidos. A propriedade name deve ser exclusiva dentro do dispositivo.

Arquivo de exemplo component-inventory.json

Observação

O conteúdo desse arquivo é praticamente o mesmo que o valor retornado da função GetAllComponents. No entanto, o ComponentInfo nesse arquivo não contém as propriedades version e status. O enumerador de componente preencherá essas propriedades em runtime.

Por exemplo, para hostfw, o valor da propriedade será populado do valor properties.version especificado (mock) firmwareDataFile (/usr/local/contoso-devices/vacuum-1/hostfw/firmware.json).

{
    "components": [
        {
            "id": "hostfw",
            "name": "hostfw",
            "group": "firmware",
            "manufacturer": "contoso",
            "model": "virtual-firmware",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
                "firmwareDataFile": "firmware.json",
            }
        },
        {
            "id": "bootfs",
            "name": "bootfs",
            "group": "boot-image",
            "manufacturer": "contoso",
            "model": "virtual-disk",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/bootfs",
                "firmwareDataFile": "diskimage.json",
            }
        },
        {
            "id": "rootfs",
            "name": "rootfs",
            "group": "os-image",
            "manufacturer": "contoso",
            "model": "virtual-os",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/rootfs",
                "firmwareDataFile": "diskimage.json",
            }
        },
        {
            "id": "contoso-motor-serial-00000",
            "name": "left-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
                "firmwareDataFile": "firmware.json",
            }
        },
        {
            "id": "contoso-motor-serial-00001",
            "name": "right-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
                "firmwareDataFile": "firmware.json",
            }
        },
        {
            "id": "contoso-motor-serial-00002",
            "name": "vacuum-motor",
            "group": "motors",
            "manufacturer": "contoso",
            "model": "virtual-motor",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
                "firmwareDataFile": "firmware.json",
            }
        },
        {
            "id": "contoso-camera-serial-00000",
            "name": "front-camera",
            "group": "cameras",
            "manufacturer": "contoso",
            "model": "virtual-camera",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/0",
                "firmwareDataFile": "firmware.json",
            }
        },
        {
            "id": "contoso-camera-serial-00001",
            "name": "rear-camera",
            "group": "cameras",
            "manufacturer": "contoso",
            "model": "virtual-camera",
            "properties": {
                "path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/1",
                "firmwareDataFile": "firmware.json",
            }
        }
    ]
}

Próximas etapas

O exemplo neste artigo usou C. Para explorar códigos-fonte de exemplo do C++, confira:

Para obter várias atualizações de exemplo para os componentes conectados ao dispositivo Contoso Virtual Vacuum, confira Demonstração de atualização de proxy.