Industrial network communications
OPC UA on a Raspberry Pi
Use Python and Node-RED to create an industrial client-server test system.
Industrial operations such as chemical refineries, power plants, and mineral processing operations have different network communications requirements than most IT installations. Some of the key industrial communication requirements include security, multivendor connectivity, time stamping of data, and alarm or quality indicators.
To meet industrial requirements, a communications standard called OLE for Process Control (OPC) [1] was created. The original OPC design was based on Microsoft's Object Linking and Embedding (OLE) technology, and it quickly became the standard for communications between control system consoles, historians (data storage devices), and third-party applications (Figure 1).
The original OPC standard worked well, but it had major limitations in the areas of Linux and embedded systems, routing across wide-area networks (WANs), and new security concerns. To better address new industrial requirements, the Open Platform Communications Unified Architecture (OPC UA) standard [2] was created.
In this article, I look at three small projects that introduce you to OPC UA. The first project uses Python to create an OPC UA server with a client and a graphical user interface (GUI). The second project builds a Node-RED OPC UA server and client app. The final project uses Node-RED web dashboards for read-write access to a Python OPC UA server.
Getting Started
For my test system, I used a Raspberry Pi 4 and an Ubuntu laptop, but the test could also be done on a single Raspberry Pi or laptop. You have a number of OPC UA open source servers from which to choose. For C development applications, the open62541 project [3] offers a C99 architecture that runs on Windows, Linux, VxWorks, QNX (BlackBerry), Android, and a number of embedded systems.
For lightweight, quick testing, OPC UA servers are available in Python and Node-RED. The Free OPC-UA Library project [4] has a great selection of open source tools for people who want to learn and play with OPC UA.
To keep things simple, I am using the python-opcua library, which is a pure Python OPC UA server and client. (Note that a more complete Python OPC UA library, opcua-asyncio, is available for more detailed work.)
The Free OPC UA project also includes a number of useful tools, such as an OPC UA modeler and client GUI. The commands
# Python OPC UA server/client install sudo apt install python-opcua # OPC UA client/QT dependencies sudo apt install PyQT* pip3 install opcua-client # OPC UA modeler tool $ pip3 install opcua-modeler
load these items in Ubuntu/Debian/Raspian environments.
Simple Python OPC UA Server
As a first project, I create a simple OPC UA server with some simulated OPC UA tags (Listing 1) [5]. The first steps in setting up an OPC UA server are to define a server name, set a network location endpoint, and register the namespace (lines 7-12). A little later you will see that the namespace index is very important in the definition of OPC UA tags. To simplify my code, I hard-coded the IP address (lines 9 and 12). For a more flexible setup, the Python socket library could be used to determine this value for the endpoint and namespace.
Listing 1
Python OPC UA Simple Server
01 # opcua_server1.py - Create an OPC UA server and simulate 2 tags 02 # 03 import opcua 04 import random 05 import time 06 07 s = opcua.Server() 08 s.set_server_name("OpcUa Test Server") 09 s.set_endpoint("opc.tcp://192.168.0.120:4841") 10 11 # Register the OPC UA namespace 12 idx = s.register_namespace("http://192.168.0.120:4841") 13 # start the OPC UA server (no tags at this point) 14 s.start() 15 16 objects = s.get_objects_node() 17 # Define a Weather Station object with some tags 18 myobject = objects.add_object(idx, "Station") 19 20 # Add a Temperature tag with a value and range 21 myvar1 = myobject.add_variable(idx, "Temperature", 25) 22 myvar1.set_writable(writable=True) 23 24 # Add a Windspeed tag with a value and range 25 myvar2 = myobject.add_variable(idx, "Windspeed", 11,4,4) 26 myvar2.set_writable(writable=True) 27 28 # Cycle every 5 seconds with simulated data 29 while True: 30 myvar1.set_value(random.randrange(25, 29)) 31 myvar2.set_value(random.randrange(10, 20)) 32 time.sleep(5)
The OPC UA structure is based on objects and files, under which tags are configured. For this example a Station
object is created (line 18), with Temperature
and Windspeed
tags (lines 21-26). The final step is to use the set_value
method to update the tags with random values (lines 30-31).
The Free OPC UA project's opcua-client GUI tool lets you view the OPC UA server and its tags. Figure 2 shows the server with two simulated tags and their NodeIDs.
OPC UA items are accessed by their NodeIDs. The OPC UA server will autocreate a NodeID if one isn't defined when an object or tag is added. In this example, Temperature
is given the NodeID ns=2,i=2
, which means it has an index of 2 in node space 2. In the next sections, I show how NodeIDs are used and how they can be created.
In OPC UA, the terms "tags" and "variables" are often used interchangeably. In an industrial plant, hardware signals such as pumps and sensors are usually referred to as "tags" in the control systems; however, within the OPC UA server, the term "variable" is used. The key difference is that a variable can also be an internal or software-generated point, such as a counter.
Python OPC UA Client App
The opcua library is used for both server and client applications. An OPC UA client app only requires five lines to connect to a server and define a NodeID object and get its value. Listing 2 shows how to get the previously defined Temperature
tag.
Listing 2
Getting a Tag Value
>>> import opcua >>> >>> # Connect as an OPC UA client and get a tag value >>> client = opcua.Client("opc.tcp://192.168.0.120:4841") >>> client.connect() >>> temptag = client.get_node("ns=2;i=2") >>> temptag.get_value() 26
The Client
method defines the OPC UA server's endpoint location, and the connect
method enables the client connection. An OPC UA NodeID object is defined by a namespace number (ns
) and an index (i
), and the get_value
method returns the current value. For my Python client application, I use this basic code to show tag values on a gauge chart (Figure 3).
The Python tk_tools [6] library contains some useful graphic widgets (e.g., charts, gauges, LEDs, seven-segment displays). To install, enter:
pip install tk_tools
The client app (Listing 3) creates a Tkinter object (line 11) and then adds two gauge components (lines 15-20). The Tkinter after(<msec>,<function_name>)
method calls an update function (line 26) that refreshes the gauge components with OPC UA tag updates (lines 26 and 28).
Listing 3
Python OPC UA Client App
01 # station1.py - Put OPC UA data into gauges 02 # 03 import tkinter as tk 04 import tk_tools 05 import opcua 06 07 # Connect to the OPC UA server as a client 08 client = opcua.Client("opc.tcp://192.168.0.120:4841") 09 client.connect() 10 11 root = tk.Tk() 12 root.title("OPC-UA Weather Station 1") 13 14 # Create 2 gauge objects 15 gtemp = tk_tools.Gauge(root, height = 200, width = 400, 16 max_value=50, label='Temperature', unit='infinityC') 17 gtemp.pack() 18 gwind = tk_tools.Gauge(root, height = 200, width = 400, 19 max_value=100, label='Windspeed', unit='kph') 20 gwind.pack() 21 22 def update_gauge(): 23 # update the gauges with the OPC UA values every 1 second 24 gtemp.set_value(client.get_node("ns=2;i=2").get_value()) 25 gwind.set_value(client.get_node("ns=2;i=5").get_value()) 26 root.after(1000, update_gauge) 27 28 root.after(500, update_gauge) 29 30 root.mainloop()
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Linux Kernel 6.13 Offers Improvements for AMD/Apple Users
The latest Linux kernel is now available, and it includes plenty of improvements, especially for those who use AMD or Apple-based systems.
-
Gnome 48 Debuts New Audio Player
To date, the audio player found within the Gnome desktop has been meh at best, but with the upcoming release that all changes.
-
Plasma 6.3 Ready for Public Beta Testing
Plasma 6.3 will ship with KDE Gear 24.12.1 and KDE Frameworks 6.10, along with some new and exciting features.
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.