Tutorial: Use Azure PowerShell to configure IoT Hub message routing

Message routing enables sending telemetry data from your IoT devices to built-in Event Hub-compatible endpoints or custom endpoints such as blob storage, Service Bus Queues, Service Bus Topics, and Event Hubs. To configure custom message routing, you create routing queries to customize the route that matches a certain condition. Once set up, the incoming data is automatically routed to the endpoints by the IoT Hub. If a message doesn't match any of the defined routing queries, it is routed to the default endpoint.

In this 2-part tutorial, you learn how to set up and use these custom routing queries with IoT Hub. You route messages from an IoT device to one of multiple endpoints, including blob storage and a Service Bus queue. Messages to the Service Bus queue are picked up by a Logic App and sent via e-mail. Messages that do not have custom message routing defined are sent to the default endpoint, then picked up by Azure Stream Analytics and viewed in a Power BI visualization.

To complete Parts 1 and 2 of this tutorial, you perform the following tasks:

Part I: Create resources, set up message routing

  • Create the resources -- an IoT hub, a storage account, a Service Bus queue, and a simulated device. This can be done using the Azure portal, an Azure Resource Manager template, the Azure CLI, or Azure PowerShell.
  • Configure the endpoints and message routes in IoT Hub for the storage account and Service Bus queue.

Part II: Send messages to the hub, view routed results

  • Create a Logic App that is triggered and sends e-mail when a message is added to the Service Bus queue.
  • Download and run an app that simulates an IoT Device sending messages to the hub for the different routing options.
  • Create a Power BI visualization for data sent to the default endpoint.
  • View the results ...
  • ...in the Service Bus queue and e-mails.
  • ...in the storage account.
  • ...in the Power BI visualization.

Prerequisites

  • For Part 1 of this tutorial:

    • You must have an Azure subscription. If you don't have an Azure subscription, create a trial subscription before you begin.
  • For Part 2 of this tutorial:

    • You must have completed Part 1 of this tutorial, and have the resources still available.

    • Install Visual Studio.

    • Have access to a Power BI account to analyze the default endpoint's stream analytics. (Try Power BI for free.)

    • Have a work or school account for sending notification e-mails.

    • Make sure that port 8883 is open in your firewall. The sample in this tutorial 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 base resources

Before you can configure the message routing, you need to create an IoT hub, a storage account, and a Service Bus queue. These resources can be created using one of the four articles that are available for Part 1 of this tutorial: the Azure portal, an Azure Resource Manager template, the Azure CLI, or Azure PowerShell.

Use the same resource group and location for all of the resources. Then at the end, you can remove all of the resources in one step by deleting the resource group.

Below is a summary of the steps to be performed in the following sections:

  1. Create a resource group.

  2. Create an IoT hub in the S1 tier. Add a consumer group to your IoT hub. The consumer group is used by the Azure Stream Analytics when retrieving data.

    Note

    You must use an Iot hub in a paid tier to complete this tutorial. The free tier only allows you to set up one endpoint, and this tutorial requires multiple endpoints.

  3. Create a standard V1 storage account with Standard_LRS replication.

  4. Create a Service Bus namespace and queue.

  5. Create a device identity for the simulated device that sends messages to your hub. Save the key for the testing phase. (If creating a Resource Manager template, this is done after deploying the template.)

Download the script (optional)

For the second part of this tutorial, you download and run a Visual Studio application to send messages to the IoT Hub. There is a folder in the download that contains the Azure Resource Manager template and parameters file, as well as the Azure CLI and PowerShell scripts.

If you want to view the finished script, download the Azure IoT C# Samples. Unzip the main.zip file. The Azure CLI script is in /iot-hub/Tutorials/Routing/SimulatedDevice/resources/ as iothub_routing_psh.ps1.

Create your resources

Start by creating the resources with PowerShell.

Use PowerShell to create your base resources

Copy and paste the script below into local Shell and press Enter. It runs the script one line at a time. This first section of the script will create the base resources for this tutorial, including the storage account, IoT Hub, Service Bus Namespace, and Service Bus queue. As you go through the tutorial, copy each block of script and paste it into local Shell to run it.

There are several resource names that must be globally unique, such as the IoT Hub name and the storage account name. To make this easier, those resource names are appended with a random alphanumeric value called randomValue. The randomValue is generated once at the top of the script and appended to the resource names as needed throughout the script. If you don't want it to be random, you can set it to an empty string or to a specific value.

Important

The variables set in the initial script are also used by the routing script, so run all of the script in the same local Shell session. If you open a new session to run the script for setting up the routing, several of the variables will be missing values.

# This command retrieves the subscription id of the current Azure account.
# This field is used when setting up the routing queries.
$subscriptionID = (Get-AzContext).Subscription.Id

# Concatenate this number onto the resources that have to be globally unique.
# You can set this to "" or to a specific value if you don't want it to be random.
# This retrieves the first 6 digits of a random value.
$randomValue = "$(Get-Random)".Substring(0,6)

# Set the values for the resource names that don't have to be globally unique.
$location = "China North"
$resourceGroup = "ContosoResources"
$iotHubConsumerGroup = "ContosoConsumers"
$containerName = "contosoresults"

# Create the resource group to be used 
# for all resources for this tutorial.
New-AzResourceGroup -Name $resourceGroup -Location $location

# The IoT hub name must be globally unique, 
# so add a random value to the end.
$iotHubName = "ContosoTestHub" + $randomValue
Write-Host "IoT hub name is " $iotHubName

# Create the IoT hub.
New-AzIotHub -ResourceGroupName $resourceGroup `
    -Name $iotHubName `
    -SkuName "S1" `
    -Location $location `
    -Units 1 

# Add a consumer group to the IoT hub.
Add-AzIotHubEventHubConsumerGroup -ResourceGroupName $resourceGroup `
  -Name $iotHubName `
  -EventHubConsumerGroupName $iotHubConsumerGroup

# The storage account name must be globally unique, so add a random value to the end.
$storageAccountName = "contosostorage" + $randomValue
Write-Host "storage account name is " $storageAccountName

# Create the storage account to be used as a routing destination.
# Save the context for the storage account 
# to be used when creating a container.
$storageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroup `
    -Name $storageAccountName `
    -Location $location `
    -SkuName Standard_LRS `
    -Kind Storage
# Retrieve the connection string from the context. 
$storageConnectionString = $storageAccount.Context.ConnectionString
Write-Host "storage connection string = " $storageConnectionString 

# Create the container in the storage account.
New-AzStorageContainer -Name $containerName `
    -Context $storageAccount.Context

# The Service Bus namespace must be globally unique,
# so add a random value to the end.
$serviceBusNamespace = "ContosoSBNamespace" + $randomValue
Write-Host "Service Bus namespace is " $serviceBusNamespace

# Create the Service Bus namespace.
New-AzServiceBusNamespace -ResourceGroupName $resourceGroup `
    -Location $location `
    -Name $serviceBusNamespace 

# The Service Bus queue name must be globally unique,
# so add a random value to the end.
$serviceBusQueueName  = "ContosoSBQueue" + $randomValue
Write-Host "Service Bus queue name is " $serviceBusQueueName 

# Create the Service Bus queue to be used as a routing destination.
New-AzServiceBusQueue -ResourceGroupName $resourceGroup `
    -Namespace $serviceBusNamespace `
    -Name $serviceBusQueueName  `
    -EnablePartitioning $False 

Create a simulated device

Next, create a device identity and save its key for later use. This device identity is used by the simulation application to send messages to the IoT hub. This capability is not available in PowerShell or when using an Azure Resource Manager template. The following steps tell you how to create the simulated device using the Azure portal.

  1. Open the Azure portal and log into your Azure account.

  2. Select Resource groups and then choose your resource group. This tutorial uses ContosoResources.

  3. In the list of resources, select your IoT hub. This tutorial uses ContosoTestHub. Select IoT Devices from the Hub pane.

  4. Select +Add Device on the IoT Devices pane. On the Add Device pane, fill in the device ID. This tutorial uses Contoso-Test-Device. Leave the keys empty, and check Auto Generate Keys. Make sure Connect device to IoT hub is enabled. Select Save.

    The add-device screen

  5. Now that it's been created, select the device to see the generated keys. Select the Copy icon on the Primary key and save it somewhere such as Notepad for the testing phase of this tutorial.

    The device details, including the keys

Now that the base resources are set up, you can configure the message routing.

Set up message routing

You are going to route messages to different resources based on properties attached to the message by the simulated device. Messages that are not custom routed are sent to the default endpoint (messages/events). In the next tutorial, you send messages to the IoT Hub and see them routed to the different destinations.

Value Result
level="storage" Write to Azure Storage.
level="critical" Write to a Service Bus queue. A Logic App retrieves the message from the queue and uses Office 365 to e-mail the message.
default Display this data using Power BI.

The first step is to set up the endpoint to which the data will be routed. The second step is to set up the message route that uses that endpoint. After setting up the routing, you can view the endpoints and message routes in the portal.

To create a routing endpoint, use Add-AzIotHubRoutingEndpoint. To create the messaging route for the endpoint, use Add-AzIotHubRoute.

Route to a storage account

First, set up the endpoint for the storage account, then create the message route.

Note

The data can be written to blob storage in either the Apache Avro format, which is the default, or JSON.

The encoding format can be only set at the time the blob storage endpoint is configured. The format cannot be changed for an endpoint that has already been set up. When using JSON encoding, you must set the contentType to JSON and the contentEncoding to UTF-8 in the message system properties.

For more detailed information about using a blob storage endpoint, please see guidance on routing to storage.

These are the variables used by the script that must be set within your local Shell session:

resourceGroup: There are two occurrences of this field -- set both of them to your resource group.

name: This field is the name of the IoT Hub to which the routing will apply.

endpointName: This field is the name identifying the endpoint.

endpointType: This field is the type of endpoint. This value must be set to azurestoragecontainer, eventhub, servicebusqueue, or servicebustopic. For your purposes here, set it to azurestoragecontainer.

subscriptionID: This field is set to the subscriptionID for your Azure account.

storageConnectionString: This value is retrieved from the storage account set up in the previous script. It is used by the routing to access the storage account.

containerName: This field is the name of the container in the storage account to which data will be written.

Encoding: Set this field to either AVRO or JSON. This designates the format of the stored data. The default is AVRO.

routeName: This field is the name of the route you are setting up.

condition: This field is the query used to filter for the messages sent to this endpoint. The query condition for the messages being routed to storage is level="storage".

enabled: This field defaults to true, indicating that the message route should be enabled after being created.

Copy this script and paste it into your local Shell window.

##### ROUTING FOR STORAGE #####

$endpointName = "ContosoStorageEndpoint"
$endpointType = "azurestoragecontainer"
$routeName = "ContosoStorageRoute"
$condition = 'level="storage"'

The next step is to create the routing endpoint for the storage account. You also specify the container in which the results will be stored. The container was created when the storage account was created.

# Create the routing endpoint for storage.
# Specify 'AVRO' or 'JSON' for the encoding of the data.
Add-AzIotHubRoutingEndpoint `
  -ResourceGroupName $resourceGroup `
  -Name $iotHubName `
  -EndpointName $endpointName `
  -EndpointType $endpointType `
  -EndpointResourceGroup $resourceGroup `
  -EndpointSubscriptionId $subscriptionId `
  -ConnectionString $storageConnectionString  `
  -ContainerName $containerName `
  -Encoding AVRO

Next, create the message route for the storage endpoint. The message route designates where to send the messages that meet the query specification.

# Create the route for the storage endpoint.
Add-AzIotHubRoute `
   -ResourceGroupName $resourceGroup `
   -Name $iotHubName `
   -RouteName $routeName `
   -Source DeviceMessages `
   -EndpointName $endpointName `
   -Condition $condition `
   -Enabled 

Route to a Service Bus queue

