之前有提過,Azure上的IoT Hub有個與眾不同的功能,就是它與裝置之間是處於雙向溝通的模式
所以訊息的傳遞,也可以從裝置到IoT Hub,IoT Hub也可以逆向傳送訊息到裝置中
不過Microsoft在2017年2月的更新版本中,IoT Hub可以直接對裝置端呼叫裝置中的副程式,而裝置也可以透過這個註冊的副程式,回傳資料到IoT Hub
要實作讓IoT Hub呼叫裝置上註冊的副程式,並回傳訊息的方式很簡單,在程式碼中加一些內容就可以了
1.在裝置的程式中,加入下面的程式碼
/// <summary>
/// 程式執行的動作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <returns></returns>
private async void frmMain_Load(object sender, EventArgs e)
{
// 定義裝置為IoT的device
if (deviceClient == null)
deviceClient = DeviceClient.CreateFromConnectionString("[IoT Hub的連接字串]", Microsoft.Azure.Devices.Client.TransportType.Amqp);
// 註冊回傳事件的動作
await deviceClient.SetMethodHandlerAsync("[在這裡輸入要註冊進IoT Hub的Function名稱]", OnCallMethod, null);
}
/// <summary>
/// 當IoT Call Method時,回傳的動作
/// </summary>
/// <param name="request"></param>
/// <param name="userContext"></param>
/// <returns></returns>
private async Task<MethodResponse> OnCallMethod(MethodRequest request, object userContext)
{
// 取得從IoT Hub上傳入的參數
string strInput = request.DataAsJson;
// 取得設定要直接回傳的值
string strReturnValue = "[在這裡可以放入JSON的物件並轉換成為字串]";
// 進行回傳動作
return new MethodResponse(Encoding.UTF8.GetBytes(strReturnValue), 200);
}
這段程式碼的動作,共分為兩個部份,frmMain_Load的動作中,執行了向IoT Hub註冊副程式名稱的動作,並且在device端的程式碼中,加入了被呼叫的副程式
而OnCallMethod就是當IoT Hub呼叫device端的副程式會執行的動作,並透過回傳JSON的字串,將訊息回傳到IoT Hub中。在OnCallMethod的內容中,request.DataAsJson的內容則是從IoT Hub上傳入至device端的訊息內容
程式碼的部份,就加入這樣的功能就可以,接著就可以直接開啟DeviceExplorer,進行Call Method的動作
https://github.com/Azure/azure-iot-sdk-csharp/tree/master/tools/DeviceExplorer
2.開啟DeviceExplorer,並連上IoT Hub後,切換到[Call Method On Device]的頁籤,在這個頁籤中,選擇了要從IoT Hub呼叫的裝置代碼,並輸入要呼叫在device端註冊的Function名稱,而下方的[Method Payload]則是要從IoT Hub送到device端的JSON訊息
3.接著打開裝置端的程式,將Call Method的資訊作一個填入的動作,從下圖中可以看到,在裝置的程式中,Method Name必須要與IoT Hub傳入的Method Name相同,而下方的Return Value,則是當IoT Hub執行Call Method的時候會回傳的JSON訊息
4.到這裡,IoT Hub與Device端都已經準備好,從DeviceExplorer按下呼叫後,可以看到在右方的device端接收到了IoT Hub上傳下來的訊息並顯示在畫面上,而從device端回傳的JSON訊息,也顯示在左方的 DeviceExplorer的畫面中。這代表了雙方的訊息已經透過註冊後的副程式進行直接的呼叫,並進行訊息的交換
如果不想下載DeviceExplorer的話,現在在Azure Portal上也可以透過現有的功能直接進行註冊副程式的呼叫,叫用的方式也很簡單
1.進入Azure Portal後,點開IoT Hub的項目後,點選左方[Device Explorer]的功能選單,再點選要呼叫副程式的裝置項目,接著在[裝置詳細資料]的視窗上,點選[直接方法]
2.接著在[直接方法]的視窗中,把[方法名稱] (Method Name)、[裝載] (Method Payload) 這兩個參數填入,並按下[叫用方法],執行完成後就可以看到下圖的結果,IoT Hub送出的訊息,透過呼叫直接方法,把訊息送至Device端,Device端的JSON也回傳至下方的[結果]畫面
如果說想透過程式碼的方式進行方法的呼叫,而不想使用Portal或是Device Explorer執行的話,透過SDK已經作好的套件也是可以達到一樣的效果的
1.我們先建立一個新的應用程式,並在畫面上放入DeviceId、Message以及Call Method用的文字方塊
2.接著在[Send]的按鈕事件中,加入下面的程式碼
/// <summary>
/// 回送訊息的動作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void btnSend_Click(object sender, EventArgs e)
{
string strDeviceId = txtDeviceId.Text;
string strMessage = txtMessage.Text;
if (!string.IsNullOrEmpty(strMessage))
{
var serviceMessage = new Microsoft.Azure.Devices.Message(Encoding.ASCII.GetBytes(strMessage));
serviceMessage.Ack = DeliveryAcknowledgement.Full;
serviceMessage.MessageId = Guid.NewGuid().ToString();
await serviceClient.SendAsync(strDeviceId, serviceMessage);
}
else
MessageBox.Show("請輸入要傳送的文字訊息");
}
這段程式碼,主要的內容就是將要下傳至裝置的訊息,透過SendAsync的方法,傳入到指定的裝置上,若是有需要進行訊息回傳的話,透過這個方法就可以達到了
3.在[Call Method]的按鈕事件中,加入下面的程式碼
/// <summary>
/// 呼叫Device端事件方法的動作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void btnCallMethod_Click(object sender, EventArgs e)
{
string strDeviceId = txtDeviceId.Text;
if (txtCallMethod.Text != "")
{
// 指定TimeOut的秒數
TimeSpan objTimeSpan = new TimeSpan(0, 0, 0, int.Parse(txtTimeout.Text));
// 建立呼叫用的DeviceMethod
CloudToDeviceMethod objMethod = new CloudToDeviceMethod(txtCallMethod.Text, objTimeSpan);
// 放入要下傳的Json字串
objMethod.SetPayloadJson(txtPayLoad.Text);
// 執行呼叫的動作
CloudToDeviceMethodResult result = await serviceClient.InvokeDeviceMethodAsync(txtDeviceId.Text, objMethod);
// 將結果放入到控制項中
txtResultStatus.Text = result.Status.ToString();
txtCallMethodResult.Text = result.GetPayloadAsJson();
}
else
MessageBox.Show("請輸入要呼叫的事件方法名稱");
}
這段程式碼就是用來呼叫裝置端事件的程式了,除了可以透過SetPayloadJson的方法,將有需要下傳到裝置端的JSON資料放入並一起呼叫外,在執行Call Method完成後,也可以透過CloudToDeviceMothodResult的物件,將呼叫得狀態以及從裝置端要回傳的JSON訊息內容,放入至文字方塊的內容
實際執行的結果如下圖
從上圖的結果可以看到,透過CallMethod的方法,不論是從Device端要傳送到IoT Hub的JSON訊息,或是要從IoT Hub下送至裝置端的內容,都可以完整的互相傳送了
舊版的IoT Hub,僅能透過訊息傳送的方式逆送至Device端,當Device端接收到訊息後,必須在程式碼中加入相對應的判斷才能進行訊息的回傳,但是回傳的內容不外乎將訊息再次傳入至IoT Hub,或是呼叫WebHooks的方式進行訊息的傳遞。現在,透過了呼叫直接方法(Call Method)的功能,IoT Hub就能直接執行裝置上的副程式,並直接取得裝置要與IoT Hub溝通並交換的訊息了