Professional Documents
Culture Documents
AZ 220 Microsoft Azure IoT Developer
AZ 220 Microsoft Azure IoT Developer
Exercise 1 -
Develop Azure Digital Twins (ADT) solutions
Configure Lab
Prerequisites
Lab Scenario
Exercise 2 -
Create an Contoso Management has decided to take the next step in their digital evolution and develop a model of their
instance of the
Azure Digital
cheese making facility using Azure Digital Twins (ADT). With Azure Digital Twins, it is possible to create and
Twins resource interact with live models of real-world environments. First, each individual element is modeled as a digital twin.
Then, these models are connected into a knowledge graph that can respond to live events and be queried for
Exercise 3 -
information.
Create a graph
of the models
In order to better understand how to best leverage ADT, you have been asked to build a proof-of-concept
Exercise 4 - prototype that demonstrates how the existing Cheese Cave Device sensor telemetry can be incorporated into a
Query the graph simple model hierarchy:
using ADT
Explorer
Cheese Factory
Exercise 5 -
Cheese Cave
Configure and Cheese Cave Device
launch device
simulator In this first prototype, you have been asked to demonstrate the solutions to the following scenarios:
Exercise 6 - Set How device telemetry can be mapped from an IoT Hub into the appropriate device in ADT
up Azure
Function to How updates to a child digital twin property can be used to update a parent twin property (from a Cheese
ingest data Cave Device to a Cheese Cave)
How device telemetry can be routed via ADT to Time Series Insights
Exercise 7 -
Connect IoT
The following resources will be created:
Hub to the
Azure Function
Exercise 8 -
Connect ADT to
TSI
In This Lab
In this lab, you will complete the following activities:
Lab Instructions
This lab assumes that the following Azure resources are available:
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 1/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
TSI tsi-az220-training-{your-id}
1. In the virtual machine environment, open a Microsoft Edge browser window, and then navigate to the
following Web address:
+++https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FMicrosoftLearning%2FAZ-
220-Microsoft-Azure-IoT-Developer%2Fbicep%2FAllfiles%2FARM%2Flab19.json+++
❕ NOTE: Whenever you see the green “T” symbol, for example +++enter this text+++, you can click the associated text
and the information will be typed into the current field within the virtual machine environment.
2. If prompted to log in to the Azure portal, enter the Azure credentials that you are using for this course.
3. Under Project details, in the Subscription dropdown, ensure that the Azure subscription that you intend
to use for this course is selected.
5. Under Instance details, in the Region dropdown, select the region closest to you.
❕ NOTE: If the rg-az220 group already exists, the Region field is set to the region used by the resource group and is
read-only.
8. To determine the current user object ID, open the Cloud Shell and execute the following command:
Shell Copy
9. In the Object ID field, enter the object ID copied from the above step.
12. Once the deployment has completed, in the left navigation area, to review any output values from the
template, click Outputs.
connectionString
deviceConnectionString
devicePrimaryKey
storageAccountName
1. Open a command prompt and verify the Azure CLI is installed locally, by entering the following command:
Code Copy
az --version
If Azure CLI is not installed, you must install it before you continue.
In this exercise, the Azure portal will be used to create an Azure Digital Twins (ADT) instance. The connection
data for Azure Digital Twins will then be stored in a text file for later use. Finally the current user will be assigned
a role to allow the ADT resource to be accessed.
Task 1 - Use the Azure portal to create a resource (Azure Digital Twins)
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 2/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
The New blade that opens is a front-end to the Azure Marketplace, which is a collection of all the resources
you can create in Azure. The marketplace contains resources from both Microsoft and the community.
3. In the Search the marketplace text box, type Azure Digital Twins
4. When the option appears, select Azure Digital Twins, and then click Create.
5. On the Create Resource pane, under Subscription, ensure that the subscription you are using for this
course is selected.
❕ Note: Your account must have the administrator role for the subscription
8. In the Region dropdown, select the region where your Azure IoT Hub is provisioned (or the closest region
available).
9. Under Grant access to resource, to ensure the current user can use the Digital Twins Explorer app, check
Assign Azure Digital Twins Owner Role.
❕ Note: To manage the elements within an instance, a user needs access to Azure Digital Twins data plane APIs. Select
the suggested role above grants the current user full access to the data plane APIs. You can also use Access Control
(IAM) to choose appropriate roles later. You can learn more about Azure Digital Twins Security here
You should see the Overview pane for your ADT resource, which includes a body section titled Get started
with Azure Digital Twins.
2. Add the name of the Azure Digital Twins instance to the file - adt-az220-training-{your-id}
5. In the Essentials section of the pane, locate the Host name field.
6. Hover the mouse pointer over the Host name field, use the icon than appears to the right of the value to
copy the host name to the clipboard, and then paste it into the text file.
7. In the text file, convert the host name to a connection url to your digital twins instance by adding https://
to the start of the host name.
Code Copy
https://adt-az220-training-dm030821.api.eus.digitaltwins.azure.net
The Azure Digital Twin resource is now created and the user account has been updated so that the resource can
be accessed via APIs.
As part of a modeling activity, analysts would consider many factors, such as the Cheese Cave Device message
content, and create mappings in DTDL Property and Telemetry field definitions. In order to use these DTDL
code fragments, they would be incorporated into an Interface (the top-level code item for a model). However,
the Interface for a Cheese Cave Device model would form just a small part of the Azure Digital Twins
environment for a Contoso Cheese Factory. As modeling an environment that represents an entire factory is
beyond the scope of this course, a greatly simplified environment that focuses on a Cheese Cave Device model,
an associated Cheese Cave model, and a Factory model will be considered instead. The model hierarchy is as
follows:
Considering the hierarchy of Interface definitions above, and the relationships between them, it can be said that
a Cheese Factory has Cheese Caves, and a Cheese Cave has Cheese Cave Devices.
When designing the Digital Twin models for an ADT environment, it is best to use a consistent approach for
creating the IDs used for the Interfaces, Schemas, and Relationships. Each entity within the environment has an
@id property (it is required for Interfaces) and should uniquely identify that entity. The format of the ID value is
that of a digital twin model identifier (DTMI). A DTMI has three components: scheme, path, and version. The
scheme and path are separated by a colon : , while path and version are separated by a semicolon ; . The
format looks like this: <scheme> : <path> ; <version> . The value for scheme within the DTMI formatted ID is
always dtmi.
One example for the ID value of a Contoso cheese factory would be:
dtmi:com:contoso:digital_factory:cheese_factory;1 .
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 3/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
In this example, the scheme value is dtmi as expected and the version is set to 1. The <path> component within
this ID value utilizes the following taxonomy:
❕ TIP: To learn more about the DTMI format, review the following resource:
Digital Twin Model Identifier
Recalling the model hierarchy and relationships identified above, an example of the IDs used could be:
Interface ID
Relationship ID From ID To ID
❕ NOTE: In Lab 3: Setup the Development Environment, you The complete models
Allfiles
cloned the GitHub repository containing lab resources by referenced in this
downloading a ZIP file and extracting the contents locally. Labs exercise are available
The extracted folder structure includes the following folder in this folder
path: 19-Azure Digital location.
Twins
Final
Models
Fore the purposes of this exercise, the interfaces have already been defined for each of the digital twins that will
be used in the proof-of-concept, it is time to construct the actual graph of digital twins. The flow for building a
graph is straightforward:
As the ADT Explorer includes rich visualization of an ADT graph, it is well suited for building out the simple model
for the proof-of-concept. However, larger, more complex, models are also supported and a comprehensive bulk
import/export capability helps with iterative design. During this exercise the following tasks will be completed:
The ADT Explorer is a an application for the Azure Digital Twins service. The app connects to an Azure Digital
Twins instance and provides the following features/capabilities:
The ADT explorer is incorporated into the Azure Portal as a preview feature and is also available as a standalone
sample application. In this lab, the version incorporated into the Azure Portal will be used.
3. To open the ADT Explorer in a new browser tab, click Open Azure Digital Twins Explorer (preview).
A new browser tab hosting the ADT Explorer will open. You will see an alert indicating no results have been
found - this is expected as no models have been imported.
❕ Important: If you are prompted to login, ensure you use the same account that you used when creating the Azure
Digital Twins instance, otherwise you will not have access to the data plane APIs and will see errors.
The ADT Explorer sample application is now ready for use. Loading models is your next task, so don’t be
alarmed if you see an error message telling you that there are no models available.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 4/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
Task 2 - Import Models
In order to create Digital Twins in ADT, it is necessary to first upload models. There are a number of ways that
models can be uploaded:
The first two options are more appropriate for programmatic scenarios, whereas the Azure CLI can be useful in
configuration as code scenarios or “one-off” requirements. The ADT Explorer app provides an intuitive way to
interact with ADT.
❕ TIP: What is configuration as code? As configuration is written as source code (for example, scripts containing Azure CLI
commands), you can use best development practices to optimise it, such as: creating reusable definitions of model uploads,
parameterization, using loops to create multiple instances of the models and so on. These scripts can then be stored in
source code control to ensure they are retained, version controlled, etc.
In this task, you will use Azure CLI commands and the ADT Explorer sample app to upload the models included
in the Allfiles\Labs\19-Azure Digital Twins\Final\Models folder.
2. To ensure that you using correct Azure account credentials, login to Azure using the following command:
Code Copy
az login
Code Copy
Ensure you replace the {file-root} with the folder the companion files for this lab are located, and replace
{your-id} with your unique identifier.
Code Copy
[
{
"decommissioned": false,
"description": {},
"displayName": {
"en": "Cheese Factory - Interface Model"
},
"id": "dtmi:com:contoso:digital_factory:cheese_factory;1",
"uploadTime": "2021-03-24T19:56:53.8723857+00:00"
}
]
❕ TIP: Click the Refresh button in the MODELS explorer to update the list of models.
5. To import the remaining two models using the ADT Explorer, in the MODELS explorer, click the Upload a
Model icon
6. In the Open dialog, navigate to the Models folder, select the CheeseCaveInterface.json and the
CheeseCaveDeviceInterface.json files, and then click Open.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 5/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
The two files will then be uploaded to ADT and the models added. Once complete, the MODELS explorer
will update and list all three models.
Now that the models are uploaded, Digital Twins can be created.
In an Azure Digital Twins solution, the entities in your environment are represented by digital twins. A digital twin
is an instance of one of your custom-defined models. It can be connected to other digital twins via relationships
to form a twin graph: this twin graph is the representation of your entire environment.
Similar to models, digital twins and relationships can be created in multiple ways:
As before, the first two options are more appropriate for programmatic scenarios, whereas the Azure CLI remains
useful in configuration as code scenarios or “one-off” requirements. The most intuitive way to create digital
twins and relationships is via the ADT Explorer, however there are some limitations when it comes to initializing
properties.
1. Open the command line window that you used to upload the CheeseFactoryInterface model.
2. To create a digital twin from the Cheese Factory model using the Azure CLI, enter the following command:
Code Copy
Ensure you replace the {file-root} with the folder the companion files for this lab are located, and replace
{your-id} with your unique identifier.
Code Copy
{
"$dtId": "factory_1",
"$etag": "W/\"09e781e5-c31f-4bf1-aed4-52a4472b0c5b\"",
"$metadata": {
"$model": "dtmi:com:contoso:digital_factory:cheese_factory;1",
"FactoryName": {
"lastUpdateTime": "2021-03-24T21:51:04.1371421Z"
},
"GeoLocation": {
"lastUpdateTime": "2021-03-24T21:51:04.1371421Z"
}
},
"FactoryName": "Contoso Cheese 1",
"GeoLocation": {
"Latitude": 47.64319985218156,
"Longitude": -122.12449651580214
}
}
Notice that the $metadata property contains an object that tracks the last time properties were updated.
Code Copy
{
"FactoryName": "Contoso Cheese 1",
"GeoLocation": {
"Latitude": 47.64319985218156,
"Longitude": -122.12449651580214
}
}
The property names match the DTDL Property values declared in the Cheese Factory Interface.
❕ NOTE: The complex property GeoLocation is assigned via a JSON object with Latitude and Longitude properties.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 6/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
After a few moments, the factory_1 digital twin should be displayed in the TWIN GRAPH view.
6. To view the digital twin properties, in the TWIN GRAPH view, click factory_1.
The properties for factory_1 are displayed in the Property View as nodes in a tree view.
Notice that the values are consistent with those in the FactoryProperties.json file.
8. To create another digital twin from the Cheese Factory model, in the MODELS explorer, locate the Cheese
Factory model, and then click Create a Twin
9. When prompted for the New Twin Name enter factory_2 and then click Save.
10. To view the digital twin properties for factory_2, in the TWIN GRAPH view, click factory_2.
11. To set the factoryName, position the mouse cursor to the right of the property - a textbox control should
appear. Enter Cheese Factory 2.
12. In the PROPERTIES Explorer pane, to save the update to the property, select the Patch Twin icon.
❕ Note: The Patch Twin icon appears identical to the Save Query icon located to the right of the Run Query button. You
don’t want the Save Query icon.
Selecting Patch Twin will result in a JSON Patch being created and sent to update the digital twin. The
Patch Information will be displayed in a dialog. Notice that as this is the first time the value has been set,
the op (operation) property is add. Subsequent changes to the value would be replace operations - to see
this, click Run Query to refresh the TWIN GRAPH view before making another update.
❕ TIP: To learn more about a JSON Patch document, review the following
Javascript Object Notation (JSON)
resources:
Patch
What is JSON Patch?
13. In the PROPERTIES explorer, examine the factory_2 GeoLocation property - notice the values for
Latitude and Longitude are shown as Unset.
❕ Info: Earlier versions of the ADT Explorer did not support editing “sub-properties” via the UI - this feature is a welcome
addition.
Latitude 47.64530450740752
Longitude -122.12594819866645
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 7/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
15. In the PROPERTIES Explorer pane, to save the update to the properties, select the Patch Twin icon.
16. Add the following digital twins by selecting the appropriate model in MODELS explorer and clicking Add a
Twin:
Now that some twins have been created, it is time to add some relationships.
Twins are connected into a twin graph by their relationships. The relationships that a twin can have are defined
as part of its model.
For example, the Cheese Factory model defines a “contains” relationship that targets twins of type Cheese Cave.
With this definition, Azure Digital Twins will allow you to create rel_has_caves relationships from any Cheese
Factory twin to any Cheese Cave twin (including any twins that may be subtypes of a Cheese Cave - for
example a specialized Cheese Cave for a specific cheese).
The result of this process is a set of nodes (the digital twins) connected via edges (their relationships) in a graph.
1. To create a relationship via the Azure CLI, return to the command prompt and execute the following
command:
Code Copy
Code Copy
{
"$etag": "W/\"cdb10516-36e7-4ec3-a154-c050afed3800\"",
"$relationshipId": "factory_1_has_cave_1",
"$relationshipName": "rel_has_caves",
"$sourceId": "factory_1",
"$targetId": "cave_1"
}
The diagram will refresh and the new relationship will be displayed.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 8/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
If you don’t see the relationship, refresh the browser window and then run the query.
4. To add a relationship using the ADT Explorer, first click cave_1 to select it, and then right-click device_1.
In the displayed context menu, select Add relationships.
5. In the Create Relationship dialog, under Source ID, confirm that cave_1 is displayed.
❕ NOTE: Unlike relationships created with the Azure CLI, there is no equivalent UI to supply a $relationshipId value.
Instead, a GUID will be assigned.
The relationship will be created and the diagram will update to display the relationship. The diagram now
shows that factory_1 has cave_1, which has device_1.
10. To view the layout options for the TWIN GRAPH view, click the Choose Layout button.
The TWIN GRAPH view can use different algorithms to layout the graph. The Klay layout is selected by
default. You can try selecting different layouts to see how the graph is impacted.
During the design process for modeling with ADT, it is likely that a number of proof-of-concepts will be created,
many of which will be deleted. Similar to the other operations on digital twins, there are programmatic
approaches (API, SDK, and CLI) to deleting models and twins, and you can also use the ADT Explorer.
❕ NOTE: One thing to note is that the delete operations are asynchronous and although, for example, a REST API call or a
delete in ADT Explorer may appear to complete instantly, it may take a few minutes for the operation to complete within the
ADT service. Attempting to upload revised models with the same name as recently deleted models may fail unexpectedly until
the back-end operations have completed.
1. To delete the factory_2 digital twin via the CLI, return to your command prompt window, and then enter
the following command:
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 9/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
Code Copy
Unlike other commands, no output is displayed (unless the command produces an error).
2. To delete the relationship between factory_1 and cave_1, enter the following command:
Code Copy
Notice that this command requires the relationship ID. You can view the relationship IDs for a given twin.
For example, to view the relationship IDs for factory_1, you can enter the following command:
Code Copy
If you ran this command prior to deleting the relationship to cave 1, you would see output similar to the
following:
Code Copy
[
{
"$etag": "W/\"a6a9f506-3cfa-4b62-bcf8-c51b5ecc6f6d\"",
"$relationshipId": "47b0754a-25d1-4b71-ac47-c2409bb08535",
"$relationshipName": "rel_has_caves",
"$sourceId": "factory_1",
"$targetId": "cave_2"
},
{
"$etag": "W/\"b5207e88-7c86-498f-a272-7f81dde88dee\"",
"$relationshipId": "factory_1_has_cave_1",
"$relationshipName": "rel_has_caves",
"$sourceId": "factory_1",
"$targetId": "cave_1"
}
]
Code Copy
❕ IMPORTANT: This command deleted the factory model and succeeded, even though a digital twin factory_1 still
exists. Digital twins that were created using the deleted model can still be found by querying the graph, however,
properties of the twin can no longer be updated without the model. Be very careful when completing model
management tasks (versioning, deleting, etc.) to avoid creating inconsistent graphs.
4. To display the recent changes to the digital twins, return to the ADT Explorer.
5. To update the display, refresh the browser page and then click Run Query.
The Cheese Factory model should be missing from the MODELS explorer and there should be no
relationship between factory_1 and cave_1 in the TWIN GRAPH view.
6. To select the relationship between cave_1 and device_1, click the line between the two twins.
The line should thicken indicating it is selected and the Delete Relationship button will be enabled.
7. To delete the relationship, right-lick the line and select Delete relationship(s) from the context menu, and
confirm by clicking Delete.
8. To delete the device_1 digital twin, right-click device_1, and select Delete twin(s) from the context menu.
❕ NOTE: By using CTRL and left-click, multiple twins can be selected. To delete them, right-click the final twin and select
Delete twin(s) from the context menu.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 10/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
9. In the upper-right corner of the ADT Explorer page, to delete all of the digital twins in a graph, click Delete
All Twins, and confirm by clicking Delete.
10. To delete the Cheese Cave Device model from the MODELS explorer, click the associated Delete Model
button, and confirm by clicking Delete.
11. To delete all models, click Delete All Models at the top of the MODELS explorer.
At this point, the ADT instance should be clear of all models, twins and relationships. Don’t worry - in the next
task the Import Graph feature will be used to create a new graph.
The ADT Explorer supports the import and export of a digital twin graph. The Export capability serializes the
most recent query results to a JSON-based format, including models, twins, and relationships. The Import
capability deserializes from either a custom Excel-based format or the JSON-based format generated on export.
Before import is executed, a preview of the graph is presented for validation.
ModelId: The complete dtmi for the model that should be instantiated.
ID: The unique ID for the twin to be created
Relationship: A twin id with an outgoing relationship to the new twin
Relationship name: The name for the outgoing relationship from the twin in the previous column
Init data: A JSON string that contains Property settings for the twins to be created
❕ NOTE: The Excel import capability does not import model definitions, only twins and relationships. The JSON format supports
models as well.
The following table shows the twins and relationships that will be created in this task (the Init Data values are
removed for readability):
dtmi:com:contoso:digital_factory:cheese_factory;1 factory_1
2. To import your models using the ADT Explorer, in the MODELS explorer, click the Upload a Model icon
3. In the Open dialog, navigate to the Models folder, select the CheeseFactoryInterface.json,
CheeseCaveInterface.json, and CheeseCaveDeviceInterface.json files, and then click Open.
5. In the Open dialog, navigate to the Models folder and select the cheese-factory-scenario.xlsx file, then
click Open.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 11/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
An Import Successful dialog will be displayed, detailing that 7 twins and 6 relationships were imported.
Click Close to proceed.
The imported graph should now be displayed. You can click on each twin to view the properties (each twin
has been initialized with values).
8. To export the current graph as JSON, click Export Graph (next to the Import Graph button used earlier).
The Export view is displayed with a Download link in the top-left corner.
10. To view the JSON, open the downloaded file in Visual Studio Code.
If the JSON is shown as a single line, reformat the JSON using the Format Document command via the
command palette or by pressing SHIFT+ALT+F.
❕ NOTE: Unlike the Excel format, the JSON file includes the model definitions, meaning that everything can be imported
with just the one file.
11. To import the JSON file, use ADT Explorer to delete the models and twins following the instructions in
earlier tasks, and then import the JSON export file that was just created. Note that the models, twins and
their properties, and the relationships are recreated.
This twin graph will be used as the basis for the exercise on querying.
❕ NOTE: This exercise requires the graph imported in the previous exercise.
You can query the digital twin graph that you just built, to get information about the digital twins and
relationships it contains. You write these queries in a custom, SQL-like query language, referred to as the Azure
Digital Twins query language. This language is also similar to the query language for Azure IoT Hub.
Queries can be made through the Digital Twins REST API and with the SDKs. In this exercise, you’ll be using the
Azure Digital Twins explorer sample app to handle the API calls for you. Additional tools will be explored later in
this lab.
❕ NOTE: The ADT Explorer is designed to visualize a graph and can only display entire twins, rather than just single values
selected from a twin, such as the name.
In this task, the ADT Explorer will be used to execute graph queries and render the results as a graph. Twins can
be queried by properties, model type and by relationships. Queries can be combined into compound queries
using combination operators that can query for more than one type of twin descriptor at a a time.
Sql Copy
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 12/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
If you are at all familiar with SQL, you will expect that this will return everything from digital twins.
4. To save this as a named query, click on the Save icon (just to the right of the Run Query button).
5. In the Save Query dialog, enter the name All Twins and click Save.
This query will then be saved locally and be available in the Saved Queries drop down to the left of the
query text box. To delete a saved query, click on the X icon next to the name of the query when the Saved
Queries drop down is open.
❕ TIP: Run the All Twins query to return to the full view at any time.
6. To filter the graph so that only Cheese Cave twins are displayed, enter and run the following query:
Sql Copy
The graph will now display just the 3 Cheese Cave twins.
7. To display only the Cheese Cave twins that are inUse, enter and run the following query:
Sql Copy
8. To display only the Cheese Cave twins that are inUse and have a temperatureAlert, enter and run the
following query:
Sql Copy
9. To use relationships to find the parent of the device sensor-th-0055 via a join, enter the following query:
Sql Copy
For those familiar with the SQL JOIN, the syntax used here will look different from what you might be used
to. Notice that the name of the relationship rel_has_devices is specified, rather than correlating this JOIN
with a key value in a WHERE clause or specifying a key value inline with the JOIN definition. This correlation
is computed automatically, as the relationship properties themselves identify the target entity. Here is the
relationship definition:
Code Copy
{
"@type": "Relationship",
"@id": "dtmi:com:contoso:digital_factory:cheese_cave:rel_has_devices;1",
"name": "rel_has_devices",
"displayName": "Has devices",
"target": "dtmi:com:contoso:digital_factory:cheese_factory:cheese_cave_device;1"
}
A key limitation of the ADT Explorer is is that it is designed to render a graph and the primary display cannot
show the results for queries that return just properties. In this task, you will learn how it is possible to see the
results of such queries without resorting to coding solutions.
1. To run a valid query that returns just a property, enter the following query and click Run Query:
Sql Copy
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 13/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
Despite the fact that the query will run without error, no graph is displayed. However, there is a way to view
the results in ADT Explorer, and you will open the Output pane to view the query results in the next task.
2. To open the Output pane, click the Settings icon at the top-right of the page.
3. On the dialog that appears, under View, enable Output, and then close the dialog.
4. Rerun the query above and review the contents of the Output pane.
The OUTPUT pane should display the Requested query, and then show the returned JSON. The JSON
should be similar to the following:
Code Copy
{
"queryCharge": 20.259999999999998,
"connection": "close",
"content-encoding": "gzip",
"content-type": "application/json; charset=utf-8",
"date": "Thu, 25 Mar 2021 21:34:40 GMT",
"strict-transport-security": "max-age=2592000",
"traceresponse": "00-182f5e54efb95c4b8b3e2a6aac15499f-9c5ffe6b8299584e-01",
"transfer-encoding": "chunked",
"vary": "Accept-Encoding",
"x-powered-by": "Express",
"value": [
{
"desiredTemperature": 50
}
],
"continuationToken": null
}
Along with additional result metadata, notice that the value property contains the selected
desiredTemperature property and value.
In the preceding exercises, the digital twin model and graph for the proof-of-concept were created. In order to
demonstrate how to route device message traffic from IoT Hub to ADT, it is useful to use a device simulator. In
this exercise, you will be configuring a simulated device app to send telemetry to your IoT Hub.
In this task, the Cheese Cave Device simulator app will be opened in Visual Studio Code in preparation for
configuration.
In Lab 3: Setup the Development Environment, you cloned the GitHub repository containing lab resources
by downloading a ZIP file and extracting the contents locally. The extracted folder structure includes the
following folder path:
Allfiles
Labs
Starter
CheeseCaveDevice
You should see the following files listed in the EXPLORER pane of Visual Studio Code:
CheeseCaveDevice.csproj
Program.cs
A cursory glance will reveal that this application is very similar to the simulated device applications that you
have worked on in the preceding labs. This version uses symmetric Key authentication, sends both
telemetry and logging messages to the IoT Hub, and has a more complex sensor implementation.
Notice the directory path indicated as part of the command prompt. You do not want to start building this
project within the folder structure of a previous lab project.
7. At the terminal command prompt, to verify the application builds, enter the following command:
Code Copy
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 14/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
dotnet build
Code Copy
Build succeeded.
0 Warning(s)
0 Error(s)
In the next task, you will configure the connection string and review the application.
The simulated device app that you will build in this task simulates an IoT device that monitors temperature and
humidity. The app will simulate sensor readings and communicate sensor data every two seconds and is the
same app that was built in Lab 15.
C# Copy
3. Replace the <your device connection string> with the device connection string that you saved near the
end of the lab setup exercise.
This is the only change that you need to implement before sending telemetry to the IoT Hub.
❕ NOTE: You saved both a Device and Service connection string. Be sure to provide the Device connection string.
In this task, the configured simulator app is launched and the the successful transmission of telemetry is verified.
1. In Visual Studio Code, ensure that you still have the Terminal open.
2. At the Terminal command prompt, to run the simulated device app, enter the following command:
Code Copy
dotnet run
This command will run the Program.cs file in the current folder.
❕ Note: Green text is used to indicate when things are working as they should be. Red text is used to indicate when
there is a problem. If you don’t get a screen similar to the image above, start by checking your device connection
string.
A key part of the proof-of-concept is to demonstrate how data from a device can be delivered to Azure Digital
Twins. Data can be ingested into Azure Digital Twins through external compute resources such as Virtual
Machines, Azure Functions, and Logic Apps. In this exercise, a function app will be invoked by an IoT Hub’s built-
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 15/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
in Event Grid. The function app receives the data and uses the Azure Digital Twins APIs to set properties on the
appropriate digital twin instance.
In order to configure an IoT Hub event grid endpoint to route telemetry to an Azure Function, it is necessary to
first create the Azure Function. In this task, an Azure Function App is created that provides the execution context
in which individual Azure Functions run.
In order to access Azure Digital Twins and it’s APIs, it is necessary to utilize a service principal with the
appropriate permissions. During this task, a service principal is created for the function app and then assigned
the appropriate permission. Once the function app has the appropriate permission, any Azure Functions that
execute within the function app context will use that service principal and will therefore have permission to
access ADT.
The function app context also provides an environment for managing app settings for one or more functions.
This capability will be used to define a setting that contains the ADT connection string which can then be read by
the Azure Functions. Encapsulating connection strings and other configurations values in app settings is
considered a much better practice than hard-coding the values in the function code.
1. Open the browser window containing your Azure portal, and then open the Azure Cloud Shell.
2. At the Cloud Shell command prompt, to create an Azure Function App, enter the following command:
Code Copy
The Azure function requires that a bearer token to be passed to it in order to authenticate with Azure
Digital Twins. To make sure that this token is passed, you’ll need to create a managed identity for the
function app.
3. To create (assign) the system-managed identity for the function app and display the associated principal Id,
enter the following command:
Code Copy
Code Copy
1179da2d-cc37-48bb-84b3-544cbb02d194
This is the principal ID that was assigned to the function app - you will need the principal ID in the next
step.
4. To assign the Azure Digital Twins Data Owner role to the Function App principal, enter the following
command:
Code Copy
❕ Note: Remember to replace the {your-id} and {principal-id} tokens above. The {principal-id} value was displayed as
the output of the previous step.
Now that the principal has been assigned to the Azure Function App, that principal must be assigned the
Azure Digital Twins Data Owner role so that is can access the Azure Digital Twins instance.
5. In order to supply the Azure Digital Twin instance URL to the Azure Function App as an environment
variable, enter the following command:
Code Copy
❕ Note: Remember to replace the {your-id} and {adt-url} tokens above. The {adt-url} value was saved to the adt-
connection.txt file in an earlier task and will be similar to
https://adt-az220-training-dm030821.api.eus.digitaltwins.azure.net .
Once complete, the command lists all of the available settings. The Azure Function will now be able to
obtain the ADT service URL by reading the ADT_SERVICE_URL value.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 16/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
Task 2 - Review Contoso.AdtFunctions Project
In this task you will review the Azure Function that will be executed whenever an event occurs on the associated
Event Grid. The event will be processed and the message and telemetry will be routed to ADT.
Final
Contoso.AdtFunctions
Code Copy
* The **Azure.DigitalTwins.Core** package contains the SDK for the Azure Digital Twins service.
This library provides access to the Azure Digital Twins service for managing twins, models,
relationships, etc.
* The **Microsoft.Azure.WebJobs.Extensions.EventGrid** package provides functionality for
receiving Event Grid webhook calls in Azure Functions, allowing you to easily write functions
that respond to any event published to Event Grid.
* The **Microsoft.Azure.WebJobs.Extensions.EventHubs** package provides functionality for
receiving Event Hub webhook calls in Azure Functions, allowing you to easily write functions that
respond to any event published to Event Hub.
* The **Microsoft.NET.Sdk.Functions** packages includes a build task for building .NET function
projects.
* The **Azure.identity** package contains the implementation of the Azure SDK Client Library for
Azure Identity. The Azure Identity library provides Azure Active Directory token authentication
support across the Azure SDK. It provides a set of TokenCredential implementations which can be
used to construct Azure SDK clients which support AAD token authentication
* The **System.Net.Http** package provides a programming interface for modern HTTP applications,
including HTTP client components that allow applications to consume web services over HTTP and
HTTP components that can be used by both clients and servers for parsing HTTP headers.
2. To review the member variables for the function, locate the // INSERT member variables below here
comment and review the code below it:
C# Copy
Notice that the adtInstanceUrl variable is assigned the value of the ADT_SERVICE_URL environment
variable defined earlier in the exercise. The code also follows a best practice of using a single, static,
instance of the HttpClient.
C# Copy
[FunctionName("HubToAdtFunction")]
public async static Task Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
Notice the use of the FunctionName attribute to mark the Run method as the entry point Run for
HubToAdtFunction. The method is also declared async as the code to update the Azure Digital Twin runs
asynchronously.
The eventGridEvent parameter is assigned the Event Grid event that triggered the function call and the
log parameter provides access to a logger that can be used for debugging.
❕ TIP: To learn more about the Azure Event Grid trigger for Azure Functions,
Azure Event Grid trigger for Azure
review the resource below:
Functions
C# Copy
log.LogInformation(eventGridEvent.Data.ToString());
The ILogger interface is defined in the Microsoft.Extensions.Logging namespace and aggregates most
logging patterns to a single method call. In this case, a log entry is created at the Information level - other
methods exists for various levels including critical, error. etc. As the Azure Function is running in the cloud,
logging is essential during development and production.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 17/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
5. Locate the following code to understand how the adtInstanceUrl variable value is checked:
C# Copy
if (adtInstanceUrl == null)
{
log.LogError("Application setting \"ADT_SERVICE_URL\" not set");
return;
}
This code checks if the adtInstanceUrl variable has been set - if not, the error is logged and the function
exits. This demonstrates the value of logging to capture the fact that the function has been incorrectly
configured.
C# Copy
try
{
// ... main body of code
}
catch (Exception e)
{
log.LogError(e.Message);
}
7. To see how the function app principal is used to authenticate to ADT and create a client instance, locate the
// REVIEW authentication code below here comment and review the following code:
C# Copy
Notice the use of the ManagedIdentityCredential class. This class attempts authentication using the
managed identity that has been assigned to the deployment environment earlier. Once the credential is
returned, it is used to construct an instance of the DigitalTwinsClient. The client contains methods to
retrieve and update digital twin information, like models, components, properties and relationships.
8. To review the code that starts to process the Event Grid event, locate the
// REVIEW event processing code below here comment and review the following code below it:
C# Copy
Notice the use of JSON deserialization to access the event data. The event data JSON will be similar to:
Code Copy
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 18/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
{
"properties": {
"sensorID": "S1",
"fanAlert": "false",
"temperatureAlert": "true",
"humidityAlert": "true"
},
"systemProperties": {
"iothub-connection-device-id": "sensor-th-0055",
"iothub-connection-auth-method": "
{\"scope\":\"device\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}"
"iothub-connection-auth-generation-id": "637508617957275763",
"iothub-enqueuedtime": "2021-03-11T03:27:21.866Z",
"iothub-message-source": "Telemetry"
},
"body": "eyJ0ZW1wZXJhdHVyZSI6OTMuOTEsImh1bWlkaXR5Ijo5OC4wMn0="
}
The message properties and systemProperties are easily accessible using an indexer approach, however
where properties are optional, such as temperatureAlert and humidityAlert, the use of SelectToken and
a null-coalescing operation is required to prevent an exception being thrown.
The message body contains the telemetry payload and is ASCII encoded JSON. Therefore, it must first be
decoded and then deserialized before the telemetry properties can be accessed.
❕ TIP: To learn more about the event schema, review the following resource:
Event schema
9. To inspect the code that updates the ADT twin, locate the // REVIEW ADT update code below here comment
and review the following code below it:
C# Copy
//Update twin
var patch = new Azure.JsonPatchDocument();
patch.AppendReplace<bool>("/fanAlert", fanAlert); // already a bool
patch.AppendReplace<bool>("/temperatureAlert", temperatureAlert.Value<bool>()); // convert
the JToken value to bool
patch.AppendReplace<bool>("/humidityAlert", humidityAlert.Value<bool>()); // convert the
JToken value to bool
// publish telemetry
await client.PublishTelemetryAsync(deviceId, null, bodyJson);
There are two approaches being used to apply data to the digital twin - the first via property updates using
a JSON patch, the second via the publishing of telemetry data.
The ADT client utilizes a JSON Patch document to add or update digital twin properties. The JSON Patch
defines a JSON document structure for expressing a sequence of operations to apply to a JSON document.
The various values are added to the patch as append or replace operations, and the ADT is then updated
asynchronously.
❕ TIP: To learn more about a JSON Patch document, review the following
Javascript Object Notation (JSON)
resources:
Patch
What is JSON Patch?
JsonPatchDocument Class
❕ IMPORTANT: The digital twin instance must have existing values before the AppendReplace operation is used.
Notice that the telemetry data is handled differently than the properties - rather than being used to set
digital twin properties, it is instead being published as telemetry events. This mechanism ensures that the
telemetry is available to be consumed by any downstream subscribers to the digital twins event route.
❕ NOTE: The digital twins event route must be defined before publishing a telemetry message, otherwise the message
will not be routed for consumption.
1. In the Azure Functions extension for Visual Studio Code, select Deploy to Function App:
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 19/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
The function will then be compiled and, if successful, deployed. This may take a few moments.
3. Once the deployment has completed, the following prompt will be displayed:
Click Stream logs and in the confirmation dialog to enable application logging, click Yes.
The OUTPUT pane will now display the log stream for the deployed function - this will timeout after 2
hours. There will be some status information displayed, however there will not be any diagnostic
information from the function itself until it is launched. That will be covered in the next exercise.
The streaming can be stopped or started at any time by right-clicking the Azure function in Visual Studio
Code and select Start Streaming Logs or Stop Streaming Logs:
In this exercise, the IoT Hub created by the setup script will be configured to publish events as they occur to the
Azure Function created in the previous exercise. The telemetry from the device simulator created earlier will then
be routed to the ADT instance.
5. In the EVENT SUBSCRIPTION DETAILS section, in the Name field, enter device-telemetry.
6. In the Event Grid Schema dropdown, ensure Event Grid Schema is selected.
7. In the TOPIC DETAILS section, verify that the Topic Type is set to IoT Hub and the Source Resource is set
to iot-az220-training-{your-id}.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 20/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
9. In the EVENT TYPES section, in the Filter to Event Types dropdown, select only Device Telemetry.
10. In the ENDPOINT DETAILS section, in the Endpoint Type dropdown, select Azure Function.
12. In the Select Azure Function pane, under Subscription, ensure the correct subscription is selected.
On the Create Event Subscription pane, in the ENDPOINT DETAILS section, the Endpoint field should
now display HubToAdtFunction.
After the subscription has been created, you should see messages in the Azure Functions log stream that
you configured in the preceding exercise. The Azure Functions log stream shows the telemetry being
received from Event Grid. It also shows any errors that occur when connecting to Azure Digital Twins or
updating the twin.
The log output for a successful function call will be similar to:
Code Copy
"iothub-connection-auth-generation-id": "637508617957275763",
"iothub-enqueuedtime": "2021-03-12T19:14:16.824Z",
"iothub-message-source": "Telemetry"
},
"body": "eyJ0ZW1wZXJhdHVyZSI6NjkuNDcsImh1bWlkaXR5Ijo5Ny44OX0="
}
2021-03-12T19:14:17.181 [Information] Azure digital twins service client connection created.
2021-03-12T19:14:17.181 [Information] Device:sensor-th-0055 fanAlert is:False
2021-03-12T19:14:17.181 [Information] Device:sensor-th-0055 temperatureAlert is:true
2021-03-12T19:14:17.181 [Information] Device:sensor-th-0055 humidityAlert is:true
2021-03-12T19:14:17.181 [Information] Device:sensor-th-0055 Temperature is:69.47
2021-03-12T19:14:17.181 [Information] Device:sensor-th-0055 Humidity is:97.89
2021-03-12T19:14:17.182 [Information] Executed 'HubToAdtFunction' (Succeeded, Id=88d9f9e8-
5cfa-4a20-a4cb-36e07a78acd6, Duration=2ms)
Code Copy
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 21/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
"iothub-connection-auth-generation-id": "637508617957275763",
"iothub-enqueuedtime": "2021-03-11T16:35:43.279Z",
"iothub-message-source": "Telemetry"
},
"body": "eyJ0ZW1wZXJhdHVyZSI6NjkuNzMsImh1bWlkaXR5Ijo5OC4wOH0="
}
2021-03-11T16:35:43.646 [Information] Azure digital twins service client connection created.
2021-03-11T16:35:43.647 [Information] Device:sensor-th-0055 fanAlert is:False
2021-03-11T16:35:43.647 [Information] Device:sensor-th-0055 temperatureAlert is:true
2021-03-11T16:35:43.647 [Information] Device:sensor-th-0055 humidityAlert is:true
2021-03-11T16:35:43.647 [Information] Device:sensor-th-0055 Temperature is:69.73
2021-03-11T16:35:43.647 [Information] Device:sensor-th-0055 Humidity is:98.08
2021-03-11T16:35:43.648 [Information] Executed 'HubToAdtFunction' (Succeeded, Id=9f7a3611-
0795-4da7-ac8c-0b380310f4db, Duration=2ms)
2021-03-11T16:35:43.728 [Error] Service request failed.
Status: 404 (Not Found)
Content:
{"error":{"code":"DigitalTwinNotFound","message":"There is no digital twin instance that
exists with the ID sensor-th-0055. Please verify that the twin id is valid and ensure that
the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query."}}
Headers:
Strict-Transport-Security: REDACTED
traceresponse: REDACTED
Date: Thu, 11 Mar 2021 16:35:43 GMT
Content-Length: 267
Content-Type: application/json; charset=utf-8
20. Return to the ADT Explorer instance in the browser and query the graph.
You should be able to see that the fanAlert, temperatureAlert and humidityAlert properties have been
updated.
At this point, the data ingestion from device (in this case a device simulator) into ADT has been demonstrated.
The next exercise will demonstrate how telemetry can be streamed to Time Series Insights (TSI).
In this exercise, you will complete the final part of the proof-of-concept - streaming the device telemetry sent
from the Cheese Cave Device sensor-th-0055 via the simulator, through Azure Digital Twins to Time Series
Insights.
❕ NOTE: The setup script for this lab created the Azure Storage Account, Time Series Insights Environment and Access Policy
that will be used during this exercise.
Routing event data from ADT to TSI is achieved by the following basic flow:
In order to implement this flow, the following resources must be created (in addition to ADT and TSI):
An Azure Function
An Event Hub Namespace
Two Event Hubs - one for events from ADT to the Azure Function, another for events from the Azurre
Function for TSI.
Map device specific telemetry message formats (property names, data types, etc.) to a single format for TSI.
This can provide a consolidated view across different devices as well as insulate the TSI solution from
changes to other parts of the solution.
Enrich the messages from other sources
Add a field to each event for use as the Time Series ID Property within TSI.
An Event Hubs namespace provides DNS integrated network endpoints and a range of access control and
network integration management features such as IP filtering, virtual network service endpoint, and Private Link
and is the management container for one of multiple Event Hub instances (or topics, in Kafka parlance). The two
Event Hubs required for this solution will be created within this namespace.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 22/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
3. In the Search textbox, type Event Hubs and then click the Event Hubs search result.
5. On the Create Namespace blade, in the Subscription dropdown, ensure that the Azure subscription that
you are using for this course is selected.
6. To the right of Resource group, open the dropdown, and then click rg-az220
8. To the right of Location, open the drop-down list and select the same location that you selected for your
resource group.
9. To the right of Pricing tier, open the drop-down list and select Standard.
❕ TIP: In this exercise, the Basic tier would also work, however in most
Basic
production scenarios, Standard would be the better choice:
1 Consumer Group
100 Brokered Connections
Ingress events - $0.028 per
million (at time of writing)
Message retention - 1 day
Standard
20 Consumer Group
1000 Brokered Connections
Ingress events - $0.028 per
million (at time of writing)
Message retention - 1 day
Additional storage - up to 7
days
Publisher policies
Auto-Inflate automatically scales the number of Throughput Units assigned to your Standard Tier Event
Hubs Namespace when your traffic exceeds the capacity of the Throughput Units assigned to it. You can
specify a limit to which the Namespace will automatically scale.
12. To start the validation of the data entered, click Review + create.
This namespace will contain the event hub used to integrate the digital twin telemetry with an Azure function,
and an event hub that will take the output of the Azure function and integrate it with Time Series Insights.
This task will create an Event Hub that will subscribe to the twin telemetry events and pass them to an Azure
Function.
❕ Note: As the event hub is scoped within a globally unique namespace, the event hub name itself need not be globally
unique.
❕ TIP: Partitions are a data organization mechanism that relates to the downstream parallelism required in consuming
applications. The number of partitions in an event hub directly relates to the number of concurrent readers you expect
to have.
❕ TIP: This is the retention period for events. You can set the retention period between 1 and 7 days.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 23/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
❕ TIP: Azure Event Hubs Capture enables you to automatically deliver the streaming data in Event Hubs to an Azure Blob
storage or Azure Data Lake Store account of your choice, with the added flexibility of specifying a time or size interval.
Setting up Capture is fast, there are no administrative costs to run it, and it scales automatically with Event Hubs
throughput units. Event Hubs Capture is the easiest way to load streaming data into Azure, and enables you to focus
on data processing rather than on data capture.
After a moment, the Event Hub is created and Event Hubs namespace Overview is displayed. If necessary,
scroll to the bottom of the page and the evh-az220-adt2func Event Hub is listed.
Each Event Hubs namespace and each Event Hubs entity (an event hub instance or a Kafka topic) has a shared
access authorization policy made up of rules. The policy at the namespace level applies to all entities inside the
namespace, irrespective of their individual policy configuration. For each authorization policy rule, you decide on
three pieces of information: name, scope, and rights. The name is a unique name in that scope. The scope is the
URI of the resource in question. For an Event Hubs namespace, the scope is the fully qualified domain name
(FQDN), such as https://evhns-az220-training-{your-id}.servicebus.windows.net/ .
In this task, an authorization rule with Listen and Send permissions will be created.
2. In the left navigation area, under Settings, click Shared access policies.
An empty list of policies that are specific to his event hub is shown.
4. In the Add SAS Policy pane, under policy name, enter ADTHubPolicy.
7. To retrieve the primary connection string for the authorization rule, click ADTHubPolicy in the list.
8. Copy the Connection string-primary key value and add it to a new text file named telemetry-
function.txt.
Now that the Event Hub is created, it must be added as an endpoint that the ADT instance can use as an output
to send events.
6. In the Subscription dropdown, ensure that the Azure subscription that you intend to use for this course is
selected.
The pane closes and, after a moment, the endpoint list updates to include the new endpoint.
With the addition of the Event Hub endpoint to the ADT instance, it is now necessary to create a route that sends
twin telemetry events to this endpoint.
1. In the left navigation area, under Connect outputs, click Event routes.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 24/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
The advanced editor supports entering a specific filtering expression - for this task, the UI is sufficient.
The pane closes and, after a moment, the event route list updates to include the new route.
This time, the Event Hub and authorization rule will be created using the Azure CLI.
1. Return to the command prompt and verify the session is still logged in by entering:
Code Copy
az account list
2. To create the Event Hub between the Azure Function and TSI, enter the following command:
Code Copy
3. To create an authorization rule with listen and send permissions on the new Event Hub, enter the folowing
command:
Code Copy
4. To retrieve the primary connection string for the authorization rule, enter the following command:
Code Copy
Code Copy
Endpoint=sb://evhns-az220-training-
dm030821.servicebus.windows.net/;SharedAccessKeyName=TSIHubPolicy;SharedAccessKey=x4xItgUG6clhGR
az220-func2tsi
5. Copy the Connection string-primary key value and add it to the text file named telemetry-function.txt.
Task 7 - Add the Endpoint addresses as app settings for Azure Function
In order for an Azure Function to connect to an Event Hub, it must have access to the connection string for a
policy with the appropriate rights. In this scenario, two Event Hubs are involved - the hub that publishes the
event from ADT and the hub that publishes the data transformed by the Azure Function to TSI.
1. To supply the Event Hub authorization rule connections strings as environments variable, in the Azure
portal, navigate to the func-az220-hub2adt-training-{your-id} instance.
3. On the Configuration page, on the Application settings tab, review the current Application settings that
are listed.
The ADT_SERVICE_URL that was added earlier via the CLI should be listed.
4. To add an environment variable for the adt2func rule connection string, click + New application setting.
5. On the Add/Edit application setting pane, in the Name field, enter ADT_HUB_CONNECTIONSTRING
6. In the Value field, enter the authorization rule connection string value that was saved to the telemetry-
function.txt file in an earlier task and ends with EntityPath=evh-az220-adt2func .
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 25/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
Mg3Z/vjI2z9yBb9MRDGc=;EntityPath=evh-az220-adt2func
8. To add an environment variable for the func2tsi rule connection string, click + New application setting.
9. On the Add/Edit application setting pane, in the Name field, enter TSI_HUB_CONNECTIONSTRING
10. In the Value field, enter the authorization rule connection string value that was saved to the telemetry-
function.txt file in an earlier task and ends with EntityPath=evh-az220-func2tsi .
dm030821.servicebus.windows.net/;SharedAccessKeyName=TSIHubPolicy;SharedAccessKey=x4xItgUG6clhGR9pZe/U6Jq
rNV+drIfu1rlvYHEdk9I=;EntityPath=evh-az220-func2tsi
12. To save the both of the new settings, click Save and click Continue.
❕ NOTE: Any change to the application settings will restart the functions.
In this task, the second Azure function will be reviewed. This function will be responsible for mapping the device
telemetry messages to an alternate format for TSI. This approach has the advantage of being able to handle
changes to the device telemetry format without changing the TSI solution.
C# Copy
// Once processing of the batch is complete, if any messages in the batch failed
processing throw an exception so that there is a record of the failure.
if (exceptions.Count > 1)
throw new AggregateException(exceptions);
if (exceptions.Count == 1)
throw exceptions.Single();
}
}
Take a moment to look at the Run method definition. The events parameter makes use of the
EventHubTrigger attribute - the attribute’s constructor takes the name of the event hub, the optional
name of the consumer group ($Default is used if omitted), and the name of an app setting that contains
the connection string. This configures the function trigger to respond to an event sent to an event hub
event stream. As events is defined as an array of EventData, it can be populated with a batch of events.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 26/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
❕ TIP To learn more about the EventHubTrigger, review the following resource: Azure Event Hubs trigger for Azure
Functions
The next parameter, outputEvents has the EventHub attribute - the attribute’s constructor takes the name
of the event hub and the name of an app setting that contains the connection string. Adding data to the
outputEvents variable will publish it to the associated Event Hub.
As this function is processing a batch of events, a way to handle errors is to create a collection to hold
exceptions. The function will then iterate through each event in the batch, catching exceptions and adding
them to the collection. Skip[ to the end of the method, and you will see that if there are multiple
exceptions, an AggregaeException is created with the collection, if a single exception is generated, then
the single exception is thrown.
4. To review the code that checks to see if the event contains Cheese Cave Device telemetry, locate the
// REVIEW check telemetry below here comment and review the following code below it:
C# Copy
This code checks that the current event is telemetry from a Cheese Cave Device ADT twin - if not, logs that
it isn’t and then forces the method to complete asynchronously - this can make better use of resources.
❕ TIP: To learn more about the use of await Task.Yield(); review the following resource:
Task.Yield Method
5. To review the code that processes the event and creates a message for TSI, locate the
// REVIEW TSI Event creation below here comment and review the following code below it:
C# Copy
await outputEvents.AddAsync(tsiUpdateMessage);
As the eventData.Body is defined as an ArraySegment, rather than just an array, the portion of the
underlying array that contains the messageBody must be extracted, and then deserialized.
A Dictionary is then instantiated to hold the key/value pairs that will make up the properties sent within
the TSI event. Notice that the cloudEvents:source property (which contains the fully qualified twin ID -
similar to adt-az220-training-dm030821.api.eus.digitaltwins.azure.net/digitaltwins/sensor-th-0055 ) is
assigned to the $dtId key. This key has special meaning as the Time Series Insights environment created
during setup is using $dtId as the Time Series ID Property.
The temperature and humidity values are extracted from the message and added to the TSI update.
The update is then serialized to JSON and added to the outputEvents which publishes the update to the
Event Hub.
1. In the Azure Functions extension for Visual Studio Code, select Deploy to Function App:
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 27/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
Select subscription: If prompted, select the subscription you are using for this course.
Select Function App in Azure: Select func-az220-hub2adt-training-{your-id}.
The function will then be compiled and, if successful, deployed. This may take a few moments.
3. Once the deployment has completed, the following prompt will be displayed:
Click Stream logs and in the confirmation dialog to enable application logging, click Yes.
The OUTPUT pane will now display the log stream for the deployed function - this will timeout after 2
hours. There will be some status information displayed, however there will not be any diagnostic
information from the function itself until it is launched. That will be covered in the next exercise.
The streaming can be stopped or started at any time by right-clicking the Azure function in Visual Studio
Code and select Start Streaming Logs or Stop Streaming Logs:
1. In a browser, connect to the Azure Portal and locate the tsi-az220-training-{your-id} resource.
❕ NOTE: This resource was created by the setup script. If you have not run it, do so now - the script will not impact
existing resources.
2. On the Overview pane, in the Essentials section, locate the Time Series ID Property field and the value -
$dtid. This value was specified during the creation of the TSI environment and should match with a field in
the event data being streamed to TSI.
❕ IMPORTANT: The Time Series ID Property value is specified during the creation of the TSI environment and cannot
be changed later.
The list of Event Sources will be displayed - at this point, it should be empty.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 28/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
5. On the New event source pane, under Event source name, enter adt-telemetry
7. Under Import option, select Use Event Hub from available subscriptions.
8. Under Subscription ID, select the subscription being used for this course.
Notice that the read-only field Event Hub policy key is automatically populated.
❕ TIP: As there is only one event reader for the evh-az220-func2tsi Event Hub, using the $Default consumer group is
fine. If more readers were to be added, then it is recommended that one consumer group per reader is used.
Consumer groups are created on the Event Hub.
Notice there are other options available, such as Beginning now (default), that may be more suitable for
a production environment.
14. Under Event serialization format, notice that the read-only value is JSON.
❕ TIP: This specifies the name of the event property that should be used as the event timestamp. When not specified,
the event enqueue time within the event source will be used as the event timestamp.
Now, data should be flowing into your Time Series Insights instance, ready to be analyzed. Follow the steps
below to explore the data coming in.
3. In the explorer, you will see Azure Digital Twins shown on the left.
4. To add telemetry to the graph, click the twin and select EventCount, humidity and temperature.
Select an appropriate time range, and the displayed data will be similar to:
By default, digital twins are stored as a flat hierarchy in Time Series Insights, however they can be enriched with
model information and a multi-level hierarchy for organization. You can write custom logic to automatically
provide this information using the model and graph data already stored in Azure Digital Twins.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 29/30
2/8/22, 4:05 PM AZ-220-Microsoft-Azure-IoT-Developer
Congratulations - you are now passing device telemtry data to Time Series Insights.
https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/Instructions/Labs/LAB_AK_19-azure-digital-twins.html 30/30