Usare la gestione dei dispositivi per avviare un aggiornamento del firmware del dispositivo (.NET/Node)

Nell'esercitazione Introduzione alla gestione dei dispositivi è stato illustrato come usare il dispositivo gemello e le primitive dei metodi diretti per riavviare un dispositivo in modalità remota. Questa esercitazione usa le stesse primitive dell'hub IoT e illustra come eseguire un aggiornamento del firmware simulato completo. Questo modello viene usato nell'implementazione dell'aggiornamento del firmware per l'esempio di implementazione del dispositivo Raspberry Pi.

Questa esercitazione illustra come:

  • Creare un'app console .NET che chiama il metodo diretto firmwareUpdate nell'app per dispositivo simulato tramite l'hub IoT.
  • Creare un'app di dispositivo simulato che implementa un metodo diretto firmwareUpdate. Questo metodo avvia un processo in più fasi che attende di scaricare l'immagine del firmware, quindi la scarica e infine la applica. Durante l'esecuzione di ogni fase, il dispositivo usa le proprietà segnalate per aggiornare lo stato.

Al termine dell'esercitazione saranno disponibili un'app per il dispositivo console Node.js e un'app back-end console .NET (C#):

dmpatterns_fwupdate_service.js, che chiama un metodo diretto nell'app per dispositivo simulato, visualizza la risposta e visualizza regolarmente (ogni 500 ms) le proprietà segnalate aggiornate.

TriggerFWUpdate, che connette all'hub IoT con l'identità del dispositivo creata prima, riceve un metodo diretto firmwareUpdate, esegue un processo in più stati per simulare un aggiornamento del firmware, inclusi l'attesa del download dell'immagine, il download della nuova immagine e infine l'applicazione dell'immagine.

Per completare l'esercitazione, sono necessari gli elementi seguenti:

  • Visual Studio 2015 o Visual Studio 2017.
  • Node.js 4.0.x o versione successiva.
    Prepare your development environment (Preparare l'ambiente di sviluppo) descrive come installare Node.js per questa esercitazione in Windows o Linux.
  • Un account Azure attivo. Se non si ha un account, è possibile creare un account gratuito in pochi minuti.

Vedere l'articolo Introduzione alla gestione dei dispositivi per creare l'hub IoT e ottenere la stringa di connessione relativa.

Creare un hub IoT

Creare un hub IoT per connettere l'app per dispositivo simulato. La procedura seguente illustra come completare questa attività usando il portale di Azure.

  1. Accedere al portale di Azure.
  2. Nell'indice fare clic su Nuovo > Internet delle cose > Hub IoT.

    Indice del portale di Azure

  3. Nella finestra Hub IoT scegliere la configurazione per l'hub IoT.

    Finestra Hub IoT

    1. Nella casella Nome immettere un nome per l'hub IoT. Se il Nome è valido e disponibile, appare un segno di spunta verde nella casella Nome.

      Importante

      L'hub IoT sarà individuabile pubblicamente come endpoint DNS, quindi evitare di indicare informazioni riservate nell'assegnazione del nome.

    2. Selezionare un piano tariffario e un livello di scalabilità. Per questa esercitazione non è necessario un livello specifico. Per questa esercitazione, usare il livello F1 gratuito.

    3. In Gruppo di risorse creare un gruppo di risorse o selezionarne uno esistente. Per altre informazioni, vedere Using resource groups to manage your Azure resources (Uso di Gruppi di risorse per gestire le risorse di Azure).
    4. In Percorsoselezionare il percorso per ospitare l'hub IoT. Per questa esercitazione, scegliere la località più vicina.
  4. Dopo aver scelto le opzioni di configurazione dell'hub IoT, fare clic su Crea. La creazione dell'hub IoT da parte di Azure può richiedere alcuni minuti. Per verificare lo stato, è possibile monitorare l'avanzamento nella Schermata iniziale o nel pannello Notifiche.

  5. Dopo avere creato l'hub IoT, fare clic sul nuovo riquadro dell'hub IoT nel portale di Azure per aprire la finestra delle proprietà. Annotare il Nome host, quindi fare clic su Criteri di accesso condiviso.

    Finestra del nuovo hub IoT

  6. In Criteri di accesso condivisi fare clic sul criterio iothubowner, quindi copiare e annotare la stringa di connessione dell'hub IoT nella finestra iothubowner. Per altre informazioni, vedere Controllo di accesso nella "Guida per gli sviluppatori dell'hub IoT".

    Criteri di accesso condivisi

Creare un'identità del dispositivo

In questa sezione si usa uno strumento di Node.js denominato iothub-explorer per creare un'identità del dispositivo per questa esercitazione. Gli ID dispositivo fanno distinzione tra maiuscole e minuscole.

  1. Eseguire il codice seguente nell'ambiente della riga di comando:

    npm install -g iothub-explorer@latest

  2. Eseguire quindi il comando indicato di seguito per accedere all'hub. Sostituire {iot hub connection string} con la stringa di connessione all'hub IoT copiata prima:

    iothub-explorer login "{iot hub connection string}"

  3. Creare infine una nuova identità del dispositivo denominata myDeviceId con il comando:

    iothub-explorer create myDeviceId --connection-string

    Importante

    L'ID dispositivo può essere visibile nei log raccolti per il supporto tecnico e la risoluzione dei problemi, quindi evitare di indicare informazioni riservate nell'assegnazione del nome.

Annotare la stringa di connessione del dispositivo visualizzata nei risultati. Questa stringa di connessione del dispositivo viene usata dall'app del dispositivo per la connessione all'hub IoT come dispositivo.

Per creare identità del dispositivo a livello di codice, vedere Introduzione all'hub IoT.

Attivare un aggiornamento del firmware remoto nel dispositivo con un metodo diretto

In questa sezione viene creata un'app console .NET (tramite C#) che avvia un aggiornamento del firmware remoto in un dispositivo. L'applicazione usa un metodo diretto per avviare l'aggiornamento e usa le query di dispositivo gemello per ottenere periodicamente lo stato di aggiornamento del firmware attivo.

  1. In Visual Studio aggiungere un progetto desktop di Windows classico in Visual C# usando il modello di progetto Applicazione console . Assegnare al progetto il nome TriggerFWUpdate.

    Nuovo progetto desktop di Windows classico in Visual C#

  2. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto TriggerFWUpdate e quindi scegliere Gestisci pacchetti NuGet.

  3. Nella finestra Gestione pacchetti NuGet selezionare Esplora, cercare microsoft.azure.devices, selezionare Installa per installare il pacchetto Microsoft.Azure.Devices e accettare le condizioni per l'uso. Questa procedura scarica, installa e aggiunge un riferimento al pacchetto NuGet Azure IoT - SDK per dispositivi e alle relative dipendenze.

    Finestra Gestione pacchetti NuGet

  4. Aggiungere le istruzione using seguenti all'inizio del file Program.cs :

     using Microsoft.Azure.Devices;
     using Microsoft.Azure.Devices.Shared;
    
  5. Aggiungere i campi seguenti alla classe Program . Sostituire il valore dei segnaposti multipli con la stringa di connessione dell'hub IoT creato nella sezione precedente e l'ID del dispositivo.

     static RegistryManager registryManager;
     static string connString = "{iot hub connection string}";
     static ServiceClient client;
     static JobClient jobClient;
     static string targetDevice = "{deviceIdForTargetDevice}";
    
  6. Aggiungere il metodo seguente alla classe Program :

     public static async Task QueryTwinFWUpdateReported()
     {
         Twin twin = await registryManager.GetTwinAsync(targetDevice);
         Console.WriteLine(twin.Properties.Reported.ToJson());
     }
    
  7. Aggiungere il metodo seguente alla classe Program :

     public static async Task StartFirmwareUpdate()
     {
         client = ServiceClient.CreateFromConnectionString(connString);
         CloudToDeviceMethod method = new CloudToDeviceMethod("firmwareUpdate");
         method.ResponseTimeout = TimeSpan.FromSeconds(30);
         method.SetPayloadJson(
             @"{
                 fwPackageUri : 'https://someurl'
             }");
    
         CloudToDeviceMethodResult result = await client.InvokeDeviceMethodAsync(targetDevice, method);
    
         Console.WriteLine("Invoked firmware update on device.");
     }
    
  8. Aggiungere infine le righe seguenti al metodo Main :

     registryManager = RegistryManager.CreateFromConnectionString(connString);
     StartFirmwareUpdate().Wait();
     QueryTwinFWUpdateReported().Wait();
     Console.WriteLine("Press ENTER to exit.");
     Console.ReadLine();
    
  9. In Esplora soluzioni aprire Imposta progetti di avvio e assicurarsi che l'azione per il progetto TriggerFWUpdate sia impostata su Avvio.

  10. Compilare la soluzione.

Creare un'app di dispositivo simulato

In questa sezione verrà illustrato come:

  • Creare un'app console Node.js che risponde a un metodo diretto chiamato dal cloud
  • Attivare un aggiornamento del firmware simulato
  • Usare le proprietà segnalate per abilitare le query nei dispositivi gemelli in modo da identificare i dispositivi e l'ora dell'ultimo completamento di un aggiornamento del firmware
  1. Creare una cartella vuota denominata manageddevice. Nella cartella manageddevice creare un file package.json eseguendo questo comando al prompt dei comandi. Accettare tutte le impostazioni predefinite:

    npm init
    
  2. Eseguire questo comando al prompt dei comandi nella cartella manageddevice per installare i pacchetti SDK per dispositivi azure-iot-device e azure-iot-device-mqtt:

    npm install azure-iot-device azure-iot-device-mqtt --save
    
  3. Con un editor di testo creare un file dmpatterns_fwupdate_device.js nella cartella manageddevice.

  4. Aggiungere le istruzioni "require" seguenti all'inizio del file dmpatterns_fwupdate_device.js:

    'use strict';
    
    var Client = require('azure-iot-device').Client;
    var Protocol = require('azure-iot-device-mqtt').Mqtt;
    
  5. Aggiungere una variabile connectionString e usarla per creare un'istanza Client. Sostituire il segnaposto {yourdeviceconnectionstring} con la stringa di connessione di cui si è preso nota prima nella sezione "Create a device identity" (Creare un'identità del dispositivo):

    var connectionString = '{yourdeviceconnectionstring}';
    var client = Client.fromConnectionString(connectionString, Protocol);
    
  6. Aggiungere la funzione seguente che viene usata per aggiornare le proprietà segnalate:

    var reportFWUpdateThroughTwin = function(twin, firmwareUpdateValue) {
      var patch = {
          iothubDM : {
            firmwareUpdate : firmwareUpdateValue
          }
      };
    
      twin.properties.reported.update(patch, function(err) {
        if (err) throw err;
        console.log('twin state reported: ' + firmwareUpdateValue.status);
      });
    };
    
  7. Aggiungere le funzioni seguenti che simulano il download e l'applicazione dell'immagine del firmware:

    var simulateDownloadImage = function(imageUrl, callback) {
      var error = null;
      var image = "[fake image data]";
    
      console.log("Downloading image from " + imageUrl);
    
      callback(error, image);
    }
    
    var simulateApplyImage = function(imageData, callback) {
      var error = null;
    
      if (!imageData) {
        error = {message: 'Apply image failed because of missing image data.'};
      }
    
      callback(error);
    }
    
  8. Aggiungere la funzione seguente che imposta lo stato di aggiornamento del firmware tramite le proprietà segnalate su waiting. In genere i dispositivi vengono informati che è disponibile un aggiornamento e i criteri definiti dall'amministratore fanno in modo che il dispositivo avvii il download e applichi l'aggiornamento. In questa funzione viene eseguita la logica per abilitare tali criteri. Per semplicità, l'esempio attende quattro secondi prima di procedere al download dell'immagine del firmware:

    var waitToDownload = function(twin, fwPackageUriVal, callback) {
      var now = new Date();
    
      reportFWUpdateThroughTwin(twin, {
        fwPackageUri: fwPackageUriVal,
        status: 'waiting',
        error : null,
        startedWaitingTime : now.toISOString()
      });
      setTimeout(callback, 4000);
    };
    
  9. Aggiungere la funzione seguente che imposta lo stato di aggiornamento del firmware tramite le proprietà segnalate su downloading. La funzione simula quindi un download del firmware e infine imposta lo stato di aggiornamento del firmware su downloadFailed o su downloadComplete:

    var downloadImage = function(twin, fwPackageUriVal, callback) {
      var now = new Date();   
    
      reportFWUpdateThroughTwin(twin, {
        status: 'downloading',
      });
    
      setTimeout(function() {
        // Simulate download
        simulateDownloadImage(fwPackageUriVal, function(err, image) {
    
          if (err)
          {
            reportFWUpdateThroughTwin(twin, {
              status: 'downloadfailed',
              error: {
                code: error_code,
                message: error_message,
              }
            });
          }
          else {        
            reportFWUpdateThroughTwin(twin, {
              status: 'downloadComplete',
              downloadCompleteTime: now.toISOString(),
            });
    
            setTimeout(function() { callback(image); }, 4000);   
          }
        });
    
      }, 4000);
    }
    
  10. Aggiungere la funzione seguente che imposta lo stato di aggiornamento del firmware tramite le proprietà segnalate su applying. La funzione simula quindi l'applicazione dell'immagine del firmware e infine imposta lo stato di aggiornamento del firmware su applyFailed o su applyComplete:

    var applyImage = function(twin, imageData, callback) {
      var now = new Date();   
    
      reportFWUpdateThroughTwin(twin, {
        status: 'applying',
        startedApplyingImage : now.toISOString()
      });
    
      setTimeout(function() {
    
        // Simulate apply firmware image
        simulateApplyImage(imageData, function(err) {
          if (err) {
            reportFWUpdateThroughTwin(twin, {
              status: 'applyFailed',
              error: {
                code: err.error_code,
                message: err.error_message,
              }
            });
          } else { 
            reportFWUpdateThroughTwin(twin, {
              status: 'applyComplete',
              lastFirmwareUpdate: now.toISOString()
            });    
    
          }
        });
    
        setTimeout(callback, 4000);
    
      }, 4000);
    }
    
  11. Aggiungere la funzione seguente che gestisce il metodo diretto firmwareUpdate e avvia il processo di aggiornamento del firmware in più fasi:

    var onFirmwareUpdate = function(request, response) {
    
      // Respond the cloud app for the direct method
      response.send(200, 'FirmwareUpdate started', function(err) {
        if (!err) {
          console.error('An error occured when sending a method response:\n' + err.toString());
        } else {
          console.log('Response to method \'' + request.methodName + '\' sent successfully.');
        }
      });
    
      // Get the parameter from the body of the method request
      var fwPackageUri = request.payload.fwPackageUri;
    
      // Obtain the device twin
      client.getTwin(function(err, twin) {
        if (err) {
          console.error('Could not get device twin.');
        } else {
          console.log('Device twin acquired.');
    
          // Start the multi-stage firmware update
          waitToDownload(twin, fwPackageUri, function() {
            downloadImage(twin, fwPackageUri, function(imageData) {
              applyImage(twin, imageData, function() {});    
            });  
          });
    
        }
      });
    }
    
  12. Aggiungere infine il codice seguente che effettua la connessione all'hub IoT:

    client.open(function(err) {
      if (err) {
        console.error('Could not connect to IotHub client');
      }  else {
        console.log('Client connected to IoT Hub.  Waiting for firmwareUpdate direct method.');
      }
    
      client.onDeviceMethod('firmwareUpdate', onFirmwareUpdate);
    });
    

Nota

Per semplicità, in questa esercitazione non si implementa alcun criterio di ripetizione dei tentativi. Nel codice di produzione è consigliabile implementare criteri per i tentativi, ad esempio un backoff esponenziale, come illustrato nell'articolo di MSDN Transient Fault Handling (Gestione degli errori temporanei).

Eseguire le app

A questo punto è possibile eseguire le app.

  1. Al prompt dei comandi nella cartella manageddevice eseguire questo comando per iniziare l'ascolto del metodo diretto di riavvio.

    node dmpatterns_fwupdate_device.js
    
  2. In Visual Studio fare clic con il pulsante destro del mouse sul progetto TriggerFWUpdate, selezionare Debug e Avvia nuova istanza.

  3. Nella console viene visualizzata la risposta del dispositivo al metodo diretto.

    Firmware aggiornato

Passaggi successivi

In questa esercitazione è stato usato un metodo diretto per attivare un aggiornamento del firmware remoto in un dispositivo e sono state usate le proprietà segnalate per conoscere lo stato del processo di aggiornamento del firmware.

Per informazioni su come estendere la soluzione IoT e pianificare le chiamate al metodo su più dispositivi, vedere l'esercitazione Pianificare e trasmettere processi.