Skip to main content

Using the Trace Scripting Interface

The CODESYS Trace add-on provides a scripting interface. Below you will find examples of how to use this interface.

Creating a Trace

# a new trace can be created using the toplevel trace api
myApplication = projects.primary.find("Device", "PLC Logic", "Application")[0]
traceObject = trace.create(myApplication, "MyTraceName")
traceObject.task_name = "Task" # a task with the name "Task" should already exist here. If it does not exist, this assignment throws an ValueError.
# the task of the trace can be set during creation
myApplication = projects.primary.find("Device", "PLC Logic", "Application")[0]
traceObjectWithTaskSet = trace.create(myApplication, "NameOfMySecondTrace", "MainTask")
assert traceObjectWithTaskSet.task_name == "MainTask"

Finding and verifying existing traces

# finding an existing trace can be done via the project.find method
foundObjects = projects.primary.find("Device", "PLC Logic", "Application", "MyTraceObject")
expectedTraceObject = foundObjects[0]
assert expectedTraceObject.is_trace_object, "Could not find trace object with the expected name" # .is_trace_object is False for all other objects of type IScriptObject

Adding and changing trace variables

myTrace = projects.primary.find("Device", "PLC Logic", "Application", "MyTraceObject")[0]

# add_variable() is a convenience method to add a new ScriptTraceVariable and set its properties during creation
addedVariable = myTrace.add_trace_variable(variableName="PLC_PRG.a1",
    graphColor= 0xff000000,
    graphType=GraphType.LINES,
    activateMaxWarning=True,
    maxWarningArea=9.0,
    maxColor= 0xffff0000)

addedVariable.enabled = False

for i in range(2,11):
    newVariable = myTrace.variable_list.add()
    newVariable.variable_name = "PLC_PRG.a"+str(i)
    newVariable.graph_type = GraphType.LINES_CROSSES

assert len(myTrace.variable_list) == 10

Changing the ScriptTrace variable list

Removing a specific ScriptTrace variable

The following code snippet finds the variable with the specified name and removes it from the ScriptTrace variable list.

def remove_variable_by_name(traceObject, variableName):
    index_to_remove = -1
    for variable in traceObject.variable_list:
        if variable.variable_name == variableName:
            index_to_remove = traceObject.variable_list.index_of(variable)
            break
        if index_to_remove != -1:
            traceObject.variable_list.remove(index_to_remove)

Changing the recording settings

Setting the resolution (ms/µs) of the trace recording

The following code snippet is based on the ??? snippet.

traceObject.resolution = Resolution.MicroSeconds
# Use Resolution.MilliSeconds if you want to have a trace recording based on milliseconds

Setting the recording condition

The following code snippet is based on the ??? snippet.

traceObject.record_condition = "PLC_PRG.bDoRecord"

Setting the comment

The following code snippet is based on the ??? snippet.

traceObject.comment = "This trace records the ..."

Setting the autostart option

The following code snippet is based on the ??? snippet.

traceObject.auto_start = True

Setting the option to record only every n-th cycle

The following code snippet is based on the ??? snippet.

traceObject.every_n_cycles = 10

Diagrams and Their Variables

Creating a ScriptTrace chart with all ScriptTrace variables

The following script shows how to create a simple diagram and its variables.

# first we need a ScriptTraceObject and some ScriptTraceVariables
traceObject = projects.primary.find("Device","PLC Logic","Application","Trace")[0]
assert traceObject.is_trace_object
for i in range(5):
    traceObject.add_trace_variable(variableName="PLC_PRG.a"+str(i))

# create one ScriptTraceDiagram and add all ScriptTraceVariables to it
traceDiagram = traceObject.diagrams.add()
for traceVar in traceObject.variable_list:
    traceDiagram.add_diagram_variable(traceVar)

Creating a ScriptTrace diagram per ScriptTrace variable

The following Python method takes one ScriptTrace object and adds a diagram per ScriptTrace variable.

def one_diagram_per_variable(traceObject):
    assert traceObject.is_trace_object
    for traceVar in traceObject.variable_list:
        diagram = traceObject.diagrams.add(traceVar)
        diagram.name = traceVar.variable_name

Copying the Settings of a ScriptTrace Diagram

The following script shows how to modify and copy the settings of a ScriptTrace diagram.

# we assume, that the traceObject already has multiple diagrams
traceObject = projects.primary.find("Device","PLC Logic","Application","Trace")[0]
assert traceObject.is_trace_object

