Using Azure Logic apps as business rules for Azure Digital Twins

Although this feature just went into Public Preview, the new Azure Digital Twins connector for Microsoft Power Platform is very promising:

Azure Digital Twins (ADT) connector for Microsoft Power Platform enables you to incorporate Azure Digital Twins into Microsoft Power Automate flows, Power Apps applications, or Azure Logic Apps flows. 

With this connector, you can combine Azure Digital Twins with 700+ other Power Platform connectors to build flows or apps by ingesting data, coming from other systems, into the Azure Digital Twins environment.

You can do graph traversal:

Or, you can send data to Azure Digital Twins (twin update) as seen here:

It’s even possible to develop a flow that creates a digital twin, deriving from a model when an external system emits an event.

Let’s check out what this Azure Logic Apps connector offers for Azure Digital Twins.

Although this connector also serves the power platform, today we check out the support for Azure Logic Apps.

Azure Digital Twins environment

It all starts with having a working Azure Digital Twins environment.

I created one and loaded some twin models:

Note: Loading twin models into the environment is also a feature of this new connector.

With my personal account, I have ‘Azure Digital Twins Data Owner’ access rights so I can both manipulate the environment and I can work with twin data:

Notice, if you only want to read data from the ADT environment, read-only access should be enough:

Why is it important to check access rights?

The Logic App connector needs AAD access and uses an account to access the ADT environment, as we will see in a moment.

Azure Logic App actions for Azure Digital Twins

At this moment, there are twenty actions to choose from:

Pick one of them and start interacting with the Azure Digital Twins APIs.

It’s very powerful. As said before, you can manipulate models, query the graph, and manipulate twins. It even knows about the twin components feature.

You need to know how that ADT Rest API works in detail because not everything is made available as action properties using the connector actions. Sometimes you have to construct an API request body. Or, you need to check the response JSON.

For a more detailed action explanation, go to the Azure Digital Twins connector documentation. The most important actions are shown in detail below!

Notice, there are no triggers:

So, if you want to react to Azure Digital Twins events like twin updates or telemetry, you need to add an EventGrid, ServiceBus, or EventHub between the ADT environment and the logic app and used the accompanying event trigger.

These are the events the ADT environment exposes to resources like Logic Apps:

Note: these events are out of the scope of this blog post.

Let’s connect our logic app to the ADT environment.

Azure Digital Twins connector

Before you can make use of any action, you need to set up a connection between Logic Apps and Azure Digital Twins. This is a one-time step, seen as a dialog, part of the Logic App editor.

That connection dialog shows up when you add your first ADT connector action.

Now, one of the actions of the ADT Connector is selected:

You need to provide the instance URI of the Azure Digital Twins environment.

You can either find it on the overview page of the environment (called Host name) or in the ADT explorer as URL:

Note: here, ‘https://’ is added to the hostname.

It is advertised that both notations should work. My personal favorite is the hostname.

When saving this, you need to log in with the account having ‘Azure Digital Twins Data Owner access’ rights.

Once this is done, notice an API connection is added:

This connection is used for all related actions.

Some Sample interaction

Now we have a working connection, let’s have some fun with ADT. Let’s trigger some actions and see what is happening.

Adding a Twin

To add a twin seems somewhat easy. You need to add the name of the new twin and you must have composed the request for the API call:

Composing the JSON message is less straightforward. This is where extended knowledge about the API is needed.

