计划和广播作业 (Node)

Azure IoT 中心是一项完全托管的服务,允许后端应用创建和跟踪用于计划和更新数百万台设备的作业。 作业可以用于以下操作:

  • 更新所需属性
  • 更新标记
  • 调用直接方法

从概念上讲,作业包装这些操作之一,并跟踪针对一组设备执行(由设备孪生查询定义)的进度。 例如,后端应用可使用作业重启 10,000 台设备(由设备孪生查询指定并计划在将来执行)。 该应用程序随后可以在其中每个设备接收和执行重新启动方法时跟踪进度。

可在以下文章中了解有关所有这些功能的详细信息:

本教程演示如何:

  • 创建一个具有直接方法的 Node.js 模拟设备应用,启用可由解决方案后端进行调用的 lockDoor。
  • 创建一个 Node.js 控制台应用,该应用使用作业调用模拟设备应用中的 lockDoor 直接方法,并使用设备作业更新所需属性。

在本教程结束时,会创建两个 Node.js 应用:

simDevice.js,它使用设备标识连接到 IoT 中心,并接收 lockDoor 直接方法。

scheduleJobService.js,它调用模拟设备应用中的直接方法,并通过作业更新设备孪生的所需属性。

要完成本教程,需要以下各项:

  • Node.js 版本 4.0.x 或更高版本;
    准备开发环境介绍了如何在 Windows 或 Linux 上安装本教程所用的 Node.js。
  • 有效的 Azure 帐户。 如果没有帐户,可以创建一个试用帐户,只需几分钟即可完成。

创建 IoT 中心

创建模拟设备应用要连接到的 IoT 中心。 以下步骤说明如何使用 Azure 门户来完成此任务。

  1. 登录到 Azure 门户

  2. 选择“新建” > “物联网” > “IoT 中心”。

    Azure 门户跳转栏

  3. 在“IoT 中心”窗格中,输入 IoT 中心的以下信息:

    • 名称:创建 IoT 中心的名称。 如果输入的名称有效,则显示一个绿色复选标记。

    Important

    IoT 中心将公开为 DNS 终结点,因此,命名时请务必避免包含任何敏感信息。

    • 定价和缩放级别:对于本教程,请选择F1 - 免费级别。 有关详细信息,请参阅定价和缩放层

    • 资源组:创建用于托管 IoT 中心的资源组,或使用现有的资源组。 有关详细信息,请参阅使用资源组管理 Azure 资源

    • 位置:选择最近的位置。

    • 固定仪表板:选中此选项可以方便地从仪表板访问 IoT 中心。

      IoT 中心窗口

  4. 单击“创建”。 创建 IoT 中心可能需要数分钟的时间。 可在“通知”窗格中监视进度。

  5. 新的 IoT 中心就绪以后,请在 Azure 门户中单击其磁贴,打开其属性窗口。 创建 IoT 中心以后,即可找到将设备和应用程序连接到 IoT 中心时需要使用的重要信息。 记下“主机名”,并单击“共享访问策略”。

    新建 IoT 中心窗口

  6. 在“共享访问策略”中,单击“iothubowner”策略,然后记下“iothubowner”窗口中的 IoT 中心连接字符串。 有关详细信息,请参阅“IoT 中心开发人员指南”中的访问控制

    共享访问策略

创建设备标识

本部分使用名为 iothub-explorer 的 Node.js 工具为本教程创建设备标识。 设备 ID 区分大小写。

  1. 在命令行环境中运行以下命令:

    npm install -g iothub-explorer@latest

  2. 然后,运行以下命令登录到中心。 将 {iot hub connection string} 替换为前面复制的 IoT 中心连接字符串:

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

  3. 最后,以下使用命令创建名为 myDeviceId 的新设备标识:

    iothub-explorer create myDeviceId --connection-string

    Important

    收集的日志中可能会显示设备 ID 用于客户支持和故障排除,因此,在为日志命名时,请务必避免包含任何敏感信息。

记下结果中的设备连接字符串。 设备应用使用此设备连接字符串以设备身份连接到 IoT 中心。

若要以编程方式创建设备标识,请参阅 IoT 中心入门

创建模拟设备应用程序

本部分将创建一个 Node.js 控制台应用,用于响应通过云调用的方法,这会触发模拟 lockDoor 方法。

  1. 新建名为 simDevice的空文件夹。 在 simDevice 文件夹的命令提示符处,使用以下命令创建 package.json 文件。 接受所有默认值:

    npm init
    
  2. simDevice 文件夹的命令提示符处,运行下述命令以安装 azure-iot-device 设备 SDK 包和 azure-iot-device-mqtt 包:

    npm install azure-iot-device azure-iot-device-mqtt --save
    
  3. simDevice.js 文件夹中,利用文本编辑器创建新的 simDevice 文件。
  4. simDevice.js 文件的开头添加以下“require”语句:

    'use strict';
    
    var Client = require('azure-iot-device').Client;
    var Protocol = require('azure-iot-device-mqtt').Mqtt;
    
  5. 添加 connectionString 变量,并使用它创建一个客户端实例。

    var connectionString = 'HostName={youriothostname};DeviceId={yourdeviceid};SharedAccessKey={yourdevicekey}';
    var client = Client.fromConnectionString(connectionString, Protocol);
    
  6. 添加以下函数以处理 lockDoor 方法。

    var onLockDoor = function(request, response) {
    
        // Respond the cloud app for the direct method
        response.send(200, 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.');
            }
        });
    
        console.log('Locking Door!');
    };
    
  7. 添加以下代码以注册 lockDoor 方法的处理程序。

    client.open(function(err) {
        if (err) {
            console.error('Could not connect to IotHub client.');
        }  else {
            console.log('Client connected to IoT Hub. Register handler for lockDoor direct method.');
            client.onDeviceMethod('lockDoor', onLockDoor);
        }
    });
    
  8. 保存并关闭 simDevice.js 文件。

Note

为简单起见,本教程不实现任何重试策略。 在生产代码中,应该按 MSDN 文章 Transient Fault Handling(暂时性故障处理)中所述实施重试策略(例如指数性的回退)。

安排作业,用于调用直接方法和更新设备孪生的属性

在此部分中,会创建一个 Node.js 控制台应用,它使用直接方法对设备启动远程 lockDoor 并更新设备孪生的属性。

  1. 新建名为 scheduleJobService的空文件夹。 在 scheduleJobService 文件夹的命令提示符处,使用以下命令创建 package.json 文件。 接受所有默认值:

    npm init
    
  2. 在 scheduleJobService 文件夹的命令提示符处,运行以下命令安装 azure-iothub 设备 SDK 包和 azure-iot-device-mqtt 包:

    npm install azure-iothub uuid --save
    
  3. scheduleJobService 文件夹中,利用文本编辑器创建新的 scheduleJobService.js 文件。
  4. dmpatterns_gscheduleJobServiceetstarted_service.js 文件开头添加以下“require”语句:

    'use strict';
    
    var uuid = require('uuid');
    var JobClient = require('azure-iothub').JobClient;
    
  5. 添加以下变量声明并替换占位符值:

    var connectionString = '{iothubconnectionstring}';
    var queryCondition = "deviceId IN ['myDeviceId']";
    var startTime = new Date();
    var maxExecutionTimeInSeconds =  300;
    var jobClient = JobClient.fromConnectionString(connectionString);
    
  6. 添加以下用于监视作业执行的函数:

    function monitorJob (jobId, callback) {
        var jobMonitorInterval = setInterval(function() {
            jobClient.getJob(jobId, function(err, result) {
            if (err) {
                console.error('Could not get job status: ' + err.message);
            } else {
                console.log('Job: ' + jobId + ' - status: ' + result.status);
                if (result.status === 'completed' || result.status === 'failed' || result.status === 'cancelled') {
                clearInterval(jobMonitorInterval);
                callback(null, result);
                }
            }
            });
        }, 5000);
    }
    
  7. 添加以下代码以安排调用设备方法的作业:

    var methodParams = {
        methodName: 'lockDoor',
        payload: null,
        responseTimeoutInSeconds: 15 // Timeout after 15 seconds if device is unable to process method
    };
    
    var methodJobId = uuid.v4();
    console.log('scheduling Device Method job with id: ' + methodJobId);
    jobClient.scheduleDeviceMethod(methodJobId,
                                queryCondition,
                                methodParams,
                                startTime,
                                maxExecutionTimeInSeconds,
                                function(err) {
        if (err) {
            console.error('Could not schedule device method job: ' + err.message);
        } else {
            monitorJob(methodJobId, function(err, result) {
                if (err) {
                    console.error('Could not monitor device method job: ' + err.message);
                } else {
                    console.log(JSON.stringify(result, null, 2));
                }
            });
        }
    });
    
  8. 添加以下代码以安排更新设备孪生的作业:

    var twinPatch = {
       etag: '*', 
       properties: {
           desired: {
               building: '43', 
               floor: 3
           }
       }
    };
    
    var twinJobId = uuid.v4();
    
    console.log('scheduling Twin Update job with id: ' + twinJobId);
    jobClient.scheduleTwinUpdate(twinJobId,
                                queryCondition,
                                twinPatch,
                                startTime,
                                maxExecutionTimeInSeconds,
                                function(err) {
        if (err) {
            console.error('Could not schedule twin update job: ' + err.message);
        } else {
            monitorJob(twinJobId, function(err, result) {
                if (err) {
                    console.error('Could not monitor twin update job: ' + err.message);
                } else {
                    console.log(JSON.stringify(result, null, 2));
                }
            });
        }
    });
    
  9. 保存并关闭 scheduleJobService.js 文件。

运行应用程序

现在,已准备就绪,可以运行应用程序了。

  1. 在 simDevice 文件夹的命令提示符处,运行以下命令以开始侦听重启直接方法。

    node simDevice.js
    
  2. scheduleJobService 文件夹的命令提示符处运行以下命令,以便触发作业进行锁门和孪生项的更新

    node scheduleJobService.js
    
  3. 可以在控制台中看到设备对直接方法的响应。

后续步骤

在本教程中,使用了作业来安排用于设备的直接方法以及设备孪生属性的更新。

若要继续完成 IoT 中心和设备管理模式(如远程无线固件更新)的入门内容,请参阅:

教程:如何进行固件更新

若要继续完成 IoT 中心入门内容,请参阅 Azure IoT Edge 入门