Computational Logic
To get a better understanding of the operational logic of an Execution Engine, Figure 1 illustrates its computational logic. The OPC UA Server of the Execution, as well as its OPC UA Clients are implemented with the open source Python asyncio Stack, which uses with asyncio asynchronous programming. Here, an EventLoop allows the managing and distributed execution of different operations. However, to effectively execute the separated Client and Server Loops, the Execution Engine’s OPC UA Server is executed in a main thread and each Client is started in a separate thread with an individual EventLoop.
While the open source Python asyncio Stack completely relies on asynchronous programming, a custom dispatcher implementation may not, so that it is required to invoke asynchronous operations (Callbacks Dispatcher Interface) from synchronous operations (Dispatcher). Here, the Python nest_asyncio library allows the nesting of asyncio EventLoops, so that a Dispatcher invocation of an Execution Engine callback is accomplished with a wrapper function that only starts a nested EventLoop, which then executes the actual callback of the dispatcher interface.
The separate processing of the different program functionalities requires interfaces between them to make data available between different EventLoops and threads. Here, the nested EventLoops of the Dispatcher interface Callbacks can directly interact with the Main Loop of the OPC UA Server and thus, perform operations on the OPC UA Server, such as the adding or removing of variables and objects, or the reading and writing of variable values.
Since OPC UA Clients of the Control Interface are started from the Dispatcher Interface’s Service Started Callback, the Python queue library is deployed to ensure a safe exchange of information between the different threads. On the other side, the Main Thread receives information from the Control Interface about the completion of services, as well as the provision of execution parameter. Here a Semaphore between the different threads is utilized, where the Control Interfaces adds elements to either the service execution list or the Execution Parameter List. The Main Thread, checks at each iteration whether elements were added to the list or not. If so, the Main Thread can access these information through the callbacks or the OPC UA Server and react to their occurrence.

Figure 1: Computational Logic of the Execution Engine