Here, I just provide the ID of the model:

  "$metadata": {
    "$model": "dtmi:com:adt:flightintoint:airliner;5"

After execution, I get this response:

  "$dtId" : "TestAirliner",
  "$etag" : "W/\"2b50d72a-6745-4e5f-bb9b-96c50ff6f8de\"",
  "$metadata": {

The twin is added:

Notice the properties are still empty. This is correct, I did not provide them yet.

I could add them later on or I can add the properties together with the twin in one go:

  "$metadata": {
    "$model": "dtmi:com:adt:flightintoint:airliner;5"
  "abbreviation": "FI",
  "companyName": "iotedger",

Here the other twin is shown too, including the properties:

So, it helps if you know how to fill in the request body JSON format of the API call.

Check the related API documentation for more details.

Note: It’s not documented how to handle possible exceptions or even throttling. This is something we need to find out in the near future.

Adding a relationship

Relationships between twins are one of the most important features of an Azure Digital Twins graph. Without relationships, the value of ADT would be minimal…

We can try adding a relationship between an airliner and an airplane (a second type of twin I created already).

The call seems pretty straightforward:

Note: We get a wide range of return values to choose from.

We need to provide the name of the airliner we reference and the name of the relationship which we are adding.

In the JSON body of the request, the related (child) airplane and kind of relation are added:

  "$targetId": "DutchFI",
  "$relationshipName": "rel_has_airplanes"

The relationship is added once the action is executed:

So, we are in control of the whole graph: twins and relations.

Check the related API documentation for more details.

Get twin by id

Another useful action is looking up a twin using its unique ID:

You need to specify the twin id only. Easy.

The result of this action is this JSON response:

  "$dtId" : "FlyIoT",
  "$etag" : "W/\"b2fe97e7-b147-419f-92e6-a9cacbd6c9ff\"",
  "abbreviation" : "FI",
  "companyName" : "iotedger",
  "$metadata" : {
    "$model" : "dtmi:com:adt:flightintoint:airliner;5",
    "abbreviation" : {
      "lastUpdateTime" : "2023-03-11T13:39:03.7316544Z"
    "companyName" : {
      "lastUpdateTime" : "2023-03-11T13:39:03.7316544Z"

As you see, the full twin model representation is put in this JSON. You need to parse it within the logic app to get to the properties.

Check the related API documentation for more details.

Query the twin graph, traverse through the graph

So, it’s quite simple to find a twin if you know the name.

If you do not know the exact ID, you need to traverse the graph.

Note: It’s ok to traverse the full graph when executing a business rule but keep twin changes limited to only a few layers: the parent, the twin itself, or a child. From there subsequent rules pick up changes and make further modifications through the graph until changes fade out. This keeps the rules understandable and maintainable.

Here, we execute a query to find the parent of a certain child, using the relationship between them:

In this case, we search for the parent airliner of a child airplane:

SELECT parent FROM DIGITALTWINS parent JOIN child RELATED parent.rel_has_airplanes WHERE child.$dtId = 'DutchFI' 

Note: the cardinality of one parent with multiple children is something we have in our minds. The ADT environment is unaware of these restrictions. a child can have multiple parents in ADT.

The response is an array with only one element, the parent airliner:

    "parent": {
      "$dtId": "FlyIoT",
      "$etag": "W/\"b2fe97e7-b147-419f-92e6-a9cacbd6c9ff\"",
      "abbreviation": "FI",
      "companyName": "iotedger",
      "$metadata": {
        "$model": "dtmi:com:adt:flightintoint:airliner;5",
        "abbreviation": {
          "lastUpdateTime": "2023-03-11T13:39:03.7316544Z"
        "companyName": {
          "lastUpdateTime": "2023-03-11T13:39:03.7316544Z"

More detailed queries are explained here in the documentation.

Next to twins, you can also query for certain twin properties.

Here the abbreviation property of the parent airliner is queried:

This is the query we send:

SELECT parent.abbreviation FROM DIGITALTWINS parent JOIN child RELATED parent.rel_has_airplanes WHERE child.$dtId = 'DutchFI'

The requested properties are returned as an array:

    "abbreviation": "FI"

This gives you all the tools for graph traversal.

Check the related API documentation for more details.

Update a twin

We can also update twin properties.

Here is an example of engine data sent to an Engine twin (the twin was created already).

We send a list of patches for multiple twin properties:

    "op": "add",
    "path": "/counter",
    "value": 4242
    "op": "add",
    "path": "/enginePressureRatio",
    "value": 300
    "op": "add",
    "path": "/engineTemp",
    "value": 150
    "op": "add",
    "path": "/fuelFlow",
    "value": 2000
    "op": "add",
    "path": "/fuelOnBoard",
    "value": 19000
    "op": "add",
    "path": "/oilPressure",
    "value": 1000
    "op": "add",
    "path": "/oilTemperature",
    "value": 350
    "op": "add",
    "path": "/rotations",
    "value": 15000

This action only expects the ID of the twin and that array of patches as JSON:

Once executed, the response is a 204 status-code so the execution succeeded:

The Engine twin is updated:

If an EventHub is connected, listening for routed twin changes, we see these lines arriving in the hub:

Check the related API documentation for more details.

Send telemetry to twin

We can also send telemetry to twins.

Note: The twins themselves will not be affected by related telemetry messages but the related ADT route will output those messages.

Here is how we send telemetry using a Logic App action:

Next to the ID of the twin, a unique ID of the telemetry message and a timestamp can be provided.

Note: that ID is used by the ADT environment to prevent handling the same message twice.

The telemetry itself is sent as a JSON message.

Here, the message has been picked up by the ADT environment:

If we check an attached Event Hub, only the JSON telemetry part of the request seems to be passed on to the Event Hub:

Again, check the related API documentation for more details.


Let’s talk a little about costs when building a rule engine based on Logic Apps.

Building rules using the visual designer of Logic apps is very interesting because it offers a lot of benefits.

One of them is that you keep a good sense of what is happening within a rule even when it becomes a very large flow diagram. And you can still change them, opposite to rules captured in code like Azure Functions.

On the other hand, it’s smart to check out which cost models are offered for Logic Apps and how costs are calculated.

You will see that you can choose the standard plan (single-tenant) or consumption plan (multi-tenant).

The key is the number of trigger and action executions.

It depends on your use case and the number of (expected) executions to see how cost-effective your new rule engine is.

You can always start cheap, using the consumption plan, and migrate later on when it gets more interesting to move over to the standard plan.

Note: Microsoft offered a free plan for Logic Apps: 4,000 built-in actions with a Consumption plan per month.

Check the Azure calculator for more details:

The choice you make can also have an impact on your development tools:


You have seen how the Logic apps connector for Azure Data Explorer offers you full control over the Azure Digital Twins environment, showing the current situation in the environment.

Above, multiple times you have seen you need to construct JSON messages as equivalent to the body messages in the requests.

These actions are basically wrappers around (part of) the ADT Rest API data pane:

Note: Perhaps the other API calls will be supported in the future too.

Despite the knowledge investment, it’s an interesting way to interact with your Azure Digital Twins environment, next to plain Azure Functions,

The fact it now simplifies the workflow of your rules due to the use of a visual designer is a big plus!

At this moment, I personally do not know the impact of the costs though. Maintenance should be cheaper though compared to hard-coded solutions.

In all cases where rules are executed, introducing an Azure Stream Analytics job can offer additional flexibility due to the aggregation and enrichment of incoming data. Making use of time windowing and filtering can limit the number of executions without impacting usability.

This is the second connector in a short time, I am blogging about. The previous one was about Azure Data Explorer.

Because Azure Data Explorer can be used to store historical twin changes, you can now combine both the current situation and historical information as data sources for your business rules.

The rules themselves can get a quality check when you also store the historical raw Azure IoT Hub telemetry output too.

So, you can go full circle with all logic.

Also, Check out this IoT Show presentation:

The connector is still in preview so share your findings with the product team.

This post is part four of a series of posts about Azure Digital Twins:

  1. Extending the AZ-220 Digital Twins hands-on lab with 3D visualization
  2. ADX Kusto plug-in for Azure Digital Twins history
  3. Exploring Azure Digital Twins Graph history
  4. Using Azure Logic apps as business rules for Azure Digital Twins


3 gedachten over “Using Azure Logic apps as business rules for Azure Digital Twins

Geef een reactie

Vul je gegevens in of klik op een icoon om in te loggen. logo

Je reageert onder je account. Log uit /  Bijwerken )


Je reageert onder je Twitter account. Log uit /  Bijwerken )

Facebook foto

Je reageert onder je Facebook account. Log uit /  Bijwerken )

Verbinden met %s