Welcome to our new forum
All users of the legacy CODESYS Forums, please create a new account at account.codesys.com. But make sure to use the same E-Mail address as in the old Forum. Then your posts will be matched. Close

Scripting - examples and receipes

Anonymous
2011-05-05
2020-02-24
1 2 > >> (Page 1 of 2)
  • Anonymous - 2011-05-05

    Originally created by: M.Schaber

    In this thread we would like to collect samples and recipes to show you how to implement more complex procedures in the CoDeSys script language.

     
  • Anonymous - 2011-05-05

    Originally created by: M.Schaber

    This example is a further development of example 1 from the documentation.

    Purpose: To read a controller variable out of an external program or a batch file and to print it on the standard display so that it can be evaluated, e.g.:

    C:\Program Files\3S CoDeSys V3.4 SP3\CoDeSys\Common>start /wait CoDeSys.exe --profile="CoDeSys V3.4 SP3" --noUI --runscript="D:\TestScripts\ReadVariable.py" 
    

    This is the actual code:

    \# We use the python 3 syntax for print
    from __future__ import print_function
       
    \# Our project file is in the data subdirectory of the directory containing
    \# the script, so we calculate the appropriate path.
    import os
    scriptdir = os.path.dirname(__file__) # Directory of our script.
    datadir = os.path.join(scriptdir, "Data") # Enter the subdirectory.
    projectpath = os.path.join(datadir, "Ampel.project") # And add the project name.
    \# Now, we can open the project.
    proj = projects.open(projectpath)
    \# We fetch the active application.
    app = proj.active_application
    \# And create the online application for it.
    onlineapp = online.create_online_application(app)
    \# We login into the device.
    onlineapp.login(OnlineChangeOption.Try, True)
    \# We start the application, if necessary.
    if not onlineapp.application_state == ApplicationState.run:
        onlineapp.start()
    \# We let the app do its work for some time...
    system.delay(1000)
    \# We read the value of the variable we're interested in.
    value = onlineapp.read_value("PLC_PRG.iVar1")
    \# We output the value to standard output, so our caller can process it.
    print(value)
    \# Last but not least, we clean up.
    onlineapp.logout()
    proj.close()
    

    In a windows command window, this looks as follows:

    C:\Program Files\3S CoDeSys V3.4 SP3\CoDeSys\Common>start /wait CoDeSys --profile="CoDeSys V3.4 SP3" --noUI --runscript="D:\TestScripts\Forum_ReadVariable.py"
    ------ Build started: Application: Device.App -------
    The application is up to date
    Build: Information: Size of generated code: 6419 bytes
    Build: Information: Size of global data: 2594 bytes
    Build: Information: Total allocated memory size for code and data: 10997 bytes
    Build: Information: Memory area 0 contains  Data, Input, Output, Memory and Code
    : highest used address: 1048576, largest contiguous memory gap: 1037579 (98 %)
    Compile complete -- 0 errors, 0 warnings
    INT#2263
    C:\Program Files\3S CoDeSys V3.4 SP3\CoDeSys\Common>
    
     
  • Anonymous - 2011-05-05

    Originally created by: M.Schaber

    Expecially when one calls Scripts from the command line interpreter, a possibility to pass parameters to the scripts would be handy.

    As a workaroound, one can use environment variables:

    from __future__ import print_function
    import os
    print("project to open: ", os.environ["PROJECT"])
    \# We assert that the application on the device is already running.
    proj = projects.open(os.environ["PROJECT"])
    onlineapp = online.create_online_application(proj.active_application)
    onlineapp.login(OnlineChangeOption.Try, True)
    print("variables to read:")
    for var in os.environ["VARIABLES"].split(","):
       print ("    ", var, " = ", onlineapp.read_value(var))
    

    This can be launched from a batch file as follows:

    @echo off
    SET PROJECT=D:\TestScripts\Data\OnlineTest.project
    SET VARIABLES=POU.testint,POU.testoutput
    start /wait CoDeSys.exe --profile="CoDeSys V3.4 SP3" --noUI --runscript="D:\TestScripts\Forum_Environment.py"
    

    The result looks like this:

    C:\Program Files\3S CoDeSys V3.4 SP3\CoDeSys\Common>d:\TestScripts\Forum_Environment.bat
    project to openD:\TestScripts\Data\OnlineTest.project
    ------ Build started: Application: CoDeSys_Control_Win_V3.Application -------
    The application is up to date
    Build: Information: Size of generated code: 6453 bytes
    Build: Information: Size of global data: 2606 bytes
    Build: Information: Total allocated memory size for code and data: 12505 bytes
    Build: Information: Memory area 0 contains  Data, Input, Output, Memory and Code: highest used address: 1048576, largest contiguous memory gap: 1036071 (98 %)
    Compile complete -- 0 errors, 0 warnings
    variables to read:
         POU.testint  =  INT#1
         POU.testoutput  =  INT#3
    C:\Program Files\3S CoDeSys V3.4 SP3\CoDeSys\Common>
    
     
  • Anonymous - 2011-05-05

    Originally created by: M.Schaber

    Currently, scripts can add devices only via the Device ID. If one doesn't know the ID of a specific device, the following script can help to find out. Just insert the device into the current project, and launch the script:

    \# Prints out all devices and other objects in the currently open project.
    \# We enable the new python 3 print syntax
    from __future__ import print_function
    \# define the printing function
    def printtree(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(child, depth+1)
    for obj in projects.primary.get_children():
       printtree(obj)
    print("--- Script finished. ---")
    

    The output looks like this:

    - CoDeSys_Control_Win_V3 DeviceID(type=4096, Id='0000 0001', Version='3.4.2.0')
       - CANbus DeviceID(type=15, Id='181015', Version='3.4.2.0')
          - CANopen_Manager DeviceID(type=16, Id='181016', Version='3.4.2.0')
    --- Script finished. ---
    

    And now you know the Device ID you needed.

     
  • Anonymous - 2011-05-05

    Originally created by: M.Schaber

    Some users want to fetch the starting basis for their projects from a Subversion repository.

    The following example (which is similar to Example 4 in the documentation) creates a new project, and adds a device via PLCOpenXML.

    \# Imports a Device in PLCOpenXML from Subversion via command line svn client.
    \# We enable the new python 3 print syntax
    from __future__ import print_function
    import sys, os
    \# some variable definitions:
    SVNEXE = r"C:\Program Files\Subversion\bin\svn.exe"
    XMLURL = "file:///D:/testrepo/testfolder/TestExport.xml"
    PROJECT = r"D:\test.project"
    \# clean up any open project:
    if projects.primary:
       projects.primary.close()
    \# Fetch the plcopenxml data from subversion. 
    \# The 'with' construct automatically closes the open pipe for us.
    with os.popen('"' + SVNEXE + '" cat ' + XMLURL, 'r') as pipe:
       xmldata = pipe.read()
    \# create a new project:
    proj = projects.create(PROJECT)
    \# create the import reporter
    class Reporter(ImportReporter):
       def error(self, message):
          system.write_message(Severity.Error, message)
       def warning(self, message):
          system.write_message(Severity.Warning, message)
       
       def resolve_conflict(self, obj):
          return ConflictResolve.Copy
       
       def added(self, obj):
          print("added: ", obj)
       def replaced(self, obj):
          print("replaced: ", obj)
       def skipped(self, obj):
          print("skipped: ", obj)
          
       @property
       def aborting(self):
          return False
    \# create the importer instance.
    reporter = Reporter()      
    \# import the data into the project.
    proj.import_xml(reporter, xmldata)
    \# and finally save. :-)
    proj.save()
    print("--- Script finished. ---")
    

    The subversion command line client which is needed for the script above is available for free from several providers. The Subversion Download Page contains links to some of them, the Cygwin-Project contains another one.

     
  • Anonymous - 2011-08-02

    Originally created by: M.Schaber

    Example snippets: Quickly finding library managers:

    Find all library managers in the project:

    objects = proj.get_children(recursive=True)
    for candidate in objects:
        if candidate.is_libman:    
            print(candidate)
    

    The quick way is via list comprehension:

    managers = [i for i in proj.get_children(True) if i.is_libman]
    

    Or via the filter function:

    managers = filter(lambda i: i.is_libman, proj.get_children(True))
    

    If you are only interested in the top level library manager (the one in the POU view), you set recursive to False.

    Remind that you can also search under a specific device or application if you call get_children on that object instead of the project.

     
  • TimvH

    TimvH - 2011-08-02

    About the device ID (for automatically inserting devices to your project):

    Since 3.4.4.0 you can go to the information tab of the device which shows all details like type, ID and version.
    This makes it much easier than first creating a script to get this information.

     
  • Anonymous - 2011-08-02

    Originally created by: M.Schaber

    TimvH hat geschrieben:
    About the device ID (for automatically inserting devices to your project):
    Since 3.4.4.0 you can go to the information tab of the device which shows all details like type, ID and version.
    This makes it much easier than first creating a script to get this information.

    It seems you're right, but unfortunately, it seems that module IDs are not displayed there.

     
  • aoj - 2011-10-06

    Hi hi,

    i was trying to understand the following code:

    # We use the python 3 syntax for print
    from future import print_function

    # Our project file is in the data subdirectory of the directory containing
    # the script, so we calculate the appropriate path.
    import os
    scriptdir = os.path.dirname(file) # Directory of our script.
    datadir = os.path.join(scriptdir, "Data") # Enter the subdirectory.
    projectpath = os.path.join(datadir, "Ampel.project") # And add the project name.
    ...................................

    but I recieve always the following error: NameError: name 'projects' is not defined
    could u help please and tell me how to correct it?
    Thank you

     
  • Anonymous - 2011-10-07

    Originally created by: M.Schaber

    Hi,

    aoj hat geschrieben:
    i was trying to understand the following code:
    # We use the python 3 syntax for print
    from future import print_function

    This statement enables the python 3 syntax for print (See the python documentation for more details). I use this syntax so that this script can run with both Python 2 and python 3 without modifications.

    aoj hat geschrieben:
    # Our project file is in the data subdirectory of the directory containing
    # the script, so we calculate the appropriate path.
    import os
    scriptdir = os.path.dirname(file) # Directory of our script.
    datadir = os.path.join(scriptdir, "Data") # Enter the subdirectory.
    projectpath = os.path.join(datadir, "Ampel.project") # And add the project name.
    ...................................

    This code calculates the location of the project "Ampel.project" relative to the directory where the script itsself is. It assumes that in the directory containing the script file there is a subdirectory "Data" containing the "Ampel.project" file. This just happens to be the directory layout I used for my internal test scripts.

    aoj hat geschrieben:
    but I recieve always the following error:
    could u help please and tell me how to correct it?

    "projects" is an object imported into the namespace for scripts running in CoDeSys, so it is only available if your script is being started in CoDeSys directly (either via the "Execute Script" menu command or button, or via the "--runscript" command line parameter.)

    For modules imported by your scripts, this automatic injection does not take place because it would break some modules from the standard library. Simply add "from scriptengine import *" at the top of your module.

    If you run the script from outside of CoDeSys (for example in the py.exe or ipy.exe interpreters, or an IDE like IDLE or Eric), it won't work, since the codesys environment is not available there.

    But remember that you can start CoDeSys with the "--runscript" and "--NoUI" parameters to execute python scripts within CoDeSys. (See the documentation for more information.)

     
  • aoj - 2011-10-07

    Hi Hi,

    thank u for the reply.

    "If you run the script from outside of CoDeSys (for example in the py.exe or ipy.exe interpreters, or an IDE like IDLE or Eric), it won't work, since the codesys environment is not available there."
    I run the script from IDLE! It means it won't work.

    I want actually to export a xml-file with python. I have a CoDeSys-Project named Test.project. The first step ist to open this project, which i did with "os.startfile". The second step is to export the xml-file directly from python.

    Could you give some tips??

     
  • Anonymous - 2011-10-07

    Originally created by: M.Schaber

    Hi,

    aoj hat geschrieben:
    "If you run the script from outside of CoDeSys (for example in the py.exe or ipy.exe interpreters, or an IDE like IDLE or Eric), it won't work, since the codesys environment is not available there."
    I run the script from IDLE! It means it won't work.

    Yes. If you run the script from IDLE, it has no way to access the CoDeSys functionality. The CoDeSys ScriptEngine is not a bunch of ordinary python modules, but a so-called hosted environment, that means the Python interpreter is embedded (and deeply integrated) into the CoDeSys application.

    aoj hat geschrieben:
    I want actually to export a xml-file with python. I have a CoDeSys-Project named Test.project. The first step ist to open this project, which i did with "os.startfile". The second step is to export the xml-file directly from python.
    Could you give some tips??

    Ah, now I see. Your current approach would require the Python script from IDLE to magically recognize the running CoDeSys instance, and then send the commands to that application. Unfortunately, that is not how it currently works. (Note that os.startfile() gives you no way to wait for the application to finish startup and loading, so you would not know when you could actually start to send commands to CoDeSys.)

    What you currently could do is something like ```

    os.system(r'c:\Path\to\CoDeSys.exe --runscript="c:\Path\to\CoDeSysScript.py"')

    ``` and use an environment variable to pass the name of the CoDeSys project to the script. (See l viewtopic.php?p=3803#p3803 l for an example of parameter passing via environment variables.) Then, in the CoDeSysScript.py, you can load the project and export the files.

     
  • aoj - 2011-10-10

    Hi M.Schaber,

    if i use the code: os.system(r'c:\Path\to\CoDeSys.exe --runscript="c:\Path\to\CoDeSysScript.py"' and in my CoDeSysScript.py should only open the project Test.project; is it fine to use os.startfile()??? or is there a better command to load the project?

    Another question: what is the difference between using PLCOpenXML and using the native Export format of CoDeSys?

    Thanks a lot.

     
  • Anonymous - 2011-10-10

    Originally created by: M.Schaber

    Hi, Aoj,

    aoj hat geschrieben:
    if i use the code: os.system(r'c:\Path\to\CoDeSys.exe --runscript="c:\Path\to\CoDeSysScript.py"' and in my CoDeSysScript.py should only open the project Test.project; is it fine to use os.startfile()??? or is there a better command to load the project?

    Inside the CoDeSysScript.py, do not use os.startfile(). That will start a second instance of codesys loading the project, and you still don't have control over that second instance.

    You need to open the project and do the export from within the CoDeSysScript.py. This may look like:

    \# .. initialization skipped
    proj = projects.open(PathToProject)
    device = proj.find('_3S_Testspec_Device')[0]
    device.export_xml(reporter, ExportFileName, recursive = True)
    

    projects.open, and the find and export_xml methods are provided by the CoDeSys environment.

    aoj hat geschrieben:
    Another question: what is the difference between using PLCOpenXML and using the native Export format of CoDeSys?

    PLCOpenXML is a standardized format for interchange of data between independent IEC-61131 implementations. Due to that, it is interoperable with other software, but it is not lossless (some aspects may be lost if you export in that format).

    The native Export format is CoDeSys-specific and less human-readable, but it is lossless.

    So if you only use those exported objects for re-importing them into CoDeSys later, you use the native format. If you want to process those files using 3rd-party tools, you should use the PLCOpenXML format.

     
  • aoj - 2011-10-10

    Thank you for the explanation about the difference between the PLCOpenXML and the native export format.

    in a previous post we talked about the error: "NameError: name 'projects' is not defined".
    you said i can correct this error by adding "from scriptengine import *" at the top of the module in condition i am starting CoDeSys with the "--runscript".

    after adding "from scriptengine import *", i get the following error: "ImportError: No module named scriptengine" !!!!

     
  • Anonymous - 2011-10-10

    Originally created by: M.Schaber

    aoj hat geschrieben:
    in a previous post we talked about the error: "NameError: name 'projects' is not defined".
    you said i can correct this error by adding "from scriptengine import *" at the top of the module in condition i am starting CoDeSys with the "--runscript".

    It seems that you did misunderstand what I wrote. This works if used inside a python module which is imported by a script running inside CoDeSys, but it is not necessary for the main script itsself (the one whose name you pass to --runscript).

    aoj hat geschrieben:
    after adding "from scriptengine import *", i get the following error: "ImportError: No module named scriptengine" !!!!

    Is this in the script running inside CoDeSys, or is it the outer script you use to start CoDeSys?

     
  • aoj - 2011-10-10

    it is the the script, which i use to start CoDeSys.

    i have to write a script, which it starts a CoDeSys-project and export it as xml.

     
  • Anonymous - 2011-10-10

    Originally created by: M.Schaber

    aoj hat geschrieben:
    it is the the script, which i use to start CoDeSys.

    Then it is in the wrong script. It should be in the script running inside CoDeSys.

    aoj hat geschrieben:
    i have to write a script, which it starts a CoDeSys-project and export it as xml.

    As I told you, you cannot command CoDeSys to export a file as XML "from outside". The way to achieve that goal is to start a CoDeSys instance with the "--runscript" parameter, which makes CoDeSys executing the script you pass via --runscript inside the CoDeSys environment. Then this script running inside CoDeSys can perform the opening of the project and exporting of XML.

    To rephrase it again in other words: You need two scripts:

    All CoDeSys specific commands like projects.open or export_xml are only available to scripts running inside CoDeSys (the '' script). CoDeSys itsself must be executing that script using the built-in IronPython interpreter so that the script has access to all the CoDeSys commands. This concept is called a "Hosted Environment" or an "Embedded Interpreter".

     
  • nfredrik - 2011-10-11

    Hi,

    a question about reading a variable with a python script. I get an exception (not a builtin one)
    when I trying to read a variable (inte) in a program unit, PLC_PRG.

    .
    ..
    ...
    # read value of inte
    value = onlineapp.read_value("PLC_PRG.inte")

    [INFORMATION] test.py(25): exception (<type 'exceptions.exception'="">,
    Exception('Invalid expression',), None)</type>

    The variable is declared:
    PROGRAM PLC_PRG
    VAR
    inte: INT;
    END_VAR

    .
    ..
    ...
    int := 42;

    How come?

    The whole trace on the script (a modified example script) looks like this:

    [INFORMATION] test.py(4): Begin of script
    [INFORMATION] test.py(4): while len(projects.all) > 0:
    [INFORMATION] test.py(5): projects.all[0].close()
    [INFORMATION] test.py(8): proj = projects.open("C:\python\
    \ObserverPattern.project")
    [INFORMATION] test.py(11): app = proj.active_application
    [INFORMATION] test.py(12): onlineapp =
    online.create_online_application(app)
    [INFORMATION] test.py(15): onlineapp.login(OnlineChangeOption.Try,
    True)
    [INFORMATION] test.py(18): if not onlineapp.application_state ==
    ApplicationState.run:
    [INFORMATION] test.py(19): onlineapp.start()
    [INFORMATION] test.py(22): system.delay(1000)
    [INFORMATION] test.py(25): value =
    onlineapp.read_value("PLC_PRG.inte")
    [INFORMATION] test.py(25): exception (<type 'exceptions.exception'="">,
    Exception('Invalid expression',), None)</type>

    Fredrik

     
  • Anonymous - 2011-10-11

    Originally created by: M.Schaber

    Hi,

    nfredrik hat geschrieben:
    a question about reading a variable with a python script. I get an exception (not a builtin one)
    when I trying to read a variable (inte) in a program unit, PLC_PRG.
    # read value of inte
    value = onlineapp.read_value("PLC_PRG.inte")

    As far as I can see, it should work this way. Could you please send me the project archive and script via our support contact, so I can investigate that case further? Thanks!

     
  • aoj - 2011-10-12

    Hallo M. Schaber,

    first of all I want to thank you very much for yout help.

    I have wrote a Python-script, which it execute CoDeSys and call a second scipt. This second script opens A CoDeSys-Project and should export it as XML. But after opening the CoDeSys-Project I got an Error:

    What does this Error mean and how can I correct it?

    IMG: Error.JPG

     
  • Anonymous - 2011-10-12

    Originally created by: M.Schaber

    aoj hat geschrieben:
    first of all I want to thank you very much for yout help.

    You're welcome!

    aoj hat geschrieben:
    I have wrote a Python-script, which it execute CoDeSys and call a second scipt. This second script opens A CoDeSys-Project and should export it as XML. But after opening the CoDeSys-Project I got an Error:
    What does this Error mean and how can I correct it?

    The error message shows an ArgumentOutOfRangeException. That means that some code accessed some array or list via an index which was out of range.

    I don't know your script, so it's hard to diagnose the problem, but maybe you did use a construct like ```

    device = proj.find('_3S_Testspec_Device')[0]

    ``` and there is no object with that name. In that case, find returns an empty list, so the index access with [0] fails.

    You should enable script tracing to find out which line of the code is the one causing the error.

    Yours, Markus

    PS: To enable script tracing, you have three options:

     
  • aoj - 2011-10-12

    you are right, the error is because of device = proj.find('_3S_Testspec_Device')[0].

    What for is "_3S_Testspec_Device"?

     
  • Anonymous - 2011-10-12

    Originally created by: M.Schaber

    Hi,

    aoj hat geschrieben:
    you are right, the error is because of .
    What for is "_3S_Testspec_Device"?

    "_3S_Testspec_Device" is the name of the device object I want to find.

    The find() function returns a list of all objects it found with that name.

    The reason why find() returns a list is that some objects (like folders) can have the same names, so a find() can return several objects.

    If you want to export the complete project, you should call the export_xml or export_native methods of the proj object instead.

     
  • aoj - 2011-10-13

    Hali Halo,

    I am trying now with the following script:
    [img]
    from future import print_function
    from scriptengine import *

    import sys, io, utils
    utils.ensure_tempdir()
    utils.close_all()

    system.trace = True
    proj = projects.open(utils.data('.........../Test.project'))

    class ExportHandler(NativeExportReporter):
    def cancel(self, message):
    system.write_message(Severity.Error, "Cancelling export: %s" % message)

    def warn(self, message):   
        system.write_message(Severity.Warning, "Warning exporting %s: %s" % message)
    
    def skipped(self, type_name, value_name):   
        system.write_message(Severity.Information, "Object not exportable: %s value %s" % (type_name, value_name))
    

    reporter = ExportHandler()

    proj.export_native("....../FileName.export", recursive = True, reporter = reporter)
    [/img]

    The script open the CoDeSys-Project and show the following error:

    Zitat:

    What does this error mean and what could be the solution?

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.