Conexión del dispositivo al acelerador de soluciones de supervisión remota (Node.js)

En este tutorial, implementará un dispositivo Refrigerador que envía la siguiente telemetría al acelerador de soluciones de supervisión remota:

  • Temperatura
  • Presión
  • Humedad

Para simplificar, el código genera valores de telemetría de ejemplo para el Chiller. Puede ampliar el ejemplo conectando sensores reales al dispositivo y enviando telemetría real.

El dispositivo de ejemplo también:

  • Envía los metadatos a la solución para describir sus funcionalidades.
  • Responde a las acciones que se desencadenan desde la página Dispositivos de la solución.
  • Responde a los cambios de configuración que se envían desde la página Dispositivos de la solución.

Para completar este tutorial, deberá tener una cuenta activa de Azure. En caso de no tener cuenta, puede crear una de evaluación gratuita en tan solo unos minutos. Para obtener más información, consulte Evaluación gratuita de Azure.

Antes de comenzar

Antes de escribir ningún código para el dispositivo, implemente el acelerador de soluciones de supervisión remota y agregue un nuevo dispositivo real a la solución.

Implementación del acelerador de soluciones de supervisión remota

El dispositivo Refrigerador que se crea en este tutorial envía datos a una instancia del acelerador de soluciones de supervisión remota. Si todavía no ha aprovisionado el acelerador de soluciones de supervisión remota en su cuenta de Azure, consulte Implementación del acelerador de soluciones de supervisión remota.

Cuando finalice el proceso de implementación para la solución de supervisión remota, haga clic en Iniciar para abrir el panel de la solución en el explorador.

El panel de soluciones

Adición del dispositivo a la solución de supervisión remota

Nota

Si ya ha agregado un dispositivo a la solución, puede omitir este paso. Sin embargo, el paso siguiente requiere la cadena de conexión del dispositivo. Puede recuperar la cadena de conexión de un dispositivo desde Azure Portal o con la herramienta CLI az iot.

Para que un dispositivo se conecte al acelerador de soluciones, debe identificarse en IoT Hub con credenciales válidas. Tendrá la oportunidad de guardar la cadena de conexión del dispositivo que contiene estas credenciales cuando agregue el dispositivo a la solución. Más adelante en este tutorial incluirá esta cadena en su aplicación cliente.

Para agregar un dispositivo a la solución de supervisión remota, realice los pasos siguientes en la página Explorador de dispositivos de la solución:

  1. Elija + Nuevo dispositivo y, luego, Real en Tipo de dispositivo:

    Adición de un dispositivo real

  2. Escriba Refrigerador físico como identificador de dispositivo. Elija las opciones Clave simétrica y Generar claves automáticamente:

    Elección de las opciones de dispositivo

  3. Elija Aplicar. A continuación, anote los valores de Id. de dispositivo, Clave principal y Cadena de conexión: clave principal:

    Recuperación de las credenciales

Ya ha agregado un dispositivo real al acelerador de soluciones de supervisión remota y ha anotado la cadena de conexión del dispositivo. En las siguientes secciones, implementará la aplicación cliente que utiliza la cadena de conexión del dispositivo para conectarse a la solución.

La aplicación cliente implementa el modelo de dispositivo Chiller integrado. Un modelo de dispositivo de acelerador de soluciones especifica lo siguiente acerca de un dispositivo:

  • Las propiedades que el dispositivo notifica a la solución. Por ejemplo, un dispositivo Chiller notifica información acerca de su ubicación y firmware.
  • Los tipos de telemetría que el dispositivo envía a la solución. Por ejemplo, un dispositivo Chiller envía los valores de temperatura, humedad y presión.
  • Los métodos que puede programar desde la solución para ejecutarse en el dispositivo. Por ejemplo, un dispositivo refrigerador debe implementar los métodos Reboot, FirmwareUpdate, EmergencyValveRelease e IncreasePressuree.

En este tutorial se muestra cómo conectar un dispositivo real al acelerador de soluciones de supervisión remota. En este tutorial, se usa Node.js, que es una buena opción para entornos con las restricciones de recursos mínimos.

Si prefiere simular un dispositivo, consulte Crear y probar un nuevo dispositivo simulado.

