本文介紹在一些特殊的場景和需求下,使用HslCommunication的可以實現一些比較有意思的功能。例行介紹HSL的安裝
github地址:https://github.com/dathlin/HslCommunication 如果喜歡可以star或是fork,還可以打賞支持,打賞請認准源代碼項目。
聯系作者及加群方式:http://www.hslcommunication.cn/
在Visual Studio 中的NuGet管理器中可以下載安裝,也可以直接在NuGet控制台輸入下面的指令安裝:
Install-Package HslCommunication
如果需要教程:Nuget安裝教程:http://www.cnblogs.com/dathlin/p/7705014.html
組件的完整信息和API介紹參照: http://api.hslcommunication.cn 組件的使用限制,更新日志,都在該頁面里面。
我們來看看這種系統的架構設計模式。

我們有一個主的后台服務器來連接現場的各種PLC設備,然后進行數據交互。這個沒有問題,很好實現,但是現在有需求,我們在遠程客戶端界面,或是手機端界面,瀏覽器界面,等等,需要對遠程的PLC進行讀寫一些數據操作,這時候怎么實現是最簡單方便的?
在HSL里,提供了兩種簡單的可能性。可以輔助你快速實現需要的操作信息。
1. 基於MRPC實現,詳細見文章:https://www.cnblogs.com/dathlin/p/14094128.html
優點:對客戶端的控制更強,權限控制也更加強,可以細化到每個API的權限控制,和MQTT深度結合,支持訪問TOPIC信息,傳輸數據有進度報告。
缺點:MRPC為定制協議,需要定制開發,目前實現了C#,java,python版本,其他平台或是語言都需要定制實現。
2.基於WebApi實現,下文詳細說明。
優點:客戶端標准化,使用postman即可測試,絕大多數語言和平台都支持webapi接口,已經有相關的輪子,可以直接調用。
缺點:MRPC的優點就是缺點。
我們開始寫代碼,我們先假設有1個PLC需要不停的采集,分析數據,做處理。我們新建一個控制台程序,安裝HslCommunication組件。為了方便起見,我們假設這個PLC是西門子PLC,實際上無論什么牌子的都是一樣的。
namespace ConsoleServer
{
class Program
{
static void Main( string[] args )
{
SiemensS7Net plc = new SiemensS7Net( SiemensPLCS.S1200, "127.0.0.1" ); // 此處拿了本地虛擬的PLC測試
plc.SetPersistentConnection( ); // 設置了長連接
while (true)
{
Thread.Sleep( 1000 ); // 每秒讀取一次
OperateResult<short> read = plc.ReadInt16( "M100" );
if (read.IsSuccess)
{
// 讀取成功后,進行業務處理,存入數據庫,或是其他的分析
Console.WriteLine( "讀取成功,M100:" + read.Content );
}
else
{
// 讀取失敗之后,顯示下狀態
Console.WriteLine( "讀取PLC失敗,原因:" + read.Message );
}
}
}
}
}
此處就簡化了一些操作信息,反正是要執行一些業務操作的。現在我們需要在客戶端的程序里,增加一個按鈕,比如功能是鎖定機台。這個功能的實現是寫入M300.1為True。如果解鎖,就是寫false

因為我們的客戶端是部署在其他電腦的,當然是需要新建一個winform的項目了,如果是WPF也是一樣的。也是弄兩個按鈕出來,然后寫事件。

有了事件之后,我們怎么來寫代碼呢?
如果想實現基於webapi來讀寫,代碼非常精簡。我們改造下服務器端的實現:
namespace ConsoleServer
{
class Program
{
static void Main( string[] args )
{
SiemensS7Net plc = new SiemensS7Net( SiemensPLCS.S1200, "127.0.0.1" ); // 此處拿了本地虛擬的PLC測試
plc.SetPersistentConnection( ); // 設置了長連接
HttpServer httpServer = new HttpServer( );
httpServer.RegisterHttpRpcApi( "MainPlc", plc );
httpServer.Start( 8000 ); // 需要管理員啟動
while (true)
{
Thread.Sleep( 1000 ); // 每秒讀取一次
OperateResult<short> read = plc.ReadInt16( "M100" );
if (read.IsSuccess)
{
// 讀取成功后,進行業務處理,存入數據庫,或是其他的分析
Console.WriteLine( "讀取成功,M100:" + read.Content );
}
else
{
// 讀取失敗之后,顯示下狀態
Console.WriteLine( "讀取PLC失敗,原因:" + read.Message );
}
}
}
}
}
增加了三段話,實例化服務,注冊PLC,啟動。
當前的服務器提供了什么RPC的接口呢?,我們運行起來。然后用HslCommunication的DEMO程序打開瞧瞧就可以了。
服務器端啟動之后,就是一直在打印讀取成功了。沒有其他的內容

好了,到這里我們的程序寫完了,我們的PLC已經提供了遠程讀寫的WebApi的接口了,可能我們會問,在哪里呢?我們打開demo看看。

