控制逻辑帮助
一、控制逻辑功能
通过编写控制逻辑可按照不同的判断条件对所关联的点进行不同操作,控制逻辑分为四种类型:启动、循环、定时和数据改变。控制逻辑支持javascript脚本语言。
1.1、”启动”逻辑
运行程序启动时会执行此脚本,目前仅支持“运行状态”中的“启动前”类型。
参数 | 说明 |
---|---|
运行状态 | 仅支持“运行前”状态 |
描述 | 对此逻辑的描述,与工程运行无关 |
变量名 | 变量名为自定义,变量名命名仅支持以字母为开头,并且除下划线外不允许有其它符号,在填写变量名时需要注意。 |
引用点名 | 可选择在通道中配置过的点 |
Code | 为脚本语言编写区,支持js语言,所有符号必须使用半角符号 |
当需要给变量设置一个固定的初始值时可以通过”启动”逻辑中的”运行前”配置变量的初始值。如下所示:
1.2、”循环”逻辑
可以按照设定的“循环间隔(s)”参数定时的执行此脚本。
1.2.1 当“描述”不为“1”时
弃用"描述"不为"1",建议使用下方"描述"为"1"的形式
参数 | 说明 |
---|---|
名称 | 填写此脚本的名称,无限制,不能重复 |
描述 | 对此逻辑的描述 |
循环间隔(s) | 执行此脚本的时间间隔 |
变量名 | 变量名为自定义,变量名命名仅支持以字母为开头,并且除下划线外不允许有其它符号,在填写变量名时需要注意 |
引用点名 | 可选择在通道中配置过的点 |
Code | 为脚本语言编写区,支持js语言,所有符号必须使用半角符号 |
上图表示每秒钟执行一次此脚本,每次数值累加100
1.2.2 当“描述”配置为“1”时
可使用JavaScript语言编写,并且支持JavaScript的函数库,同时提供如下函数:
获取值函数:qso.GetValue(‘采集点名’);
返回值:数值
设置值函数:qso.SetValue(‘采集点名’,数值);
返回值:无
获取文件内容函数:qso.ReadFile(‘文件名’);
返回值:文件内容
获取点数值是否有效:qso.GetValid(‘采集点名’);
返回值:数据点数值有效返回true,数据点数值无效返回false
延时函数:qso.Delay(毫秒);
返回值:无
例如:
qso.GetValue('Serial1.设备1@电压')函数可以获取电压值;
qso.SetValue('Serial1.设备1@电流',2)可设置电流值为2。
参数 | 说明 |
---|---|
名称 | 填写此脚本的名称,无限制,不能重复 |
描述 | 必须设置为1 |
循环间隔(s) | 执行此脚本的时间间隔 |
变量名 | 无需编辑,无需填写,无意义 |
引用点名 | 无需编辑,无需填写,无意义 |
Code | 为脚本语言编写区,支持js语言,所有符号必须使用半角符号 |
上图表示每30秒执行一次电表累加计算脚本
3、 “定时”逻辑
1.3.1 当“描述”不为“1”时
弃用"描述"不为"1",建议使用下方"描述"为"1"的形式
参数 | 说明 |
---|---|
名称 | 填写此脚本的名称,无限制,不能重复 |
描述 | 对此逻辑的描述 |
时间 | 填写执行此脚本的时刻 格式为 xxxx-xx-xx xx:xx:xx 例: 每个整点执行脚本,应设置为xxxx-xx-xx xx:00:00 每天的十二点执行脚本,应设置为xxxx-xx-xx 12:00:00 每月的十号零点执行脚本,应设置为xxxx-xx-10 00:00:00 |
变量名 | 变量名为自定义,变量名命名仅支持以字母为开头,并且除下划线外不允许有其它符号,在填写变量名时需要注意 |
引用点名 | 可选择在通道中配置过的点 |
Code | 为脚本语言编写区,支持js语言,所有符号必须使用半角符号 |
上图表示每天0点执行此脚本
1.3.2 当“描述”配置为“1”时
参数 | 说明 |
---|---|
名称 | 填写此脚本的名称,无限制,不能重复 |
描述 | 必须设置为1 |
时间 | 填写执行此脚本的时刻 格式为 xxxx-xx-xx xx:xx:xx 例: 每个整点执行脚本,应设置为xxxx-xx-xx xx:00:00 每天的十二点执行脚本,应设置为xxxx-xx-xx 12:00:00 每月的十号零点执行脚本,应设置为xxxx-xx-10 00:00:00 |
变量名 | 无需编辑,无需填写,无意义 |
引用点名 | 无需编辑,无需填写,无意义 |
Code | 为脚本语言编写区,支持js语言,所有符号必须使用半角符号 |
当“描述”配置为“1”时可使用JavaScript语言编写,并且支持js的函数库,同时提供如下函数:
获取值函数:qso.GetValue(‘采集点名’);
返回值:数值
设置值函数:qso.SetValue(‘采集点名’,数值);
返回值:无
获取文件内容函数:qso.ReadFile(‘文件名’);
返回值:文件内容
获取点数值是否有效:qso.GetValid(‘采集点名’);
返回值:数据点数值有效返回true,数据点数值无效返回false
延时函数:qso.Delay(毫秒);
返回值:无
例如:
qso.GetValue('Serial1.设备1@电压')函数可以获取电压值;
qso.SetValue('Serial1.设备1@电流',2)可设置电流值为2。
上图表示每天0点执行此脚本,设置该点值为0
4、 “数据改变”逻辑
注意:如果“设置值”的点在"变化逻辑"中为触发条件的话,不应执行设置值操作,否则会造成死锁,会造成死循环一直触发变化逻辑,需要“设置值”的点不应作为“引用点名”
不应在逻辑中出现执行时间过长的操作(例如类似于延时功能),因为逻辑是顺序执行、逐个执行的,因此不应出现执行时间过长的操作。
1.4.1 当“描述”配置不为“1”时
弃用"描述"不为"1",建议使用下方"描述"为"1"的形式
参数 | 说明 |
---|---|
名称 | 填写此脚本的名称,无限制,不能重复 |
描述 | 对此逻辑的描述 |
变量名 | 变量名为自定义,变量名命名仅支持以字母为开头,并且除下划线外不允许有其它符号,在填写变量名时需要注意 |
引用点名 | 可选择在通道中配置过的点,当配置的点数值或时间发生改变时均会执行此脚本 |
Code | 为脚本语言编写区,支持js语言,所有符号必须使用半角符号 |
上图表示当左侧三个点数值发生改变时会执行右侧脚本
1.4.2 当“描述”配置为“1”时
参数 | 说明 |
---|---|
名称 | 填写此脚本的名称,无限制,不能重复 |
描述 | 必须设置为1 |
变量名 | 无需配置 |
引用点名 | 可选择在通道中配置过的点,当配置的点数值或时间发生改变时均会执行此脚本 |
Code | 为脚本语言编写区,支持js语言,所有符号必须使用半角符号 |
当“描述”配置为“1”时可使用JavaScript语言编写,并且支持js的函数库,同时提供了两个函数:
获取值函数:qso.GetValue(‘采集点名’);
返回值:数值
设置值函数:qso.SetValue(‘采集点名’,数值);
返回值:无
获取文件内容函数:qso.ReadFile(‘文件名’);
返回值:文件内容
获取点数值是否有效:qso.GetValid(‘采集点名’);
返回值:数据点数值有效返回true,数据点数值无效返回false
延时函数:qso.Delay(毫秒);
返回值:无
例如:
qso.GetValue('Serial1.设备1@电压')函数可以获取电压值;
qso.SetValue('Serial1.设备1@电流',2)可设置电流值为2。
上图表示当Serial1.新建设备1@直流侧电压发生改变时会执行右侧脚本
二、常见问题
2.1 基于ECMAScript的脚本
基于ECMAScript脚本语言,使用ECMA-262标准。微软的JScript和网景的javascript也是基于ECMAScript标准,有关 ECMAScript的概述,可以查看ECMAScript标准。如果你不熟悉ECMAScript语言,有一些指导和书籍,例如JavaScript: The Definitive Guide.
http://www.ecma-international.org/ecma-262/
2.2 在使用Math.max()前最好先将数据做Number() 计算,把对象的值转换为数字。
要确保参数是数字类型的,如果不确定是不是数字需要先将参数做Number()后再使用Math.max()
三、示例
// 循环逻辑中实现
// 描述设置为1
// 循环间隔为1秒
// js中月份:0表示1月,11表示12月
// 2020,8,11表示的是从2020年9月11号开始算起
var start = new Date(2020, 8, 11);// 此处设置开始运行时间
var current = new Date();
var days = current.getTime() - start.getTime();
var day = parseInt(days / (1000 * 60 * 60 * 24));
qso.SetValue('API.新建设备1@安全运行天数',day);
var value1 = qso.GetValue('API.新建设备1@YK1');
var myDate = new Date();
var hour = myDate.getHours();
var minute = myDate.getMinutes();
if (minute % 2 == 0) {// 分钟数为双数时打开开关
if (value1 != 1) {
qso.SetValue('API.新建设备1@YK1', 1);
}
} else {// 分钟数为单数时关闭开关
if (value1 != 0) {
qso.SetValue('API.新建设备1@YK1', 0);
}
}
// 描述设置为1才可用此方式
// 此脚本将从“环境监测”设备中读取到的“纬度、经度、风速”数据分别设置给多个通道中的“广播设备”
var vGetChannel = 'Serial1.环境监测@';
var Latitude = '维度';
var Longitude = '经度';
var WindSpd = '风速';
var vbeiyong = '备用';
var vSetChannel1 = 'Serial1.广播设备@';
var vSetChannel2 = 'Serial2.广播设备@';
var vSetChannel3 = 'Serial3.广播设备@';
var vSetChannel4 = 'Serial4.广播设备@';
if ( qso.GetValid(vGetChannel+Latitude)
&& qso.GetValid(vGetChannel+Longitude)
&& qso.GetValid(vGetChannel+WindSpd) )
{
var ReadLatitude = qso.GetValue(vGetChannel+Latitude);
var ReadLongitude = qso.GetValue(vGetChannel+Longitude);
var ReadWindSpd = qso.GetValue(vGetChannel+WindSpd);
qso.SetValue(vSetChannel1+Latitude,ReadLatitude);
qso.SetValue(vSetChannel1+vbeiyong,0);
qso.SetValue(vSetChannel1+Longitude,ReadLongitude);
qso.SetValue(vSetChannel1+WindSpd,ReadWindSpd);
qso.SetValue(vSetChannel2+Latitude,ReadLatitude);
qso.SetValue(vSetChannel2+vbeiyong,0);
qso.SetValue(vSetChannel2+Longitude,ReadLongitude);
qso.SetValue(vSetChannel2+WindSpd,ReadWindSpd);
qso.SetValue(vSetChannel3+Latitude,ReadLatitude);
qso.SetValue(vSetChannel3+vbeiyong,0);
qso.SetValue(vSetChannel3+Longitude,ReadLongitude);
qso.SetValue(vSetChannel3+WindSpd,ReadWindSpd);
qso.SetValue(vSetChannel4+Latitude,ReadLatitude);
qso.SetValue(vSetChannel4+vbeiyong,0);
qso.SetValue(vSetChannel4+Longitude,ReadLongitude);
qso.SetValue(vSetChannel4+WindSpd,ReadWindSpd);
}
// 描述设置为1才可用此方式
// 此脚本将从“环境监测”设备中读取到的“年、月、日、时、分、秒”数据分别设置给多个通道中的“广播设备”
var vGetChannel = 'Serial1.环境监测@';
var vYear = '年';
var vMonth = '月';
var vDay = '日';
var vHour = '时';
var vMinute = '分';
var vSecond = '秒';
var vSetChannel1 = 'Serial1.广播设备@';
var vSetChannel2 = 'Serial2.广播设备@';
var vSetChannel3 = 'Serial3.广播设备@';
var vSetChannel4 = 'Serial4.广播设备@';
if ( qso.GetValid(vGetChannel+vYear)
&& qso.GetValid(vGetChannel+vMonth)
&& qso.GetValid(vGetChannel+vDay)
&& qso.GetValid(vGetChannel+vHour)
&& qso.GetValid(vGetChannel+vMinute)
&& qso.GetValid(vGetChannel+vSecond) )
{
var ReadYear = qso.GetValue(vGetChannel+vYear);
var ReadMonth = qso.GetValue(vGetChannel+vMonth);
var ReadDay = qso.GetValue(vGetChannel+vDay);
var ReadHour = qso.GetValue(vGetChannel+vHour);
var ReadMinute = qso.GetValue(vGetChannel+vMinute);
var ReadSecond = qso.GetValue(vGetChannel+vSecond);
qso.SetValue(vSetChannel1+vYear,ReadYear);
qso.SetValue(vSetChannel1+vMonth,ReadMonth);
qso.SetValue(vSetChannel1+vDay,ReadDay);
qso.SetValue(vSetChannel1+vHour,ReadHour);
qso.SetValue(vSetChannel1+vMinute,ReadMinute);
qso.SetValue(vSetChannel1+vSecond,ReadSecond);
qso.SetValue(vSetChannel2+vYear,ReadYear);
qso.SetValue(vSetChannel2+vMonth,ReadMonth);
qso.SetValue(vSetChannel2+vDay,ReadDay);
qso.SetValue(vSetChannel2+vHour,ReadHour);
qso.SetValue(vSetChannel2+vMinute,ReadMinute);
qso.SetValue(vSetChannel2+vSecond,ReadSecond);
qso.SetValue(vSetChannel3+vYear,ReadYear);
qso.SetValue(vSetChannel3+vMonth,ReadMonth);
qso.SetValue(vSetChannel3+vDay,ReadDay);
qso.SetValue(vSetChannel3+vHour,ReadHour);
qso.SetValue(vSetChannel3+vMinute,ReadMinute);
qso.SetValue(vSetChannel3+vSecond,ReadSecond);
qso.SetValue(vSetChannel4+vYear,ReadYear);
qso.SetValue(vSetChannel4+vMonth,ReadMonth);
qso.SetValue(vSetChannel4+vDay,ReadDay);
qso.SetValue(vSetChannel4+vHour,ReadHour);
qso.SetValue(vSetChannel4+vMinute,ReadMinute);
qso.SetValue(vSetChannel4+vSecond,ReadSecond);
}
var datetime = new Date();
qso.Display("datetime",datetime);
var year = new Date().getFullYear();
var month = new Date().getMonth() + 1;
var day = new Date().getDate();
var hours = new Date().getHours();
var minutes = new Date().getMinutes();
var seconds = new Date().getSeconds();
qso.Display("year",year);
qso.Display("month",month);
qso.Display("day",day);
qso.Display("hours",hours);
qso.Display("minutes",minutes);
qso.Display("seconds",seconds);
var monthn;
var dayn;
// 遵循YYYYMMDD格式
if(month < 10)
monthn = '0' + month;
else
monthn = '' + month;
if(day < 10)
dayn = '0' + day;
else
dayn = '' + day;
var fileName_a = String(year) + monthn + dayn; // 日前调度文件
var fileName_r = String(year) + monthn + dayn; // 实时调度文件
qso.Display("fileName_a",fileName_a);
qso.Display("fileName_r",fileName_r);
var oDate=new Date(); //初始化系统时间函数
var year = oDate.getFullYear()-2000;
var month = oDate.getMonth()+1;
var day = oDate.getDate();
var hour = oDate.getHours();
var minute = oDate.getMinutes();
var second = oDate.getSeconds();
qso.SetValue('Serial1.BD@年月',year*256+month);
qso.SetValue('Serial1.BD@日时',day*256+hour);
qso.SetValue('Serial1.BD@分秒',minute*256+second);
var value1 = Math.sqrt(15);
qso.Display("value1",value1);
var value2 = new String("123456#7890");
qso.Display("value2",value2);
var value3 = value2.split("#");
qso.Display("value3",value3);
// 信息初始化,读取变流器运行状态、功率等信息到预定义变量中
var ess = "wbqbx_es_";
var year = new Date().getFullYear();
var month = new Date().getMonth() + 1;
var day = new Date().getDate();
var hours = new Date().getHours();
var minutes = new Date().getMinutes();
var seconds = new Date().getSeconds();
var nian = qso.GetValue('API.device@h_year');
var yue = qso.GetValue('API.device@h_month');
var ri = qso.GetValue('API.device@h_day');
var flagRead = qso.GetValue('API.device@f_Read'); // 文件读取标志
var col_a = [];
var col_i = [];
var col_r = [];
var path = '/mnt/';
// 检测下发的最新日内调度文件
function fileTest()
{
var fileName_i1 = 'i1' + '_wbbx_' + ess + String(year) + monthn + dayn + '.rb'; // 日内调度文件1
var fileName_i2 = 'i2' + '_wbbx_' + ess + String(year) + monthn + dayn + '.rb'; // 日内调度文件2
var fileName_i3 = 'i3' + '_wbbx_' + ess + String(year) + monthn + dayn + '.rb'; // 日内调度文件3
var fileName_i4 = 'i4' + '_wbbx_' + ess + String(year) + monthn + dayn + '.rb'; // 日内调度文件4
var fileName_i5 = 'i5' + '_wbbx_' + ess + String(year) + monthn + dayn + '.rb'; // 日内调度文件5
var fileName_i6 = 'i6' + '_wbbx_' + ess + String(year) + monthn + dayn + '.rb'; // 日内调度文件6
var iFile1 = qso.ReadFile(fileName_i1);
var iFile2 = qso.ReadFile(fileName_i2);
var iFile3 = qso.ReadFile(fileName_i3);
var iFile4 = qso.ReadFile(fileName_i4);
var iFile5 = qso.ReadFile(fileName_i5);
var iFile6 = qso.ReadFile(fileName_i6);
if(iFile6 != undefined)
{
return [1, fileName_i6];
}
else
{
if(iFile5 != undefined)
{
return [1, fileName_i5];
}
else
{
if(iFile4 != undefined)
{
return [1, fileName_i4];
}
else
{
if(iFile3 != undefined)
{
return [1, fileName_i3];
}
else
{
if(iFile2 != undefined)
{
return [1, fileName_i2];
}
else
{
if(iFile1 != undefined)
{
return [1, fileName_i2];
}
else
{
return 0;
}
}
}
}
}
}
}
// 获取当天的下发曲线
function savePoint(col, xFile)
{
qso.Display("col",col);
qso.Display("xFile",xFile);
var xx = qso.Split(xFile,"\n");
qso.SetValue('API.device@Pa1', 1680);
for(var i = 0; i < xx.length; i ++)
{
if(xx[i].split(' ').length > 1)
{
col[i] = xx[i].split(' ');
}
if(xx[i].split(' ').length > 1)
{
col[i] = xx[i].split(' ');
}
}
}
// 遵循YYYYMMDD格式
if(month < 10)
{
monthn = '0' + month;
}
else
{
monthn = '' + month;
}
if(day < 10)
{
dayn = '0' + day;
}
else
{
dayn = '' + day;
}
var fileName_a = 'i5_wbqbx_' + ess + String(year) + monthn + dayn + '.rb' // 日前调度文件
var fileName_r = 'i_wbqbx_' + ess + String(year) + monthn + dayn + '.rb' // 实时调度文件
// 使用内置函数ReadFile读取E文件
var aFile = qso.ReadFile(path + fileName_a);
var rFile = qso.ReadFile(path + fileName_r);
qso.Display("aFile",aFile);
qso.Display("rFile",rFile);
var n=qso.Split(aFile,"\n");
qso.Display("n",n);
for (var i = 0; i < n.length; i++)
{
qso.Display(i,n[i]);
}
// 需要转换成String才可以使用split分割函数
var value5 = new String(aFile);// 构建js的String类型,才可以使用js的String的split()函数
var value6 = value5.split("\n");
qso.Display("value6",value6);
qso.Display("value6 length",value6.length);
for (var j = 0; j < value6.length; j++)
{
qso.Display(j,value6[j]);
}
var value7 = aFile.toString();// 转换成js的String类型,才可以使用js的String的split()函数
qso.Display("value7",value7);
var value8 = value7.split("\n");
for (var j = 0; j < value8.length; j++)
{
qso.Display(j,value8[j]);
}
//savePoint(col_a, value5);
//savePoint(col_r, rFile);
//if(fileTest()[0])
//{
// var iFile = qso.ReadFile(path + fileTest()[1]);
// savePoint(col_i, iFile);
//}
// https://www.w3school.com.cn/jsref/jsref_obj_string.asp
// 验证 "JavaScript String"对象的部分函数功能
var myarray = new Array('88.99.66');
qso.Display("myarray",myarray);
var a = myarray.toString();
qso.Display("a",a);// "a" QVariant(QString, "88.99.66")
var a = new String("88.99.66");// QVariant(QVariantMap, QMap(("0", QVariant(QString, "8") ) ( "1" , QVariant(QString, "8") ) ( "2" , QVariant(QString, ".") ) ( "3" , QVariant(QString, "9") ) ( "4" , QVariant(QString, "9") ) ( "5" , QVariant(QString, ".") ) ( "6" , QVariant(QString, "6") ) ( "7" , QVariant(QString, "6") ) ( "length" , QVariant(int, 8) ) ) )
qso.Display("a",a);
var a = "88.99.66";// QVariant(QString, "88.99.66")
qso.Display("a",a);
qso.SetValue("API.新建设备1@YK1",a);
// 只有当a的类型为String时,才可以使用split函数
var b = a.split(".");// QVariant(QVariantList, (QVariant(QString, "88") , QVariant(QString, "99") , QVariant(QString, "66") ) )
qso.Display("b",b);
// 遍历显示
for (var i = 0; i < b.length; i++)
{
qso.Display(i,b[i]);
var bianhao = i+2;
var name = "API.新建设备1@YK"+bianhao;
qso.Display("name",name);
qso.SetValue(name,b[i]);
// "0" QVariant(QString, "88")
// "1" QVariant(QString, "99")
// "2" QVariant(QString, "66")
}
// 只有当a的类型为String时,才可以使用indexOf函数
var c = a.indexOf("99");
qso.Display("c",c);// "c" QVariant(int, 3)
示例-温度-空调-联动模拟
var wendu = qso.GetValue('API.设备_1@实时温度'); var temp = qso.GetValue('API.设备_1@中间变量'); if (wendu > 30) { // 制冷 if (temp != 3) { qso.SetValue('API.设备_1@中间变量', 3); qso.SetValue('API.设备_1@实际遥控点', 100);// 100 模拟制冷 } } else if (wendu < 10) { // 制热 if (temp != 2) { qso.SetValue('API.设备_1@中间变量', 2); qso.SetValue('API.设备_1@实际遥控点', 50);// 100 模拟制热 } } else { // 关闭 if (temp != 1) { qso.SetValue('API.设备_1@中间变量', 1); qso.SetValue('API.设备_1@实际遥控点', 0);// 100 模拟关机 } }