aardio调用HslCommunication.dll实现工业自动化通信研究学习
HslCommunication 专注于底层的技术通信及跨平台,由C#语言编写的dll类库, 可实现各种主流的PLC数据读写,实现modbus,机器人的各种协议读写等等 , 提供统一接口 , 程序人员只需要关注读写内容即可 .
官方网址: http://www.hslcommunication.cn
官方文档: http://api.hslcommunication.cn/html/c136d3de-eab7-9b0f-4bdf-d891297c8018.htm
目前支持多家设备和仪器,列表如下:
以三菱PLC为例子 , 其他的plc调用方式基本是一模一样的,就是调用的类不一样,参数配置不一样而已。以下的逻辑都是适用的.
很遗憾, 我这边没有PLC测试, 也没有去安装PLC虚拟机 , 如果你有的话可以测试下.
//调用C#程序集 import dotNet; var appDomain = dotNet.clr().createAppDomain(); //加载应用程序目录下的程序集 var HSIdll = appDomain.loadFile("\res\HslCommunication.dll"); //声明接口 , 地址和端口号 var melsecMc = HSIdll.new("HslCommunication.Profinet.Melsec.MelsecMcNet", "192.168.1.110", 6000); //连接服务器 var connect = melsecMc.ConnectServer( ); //判断是否成功 if (!connect.IsSuccess) { console.log( "connect failed:" + connect.Message ); }else { console.log( "connect success!"); } // 举例读取D100的值 var D100 = melsecMc.ReadInt16( "D100" ).Content; console.log("D100",D100); // 实际上所有的读写都是返回是否成功的标记的,在实际的开发中,需要严格的判定,怎么判定呢?如下的代码 var readD100 = melsecMc.ReadInt16( "D100" ); if (readD100.IsSuccess) { // 读取成功,这时候获取Content才是正确的值 var value = readD100.Content; console.log("readD100",readD100); } else { // 读取失败,如果仍然坚持去获取Content的值,就为0 } // 读写是否成功的情况,应用于几乎所有的读写代码,只要看清楚返回的数据类型即可 melsecMc.ConnectClose( );
modbus的例子:
//调用C#程序集 import dotNet; var appDomain = dotNet.clr().createAppDomain(); //加载应用程序目录下的程序集 var HSIdll = appDomain.loadFile("\res\HslCommunication.dll"); //声明接口 , 参数: 站号 var BusRtuClient = HSIdll.new("HslCommunication.ModBus.ModbusRtu",com.Variant(1,0x11/*_VT_UI1*/)); mainForm.button.oncommand = function(id,event){ BusRtuClient.SerialPortInni( "COM1",9600 ); BusRtuClient.Open( ); // 打开 } mainForm.button2.oncommand = function(id,event){ //从100寄存器读取一个int32数据 var short100 = BusRtuClient.ReadInt32("100").Content; // 读取寄存器100的short值 console.log("short100",short100); } mainForm.button3.oncommand = function(id,event){ //向寄存器100里面写入uint16类型的数据 BusRtuClient.Write("100", com.Variant((tonumber(mainForm.edit.text)),0x12/*_VT_UI2*/) );// 写入寄存器100为12345 } mainForm.button4.oncommand = function(id,event){ BusRtuClient.Close( ); }
这里需要特别注意: BusRtuClient.SerialPortInni( "COM1",9600 );其实可以有多个参数
BusRtuClient.Write("100", 123 );的第二个参数传过去后会变成 int32 , , 那么如果是其他参数类型, 那么就需要用
com.Variant(2,0x12/*_VT_UI2*/)
或者 用新版aardio的
com.Uint16(2);
来定义Uint16类型, 其他的依次类推.
数组的话, 用
com.SafeArray(3/*_VT_I4*/,12,34,56)
或者 新版aardio的 ,
com.int32({12,34,56})
来定义三个int32类型数组.
于是, 我们测试下读取两个uint16数据:
mainForm.button2.oncommand = function(id,event){ var short100 = BusRtuClient.ReadInt16("100",com.Variant(2,0x12/*_VT_UI2*/)).Content; // 读取寄存器100的short值 console.dump("short100",short100); }
using System; using System.Text; using System.Threading; using HslCommunication; using HslCommunication.MQTT; namespace MqttTestClient { class Program { static void Main(string[] args) { MyClass mc = new MyClass(); mc.Start(); mc.Connect();//连接 mc.Regist();//注册 Console.WriteLine("输入“send”发送消息"); string s = Console.ReadLine(); if (s == "send") { Console.WriteLine("我发送成功了"); mc.SendMsg(); } Console.ReadLine(); } public class MyClass { private MqttClient mqttClient = null; public void Start() { mqttClient = new MqttClient(new MqttConnectionOptions() { ClientId = "ABC", IpAddress = "127.0.0.1", Port = 6666, Credentials = new MqttCredential("admin", "admin"), // 设置了用户名和密码 }); } public void Connect() { // 连接 OperateResult connect = mqttClient.ConnectServer(); if (connect.IsSuccess) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed"); } } public void SendMsg() { // 测试发布 mqttClient.PublishMessage(new MqttApplicationMessage() { Topic = "A", // 主题 QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce, // 消息等级 Payload = Encoding.UTF8.GetBytes("This is test message!"), // 数据 Retain = false, // 是否保留 }); } public void Regist() { // 订阅测试,在label1上显示结果 mqttClient.OnMqttMessageReceived += MqttClient_OnMqttMessageReceived; // 调用一次即可 mqttClient.SubscribeMessage("A"); // 订阅A的主题 } private void MqttClient_OnMqttMessageReceived(string topic, byte[] payload) { //topic是主题名字。payload是消息内容; Console.WriteLine("我收到了消息了"); string s = Encoding.UTF8.GetString(payload); Console.WriteLine(s); } } } }
这是个mqtt客户端,但是处理
mqttClient.OnMqttMessageReceived += MqttClient_OnMqttMessageReceived; // 调用一次即可
总是报错,不知道怎么写了,现在连接成功,就是不知道如何输出消息,请求高手能指点下不
import console; //调用C#程序集 import dotNet; var appDomain = dotNet.clr().createAppDomain(); //加载应用程序目录下的程序集 var HSIdll = appDomain.loadFile("\res\HslCommunication.dll"); var options= HSIdll.new("HslCommunication.MQTT.MqttConnectionOptions"); options.CleanSession = false; options.IpAddress="127.0.0.1"; options.Port=1883; options.ClientId="abc123"; var mqttClient= HSIdll.new("HslCommunication.MQTT.MqttClient",options); mqttClient.OnMqttMessageReceived = MqttClient_OnMqttMessageReceived; // 绑定事件显示总是报错 //连接服务器 var connect = mqttClient.ConnectServer(); //判断是否成功 if (!connect.IsSuccess) { console.log( "connect failed:" + connect.Message ); }else { console.log( "connect success!"); } var sub = mqttClient.SubscribeMessage( "/Pub" ); if (sub.IsSuccess) { console.log( "订阅"++ sub.Message ); } else { console.log( "connect failed:" + sub.Message ); } mqttClient.OnMqttMessageReceived=function(topic,payload) begin Console.log( "Topic:" + topic ); end; console.pause(true);
回复#11 @你又变了 :
实测可以收到, 是你自己代码写的有问题, 都说了让你删掉那句你纠结的...... , 另外回调参数有三个 .... , 为什么有三个参数你楼上自己函数原型都写出来了
import win.ui; /*DSG{{*/ var winform = win.form(text="aardio mqtt";right=354;bottom=190) winform.add() /*}}*/ import console; console.open() //调用C#程序集 import dotNet; //加载应用程序目录下的程序集 var HSIdll = dotNet.load("\HslCommunication.dll"); var options = HSIdll.new("HslCommunication.MQTT.MqttConnectionOptions"); options.CleanSession = false; options.IpAddress="127.0.0.1"; options.Port=1883; options.ClientId="abc123"; var mqttClient= HSIdll.new("HslCommunication.MQTT.MqttClient",options); //连接服务器 var connect = mqttClient.ConnectServer(); //判断是否成功 if (!connect.IsSuccess) { console.log( "connect failed:" + connect.Message ); }else { console.log( "connect success!"); } mqttClient.OnMqttMessageReceived=function(client,topic,payload){ console.log("client:",client.ToString()) console.log("topic:",topic) console.log("payload:",payload) } winform.show(); win.loopMessage();
回复#15 @admin :
再请教:
在 OnMqttMessageReceived 这个线程回调函数里需要把接收数据显示到一个文本框里,但是收到信息会出现 闪崩现象。谢谢
thread.command.instance().updateStatic = function(stopic){ winform.ttopic.text= "主题:" ++ stopic; } mqttClient.OnMqttMessageReceived = function (client,topic,payload) { import thread.command; thread.command.post(topic); //console.log("topic:",topic) }
回复#17 @mndsoft :
首先, 你thread.command.post都用错了, post的第一个参数是啥, 自己看智能提示吧
其次, 这个received事件不需要你当线程用, 不需要每次都import thread...... , 你直接winform.edit.text = topic就可以.
import thread.command; var cmmd = thread.command(); cmmd.rev = function(str){ winform.edit.appendText(str); } mqttClient.OnMqttMessageReceived=function(client,topic,payload){ console.log("client:",client.ToString()) console.log("topic:",topic) console.log("payload:",payload) thread.command.post("rev",topic); //winform.edit.appendText(topic); }
大致研究了下,基本算在aardio下完整实现了连接(带验证),订阅,发布等功能,贴下供一起学习。目前的一个问题就是mqttClient.OnMqttMessageReceived事件里无法把接收到的数据显示到 富文本框里,只能打印在普通文本框中或控制台,如下:
winform.edit.text = topic;
console.log("topic:",topic)
import win.ui; import enet.richeditEx; import fonts.fontAwesome; /*DSG{{*/ var winform = win.form(text="MQTT 基于HslCommunication 测试";right=701;bottom=492) winform.add( btnConnect={cls="plus";text="连接";left=546;top=34;right=660;bottom=65;bgcolor=5329231;border={radius=8};color=16777215;dl=1;dt=1;font=LOGFONT(h=-18;name='微软雅黑');iconStyle={align="left";font=LOGFONT(h=-20;name='FontAwesome');padding={left=10;top=2}};iconText='\uF0C1';notify=1;tabstop=1;textPadding={right=-35};x=8;y=5;z=14}; btnPM={cls="plus";text="发布";left=578;top=273;right=692;bottom=304;bgcolor=5329231;border={radius=8};color=16777215;dl=1;dt=1;font=LOGFONT(h=-18;name='微软雅黑');iconStyle={align="left";font=LOGFONT(h=-20;name='FontAwesome');padding={left=10;top=2}};iconText='\uF0C1';notify=1;tabstop=1;textPadding={right=-35};x=8;y=5;z=16}; btnSM={cls="plus";text="订阅";left=238;top=220;right=352;bottom=251;bgcolor=5329231;border={radius=8};color=16777215;dl=1;dt=1;font=LOGFONT(h=-18;name='微软雅黑');iconStyle={align="left";font=LOGFONT(h=-20;name='FontAwesome');padding={left=10;top=2}};iconText='\uF0C1';notify=1;tabstop=1;textPadding={right=-35};x=8;y=5;z=15}; checkbox={cls="checkbox";left=113;top=177;right=184;bottom=203;z=19}; checkbox2={cls="checkbox";text="HEX";left=520;top=279;right=569;bottom=298;checked=1;z=25}; cmbSM={cls="combobox";left=101;top=222;right=216;bottom=248;edge=1;items={"B003"};mode="dropdown";z=20}; combobox2={cls="combobox";left=479;top=221;right=630;bottom=247;edge=1;items={};mode="dropdown";z=23}; edit={cls="edit";text="Edit";left=10;top=324;right=695;bottom=373;edge=1;multiline=1;z=26}; plus={cls="plus";left=14;top=14;right=507;bottom=211;border={color=-5846288;radius=15;width=2};z=2}; plus3={cls="plus";text="连接参数";left=40;top=0;right=118;bottom=28;font=LOGFONT(h=-16);z=5}; plus9={cls="plus";text="55 AA AA AA AA AA 00 01 2F D7 16";left=98;top=270;right=514;bottom=305;align="left";border={color=-5846288;radius=4;width=1};editable=1;font=LOGFONT(h=-14;name='微软雅黑');notify=1;textPadding={left=6;top=6};z=17}; static={cls="static";text="主机:";left=38;top=50;right=86;bottom=72;transparent=1;z=3}; static2={cls="static";text="主机:";left=266;top=51;right=314;bottom=73;transparent=1;z=6}; static3={cls="static";text="客户端 ID:";left=27;top=92;right=86;bottom=114;transparent=1;z=8}; static4={cls="static";text="用户名:";left=33;top=138;right=97;bottom=160;transparent=1;z=10}; static5={cls="static";text="密码:";left=267;top=138;right=315;bottom=160;transparent=1;z=12}; static6={cls="static";text="清除会话:";left=36;top=177;right=101;bottom=199;transparent=1;z=18}; static7={cls="static";text="订阅主题:";left=19;top=227;right=84;bottom=249;transparent=1;z=21}; static8={cls="static";text="发布主题:";left=395;top=225;right=460;bottom=247;transparent=1;z=22}; static9={cls="static";text="发布内容:";left=23;top=280;right=88;bottom=302;transparent=1;z=24}; txtClientID={cls="plus";text="PC002";left=93;top=86;right=247;bottom=115;align="left";border={color=-2302756;radius=20;width=1};editable=1;font=LOGFONT(h=-14;name='微软雅黑');notify=1;textPadding={left=10;top=5;right=10};z=9}; txtIP={cls="plus";text="101.43.104.144";left=91;top=45;right=245;bottom=74;align="left";border={color=-16728032;radius=15;width=1};editable=1;font=LOGFONT(h=-14;name='微软雅黑');notify=1;textPadding={left=10;top=5;right=10};z=4}; txtLog={cls="richedit";left=7;top=379;right=697;bottom=486;bgcolor=0;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-13;name='微软雅黑');multiline=1;readonly=1;vscroll=1;wrap=1;z=1}; txtPW={cls="plus";text="12345678";left=323;top=132;right=477;bottom=161;align="left";border={color=-2302756;radius=20;width=1};editable=1;font=LOGFONT(h=-14;name='微软雅黑');notify=1;textPadding={left=10;top=5;right=10};z=13}; txtPort={cls="plus";text="1883";left=315;top=45;right=469;bottom=74;align="left";border={color=-2302756;radius=20;width=1};editable=1;font=LOGFONT(h=-14;name='微软雅黑');notify=1;textPadding={left=10;top=5;right=10};z=7}; txtUN={cls="plus";text="PC002";left=98;top=132;right=252;bottom=161;align="left";border={color=-2302756;radius=20;width=1};editable=1;font=LOGFONT(h=-14;name='微软雅黑');notify=1;textPadding={left=10;top=5;right=10};z=11} ) /*}}*/ import thread.command; //log信息 var r = enet.richeditEx(winform.txtLog) //调用C#程序集 import dotNet; //加载应用程序目录下的程序集 var HSIdll = dotNet.load("\HslCommunication.dll"); var options = HSIdll.new("HslCommunication.MQTT.MqttConnectionOptions"); var credential = HSIdll.new("HslCommunication.MQTT.MqttCredential",winform.txtUN.text, winform.txtPW.text); options.CleanSession = true; options.IpAddress=winform.txtIP.text; options.Port=1883; options.ClientId=winform.txtClientID.text; //创建 MqttCredential 对象并设置用户名和密码 options.Credentials = credential; //options.UseRSAProvider = true // 通信加密 mqttClient= HSIdll.new("HslCommunication.MQTT.MqttClient",options); //按钮前景色、背景色可以都改为图像路径 var skin = { background={ active=0xFF4B739A; default=0xFF4F5151; hover=0xFF4B739A; } foreground = { disabled = 0xFFCCCCCC; }; color = { }; border = { active = {bottom=3;color=0xFF8FC31F;padding=8;radius=10;} }; } winform.txtIP.skin( border = { focus = {width=1;color=0xFF6AB100;radius=15}; } ) winform.txtPort.skin( border = { focus = {width=1;color=0xFF6AB100;radius=15}; } ) winform.btnConnect.oncommand = function(id,event){ if winform.btnConnect.text="断开" { mqttClient.ConnectClose(); winform.btnConnect.iconText = '\uF0C1' winform.btnConnect.text ="连接" r.log(0,"断开连接!" ,0xFFDD254C); //前景色蓝色,背景色 return ; } winform.btnConnect.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250';text='请稍候...'} //连接服务器 var connect = mqttClient.ConnectServer(); //判断是否成功 if (!connect.IsSuccess) { winform.btnConnect.disabledText =null winform.btnConnect.iconText = '\uF0C1' winform.btnConnect.text ="连接" r.log(0,"连接失败:" ++ connect.Message ,0xFFFF0000); }else { winform.btnConnect.disabledText =null winform.btnConnect.iconText = '\uF127' winform.btnConnect.text = "断开" r.log(0,"连接成功:" ++ connect.Message ,0xFF14B383); } } /* thread.command.instance().updateStatic = function(stopic){ winform.edit.text =stopic winform.txtLog.appendText( textColor = 0xFF0000,stopic ++ '\r\n'; ) } */ // 定义一个外部函数来处理接收到的消息 thread.command.instance().processReceivedMessage = function(topic, payload) { winform.edit.text = topic; // 在主线程中更新 UI winform.post(function() { // 更新主题显示 winform.edit.text = topic; // 将 payload 转换为字符串并更新日志 var payloadString = System.Text.Encoding.UTF8.GetString(payload); winform.txtLog.appendText({textColor = 0xFF0000, "主题: " ++ topic ++ "\r\n负载: " ++ payloadString ++ "\r\n";}); }); } //接收信息 mqttClient.OnMqttMessageReceived = function (client,topic,payload) { //只能打印在文本框中或控制台 winform.edit.text = topic; //console.log("client:",client.ToString()) //console.log("topic:",topic) //console.log("payload:",payload) //使用以下几种方法显示到富文本框就闪退,不知道为何? //import thread.command; //thread.command.post("updateStatic",tx); //r.log(0,"主题:" ++ topic ,0xFF14B383); //接收数据 topic显示到文本框中 会闪退 //thread.command.instance().processReceivedMessage(topic, payload); //winform.post(function() { //winform.edit.text = topic; //将 payload 转换为字符串并更新日志 //var payloadString = System.Text.Encoding.UTF8.GetString(payload); //winform.txtLog.appendText({textColor = 0xFF0000, "主题: " ++ topic ++ "\r\n负载: " ++ payloadString ++ "\r\n";}); //}); //winform.txtLog.appendText( {textColor = 0xFF0000,topic ++ '\r\n';} ) //r.log(0,"主题:" ++ topic ,0xFF14B383); // 在主线程中更新 UI /* winform.post(function(){ var currentText = winform.edit.text; var newMessage = string.format("Topic: %s\r\n Payload: %s\r\n\r\n", topic, payload); winform.edit.text = currentText + newMessage; // 滚动到文本框底部 winform.edit.scrollCaret(); }); */ } //订阅主题 winform.btnSM.oncommand = function(id,event){ var sub = mqttClient.SubscribeMessage(winform.cmbSM.text); // mqttClient.SubscribeMessage( "/Pub" ); if (sub.IsSuccess) { r.log(0,"订阅成功:" ++ sub.Message ,0xFF14B383); } else { r.log(0,"订阅失败:" ++ sub.Message ,0xFFFF0000); } } //发布主题 参考文档:http://api.hslcommunication.cn/html/90929e44-65c0-951f-9b09-d45133bcdd3b.htm winform.btnPM.oncommand = function(id,event){ // 创建 MqttApplicationMessage 对象 var message = HSIdll.new("HslCommunication.MQTT.MqttApplicationMessage"); // 设置主题 message.Topic = "A003"; // 设置消息等级为 AtMostOnce message.QualityOfServiceLevel =0 // HSIdll.get("HslCommunication.MQTT.MqttQualityOfServiceLevel.AtMostOnce"); // 设置负载 var payload = System.Text.Encoding.UTF8.GetBytes("This is test message!"); message.Payload = payload; // 直接设置 Payload 属性 // 设置是否保留消息 message.Retain = false; // 发布消息 var publish = mqttClient.PublishMessage(message); if (publish.IsSuccess) { r.log(0,"发布成功:" ++ publish.Message ,0xFF14B383); } else { r.log(0,"发布失败:" ++ publish.Message ,0xFFFF0000); } } winform.btnConnect.skin(skin); winform.btnSM.skin(skin); winform.btnPM.skin(skin); winform.show(); win.loopMessage();
登录后方可回帖
日志的读写测试: