Tutorial: configurar os seus dispositivos a partir de um serviço de back-end

Como parte do ciclo de vida do dispositivo, talvez seja necessário configurar seus dispositivos IoT a partir do serviço back-end. Ao enviar uma configuração desejada para seus dispositivos, você também deseja receber atualizações de status e conformidade desses dispositivos. Por exemplo, poderá definir um intervalo pretendido para a temperatura de um dispositivo ou recolher informações sobre a versão do firmware dos seus dispositivos.

Para sincronizar as informações de estado entre um dispositivo e um hub do IoT, deve utilizar dispositivos duplos. Um dispositivo duplo é um documento JSON que é associado a um dispositivo específico e é armazenado pelo Hub IoT na nuvem, onde pode efetuar consultas sobre o mesmo. Um dispositivo duplo contém propriedades pretendidas, propriedades reportadas e etiquetas.

  • Uma propriedade desejada é definida por um aplicativo back-end e lida por um dispositivo.
  • Uma propriedade relatada é definida por um dispositivo e lida por um aplicativo back-end.
  • Uma tag é definida por um aplicativo back-end e nunca é enviada para um dispositivo. As etiquetas são utilizadas para organizar os seus 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, vai realizar as seguintes tarefas:

  • Criar um hub do IoT e adicionar um dispositivo de teste ao registo de identidades.
  • Utilizar as propriedades pretendidas para enviar informações de estado para o seu dispositivo simulado.
  • Utilizar as propriedades reportadas para receber informações de estado do seu dispositivo simulado.

Se não tiver uma subscrição 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 nele, poderá ignorar essas etapas. Há duas maneiras de executar comandos da CLI:

  • Os dois aplicativos de exemplo que você executa neste tutorial são escritos usando Node.js. Você precisa Node.js v10.x.x ou posterior em sua máquina de desenvolvimento.

    • Pode transferir o Node.js para múltiplas plataformas em nodejs.org.

    • Pode verificar qual a versão atual do Node.js no seu computador de desenvolvimento através do seguinte comando:

      node --version
      
  • Clone ou baixe o projeto de Node.js de exemplo de exemplos do Azure IoT para Node.js.

  • Verifique se a porta 8883 está aberta no firewall. O exemplo de dispositivo neste tutorial usa o protocolo MQTT, que se comunica pela porta 8883. Essa porta pode estar bloqueada em alguns ambientes de rede corporativa e educacional. Para obter mais informações e maneiras de contornar esse problema, consulte Conectando-se ao Hub IoT (MQTT).

Configurar recursos do Azure

Para concluir este tutorial, a sua subscrição do Azure tem de conter um hub do IoT com um dispositivo adicionado ao registo de identidades de dispositivos. A entrada no registo de identidades de dispositivos permite que o dispositivo simulado que executará neste tutorial se ligue ao seu hub.

Se você ainda não tiver um hub IoT configurado em sua assinatura, poderá configurá-lo com o seguinte script CLI. Esse script usa o nome tutorial-iot-hub com um número aleatório anexado 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 E.U.A. Central, que pode alterar para uma região mais próxima de si. O script obtém a cadeia de ligação do serviço do hub do IoT, que irá utilizar no exemplo de back-end para ligar ao seu hub do 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 utiliza um dispositivo simulado chamado MyTwinDevice. O seguinte script adiciona este dispositivo ao seu registo de identidades e obtém a respetiva cadeia de ligaçã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

As propriedades pretendidas são utilizadas para enviar informações de estado de uma aplicação de back-end para um dispositivo. Nesta secção, saberá como:

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

Propriedades pretendidas de exemplo

Pode estruturar as suas propriedades pretendidas da forma que for mais conveniente para a sua aplicação. Este exemplo utiliza uma propriedade de nível superior chamada fanOn e agrupa as restantes propriedades em componentes separados. O trecho JSON a seguir mostra a estrutura das propriedades desejadas usadas neste tutorial. O JSON está no arquivo desired.json.

{
  "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 ver o código de exemplo do dispositivo simulado que recebe as propriedades pretendidas, navegue para a pasta iot-hub/Tutorials/DeviceTwins no projeto de exemplo Node.js que transferiu. Em seguida, abra o ficheiro SimulatedDevice.js num 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 back-end.

Obter o objeto do dispositivo duplo

Quando você registrou seu dispositivo no hub IoT, obteve 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 seguinte código liga o seu hub do IoT através de uma cadeia de ligação do dispositivo:

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

O seguinte código obtém um duplo a partir 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 processadores

Pode criar processadores para atualizações de propriedades pretendidas que correspondam a atualizações de diferentes níveis na hierarquia de JSON. Por exemplo, este processador monitoriza todas as alterações de propriedades pretendidas enviadas para o dispositivo a partir de uma aplicação de back-end. A variável delta contém as propriedades pretendidas enviadas a partir da solução de back-end:

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

O seguinte processador só reage a alterações feitas à propriedade pretendida 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}';
});

Processadores para múltiplas propriedades

