演示地址:http://121.40.16.189:12000
万维组态数据通讯架构图
1、创建模版及点位
(1)点击左侧菜单数据模版管理菜单 ;(2)点击新增按钮;(3)输入模版名称,添加数据点位;
注意: 添加数据点位时,【点位属性】这个字段是我们在数据通信的时候的键,举例如下: 如上图中,我们添加了4个点位,那我们在数据通信的时候,消息体如下,
{
'wd': 0,
'sd': 0.5,
'fg': 1,
'sw': 1.2
}
2、创建组态及关联模版
(1)点击左侧菜单组态管理管理菜单 ;(2)点击新增按钮;(3)输入组态名称;(4)选择数据模版;
新增一个组态,绑定刚刚添加的模版
3、设置数据源
3.1、MQTT数据源
(1)点击左侧菜单组态管理管理菜单打开组态列表 ;(2)找到刚刚添加的组态;(3)点击列表最后一栏[【操作】栏目中的数据源配置;(4)选择【MQTT】;
连接地址:地址中可以设置动态参数占位符,如:ws://localhost:8083/mqtt/{{a1}}/{{a2}}/point, 我们在代码中解析到这个地址时, 会从编辑器组件的对象参数【initOptions】中取键为 【a1】和【a2】的值进行替换,initOptions的设置请参考【src/views/editor.vue】 或【src/views/preview.vue】中;而在【src/views/home.vue】中,我们会把路由参数全部合并到initOptions中去,从而达到参数动态的效果;
用户名:MQTT连接的认证账号用户名;
密码:MQTT连接的认证账号密码;
3.2、websocket数据源
(1)点击左侧菜单组态管理管理菜单打开组态列表 ;(2)找到刚刚添加的组态;(3)点击列表最后一栏[【操作】栏目中的数据源配置;(4)选择【WebSocket】;
连接地址和[3.1]中的地址一样可以设置动态参数, 我们管理后端java服务中就开启了一个websocket服务,在【com.rcscada.common.utils.websocket.WebSocketServer类中, 服务地址: ws://localhost:8089/app/ws/{{deviceId}}, {{deviceId}} 是组态id,所以我们编辑器在连接这个服务时,就会把{{deviceId}}替换成组态id去连接;
3.3、http数据源
(1)点击左侧菜单组态管理管理菜单打开组态列表 ;(2)找到刚刚添加的组态;(3)点击列表最后一栏[【操作】栏目中的数据源配置;(4)选择【HTTP】;
数据源域名:http数据源的请求域名 它是轮询请求和事件请求两个接口的域名部分,如:http://127.0.0.1:8080或http://www.xxx.com;格式:[协议://域名:端口]();
轮询请求接口:和MQTT/websocket不同,http源需要我们的组态主动请求点位数据,所以我们这里就要设置域名和接口等信息; 这部分需要我们在业务系统中自己开发,将点位数据通过接口的形式返回给编辑器;支持动态参数{{}}
轮询周期:轮询请求接口的请求周期,如上图我们设置了 5000毫秒,也就是5秒,这个频率可以根据实际情况来做调节;
轮询请求头:轮询请求接口如果有需要传递的请求头部信息,就在这里定义,如上我们定义了token和ContentType两个参数,其中token是动态的,ContentType为静态的 ${token={{token}}}${ContentType=application/json},格式:${key=value},其中key为属性名,value为属性值, value如果是动态的就使用我们的动态参数替换,如:${key={{value}}}
轮询请求参数:轮询请求接口如果有需要传递的请求参数,就在这里定义,如上我们定义了params1、params2和deviceId三个参数,params1和deviceId为动态参数,params2为静态的 ${params1={{params1}}}${params2=100}${deviceId={{deviceId}}},格式和轮询请求头的格式一样
【轮询请求接口】响应体固定如下
{
code: 0, //成功 非0 就是失败
msg: 'success',
data: JSON.stringify({
'wd': 0,
'sd': 0.5,
'fg': 1,
'sw': 1.2
})// 点位数据的json字符串 一定为字符串,否则没效果
}
注意 点位数据一定要是 JSON string
事件请求接口:格式和轮询请求接口一样,区别在于编辑器中绑定了反向控制事件时,触发事件后调用此接口; 事件请求头:与轮询请求头一样; 事件请求参数:格式和轮询请求参数一样;自定义请求参数 + message
【事件请求接口】请求参数固定如下
// 发送反向修改点位值
{
params1: {{params1}},//事件请求参数中设置的
params2: 100,//事件请求参数中设置的
deviceId={{deviceId}},//事件请求参数中设置的
message: JSON.stringify({
deviceId: '组态id',
type: 'changePointValue',
data: {
key: '点位属性',
value: '需要修改的新值'
}
})// message 是固定的 所以定义事件请求参数时不要定义成'message'
}
// 发送反向控制指令
{
params1: {{params1}},//事件请求参数中设置的
params2: 100,//事件请求参数中设置的
deviceId={{deviceId}},//事件请求参数中设置的
message: JSON.stringify({
deviceId: '组态id',
type: 'ctrlCommand',
data: {
command: '绑定时设置的指令值',
}
})// message 是固定的 所以定义事件请求参数时不要定义成'message'
}
// 点位数据 json字符串数据 下面会用到这个
JSON.stringify({
'wd': 0,
'sd': 0.5,
'fg': 1,
'sw': 1.2
})
【事件请求接口】响应体固定如下
{
code: 0, //成功 非0 就是失败
msg: 'success'
}
从【轮询请求接口】和【事件请求接口】响应体可以看到是固定的
{
code: 0,
msg: 'success',
data: JSON.stringify({
'wd': 0,
'sd': 0.5,
'fg': 1,
'sw': 1.2
})
}
我们编辑器判断响应体的code === 0才是成功,点位数据是存放在【data】字段中的所以为了让编辑器能够识别, 如果【轮询请求接口】和【事件请求接口】返回的响应体内容不是以上格式, 就需要我们在上图的右边代码区配置转换方法, 默认已写入:
const response = arguments[0];
return response.data;
以上 response是我们将axios的response注入到这个转换方法体的, response的键值如下:
{
"data": {
"resCode": 200,
"resMsg": '成功',
"resData": Object
},
"status": 200,
"statusText": "OK",
"headers": {
"connection": "close",
"content-type": "application/json",
"date": "Fri, 29 Dec 2023 07:50:31 GMT",
"transfer-encoding": "chunked",
"vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers",
"x-content-type-options": "nosniff",
"x-powered-by": "Express",
"x-xss-protection": "1; mode=block"
},
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 10000,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"headers": {
"Accept": "application/json, text/plain, */*",
"Authorization": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjQ1N2Y3NDJkLWQ1NzktNGY0Ni04YTI1LTZhMjY4MjYwY2ZiMSJ9.ULxPQnH1yYOUE9MR0YtTQ9mJb2S32XUqY64NnsS2zfkQRxv_qKZtXcoqpNy_J3FAa-eP6um0KXPnRLvMwnU0Zg"
},
"baseURL": "/dev-api",
"url": "/system/dict/data/type/data_source_type",
"method": "get"
},
"request": {}
}
从如上返回信息中我们可以看到 data 不是我们想要格式{code, msg, data},而是{resCode, resMsg, resData} 这个时候转换区的代码就该如下:
const response = arguments[0];
if(response.status === 200 && response.data){
// http 状态正常
const oldData = response.data;
// 你自己业务系统的状态码 resCode == 200 为成功,转换到我们这边就是
const data = {
code: oldData.resCode == 200 ? 0 : -1,// 0成功,非0失败
msg: oldData.resMsg,
data: oldData.resData,
// 注意 轮询请求接口 这个地方需要【点位数据】json string,如果oldData.resData不是上面的 【点位数据json字符串数据】 时
// 就可以在这里做转换 把它转换成我们想要的格式
// 如何判断是不是 【轮询请求接口】可以用response.config.url来和我们填写的【轮询请求接口】进行对比;
}
}
return response.data;
注意 轮询请求接口 这个地方需要【点位数据】json string,如果oldData.resData不是上面的 【点位数据json字符串数据】 时, 就可以在这里做转换 把它转换成我们想要的格式。 如何判断是不是 【轮询请求接口】可以用response.config.urlji就是我们填写的【轮询请求接口】或【事件请求接口】;
4、变量的创建与使用
首先在组态列表中我们刚添加的组态后面点击【组态设计】进入编辑器编辑组态内容;点击右边【配置虚拟变量】;可以看到我们生成了4个变量; 这是我们编辑器自动生成的,如果不想使用可以不用管;我们重点看看新增变量;如下图:
4.1、变量的属性介绍
变量:我们这里的变量不是通常意义上的变量,是有本质区别的,我们这里的变量是虚拟的,是我们自己构造出来的,它的变量值是由我们的自定义算法计算出来的;
随便点击一个系统生成的变量后边的设置【按钮】,右边的表单区域就会显示对应的变量信息;变量的属性主要有5个属性:
4.1.1、变量名称
变量名称:变量的名称,每个变量都有属于自己的名称,便于区别记录;
4.1.2、变量类型
变量类型:和点位值类型是一样的,也是有三种类型,整型、浮点型和字符串,这个属性就是下面的自定义算法的返回值类型;
4.1.3、默认值
默认值:就是算法默认值,如果算法中出现异常或者没有返回值,变量的值就是这个值;
4.1.4、数据点位
数据点位:这里的左边显示的点位列表就是我们在创建模版时添加的数据点位,这里是多选,意味着可以选择n个点位,那么这n个点位的实时值 就会被我们注入到自定义算法的第一个形参里面,第二个形参就是【4.1.3】中的默认值;比如我们在调用的时候就是如下
自定义算法名([点位值1,点位值2,点位值3,...], 默认值);
我们会把所有点位值按选择的顺序放到数组中,然后在作为自定义算法的第一个形参中;
4.1.5、自定义算法
自定义算法: 算法是我们变量的核心,一切皆变量;在自定义算法中, 我们可以像在普通js方法中一样写我们想要的结果的代码,它的参数就是我们选择 的点位值,也就是说,可以用n个点位值,通过这个方法得到我们想要的结果,然后把这个值给到我们绑定的图元上,达到我们的就控制显示效果;
4.2、变量应用场景举例
4.2.1、返回一个点位实时值的变量
只选择一个数据点位参与计算,变量值的类型就是点位值的类型,直接返回改点位值的变量。其实,我们系统生成的这 四个变量就是这种变量,就是点位值原值输出,什么换算都不做;如果我们像直接取某个点位的值就用这种变量;
4.2.2、将一个点位值缩小1000倍的变量
(1)首先在【数据模版管理】中添加一个数据点位,叫‘测点电压’,它的点位值类型为浮点型;
(2) 在编辑器的配置虚拟变量面板中点击【新增】按钮添加一个变量;如下图所示:
设置:
变量名称:测点电压(kv),顾名思义这个变量返回一个单位为 kv的值;
变量类型:浮点型 ,【测点电压】点位的类型为浮点型,缩小1000倍还是浮点型;
默认值:0;
数据点位:只选择 【测点电压】;
自定义算法:算法内容如下
const params = arguments[0];
const defaultValue = arguments[1];
try{
if(!params || params.length <= 0) return defaultValue;
let dyValue = params[0];
// dyValue数量级单位是 V 缩小1000倍 数量级单位为 KV
dyValue = parseFloat(dyValue) / 1000
return dyValue;
} catch (e) {
return defaultValue;
}
从参数arguments 中取出 arguments[0], 里面存放的就是点位值的数组也就是: [测点电压值],所以我们要获取 测点电压值电压值的话就是这样获取:arguments[0][0],对应到我们的算法中的代码就是
const params = arguments[0];
let dyValue = params[0];
dyValue就是arguments[0][0],就是【测点电压值】; 这个电压值的单位是 v(伏),我们要转化为 kv(千伏),dyValue就要缩小1000倍;对应的代码就是:
dyValue = parseFloat(dyValue) / 1000;
然后 return dyValue; 返回了这个缩小了1000倍的电压值;
注意自定义算法为了规范一定要有返回值;
4.2.3、三个开关的状态决定电灯是否开关的变量
我们规定 开关状态有两种:开为1 关为0;电灯状态有两种:1点亮,2熄灭; 这里有个三个开关控制的电灯,是一个三控开关系统,其中一个开关开,电灯就会点亮,所有开关关,电灯就熄灭;
(1)首先在【数据模版管理】中添加三个数据点位,叫‘开关1、开关2、开关3’,这三个点位的值类型类整型,并且取值为只有 0或1; 定义0为关,1为开,
(2) 在编辑器的配置虚拟变量面板中点击【新增】按钮添加一个变量;如下图所示:
设置:
变量名称:电灯状态控制变量;
变量类型:整型; 1点亮,2熄灭;
默认值:0;默认关闭;
数据点位:选择3个点位, 开关1、开关2、开关3;
自定义算法:算法内容如下
const params = arguments[0];
const defaultValue = arguments[1];
try{
if(!params || params.length <= 0) return defaultValue;
let kg1Value = params[0];
let kg2Value = params[1];
let kg3Value = params[2];
let status = kg1Value == 1 || kg2Value == 1 || kg3Value == 1;
return status ? 1 : 0;
} catch (e) {
return defaultValue;
}
从参数arguments 中取出 arguments[0], 里面存放的就是点位值的数组也就是: [开关1值,开关2值,开关3值],所以我们要获取 开关1、开关2、开关3的状态值的话就是这样获取:arguments[0][0]、arguments[0][1]、arguments[0][2],对应到我们的算法中的代码就是
const params = arguments[0];
let kg1Value = params[0];// 开关1状态
let kg2Value = params[1];// 开关2状态
let kg3Value = params[2];// 开关3状态
电灯状态值计算如下
let status = kg1Value == 1 || kg2Value == 1 || kg3Value == 1;
return status ? 1 : 0;
然后 return status ? 1 : 0; 返回了电灯要么开1, 要么关0;
5、图元绑定变量
5.1、变量控制图元状态
5.1.1、创建变量控制图元
5.1.2、绑定变量
根据上图操作后,电灯状态控制变量就和电灯图元绑定上了;
注意最后一定要点击右上角保存按钮同步到服务器; ctrl + S 只会保存到本地;
5.1.3、模拟发布三个开关点位值切换图元状态
点击右上角预览;这时我们可以去 emqx websocket客户端模拟发送点位数据;
(1)topic为: topic/preview/subscribe/device/{deviceId} 发送数据为:{'kg1':0,'kg2':0,'kg3':0}
预览界面收到消息:点位数据是 {'kg1':0,'kg2':0,'kg3':0}
此时电灯显示的是关状态的图片;
(2)再次发送点位数据 {'kg1':1,'kg2':0,'kg3':0}
预览界面收到消息:点位数据是 {'kg1':0,'kg2':0,'kg3':0}
此时电灯显示的是开状态的图片;
5.2、将变量值显示到图元上
5.2.1、创建图元;
5.2.2、绑定变量
根据上图操作后,我们把在【4.2.2】步骤中创建的 测点电压(kv)变量就和显示电压的变量文本图元绑定了,我们给这个图元取名为 【测点电压文本】,它由两部分组成,数值区和单位区,单位区显示固定文本 ‘千伏’;
5.2.3、模拟发布测点电压点位值切换图元显示的电压
点击右上角预览;这时我们可以去 emqx websocket客户端模拟发送点位数据;
(1)topic为: topic/preview/subscribe/device/{deviceId} 发送数据为:{"dy":1500,"kg1":1,"kg2":0,"kg3":0}
如需了解更多关于万维组态,请添加微信: