一、需求分析
- 某生产企业想在微信端随时查看其所有设备的工作状况的实时数据。并能对超标值、异常值等进行报警。
- 内外网隔离,保证企业内网安全,互联网绝不能进入内网操控设备进行破坏。
二、实际困难
- 虽然所有数据都已经归集到其中控室的组态王软件中,但软件已经过保过维,当时的组态工程师早已经离职,无法咨询。
- 我 从来没有接触过组态软件。
三、入坑研究
-
因为没接触过组态软件,直接先花了几个小时坐在企业中控室研究组态软件的各种。先看界面,再看帮助手册,因为是生产系统,不敢乱点乱操作。未果,说拷贝他们的组态安装包回家继续研究才能决定能不能实现微信看数据。
-
实例不够进度慢,在本机安装了组态王,慢慢吞吞研究了两三天,在其安装目录下的文档“第26章 其他程序访问组态王数据的方式”中找到了一点理论希望。
文档原文:通过ActiveX控件访问 组态王提供客户端控件KvTcpipClientOcx.ocx,用户通过在第三方程序中调用该控件,可以获得组态王实时数据,也可以订阅组态王实时数据。
组态王自己实现了个叫KvRealDBClient.exe程序,就是利用KvTcpipClientOcx开发的,有两个关键的方法:
short Method_LoginServer(LPCTSTR server_ip_address, unsigned short server_port,
LPCTSTR user_name,LPCTSTR user_password);
登录组态王的实时变量服务器。
参数:server_ip_address:服务器(组态王)IP地址
server_port:服务气端口号
user_name:用户名
user_password:用户密码
返回值:
0:登录失败
1:登录通讯五秒钟内没有应答
2:登录成功(用户具有最高级别999时才具有写入权限)
3:登录通讯五秒钟内有应答,但客户CliendId没有正确分配
4:已处在登录状态
11:非法用户,验证失败
short Method_GetVariableValueByVariableId(unsigned short station_id, unsigned long variable_id,
short * variable_value_ type, BSTR* variable_value_string)
取得某站点下某变量的变量值(根据变量ID)
参数: station_id:站点ID
variable_id:变量ID
variable_value_type:变量类型,变量类型的描述为
整型 3
实型 4
离散型 11
字符串型 16400
variable_value_string:变量值
返回值: 0 成功, 1 web控件未启动,2、访问本地库或者远程库失败。
点击KvRealDBClient.exe测试也确实能登录、获取变量ID,能根据ID获取到实时数据:
四、坑我方案Version0.1
- 企业置一台服务器,能上互联网,作为微信端查看数据的web服务器,买个穿透软件将80端口的web服务挂到互联网(自己不会这个技术)。其实如果不嫌繁杂和预算多点,可以做成小程序或者直接上App。
- 内外网隔离实在是想不出啥招,摆渡型网闸之类的硬件太贵,都懒得跟企业提了。那怎么办?服务器和组态王中控机通过串口通信!!! 服务器的串口接收中控机串口发出的数据并解析入库,中控机每分钟给串口写数据。这是我以为的安全方式了,才疏学浅,请求各位看官指教。
- 中控机用aardio调用KvTcpipClientOcx插件的方法获取各个变量的值,组成字符串,然后通过串口发送。为何用aardio?写串口代码少!!!暂时看是满足需求的。于是注册Ocx控件,临时边学边写aardio,弄出了未验证的代码如下:
import console;
import fsys.ini;
console.setTitle("数据发送");
//读取配置
ini=fsys.ini("\配置文件.ini");
setting = ini.getSection("服务器");
//console.dump(setting)
var idMaps = {
//进水
{"42343423432423"; "1101"; 3};
}
var dataStr = "##";
//组态王控件调用
import com.comm;
var kvServer = com.CreateObject("KVTCPIPCLIENTOCX.KvTcpipClientOcxCtrl.1");
var station_id = 1;
var variable_value_string = "";
console.log("登录组态王...");
var logined = kvServer.Method_LoginServer(setting.ip, setting.port, setting.user,
setting.password);
console.log("登录返回: " , logined);
if(2 == logined || 4 == logined){
var tmp;
for(i=1; #idMaps; 1){
tmp = idMaps[i];
//获取当前时间数据
var ret = kvServer.Method_GetVariableValueByVariableId(station_id, tmp[1],
tmp[3], variable_value_string) ;
//调用成功才将值计入
if(0 == ret){
dataStr += "#" + tmp[2] +"-" + variable_value_string;
}
}
}
dataStr += '\r\n';
console.log(dataStr);
//将数据发送到串口
//创建MSComm控件
var comm = com.comm();
//响应MSComm控件的事件
comm.onComm = function(event){
if( event == comm.comEvReceive ){
//不做任何处理
}
}
//设置串口控件属性
comm.commPort = setting.comname; //设置串口
comm.sttings = "9600,N,8,1";//设置波特率等参数
comm.inBufferSize = 1024; //设置输入缓冲区大小
comm.outBufferSize = 512; //设置输出缓冲区大小
comm.rThreshold = 1; //设置收到多少个字符后触发OnComm事件
comm.inputMode = 1; //设置输入方式为二进制方式
comm.inputLen = 0; //设置当前接收长度为0
comm.portOpen = true; //打开串口
comm.getInput(); //清除接收缓冲区数据
//发送,字符串太长,分几次发送
var cishu = #dataStr;
//console.log(string.left(dataStr, 512));
//console.log(string.right(dataStr, (cishu - 512)));
comm.output = string.left(dataStr, 512);
comm.output = string.right(dataStr, (cishu - 512));
//关闭串口
comm.portOpen = false;
//console.pause();
}
wonderful,看上去很快就能完成了。就差把这个1.4M的exe放到工控机上去测试了。
五、现实打得我脸无完肤
- 因为组态王保护措施很足,有加密狗插着才能正常运行,我自己按照文档编的组态工程只能运行在演示环境下,且两个小时自动退出,哎,被这个晃晕了,以为只能去工控机上测试,后来发现这两个小时内也是可以测试的。
- 于是屁颠屁颠抱着开发好的程序去企业了。
哎!理想很丰满,现实很悲感。 因为第一步登录就通不过。不知道是数据类型不对呢,还是咋地,没细究出原因,因为aardio也不熟。
浪费了差不多两个星期时间,从企业回来,决定直接上Vc++试看看。
@todo......