No exemplo de propriedades desejadas JSON para este tutorial, o nó de clima sob componentes contém duas propriedades, minTemperature e maxTemperature.

O objeto duplo local de um dispositivo armazena um conjunto completo de propriedades pretendidas e reportadas. A variável delta enviada do back-end pode atualizar apenas um subconjunto de propriedades pretendidas. No seguinte fragmento de código, se o dispositivo simulado receber uma atualização a uma das propriedades, minTemperature ou maxTemperature, utilizará o valor no objeto duplo local do 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();
    }
});

Processar operações de inserção, atualização e eliminação

As propriedades pretendidas enviadas a partir do back-end não indicam qual a operação que está a ser realizada numa propriedade pretendida específica. O seu código tem de deduzir qual é a operação, com base no conjunto atual de propriedades pretendidas armazenadas localmente e nas alterações enviadas a partir do hub.

O seguinte fragmento de código mostra como o dispositivo simulado processa operações de inserção, atualização e eliminação na lista de componentes nas propriedades pretendidas. Pode ver como utilizar valores nulos para indicar que um componente deve ser eliminado:

// 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 propriedades desejadas de um aplicativo back-end

Já viu como um dispositivo implementa processadores para receber atualizações de propriedades pretendidas. Esta secção mostra-lhe como enviar alterações de propriedades pretendidas para um dispositivo a partir de uma aplicação de back-end.

Para ver o código de exemplo do dispositivo simulado que recebe as propriedades pretendidas, navegue para a pasta iot-hub/Tutorials/DeviceTwins no projeto de exemplo Node.js que transferiu. Em seguida, abra o ficheiro ServiceClient.js num editor de texto.

O seguinte fragmento de código mostra-lhe como ligar ao registo de identidades de dispositivos e aceder ao duplo de 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 seguinte fragmento de código mostra diferentes patches de propriedades pretendidas que a aplicação de back-end envia para o 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 seguinte fragmento de código mostra como a aplicação de back-end envia uma atualização de propriedades pretendidas para 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

A sua aplicação de back-end recebe as informações de estado de um dispositivo na forma de propriedades reportadas. O dispositivo define as propriedades reportadas e envia-as para o seu hub. A aplicação de back-end consegue ler os valores atuais das propriedades reportadas do dispositivo duplo armazenado no seu hub.

Enviar propriedades reportadas a partir de um dispositivo

Pode enviar as atualizações feitas aos valores das propriedades reportadas como um patch. O seguinte fragmento de código mostra um modelo do patch que o dispositivo simulado envia. O dispositivo simulado atualiza os campos no patch antes de o enviar para o hub:

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

O dispositivo simulado utiliza a seguinte função para enviar o patch que contém as propriedades reportadas para o 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 reportadas

Uma aplicação de back-end acede aos valores atuais das propriedades reportadas de um dispositivo através do dispositivo duplo. O seguinte fragmento de código mostra-lhe como a aplicação de back-end lê os valores das propriedades reportadas 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 as aplicações

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

Para executar as aplicações de back-end e de dispositivo simulado, precisa das cadeias de ligação do serviço e do dispositivo. Tomou nota das cadeias de ligação quando criou os recursos no início deste tutorial.

Para executar a aplicação de dispositivo simulado, abra uma janela da linha de comandos ou shell e navegue para a pasta iot-hub/Tutorials/DeviceTwins no projeto Node.js que transferiu. Em seguida, execute os seguintes comandos:

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

Para executar a aplicação de back-end, abra outra janela da linha de comandos ou shell. Navegue para a pasta iot-hub/Tutorials/DeviceTwins no projeto Node.js que transferiu. Em seguida, execute os seguintes comandos:

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

Observe as atualizações de propriedade desejadas

A seguinte captura de ecrã mostra os dados de saída da aplicação de dispositivo simulado e realça como esta processa uma atualização feita à propriedade pretendida maxTemperature. Pode ver como o processador de nível superior e os processadores de componentes de clima são executados:

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

A seguinte captura de ecrã mostra os dados de saída da aplicação de back-end e realça como esta envia uma atualização feita à propriedade pretendida maxTemperature:

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

Observe as atualizações de propriedade relatadas

A seguinte captura de ecrã mostra os dados de saída da aplicação de dispositivo simulado e realça como esta envia uma atualização de propriedades reportadas para o seu 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 ele recebe e processa uma atualização de propriedade relatada de um dispositivo:

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

Clean up resources (Limpar recursos)

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

Se já não precisar do Hub IoT, elimine-o, bem como ao grupo de recursos, no portal. Para fazer isso, selecione o grupo de recursos tutorial-iot-hub-rg que contém seu hub IoT e selecione Excluir.

Em alternativa, utilize a CLI:

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

Próximos passos

Neste tutorial, aprendeu a sincronizar informações de estado entre os seus dispositivos e o seu hub do IoT. Avance para o próximo tutorial para aprender a usar gêmeos de dispositivo para implementar o processo de atualização de dispositivo.