Registrare i componenti con Aggiornamento dispositivi

In questo articolo viene illustrato un esempio di implementazione di un enumeratore di componenti Aggiornamento dispositivi per hub IoT. È possibile fare riferimento a questo esempio per implementare un enumeratore di componenti personalizzato per i dispositivi IoT. Il componente è un'identità al di sotto del livello del dispositivo con una relazione di composizione con il dispositivo host.

In questo articolo viene illustrato un enumeratore di componenti che usa un dispositivo IoT virtuale denominato Contoso Virtual Vacuum. Gli enumeratori di componenti vengono usati per implementare la funzionalità di aggiornamento proxy.

L'aggiornamento proxy consente di aggiornare più componenti nello stesso dispositivo IoT o più sensori connessi al dispositivo IoT con una singola distribuzione over-the-air. L'aggiornamento proxy supporta l'ordine di installazione per l'aggiornamento dei componenti. Supporta anche l'aggiornamento in più passaggi con funzionalità di preinstallazione, installazione e post-installazione.

I casi d'uso in cui gli aggiornamenti proxy sono applicabili includono:

  • Destinazione di file di aggiornamento specifici alle partizioni nel dispositivo.
  • Destinazione di file di aggiornamento specifici per app o componenti nel dispositivo.
  • Destinazione di file di aggiornamento specifici per sensori connessi ai dispositivi IoT tramite un protocollo di rete (ad esempio, USB o CAN-Bus).

Per altre informazioni, vedere Aggiornamenti proxy e aggiornamento multi-componente.

L'agente di Aggiornamento dispositivi viene eseguito nel dispositivo host. Può inviare ogni aggiornamento a un componente specifico o a un gruppo di componenti della stessa classe hardware (ovvero, che richiede lo stesso aggiornamento software o firmware).

Che cos'è un enumeratore di componenti?

Un enumeratore di componenti è un'estensione per l'agente di Aggiornamento dispositivi che fornisce informazioni su ogni componente necessario per un aggiornamento over-the-air tramite la connessione dell'hub IoT di Azure di un dispositivo host.

L'agente di Aggiornamento dispositivi è indipendente dal dispositivo e dal componente. Da solo, l'agente non sa nulla sui componenti in (o connessi a) un dispositivo host al momento dell'aggiornamento.

Per abilitare gli aggiornamenti proxy, i generatori di dispositivi devono identificare tutti i componenti del dispositivo che possono essere aggiornati e assegnare un nome univoco a ogni componente. Inoltre, è possibile assegnare un nome di gruppo ai componenti della stessa classe hardware, in modo che lo stesso aggiornamento possa essere installato in tutti i componenti dello stesso gruppo. Il gestore del contenuto di aggiornamento può quindi installare e applicare l'aggiornamento ai componenti corretti.

Diagramma che mostra il flusso di aggiornamento del proxy.

Ecco le responsabilità di ogni parte del flusso di aggiornamento del proxy:

  • Generatore di dispositivi

    • Progettare e compilare il dispositivo.

    • Integrare l'agente di Aggiornamento dispositivi e le relative dipendenze.

    • Implementare un'estensione dell'enumeratore di componenti specifica del dispositivo e registrarsi con l'agente di Aggiornamento dispositivi.

      L'enumeratore di componenti usa le informazioni di un inventario di componenti o di un file di configurazione per aumentare i dati dei componenti statici (è richiesto Aggiornamento dispositivi) con dati dinamici (ad esempio, la versione del firmware, lo stato della connessione e l'identità hardware).

    • Creare un aggiornamento proxy che contenga uno o più aggiornamenti figlio destinati (o connessi) a uno o più componenti nel dispositivo.

    • Inviare l'aggiornamento all'operatore della soluzione.

  • Operatore di soluzioni

    • Importare l'aggiornamento e il manifesto nel servizio Aggiornamento dispositivi.

    • Distribuire l'aggiornamento in un gruppo di dispositivi.

  • Agente di Aggiornamento dispositivi

    • Ottenere informazioni sull'aggiornamento dall'hub IoT tramite il dispositivo gemello o il modulo gemello.

    • Richiamare un gestore passaggi per elaborare l'aggiornamento proxy destinato a uno o più componenti nel dispositivo.

      L'esempio in questo articolo include due aggiornamenti: host-fw-1.1 e motors-fw-1.1. Per ogni aggiornamento figlio, il gestore dei passaggi padre richiama un gestore dei passaggi figlio per enumerare tutti i componenti che corrispondono alle proprietà Compatibilities specificate nel file manifesto dell'aggiornamento figlio. Successivamente, il gestore scarica, installa e applica l'aggiornamento figlio a tutti i componenti di destinazione.

      Per ottenere i componenti corrispondenti, l'aggiornamento figlio chiama un'API SelectComponents fornita dall'enumeratore di componenti. Se non sono presenti componenti corrispondenti, l'aggiornamento figlio viene ignorato.

    • Raccogliere tutti i risultati degli aggiornamenti dagli aggiornamenti padre e figlio e segnalare tali risultati all'hub IoT.

  • Gestore dei passaggi figlio

    • Scorrere un elenco di istanze del componente compatibili con il contenuto di aggiornamento figlio. Per altre informazioni, vedere Gestore passaggi.

Nell'ambiente di produzione i generatori di dispositivi possono usare gestori esistenti o implementare un gestore personalizzato che richiami qualsiasi programma di installazione necessario per un aggiornamento over-the-air. Per altre informazioni, vedere Implementare un gestore di contenuti di aggiornamento personalizzato.

Componenti Virtual Vacuum

