How autonomy-logic/openplc-runtime works
1. This repository is a headless PLC runtime, not a user-facing app. Its architecture is centered on two cooperating processes: a Python web server that exposes the control plane, and a C/C++ PLC runtime that executes IEC 61131-3 logic with real-time scheduling.
2. The top-level boundary is between the external controller and the runtime. The main external client is the OpenPLC Editor v4, which uploads programs, polls compilation state, starts/stops execution, and connects to debug streams. There is also support for cloud-controlled operation via Autonomy Edge Cloud, but the same runtime-facing APIs are used.
3. The Python subsystem in webserver/ is the orchestration layer. It hosts the HTTPS REST API, JWT authentication, user management, file upload validation, runtime status endpoints, and the Socket.IO/WebSocket debug interface. It also manages startup/shutdown of the PLC runtime process and bridges editor requests into runtime commands.
4. The C/C++ subsystem in core/src/plc_app/ is the execution engine. It owns PLC state, scan-cycle timing, watchdog/logging utilities, socket communication, and dynamic loading of compiled PLC programs. This is the part that must stay deterministic and is the only layer that needs real-time priority.
5. Communication between the two main processes happens over Unix domain sockets under /run/runtime/. That IPC boundary is important: the web server does not execute PLC code directly; it sends control commands and receives logs/status through the socket while the runtime remains isolated as a separate process.
6. Program deployment follows a compile-and-load pipeline. The editor uploads a ZIP package to the web server, the server validates and extracts it, and the build flow compiles it into a shared library. The runtime then loads that shared library dynamically, so PLC logic is treated as a deployable binary artifact rather than source code executed in place.
7. The scan-cycle and I/O boundary lives inside the runtime plus the driver layer. core/src/drivers/ provides the plugin system for hardware interaction, with plugin configuration, driver abstractions, and plugin-specific implementations. This is where external fieldbus or device communication is integrated into the PLC loop.
8. The driver subsystem is split by implementation language. Native plugins include EtherCAT and S7comm, while Python plugins cover Modbus master/slave and OPC UA. Shared Python support code in core/src/drivers/plugins/python/shared/ provides buffer access, config decoding, type conversion, synchronization, and logging so plugins can interact with PLC memory safely and consistently.
9. OPC UA is a significant protocol-specific subsystem within the Python plugins. It has its own address-space, security, subscription, and server modules, plus dedicated tests and config models. In architectural terms, it acts as both a network-facing data server and a bridge into PLC memory/debug data.
10. The runtime has a security and control plane layered on top of the transport. TLS is used on port 8443, authentication is JWT-based, upload handling includes validation against path traversal and archive abuse, and secrets are stored in the runtime data directory. These controls live mainly in the Python web layer, not in the real-time core.
11. Build and packaging are split across tooling layers. CMake builds the C/C++ runtime and native plugin code; Python packaging/venvs support the web server and Python plugins; Dockerfiles and GitHub workflows package cross-platform runtime images and installers. The build outputs include the PLC executable and compiled program libraries.
12. For an architecture diagram, the key nodes are: external editor/cloud client, Python web/API server, Unix-socket IPC, PLC runtime core, dynamic PLC program library, and plugin drivers reaching hardware/network protocols. The main data flow is editor upload -> validation/compile -> shared library load -> real-time scan cycle -> plugin I/O and debug/status back to the editor.
Main entry points: app.py Web server · plugin_driver.c Plugin API · plc_main.c PLC app · CMakeLists.txt Build & package
Components 19
External control
Clients that operate or monitor the runtime
- Editor v4 · Primary programmer client that uploads projects, starts/stops execution, and consumes debug/status streams
- Cloud Ops · Autonomy Edge Cloud control path using the same control-plane APIs
Python control plane
HTTPS API, auth, uploads, and editor/runtime orchestration
- Web server · Main Python process that exposes the control plane
webserver/app.py - REST API · Endpoints for upload, runtime status, control, and management
webserver/restapi.py - Auth & creds · JWT authentication and credential handling for the control plane
webserver/credentials.py - Runtime manager · Starts, stops, and supervises the PLC runtime process
webserver/runtimemanager.py - Debug stream · Socket.IO/WebSocket channel for debug data and editor feedback
webserver/debug_websocket.py - Unix client · Python-side Unix-domain socket bridge into the runtime
webserver/unixclient.py
PLC runtime
Deterministic execution engine and IPC boundary
- PLC app · Native runtime process entry and top-level lifecycle
core/src/plc_app/plc_main.c - State manager · Owns PLC execution state and mode transitions
core/src/plc_app/plc_state_manager.cpp - Scan cycle · Deterministic scan-cycle timing and execution scheduling
core/src/plc_app/scan_cycle_manager.c - Unix socket · Runtime-side Unix-domain socket endpoint under /run/runtime
core/src/plc_app/unix_socket.c - Program loader · Dynamically loads compiled PLC program libraries
core/src/plc_app/python_loader.c
Driver plugins
Hardware and protocol integration for PLC I/O
- Plugin API · Driver abstraction and plugin configuration layer
core/src/drivers/plugin_driver.c - Plugin config · Plugin configuration, types, and validation helpers
core/src/drivers/plugin_config.c - Native I/O · C/C++ hardware and fieldbus drivers such as EtherCAT and S7comm
core/src/drivers/plugins/native/ethercat/ethercat_plugin.c - Python I/O · Python-based drivers for Modbus and OPC UA using shared runtime helpers
core/src/drivers/plugins/python/shared/buffer_accessor.py - OPC UA · Network-facing OPC UA server, address space, security, and subscription bridge
core/src/drivers/plugins/python/opcua/server.py
Build and packaging
Compilation and deployment tooling
- Build & package · CMake, Python packaging, Docker, and release workflows
CMakeLists.txt
Connections 21
- Editor v4 → Web server: upload/control · Editor drives deployment and runtime control through the web server
- Cloud Ops → Web server: remote control · Cloud control uses the same external control plane
- Web server → REST API: serves · Application hosts the HTTP API surface
- Web server → Auth & creds: secures · Authentication and credentials protect the control plane
- Web server → Runtime manager: supervises · Web layer starts and stops the runtime process
- Web server → Debug stream: streams debug · Editor debug data and runtime events flow over WebSocket
- Web server → Unix client: IPC bridge · Python control plane sends commands over Unix-domain sockets
- Unix client → Unix socket: connects · Client-side endpoint for runtime IPC
- Unix socket → PLC app: commands · Runtime receives control, status, and log messages
- PLC app → State manager: owns · Main process drives PLC lifecycle state
- State manager → Scan cycle: schedules · State manager governs real-time scan execution
- Scan cycle → Program loader: loads · Scan/runtime layer loads deployed PLC binaries
- Scan cycle → Plugin API: uses · Execution loop delegates I/O to the driver framework
- Plugin API → Plugin config: configures · Plugins are instantiated from config and type metadata
- Plugin API → Native I/O: hosts · Native implementations provide fieldbus and device access
- Plugin API → Python I/O: hosts · Python implementations provide protocol and device access
- Python I/O → OPC UA: includes · OPC UA is the major Python protocol subsystem
- OPC UA → PLC app: memory bridge · OPC UA reads and writes PLC memory/debug data through the runtime bridge
- Build & package → Web server: packages · Tooling builds and packages the Python control plane
- Build & package → PLC app: builds · Tooling compiles the native runtime and plugin artifacts
- Build & package → Program loader: deploys · Build flow produces deployable shared libraries for the runtime