Partilhar 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 o Hub IoT. Você pode fazer referência a este exemplo para implementar um enumerador de componentes personalizado para seus dispositivos IoT. Um componente é uma identidade abaixo do nível do dispositivo que tem uma relação de composição com o dispositivo host.

Este artigo demonstra um enumerador de componentes usando um dispositivo IoT virtual chamado Contoso Virtual Vacuum. Os enumeradores de componentes são usados para implementar o recurso de atualização de proxy.

A atualização de proxy permite atualizar 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 suporta uma ordem de instalação para atualizar componentes. Ele também suporta 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:

  • Direcionamento de arquivos de atualização específicos para partições no dispositivo.
  • Direcionamento de arquivos de atualização específicos para aplicativos ou componentes no dispositivo.
  • Direcionamento de arquivos de atualização específicos para sensores conectados a dispositivos IoT através de um protocolo de rede (por exemplo, barramento USB ou CAN).

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

O agente de 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 para o agente de Atualização de Dispositivo que fornece informações sobre todos os componentes necessários para uma atualização over-the-air por meio da conexão do Hub IoT do Azure de um dispositivo host.

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

Para habilitar atualizações de proxy, os construtores de dispositivos devem identificar todos os componentes no dispositivo que podem ser atualizados e atribuir um nome exclusivo a cada componente. Além disso, um nome de grupo pode ser atribuído a componentes da mesma classe de hardware, para que a mesma atualização possa ser instalada em todos os componentes do mesmo grupo. Em seguida, o manipulador de conteúdo de atualização pode 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 construa o dispositivo.

    • Integre o agente de Atualização de Dispositivo e suas dependências.

    • Implemente uma extensão de enumerador de componente específico do dispositivo e registre-se com o agente de Atualização de Dispositivo.

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

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

    • Envie a atualização para o operador da solução.

  • Operador da solução

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

    • Implante a atualização em um grupo de dispositivos.

  • Agente de atualização de dispositivo

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

    • Invoque um 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 correspondem às Compatibilities propriedades especificadas no arquivo de manifesto 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 chama uma SelectComponents API fornecida pelo enumerador de componentes. Se não houver componentes correspondentes, a atualização filho será ignorada.

    • Colete todos os resultados de atualização de atualizações pai e filho e relate esses resultados ao Hub IoT.

  • Manipulador de etapas filho

    • Itere por meio de uma lista de instâncias de componentes compatíveis com o conteúdo de atualização filho. Para obter mais informações, consulte Manipulador de etapas.

Na produção, os construtores 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, consulte Implementar um manipulador de conteúdo de atualização personalizado.

Componentes de vácuo virtual

Para este artigo, usamos um dispositivo IoT virtual para demonstrar os principais conceitos e recursos. O dispositivo Contoso Virtual Vacuum consiste em cinco componentes lógicos:

  • Firmware do anfitrião
  • 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âmaras (dianteira e traseira)

Diagrama que mostra os componentes do Contoso Virtual Vacuum.

A seguinte estrutura de diretórios 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 simulado de cada componente. Exemplos de arquivos JSON são firmware.json e diskimage.json.

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

Aqui está um exemplo firmware.json arquivo:

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

Nota

O Contoso Virtual Vacuum contém versões de software ou firmware com a finalidade de demonstrar a atualização de proxy. Ele não fornece nenhuma outra funcionalidade.

Implementar um enumerador de componentes (linguagem C)

Requisitos

Implemente todas as APIs declaradas em component_enumerator_extension.hpp:

Function Argumentos Devoluções
char* GetAllComponents() Nenhuma Uma cadeia de caracteres JSON que contém uma matriz de todos os ComponentInfo valores. Para obter mais informações, consulte Exemplo de valores de retorno.
char* SelectComponents(char* selector) Uma cadeia de caracteres JSON que contém um ou mais pares nome/valor usados para selecionar componentes de destino de atualização Uma cadeia de caracteres JSON que contém uma matriz de ComponentInfo valores. Para obter mais informações, consulte Exemplo de valores de retorno.
void FreeComponentsDataString(char* string) Um ponteiro para buffer de cadeia de caracteres retornado anteriormente por GetAllComponents ou SelectComponents funções Nenhuma

ComponentInfo

A ComponentInfo cadeia de caracteres JSON deve incluir as seguintes propriedades:

Nome Tipo Description
id string Identidade exclusiva de um componente (escopo do dispositivo). Os exemplos incluem número de série do hardware, ID da partição do disco e caminho de arquivo exclusivo do componente.
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 todos os dispositivos da mesma device classe.

Por exemplo, cada dispositivo de Vácuo Virtual da Contoso contém um motor que aciona uma roda esquerda. A Contoso atribuiu o motor esquerdo como um nome (lógico) comum para esse mecanismo para se referir facilmente a esse componente, em vez da ID de hardware, que pode ser globalmente exclusiva.
group string Um grupo ao qual esse 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 um componente lógico, como uma partição de disco ou diretório, pode ser o valor definido por qualquer construtor de dispositivos.
model string Para um componente de hardware físico, essa propriedade é um nome de modelo.

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

Aqui está um exemplo de ComponentInfo código baseado nos componentes do Contoso Virtual Vacuum:

{
    "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 de retorno

A seguir está um documento JSON retornado da GetAllComponents função. Baseia-se no exemplo de implementação do enumerador de componentes Contoso Virtual Vacuum.

{
    "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"
            }
        }
    ]
}

O seguinte documento JSON é retornado da SelectComponents função. Baseia-se no exemplo de implementação do enumerador de componentes Contoso.

Aqui está o parâmetro de entrada para selecionar o grupo de componentes de motores :

{
    "group" : "motors"
}

Aqui está a saída do parâmetro. Todos os componentes pertencem ao grupo dos 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"
            }
        }
    ]
}

Aqui está o parâmetro de entrada para selecionar um único componente chamado hostfw:

{
    "name" : "hostfw"
}

Aqui está 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"
            }
        }
    ]
}

Nota

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

Arquivo de inventário

O exemplo de implementação mostrado anteriormente para o enumerador de componentes Contoso Virtual Vacuum lerá as informações dos componentes específicos do dispositivo do arquivo component-inventory.json . Este exemplo de implementação é apenas para fins de demonstração.

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

O construtor de dispositivos define as name propriedades e group . Esses valores nunca devem mudar depois de definidos. A name propriedade deve ser exclusiva dentro do dispositivo.

Exemplo de arquivo component-inventory.json

Nota

O conteúdo neste arquivo parece quase o mesmo que o valor retornado da GetAllComponents função. No entanto, ComponentInfo neste arquivo não contém version e status propriedades. O enumerador de componentes preencherá essas propriedades em tempo de execução.

Por exemplo, para hostfw, o valor da propriedade properties.version será preenchido a partir do valor 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óximos passos

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

Para obter vários exemplos de atualizações para componentes conectados ao dispositivo Contoso Virtual Vacuum, consulte Demonstração de atualização de proxy.