MetaFacture提供脚本的所有对象和命令也在Python模块“scriptengine”中。每当启动脚本时，导入`from scriptengine import *`的结果。这样可以轻松访问MetaFacture。但是，如果你的脚本导入了需要访问MetaFactureAPIs的模块，则这些模块必须自己导入模块scriptengine。

在下表中，你将找到可以在Python脚本中用作入口点的主要对象（类别）。有关入口点的全面文档，请参阅MetaFactureScriptEngine的API参考文档。

| 对象 | 描述 |
|---|---|
| 系统 | 访问常规的MetaFacture功能，例如：  - 退出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.---")  
>    
> 设备树（在“设备”视图中）显示在消息视图中，所有非设备对象均被忽略：
> 
> ![](https://resource.helplook.net/docker_production/3648ne/article/TCOD7gLQ/67289c54dd341.png)

---

### 示例：变量的读取​

脚本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\_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\]
> 
> \# 创建一个结构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 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**
> 
> \# 编码:utf-8  
> from \_\_future\_\_ import print\_function
> 
> proj = 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\_function
> 
> import 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()