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
-
Halcyon Creates Anti-Ransomware Protection for Linux
As more Linux systems are targeted by ransomware, Halcyon is stepping up its protection.
-
Valve and Arch Linux Announce Collaboration
Valve and Arch have come together for two projects that will have a serious impact on the Linux distribution.
-
Hacker Successfully Runs Linux on a CPU from the Early ‘70s
From the office of "Look what I can do," Dmitry Grinberg was able to get Linux running on a processor that was created in 1971.
-
OSI and LPI Form Strategic Alliance
With a goal of strengthening Linux and open source communities, this new alliance aims to nurture the growth of more highly skilled professionals.
-
Fedora 41 Beta Available with Some Interesting Additions
If you're a Fedora fan, you'll be excited to hear the beta version of the latest release is now available for testing and includes plenty of updates.
-
AlmaLinux Unveils New Hardware Certification Process
The AlmaLinux Hardware Certification Program run by the Certification Special Interest Group (SIG) aims to ensure seamless compatibility between AlmaLinux and a wide range of hardware configurations.
-
Wind River Introduces eLxr Pro Linux Solution
eLxr Pro offers an end-to-end Linux solution backed by expert commercial support.
-
Juno Tab 3 Launches with Ubuntu 24.04
Anyone looking for a full-blown Linux tablet need look no further. Juno has released the Tab 3.
-
New KDE Slimbook Plasma Available for Preorder
Powered by an AMD Ryzen CPU, the latest KDE Slimbook laptop is powerful enough for local AI tasks.
-
Rhino Linux Announces Latest "Quick Update"
If you prefer your Linux distribution to be of the rolling type, Rhino Linux delivers a beautiful and reliable experience.