Using OPC-Twin for OPC-UA discovery and sending back commands

In the past, I have written multiple blogs about implementing OPC-UA on IoT Edge.

Until now I have written about collecting OPC-UA values and sending them to the cloud using the OPC Publisher.

But this OPC Publisher is actually just a small part of what Microsoft is actually offering regarding OPC-UA.

Microsoft has a team in both Redmond (USA) and Munich (Germany) working on Industrial IoT. Everything they produce is open source. You can find thier work on github.

With the OPC Twin, they also make it possible to discover, register and manage your Industrial Assets with Azure IoT and most of it can be done zero-touch.

Look at this diagram covering OPC-AU on Azure:


To the left, we see a OPC-UA server and an IoT Edge gateway. It is ‘living’ on the factory network. In the middle we see the Azure IoT Hub acting as cloud gateway and to the right, we see the OPC-UA backend which is provided by the IIoT team.

Of course, all of this is open source. And out of the box, a lot is already working.

OPC-UA, the full round trip

In this blog, I want to show how we can discover OPC-UA servers, update the OPC Publisher to read new nodes (exposed by the discovered servers) and I want to send commands back to the OPC-UA servers.

This is part four of a series of blogs about OPC-UA:

  1. Getting started with OPC-UA on Azure IoT Edge
  2. Managing nodes from the cloud in the OPC-UA Publisher Edge
  3. A new batch of OPCPublisher direct methods
  4. Using OPC-Twin for OPC-UA discovery and sending back commands

I focus in this blog on these six main parts:

The whole picture falls apart in these sections:

  • Our OPC-UA Server. This is the device (or application) which talks OPC-UA. It exposes nodes and commands, both for reading and writing data
  • The IoT Edge gateway onpremise, running two modules: the OPC Publisher (which acts like an OPC-UA Client) and the OPC Twin (for discovery and commands). Eventually, we will focus on the Twin
  • The IoT Hub. We just register our IoT Edge gateway and we are good
  • The OPC-UA back-end which is quite bulky. It runs microservices on a VM and uses storage for persisting stuff. This back-end can be controlled using a Rest API.
  • A simple webapplication which makes the OPC-UA backed accessible. We can see the OPC-UA servers discovered, read incoming node data and send commands.


The solution I show is a starting point for you. It helps you to discover what it needs to get started with the OPC Twin.

I expect you to have some expeience with the OPC Publisher already or read my blog about getting started with it.

Note: I do not implement regular security, just to simplify this demonstration. It is not recommended to do this in a production environment!

1. The OPC-UA Server

So we need an OPC-UA Server to serve data and commands. In my previous blog I used the Prosys OPC-UA Server Simulation. But I had some issues discovering this application so this time I used a real OPC-UA server device, this EKI.

The Advantech EKI-1242OUMS is a Modbus TCP/RTU to OPC-UA Fieldbus Gateway which can also send commands back to the connected Modbus devices:

It is able to support multiple slaves over Modbus TCP and Modbus RTU. It supports both RS232 and RS485. One interesting feature is the ability to separate the network with the Modbus devices from the network with the OPC-UA calls.

As a Modbus slave, I used my trusted Advantech Wise 4012E. It is designed as a developer kit (so it can be powered by the USB port of your laptop) but communicates just like any other Wise module:

So I configured my EKI with these settings for exposing the Wise module Modbus coils and registers and writing data (setting the two relays on the Wise):

From an OPC-UA standpoint, these nodes are exposed by the EKI:

You can see the exposed nodes and the namespace values of the nodes.

2. The OPC Publisher module deployment

Although the OPC Publisher is not the focus point of this blog, it is good to start with this module right now.

First, because we can check the OPC-UA server configuration.

Second, because the OPC Twin (commands) will not work without the OPC Publisher:

If no OPC Publisher module is deployed alongside OPC Twin module, OPC Twin publishing REST calls will fail.

You can now add the OPC Publisher to your IoT Edge manifest. Adding an OPC Publisher to your IoT Edge runtime on your Edge gateway can also be done using the IoT Edge Module Marketplace:

We deploy the OPC Publisher with these settings:


Image URI:

