Snippets

Admin Ingo aliazzz

Editing of Python scripts

CODESYS does not posses an internal Python script editor.
To edit python scripts there are more then enough alternatives available.
Offcourse you are free to use any tool that you wish, but we can give some suggestions (not exhaustive):

Notepad++
1. + Very small but variable installation footprint (dependent on extension choices)
2. - Only provides intellisense help on standard libraries
3. + Syntax highlighting
4. + Indentation help
5. + Quickly edit single files
6. - Less suited for larger projects

VS.Net Select the "Visual Studio IDE Community" version, install IronPython support via the installation proces.
1. - Large but variable installation footprint (heavily dependent on installation/extension choices)
2. + Provides very good intellisense help
3. + Syntax highlighting
4. + Indentation help
5. - Not well suited to edit single files
6. + Suited for large projects

PyCharm
1. + Medium but variable sized installation footprint (dependent on installation/extension choices)
2. + Provides very good intellisense
3. + Syntax highlighting
4. + Indentation help
5. - Not well suited to edit single files
6. + Suited for larger projects

TIP: you can opt to install notepad++ and VS.NET in tandem as they complement each other well
*Visual Studio Code can be an alternative, however, the CFORGE tool is developped using VS.NET, so your mileage may vary.

Help.codesys.com

As of CODESYS version 3.5.14.0, https://help.codesys.com/webapp/idx-scriptingengine;product=ScriptEngine;version=3.5.14.0 offers an exthaustive overview of the various available scripting objects and their possibilities.

Project

The provided codesnippets are conceptual examples without any liability.

Importing the CODESYS scripting objects into python

// Simple all-everything import:
from scriptengine import *

// Import only the needed objects:
from scriptengine import ImportReporter, OnlineChangeOption

// Import only the module itself:
import scriptengine 
// and then later in the code somewhere:
class Reporter(scriptengine.ImportReporter):

Open project

proj = projects.open(filepath)

Iterate Device Tree

def printtree_rec(treeobj, depth=0):
   name = treeobj.get_name(False)    
   if treeobj.is_device:
      deviceid = treeobj.get_device_identification()
      print("{0} - {1} {2}".format("--"*depth, name, deviceid))
   for child in treeobj.get_children(False):
      printtree_rec(child, depth+1)

def printTree(proj):
   for obj in proj.get_children():
      printtree_rec(obj)

Create an FB

  • Only Structured Text can be edited directly!
    For the graphical languages you have to import the POU from PLCopenXML or the codesys native format.
    See IScriptTextualObjectMarker, IScriptObjectWithTextualDeclaration, IScriptObjectWithTextualImplementation and IScriptTextDocument for the textual language and the methods importxml() and importnative() from IScriptObject2 and IScriptProject2 for the import. Find the Scripting object, for example withfind(), and use the method remove() to delete an object.
proj = projects.primary

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 a DUT

proj = projects.primary

found = proj.find("Application", True)

app = found[0]

myDUT = app.create_dut("STATE", DutType.Enumeration)     # add declaration of the ENUM 
      # here parameter "DutType" can be  DutType.Structure(default), DutType.Enumeration , DutType.Alias, DutType.Union .

implementation = myDUT.textual_declaration.replace("""TYPE STATE :
(
   Examples_INT := 0,    (* *)
   SEND,      (* Send messages *)
   READ,      (* Receive messages *)
   ERROR      (* error single *)
);
END_TYPE""")

Export as PLCOpen XML

class ER(ExportReporter):
    def error(self, object, message):   
        system.write_message(Severity.Error, "Error exporting %s: %s" % (object, message))
    def warning(self, object, message):   
        system.write_message(Severity.Warning, "Warning exporting %s: %s" % (object, message))
    def nonexportable(self, object):   
        system.write_message(Severity.Information, "Object not exportable: %s" % object)
    @property
    def aborting(self):
        return False;

reporter = ER()
proj = projects.open(filename)
proj.export_xml(reporter, proj.get_children(False), tempname, recursive = True)
proj.close()

Modify Properties / Compiler defines

# Find Object VICTIM in projecttree
victim = projects.primary.find("VICTIM", True)[0]
props = victim.build_properties

