Integrating Artificial Intelligence (AI) into Programmable Logic Controller (PLC) programming is revolutionizing industrial automation by enhancing efficiency, adaptability, and predictive capabilities. Leveraging tools like the Python Scripting Engine in CODESYS and cloud-based AI services offers engineers innovative approaches to designing and managing PLC applications.
Python Scripting Engine in CODESYS
The Python Script Engine in CODESYS is a powerful tool that enables automation of various development and project management tasks within the CODESYS environment. By integrating IronPython scripting, developers can streamline processes such as project creation, device configuration, and code generation, thereby enhancing efficiency and precision.
Key functionalities accessible through the Python Script Engine include:
- System: Access to general CODESYS functionalities, such as exiting the application and handling the user interface.
- Projects: Management of projects, including loading, creating, saving, and closing projects.
- Online: Online functions like logging into devices and applications, managing access data, performing network scans, and gateway management.
- LibraryManager: Management of library repositories, including viewing, installation, and removal of libraries.
- DeviceRepository: Handling of device repositories, including import and export of device descriptions.
Scripts can be executed directly from the CODESYS Development System interface or via the command line, allowing for flexible integration of automation processes into existing workflows.
To facilitate the creation and editing of scripts, CODESYS offers a Python Editor plug-in. This tool provides features such as auto-completion, syntax highlighting, code structuring, and intelligent indentation, thereby increasing productivity during the development of automation solutions based on Python scripts.
By leveraging the Python Script Engine, developers can achieve a higher level of automation and accuracy in managing projects within CODESYS, leading to more efficient and reliable development processes.
For professionals in the field of industrial automation, precision and consistency are critical. The CODESYS Python Scripting Engine provides powerful capabilities to automate repetitive tasks such as adding devices, creating programs, importing libraries, or configuring projects — all with surgical precision.
The default path to the Script Engine stubs is:
C:\Program Files\CODESYS 3.5.xx.xx\CODESYS\ScriptLib\Stubs\scriptengine
This folder contains all the Python stubs required to interact with the CODESYS scripting API. These stubs act as an interface between your Python code and the internal CODESYS objects.
How to Use in VS Code
To enable features like code completion, syntax highlighting, and type hinting when writing CODESYS scripts in Visual Studio Code, you can do the following:
- Copy the scriptengine folder from the default path:
C:\Program Files\CODESYS 3.5.xx.xx\CODESYS\ScriptLib\Stubs\scriptengine
- Paste it into your Python project directory, for example:
my-codesys-scripts/
├── scriptengine/
├── my_script.py
This setup allows VS Code to recognize the CODESYS-specific modules, which helps with writing, testing, and debugging your automation scripts more efficiently — even outside of the CODESYS IDE.
Sample Programs in Python Scripting Engine for interacting with Codesys
Sample program:
devId = None
devices = device_repository.get_all_devices("CODESYS Control Win V3")
for device in devices:
devId = device.device_id
proj = projects.primary
# delete existing testdev device
existing = proj.find('testdev')
if len(existing) > 0:
existing[0].remove()
# add device
proj.add('testdev', devId)
apps = proj.find('Application', True)
if len(apps) > 0:
app = apps[0]
tc = app.create_task_configuration()
What the Script Does
This script is used to:
- Fetch a device ID for CODESYS Control Win V3,
- Remove any existing device called testdev from the project,
- Add a new device using the fetched device ID,
- Create a Task Configuration for the application in the project.
Script Explained – Line by Line
devId = None
devices = device_repository.get_all_devices("CODESYS Control Win V3")
for device in devices:
devId = device.device_id
- Fetches all available devices from the Device Repository matching the type “CODESYS Control Win V3”.
- Loops through the results and stores the device_id of the last matching device into the devId variable.
💡 In production scripts, you’d typically select a specific version or device instead of blindly taking the last one.
proj = projects.primary
Gets the currently opened CODESYS project — this is the project that the script will modify.
# delete existing testdev device
existing = proj.find('testdev')
if len(existing) > 0:
existing[0].remove()
- Searches the project for any device named testdev.
- If found, it removes the existing device to avoid duplicates.
- This makes the script idempotent — safe to run multiple times.
# add device
proj.add('testdev', devId)
Adds a new device to the project with the name testdev, using the device_id fetched earlier.
apps = proj.find('Application', True)
if len(apps) > 0:
app = apps[0]
tc = app.create_task_configuration()
- Searches for the Application object in the project (recursive = True).
- If found, it gets the first one and creates a Task Configuration within it.
- Task configurations are needed to define cyclic tasks like MainTask or VISU_TASK.
Summary
This script:
- Dynamically finds a CODESYS device,
- Ensures the project has no duplicates,
- Adds the new device cleanly,
- Prepares the project with a new task configuration — ready for adding programs.
More sample scripts:
Add a device with a task configuration
# add device with a task configuration
proj.add('PLC', devId)
apps = proj.find('Application', True)
if len(apps) > 0:
tc = apps[0].create_task_configuration()
# add task
task = tc.create_task('Task')
task.pous.add('PLC_PRG')
# proj = projects.open("C:\Users\Administrator\Documents\PL Przepompownia AI\Untitled1.project")
# devId = None
# devices = device_repository.get_all_devices("CODESYS Control Win V3")
# for device in devices:
# devId = device.device_id
# proj = projects.primary
# # add device
# proj.add('PLC', devId)
# apps = proj.find('Application', True)
# if len(apps) > 0:
# tc = apps[0].create_task_configuration()
# # add task
# task = tc.create_task('Task')
# task.pous.add('PLC_PRG')
Create a POU
proj = projects.primary # current project
found = proj.find("Application", True)
app = found[0]
# Create FB
mypou = app.create_pou("MyPou")
# Change declaration of the FB
implementation = mypou.textual_declaration.replace("""FUNCTION_BLOCK MyPou
VAR_INPUT
iValue : INT;
END_VAR
VAR_OUTPUT
END_VAR
VAR
END_VAR""")
# Change implementation of the FB
mypou.textual_implementation.replace("""iValue := iValue + 1;""")
# Add method to FB
dosomething = mypou.create_method("DoSomething", "INT")
# Change declaration of the method
dosomething.textual_declaration.replace("""METHOD DoSomething : INT
VAR_INPUT
iVal1 : INT;
iVal2 : INT;
END_VAR""")
# Change implementation of the method
dosomething.textual_implementation.replace("""DoSomething := iVal1 + iVal2;""")
# # Find the pou and delete it
# found = app.find("MyPou")
# if found and len(found) == 1:
# found[0].remove()
# else:
# print("POU 'MyPou' was not found")
Create global and persistent variable list:
# Get the primary project or open a project
proj = projects.primary # Use the currently open project
# Find the Application object
found = proj.find("Application", True)
app = found[0]
# Create a Global Variable List (GVL)
gvl = app.create_gvl("GVL_Process")
# Define the global variables in the GVL
gvl.textual_declaration.replace("""VAR_GLOBAL
// System Configuration
g_xSystemEnabled : BOOL := TRUE; // System enable flag
g_xEmergencyStop : BOOL := FALSE; // Emergency stop status
g_xMaintenanceMode : BOOL := FALSE; // Maintenance mode flag
// Process Variables
g_rTemperature : REAL; // Process temperature
g_rPressure : REAL; // Process pressure
g_rFlowRate : REAL; // Flow rate
g_rLevel : REAL; // Tank level
// Control Parameters
g_rTempSetpoint : REAL := 25.0; // Temperature setpoint
g_rPressSetpoint : REAL := 2.5; // Pressure setpoint
g_rFlowSetpoint : REAL := 100.0; // Flow rate setpoint
g_rLevelSetpoint : REAL := 50.0; // Level setpoint
// Alarms
g_xTempAlarm : BOOL; // Temperature alarm
g_xPressAlarm : BOOL; // Pressure alarm
g_xFlowAlarm : BOOL; // Flow rate alarm
g_xLevelAlarm : BOOL; // Level alarm
// Timers
g_tCycleTime : TIME := T#100MS; // Control cycle time
g_tAlarmDelay : TIME := T#5S; // Alarm delay time
END_VAR""")
# Create a persistent Global Variable List
persistent_gvl = app.create_persistentvars("GVL_Settings")
# Define the persistent global variables
persistent_gvl.textual_declaration.replace("""VAR_GLOBAL PERSISTENT
// System Settings
p_xAutoStartEnabled : BOOL := TRUE; // Auto-start on power up
p_tStartupDelay : TIME := T#30S; // Startup delay time
// Control Parameters
p_rTempKp : REAL := 1.5; // Temperature controller P gain
p_rTempKi : REAL := 0.2; // Temperature controller I gain
p_rTempKd : REAL := 0.1; // Temperature controller D gain
p_rPressKp : REAL := 2.0; // Pressure controller P gain
p_rPressKi : REAL := 0.3; // Pressure controller I gain
p_rPressKd : REAL := 0.05; // Pressure controller D gain
p_rFlowKp : REAL := 1.0; // Flow controller P gain
p_rFlowKi : REAL := 0.15; // Flow controller I gain
p_rFlowKd : REAL := 0.0; // Flow controller D gain
p_rLevelKp : REAL := 3.0; // Level controller P gain
p_rLevelKi : REAL := 0.25; // Level controller I gain
p_rLevelKd : REAL := 0.1; // Level controller D gain
// Alarm Thresholds
p_rTempHighLimit : REAL := 80.0; // Temperature high limit
p_rTempLowLimit : REAL := 5.0; // Temperature low limit
p_rPressHighLimit : REAL := 5.0; // Pressure high limit
p_rPressLowLimit : REAL := 0.5; // Pressure low limit
p_rFlowHighLimit : REAL := 200.0; // Flow high limit
p_rFlowLowLimit : REAL := 10.0; // Flow low limit
p_rLevelHighLimit : REAL := 90.0; // Level high limit
p_rLevelLowLimit : REAL := 10.0; // Level low limit
END_VAR""")
# Create a constant Global Variable List
const_gvl = app.create_gvl("GVL_Constants")
# Define the constant global variables
const_gvl.textual_declaration.replace("""VAR_GLOBAL CONSTANT
// System Constants
c_iMaxDevices : INT := 10; // Maximum number of devices
c_iMaxAlarms : INT := 100; // Maximum number of alarms
// Physical Constants
c_rGravity : REAL := 9.81; // Gravity acceleration (m/s²)
c_rWaterDensity : REAL := 1000.0; // Water density (kg/m³)
c_rAirDensity : REAL := 1.225; // Air density at sea level (kg/m³)
// Conversion Factors
c_rPa_To_Bar : REAL := 0.00001; // Pascal to Bar conversion
c_rBar_To_PSI : REAL := 14.5038; // Bar to PSI conversion
c_rLiter_To_M3 : REAL := 0.001; // Liter to cubic meter conversion
// Time Constants
c_tMaxRunTime : TIME := T#24H; // Maximum continuous run time
c_tMaintenanceInterval : TIME := T#720H; // Maintenance interval (30 days)
END_VAR""")
print("Global Variable Lists created successfully!")
Simulation mode:
# set device to simulation mode - this only check Simulation mark in the online tab
devs = proj.find('testdev') # type here project name up to Application
devs[0].set_simulation_mode(True)
# alternatively check the sim is enabled beforehand and turn it on if not yet enabled
devs = proj.find('testdev')
if len(devs) > 0:
# check if sim is enabled
cur_sim_mode = devs[0].get_simulation_mode()
print(cur_sim_mode)
# enable sim conditionally
if not cur_sim_mode:
devs[0].set_simulation_mode(True)
If you want to fully discover the potential of the Python Scripting Engine in CODESYS and understand how to streamline process automation with insights from Claude Sonnet, be sure to check out Part 2 of the article. There, you’ll learn how to apply the acquired knowledge in practice and harness the advanced capabilities of this tool.