Creación de una solución Node.js

Asegúrese de que tiene instalada la versión 4.0.0 o posterior de Node.js en la máquina de desarrollo. Para comprobar la versión, puede ejecutar node --version en la línea de comandos.

  1. Cree una carpeta denominada remotemonitoring en la máquina de desarrollo. Vaya a esta carpeta en el entorno de línea de comandos.

  2. Para descargar e instalar los paquetes que necesita para realizar la aplicación de ejemplo, ejecute los comandos siguientes:

    npm init
    npm install async azure-iot-device azure-iot-device-mqtt --save
    
  3. En la carpeta remotemonitoring, cree un archivo llamado remote_monitoring.js. Abra este archivo en un editor de texto.

  4. En el archivo remote_monitoring.js, agregue las siguientes instrucciones require:

    var Protocol = require('azure-iot-device-mqtt').Mqtt;
    var Client = require('azure-iot-device').Client;
    var Message = require('azure-iot-device').Message;
    var async = require('async');
    
  5. Agregue las siguientes declaraciones de variable después de las instrucciones require . Sustituya el valor del marcador de posición {device connection string} por el valor que ha anotado para el dispositivo que ha aprovisionado en la solución de supervisión remota:

    var connectionString = '{device connection string}';
    
  6. Para definir algunos datos de telemetría básicos, agregue las siguientes variables:

    var temperature = 50;
    var temperatureUnit = 'F';
    var humidity = 50;
    var humidityUnit = '%';
    var pressure = 55;
    var pressureUnit = 'psig';
    
  7. Para definir algunos valores de propiedades, agregue las siguientes variables:

    var schema = "real-chiller;v1";
    var deviceType = "RealChiller";
    var deviceFirmware = "1.0.0";
    var deviceFirmwareUpdateStatus = "";
    var deviceLocation = "Building 44";
    var deviceLatitude = 47.638928;
    var deviceLongitude = -122.13476;
    var deviceOnline = true;
    
  8. Agregue la siguiente variable para definir las propiedades notificadas para enviar a la solución. Estas propiedades incluyen los metadatos que se van a mostrar en la interfaz de usuario web:

    var reportedProperties = {
      "SupportedMethods": "Reboot,FirmwareUpdate,EmergencyValveRelease,IncreasePressure",
      "Telemetry": {
        [schema]: ""
      },
      "Type": deviceType,
      "Firmware": deviceFirmware,
      "FirmwareUpdateStatus": deviceFirmwareUpdateStatus,
      "Location": deviceLocation,
      "Latitude": deviceLatitude,
      "Longitude": deviceLongitude,
      "Online": deviceOnline
    }
    
  9. Para imprimir los resultados de la operación, agregue la función auxiliar siguiente:

    function printErrorFor(op) {
        return function printError(err) {
            if (err) console.log(op + ' error: ' + err.toString());
        };
    }
    
  10. Agregue la siguiente función auxiliar para aleatorizar los valores de telemetría:

    function generateRandomIncrement() {
        return ((Math.random() * 2) - 1);
    }
    
  11. Agregue la siguiente función genérica para controlar las llamadas al método directo desde la solución. La función muestra información sobre el método directo que se ha invocado, pero en este ejemplo no se modifica el dispositivo en modo alguno. La solución utiliza métodos directos para actuar en los dispositivos:

    function onDirectMethod(request, response) {
      // Implement logic asynchronously here.
      console.log('Simulated ' + request.methodName);
    
      // Complete the response
      response.send(200, request.methodName + ' was called on the device', function (err) {
        if (err) console.error('Error sending method response :\n' + err.toString());
        else console.log('200 Response to method \'' + request.methodName + '\' sent successfully.');
      });
    }
    
  12. Agregue la siguiente función para controlar las llamadas al método directo FirmwareUpdate desde la solución. La función verifica los parámetros pasados en la carga del método directo y, a continuación, ejecuta de forma asincrónica una simulación de actualización de firmware:

    function onFirmwareUpdate(request, response) {
      // Get the requested firmware version from the JSON request body
      var firmwareVersion = request.payload.Firmware;
      var firmwareUri = request.payload.FirmwareUri;
    
      // Ensure we got a firmware values
      if (!firmwareVersion || !firmwareUri) {
        response.send(400, 'Missing firmware value', function(err) {
          if (err) console.error('Error sending method response :\n' + err.toString());
          else console.log('400 Response to method \'' + request.methodName + '\' sent successfully.');
        });
      } else {
        // Respond the cloud app for the device method
        response.send(200, 'Firmware update started.', function(err) {
          if (err) console.error('Error sending method response :\n' + err.toString());
          else {
            console.log('200 Response to method \'' + request.methodName + '\' sent successfully.');
    
            // Run the simulated firmware update flow
            runFirmwareUpdateFlow(firmwareVersion, firmwareUri);
          }
        });
      }
    }
    
  13. Agregue la siguiente función para simular un flujo de actualización de firmware de larga duración que informe del progreso a la solución:

    // Simulated firmwareUpdate flow
    function runFirmwareUpdateFlow(firmwareVersion, firmwareUri) {
      console.log('Simulating firmware update flow...');
      console.log('> Firmware version passed: ' + firmwareVersion);
      console.log('> Firmware URI passed: ' + firmwareUri);
      async.waterfall([
        function (callback) {
          console.log("Image downloading from " + firmwareUri);
          var patch = {
            FirmwareUpdateStatus: 'Downloading image..'
          };
          reportUpdateThroughTwin(patch, callback);
          sleep(10000, callback);
        },
        function (callback) {
          console.log("Downloaded, applying firmware " + firmwareVersion);
          deviceOnline = false;
          var patch = {
            FirmwareUpdateStatus: 'Applying firmware..',
            Online: false
          };
          reportUpdateThroughTwin(patch, callback);
          sleep(8000, callback);
        },
        function (callback) {
          console.log("Rebooting");
          var patch = {
            FirmwareUpdateStatus: 'Rebooting..'
          };
          reportUpdateThroughTwin(patch, callback);
          sleep(10000, callback);
        },
        function (callback) {
          console.log("Firmware updated to " + firmwareVersion);
          deviceOnline = true;
          var patch = {
            FirmwareUpdateStatus: 'Firmware updated',
            Online: true,
            Firmware: firmwareVersion
          };
          reportUpdateThroughTwin(patch, callback);
          callback(null);
        }
      ], function(err) {
        if (err) {
          console.error('Error in simulated firmware update flow: ' + err.message);
        } else {
          console.log("Completed simulated firmware update flow");
        }
      });
    
      // Helper function to update the twin reported properties.
      function reportUpdateThroughTwin(patch, callback) {
        console.log("Sending...");
        console.log(JSON.stringify(patch, null, 2));
        client.getTwin(function(err, twin) {
          if (!err) {
            twin.properties.reported.update(patch, function(err) {
              if (err) callback(err);
            });      
          } else {
            if (err) callback(err);
          }
        });
      }
    
      function sleep(milliseconds, callback) {
        console.log("Simulate a delay (milleseconds): " + milliseconds);
        setTimeout(function () {
          callback(null);
        }, milliseconds);
      }
    }
    
  14. Agregue el código siguiente para enviar los datos de telemetría a la solución. La aplicación cliente agrega propiedades al mensaje para identificar el esquema del mensaje:

    function sendTelemetry(data, schema) {
      if (deviceOnline) {
        var d = new Date();
        var payload = JSON.stringify(data);
        var message = new Message(payload);
        message.properties.add('iothub-creation-time-utc', d.toISOString());
        message.properties.add('iothub-message-schema', schema);
    
        console.log('Sending device message data:\n' + payload);
        client.sendEvent(message, printErrorFor('send event'));
      } else {
        console.log('Offline, not sending telemetry');
      }
    }
    
  15. Agregue el código siguiente para crear una instancia de cliente:

    var client = Client.fromConnectionString(connectionString, Protocol);
    
  16. Agregue el siguiente código para:

    • Abrir la conexión.

    • Configurar un controlador para propiedades deseadas.

    • Enviar propiedades notificadas.

    • Registrar controladores para métodos directos. El ejemplo utiliza un controlador independiente para el método directo de actualización de firmware.

    • Empezar a enviar telemetría.

      client.open(function (err) {
      if (err) {
        printErrorFor('open')(err);
      } else {
        // Create device Twin
        client.getTwin(function (err, twin) {
          if (err) {
            console.error('Could not get device twin');
          } else {
            console.log('Device twin created');
      
            twin.on('properties.desired', function (delta) {
              // Handle desired properties set by solution
              console.log('Received new desired properties:');
              console.log(JSON.stringify(delta));
            });
      
            // Send reported properties
            twin.properties.reported.update(reportedProperties, function (err) {
              if (err) throw err;
              console.log('Twin state reported');
            });
      
            // Register handlers for all the method names we are interested in.
            // Consider separate handlers for each method.
            client.onDeviceMethod('Reboot', onDirectMethod);
            client.onDeviceMethod('FirmwareUpdate', onFirmwareUpdate);
            client.onDeviceMethod('EmergencyValveRelease', onDirectMethod);
            client.onDeviceMethod('IncreasePressure', onDirectMethod);
          }
        });
      
        // Start sending telemetry
        var sendDeviceTelemetry = setInterval(function () {
          temperature += generateRandomIncrement();
          pressure += generateRandomIncrement();
          humidity += generateRandomIncrement();
          var data = {
            'temperature': temperature,
            'temperature_unit': temperatureUnit,
            'humidity': humidity,
            'humidity_unit': humidityUnit,
            'pressure': pressure,
            'pressure_unit': pressureUnit
          };
          sendTelemetry(data, schema)
        }, 5000);
      
        client.on('error', function (err) {
          printErrorFor('client')(err);
          if (sendTemperatureInterval) clearInterval(sendTemperatureInterval);
          if (sendHumidityInterval) clearInterval(sendHumidityInterval);
          if (sendPressureInterval) clearInterval(sendPressureInterval);
          client.close(printErrorFor('client.close'));
        });
      }
      });
      
  17. Guarde los cambios al archivo remote_monitoring.js.

  18. Ejecute el siguiente comando en un símbolo del sistema para iniciar la aplicación de ejemplo:

    node remote_monitoring.js
    

Ver la telemetría de dispositivo

Puede ver la telemetría enviada desde el dispositivo en la página Explorador de dispositivos de la solución.

  1. Seleccione el dispositivo que ha aprovisionado en la lista de dispositivos de la página Explorador de dispositivos. Un panel muestra información sobre el dispositivo incluyendo un trazado de su telemetría:

    Ver detalles del dispositivo

  2. Elija Presión para cambiar la presentación de telemetría:

    Ver la telemetría de presión

  3. Para ver información de diagnóstico sobre el dispositivo, desplácese hacia abajo hasta Diagnósticos:

    Ver el diagnóstico de los dispositivos

Actúe en su dispositivo

Para invocar métodos en los dispositivos, use la página Explorador de dispositivos de la solución de supervisión remota. Por ejemplo, en los dispositivos Chiller de la solución de supervisión remota, implemente un método Reboot.

  1. Elija Dispositivos para ir hasta la página Explorador de dispositivos de la solución.

  2. Seleccione el dispositivo que ha aprovisionado en la lista de dispositivos de la página Explorador de dispositivos:

    Selección del dispositivo real

  3. Para mostrar una lista de los métodos que se pueden llamar en el dispositivo, elija Trabajos y, luego, Métodos. Para programar un trabajo para ejecutarse en varios dispositivos, puede seleccionarlos en la lista. El panel Trabajos muestra los tipos de métodos comunes a todos los dispositivos seleccionados.

  4. Elija Arrancar, establezca el nombre del trabajo en RebootPhysicalChiller y posteriormente elija Aplicar:

    Programación de la actualización de firmware

  5. Aparece una secuencia de mensajes en la consola donde se ejecuta el código del dispositivo cuando el dispositivo controla el método.

Nota

Para realizar el seguimiento del estado del trabajo en la solución, elija Ver estado de trabajo.

Pasos siguientes

En el artículo Personalización de la solución preconfigurada de supervisión remota se describen algunas maneras de personalizar el acelerador de soluciones.