props.external = not props.external
props.enable_system_call = not props.enable_system_call
props.link_always = not props.link_always
props.exclude_from_build = not props.exclude_from_build
if ";FOOBAR" in props.compiler_defines:
        props.compiler_defines = props.compiler_defines.replace(";FOOBAR","")
else:
        props.compiler_defines = props.compiler_defines + ";FOOBAR"

Autogenerate Devices

Example of generating a modbus configuration from a configuration file:

print "Current project."
proj = projects.primary

# Search for all top-level devices in project

for dev in proj.get_children():
   if dev.is_device:
      f = open("C:\_d\Python\ModbusImport\ModbusConfiguratie.txt", "r")
      for line in f:
         tok = line.split(' ')
         print tok[1], tok[0]
         if "(COM)" in tok[1]:
            dev.add(tok[0], DeviceID(92, "0000 0001", "3.4.0.0"))
            subnodes = dev.get_children()
            master = subnodes[len(subnodes) - 1]
         elif "(ModbusMaster)" in tok[1]:
            master.add(tok[0], DeviceID(90, "0000 0002", "3.4.3.0"))
            subnodes = master.get_children()
            coupler = subnodes[len(subnodes) - 1]
         elif "(ModbusSlave)" in tok[1]:
            coupler.add(tok[0], DeviceID(91, "0000 0001", "3.4.0.0"))


print "script finished."

SVN checkout

def set_username(req):
    req.username = username
    req.password = password
    req.save = True # Optional

svn.auth_username_password += set_username
svn.checkout(url, dir, filename)
proj = projects.primary
proj.save_as(filename)

SVN commit

def set_username(req):
    req.username = username
    req.password = password
    req.save = True # Optional

svn.auth_username_password += set_username
svn.commit(message)

SVN update

def set_username(req):
    req.username = username
    req.password = password
    req.save = True # Optional

svn.auth_username_password += set_username
svn.update()

Add Device with Task Configuration

# 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')

Compiler

Check compile errors of libraries

CompileCategory = Guid("{97F48D64-A2A3-4856-B640-75C046E37EA9}")

# Clear messages from Build category
system.clear_messages(CompileCategory)

projects.primary.check_all_pool_objects()

# Get message objects which contain all the data
severities = {
   Severity.FatalError : "Fatal error", Severity.Error : "Error",
   Severity.Warning : "Warning", Severity.Information : "Information",
   Severity.Text : "Text"
   }

msgs = system.get_message_objects(CompileCategory, Severity.FatalError|Severity.Error)
for msg in msgs:
   sev = severities[msg.severity]
   print("{} {}{}: {}".format(sev, msg.prefix, msg.number, msg.text)

External Tools

Excel

Frame for interworking with excel:

    # load relevant clr
   import clr
   clr.AddReferenceByName("Microsoft.Office.Interop.Excel, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
   clr.AddReference("System")

   # import garbage collector
   from System import GC

   # import .NET library for Excel
   from Microsoft.Office.Interop import Excel
   excel = Excel.ApplicationClass()
   
   excel.Visible = False # makes the Excel application visible to the user
   excel.DisplayAlerts = False
   
   from System.Runtime.InteropServices import Marshal
   #excel = Marshal.GetActiveObject("Excel.Application") # <-- not sure about that one

   # finding a workbook that's already open
   workbooks = [wb for wb in excel.Workbooks if wb.FullName == filepath]
   if workbooks:
       workbook = workbooks[0]
   else:
      workbooks = excel.Workbooks
      workbook = workbooks.Open(filepath,False,True)
   workbook.Saved = True
      
   # select work sheet
   worksheets = workbook.Worksheets(sheetname)
   worksheet = worksheets.Range(worksheets.Cells(1,1),worksheets.Cells(maxRow,maxCol))
   worksheetDict = worksheet.Value2
   
   ...
   
   # Close workbook after readout
   workbook.Close(False)
   excel.Application.Quit()
   excel.Quit()
   Marshal.ReleaseComObject(worksheet)
   Marshal.ReleaseComObject(worksheets)
   Marshal.ReleaseComObject(workbook)
   Marshal.ReleaseComObject(workbooks)
   Marshal.ReleaseComObject(excel)
   workbook = None
   workbooks = None
   worksheet = None
   worksheets = None
   excel = None

   GC.Collect();
   GC.WaitForPendingFinalizers();

Related

Home: IndexMain