# apply settings for the first diagram
traceObject.diagrams[0].y_axis.mode = AxisScaleMode.FixedLength
traceObject.diagrams[0].y_axis.range = 10.0
traceObject.diagrams[0].y_axis.color = 0xffee0000
traceObject.diagrams[0].y_axis.draw_grid = True
traceObject.diagrams[0].y_axis.grid_color = 0xffee0000
traceObject.diagrams[0].tickmark_fixed_spacing = True
traceObject.diagrams[0].tickmark_fixed_distance = 5.0
traceObject.diagrams[0].tickmark_fixed_subdivisions = 4

# copy the settings from the first diagrams to all other diagrams
for i in range(1,len(traceObject.diagrams))    
    traceObject.diagrams[i].y_axis.copy_from(traceObject.diagrams[0])

Online Handling of Trace

Downloading and starting the trace

The following code snippet finds the Trace trace of the Application application, downloads it, and starts it.

proj = projects.open(r"<Path to the project file>")
app = proj.find("Device", "PLC Logic", "Application")[0]
with online.create_online_application(app) as onlineapp:
    traceObject = proj.find("Device", "PLC Logic", "Application", "Trace")[0]
    onlineapp.login(OnlineChangeOption.Never, True)
    onlineapp.start()
    editor = traceObject.open_editor()
    editor.download()
    editor.start()

Saving the trace in a file

The following code snippet is based on the Downloading and starting the trace snippet. A trace must be stopped before it can be saved. This can be done either by reaching the trigger condition or by an explicit call of stop().

# We assume, that we have an already running trace
editor.stop()
editor.save(r"<File path to csv file>")

Querying various information for trace recording

The following code snippet is based on the Downloading and starting the trace snippet.

# We assume, that we have an already running trace
print("Packet State: {}".format(editor.get_packet_state()))
print("Trace started at {} (absolute timestamp)".format(editor.get_trace_start_timetamp()))

Trigger Handling

Configuring a BOOL trigger

traceObject = proj.find("Device", "PLC Logic", "Application", "Trace")[0]
traceObject.trigger_variable = "PLC_PRG.bVar"
traceObject.trigger_edge = TriggerEdge.Positive
traceObject.post_trigger_samples = 20

# The trigger level is only needed for numeric trigger variables. It is a good coding style to set the trigger explicitly to "None"
traceObject.trigger_level = None

Configuring a numeric trigger

traceObject = proj.find("Device", "PLC Logic", "Application", "Trace")[0]
traceObject.trigger_variable = "PLC_PRG.iTemperature"
traceObject.trigger_edge = TriggerEdge.PositivetraceObject.post_trigger_samples = 20

# In case of a trigger variable of REAL or LREAL type it is also possible to specify floating point trigger levels, e.g. 80.5
traceObject.trigger_level = 80

Waiting for a trigger and saving the recorded data

The following code snippet is based on the “Configuring a BOOL-triggers” and “Configuring a * trigger” snippets.

triggerstate = editor.get_trigger_state()
while triggerstate != TriggerState.TriggerReached:
    system.delay(200)
    triggerstate = editor.get_trigger_state()
    editor.save(r"<File path to csv file>")

Querying timestamp information after the trigger has been reached

The following code snippet is based on the “Configuring a BOOL-Trigger” and “Configuring a * Trigger” snippets.

print("Trigger reached at {} (absolute timestamp)".format(editor.get_trigger_timetamp()))
print("Trigger reached at {}".format(editor.get_trigger_startdate()))
print("Trace was running {}ms until trigger has been reached".format(editor.get_trigger_timetamp() - editor.get_trace_start_timetamp()))

Resuming the trace recording after reaching the trigger

The following code snippet is based on the “Configuring a BOOL-Trigger” and “Configuring a * Trigger" snippets.

editor.reset_trigger()

Device Trace

Creating a DeviceTrace

myDevice = projects.primary.find("Device")[0]
devicetrace = trace.create(myDevice, "DeviceTrace")

Querying the current trace recordings of the device

The following code snippet is based on the “Create a DeviceTrace“ snippet.

traceObject = projects.primary.find("Device", "DeviceTrace")[0]

# for application traces the result of get_online_traces contains only the traces of the application
# traceObject = projects.primary.find("Device", "PLC Logic", "Application", "Trace")[0]
editor = traceObject.open_editor()
for tracepacket in editor.get_online_traces():
    print(tracepacket)

Downloading an existing recording to the DeviceTrace

The following code snippet is based on the “Create a DeviceTrace“ snippet.

traceObject = projects.primary.find("Device", "DeviceTrace")[0]
editor = traceObject.open_editor()
editor.upload_to_device_trace("CpuCoreLoad")

What doesn't work with the DeviceTrace

  • Access to traceobject.variable_list

  • Creation of trace variables using traceobject.add_variable())

  • Access to traceobject.diagrams