Per questo articolo viene usato un dispositivo IoT virtuale per illustrare i concetti e le funzionalità principali. Il dispositivo Contoso Virtual Vacuum è costituito da cinque componenti logici:

  • Firmware host
  • File system di avvio host
  • File system radice host
  • Tre motori (rotella sinistra, rotella destra e vuoto)
  • Due fotocamere (anteriore e posteriore)

Diagramma che mostra i componenti Contoso Virtual Vacuum.

La struttura di directory seguente simula i componenti:

/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 */

La directory di ogni componente contiene un file JSON che archivia un numero di versione software fittizio di ogni componente. I file JSON di esempio sono firmware.json e diskimage.json.

Per questa demo, per aggiornare il firmware dei componenti, copiare firmware.json o diskimage.json (aggiornamento del payload) nella directory dei componenti di destinazione.

Di seguito è riportato un esempio di file firmware.json:

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

Nota

Contoso Virtual Vacuum contiene versioni software o firmware allo scopo di illustrare l'aggiornamento proxy. Non fornisce altre funzionalità.

Implementare un enumeratore di componenti (linguaggio C)

Requisiti

Implementare tutte le API dichiarate in component_enumerator_extension.hpp:

Funzione Argomenti Valori restituiti
char* GetAllComponents() None Stringa JSON che contiene una matrice di tutti i valori ComponentInfo. Per altre informazioni, vedere Esempio di valori restituiti.
char* SelectComponents(char* selector) Una stringa JSON che contiene una o più coppie nome/valore usate per selezionare i componenti di destinazione dell'aggiornamento Stringa JSON che contiene una matrice di valori ComponentInfo. Per altre informazioni, vedere Esempio di valori restituiti.
void FreeComponentsDataString(char* string) Puntatore al buffer stringa restituito in precedenza da funzioni di GetAllComponents o SelectComponents None

ComponentInfo

La stringa JSON ComponentInfo deve includere le proprietà seguenti:

Nome Tipo Descrzione
id stringa Identità univoca di un componente (ambito del dispositivo). Gli esempi includono il numero di serie hardware, l'ID partizione del disco e il percorso univoco del file del componente.
name string Nome logico di un componente. Questa proprietà è il nome assegnato da un generatore di dispositivi a un componente disponibile in ogni dispositivo della stessa classe device.

Ad esempio, ogni dispositivo Contoso Virtual Vacuum contiene un motore che guida una rotella sinistra. Contoso ha assegnato motore sinistro come nome comune (logico) affinché tale motore faccia facilmente riferimento a questo componente, anziché all'ID hardware, che può essere univoco a livello globale.
group string Gruppo a cui appartiene questo componente.

Ad esempio, tutti i motori possono appartenere a un gruppo motori.
manufacturer string Per un componente hardware fisico, questa proprietà è un nome del produttore o del fornitore.

Per un componente logico, ad esempio una partizione o una directory del disco, può essere un valore definito da qualsiasi generatore di dispositivi.
model string Per un componente hardware fisico, questa proprietà è un nome di modello.

Per un componente logico, ad esempio una partizione o una directory del disco, questa proprietà può essere qualsiasi valore definito dal generatore di dispositivi.
properties oggetto Oggetto JSON che contiene eventuali proprietà facoltative specifiche del dispositivo.

Ecco un esempio di codice ComponentInfo basato sui componenti 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"
    }
}

Valori restituiti di esempio

Di seguito è riportato un documento JSON restituito dalla funzione GetAllComponents. Si basa sull'implementazione di esempio dell'enumeratore di componenti 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"
            }
        }
    ]
}

Il documento JSON seguente viene restituito dalla funzione SelectComponents. Si basa sull'implementazione di esempio dell'enumeratore di componenti Contoso.

Ecco il parametro di input per la selezione del gruppo di componenti motori :

{
    "group" : "motors"
}

Ecco l'output del parametro. Tutti i componenti appartengono al gruppo motori.

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

Ecco il parametro di input per la selezione di un singolo componente denominato hostfw:

{
    "name" : "hostfw"
}

Ecco l'output del parametro per il 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

L'esempio precedente ha dimostrato che, se necessario, è possibile inviare un aggiornamento più recente a qualsiasi istanza di un componente selezionato dalla proprietà name. Ad esempio, distribuire l'aggiornamento motor-fw-2.0 per vacuum-motor continuando a usare motor-fw-1.0 su left-motor e right-motor.

File di inventario

L'implementazione di esempio illustrata in precedenza per l'enumeratore di componenti Contoso Virtual Vacuum leggerà le informazioni dei componenti specifici del dispositivo dal file component-inventory.json. Questa implementazione di esempio è solo a scopo dimostrativo.

In uno scenario di produzione, alcune proprietà devono essere recuperate direttamente dai componenti effettivi. Queste proprietà includono id, manufacturere model.

Il generatore di dispositivi definisce le proprietà name e group. Questi valori non dovrebbero mai cambiare dopo la definizione. La proprietà name deve essere univoca all'interno del dispositivo.

File component-inventory.json di esempio

Nota

Il contenuto di questo file è quasi identico al valore restituito dalla funzione GetAllComponents. Tuttavia, il componente ComponentInfo in questo file non contiene le proprietà version e status. L'enumeratore di componenti popola queste proprietà in fase di esecuzione.

Ad esempio, per hostfw, il valore della proprietà properties.version verrà popolato dal valore specificato (fittizio) 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",
            }
        }
    ]
}

Passaggi successivi

L'esempio in questo articolo ha usato C. Per esplorare i codici sorgente di esempio C++, vedere:

Per vari aggiornamenti di esempio per i componenti connessi al dispositivo Contoso Virtual Vacuum, vedere Demo di aggiornamento proxy.