Overview
Bridging a building management system that runs Siemens Desigo CC on PXC-100 series automation stations to Microsoft Azure requires an industrial edge gateway that can translate between two protocol worlds: OPC UA on the plant side and a cloud-friendly MQTT/AMQP transport on the Azure side. The Siemens SIMATIC IoT2040 (6ES7647-0AA00-0YA2) is an Intel Quark-based DIN-rail gateway shipped with a Yocto Linux image that already contains Node-RED, the Modbus TCP contrib nodes, and a working OPC UA stack. Combined with node-red-contrib-opcua on the field side and the official azure-iot-sdk-node device client on the cloud side, the IoT2040 becomes a self-contained Desigo CC → Azure IoT Hub forwarder that requires no Windows service, no custom C++ driver, and no permanent outbound firewall holes for SCADA workstations.
This article documents the full reference architecture, the bring-up of the IoT2040 firmware image, the Desigo CC OPC UA server configuration, the Node-RED flow that performs subscription-based polling, and the JSON telemetry payload that lands in Azure IoT Hub. It also explains why BACnet over the IoT2040 is not the recommended path (the node-bacnet package is known to fail on the IOT2000 class of devices due to UDP broadcast and timing issues on the Yocto userspace) and why OPC UA is the protocol of choice when Desigo CC exposes it.
Reference Architecture
The end-to-end data path has five discrete hops. Each hop is owned by a different component, and a failure at any hop is isolated by design so that a cloud outage does not stop on-site control.
- PXC-100 automation station – reads physical I/O (analog inputs, binary inputs) and exposes them as BACnet/OPC objects.
- Desigo CC server – the supervisory SCADA that aggregates PXC points, runs graphics, and hosts the OPC UA server endpoint on TCP port 4840 (or 4841 for encrypted).
-
IoT2040 gateway – runs Node-RED with the
node-red-contrib-opcuaclient package. Reads subscribed OPC UA nodes at a configurable scan rate and forwards them as JSON. - Azure IoT Hub – the cloud ingress that accepts device-to-cloud telemetry over MQTT (port 8883), AMQP (port 5671), or HTTPS (port 443).
-
Downstream Azure services – Stream Analytics, Time Series Insights, Event Grid, or Data Lake – consume device-to-cloud messages from the built-in endpoint
messages/events.
Prerequisites
| Component | Specification / Version |
|---|---|
| Siemens IoT2040 | 6ES7647-0AA00-0YA2, Intel Quark x86, 1 GB RAM, 8 GB eMMC |
| Example image | Siemens IOT2000 V2.6.0 (or later) – includes Node-RED 0.20.x, Node.js 8.x |
| Desigo CC | V4.x or V5.x with the OPC UA Server option licensed and enabled |
| PXC-100 controllers | Firmware ≥ 4.0 with the BACnet/IP profile exposed to Desigo CC |
| Azure subscription | Active subscription with permission to create IoT Hub (S1 tier recommended for BMS telemetry) |
| Node-RED contrib |
node-red-contrib-opcua ≥ 0.2.1 and node-red-contrib-azure-iot-hub ≥ 1.5.0 |
| Network | TCP 4840 (or 4841) from IoT2040 to Desigo CC, outbound TCP 8883 from IoT2040 to Azure |
Step 1 – Configure the Desigo CC OPC UA Server
Desigo CC ships with a built-in OPC UA server, but it is not enabled by default. Activate it once per management station.
- Open the Desigo CC Management Console and log in with engineering credentials.
- Navigate to System → Connectivity → OPC UA Server.
- Tick Enable OPC UA Server and choose the listen port (default 4840). If you need encryption, switch to 4841 and bind the Desigo CC project certificate.
- Add the security policies you want to expose. For an IoT2040 client on the same VLAN,
None+Signis acceptable. For multi-tenant or shared networks, selectBasic256Sha256and load the IoT2040 client certificate. - Click Apply. The service
DesigoCC OPC UA Serverrestarts and binds to0.0.0.0:4840. - Verify reachability from a Windows workstation using UaExpert – connect to
opc.tcp://<desigo-cc-fqdn>:4840, accept the self-signed certificate, and browse the Objects → Desigo CC folder to confirm that the PXC-100 points are visible.
http request node. The rest of the article still applies – only step 3 changes.
Step 2 – Bring Up the IoT2040
- Download the latest Example Image V2.6.0 for the IoT2040 from Siemens Industry Online Support (article ID 109741799). The image is a 1.6 GB ZIP that contains a pre-baked SD card image.
- Write the image to a ≥ 8 GB industrial-grade microSD card using
balenaEtcherorWin32DiskImager. - Insert the card, power the IoT2040 with 24 V DC on the bottom terminal block, and wait ~90 s for the green
PWRandRUNLEDs to go solid. - Connect a serial console (115 200 8N1) to the
CONport and log in asrootwith the default password from the image release notes. - Assign a static IP on X1P1 (the plant-side NIC) and route X2P1 (the cloud-side NIC) through the corporate firewall:
ifconfig eth0 192.168.10.50 netmask 255.255.255.0 up
route add default gw 192.168.10.1
- Confirm internet egress:
ping -c 3 mqtt.azure-devices.net
If the ping is blocked, add an explicit NAT or proxy exception for *.azure-devices.net on TCP 8883 and TCP 443.
Step 3 – Install the Node-RED Contrib Packages
Open the Node-RED UI on http://192.168.10.50:1880, then from the menu select Manage palette → Install and add the following two packages:
node-red-contrib-opcua
node-red-contrib-azure-iot-hub
For headless installs, drop to the IoT2040 shell and run:
cd /usr/lib/node_modules/node-red
npm install node-red-contrib-opcua
npm install node-red-contrib-azure-iot-hub
systemctl restart node-red
The node-red-contrib-opcua package provides the OpcUa-Browser, OpcUa-Client, and OpcUa-Item nodes used to discover, subscribe to, and read Desigo CC points. The node-red-contrib-azure-iot-hub package wraps the azure-iot-sdk-node device client and exposes a configurable Azure IoT Hub node that takes a connection string and a topic filter.
Step 4 – Create the OPC UA Subscription Flow
The recommended pattern is to subscribe to a MonitoredItem on the Desigo CC server with a 1000 ms publishing interval. Subscription-based reads are dramatically more efficient than polled reads because the server pushes only deltas.
- Drag an OpcUa-Client node into the flow and configure it:
-
Endpoint:
opc.tcp://192.168.10.20:4840 -
Security Mode:
None(orSignif you enabled signing) -
Security Policy:
None -
Authentication:
Anonymousfor the default Desigo CC install, or User/Password for an OPC UA account.
-
Endpoint:
- Add an OpcUa-Item node for each Desigo CC point you want to forward. Use the OpcUa-Browser to navigate to
Objects → Desigo CC → <System> → ...and pick a node by double-click. Common candidates are room temperature, damper position, and AHU enable command. - Wire the OpcUa-Item to an OpcUa-Subscription node with these settings:
-
Interval:
1000ms -
QueueSize:
10 -
DiscardOldest:
true
-
Interval:
The subscription node emits a msg.payload object with the structure:
{
"topic": "ns=4;s=Plant1.AHU01.RoomTemp",
"payload": 22.4,
"dataType": "Float",
"value": { "value": 22.4, "dataType": "Float" },
"statusCode": { "value": 0 }
}
Step 5 – Connect to Azure IoT Hub
- In the Azure portal, create an IoT Hub (S1 tier is fine for BMS data rates below 50 messages/s). Note the hostname (e.g.
bms-hub.azure-devices.net). - Under Devices → Add Device, create a device with ID
iot2040-gw-01and copy the primary connection string – it has the form:
HostName=bms-hub.azure-devices.net;DeviceId=iot2040-gw-01;SharedAccessKey=xxxxxxxxxxxxxx=
- Drop an Azure IoT Hub node in the Node-RED flow and paste the connection string. Set the Method to
device-to-cloudand the topic todevices/iot2040-gw-01/messages/events/. - Add a function node between the OpcUa-Subscription and the Azure node to build a clean JSON envelope:
msg.payload = {
deviceId: "iot2040-gw-01",
ts: new Date().toISOString(),
point: msg.topic,
value: msg.payload.value,
dataType: msg.payload.dataType,
quality: (msg.statusCode && msg.statusCode.value === 0) ? "Good" : "Bad"
};
msg.payload = JSON.stringify(msg.payload);
return msg;
- Wire the function output to the Azure IoT Hub node and click Deploy. The bottom-right status bar should read Connected within five seconds.
Step 6 – Verify the End-to-End Path
- From any workstation with the Azure IoT Explorer tool installed, connect to the hub and select device
iot2040-gw-01. - Click Telemetry and observe live messages arriving. Each message corresponds to one subscribed OPC UA point.
- From the IoT2040 shell, run
journalctl -u node-red -fand confirm that noBAD_COMMUNICATION_ERRORorSERVICE_BADlines appear in the last hour. - Force a value change in Desigo CC (e.g. override an analog output). The new value should land in IoT Explorer within one scan interval (≤ 1 s).
value field is always null, the OpcUa-Client is connected but the subscription is using Read instead of Subscribe. Open the subscription node, switch the action from read to subscribe, and redeploy.
Message Format and Schema
Every device-to-cloud message is a UTF-8 JSON document with the schema below. Schema-enforcement at the IoT Hub route simplifies downstream Stream Analytics queries.
| Field | Type | Description |
|---|---|---|
deviceId |
string | Always iot2040-gw-01; redundant with the IoT Hub system property but convenient for routing. |
ts |
string (ISO 8601) | UTC timestamp the IoT2040 received the value. |
point |
string | OPC UA node id, e.g. ns=4;s=Plant1.AHU01.RoomTemp. |
value |
number / boolean / string | The actual data value. |
dataType |
string | OPC UA data type: Float, Double, Boolean, String, Int32. |
quality |
string |
Good or Bad; derived from statusCode. |
Performance and Sizing
The IoT2040 has a single-core 400 MHz Intel Quark CPU and 1 GB of RAM. The practical ceiling for an OPC UA subscription running through Node-RED is approximately 500 monitored items at a 1 s interval. Above that, the node-opcua client begins to drop KeepAlive packets and the Azure node queues up.
For a typical BMS of one Desigo CC server with 200 physical points, the load is well within the budget. If you need to forward 1 000+ points, the recommended path is to deploy a SIMATIC IOT2050 (6ES7647-0BA00-0YA2) with the dual-core ARM Cortex-A53 and 2 GB of RAM, and run the same flow.
Security Hardening
- Change the default root password on the IoT2040 image before commissioning. Siemens ships the example image with a publicly documented password.
- Enable OPC UA Sign-and-Encrypt on Desigo CC and load the IoT2040 client certificate. Generate the cert with
opensslon the IoT2040:
openssl req -x509 -newkey rsa:2048 -keyout iot2040.key -out iot2040.pem \
-days 3650 -nodes -subj "/CN=iot2040-gw-01"
- Switch the Azure node to MQTT over TLS (port 8883). The default contrib node does this automatically when the connection string contains the SAS key.
- Add an IoT Hub IP filter that whitelists only the IoT2040's public IP. This prevents rogue devices from injecting telemetry.
- Enable IoT Hub diagnostic logs to Azure Monitor and alert on
ThrottlingorUnauthorizedevents.
Alternative: Azure IoT Hub Integration Patterns
The Node-RED + IoT2040 path is the lowest-cost, on-premises-only option. If your facility cannot host the IoT2040 or you want a managed connector, third-party services such as CloudRail provide a drop-in OPC UA → Azure IoT Hub bridge that can read Desigo CC points in minutes without any on-site Linux box. The trade-off is per-message licensing and a hard dependency on the vendor's cloud relay.
For a hybrid architecture where Desigo CC stays on-prem and only aggregated alarms are pushed to Azure, the recommended Azure-side services are Azure IoT Hub (ingress), Stream Analytics (windowing), and Time Series Insights (historical visualization). For an SAP DMC integration, see the reference pattern documented on Microsoft Learn for routing IoT Hub events to SAP Digital Manufacturing via Event Grid.
Troubleshooting Matrix
| Symptom | Likely Cause | Remediation |
|---|---|---|
| Node-RED disconnected from Desigo CC | Firewall on TCP 4840 or wrong endpoint URL | Test with telnet desigo-cc 4840 from the IoT2040 shell; correct the Endpoint string. |
| Subscription publishes, Azure node stays idle | Wrong connection string or expired SAS key | Regenerate the device key in IoT Hub, redeploy with the new string. |
Values are null in IoT Explorer |
Action is read instead of subscribe | Change the subscription node action and redeploy. |
| Bad quality codes | PXC-100 offline or BACnet link down | Check the PXC status in Desigo CC; resolve the field link first. |
| Gateway runs out of memory | Too many monitored items or a payload-format loop | Lower the queue size; add a debug counter; switch to IOT2050. |
| TLS handshake fails on Azure | Outdated CA bundle on the Yocto image | Update ca-certificates package and restart Node-RED. |
FAQ
Why is BACnet not used on the IoT2040?
The node-bacnet contrib package relies on UDP broadcast, which the IOT2000 series example image does not support reliably because of the custom Yocto network stack. Building a BACnet stack from source is possible but not production-stable. OPC UA over TCP is the recommended transport when the upstream SCADA exposes it.
Does the IoT2040 support encryption on the Azure side?
Yes. The node-red-contrib-azure-iot-hub package uses MQTT over TLS on TCP 8883 by default. The shared access key in the connection string authenticates the device to IoT Hub; no additional cert is required.
How many OPC UA points can a single IoT2040 forward?
Roughly 500 monitored items at a 1 s scan rate on a 400 MHz Quark with 1 GB RAM. For 1 000+ points, migrate to the IOT2050 (dual-core ARM, 2 GB RAM) running the same Node-RED flow.
Can I read Desigo CC points without enabling the OPC UA server?
Yes – use the Desigo CC Automation REST API and an http request node. The endpoint pattern is https://<desigo>/api/automation/v1/points/.... The Azure side of the flow is identical.
What happens if Azure IoT Hub is unreachable?
The azure-iot-sdk-node device client buffers messages locally and retries with exponential backoff. On the IoT2040 the default buffer is 50 messages – increase it in the Azure node configuration if you expect longer outages.