上面的操作之后我們看到了所有的接口列表。

我們點擊其中的一個接口,例如 ReadOrderNumber 接口,我們想讀取PLC的訂貨號。點擊之后,界面變化了。

不管他,我們直接點擊讀取。

我們看到有數據返回了。我們成功讀取到了一個json字符串,是不是很熟悉,獲取規則如下:
因為讀取是可能會失敗的,也就是Content屬性可能為空,那么我們就需要先判斷 IsSuccess 為 True ,我們再去拿Content的數據。
如果為 False, 那么代表讀取失敗了,失敗原因就在 Message 里面。這時候,你可以顯示出來。或是記錄日志,寫入寫入數據庫都是可以的。
我們再來嘗試讀取M100的short數據,在PLC里就是 MW100的值。

結果如下:

當我們重新選擇ReadInt16接口的方法時,

這時候已經顯示當前的接口已經有一次調用的信息了。
我們再測試一個寫入的操作。

我們可以讀取驗證一下、

OK,我們現在用POSTMAIN測試一下。

需要注意的是,當前的方法是POST的。
既然支持webapi,最后我們來嘗試在網頁上的操作,我們先做一個網頁,放一個按鈕,然后搞一個點擊事件。去請求數據,然后顯示讀取結果。我們用到了 jquery,頁面如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HslCommunication教程</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<h1>測試Webapi的內容</h1>
<p>點擊下方的按鈕即可
</p>
<button onclick="GetPlcValue()">測試</button>
<p>結果如下:</p>
<p id="test1"></p>
<script type="text/javascript">
function GetPlcValue(){
$.ajax({
type:'post',
async: false,
url:'http://127.0.0.1:8000/MainPlc/ReadInt16',
dataType:'JSON',
data:JSON.stringify({
'address': 'M100'
}),
success:function(result){
console.log(result);
if(result.IsSuccess){
$("#test1").text("Read Success, value is : " + result.Content);
}
else{
$("#test1").text("Read Failed, Message: " + result.Message);
}
}
});
}
</script>
</body>
</html>
很簡單沒啥內容,我們運行下。

emmm,好像遇到跨域問題了,沒關系,我們在服務器上稍微更改一下。

然后我們在頁面上再次進行操作一下:

同理,寫入都是類似的。
最后我們來聊聊,如何實現你自己的API接口到 webapi上。例如我們要增加一個算法的接口,傳入兩個數,返回方法之和。
我們定義一個類。
public class Algorithms
{
[HslCommunication.Reflection.HslMqttApi(HttpMethod = "POST", Description = "這是一個計算兩個數相加的方法。")]
public int Add(int a, int b )
{
return a + b;
}
}
我們看這個方法,定義了POST,當然了,GET也可以的,這樣客戶端的方式只要匹配就好了。
然后我們注冊下服務

完事,我們看看客戶端的界面。

我們更改下傳入的值

當然,HttpServer進行用戶名驗證也是可以的。具體可以查看另一篇博客:https://www.cnblogs.com/dathlin/p/12335933.html
這時候的POSTMAN就是要攜帶基本的驗證了,我們來看看加一個權限控制的api的使用方法
public class Algorithms
{
[HslCommunication.Reflection.HslMqttApi(HttpMethod = "POST", Description = "這是一個計算兩個數相加的方法。")]
public int Add(int a, int b )
{
return a + b;
}
[HslCommunication.Reflection.HslMqttPermission(UserName = "admin")]
[HslCommunication.Reflection.HslMqttApi( HttpMethod = "POST", Description = "這是一個計算兩個數相乘的方法。" )]
public int Multipy( int a = 10, int b = 20 )
{
// 當前方法只能用戶名為admin的調用
return a * b;
}
}
我們增加的第二個方法就是增加權限的控制,這樣的話,客戶端再請求的話,就是需要增加權限頭
我們先看POSTMAN


我們看到了返回了數據,然后我們再看看發送的header里都有什么

這個內容就校驗的內容之一了,好了,我們在js里可以這么寫代碼了
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HslCommunication教程</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<h1>測試Webapi的內容</h1>
<p>點擊下方的按鈕即可
</p>
<button onclick="GetPlcValue()">測試</button>
<p>結果如下:</p>
<p id="test1"></p>
<script type="text/javascript">
function GetPlcValue(){
$.ajax({
headers:{
'Authorization': 'Basic YWRtaW46MTIzNDU2'
},
type:'post',
async: false,
url:'http://127.0.0.1:8000/Algorithms/Multipy',
dataType:'JSON',
data:JSON.stringify({
'a': 10,
'b': 20
}),
success:function(result){
console.log(result);
$("#test1").text("Read Success, value is : " + result);
//if(result.IsSuccess){
//$("#test1").text("Read Success, value is : " + result.Content);
//}
//else{
//$("#test1").text("Read Failed, Message: " + result.Message);
//}
}
});
}
</script>
</body>
</html>
然后再運行,就是返回了正確的結果了

如果有什么其他的問題,歡迎留言。
