Tutorial: Configurar seus dispositivos de um serviço de back-end

Como parte do ciclo de vida do dispositivo, talvez seja necessário configurar seus dispositivos IoT do serviço de back-end. Ao enviar uma configuração desejada aos dispositivos, você também vai querer receber atualizações de conformidade e status desses dispositivos. Por exemplo, você pode definir uma faixa de temperatura operacional de destino para um dispositivo ou coletar informações de versão de firmware dos dispositivos.

Para sincronizar informações de estado entre um dispositivo e um Hub IoT, você usa dispositivos gêmeos. Um dispositivo gêmeo é um documento JSON, associado a um dispositivo específico e armazenado pelo Hub IoT na nuvem, onde é possível pesquisá-los. Um dispositivo gêmeo contém propriedades desejadas, propriedades relatadas e marcas.

  • Uma propriedade desejada é definida por um aplicativo de back-end e lida por um dispositivo.
  • Uma propriedade relatada é definida por um dispositivo e lida por um aplicativo de back-end.
  • Uma marca é definida por um aplicativo de back-end e nunca é enviada para um dispositivo. As marcas são usadas para organizar os dispositivos.

Este tutorial mostra como usar as propriedades desejadas e relatadas para sincronizar informações de estado.

Diagram of device twins on the device and in the cloud.

Neste tutorial, você executa as seguintes tarefas:

  • Criar um Hub IoT e adicionar um dispositivo de teste ao registro de identidade.
  • Usar as propriedades desejadas para enviar informações de estado ao dispositivo simulado.
  • Usar as propriedades relatadas para receber informações de estado do dispositivo simulado.

Se você não tiver uma assinatura do Azure, crie uma conta gratuita antes de começar.

Pré-requisitos

  • Este tutorial usa a CLI do Azure para criar recursos de nuvem. Se você já tiver um hub IoT com um dispositivo registrado, ignore essas etapas. Há duas maneiras de executar comandos da CLI:

  • Os dois exemplos de aplicativo executados neste tutorial são escritos usando o Node.js. Você precisa do Node.js v10.x.x ou posterior em seu computador de desenvolvimento.

    • Você pode fazer o download do Node.js para várias plataformas a partir do nodejs.org.

    • Você pode verificar a versão atual do Node.js no computador de desenvolvimento usando o seguinte comando:

      node --version
      
  • Clone ou baixe o projeto de Node.js de exemplo em Exemplos de Internet das Coisas do Azure para Node.js.

  • Verifique se a porta 8883 está aberta no firewall. A amostra de dispositivo deste tutorial usa o protocolo MQTT, que se comunica pela porta 8883. Essa porta poderá ser bloqueada em alguns ambientes de rede corporativos e educacionais. Para obter mais informações e maneiras de resolver esse problema, confira Como se conectar ao Hub IoT (MQTT).

Configurar recursos do Azure

Para concluir este tutorial, a assinatura do Azure deve conter um Hub IoT com um dispositivo adicionado ao registro de identidade do dispositivo. A entrada no registro de identidade do dispositivo permite que o dispositivo simulado executado neste tutorial conecte-se ao hub.

Se ainda não houver um Hub IoT configurado na assinatura, será possível configurar um com o script de CLI a seguir. Esse script usa o nome tutorial-iot-hub com um número aleatório acrescentado para o nome do hub IoT. Você pode substituir esse nome por seu próprio nome globalmente exclusivo ao executá-lo. O script cria o grupo de recursos e o hub na região Centro dos EUA, a qual é possível alterar para uma região mais próxima a você. O script recupera a cadeia de conexão de serviço do Hub IoT, que é usado no exemplo de back-end para conectar ao Hub IoT:

let "randomIdentifier=$RANDOM*$RANDOM"  
hubname="tutorial-iot-hub-$randomIdentifier"
location=centralus

# Install the IoT extension if it's not already installed:
az extension add --name azure-iot

# Create a resource group:
az group create --name tutorial-iot-hub-rg --location $location

# Create your free-tier IoT hub. You can only have one free IoT hub per subscription.
# Change the sku to S1 to create a standard-tier hub if necessary.
az iot hub create --name $hubname --location $location --resource-group tutorial-iot-hub-rg --partition-count 2 --sku F1

# Make a note of the service connection string, you need it later:
az iot hub connection-string show --hub-name $hubname --policy-name service -o table

Este tutorial usa um dispositivo simulado chamado MyTwinDevice. O script a seguir adiciona esse dispositivo ao registro de identidade e recupera a cadeia de conexão:

# Create the device in the identity registry:
az iot hub device-identity create --device-id MyTwinDevice --hub-name $hubname --resource-group tutorial-iot-hub-rg

# Retrieve the device connection string, you need this later:
az iot hub device-identity connection-string show --device-id MyTwinDevice --hub-name $hubname --resource-group tutorial-iot-hub-rg -o table

Enviar informações de estado para um dispositivo

Você usa as propriedades desejadas para enviar informações de estado de um aplicativo de back-end para um dispositivo. Nesta seção, você verá como:

  • Configure um dispositivo para receber e processar as propriedades desejadas.
  • Envie as propriedades desejadas de um aplicativo de back-end para um dispositivo.

Exemplo de propriedades desejadas

É possível estruturar as propriedades desejadas de qualquer maneira que seja conveniente ao aplicativo. Este exemplo usa uma propriedade de nível superior chamada fanOn e agrupa as propriedades restantes em componentes separados. O snippet de código JSON a seguir mostra a estrutura das propriedades desejadas que este tutorial usa. O JSON está no arquivo .json desejado.

{
  "fanOn": "true",
  "components": {
    "system": {
      "id": "17",
      "units": "farenheit",
      "firmwareVersion": "9.75"
    },
    "wifi" : { 
      "channel" : "6",
      "ssid": "my_network"
    },
    "climate" : {
      "minTemperature": "68",
      "maxTemperature": "76"
    }
  }
}

Receber as propriedades desejadas em um aplicativo de dispositivo

Para exibir o código de exemplo do dispositivo simulado que recebe as propriedades desejadas, navegue até a pasta iot-hub/Tutorials/DeviceTwins no projeto Node.js de exemplo transferido por download. Em seguida, abra o arquivo SimulatedDevice.js em um editor de texto.

As seções a seguir descrevem o código executado no dispositivo simulado que responde às alterações de propriedade desejadas enviadas do aplicativo de back-end.

Recuperar o objeto de dispositivo gêmeo

Ao registrar seu dispositivo no hub IoT, você tem uma cadeia de conexão de dispositivo como saída. Uma cadeia de conexão de dispositivo é usada pelo dispositivo para autenticar com sua identidade registrada na nuvem. O código a seguir conecta o Hub IoT usando uma cadeia de conexão de dispositivo:

// Get the device connection string from a command line argument
var connectionString = process.argv[2];

O código a seguir obtém um dispositivo gêmeo do objeto de cliente:

// Get the device twin
client.getTwin(function(err, twin) {
  if (err) {
    console.error(chalk.red('Could not get device twin'));
  } else {
    console.log(chalk.green('Device twin created'));

Criar manipuladores

É possível criar manipuladores para atualizações de propriedades desejadas que respondem a atualizações em diferentes níveis na hierarquia JSON. Por exemplo, esse manipulador vê todas as alterações de propriedade desejadas enviadas ao dispositivo a partir de um aplicativo de back-end. A variável delta contém as propriedades desejadas enviadas do back-end da solução:

// Handle all desired property updates
twin.on('properties.desired', function(delta) {
    console.log(chalk.yellow('\nNew desired properties received in patch:'));

O manipulador a seguir reage apenas às alterações feitas na propriedade desejada fanOn:

// Handle changes to the fanOn desired property
twin.on('properties.desired.fanOn', function(fanOn) {
    console.log(chalk.green('\nSetting fan state to ' + fanOn));

    // Update the reported property after processing the desired property
    reportedPropertiesPatch.fanOn = fanOn ? fanOn : '{unknown}';
});

Manipuladores para várias propriedades

No JSON de exemplo de propriedades desejadas deste tutorial, o nó clima em componentes contém duas propriedades, minTemperature and maxTemperature.

Um objeto gêmeo local do dispositivo armazena um conjunto completo de propriedades desejadas e relatadas. A variável delta enviada do back-end pode atualizar apenas um subconjunto de propriedades desejadas. No snippet de código a seguir, se o dispositivo simulado receber uma atualização apenas para um dos valores minTemperature e maxTemperature, ele usará o valor no gêmeo local para o outro valor para configurar o dispositivo:

// Handle desired properties updates to the climate component
twin.on('properties.desired.components.climate', function(delta) {
    if (delta.minTemperature || delta.maxTemperature) {
      console.log(chalk.green('\nUpdating desired tempertures in climate component:'));
      console.log('Configuring minimum temperature: ' + twin.properties.desired.components.climate.minTemperature);
      console.log('Configuring maximum temperture: ' + twin.properties.desired.components.climate.maxTemperature);

      // Update the reported properties and send them to the hub
      reportedPropertiesPatch.minTemperature = twin.properties.desired.components.climate.minTemperature;
      reportedPropertiesPatch.maxTemperature = twin.properties.desired.components.climate.maxTemperature;
      sendReportedProperties();
    }
});

Manipular operações de inserção, atualização e exclusão

As propriedades desejadas enviadas do back-end não indicam qual operação está sendo executada em uma propriedade desejada específica. O código precisa inferir a operação do conjunto atual de propriedades desejadas armazenadas localmente e as alterações enviadas do hub.

O snippet de código a seguir mostra como o dispositivo simulado manipula operações de inserção, atualização e exclusão na lista de componentes nas propriedades desejadas. É possível ver como utilizar valores nulos para indicar que um componente deve ser excluído:

// Keep track of all the components the device knows about
var componentList = {};

// Use this componentList list and compare it to the delta to infer
// if anything was added, deleted, or updated.
twin.on('properties.desired.components', function(delta) {
  if (delta === null) {
    componentList = {};
  }
  else {
    Object.keys(delta).forEach(function(key) {

      if (delta[key] === null && componentList[key]) {
        // The delta contains a null value, and the
        // device has a record of this component.
        // Must be a delete operation.
        console.log(chalk.green('\nDeleting component ' + key));
        delete componentList[key];

      } else if (delta[key]) {
        if (componentList[key]) {
          // The delta contains a component, and the
          // device has a record of it.
          // Must be an update operation.
          console.log(chalk.green('\nUpdating component ' + key + ':'));
          console.log(JSON.stringify(delta[key]));
          // Store the complete object instead of just the delta
          componentList[key] = twin.properties.desired.components[key];

        } else {
          // The delta contains a component, and the
          // device has no record of it.
          // Must be an add operation.
          console.log(chalk.green('\nAdding component ' + key + ':'));
          console.log(JSON.stringify(delta[key]));
          // Store the complete object instead of just the delta
          componentList[key] = twin.properties.desired.components[key];
        }
      }
    });
  }
});

Enviar as propriedades desejadas de um aplicativo de back-end

Vimos como um dispositivo implementa manipuladores para receber atualizações de propriedade desejadas. Esta seção mostra como enviar alterações de propriedade desejadas a um dispositivo a partir de um aplicativo de back-end.

Para exibir o código de exemplo do dispositivo simulado que recebe as propriedades desejadas, navegue até a pasta iot-hub/Tutorials/DeviceTwins no projeto Node.js de exemplo transferido por download. Em seguida, abra o arquivo ServiceClient.js em um editor de texto.

O snippet de código a seguir mostra como conectar o registro de identidade do dispositivo e acessar o gêmeo para um dispositivo específico:

// Create a device identity registry object
var registry = Registry.fromConnectionString(connectionString);

// Get the device twin and send desired property update patches at intervals.
// Print the reported properties after some of the desired property updates.
registry.getTwin(deviceId, async (err, twin) => {
  if (err) {
    console.error(err.message);
  } else {
    console.log('Got device twin');

O snippet de código a seguir mostra diferentes patches de propriedade desejada que o aplicativo de back-end envia ao dispositivo:

// Turn the fan on
var twinPatchFanOn = {
  properties: {
    desired: {
      patchId: "Switch fan on",
      fanOn: "false",
    }
  }
};

// Set the maximum temperature for the climate component
var twinPatchSetMaxTemperature = {
  properties: {
    desired: {
      patchId: "Set maximum temperature",
      components: {
        climate: {
          maxTemperature: "92"
        }
      }
    }
  }
};

// Add a new component
var twinPatchAddWifiComponent = {
  properties: {
    desired: {
      patchId: "Add WiFi component",
      components: {
        wifi: { 
          channel: "6",
          ssid: "my_network"
        }
      }
    }
  }
};

// Update the WiFi component
var twinPatchUpdateWifiComponent = {
  properties: {
    desired: {
      patchId: "Update WiFi component",
      components: {
        wifi: { 
          channel: "13",
          ssid: "my_other_network"
        }
      }
    }
  }
};

// Delete the WiFi component
var twinPatchDeleteWifiComponent = {
  properties: {
    desired: {
      patchId: "Delete WiFi component",
      components: {
        wifi: null
      }
    }
  }
};

O snippet de código a seguir mostra como o aplicativo de back-end envia uma atualização de propriedade desejada a um dispositivo:

// Send a desired property update patch
async function sendDesiredProperties(twin, patch) {
  twin.update(patch, (err, twin) => {
    if (err) {
      console.error(err.message);
    } else {
      console.log(chalk.green(`\nSent ${twin.properties.desired.patchId} patch:`));
      console.log(JSON.stringify(patch, null, 2));
    }
  });
}

Receber informações de estado de um dispositivo

O aplicativo de back-end recebe informações de estado de um dispositivo como propriedades relatadas. Um dispositivo define as propriedades relatadas e as envia ao hub. Um aplicativo de back-end pode ler os valores atuais das propriedades relatadas do dispositivo gêmeo armazenado no hub.

Enviar propriedades relatadas de um dispositivo

É possível enviar atualizações para valores de propriedade relatados como um patch. O snippet de código a seguir mostra um modelo para o patch enviado pelo dispositivo simulado. O dispositivo simulado atualiza os campos no patch antes de enviá-lo ao hub:

// Create a patch to send to the hub
var reportedPropertiesPatch = {
  firmwareVersion:'1.2.1',
  lastPatchReceivedId: '',
  fanOn:'',
  minTemperature:'',
  maxTemperature:''
};

O dispositivo simulado usa a função a seguir para enviar o patch que contém as propriedades relatadas ao hub:

// Send the reported properties patch to the hub
function sendReportedProperties() {
  twin.properties.reported.update(reportedPropertiesPatch, function(err) {
    if (err) throw err;
    console.log(chalk.blue('\nTwin state reported'));
    console.log(JSON.stringify(reportedPropertiesPatch, null, 2));
  });
}

Processar propriedades relatadas

Um aplicativo de back-end acessa os valores de propriedade relatados atuais para um dispositivo por meio do dispositivo gêmeo. O snippet de código a seguir mostra como o aplicativo de back-end lê os valores da propriedade relatada do dispositivo simulado:

// Display the reported properties from the device
function printReportedProperties(twin) {
  console.log("Last received patch: " + twin.properties.reported.lastPatchReceivedId);
  console.log("Firmware version: " + twin.properties.reported.firmwareVersion);
  console.log("Fan status: " + twin.properties.reported.fanOn);
  console.log("Min temperature set: " + twin.properties.reported.minTemperature);
  console.log("Max temperature set: " + twin.properties.reported.maxTemperature);
}

Executar os aplicativos

Nesta seção, você executará os dois aplicativos de exemplo para observar como um aplicativo de back-end envia atualizações de propriedades desejadas a um aplicativo de dispositivo simulado.

Para executar o dispositivo simulado e os aplicativos de back-end, serão necessários as cadeias de conexão de serviço e dispositivo. Você fez uma anotação das cadeias de conexão quando criou os recursos no início deste tutorial.

Para executar o aplicativo de dispositivo simulado, abra uma janela do prompt de comando ou shell e navegue até a pasta iot-hub/Tutorials/DeviceTwins no projeto Node.js que você baixou. Em seguida, execute os comandos a seguir:

npm install
node SimulatedDevice.js "{your device connection string}"

Para executar o aplicativo de back-end, abra outra janela do prompt de comando ou shell. Em seguida, navegue até a pasta iot-hub/Tutorials/DeviceTwins no projeto Node.js que você baixou. Em seguida, execute os comandos a seguir:

npm install
node ServiceClient.js "{your service connection string}"

Observar as atualizações de propriedade desejadas

A captura de tela a seguir mostra a saída do aplicativo de dispositivo simulado e destaca como ele trata uma atualização para a propriedade desejada maxTemperature. É possível ver como o manipulador de nível superior e os manipuladores de componente de clima executam:

Screenshot that shows how both the top-level handler and the climate component handlers run.

A captura de tela a seguir mostra a saída do aplicativo de back-end e destaca como ele envia uma atualização para a propriedade desejada maxTemperature:

Screenshot that shows the output from the back-end application and highlights how it sends an update.

Observar as atualizações de propriedade relatada

A captura de tela a seguir mostra a saída do aplicativo de dispositivo simulado e destaca como ele envia uma atualização de propriedade relatada ao hub:

Screenshot that shows the simulated device updating its twin state.

A captura de tela a seguir mostra a saída do aplicativo back-end e destaca como ela recebe e processa uma atualização de propriedade relatada de um dispositivo:

Screenshot that shows the back-end application receiving the device reported properties.

Limpar os recursos

Se você planeja concluir o próximo tutorial, deixe o grupo de recursos e o hub IoT para reutilizá-los posteriormente.

Se você não precisar mais do hub IoT, exclua-o junto com o grupo de recursos no portal. Para fazer isso, selecione o grupo de recursos tutorial-iot-hub-rg que contém o hub IoT e selecione Excluir.

Como alternativa, use a CLI:

# Delete your resource group and its contents
az group delete --name tutorial-iot-hub-rg

Próximas etapas

Neste tutorial, você aprendeu a sincronizar informações de estado entre os dispositivos e o Hub IoT. Avance para o próximo tutorial para aprender a usar dispositivos gêmeos para implementar um processo de atualização de firmware.