Container Creation Options:
  "Hostname": "publisher",
  "Cmd": [
  "HostConfig": {
    "PortBindings": {
      "62222/tcp": [
          "HostPort": "62222"
    "Binds": [

So the OPC Publisher expects a file named pn.json on /var/iiotedge (this is a Linux gateway). It lists all servers to read data from and the specific nodes:

    "EndpointUrl": "opc.tcp://",
    "UseSecurity": false,
    "OpcNodes": [
        "Id": "ns=1;i=61011"
        "Id": "ns=1;i=61012"
        "Id": "ns=1;i=61013"
        "Id": "ns=1;i=61014"
        "Id": "ns=1;i=61015"
        "Id": "ns=1;i=61016"

This administration reflects the settings of the OPC-UA server for the two knobs, the two switches and the two relays on the Wise 4012E module.


The IIoT Team has a tool available: The Azure Industrial IoT Gateway Installer.

With this tool, all resources on your gateway are installed by iether a UI app (Windows) or with a console app (Windows and Linux). You must have Visual Studio or Visual Studio Code available to compile and build the tool.

Note: I tested this tool on Windows. I had to install the Azure CLI first. In the end, I got some Hyper-V exception I was not able to cure. I hope you have more luck 😉

3. IoT Hub (part of the OPC-UA Back-end)

An IoT Edge gateway on the edge does not live without an IoT Hub in the cloud.

Does this mean we can just create one and start receiving data?


The Industrual IoT team has a bigger plan regarding the OPC-UA back-end in Azure and the IoT Hub is part of it.

So how do we get access to it?

The team has provided a script to create all OPC-UA resources in your Azure subscription at once in one resource group. Just run this powershell script (in elevated rights) (it will tun for 10+ minutes):

// Update: Please check for the most recent deployment procedure

// Deploy on Windows
cd c:\git // or another folder in which a subfolder can be created
git clone
cd Industrial-IoT

// Deploy on Linux
cd /var/git // or another folder in which a subfolder can be created
git clone
cd Industrial-IoT

// This older script is depricated
cd c:\git // or another folder in which a subfolder can be created
git clone
cd Industrial-IoT
cd services
cd deploy

You will be asked to provide an azure subscription and other information (eg. to come up with a unique name). A complete back-end will be deployed:

Note: automatically generated credentials for the created VM are shown after execution of the script. Save these credentials and store them somewhere safely if you want to login into the VM later on.

Note: I had some issues deploying this script due to insufficient (AAD) rights on our company subscription. Please contact your colleague with Global Administrator rights to get things done.

Once the script is completed, you are a proud owner of several new Azxure resources:

You will recognize the Virtual machine which runs the micro services. And you recognize the App service which provides the portal to see the soon to discover OPC-UA servers.

And you finally see the IoT Hub which you will use to setup the IoT Edge gateway.

We ignore all other resources and focus on the IoT Hub for now!

We already know how to configure the OPCPublisher. We also need to set the correct routing for the OPC Publisher:

  "routes": {
    "opcpublisherToUpstream": "FROM /messages/modules/opcpublisher/* INTO $upstream"

Note: The OPCPublisher has no specific output specificied so the route is using the special ‘catch all outputs’ notation.

Once the opcpublisher on the gateway is deployed, you will see the ingress of node values using Visual Studio Code:

Note: the OPC Publisher only passes data of nodes which are chancing. What we see here are values of the analog knobs which are fluctuating constantly. The switches are only sending data when these are flipped.

Note: A more elaborate description on how to deploy the OPCPublisher can be found here.

4. The OPC Twin module deployment

Although we have a full back-end running in our subscription, we now first focus on the OPC Twin module deployment.

This module will run side-by-side with the OPC Publisher and is responsible for both the discovery of OPC-UA servers and sending commands to the OPC-UA servers discovered.

You can deploy it using the marketplace or by hand:

We setup the module with these settings:


Image URI:

Container Create Options:
  "Hostname": "opctwin",
  "Cmd": [
  "NetworkingConfig": {
    "EndpointsConfig": {
      "host": {}
  "HostConfig": {
    "NetworkMode": "host",
    "CapAdd": [

And we need a separate route. We use the same notation as used for the OPC Publisher:

  "routes": {
    "opctwinToUpstream": "FROM /messages/modules/opctwin/* INTO $upstream",
    "opcpublisherToUpstream": "FROM /messages/modules/opcpublisher/* INTO $upstream"

Yes, this module communicates with the Back-end using IoT Hub messages. These are picked then up by the microservices. Here is an example of such a message:

Note: I recommend to filter these messages out so the rest of your IoT platform is not bothered with them. But still, the microservices must be able to receive these messages!

No OPC-Twin messages arriving?

If you have specified your OPC-Twin but no ‘telemetry’ is shown, you have to fix this first before you can proceed.

I had numorous experiments where no OPC-Twin telemetry was shown too.

Unfortunately, there is no golden recipe to get around this, but these step could lead you in the right direction:

0. Is your OPC Publisher working correctly?

1. Check out the logging of the OPC Twin. At leasy you should see the publisher is found:

[08:50:08 INF ()] Using publisher server at address (Microsoft.Azure.IIoT.OpcUa.Edge.Publisher.Servers.PublisherDiscovery)
[08:50:08 INF ()] Publisher connected! (Microsoft.Azure.IIoT.OpcUa.Edge.Publisher.Clients.PublisherServices)

2. Check out if the Twin is trying to discover the OPC-UA servers in the right IP address range:

[08:49:23 INF ()] Start Scan discovery run... (Microsoft.Azure.IIoT.OpcUa.Edge.Discovery.DiscoveryServices)
[08:49:23 INF ()] Start scanning [" [wlp3s0b1]", " [docker0]", " [br-4103f9144d84]"]... (Microsoft.Azure.IIoT.OpcUa.Edge.Discovery.DiscoveryServices)
[08:49:24 INF ()] None: Starting network scan (100 probes active)... (Microsoft.Azure.IIoT.OpcUa.Edge.Discovery.DiscoveryMessagePublisher)

My OPC-UA server is available at As you can see, this range is actually scanned.

To force the ranges scanned, there is not a lot of documentation, though. Check out this page regarding Server discovery. It talks about the desired properties of the OPC-Twin module:

  "properties.desired": {
    "Discovery": "Fast"

With this value you can limit or widen the range of IP-Addresses scanned. Check out the documentation for more details.

3. Check out the ‘Host’ network as documented:

I have tried this several times on Windows. I did not always work as expected. It seems that creating a new virtual switch named host has to be done before the IoT Edge runtime is deployed.

5. The OPC-Twin Portal

At this point you should have both an OPC Publisher and an OPC Twin emitting messages to the cloud.

Now it’s time to go to the WebApp and open the website:

This site is protected by AAD credentials. Once you are logged in, this rather empty screen is shown:

Try to ‘refresh’ your page. This will trigger the microservices to check all IoT Edge devices registered in the IoT Hub for having an OPC Twin module and if so, it executes the local discovery (if the desired property is NOT set to ‘off’).

In my case, this results in the discovery of my OPC-UA service:

It could be you need to flip the Scan switch to the rights, before you actually see servers appear. And try to open the tree. After a while you should see the list of servers.

Note: Actually, it seems to identify my OPCPublisher as a OPC-UA server too. Ignore that one. And please: ignore all DELETE buttons too! (I have no idea how to set things back after I deleted so lines).

Now, drill down further and further. Depending on the OPC-UA server you access, you will find the read and write options at a certain level:

Once you open the ‘Read’ tree, you see all the ‘near real time’ values on the EKI:

The values are changing every few seconds so it seems the OPC-UA Publisher stream is used also to update this page.

This is the actual list of published nodes on my EKI. This list could differ from the list of nodes set in the original pn.json of your OPC Publisher. You can update that list ‘zero-touch’ using an OPC Publisher direct method.

Finally, Check out the ‘Write’ tree:

Yes, now we have all the tools to alter values on your OPC-UA server of choice!

Let’s change one of the relays on the Wise module using the related write method:

This is working and it responds quite fast. The relay changes and the accompanying LED on the Wise is turned on or off.

6. Microservices Rest Web API

This is a great demonstration of the power of the OPC Twin. But I do not recommend to use this website in production. It’s nice for testing but it does not integrate very well with your other Enterprise services.

Setting the values is handled by the OPC Twin microservices. Luckely, it exposes as REST API just to do this kind of stuff by code.

At this moment, the following Rest endpoints are available:

  • Browse : Browse nodes services
  • Call : Call node method services
  • Publish : Value and Event publishing services
  • Read : Node read services
  • Status : Status checks
  • Write : Node writing services

Note: you need to have sufficient credentials to execute these methods.


After reading this blog, you now have a good sense of what to expect from the OPC Twin and the OPC Twin microservices.

Again, check out the security features before you bring this into production.

The discovery feature is great but not every system administrator will accept this on his or her network. So please ask permissions before you roll it out on your factory network.

There is also a Channel 9 IoT Show Deep Dive telling the background story.