动作

动作编辑器:身份与位置、脚本块、脚本可以读什么写什么、每一条校验提示、“运行”这条命令和它的日志、启用和禁用、复制和删除,以及运行的那些上限。

以 Markdown 查看

动作是一段 JavaScript 语句块,它读地址空间,写内部存储值变量和点位。动作是 Logic 的写入通路:它们可以按需运行(运行)、由一个触发器运行,或者由一个接在它们上面的仪表画面按钮运行。在 Logic 那一栏 Actions 一节下面选中一个动作(或者用“新建…”>“新建动作”造一个),就能打开它的编辑器;读要查看 Logic,编辑要配置 Logic,运行要操作 Logic

标题栏显示动作标记、名称、那一行“一段你按需运行、或者由触发器替你运行的脚本,它写入变量和点位。”,动作关着的时候还有一枚已禁用的胶囊。表单那一列里放着身份脚本;右边那条竖栏放着上次运行

身份

字段 它是什么 取值 / 默认值 影响
名称 显示名称,也是一次运行被记进日志时所用的那个标签。 自由文本;新动作叫 ActionN;名字留空则存成 Action 每一次按键都自动保存。动作是按身份被引用的,所以改名什么都不用改写,也弄不坏什么。
位置行 这个动作归在哪里,用文字写出来:Actions / Startup / Walk setpoint 只读。 动作没有地址;这一行是一个位置,绝不是拿去写进表达式的东西。要改就用树里的移动到
说明(可选) 自由文本。 默认为空。 没有影响。

脚本

脚本卡片就是那个脚本编辑器,带一句提示“JavaScript 语句(let、if、for、函数)。用赋值写内部存储值变量(Variables.Setpoint = 21.5;),用 Connector.Driver.Device.Tag.Write(value) 写点位。读取不过质量关卡:请检查 .State(),并在做算术之前用 ?? 挡住空档。”脚本每一次按键都自动保存,每半秒校验一次;提示出现在那句提示下面。校验从不执行脚本。

脚本就是普通的严格模式 JavaScript(局部变量、if、循环、函数、MathDateJSON),跑在和表达式同一个地址空间、同一套可读面之上,只有两处不同。读取过质量关卡:一个空档读作 null,所以请检查 .State(),并用 ?? 把算术挡住;处理一次不良读数正是动作的用武之地。而且脚本可以读表达式变量(读它们已发布的值);只有表达式不能引用它们。

一个动作可以写什么

恰好有两种写法能改变现场,而且两种都走那条记进日志的写入出口

写入 形式 目标
内部存储值赋值 Variables.Setpoint = 21.5;Variables.Forno.Setpoint = 21.5; 一个内部存储值变量,文件夹层级也在内。值会被强制转换成这个变量的输出类型,而且在变量是掉电保持时被标记为需要保存。
点位写入 Connector.Simulated.Pump.Cmd.Write(true); 一个实时点位。这个值是工程值:它会倒着走完这个点位的转换链,变成设备要的那个原始值。

写入是写通的:一次失败之前已经生效的仍然生效,而诊断日志把每一次写入按来源“动作”记成“从旧值到新值”。一次失败的写入会抛出异常,把那一次运行中止掉,原因写进它的结果里:

  • “对‘X’的写入被驳回:这个值不是有限数。”(NaN 或无穷)
  • “‘Tag’没有在连接器里落地。”(一台已禁用的设备,或者一个内置服务器没有带着的点位)
  • “‘value’无法为‘Tag’完成转换。”
  • “‘X’被‘<holder>’写保护。”(一次配方运行或者一个联锁占着这个信号源)
  • “对‘Tag’的写入失败。服务器在运行吗?”
  • “找不到变量‘X’。”以及“‘Variables.X’是一个表达式变量:它是算出来的,绝不会被写。”

校验拒绝什么

提示 原因
需要填一段脚本。 编辑器是空的。
脚本错误:… 这段文字解析不了。
地址必须是静态的:访问‘Root’时用了算出来的段。 Variables[name] 或者任何非字面量的段。
地址‘…’不完整。 一处太短、点不到一个点位的引用。
找不到‘X’。 一次读取,或者一个赋值目标,什么都解析不出来。
请给变量本身赋值:Variables.Name = value。 = 左边点的是一个成员,或者比一个变量的地址还深。
‘X’是一个表达式变量:它是算出来的,绝不会被写。 给一个表达式变量赋值。
‘Connector’的点位是只读的。写点位请用 Connector.Driver.Device.Tag.Write(value)。 给 Variables 以外的任何根赋值(Process 有它自己的提示)。
Process 的点位在动作里是只读的;脚本不支持运行命令和预选写入。 给一个 Process 点位赋值,或者对它调 Write
不能从动作里调用 Process 的运行命令;命令类点位暴露的是只读的就绪值。 调用 Process.<Model>.<Unit>.Commands.Start() 或者任何别的命令类点位;一个 Commands 点位只读得出这条命令此刻能不能执行。
点位上不支持 ++ 和 -- 运算符。请用 Variables.Name = Variables.Name.ValueToReal() + 1。 Variables.N++
Write(value) 是点位写入:Connector.Driver.Device.Tag.Write(value)。 对一个不是点位地址的东西调了 Write

JavaScript 的局部变量(let x = 1; x = x + 1;)不受这些规则约束。

运行

运行是一个打开着的动作上那条命令栏里排在最前的命令;它只对拥有操作 Logic 的角色画出来,工作站只读时带着“运行时已停止”置灰(工程锁定不会把它置灰:运行是操作,不是配置)。角色同时还拥有“配置 Logic”时,编辑器里的草稿会先保存下来,运行执行的是保存之后的那份定义;没有“配置”时,运行执行的是已经落盘的那份定义(那些字段本来就是只读的,所以两者绝不会不一样)。

每一次运行都在那唯一一条逻辑队列上、用一个全新的脚本引擎执行,所以两次运行之间不会有状态漏过去,一次运行也绝不会插在一次扫描周期、另一个动作或者一次操作员写入中间。一次运行超过 500 毫秒(“脚本已中止:它跑过了 500 毫秒的时间上限(死循环?)。”)、100000 条语句或者 4 MB 内存就被中止,每一种都有一条点名那个上限的提示。已禁用的动作根本不跑就失败(“这个动作已禁用。”);运行时已停止时答的是“逻辑运行时没有在运行。”记录条报告“运行成功,用时 12 毫秒。”或者“运行失败:<reason>”。只有失败会到事件控制台,记在这个动作的名字下面,并连同是谁发起的:命令按的是“手动”,排程运行的是那个触发器的名字。它第一次被记为一条警告,在它以同一个原因反复失败期间被汇总,恢复时再记一条,而那一条恢复的记录,是一次成功的运行在那里唯一写下的东西。单纯成功的一次运行,以及它写下的每一个值,只写进详细捕获:一个每次扫描周期都写的脚本会产出成千上万个值,而一个被它们填满的控制台,是一个谁也读不到工作站要闻的控制台。

上次运行那条竖栏显示这个动作上一次是什么时候跑的(或者“从未运行。”)、“用时:N 毫秒”、放在一条提醒里的最近一次错误,以及那句提示“运行在那唯一一条逻辑队列上执行。只有失败的运行会到事件控制台;成功的运行以及它写下的每一个值都留给详细捕获。触发器按排程调用动作。”这条竖栏属于活着的那个动作:一次自动保存绝不会把它抹空;把运行时重启一次会。

命令

命令 作用 何时置灰 何时不画出来
运行 保存草稿(有“配置 Logic”时)并把一次运行排进队列。 运行时已停止。 角色没有“操作 Logic”。
启用 / 禁用 翻转“已启用”;已禁用的动作拒绝运行,并让绑在它上面的每一个触发器空转。 工作站被锁住或只读。 角色没有“配置 Logic”。
复制 把这个动作复制到 Actions 根下面一个空闲的名字上并打开副本;副本没有运行记录,也没有触发器绑在它上面。 工作站被锁住或只读。 角色没有“配置 Logic”。
删除动作 先问“要删除‘X’吗?这会把这个动作拿掉。此操作无法撤销。”绑在它上面的触发器会变成没有绑定,而不是跟着一起被删掉。 工作站被锁住或只读。 角色没有“配置 Logic”。

Actions 根的面板在“数值”那一列里列出每一个动作和它的状态:“已启用 · 上次运行 <when>”,上一次运行失败时加“· 错误”,否则是“已禁用”。

动作不做什么

它们不下发 Process 的运行命令、不预选一个流程、也不给运行记录加备注(那些点位是只读的就绪值和预选值);它们不确认报警;它们不并行运行;它们两次运行之间不留状态,也不共用函数;而且它们不由数值变化或条件触发,只由“运行”、一个触发器的定时间隔或者一个仪表画面按钮触发。