Schedule and broadcast jobs (Node.js)

Azure IoT Hub is a fully managed service that enables a back-end app to create and track jobs that schedule and update millions of devices. Jobs can be used for the following actions:

  • Update desired properties
  • Update tags
  • Invoke direct methods

Conceptually, a job wraps one of these actions and tracks the progress of execution against a set of devices, which is defined by a device twin query. For example, a back-end app can use a job to invoke a reboot method on 10,000 devices, specified by a device twin query and scheduled at a future time. That application can then track progress as each of those devices receive and execute the reboot method.

Learn more about each of these capabilities in these articles:

Note

The features described in this article are available only in the standard tier of IoT Hub. For more information about the basic and standard/free IoT Hub tiers, see Choose the right IoT Hub tier.

This tutorial shows you how to:

  • Create a Node.js simulated device app that has a direct method, which enables lockDoor, which can be called by the solution back end.

  • Create a Node.js console app that calls the lockDoor direct method in the simulated device app using a job and updates the desired properties using a device job.

At the end of this tutorial, you have two Node.js apps:

  • simDevice.js, which connects to your IoT hub with the device identity and receives a lockDoor direct method.

  • scheduleJobService.js, which calls a direct method in the simulated device app and updates the device twin's desired properties using a job.

Prerequisites

  • Node.js version 10.0.x or later. Prepare your development environment describes how to install Node.js for this tutorial on either Windows or Linux.

  • An active Azure account. (If you don't have an account, you can create a free account in just a couple of minutes.)

  • Make sure that port 8883 is open in your firewall. The device sample in this article uses MQTT protocol, which communicates over port 8883. This port may be blocked in some corporate and educational network environments. For more information and ways to work around this issue, see Connecting to IoT Hub (MQTT).

Create an IoT hub

This section describes how to create an IoT hub using the Azure portal.

  1. Sign in to the Azure portal.

  2. On the Azure homepage, select the + Create a resource button.

  3. From the Categories menu, select Internet of Things then IoT Hub.

  4. On the Basics tab, complete the fields as follows:

    • Subscription: Select the subscription to use for your hub.

    • Resource group: Select a resource group or create a new one. To create a new one, select Create new and fill in the name you want to use. To use an existing resource group, select that resource group. For more information, see Manage Azure Resource Manager resource groups.

    • Region: Select the region in which you want your hub to be located. Select the location closest to you. Some features, such as IoT Hub device streams, are only available in specific regions. For these limited features, you must select one of the supported regions.

    • IoT hub name: Enter a name for your hub. This name must be globally unique, with a length between 3 and 50 alphanumeric characters. The name can also include the dash ('-') character.

    Important

    Because the IoT hub will be publicly discoverable as a DNS endpoint, be sure to avoid entering any sensitive or personally identifiable information when you name it.

    Create a hub in the Azure portal.

  5. Select Next: Networking to continue creating your hub.

    Choose the endpoints that devices can use to connect to your IoT hub. You can select the default setting, Public access, or choose Private access. Accept the default setting for this example.

    Choose the endpoints that can connect.

  6. Select Next: Management to continue creating your hub.

    Set the size and scale for a new hub using the Azure portal.

    You can accept the default settings here. If desired, you can modify any of the following fields:

    • Pricing and scale tier: Your selected tier. You can choose from several tiers, depending on how many features you want and how many messages you send through your solution per day. The free tier is intended for testing and evaluation. It allows 500 devices to be connected to the hub and up to 8,000 messages per day. Each Azure subscription can create one IoT hub in the free tier.

      If you are working through a quickstart, select the free tier.

    • IoT Hub units: The number of messages allowed per unit per day depends on your hub's pricing tier. For example, if you want the hub to support ingress of 700,000 messages, you choose two S1 tier units. For details about the other tier options, see Choosing the right IoT Hub tier.

    • Microsoft Defender for IoT: Turn this on to add an extra layer of threat protection to IoT and your devices. This option is not available for hubs in the free tier. Learn more about security recommendations for IoT Hub in Defender for IoT.

    • Role-based access control: Choose how access to the IoT hub is managed, whether shared access policies are allowed or only role-based access control is supported. For more information, see Control access to IoT Hub by using Azure Active Directory.

    • Device-to-cloud partitions: This property relates the device-to-cloud messages to the number of simultaneous readers of the messages. Most hubs need only four partitions.

  7. Select Next: Tags to continue to the next screen.

    Tags are name/value pairs. You can assign the same tag to multiple resources and resource groups to categorize resources and consolidate billing. In this document, you won't be adding any tags. For more information, see Use tags to organize your Azure resources.

    Assign tags for the hub using the Azure portal.

  8. Select Next: Review + create to review your choices. You see something similar to this screen, but with the values you selected when creating the hub.

    Review information for creating the new hub.

  9. Select Create to start the deployment of your new hub. Your deployment will be in progress a few minutes while the hub is being created. Once the deployment is complete, select Go to resource to open the new hub.

Register a new device in the IoT hub

In this section, you use the Azure CLI to create a device identity for this article. Device IDs are case sensitive.

  1. Open Azure Cloud Shell.

  2. In Azure Cloud Shell, run the following command to install the Microsoft Azure IoT Extension for Azure CLI:

    az extension add --name azure-iot
    
  3. Create a new device identity called myDeviceId and retrieve the device connection string with these commands:

    az iot hub device-identity create --device-id myDeviceId --hub-name {Your IoT Hub name}
    az iot hub device-identity connection-string show --device-id myDeviceId --hub-name {Your IoT Hub name} -o table
    

    Important

    The device ID may be visible in the logs collected for customer support and troubleshooting, so make sure to avoid any sensitive information while naming it.

Make a note of the device connection string from the result. This device connection string is used by the device app to connect to your IoT Hub as a device.

Create a simulated device app

In this section, you create a Node.js console app that responds to a direct method called by the cloud, which triggers a simulated lockDoor method.

  1. Create a new empty folder called simDevice. In the simDevice folder, create a package.json file using the following command at your command prompt. Accept all the defaults:

    npm init
    
  2. At your command prompt in the simDevice folder, run the following command to install the azure-iot-device Device SDK package and azure-iot-device-mqtt package:

    npm install azure-iot-device azure-iot-device-mqtt --save
    
  3. Using a text editor, create a new simDevice.js file in the simDevice folder.

  4. Add the following 'require' statements at the start of the simDevice.js file:

    'use strict';
    
    var Client = require('azure-iot-device').Client;
    var Protocol = require('azure-iot-device-mqtt').Mqtt;
    
  5. Add a connectionString variable and use it to create a Client instance. Replace the {yourDeviceConnectionString} placeholder value with the device connection string you copied previously.

    var connectionString = '{yourDeviceConnectionString}';
    var client = Client.fromConnectionString(connectionString, Protocol);
    
  6. Add the following function to handle the lockDoor method.

    var onLockDoor = function(request, response) {
    
        // Respond the cloud app for the direct method
        response.send(200, function(err) {
            if (err) {
                console.error('An error occurred when sending a method response:\n' + err.toString());
            } else {
                console.log('Response to method \'' + request.methodName + '\' sent successfully.');
            }
        });
    
        console.log('Locking Door!');
    };
    
  7. Add the following code to register the handler for the lockDoor method.

    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. Save and close the simDevice.js file.

Note

To keep things simple, this tutorial does not implement any retry policy. In production code, you should implement retry policies (such as an exponential backoff), as suggested in the article, Transient Fault Handling.

Get the IoT hub connection string

In this article, you create a back-end service that schedules a job to invoke a direct method on a device, schedules a job to update the device twin, and monitors the progress of each job. To perform these operations, your service needs the registry read and registry write permissions. By default, every IoT hub is created with a shared access policy named registryReadWrite that grants these permissions.

To get the IoT Hub connection string for the registryReadWrite policy, follow these steps:

  1. In the Azure portal, select Resource groups. Select the resource group where your hub is located, and then select your hub from the list of resources.

  2. On the left-side pane of your hub, select Shared access policies.

  3. From the list of policies, select the registryReadWrite policy.

  4. Under Shared access keys, select the copy icon for the Primary connection string and save the value.

    Screen capture that shows how to retrieve the connection string

For more information about IoT Hub shared access policies and permissions, see Access control and permissions.

Schedule jobs for calling a direct method and updating a device twin's properties

In this section, you create a Node.js console app that initiates a remote lockDoor on a device using a direct method and update the device twin's properties.

  1. Create a new empty folder called scheduleJobService. In the scheduleJobService folder, create a package.json file using the following command at your command prompt. Accept all the defaults:

    npm init
    
  2. At your command prompt in the scheduleJobService folder, run the following command to install the azure-iothub Device SDK package and azure-iot-device-mqtt package:

    npm install azure-iothub uuid --save
    
  3. Using a text editor, create a new scheduleJobService.js file in the scheduleJobService folder.

  4. Add the following 'require' statements at the start of the scheduleJobService.js file:

    'use strict';
    
    var uuid = require('uuid');
    var JobClient = require('azure-iothub').JobClient;
    
  5. Add the following variable declarations. Replace the {iothubconnectionstring} placeholder value with the value you copied in Get the IoT hub connection string. If you registered a device different than myDeviceId, be sure to change it in the query condition.

    var connectionString = '{iothubconnectionstring}';
    var queryCondition = "deviceId IN ['myDeviceId']";
    var startTime = new Date();
    var maxExecutionTimeInSeconds =  300;
    var jobClient = JobClient.fromConnectionString(connectionString);
    
  6. Add the following function that is used to monitor the execution of the job:

    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. Add the following code to schedule the job that calls the device method:

    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. Add the following code to schedule the job to update the device twin:

    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. Save and close the scheduleJobService.js file.

Run the applications

You are now ready to run the applications.

  1. At the command prompt in the simDevice folder, run the following command to begin listening for the reboot direct method.

    node simDevice.js
    
  2. At the command prompt in the scheduleJobService folder, run the following command to trigger the jobs to lock the door and update the twin

    node scheduleJobService.js
    
  3. You see the device response to the direct method and the job status in the console.

    The following shows the device response to the direct method:

    Simulated device app output

    The following shows the service scheduling jobs for the direct method and device twin update, and the jobs running to completion:

    Run the simulated device app

Next steps

In this tutorial, you used a job to schedule a direct method to a device and the update of the device twin's properties.

To continue getting started with IoT Hub and device management patterns such as end-to-end image-based update in Device Update for Azure IoT Hub tutorial using the Raspberry Pi 3 B+ Reference Image.

To continue getting started with IoT Hub, see Getting started with Azure IoT Edge.