使用脚本访问 CODESYS 功能
所有对象和命令 CODESYS 提供脚本编写也可在“scriptengine
" Python 模块。每当一个脚本启动时,一个隐式的 <code>from scriptengine import *</code>
结果。这允许轻松访问 CODESYS.但是,如果您的脚本导入需要访问的模块 CODESYS API,然后这些模块必须导入模块 scriptengine
他们自己。
在 Python 脚本中可用作入口点的主要对象(类别)如下表所示。入口点的详细文档可以在 API 参考文档 到 CODESYS 脚本引擎。
对象 | 描述 |
---|---|
系统 | 访问一般 CODESYS 功能 例子:
|
项目 | 访问 CODESYS 项目作为对象树,将三个导航器视图(设备、POU、模块)组合在一个项目树中 还允许加载、创建、保存和关闭项目 对于项目中的大多数对象,都有具有详细功能的特殊方法,例如编译、访问 ST POU、导出、导入、设备配置等。 |
在线的 | 访问在线功能 例子:
|
图书馆管理员 | 允许管理库存储库以及查看、安装和删除库 |
device_repository | 设备存储库的处理;设备描述的导入和导出 |
模块库 | 管理 CODESYS Application Composer 模块和 CODESYS Application Composer 存储库 |
有关访问的特定示例脚本,请参见下文 CODESYS- 功能。有关详细信息,请参阅 API 参考文档 到 CODESYS.
示例:打印当前项目的设备树
剧本 PrintDeviceTree.py
是在项目中导航的示例。它创建打开项目中所有设备的分层显示的输出。
加载一个包含一些设备对象的项目并执行脚本。
PrintDeviceTree.py
# encoding:utf-8 # We enable the new python 3 print syntax from __future__ import print_function # Prints out all devices in the currently open project. print("--- Printing the devices of the project: ---") # Define the printing function. This function starts with the # so called "docstring" which is the recommended way to document # functions in python. def print_tree(treeobj, depth=0): """ Print a device and all its children Arguments: treeobj -- the object to print depth -- The current depth within the tree (default 0). The argument 'depth' is used by recursive call and should not be supplied by the user. """ # if the current object is a device, we print the name and device identification. if treeobj.is_device: name = treeobj.get_name(False) deviceid = treeobj.get_device_identification() print("{0}- {1} {2}".format("--"*depth, name, deviceid)) # we recursively call the print_tree function for the child objects. for child in treeobj.get_children(False): print_tree(child, depth+1) # We iterate over all top level objects and call the print_tree function for them. for obj in projects.primary.get_children(): print_tree(obj) print("--- Script finished. ---")
设备树(来自“设备”视图)显示在消息视图中,所有非设备对象都被排除在外:

示例:读取变量
剧本 ReadVariable.py
登录设备并在必要时启动应用程序。然后是变量的值 PLC_PRG.iVar1
被读取和输出。要尝试该脚本,您必须修改项目路径和变量名称。
ReadVariable.py
# encoding:utf-8 from __future__ import print_function # close open project if necessary: if projects.primary: projects.primary.close() # opens project proj = projects.open(r"D:\data\projects\Ampel.project") # set "Ampel.project" to active application app = proj.active_application onlineapp = online.create_online_application(app) # login to device onlineapp.login(OnlineChangeOption.Try, True) # set status of application to "run", if not in "run" if not onlineapp.application_state == ApplicationState.run: onlineapp.start() # wait 1 second system.delay(1000) # read value of iVar1 value = onlineapp.read_value("PLC_PRG.iVar1") # display value in message view or command line print(value) # log out from device and close "Ampel.project" onlineapp.logout() proj.close()
在脚本的扩展中 ReadVariable.py
, 剧本 MailVariables.py
从配方文件加载变量和表达式,并从控制器读取它们的当前值。然后将这些值写回同一个文件。此外,它使用 Python SMTP 库发送带有包含所有变量列表的附件的电子邮件。
要使用该脚本,您必须根据您的环境修改 SMTP 服务器的路径、电子邮件地址和名称。
MailVariables.py
# encoding:utf-8 from __future__ import print_function # Close current project if necessary and open "ScriptTest.project" if not projects.primary == None: projects.primary.close() project = projects.open("D:\\Data\\projects\\scriptTest.project") # retrieve active application application = project.active_application # create online application online_application = online.create_online_application(application) # login to application. online_application.login(OnlineChangeOption.Try, True) # start PLC if necessary if not online_application.application_state == ApplicationState.run: online_application.start() # wait 2 seconds system.delay(2000) # open recipe file to read values. recipe_input_file = open("D:\\Data\\projects\\RecipeInput.txt", "r") watch_expressions = [] for watch_expression in recipe_input_file: watch_expressions.append(watch_expression.strip()) print watch_expressions # read values from the controllerd watch_values = online_application.read_values(watch_expressions) print watch_values # open output file to write values recipe_output_file = open("D:\\Data\\projects\\RecipeOutput.txt", "w") for i in range(len(watch_expressions)): recipe_output_file.write(watch_expressions[i]) recipe_output_file.write(" = ") recipe_output_file.write(watch_values[i]) recipe_output_file.write("\n") # Close files recipe_input_file.close() recipe_output_file.close() # send Email # import respective libraries import smtplib from email.mime.text import MIMEText #open output file recipe_output_file = open("D:\\Data\\projects\\RecipeOutput.txt", "r") mail = MIMEText(recipe_output_file.read()) recipe_output_file.close() #email address sender and recipient fromm = "info@example.com" to = "info@example.com" # set sender and recipient mail["Subject"] = "Attention value has changed" mail["From"] = fromm mail["To"] = to # send email smtp = smtplib.SMTP("name of smtp server") smtp.sendmail(fromm, [to], mail.as_string()) smtp.quit() # logout and close application online_application.logout() project.close()
示例:创建和编辑 POU
剧本 CreateDut.py
创建对象 MyStruct
, MyAlias
, 和 MyUnion
在里面 CODESYS 项目。文件夹 DataTypes
已经必须在场。
# encoding:utf-8 from __future__ import print_function STRUCT_CONTENT = """\ a : BOOL; b : BIT; c : BIT; """ UNION_WHOLE = """\ TYPE MyUnion : UNION Zahl : INT; Prozent : MyAlias; Bits : MyStruct; END_UNION END_TYPE """ proj = projects.primary folder = proj.find('DataTypes', recursive = True)[0] # Create a struct DUT and insert the list of variables just into the right # place in line two, row 0 (line numbering starts with line 0) struktur = folder.create_dut('MyStruct') # DutType.Structure is the default struktur.textual_declaration.insert(2, 0, STRUCT_CONTENT) # Alias types get their "content" via the base type, which will just end up # as one line in the declaration part: # TYPE MyAlias : INT (0..100); END_TYPE bereich = folder.create_dut('MyAlias', DutType.Alias, "INT (0..100)") # Instead of injecting the variables into the existing declaration, # one can also just replace the complete declaration part, including the # boilerplate code. union = folder.create_dut('MyUnion', DutType.Union) union.textual_declaration.replace(UNION_WHOLE)
示例:用户界面/与用户的交互
在某些情况下,脚本必须与用户交互。我们为最常见的交互提供了一些简单的 API。示例脚本 System_UI_Test.py
显示了这方面的所有可能功能。
System_UI_Test.py
# encoding:utf-8 from __future__ import print_function """Performs some tests on the messagestore and UI.""" print("Some Error, Warning and Information popups:") system.ui.error("Fatal error: Everything is OK. :-)") system.ui.warning("Your bank account is surprisingly low") system.ui.info("Just for your information: 42") print("Now, we ask the user something.") res = system.ui.prompt("Do you like this?", PromptChoice.YesNo, PromptResult.Yes); print("The user selected '%s'" % res) print("Now, the user can choose between custom options:") res = system.ui.choose("Please choose:", ("First", 2, 7.5, "Something else")) print("The user selected option '%s'" % str(res)) # res is a tuple print("Now, the user can choose several options:") res = system.ui.select_many("Please select one or more options", PromptChoice.OKCancel, PromptResult.OK, ("La Premiere", "The Second", "Das Dritte")) print("The returned result is: '%s'" % str(res)) # res is a tuple print("Now, the user can select files and directories") res = system.ui.open_file_dialog("Choose multiple files:", filter="Text files (*.txt)|*.txt|Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*", filter_index = 0, multiselect=True) print("The user did choose: '%s'" % str(res)) # res is a tuple as multiselect is true. res = system.ui.save_file_dialog("Choose a file to save:", filter="Text files (*.txt)|*.txt|Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*", filter_index = 0) print("The user did choose: '%s'" % res) res = system.ui.browse_directory_dialog("Choose a directory", path="C:\\") print("The user did choose: '%s'" % res) print("Now we query a single line string") res = system.ui.query_string("What's your name?") print("Nice to meet you, dear %s." % res) print("Now we query a multi line string") res = system.ui.query_string("Please tell me a nice story about your life!", multi_line=True) if (res): print("Huh, that has been a long text, at least %s characters!" % len(res)) else: print("Hey, don't be lazy!") print("Username and passwort prompts...") res = system.ui.query_password("Please enter your favourite password!", cancellable=True) if res: print("Huh, it's very careless to tell me your favourite password '%s'!" % res) else: print("Ok, if you don't want...") res = system.ui.query_credentials("Now, for real...") if res: print("Username '%s' and password '%s'" % res) # res is a 2-tuple else: print("Sigh...")
示例:操作 项目信息 目的
在脚本中 ProjectInfoExample.py
,我们在 项目信息 目的。最重要的信息项,例如 标题 和 版本, 具有显式性质。但是,您可以通过 dictionary
句法。例如,推荐用于库项目属性的那些。
下面的示例可能看起来有些不切实际,但类似的代码用于创建、测试和可能发布自动库项目和其他项目的构建服务器。 ScriptEngine 是创建 CI(持续集成)和 CD(持续交付)系统的关键元素之一。
ProjectInfoExample.py
# encoding:utf-8 from __future__ import print_function proj = projects.load("D:\Some.library") info = proj.get_project_info() # Set some values info.company = "Test Library Ltd" info.title = "Script Test Project" info.version = (0, 8, 15, 4711) info.default_namespace = "testlibrary" info.author = "Python von Scriptinger" # some values recommended in the library toolchain info.values["DefaultNamespace"] = "testlibrary" info.values["Placeholder"] = "testlibrary" info.values["DocFormat"] = "reStructuredText" # now we set a custom / vendor specific value. info.values["SpecialDeviceId"] = "PLC0815_4711" # Enable generation of Accessor functions, so the IEC # application can display the version in an info screen. info.change_accessor_generation(True) # And set the library to released info.released = True; proj.save()
示例:调用外部命令并导入 PLCOpenXML 文件
示例脚本 DeviceImportFromSVN.py
从外部程序(在本例中为 SVN 客户端)获取 PLCOpenXML 文件并将其导入新创建的 CODESYS 项目。
要使用该脚本,您必须修改环境的路径。
DeviceImportFromSVN.py
# encoding:utf-8 # 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. # We'll catch the output of the program into the xmldata variable. # 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) # import the data into the project. proj.import_xml(xmldata, False) # and finally save. :-) proj.save() print("--- Script finished. ---")
高级示例:从 SVN 调用库并将其安装在 CODESYS
以下示例脚本可以作为 CT(持续测试)环境的一部分执行库的调用和安装,以便对其进行测试。除了标准——CODESYS, 这 CODESYS SVN 附加组件也必须使用有效的许可证安装。
import tempfile if projects.primary: projects.primary.close() tempdir = tempfile.mkdtemp() URL = "svn://localhost/testrepo/trunk/SvnTestLibrary/" proj = svn.checkout(URL, tempdir, "testlibrary", as_library=True) proj.save() repo = librarymanager.repositories[0] librarymanager.install_library(proj.path, repo, True) proj.close()