Use Azure IoT Edge to send device-to-cloud messages with a simulated device (Linux)

This walkthrough of the Simulated Device Cloud Upload sample shows you how to use Azure IoT Edge to send device-to-cloud telemetry to IoT Hub from simulated devices.

This walkthrough covers:

Architecture

The Simulated Device Cloud Upload sample shows how to create a gateway that sends telemetry from simulated devices to an IoT hub. A device may not be able to connect directly to IoT Hub because the device:

  • Does not use a communications protocol understood by IoT Hub.
  • Is not smart enough to remember the identity assigned to it by IoT Hub.

An IoT Edge gateway can solve these problems in the following ways:

  • The gateway understands the protocol used by the device, receives device-to-cloud telemetry from the device, and forwards those messages to IoT Hub using a protocol understood by the IoT hub.

  • The gateway maps IoT Hub identities to devices and acts as a proxy when a device sends messages to IoT Hub.

The following diagram shows the main components of the sample, including the IoT Edge modules:

The modules do not pass messages directly to each other. The modules publish messages to an internal broker that delivers the messages to the other modules using a subscription mechanism. For more information, see Get started with Azure IoT Edge.

Protocol ingestion module

This module is the starting point for receiving data from devices, through the gateway, and into the cloud. In the sample, the module:

  1. Creates simulated temperature data. If you use physical devices, the module reads data from those physical devices.
  2. Creates a message.
  3. Places the simulated temperature data into the message content.
  4. Adds a property with a fake MAC address to the message.
  5. Makes the message available to the next module in the chain.

The module called Protocol X ingestion in the previous diagram is called Simulated device in the source code.

MAC <-> IoT Hub ID module

This module scans for messages that have a Mac address property. In the sample, the protocol ingestion module adds the MAC address property. If the module finds such a property, it adds another property with an IoT Hub device key to the message. The module then makes the message available to the next module in the chain.

The developer sets up a mapping between MAC addresses and IoT Hub identities to associate the simulated devices with IoT Hub device identities. The developer adds the mapping manually as part of the module configuration.

Note

This sample uses a MAC address as a unique device identifier and correlates it with an IoT Hub device identity. However, you can write your own module that uses a different unique identifier. For example, your devices may have unique serial numbers or the telemetry data may include a unique embedded device name.

IoT Hub communication module

This module takes messages with an IoT Hub device key property that was assigned by the previous module. The module sends the message content to IoT Hub using the HTTP protocol. HTTP is one of the three protocols understood by IoT Hub.

Instead of opening a connection for each simulated device, this module opens a single HTTP connection from the gateway to the IoT hub. The module then multiplexes connections from all the simulated devices over that connection. This approach enables a single gateway to connect many more devices.

Before you get started

Before you get started, you must:

  • Create an IoT hub in your Azure subscription, you need the name of your hub to complete this walkthrough. If you don't have an account, you can create a free account in just a couple of minutes.
  • Add two devices to your IoT hub and make a note of their ids and device keys. You can use the device explorer or iothub-explorer tool to add your devices to the IoT hub you created in the previous step and retrieve their keys.

Install the prerequisites

The steps in this tutorial assume you are running Ubuntu Linux.

Open a shell and run the following commands to install the prerequisite packages:

sudo apt-get update
sudo apt-get install curl build-essential libcurl4-openssl-dev git cmake libssl-dev uuid-dev valgrind libglib2.0-dev libtool autoconf

In the shell, run the following command to clone the Azure IoT Edge GitHub repository to your local machine:

git clone https://github.com/Azure/iot-edge.git

How to build the sample

You can now build the IoT Edge runtime and samples on your local machine:

  1. Open a shell.

  2. Navigate to the root folder in your local copy of the iot-edge repository.

  3. Run the build script as follows:

    tools/build.sh --disable-native-remote-modules
    

This script uses the cmake utility to create a folder called build in the root folder of your local copy of the iot-edge repository and generate a makefile. The script then builds the solution, skipping unit tests and end to end tests. If you want to build and run the unit tests, add the --run-unittests parameter. If you want to build and run the end to end tests, add the --run-e2e-tests.

Note

Every time you run the build.sh script, it deletes and then recreates the build folder in the root folder of your local copy of the iot-edge repository.

How to run the sample

The build.sh script generates its output in the build folder in your local copy of the iot-edge repository. This output includes the four IoT Edge modules used in this sample.

The build script places the:

  • liblogger.so in the build/modules/logger folder.
  • libiothub.so in the build/modules/iothub folder.
  • lib_identity_map.so in the build/modules/identitymap folder.
  • libsimulated_device.so in the build/modules/simulated_device folder.

Use these paths for the module path values as shown in the following JSON settings file:

The simulated_device_cloud_upload_sample process takes the path to a JSON configuration file as a command-line argument. The following example JSON file is provided in the SDK repository at samples\simulated_device_cloud_upload_sample\src\simulated_device_cloud_upload_sample_lin.json. This configuration file works as is unless you modify the build script to place the IoT Edge modules or sample executables in non-default locations.

Note

The module paths are relative to the directory from where you run the simulated_device_cloud_upload_sample executable, not the directory where the executable is located. The sample JSON configuration file defaults to writing to 'deviceCloudUploadGatewaylog.log' in your current working directory.

In a text editor, open the file samples/simulated_device_cloud_upload_sample/src/simulated_device_cloud_upload_lin.json in your local copy of the iot-edge repository. This file configures the IoT Edge modules in the sample gateway:

  • The IoTHub module connects to your IoT hub. You configure it to send data to your IoT hub. Specifically, set the IoTHubName value to the name of your IoT hub and set the IoTHubSuffix value to azure-devices.net. Set the Transport value to one of: HTTP, AMQP, or MQTT. Currently, only HTTP shares one TCP connection for all device messages. If you set the value to AMQP, or MQTT, the gateway maintains a separate TCP connection to IoT Hub for each device.
  • The mapping module maps the MAC addresses of your simulated devices to your IoT Hub device ids. Make sure that deviceId values match the ids of the two devices you added to your IoT hub, and that the deviceKey values contain the keys of your two devices.
  • The BLE1 and BLE2 modules are the simulated devices. Note how their MAC addresses match the addresses in the mapping module.
  • The Logger module logs your gateway activity to a file.
  • The module path values shown in the example assume that you run the sample from the build folder in your local copy of the iot-edge repository.
  • The links array at the bottom of the JSON file connects the BLE1 and BLE2 modules to the mapping module, and the mapping module to the IoTHub module. It also ensures that all messages are logged by the Logger module.
{
    "modules": [
        {
            "name": "IotHub",
          "loader": {
            "name": "native",
            "entrypoint": {
              "module.path": "./modules/iothub/libiothub.so"
            }
            },
            "args": {
              "IoTHubName": "<<insert here IoTHubName>>",
              "IoTHubSuffix": "<<insert here IoTHubSuffix>>",
              "Transport": "HTTP"
            }
          },
        {
            "name": "mapping",
          "loader": {
            "name": "native",
            "entrypoint": {
              "module.path": "./modules/identitymap/libidentity_map.so"
            }
            },
            "args": [
              {
                "macAddress": "01:01:01:01:01:01",
                "deviceId": "<<insert here deviceId>>",
                "deviceKey": "<<insert here deviceKey>>"
              },
              {
                "macAddress": "02:02:02:02:02:02",
                "deviceId": "<<insert here deviceId>>",
                "deviceKey": "<<insert here deviceKey>>"
              }
            ]
          },
        {
            "name": "BLE1",
          "loader": {
            "name": "native",
            "entrypoint": {
              "module.path": "./modules/simulated_device/libsimulated_device.so"
            }
            },
            "args": {
              "macAddress": "01:01:01:01:01:01"
            }
          },
        {
            "name": "BLE2",
          "loader": {
            "name": "native",
            "entrypoint": {
              "module.path": "./modules/simulated_device/libsimulated_device.so"
            }
            },
            "args": {
              "macAddress": "02:02:02:02:02:02"
            }
          },
        {
            "name": "Logger",
          "loader": {
            "name": "native",
            "entrypoint": {
              "module.path": "./modules/logger/liblogger.so"
            }
            },
            "args": {
              "filename": "deviceCloudUploadGatewaylog.log"
            }
          }
    ],
    "links": [
        {
            "source": "*",
            "sink": "Logger"
        },
        {
            "source": "BLE1",
            "sink": "mapping"
        },
        {
            "source": "BLE2",
            "sink": "mapping"
        },
        {
            "source": "mapping",
            "sink": "IotHub"
        }
    ]
}

Save the changes you made to the configuration file.

To run the sample:

  1. In your shell, navigate to the iot-edge/build folder.
  2. Run the following command:

    ./samples/simulated_device_cloud_upload/simulated_device_cloud_upload_sample ../samples/simulated_device_cloud_upload/src/simulated_device_cloud_upload_lin.json
    
  3. You can use the device explorer or iothub-explorer tool to monitor the messages that IoT hub receives from the gateway. For example, using iothub-explorer you can monitor device-to-cloud messages using the following command:

    iothub-explorer monitor-events --login "HostName={Your iot hub name}.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey={Your IoT Hub key}"
    

Next steps

To gain a more advanced understanding of Azure IoT Edge and experiment with some code examples, visit the following developer tutorials and resources:

To further explore the capabilities of IoT Hub, see: