MetaFacture提供脚本的所有对象和命令也在Python模块“scriptengine”中。每当启动脚本时,导入from scriptengine import *的结果。这样可以轻松访问MetaFacture。但是,如果你的脚本导入了需要访问MetaFactureAPIs的模块,则这些模块必须自己导入模块scriptengine。
在下表中,你将找到可以在Python脚本中用作入口点的主要对象(类别)。有关入口点的全面文档,请参阅MetaFactureScriptEngine的API参考文档。
| 对象 | 描述 | 
| 系统 | 
 访问常规的MetaFacture功能,例如: 
  | 
| 工程 | 
 以对象树的形式访问MetaFacture工程,该对象树将一个项目树中的三个导航器视图(设备,POU,模块)组合在一起。还允许加载,创建,保存和关闭工程。 对于工程中的大多数对象,都有一些具有详细功能的特殊方法,例如编译,访问ST POU,导出,导入,设备配置等。  | 
| 在线 | 
 访问在线功能,例如: 
  | 
| 库管理器 | 允许管理库存储库以及查看,安装和删除库。 | 
| 设备存储库 | 设备存储库的处理; 导入和导出设备描述。 | 
| 模块存储 | MetaFacture Application Composer模块和MetaFacture Application Composer存储库的管理。 | 
有关访问MetaFacture功能的方法,请参见以下特定的示例脚本。有关详细信息,请参阅MetaFactureScriptEngine的API参考文档。
例如:打印当前工程的设备树
脚本PrintDeviceTree.py是在工程中导航的示例。它创建打开工程中所有设备的分层显示的输出。
加载包含一些设备对象的工程并执行脚本。
例如:PrintDeviceTree.py
# 编码:utf-8
# 我们启用了新的python 3打印语法
from __future__ import print_function# 打印出当前打开的项目中的所有设备。
打印("——打印项目的设备: ---")
# 定义打印功能。此功能以
# 所谓的“ docstring”,这是推荐的记录方式
# python中的功能.
def print_tree(treeobj, depth=0):
“”“打印设备及其所有子设备
参数:
treeobj -- 要打印的对象
depth -- 树中的当前深度(默认值为0)。
递归调用使用参数“ depth”
不应由用户提供。
"""
# 如果当前对象是设备,我们将打印名称和设备标识。
if treeobj.is_device:
名称 = treeobj.get_name(False)
设备 = treeobj.get_device_identification()
print("{0}- {1} {2}".format("--"*depth, name, deviceid))
# 我们为子对象递归调用print_tree函数。
for child in treeobj.get_children(False):
print_tree(child, depth+1)# 我们遍历所有顶级对象,并为它们调用print_tree函数。
for obj in projects.primary.get_children():
print_tree(obj)print("--- Script finished.---")
设备树(在“设备”视图中)显示在消息视图中,所有非设备对象均被忽略:
示例:变量的读取
脚本ReadVariable.py登录到设备并在必要时启动应用程序。然后,读取并输出变量PLC_PRG.iVar1的值。要尝试该脚本,你必须修改工程路径和变量名称。
如:ReadVariable.py
# 编码:utf-8
from __future__ import print_function# 如有必要,关闭打开的工程:
if projects.primary:
projects.primary.close()# 打开工程
proj = projects.open(r"D:\data\projects\Ampel.project")# 将“ Ampel.project”设置为活动应用程序
app = proj.active_application
onlineapp = online.create_online_application(app)# 登录到设备
onlineapp.login(OnlineChangeOption.Try, True)# 将应用程序的状态设置为“运行”,如果不在“运行”中
if not onlineapp.application_state == ApplicationState.run:
onlineapp.start()# 延时1秒
system.delay(1000)# 读取变量iVar1
value = onlineapp.read_value("PLC_PRG.iVar1")# 在消息视图或命令行中显示值
print(value)从设备退出并关闭“ Ampel.project”
onlineapp.logout()
proj.close()
在脚本ReadVariable.py的扩展中,脚本MailVariables.py从配方文件加载变量和表达式,并从控制器读取它们的当前值。然后将这些值写回到同一文件。另外,使用Python SMTP库发送带有附件的电子邮件,该附件包含所有变量的列表。
要使用脚本,你必须修改环境的SMTP服务器的路径,电子邮件地址和名称。
示例:MailVariables.py
# 编码:utf-8
from __future__ import print_function# 必要时关闭当前项目,然后打开“ ScriptTest.project”
if not projects.primary == None:
projects.primary.close()
project = projects.open("D:\\Data\\projects\\scriptTest.project")# 检索活动的应用程序
application = project.active_application# 创建在线申请
online_application = online.create_online_application(application)# 登录到应用程序。
online_application.login(OnlineChangeOption.Try, True)# 必要时启动PLC
if not online_application.application_state == ApplicationState.run:
online_application.start()# 延时2秒
system.delay(2000)# 打开配方文件以读取值。
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
# 从控制器读取值
watch_values = online_application.read_values(watch_expressions)print watch_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")# 关闭文件
recipe_input_file.close()
recipe_output_file.close()# 发送邮件
# 导入各自的库
import smtplib
from email.mime.text import MIMEText#打开输出文件
recipe_output_file = open("D:\\Data\\projects\\RecipeOutput.txt", "r")
mail = MIMEText(recipe_output_file.read())
recipe_output_file.close()#电子邮件地址发件人和收件人
fromm = "info@example.com"
to = "info@example.com"# 设置发件人和收件人
mail["Subject"] = "Attention value has changed"
mail["From"] = fromm
mail["To"] = to# 发送邮件
smtp = smtplib.SMTP("name of smtp server")
smtp.sendmail(fromm, [to], mail.as_string())
smtp.quit()退出并关闭应用程序
online_application.logout()
project.close()
例如:创建和编辑POU
脚本CreateDut.py在MetaFacture工程中创建对象MyStruct,MyAlias和MyUnion。文件夹DataTypes已经存在。
CreateDut.py
# 编码:utf-8
from __future__ import print_functionSTRUCT_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]
# 创建一个结构DUT,并将变量列表插入到右侧
# 放在第二行第0行(行编号从第0行开始)
struktur = folder.create_dut('MyStruct') # DutType.Structure is the default
struktur.textual_declaration.insert(2, 0, STRUCT_CONTENT)# 别名类型通过基本类型获取其“内容”,该基本类型将最终结束
# 作为声明部分中的一行:
# TYPE MyAlias : INT (0..100); END_TYPE
bereich = folder.create_dut('MyAlias', DutType.Alias, "INT (0..100)")与其将变量注入到现有的声明中,
# 也可以只替换完整的声明部分,包括
# 样板代码。
union = folder.create_dut('MyUnion', DutType.Union)
union.textual_declaration.replace(UNION_WHOLE)
例如:用户界面/与用户的交互
在某些情况下,脚本必须与用户进行交互。我们为最常见的交互提供了一些简单的API。示例脚本System_UI_Test.py显示了这方面的所有可能功能。
示例:System_UI_Test.py
# 编码: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 tupleprint("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 tupleprint("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
# 编码:utf-8
from __future__ import print_functionproj = projects.load("D:\Some.library")
info = proj.get_project_info()
# 设置一些值
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"# 库工具链中推荐的一些值
info.values["DefaultNamespace"] = "testlibrary"
info.values["Placeholder"] = "testlibrary"
info.values["DocFormat"] = "reStructuredText"# 现在我们设置一个自定义/供应商特定的值。
info.values["SpecialDeviceId"] = "PLC0815_4711"# 启用访问器功能的生成,因此IEC
# 应用程序可以在信息屏幕中显示版本。
info.change_accessor_generation(True)# 并将库设置为发布
info.released = True;proj.save()
例如:调用外部命令并导入PLCOpenXML文件
示例脚本DeviceImportFromSVN.py从外部程序(在本例中为SVN客户端)获取PLCOpenXML文件,并将其导入到新创建的MetaFacture工程中。
要使用脚本,你必须修改环境的路径。
例如:DeviceImportFromSVN.py
# 编码:utf-8
# 通过命令行svn客户端从Subversion导入PLCOpenXML中的设备。# 我们启用了新的python 3打印语法
from __future__ import print_functionimport sys, os
# 一些变量定义:
SVNEXE = r"C:\Program Files\Subversion\bin\svn.exe"
XMLURL = "file:///D:/testrepo/testfolder/TestExport.xml"
PROJECT = r"D:\test.project"# 清理所有打开的工程:
if projects.primary:
projects.primary.close()# 从Subversion获取plcopenxml数据。
# 我们将程序的输出捕获到xmldata变量中。
# “ with”结构会自动为我们关闭打开的管道。
with os.popen('"' + SVNEXE + '" cat ' + XMLURL, 'r') as pipe:
xmldata = pipe.read()# 创建一个新的工程:
proj = projects.create(PROJECT)# 将数据导入工程。
proj.import_xml(xmldata, False)# 最后保存。:-)
proj.save()print("--- Script finished.---")
高级的例子:从SVN调用库并将其安装在MetaFacture
以下示例脚本可以作为CT(连续测试)环境的一部分执行库的调用和安装,以便可以对其进行测试。除了标准MetaFacture以外,还必须使用有效许可证安装的MetaFacture 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()