Now set up the routing for the Service Bus queue. To retrieve the connection string for the Service Bus queue, you must create an authorization rule that has the correct rights defined. The following script creates an authorization rule for the Service Bus queue called sbauthrule, and sets the rights to Listen Manage Send. Once this authorization rule is set up, you can use it to retrieve the connection string for the queue.

##### ROUTING FOR SERVICE BUS QUEUE #####

# Create the authorization rule for the Service Bus queue.
New-AzServiceBusAuthorizationRule `
  -ResourceGroupName $resourceGroup `
  -NamespaceName $serviceBusNamespace `
  -Queue $serviceBusQueueName `
  -Name "sbauthrule" `
  -Rights @("Manage","Listen","Send")

Now use the authorization rule to retrieve the Service Bus queue key. This authorization rule will be used to retrieve the connection string later in the script.

$sbqkey = Get-AzServiceBusKey `
    -ResourceGroupName $resourceGroup `
    -NamespaceName $serviceBusNamespace `
    -Queue $servicebusQueueName `
    -Name "sbauthrule"

Now set up the routing endpoint and the message route for the Service Bus queue. These are the variables used by the script that must be set within your local Shell session:

endpointName: This field is the name identifying the endpoint.

endpointType: This field is the type of endpoint. This value must be set to azurestoragecontainer, eventhub, servicebusqueue, or servicebustopic. For your purposes here, set it to servicebusqueue.

routeName: This field is the name of the route you are setting up.

condition: This field is the query used to filter for the messages sent to this endpoint. The query condition for the messages being routed to the Service Bus queue is level="critical".

Here is the Azure PowerShell for the message routing for the Service Bus queue.

$endpointName = "ContosoSBQueueEndpoint"
$endpointType = "servicebusqueue"
$routeName = "ContosoSBQueueRoute"
$condition = 'level="critical"'

# If this script fails on the next statement (Add-AzIotHubRoutingEndpoint),
# put the pause in and run it again. Note that if you're running it
# interactively, you can just stop it and then run the rest, because
# you have already set the variables before you get to this point.
#
# Pause for 90 seconds to allow previous steps to complete.
# Then report it to the IoT team here: 
# https://github.com/Azure/azure-powershell/issues
# pause for 90 seconds and then start again. 
# This way, it if didn't get to finish before it tried to move on, 
# now it will have time to finish first.
   Start-Sleep -Seconds 90

# This command is the one that sometimes doesn't work. It's as if it doesn't have time to
# finish before it moves to the next line.
# The error from Add-AzIotHubRoutingEndpoint is "Operation returned an invalid status code 'BadRequest'".
# This command adds the routing endpoint, using the connection string property from the key. 
# This will definitely work if you execute the Sleep command first (it's in the line above).
Add-AzIotHubRoutingEndpoint `
  -ResourceGroupName $resourceGroup `
  -Name $iotHubName `
  -EndpointName $endpointName `
  -EndpointType $endpointType `
  -EndpointResourceGroup $resourceGroup `
  -EndpointSubscriptionId $subscriptionId `
  -ConnectionString $sbqkey.PrimaryConnectionString

# Set up the message route for the Service Bus queue endpoint.
Add-AzIotHubRoute `
   -ResourceGroupName $resourceGroup `
   -Name $iotHubName `
   -RouteName $routeName `
   -Source DeviceMessages `
   -EndpointName $endpointName `
   -Condition $condition `
   -Enabled 

View message routing in the portal

Now that your endpoints and message routes are set up, you can view their configuration in the portal. Sign in to the Azure portal and go to Resource Groups. Next, select your resource group, then select your hub (the hub name starts with ContosoTestHub in this tutorial). You see the IoT Hub pane.

IoT Hub properties screen

In the options for the IoT Hub, select Message Routing. The routes you have set up successfully are displayed.

The routes you set up

On the Message routing screen, select Custom Endpoints to see the endpoints you have defined for the routes.

The endpoints set up for the routes

Next steps

Now that you have the resources set up and the message routes configured, advance to the next tutorial to learn how to send messages to the IoT hub and see them be routed to the different destinations.