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.
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
emotors-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 manifestoCompatibilities
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)
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.