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();登录后方可回帖
,之前看到也看到过这个,本来想用它WinTcpS7_Smart.dll使用西门子smartPLC通讯的,有站主的这个就准备抄代码了


日志的读写测试:
//调用C#程序集 import dotNet; var appDomain = dotNet.clr().createAppDomain(); //加载应用程序目录下的程序集 var HSIdll = appDomain.loadFile("\res\HslCommunication.dll"); //声明接口 var logNet = HSIdll.new("HslCommunication.LogNet.LogNetSingle","C:\Users\Administrator\Desktop\HSICOM\aardio工程15\log\123.txt"); logNet.WriteDebug( "Debug log test" ); logNet.WriteInfo( "Info log test" ); logNet.WriteWarn( "Warn log test" ); logNet.WriteError( "Error log test" ); logNet.WriteFatal( "Fatal log test" ); // 还有下面的几种额外的情况 logNet.WriteNewLine( ); // 追加一行空行 logNet.WriteDescrition( "test" ); // 写入额外的注释的信息 logNet.WriteAnyString( "any string" ); // 写任意的数据,不受格式化影响 // 此处的5个等级有高低之分 debug < info < warn < error < fatal < all // 如果我们需要屏蔽debug等级的话 logNet.SetMessageDegree( HSIdll.getEnum("HslCommunication.LogNet.HslMessageDegree.INFO") ); // 如果我们需要屏蔽debug及info等级的 logNet.SetMessageDegree( HSIdll.getEnum("HslCommunication.LogNet.HslMessageDegree.WARN") ); // 带关键字的功能 logNet.WriteDebug( "A","Debug log test" ); logNet.WriteInfo( "B", "Info log test" ); logNet.WriteWarn( "C", "Warn log test" ); logNet.WriteError( "A", "Error log test" ); logNet.WriteFatal( "B", "Fatal log test" ); // 有了关键字之后,我们就可以根据关键字过滤了 logNet.FiltrateKeyword( "B" ); // 我们不需要B的关键字的日志 logNet.RemoveFiltrate( "B" ); // 重新需要B的关键字的日志