Lab: Building a device for IoT plug and play
Prerequisites
This lab requires an active Microsoft Azure Subscription and a Work (AAD) account.
On Lab PC:
- Visual Studio Code with Azure IoT Device Workbench extension Link to be Updated and Remote Development
- Azure IoT Device Explorer
On HummingBoard:
- Target OS: Debian (Download and Installation instruction)
- Install Git and CMake
Lab Objective
Participants will learn about how to build an Linux-based IoT Plug and Play device from scratch with Azure IoT Device SDK using Microsoft tools like VS Code and IoT Workbench Extension on NXP i.MX6 based HummingBoard, and to connect the device to Azure services like IoT Central via device provisioning, and to get a device certify for Azure IoT Device Catalogue.
Exercise 1: Create a device model
The core of IoT Plug and Play is a device capability model schema that describes device capabilities. This schema is a JSON document that’s structured as a set of interfaces that include definitions of:
- Properties: The read-only and read/write state of a device or other entity. Ex: a device serial number may be a read-only property and a target temperature on a thermostat may be a read/write property.
- Telemetry: The data emitted by a device, whether the data is a regular stream of sensor readings, an occasional error, or information message.
- Commands: A function or operation that can be done on a device. For example, a command could reboot a gateway or take a picture using a remote camera.
You can reuse interfaces across device capability models to make collaboration easier and to speed up development.
In this exercise we will create a device model for a simulated device to run on the Hummingboard.
Task 1: Create an Interface
- Launch VS Code and open the command palette in VS Code using the shortcut Ctrl+Shift+P.
- In the command palette, enter Plug and Play , then select the IoT Plug & Play: Create Interface command. 3. 3.Browse to and select the # [ANNOTATION:
BY 'Archie Tsai (ManPower)' ON '2019-08-19T17:02:00'AT NOTE: 'After we unzip pnp_lab.zip, the folder tree is \Desktop\pnp_lab\pnp_lab\azure-iot-sdk-c...' NOTE: 'We should fix this problem.'] pnp_lab folder on the Desktop.
- Enter EnvironmentalSensor as the name of the interface and press Enter. VS Code creates a sample interface file called interface.json. 5. 5.Replace the contents of this file with the following JSON and replace {your name} in the @id field with a unique value. Use only the characters a-z, A-Z, 0-9, and underscore. For # [ANNOTATION:
BY 'Archie Tsai (ManPower)' ON '2019-08-19T16:42:00'AT NOTE: 'Double 'more''] more more information, see Digital Twin identifier format. The interface ID must be unique to save the interface in the repository:
{
"@id": "urn: {your name} :EnvironmentalSensor:1",
"@type": "Interface",
"displayName": "Environmental Sensor",
"description": "Provides functionality to report temperature, humidity. Provides telemetry, commands and read-write properties",
"comment": "Requires temperature and humidity sensors.",
"contents": [
{
"@type": "Property",
"displayName": "Customer Name",
"description": "The name of the customer currently operating the device.",
"name": "name",
"schema": "string",
"writable": true
},
{
"@type": "Property",
"displayName": "Brightness Level",
"description": "The brightness level for the light on the device. Can be specified as 1 (high), 2 (medium), 3 (low)",
"name": "brightness",
"writable": true,
"schema": "long"
},
{
"@type": [
"Telemetry",
"SemanticType/Temperature"
],
"description": "Current temperature on the device",
"displayName": "Temperature",
"name": "temp",
"schema": "double",
"unit": "Units/Temperature/fahrenheit"
},
{
"@type": [
"Telemetry",
"SemanticType/Humidity"
],
"description": "Current humidity on the device",
"displayName": "Humidity",
"name": "humid",
"schema": "double",
"unit": "Units/Humidity/percent"
}
],
"@context": "http://azureiot.com/v1/contexts/IoTModel.json"
}
This interface defines device properties such as Customer Name telemetry types such as Temperature.
1. 6.Add a command capability called blink # [ANNOTATION:
BY 'Archie Tsai (ManPower)' ON '2019-08-19T17:16:00'AT NOTE: 'I think we should describe it like "after Humidity telemetry" or something more specific.'] at the end of this interface file. Be sure to add a comma before you add the command. Try typing the definition to see how intellisense, autocomplete, and validation can help you edit an interface definition:
{
"@type": "Command",
"description": "This command will begin blinking the LED for given time interval.",
"name": "blink",
"request": {
"name": "blinkRequest",
"schema": {
"@type": "Object",
"fields": [
{
"name": "interval",
"schema": "long"
}
]
}
},
"response": {
"name": "blinkResponse",
"schema": "string"
},
"commandType": "synchronous"
}
- Save the file.
Task 2: Create a Device Model
The model file specifies the interfaces that your Plug and Play device implements. There are typically at least two interfaces in a model - one or more that define the specific capabilities of your device, and a standard interface that all Plug and Play devices must implement.
- Use Ctrl+Shift+P to open the command palette in VS Code
- Enter Plug and Play and then select the IoT Plug & Play: Create Capability Model command. Then enter HummingBoard as the name of the model. VS Code creates a sample interface file called HummingBoard.capabilitymodel.json.
- Replace the contents of this file with the following JSON and replace {your name} in the @id field and in the EnvironmentalSensor interface with the same value you used in the EnvironmentalSensor.interface.json file. The interface ID must be unique to save the interface in the repository:
{
"@id": "urn: {your name} :HummingBoard:1",
"@type": "CapabilityModel",
"displayName": "HummingBoard Model",
"implements": [
{
"schema": "urn: **{your name}** :EnvironmentalSensor:1",
"name": "environmentalSensor"
},
{
"schema": "urn:azureiot:DeviceManagement:DeviceInformation:1",
"name": "deviceinfo"
}
],
"@context": "http://azureiot.com/v1/contexts/IoTModel.json"
}
The model defines a device that implements your EnvironmentalSensor interface and the standard DeviceInformation interface.
- Save the file.
Task 3: Download DeviceInformation interface
Before you can generate code from the model, you must create a local copy of the DeviceInformation from the public model repository. The public model repository already contains the DeviceInformation interface as a standard interface for everyone to use.
To download the DeviceInformation interface from the public model repository using VS Code:
- Use Ctrl+Shift+P to open the command palette.
- Enter Plug and Play , select the Open Model Repository command, and then select Open Public Model Repository.
- Select Interfaces , then select the device information interface with ID urn:azureiot:DeviceManagement:DeviceInformation:1, and then select Download.
You now have the three files that make up your device capability model:
- urn_azureiot_DeviceManagement_DeviceInformation_1.interface.json
- EnvironmentalSensor.interface.json
- HummingBoard.capabilitymodel.json
Task 4: Publish the Model
For the Azure IoT explorer tool to read your device capability model, you need to publish it in your company repository. We will publish the model we just created into your company repository via VS Code.
- Navigate to the Azure Certified for IoT portal.
- Use your Microsoft work account to sign into the portal.
- Select Company repository and then Connection strings.
- Copy the connection string. We need this connection string to open the company repository in VS Code.
- In VS Code, use Ctrl+Shift+P to open the command palette.
- Enter Plug and Play and then select the IoT Plug & Play: Open Model Repository command.
- Select Company Repository and paste your connection string.
- Press Enter to open your company repository.
- Use Ctrl+Shift+P to open the command palette. Enter Plug and Play and then select the IoT Plug & Play: Submit files to Model Repository command.
- Select HummingBoard.capabilitymodel.json, urn_azureiot_DeviceManagement_DeviceInformation_1.interface.json **, and EnvironmentalSensor.interface.json files and select OK**.
Your files are now stored in your company repository.
Screenshot Needed
Exercise 2: Create the Device Agent for IoT Play and Play
Task 1: Generate Stub Code
You can use the Azure IoT Device Workbench extension for VS Code to generate skeleton C code from your model. To generate the stub code in VS Code:
- Use Ctrl+Shift+P to open the command palette.
- Enter Plug and Play and then select the IoT Plug & Play: Generate Device Code Stub command.
Note
The first time you use the IoT Plug and Play Code Generator utility, it takes a few seconds to download.
- Select your HummingBoard.capabilitymodel.json capability model file.
- Enter hummingboard_hub as the project name.
- Choose ANSI C as the language.
- Choose CMake Project as the target.
- Choose Via IoT Hub device connection string as the way to connect.
VS Code generates the skeleton C code and saves the files in the hummingboard_hub folder in the nxp_pnp folder. VS Code opens a new window that contains the generated code files.
Task 2: Update Generated Code
Before you can build and run the code, you need to implement the stubbed properties, telemetry, and commands.
To provide implementations for the stubbed code in VS Code:
- Open the hummingboard_impl.c file with VS Code. We will implement the stubbed functions.
- Include following libraries at the top to get system information.
#include \<sys/utsname.h\>
#include \<sys/sysinfo.h\>
- Implement the read telemetry function for the Environmental Sensor interface though some simulation:
double EnvironmentalSensor_Telemetry_ReadTemp()
{
float currentTemperature = 20.0f+ ((float)rand() / RAND\_MAX) \* 15.0f;
return currentTemperature;
}
double EnvironmentalSensor_Telemetry_ReadHumid()
{
float currentHumidity = 60.0f+ ((float)rand() / RAND\_MAX) \* 20.0f;
return currentHumidity;
}
- Implement the get property function for the Device Information interface:
char* DeviceInfo_Property_GetManufacturer()
{
// Company name of the device manufacturer.
return"{your company name. ex: contoso}";
}
char* DeviceInfo_Property_GetModel()
{
// Device model name or ID
return"{ your device model name. ex: HummingBoard Edge}";
}
char* DeviceInfo_Property_GetSwVersion()
{
// Version of the software on your device.
// This could be the version of your firmware. Ex. 1.3.45
return"1.0.0";
}
char* DeviceInfo_Property_GetOsName()
{
// Name of the operating system on the device
struct utsname details;
int ret = uname(&details);
if(ret == 0)
{
return details.sysname;
}
return"unknown";
}
char* DeviceInfo_Property_GetProcessorArchitecture()
{
// Architecture of the processor on the device
struct utsname details;
int ret = uname(&details);
if(ret == 0)
{
return details.machine;
}
return"unknown";
}
char* DeviceInfo_Property_GetProcessorManufacturer()
{
// Name of the manufacturer of the processor on the device
return"NXP";
}
long DeviceInfo_Property_GetTotalStorage()
{
// Total available storage on the device in kilobytes
return0L;
}
long DeviceInfo_Property_GetTotalMemory()
{
// Total available memory on the device in kilobytes
struct sysinfo sysInfo;
int ret = sysinfo(&sysInfo);
if(ret == 0)
{
return sysInfo.totalram;
}
return0L;
}
- Save your changes.
Task 3: Build the Device Agent in Cross-Compiler Container
Since the HummingBoard has a different architecture than our lab PC, we have setup a Docker container for cross compiling.
- Open Command Prompt and start the container.
\> docker run -d –mount type=bind,source=C:\Users\Day2\Desktop\pnp_lab,target=/workspaces –name azureiotdev azureiot_armv7hf_dev /bin/sh -c "echo Container started ; while sleep 1; do :; done"
- Open the console from running container:
\> docker exec -it azureiotdev bash
- Use the build_pnp.sh to build code in the container console:
cd /workspaces
./build_pnp.sh ./hummingboard_hub hummingboard_hub
- Copy your hummingboard_hub binary from the container to HummingBoard:
scp /work/iotsdk/cmake/app/hummingboard_hub/hummingboard_hub debian@192.168.200.200:app/hummingboard_hub
HummingBoard's login account username/password is debian / debian.
Restarting Container Instance
If at any point you need to restart your container instance, follow these steps.
- Exit your container console session.
exit
- Stop your container.
\> docker stop azureiotdev
- Remove your container instance.
\> docker rm azureiotdev
Task 4: Create a Device on IoT Hub
When we run the device agent, it connects to the IoT Hub, starts sending sample telemetry and property values, and responds to commands from IoT Hub. Before we can verify this behavior, we need to create a device identity for the device agent.
- Open Azure IoT Device Explorer.
- Enter the IoT Hub connection string: Update IoT Hub Connection String
HostName=mcIoTPnP.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=fax/ggmbCMV0LEjr2PZ7v3J3Y7TPlh1YV2hP39becHs=
- Click on the + New button to create a new device on the IoT Hub.
- Use a unique device ID for your device.
- Keep authentication type as Symmetric key and auto-generate keys as checked.
- Set "Connect this device to IoT Hub" as Enable.
Click on the Create button.
- Search for and click on your device by the device ID in the device list.
- Under the Device Identity section, copy the primary connection string using the button. We will need it for the next Task.
Task 5: Run Device Agent
In this Task we will run the IoT Plug and Play device agent on HummingBoard Edgeby assign it the IoT device identity we just created.
- Open an SSH session to HummingBoard Edge using tools like Putty. The default IP of the Hummingboard is set to 129.168.200.200.
- Run the device agent with the IoT Hub device connection string as its parameter. Don't forget to put the double quote around the connection string!
~/app/hummingboard_hub " [IoTHub device connection string] "
- Verify that the device agent is successfully connected to the IoT Hub as device starts sending telemetry to the hub.
Info: Send telemetry data to IoT Hub
Task 6: Interacting with IoT PnP Device
Now the IoT PnP device agent running on your HummingBoard, we can use Azure services application like Azure IoT Device Explorer to interact with the device.
- In Azure IoT Device Explorer , go to your device details page. Under Digital Twin section, select Properties (non-writable) under the urn:azureiot:DeviceManagement:DeviceInformation:1 interface to view the device information we reported.
- Select Telemetry under the EnvironmentalSensor interface. Select the ** Start** button on the top of the page. The telemetry we sent would show up.
- Select Property (writable) under the EnvironmentalSensor interface. Provide input for each writable property and select Update writable property. A success dialogue should pop up on the top right.
On the device log, you should see logs like below:
Info: DigitalTwin Client Core: Device Twin callback called. updateState=DEVICE_TWIN_UPDATE_PARTIAL, payload=0x1536663, size=114, userContextCallback=0x1524ab0
Info: DigitalTwin Interface : Invoking property callback for interface environmentalSensor, propertyName=name, userInterfaceContext=0x9d474
Info: ENVIRONMENTALSENSOR_INTERFACE: name property invoked…
Info: ENVIRONMENTALSENSOR_INTERFACE: name data=\<"MyPnPDevice"\>
Info: ENVIRONMENTALSENSOR_INTERFACE: Updating name property with new desired value \<"MyPnPDevice"\> …
Info: Name property new value: "MyPnPDevice"
Info: ENVIRONMENTALSENSOR_INTERFACE: Successfully queued property update for name
- Select Commands under the EnvironmentalSensor interface. Provide input for command request and select Send command A success dialogue should pop up on the top right.
On the device log, you should see logs like below:
Info: DigitalTwin Client Core: Processing method callback for method $iotin:environmentalSensor*blink, payload=0x16e766f, size=96
Info: DigitalTwin Interface : Invoking callback to process command blink on interface name environmentalSensor
Info: ENVIRONMENTALSENSOR_INTERFACE: blink command invoked.
Info: ENVIRONMENTALSENSOR_INTERFACE: blink request payload=\<{"interval":100}\>, context=\<0x9d474\>
Info: Parameter: blinkRequest-\>interval = 100
Info: Device executed 'blink' command successfully
Info: DigitalTwin Interface: Callback to process command returned. responseData=0x16ed828, responseLen=28, responseStatus=200sdfa
In addition to the GUI-based tool, we also provide Azure IoT extension to our Azure CLI, an open-source cross platform command line tool to manage Azure resources. The extension enables users to interact and test IoT Play and Play devices. For more information on the extension and its usage tutorial, please visit Link TBD.
Exercise 3: Connect IoT Plug and Play Device to Azure IoT Central
Briefly explain iot central.
Task 1: Setup an Azure IoT Central Application
In this task, we will setup an Azure IoT Central application and import our previously defined device model for the IoT Central application to create respective UI controls and even create a stimulated IoT Plug and Play device.
Create an Azure IoT Central Application
- Open LINK TBD aka.ms/bigmac to create an Azure IoT Central.
- Choose a friendly application name, such as {you name} IoT. Azure IoT Central generates a unique URL prefix for you. You can change this URL prefix to something more memorable.
- Choose the Preview application template. An application template can contain predefined items such as device templates and dashboards to help you get started.
- Select Create at the bottom of the page.
Import Device Template to IoT Central
- 1. Select the Device Templates tab on the left navigation menu. select + New on the Device Templates page to add a new device template.
Select Custom.
- 2. Enter a friendly name for your device template, ex: Contoso Sensor HE100.
- 3. Since IoT Central only support importing device model with inline interface definition. We will create an empty device model, then import each interface one by one. Choose Custom to create a new device capability model.
- 4. Select Edit identity to update the field to match of the device model you defined in Exercise 1. Save the changes.
- 5. Select ** Add Interface , then Import Interface to import EnvironmentalSensor.interface.json** file.
- 6. Select ** Add Interface , then Device Information to import the stanrdard DeviceInformation** interface.
The resulting device capability model should end up like below in IoT Central:

Create Views for Your Device Template
You can customize the application to display relevant information about the environmental sensor device to an operator. Your customizations enable the operator to manage the environmental sensor devices connected to the application. You can create two types of views for an operator to use to interact with devices:
- Forms to view and edit device and cloud properties.
- Dashboards to visualize devices.
The save time, we will generate default views in this task.
- Select Views then select Generate Default Views.
- Leave the default setting and select Generate Default Dashboard Views.
Publish Device Template
Before you can create a simulated environmental sensor, or connect a real environmental sensor, you need to publish your device template.
- Go to your device template from the Device Templates page and select Publish.
- On the Publish a Device Template dialog, choose Publish.
After a device template is published, it's visible on the Devices page. In a published device template, you can't edit a device capability model without creating a new version. However, you can make updates to cloud properties, customizations, and views, in a published device template without versioning. After making any changes, select Publish to push those changes out.
Task 2: Generate Stub Code for Device Provisioning Serivce
In this task we will generate skeleton C code from the model with Device Provisioning Service (DPS) enabled. This allows the device agent to connect to the IoT Central application with DPS, a helper service that enables zero-touch, just-in-time provisioning to the right IoT hub without requiring human intervention, allowing customers to provision millions of devices in a secure and scalable manner.
- Use Ctrl+Shift+P to open the command palette.
- Enter Plug and Play and then select the IoT Plug & Play: Generate Device Code Stub command.
- Select your HummingBoard.capabilitymodel.json capability model file.
- Enter hummingboard_dps as the project name.
- Choose ANSI C as the language.
- Choose CMake Project as the target.
- Choose Via Device Provisioning Service as the way to connect.
VS Code generates the skeleton C code and saves the files in the hummingboard_dps folder in the nxp_pnp folder. VS Code opens a new window that contains the generated code files.
Task 3: Setup Device Provisioning Service in Device Agent
Retrieve DPS information from IoT Central. Our DPS client will supply these information to our DPS service to get assigned to the correct IoT Central application.
- In your IoT Central application, go to the Administration page and select Device Connection.
- Make a note of the Scope ID and Primary Key.
- Open command prompt and run the following command to generate a device key:
dps-keygen -di:{Device ID. Ex:sensor01} -mk:{Primary Key from IoT Central}
Make a note on generated device key and the device ID you inputted .
Now we have the device provisioning information, we will add them to our device agent.
- Open main.c in your hummingboard_dps project.
- Specify parameters requested by the commented **TODO's** for your configuration.
// TODO: Specify DPS scope ID if you intend on using DPS / IoT Central.
static const char *dpsIdScope = "[DPS Id Scope]";
// TODO: Specify symmetric keys if you intend on using DPS / IoT Central and symmetric key based auth.
static const char *sasKey = "[DPS symmetric key]";
// TODO: specify your device registration ID
static const char *registrationId = "[device registration Id]";
- Replace the skeleton code hummingboard_impl.c in the hummingboard_dps with the hummingboard_impl.c you implemented in the hummingboard_hub project.
Task 4: Build and Run the Device Agent
We build the hummingboard_dps project to the cross-compiler container console. If you accidently close your cross-compiler container instance, follow the steps at Exercise 1 - Task 3: Build the Device Agent in Cross-Compiler Container to start your cross-compiler container console
- Build the hummingboard_dps in the container console for cross compiling.
./build_pnp.sh ./hummingboard_dps hummingboard_dps
- Copy your hummingboard_hub binary from the container to HummingBoard:
scp /work/iotsdk/cmake/app/hummingboard_dps/hummingboard_dps debian@192.168.200.200:app/hummingboard_dps
HummingBoard's login account username/password is debian / debian.
- In the SSH session with the HummingBoard, run the device agent by invoking the following command:
~/app/hummingboard_dps
- Verify that the device agent is successfully connected to the IoT Central through DPS by looking for following message in the device log.
…
Info: DPS successfully registered. Continuing on to creation of IoTHub device client handle.
Info: Successfully created DigitalTwin device with connectionString=\<****\>, deviceHandle=\<0x959dc0\>
…
Info: PnP enabled, running…
- Back to your IoT Central application, your device should show up with Device Status as Provision in Device Explorer section.
- Click on the device, you can see data send from device populated in the dashbarod.
Exercise 4: Certify Your IoT Plug and Play Device
To certify your IoT Plug and Play device, your device must meet the following requirements:
- Your IoT Plug and Play device code must be installed on your device.
- Your IoT Plug and Play device code are built with the Azure IoT SDK.
- Your device code must support the Azure IoT Hub Device Provisioning Service.
- Your device code must implement the Device Information Interface.
- The capability model and device code work with IoT Central.
Task 1: Enter Product Information in the Azure Certified for IoT Portal
- Sign in to the Azure Certified for IoT portal.
- Go to the Products page in the portal from the left menu and select + New.
- Enter your friendly product name and select Create. The name entered here is different from the name displayed in the device catalog.
- Select the created product link found on the Product page in the product column. The state should be in draft state.
- Select the Edit link next to Product information header. Enter information about your product in the product information page, and make sure you complete all the required fields.
- Select Save. The Save button only appears when you complete all the required fields. If the fields are incomplete, the button says Save and finish later.
- Review the content you entered.
Task 2: Connect the Discover Interfaces
To run the certification tests, connect your device to the Azure IoT certification service (AICS) that is available in the portal.
- In the Azure Certified for IoT portal, Click on Connect + test to start certification flow.
Select symmetric keys as the authentication method to provision your device to AICS using the Azure IoT Hub Device Provisioning Service.
- Open main.c in your hummingboard_dps project.
- Copy and paste symmetric keys , registration ID , and ID Scope into your device code. This is the same way we supply the DPS information for IoT Central.
// TODO: Specify DPS scope ID if you intend on using DPS / IoT Central.
static const char *dpsIdScope = "[DPS Id Scope]";
// TODO: Specify symmetric keys if you intend on using DPS / IoT Central and symmetric key based auth.
static const char *sasKey = "[DPS symmetric key]";
// TODO: specify your device registration ID
static const char *registrationId = "[device registration Id]";
- Build and deploy the hummingboard_dps project to the HummingBoard:
./build_pnp.sh ./hummingboard_dps hummingboard_dps
scp /work/iotsdk/cmake/app/hummingboard_dps/hummingboard_dps debian@192.168.200.200:app/hummingboard_dps
- In the SSH session with the HummingBoard, run the device agent by invoking the following command:
~/app/hummingboard_dps
- after your device agent is running, select Connect to discover the IoT Plug and Play interfaces.
When connection to AICS is successful, select Next to review discovered the IoT Plug and Play interfaces.

Task 3: Run Tests and Publish the Device
On the review page, you can review the discovered IoT Plug and Play interfaces. Use this page to check the primitives implemented in the interface display correctly. You can also check the location of the interface.
- Make sure payload inputs are entered for the required fields. These fields include payload information for the command primitive for the specified interface.
- When you've entered all the required information, select Next.
- To run the tests for the implemented IoT Plug and Play interfaces, select Run tests.
- All the tests run automatically. If any test fails, select View logs to view the error messages from AICS and the raw telemetry sent to Azure IoT Hub.
- To complete the certification tests, select Finish.
- Publish the certified IoT Plug and Play device to the catalog. To add the certified device to the catalog, select Add to Catalog on the toolbar.
- Select the "CERTIFIED AND IN THE CATALOG" link to view your published device on in the device catalog.
EXTRA CREDIT: Authenticate through X.509 Certification
X.509 Certificate Authority (CA) authentication is a one-to-many relationship a CA certificate has with its downstream devices. This relationship enables registration of any number of devices into IoT Hub by registering an X.509 CA certificate once, otherwise device unique certificates must be pre-registered for every device before a device can connect. This one-to-many relationship also simplifies device certificates life-cycle management operations. Read more on X.509 certificate here.
In this exercise, we will use X.509 certificate to provision the IoT Plug and Play device instead of symmetric keys.
Task 1: Create Self-Signed CA Certificate
We will leverage the Linux environment in to the cross-compiler container console to create a self-signed certificate. If you accidently close your cross-compiler container instance, follow the steps at Exercise 1 - Task 3: Build the Device Agent in Cross-Compiler Container to start your cross-compiler container console
- In the cross-compiler container console, create a folder named certificates under /workspaces.
cd /workspaces
mkdir certificates
cd certificates
- Copy the certification tools include in the Azure IoT Device SDK to the certificates folder.
cp ./azure-iot-sdk-c/tools/CACertificates/*.sh .
cp ./azure-iot-sdk-c/tools/CACertificates/*.cnf .
chmod 700 certGen.sh
- Create a CA and an intermediate certificate signer that chains back to the CA.
./certGen.sh create_root_and_intermediate
- Create a leaf device certificate with a unique device ID. This device ID will serve as the Common Name of the certificate.
./certGen.sh create_device_certificate my_device_id
This will create the files ./certs/new-device.* that contain the public key and PFX and ./private/new-device.key.pem that contains the device's private key. You should see those files created under {Desktop}/pnp_lab/certificates folder on the lab PC.
Task 2: Create Custom HSM Library
- 1. Open {Desktop}\pnp_lab\azure-iot-sdk-c\provisioning_client\samples\custom_hsm_example\custom_hsm_example.c with VS Code.
- 2. Replace the COMMON_NAME variable with the device ID you provided in Task 1, Step 4.
staticconstchar* const COMMON_NAME = "my_device_id";
- 3. Open {Desktop}\pnp_lab\certificates\certs\new-device.cert.pem. Replace the content of the CERTIFICATE variable with it.
- 4. Open {Desktop}\pnp_lab\certificates\certs\azure-iot-test-only.intermediate.cert.pem. Copy the content and append it to end of the CERTIFICATE variable. CERTIFICATE variable should end up like below:
staticconstchar*constCERTIFICATE = "—–BEGIN CERTIFICATE—–""\n"
"MIIFtDCCA5ygAwIBAgIBAjANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDDClBenVy""\n"
… device certificate…
"q+PycJvP0ceBD0RnoENKMuQ45PNOTC3m""\n"
"—–END CERTIFICATE—–""\n"
"—–BEGIN CERTIFICATE—–""\n"
"MIIFPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQsFADAqMSgwJgYDVQQDDB9BenVy""\n"
… intermediate certificate…
"hdvt9pLfayX2ZZlI35B1u8KkmUmiZVzuAWLig5bgYUAp/RMaozC9I21VikTT4fqH""\n"
"—–END CERTIFICATE—–"
;
Note
You may want to use Ctrl+Alt+Down or Ctrl+Alt+Up for multi-line vertical editing.
- 5. Open {Desktop}\pnp_lab\certificates\certs\new-device.cert.pem. Replace the content of the PRIVATE_KEY variable with it. It should be something like this.
staticconstchar*constPRIVATE_KEY = "—–BEGIN RSA PRIVATE KEY—–"
"MIIJKAIBAAKCAgEAxgwNnbp+AC2FvrkxS4DaiHXTC/jJXGllJJOHfTl/SUa8chyk""\n"
…
"VXQ9jRBqsk/T2liL+tL2p0INn+6q1ZEvr51bUJWFS8mGsXKQrzuWIpfzrro=""\n"
"—–END RSA PRIVATE KEY—–";
- 6. Asdfasd
Task 2: Register X.509 CA certificate to IoT Central Application
We need to provide and verify our root certificate to the Device Provisioning Service in our IoT Central Application so the service knows that our device can be trusted.
- Go to your IoT Central Application. Navigate to Administration and select Device Connection.
- Selec the Certificate (X.509) under the Credentials tab.
- Click on the button to upload {Desktop}/pnp_lab/certificates/certs/azure-iot-test-only.root.ca.cert.pem as the Primary Certificate.
- Now we need to prove that we actually own the certificate we uploaded. Click on the button to verify the primary certificate. In the pop-up dialogue, click on the button under Certificate Verification. It will generate a verification code we will used in the next step.
- Back in the cross-compiler container console, run the script to generate proof of possession (aka verification) certificate.
./certGen.sh create_verification_certificate \<verification code\>
The script outputs as the scripts will output the verification certificate at {** Desktop **}** \pnp_lab\certificates\certs\verification-code.cert.pem**.
- In the IoT Central Application, click on the Verify button to upload your verification certificate. The content in the pop-up dialogue would show that the certificate in verificated.
Task 4: Modify the Device Agent to Support X509
- Make a copy of the folder hummingboard_dps inside the {Desktop}/iot_pnp folder. Rename the copy to hummingboard_x509
- Open CMakeLists.txt under the hummingboard_x509 project.
- Replace all occurrences of hummingboard_dps to hummingboard_x509. Use Ctrl+H shortcut to bring out the Replace dialogue. Save the changes.
- Open main.c under the hummingboard_x509 folder.
- Make sure that ID Scope matches that of your IoT Central Application
// TODO: Specify DPS scope ID if you intend on using DPS / IoT Central.
static const char *dpsIdScope = "[DPS Id Scope]";
- Modify the security type to X509:
const SECURE_DEVICE_TYPE secureDeviceTypeForProvisioning = SECURE_DEVICE_TYPE_X509 ;
const IOTHUB_SECURITY_TYPE secureDeviceTypeForIotHub = IOTHUB_SECURITY_TYPE_X509 ;
- Remove code that sets symmetric keys information in RegisterDevice() function
staticbool registerDevice(bool traceOn)
{
...
if (IoTHub\_Init() != 0)
{
LogError("IoTHub\_Init failed");
returnfalse;
}
if (prov\_dev\_set\_symmetric\_key\_info(registrationId, sasKey) != 0)
{
LogError("prov\_dev\_set\_symmetric\_key\_info failed.");
}
elseif(prov\_dev\_security\_init(secureDeviceTypeForProvisioning) != 0)
{
LogError("prov\_dev\_security\_init failed");
}
...
}
- We will need to modify the build script to build the custom HSM library. Make a copy of build_pnp.sh and rename it to build_pnp_x509.sh.
- Open build_pnp_x509.sh with VS Code and find the line with cmake (should be around line 34). Replace the whole line as below:
cmake -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DCMAKE_INSTALL_PREFIX=${LIBC_PREFIX}/usr -Dbuild_provisioning_service_client:BOOL=OFF -Dhsm_custom_lib=custom_hsm_example -Duse_amqp:BOOL=OFF -Dbuild_service_client:BOOL=OFF -Duse_prov_client:BOOL=ON ${iotsdk_path} && \
- In the cross-compiler container console, build and deploy the hummingboard_x509 project to the HummingBoard:
./build_pnp_x509.sh ./hummingboard_x509 hummingboard_x509
scp /work/iotsdk/cmake/app/hummingboard_x509/hummingboard_x509 debian@192.168.200.200:app/hummingboard_x509
- In the SSH session with the HummingBoard, run the device agent by invoking the following command:
~/app/hummingboard_x509
- Verify that the device agent is successfully connected to the IoT Central through DPS by looking for following message in the device log.
…
Info: DPS successfully registered. Continuing on to creation of IoTHub device client handle.
Info: Successfully created DigitalTwin device with connectionString=\<****\>, deviceHandle=\<0x959dc0\>
…
Info: PnP enabled, running…
- Back to your IoT Central application, your device should show up with Device Status as Provision in Device Explorer section.