共用方式為


傳送和接收雲端到裝置的訊息

Azure IoT 中樞是一項完全受控的服務,可啟用的雙向通訊,包括數百萬個裝置和一個解決方案後端之間的雲端到裝置 (C2D) 訊息。

本文說明如何使用 Azure IoT SDK 來建置下列類型的應用程式:

  • 從 IoT 中樞傳訊佇列接收及處理雲端到裝置訊息的裝置應用程式。

  • 後端應用程式,透過 IoT 中樞訊息佇列將雲端到裝置訊息傳送給單一裝置。

本文旨在補充本文中參考的可執行 SDK 範例。

注意

本文中所述的功能僅適用於 IoT 中樞的標準層。 如需有關基本和標準/免費 IoT 中樞服務層級的詳細資訊,請參閱為您的解決方案選擇適合的 IoT 中樞層 (部分機器翻譯)。

概觀

若要讓裝置應用程式接收雲端到裝置訊息,必須連線到 IoT 中樞,然後設定訊息處理常式來處理傳入訊息。 Azure IoT 中樞裝置 SDK 提供類別和方法,讓裝置可用來接收和處理來自服務的訊息。 本文討論接收訊息的任何裝置應用程式的重要元素,包括:

  • 宣告裝置用戶端物件
  • 連線到 IoT 中樞
  • 從 IoT 中樞訊息佇列擷取訊息
  • 處理訊息,並將通知傳回 IoT 中樞
  • 設定接收訊息重試原則

若要讓後端應用程式傳送雲端到裝置訊息,必須連線到 IoT 中樞,並透過 IoT 中樞訊息佇列傳送訊息。 Azure IoT 中樞服務 SDK 提供應用程式可用來將訊息傳送至裝置的類別和方法。 本文討論傳送訊息至裝置的任何應用程式的重要元素,包括:

  • 宣告服務用戶端物件
  • 連線到 IoT 中樞
  • 建置和傳送此訊息
  • 接收傳遞意見反應
  • 設定傳送訊息重試原則

了解訊息佇列

若要了解雲端到裝置傳訊,請務必了解 IoT 中樞裝置訊息佇列運作方式的一些基本概念。

從解決方案後端應用程式傳送到 IoT 裝置的雲端到裝置訊息會透過 IoT 中樞路由傳送。 解決方案後端應用程式與目標裝置之間沒有直接的點對點傳訊通訊。 IoT 中樞會將傳入訊息放入其訊息佇列中,以供目標 IoT 裝置下載。

為了保證至少一次訊息傳遞,IoT 中樞會在每個裝置佇列保留雲端到裝置訊息。 在 IoT 中樞從佇列中移除訊息之前,裝置必須明確確認訊息已完成。 此方法保證連線失敗和裝置故障能夠恢復。

當 IoT 中樞將訊息放入裝置訊息佇列時,會將訊息狀態設定為加入佇列。 當裝置執行緒從佇列接收訊息時,IoT 中樞會藉由將訊息狀態設定為隱藏來鎖定訊息。 此狀態可防止裝置上的其他執行緒處理相同的訊息。 當裝置執行緒成功完成訊息的處理時,會通知 IoT 中樞,然後 IoT 中樞會將訊息狀態設定為已完成

成功接收和處理訊息的裝置應用程式會顯示完成訊息。 不過,如有必要,裝置也可以:

  • 「拒絕」訊息,這會導致「IoT 中樞」將它設定為 [無法寄出] 狀態。 透過訊息佇列遙測傳輸 (MQTT) 通訊協定連線的裝置無法拒絕雲端到裝置的訊息。
  • 放棄訊息,這會導致 IoT 中樞將訊息放回佇列,並將訊息狀態設定為已排入佇列。 透過 MQTT 通訊協定連線的裝置無法放棄雲端到裝置訊息。

如需雲端到裝置訊息生命週期及 IoT 中樞如何處理雲端到裝置訊息的詳細資訊,請參閱從 IoT 中樞傳送雲端到裝置訊息

接收雲端到裝置的訊息

本節說明如何在適用於 .NET 的 Azure IoT SDK 中使用 DeviceClient 類別來接收雲端到裝置訊息。

裝置用戶端應用程式可以使用兩個選項來接收訊息:

  • 輪詢:裝置應用程式會使用程式碼循環檢查新的 IoT 中樞訊息 (例如 whilefor 迴圈)。 循環會持續執行,並檢查訊息。
  • 回呼:裝置應用程式會設定非同步訊息處理常式方法,在訊息送達時立即呼叫。

宣告 DeviceClient 物件

DeviceClient 包含從 IoT 中樞接收訊息所需的方法和屬性。

例如:

static DeviceClient deviceClient;

提供連接參數

使用 CreateFromConnectionString 方法,提供 IoT 中樞主要連接字串和裝置識別碼給 DeviceClient。 除了必要的 IoT 中樞主要連接字串之外,CreateFromConnectionString 方法也可以多載以包含這些選擇性參數:

  • transportType - 傳輸通訊協定:HTTP 第 1 版、AMQP 或 MQTT 的變化。 AMQP 是預設值。 若要檢視所有可用的值,請參閱 TransportType 列舉
  • transportSettings - 介面,用來定義 DeviceClientModuleClient 的各種傳輸特定設定。 如需詳細資訊,請參閱 ITransportSettings 介面
  • ClientOptions - 允許在初始化期間設定裝置或模組用戶端執行個體的選項。

此範例會呼叫 CreateFromConnectionString 來定義 DeviceClient 連線 IoT 中樞和裝置識別碼設定。

static string connectionString = "{your IoT hub connection string}";
static string deviceID = "{your device ID}";
deviceClient = DeviceClient.CreateFromConnectionString(connectionString,deviceID);

輪詢的比較 \(英文\)

輪詢會使用 ReceiveAsync 來檢查訊息。

ReceiveAsync 的呼叫可以採取下列形式:

  • ReceiveAsync() - 等候訊息的預設逾時期間,再繼續。
  • ReceiveAsync (Timespan) - 使用特定逾時從裝置佇列接收訊息。
  • ReceiveAsync (CancellationToken) - 使用取消權杖從裝置佇列接收訊息。 使用取消權杖時,不會使用預設逾時期間。

使用傳輸類型的 HTTP 1 而不使用 MQTT 或 AMQP 時,ReceiveAsync 方法會立即傳回。 使用 HTTP 1 時,針對雲端到裝置訊息支援的模式是裝置以間歇方式連接而不常檢查訊息 (至少每 25 分鐘一次)。 發出更多 HTTP 1 接收會導致「IoT 中樞」對要求進行節流。 如需 MQTT、AMQP 和 HTTP 1 支援之間差異的詳細資訊,請參閱雲端到裝置的通訊指引選擇通訊協定

CompleteAsync 方法

在裝置收到訊息之後,裝置應用程式會呼叫 CompleteAsync 方法來通知 IoT 中樞已成功處理訊息,而且可以從 IoT 中樞裝置佇列安全地移除訊息。 無論使用的傳輸通訊協定為何,裝置在處理順利完成時,應該呼叫此方法。

郵件放棄、拒絕或逾時

使用 AMQP 和 HTTP 第 1 版通訊協定,而不使用 MQTT 通訊協定,裝置也可以:

  • 呼叫 AbandonAsync 來放棄訊息。 這會使得 IoT 中樞將訊息保留在裝置佇列中以供未來使用。
  • 呼叫 RejectAsync 來呼叫拒絕訊息。 這會將訊息從裝置佇列中永久移除。

如果發生導致裝置無法完成、放棄或拒絕訊息的情況,IoT 中樞在固定的逾時期間之後,會將訊息排入佇列以再次傳遞。 基於這個原因,裝置應用程式中的訊息處理邏輯必須是「等冪」,如此一來,多次接收相同訊息才會產生相同的結果。

如需雲端到裝置訊息生命週期及 IoT 中樞如何處理雲端到裝置訊息的詳細資訊,請參閱從 IoT 中樞傳送雲端到裝置訊息

輪詢迴圈

使用輪詢,應用程式會使用程式碼迴圈,重複呼叫 ReceiveAsync 方法,以檢查是否有新訊息,直到停止為止。

如果使用 ReceiveAsync 具有逾時值或預設逾時,在迴圈中每次呼叫 ReceiveAsync 會等候指定的逾時期間。 如果 ReceiveAsync 逾時,則會傳回 null 值,迴圈會繼續。

收到意見反應訊息時,Task 物件會由應該傳遞至 CompleteAsyncReceiveAsync 傳回。 呼叫 CompleteAsync 會通知 IoT 中樞根據 Task 參數,從訊息佇列中刪除指定的訊息。

在此範例中,迴圈會呼叫 ReceiveAsync,直到收到訊息或輪詢迴圈停止為止。

static bool stopPolling = false;

while (!stopPolling)
{
   // Check for a message. Wait for the default DeviceClient timeout period.
   using Message receivedMessage = await _deviceClient.ReceiveAsync();

   // Continue if no message was received
   if (receivedMessage == null)
   {
      continue;
   }
   else  // A message was received
   {
      // Print the message received
      Console.WriteLine($"{DateTime.Now}> Polling using ReceiveAsync() - received message with Id={receivedMessage.MessageId}");
      PrintMessage(receivedMessage);

      // Notify IoT Hub that the message was received. IoT Hub will delete the message from the message queue.
      await _deviceClient.CompleteAsync(receivedMessage);
      Console.WriteLine($"{DateTime.Now}> Completed C2D message with Id={receivedMessage.MessageId}.");
   }

   // Check to see if polling loop should end
   stopPolling = ShouldPollingstop ();
}

回撥

若要在裝置應用程式中接收回呼雲端到裝置訊息,應用程式必須連線到 IoT 中樞,並設定回呼接聽程式來處理傳入訊息。 從 IoT 中樞訊息佇列接收裝置的連入訊息。

使用回呼,裝置應用程式會使用 SetReceiveMessageHandlerAsync 來設定訊息處理常式方法。 接著會呼叫訊息處理常式,然後收到訊息。 建立回呼方法以接收訊息,可移除持續輪詢已接收訊息的需求。

回呼只能使用這些通訊協定:

  • Mqtt
  • Mqtt_WebSocket_Only
  • Mqtt_Tcp_Only
  • Amqp
  • Amqp_WebSocket_Only
  • Amqp_Tcp_only

Http1 通訊協定選項不支援回呼,因為 SDK 方法無論如何都需要輪詢已接收的訊息,這會使回呼原則失敗。

在此範例中,SetReceiveMessageHandlerAsync 設定名為 OnC2dMessageReceivedAsync 的回呼處理常式方法,每次收到訊息時都會呼叫此方法。

// Subscribe to receive C2D messages through a callback (which isn't supported over HTTP).
await deviceClient.SetReceiveMessageHandlerAsync(OnC2dMessageReceivedAsync, deviceClient);
Console.WriteLine($"\n{DateTime.Now}> Subscribed to receive C2D messages over callback.");

接收訊息重試原則

您可以使用 DeviceClient.SetRetryPolicy 來定義裝置用戶端訊息重試原則。

訊息重試逾時會儲存在 DeviceClient.OperationTimeoutInMilliseconds 屬性中。

SDK 接收訊息範例

.NET/C# SDK 包含訊息接收範例,其中包含本節所述的接收訊息方法。

傳送雲端到裝置訊息

本節說明使用 Azure IoT SDK for .NET 中的 ServiceClient 類別,將訊息從解決方案後端應用程式傳送至 IoT 裝置的基本程式碼。 如先前所述,解決方案後端應用程式會連線到 IoT 中樞,並將訊息傳送至使用目的地裝置編碼的 IoT 中樞。 IoT 中樞會將傳入訊息儲存至其訊息佇列,而訊息會從 IoT 中樞訊息佇列傳遞至目標裝置。

解決方案後端應用程式也可以針對傳送至 IoT 中樞的訊息,要求並接收傳遞意見反應,該訊息會透過訊息佇列傳送裝置。

宣告 ServiceClient 物件

ServiceClient 包含透過IoT中樞將訊息傳送至裝置所需的方法和屬性。

static ServiceClient serviceClient;

提供連線字串

使用 CreateFromConnectionString 方法,提供 IoT 中樞主要連接字串給 ServiceClient。 除了必要的 IoT 中樞主要連接字串之外,CreateFromConnectionString 方法也可以多載以包含這些選擇性參數:

  • transportType - AmqpAmqp_WebSocket_Only
  • transportSettings - Service Client 的 AMQP 和 HTTP Proxy 設定。
  • ServiceClientOptions - 允許在初始化期間設定服務用戶端執行個體的選項。 如需詳細資訊,請參閱 ServiceClientOptions

此範例會使用 IoT 中樞連接字串建立 ServiceClient 物件。

static string connectionString = "{your iot hub connection string}";
serviceClient = ServiceClient.CreateFromConnectionString(connectionString);

傳送非同步雲端到裝置訊息

使用 sendAsync,透過雲端將非同步訊息從應用程式傳送至裝置。 呼叫是使用 AMQP 通訊協定進行。

sendAsync 使用這些參數:

  • deviceID - 目標裝置的字串識別碼。
  • message - 雲端對裝置訊息。 訊息的類型為訊息,而且可以據以格式化。
  • timeout - 選用的逾時值。 如未指定,預設為一分鐘。

此範例會將測試訊息傳送至目標裝置,其逾時值為 10 秒。

string targetDevice = "Device-1";
static readonly TimeSpan operationTimeout = TimeSpan.FromSeconds(10);
var commandMessage = new
Message(Encoding.ASCII.GetBytes("Cloud to device message."));
await serviceClient.SendAsync(targetDevice, commandMessage, operationTimeout);

接收傳遞意見反應

傳送程式可向 IoT 中樞要求每個雲端到裝置訊息的傳遞 (或到期) 通知。 此動作可讓傳送程式使用通知、重試或補償邏輯。 訊息意見反應作業和屬性的完整描述會在訊息意見反應描述。

若要接收訊息傳遞意見反應:

  • 建立 feedbackReceiver 物件
  • 使用 Ack 參數傳送訊息
  • 等候接收意見反應

建立 feedbackReceiver 物件

呼叫 GetFeedbackReceiver,以建立 FeedbackReceiver 物件。 FeedbackReceiver 包含服務可用來執行意見反應接收作業的方法。

var feedbackReceiver = serviceClient.GetFeedbackReceiver();

使用 Ack 參數傳送訊息

每個訊息都必須包含傳遞通知的值,Ack 屬性,才能接收傳遞意見反應。 Ack 屬性可以是下列值之一:

  • none (預設值):不會產生任何意見反應訊息。

  • Positive:如果訊息已完成,則接收意見反應訊息。

  • Negative:如果訊息已過期 (或達到最大傳遞計數),則接收意見反應訊息,而不會由裝置完成。

  • FullPositiveNegative 結果的意見反應。

在本範例中,Ack 屬性設為 Full,針對一個訊息要求正面或負面的訊息傳遞意見反應。

var commandMessage = new
Message(Encoding.ASCII.GetBytes("Cloud to device message."));
commandMessage.Ack = DeliveryAcknowledgement.Full;
await serviceClient.SendAsync(targetDevice, commandMessage);

等候接收意見反應

定義 CancellationToken。 然後在迴圈中,重複呼叫 ReceiveAsync,檢查傳遞意見反應訊息。 每次呼叫 ReceiveAsync 會等候為 ServiceClient 物件定義的逾時期間。

  • 如果 ReceiveAsync 逾時過期且未收到任何訊息,ReceiveAsync 會傳回 null,迴圈會繼續。
  • 如果收到意見反應訊息,Task 物件會由應該傳遞至 CompleteAsync 以及取消權杖的 ReceiveAsync 傳回。 呼叫 CompleteAsync 會根據 Task 參數,從訊息佇列中刪除指定傳送的訊息。
  • 如有需要,接收程式碼可以呼叫 AbandonAsync,將傳送訊息放回佇列。
var feedbackReceiver = serviceClient.GetFeedbackReceiver();
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
// Call ReceiveAsync, passing the token. Wait for the timout period.
var feedbackBatch = await feedbackReceiver.ReceiveAsync(token);
if (feedbackBatch == null) continue;

本範例顯示包含這些步驟的方法。

private async static void ReceiveFeedbackAsync()
{
      var feedbackReceiver = serviceClient.GetFeedbackReceiver();

      Console.WriteLine("\nReceiving c2d feedback from service");
      while (true)
      {
         // Check for messages, wait for the timeout period.
         var feedbackBatch = await feedbackReceiver.ReceiveAsync();
         // Continue the loop if null is received after a timeout.
         if (feedbackBatch == null) continue;

         Console.ForegroundColor = ConsoleColor.Yellow;
         Console.WriteLine("Received feedback: {0}",
            string.Join(", ", feedbackBatch.Records.Select(f => f.StatusCode)));
         Console.ResetColor();

         await feedbackReceiver.CompleteAsync(feedbackBatch);
      }
   }

請注意,本意見反應接收模式,與在裝置應用程式中接收雲端到裝置訊息的模式類似。

服務用戶端重新連線

發生例外狀況時,服務用戶端會將該資訊轉送至呼叫的應用程式。 此時,建議您檢查例外狀況詳細資料,並採取必要的動作。

例如:

  • 如果是網路例外狀況,您可以重試作業。
  • 如果是安全性例外狀況 (未經授權的例外狀況),請檢查您的認證,並確定其為最新狀態。
  • 如果是超出節流/配額的例外狀況,請監視和/或修改傳送要求的頻率,或更新中樞執行個體級別單位。 請參閱 IoT 中樞配額和節流深入了解。

傳送訊息重試原則

您可以使用 ServiceClient.SetRetryPolicy 來定義 ServiceClient 訊息重試原則。

SDK 傳送訊息範例

.NET/C# SDK 包含訊息傳送範例,其中包含本節所述的服務用戶端方法。

接收雲端到裝置的訊息

本節說明如何從適用於 Java 的 Azure IoT SDK 使用 DeviceClient 類別來接收雲端到裝置訊息。

若要讓 Java 型裝置應用程式接收雲端到裝置訊息,必須連線到 IoT 中樞,然後設定來自 IoT 中輸的回呼接聽程式和訊息處理常式來處理傳入訊息。 如果裝置到 IoT 中樞訊息連線中斷,裝置應用程式也應該能夠偵測及處理中斷連線。

匯入 Azure IoT Java SDK 程式庫

本文所參考的程式碼會使用這些 SDK 程式庫。

import com.microsoft.azure.sdk.iot.device.*;
import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException;
import com.microsoft.azure.sdk.iot.device.transport.IotHubConnectionStatus;

宣告 DeviceClient 物件

DeviceClient 物件具現化需要下列參數:

  • connString - IoT 裝置連接字串。 連接字串是一組以 ';', 分隔的索引鍵/值組,索引鍵和值則以 '=' 分隔。 這應該包含這些索引鍵的值:HostName, DeviceId, and SharedAccessKey
  • 傳輸通訊協定 - DeviceClient 連線可以使用下列其中一個 IoTHubClientProtocol 傳輸通訊協定。 AMQP 功能最廣泛,可讓您經常檢查訊息,並允許拒絕和取消訊息。 MQTT 不支援訊息拒絕或放棄方法:
    • AMQPS
    • AMQPS_WS
    • HTTPS
    • MQTT
    • MQTT_WS

例如:

static string connectionString = "{a device connection string}";
static protocol = IotHubClientProtocol.AMQPS;
DeviceClient client = new DeviceClient(connectionString, protocol);

設立訊息回呼方式

使用 setMessageCallback 方法來定義從 IoT 中樞接收訊息時收到通知的訊息處理常式方法。

setMessageCallback 包括這些參數:

  • callback - 回呼方法名稱。 可以是 null
  • context - 選擇性類型 object 內容。 如未指定,使用 null

在這裡範例中,名為 MessageCallback 且沒有內容參數的 callback 方法會傳遞至 setMessageCallback

client.setMessageCallback(new MessageCallback(), null);

建立訊息回呼處理常式

回呼訊息處理常式會接收並處理從 IoT 中樞訊息佇列傳遞的傳入訊息。

在此範例中,訊息處理常式會處理傳入訊息,然後傳回 IotHubMessageResult.COMPLETE是。 IotHubMessageResult.COMPLETE 傳回值會通知 IoT 中樞訊息已成功處理,而且可以從裝置佇列安全地移除訊息。 裝置應該會在處理成功完成時傳回 IotHubMessageResult.COMPLETE,通知 IoT 中樞應該從訊息佇列中移除訊息,而不論其所使用的通訊協定為何。

  protected static class MessageCallback implements com.microsoft.azure.sdk.iot.device.MessageCallback
  {
      public IotHubMessageResult onCloudToDeviceMessageReceived(Message msg, Object context)
      {
          System.out.println(
                  "Received message with content: " + new String(msg.getBytes(), Message.DEFAULT_IOTHUB_MESSAGE_CHARSET));
          // Notify IoT Hub that the message
          return IotHubMessageResult.COMPLETE;
      }
  }

郵件放棄和拒絕選項

雖然應該成功接收大量傳入裝置的訊息,並導致 IotHubMessageResult.COMPLETE,但可能需要放棄或拒絕訊息。

  • 透過 AMQP 和 HTTPS,但不是透過 MQTT,應用程式可以:
    • IotHubMessageResult.ABANDON 訊息。 IoT 中樞會重新佇列,稍後再傳送。
    • IotHubMessageResult.REJECT 訊息。 IoT 中樞不會重新佇列訊息,並永久移除訊息佇列中的訊息。
  • 使用 MQTTMQTT_WS 的用戶端無法 ABANDONREJECT 訊息。

如果發生導致裝置無法完成、放棄或拒絕訊息的情況,IoT 中樞在固定的逾時期間之後,會將訊息排入佇列以再次傳遞。 基於這個原因,裝置應用程式中的訊息處理邏輯必須是「等冪」,如此一來,多次接收相同訊息才會產生相同的結果。

如需雲端到裝置訊息生命週期及 IoT 中樞如何處理雲端到裝置訊息的詳細資訊,請參閱從 IoT 中樞傳送雲端到裝置訊息

注意

如果您使用 HTTPS 而不是使用 MQTT 或 AMQP 作為傳輸,則 DeviceClient 執行個體將不會經常 (至少每隔 25 分鐘) 檢查 IoT 中樞是否有訊息。 如需 MQTT、AMQP 和 HTTPS 支援之間差異的詳細資訊,請參閱雲端到裝置的通訊指引選擇通訊協定

建立訊息狀態回呼方法

應用程式可以使用 registerConnectionStatusChangeCallback,註冊裝置連線狀態變更時要執行的回呼方法。 如此一來,應用程式就可以偵測已關閉的訊息連線,並嘗試重新連線。

在此範例中,IotHubConnectionStatusChangeCallbackLogger 註冊為聯機狀態變更回呼方法。

client.registerConnectionStatusChangeCallback(new IotHubConnectionStatusChangeCallbackLogger(), new Object());

會引發回呼並傳遞 ConnectionStatusChangeContext 物件。

呼叫 connectionStatusChangeContext.getNewStatus() 以目前連接狀態。

IotHubConnectionStatus status = connectionStatusChangeContext.getNewStatus();

傳回的連接狀態可以是下列其中一個值:

  • IotHubConnectionStatus.DISCONNECTED
  • IotHubConnectionStatus.DISCONNECTED_RETRYING
  • IotHubConnectionStatus.CONNECTED

呼叫 connectionStatusChangeContext.getNewStatusReason() 以取得連線狀態變更的原因。

IotHubConnectionStatusChangeReason statusChangeReason = connectionStatusChangeContext.getNewStatusReason();

呼叫 connectionStatusChangeContext.getCause() 以找到連線狀態變更的原因。 如果沒有可用的資訊,getCause() 可能會傳回 null

Throwable throwable = connectionStatusChangeContext.getCause();
if (throwable != null)
    throwable.printStackTrace();

如需示範如何擷取狀態變更回呼方法連線狀態變更狀態、裝置狀態變更原因和內容的完整範例,請參閱本文 SDK 接收訊息範例一節中列出的 HandleMessages 範例。

開啟裝置與 IoT 中樞之間的連線

使用開啟來建立裝置與 IoT 中樞之間的連線。 裝置現在可以以非同步方式從 IoT 中樞來回傳送和接收訊息。 如果用戶端已經開啟,方法就不會執行任何動作。

client.open(true);

SDK 接收訊息範例

HandleMessages: 一個 Microsoft Azure IoT SDK for Java 隨附的範例裝置應用程式,會連線到您的 IoT 中樞並接收雲端到裝置的訊息。

傳送雲端到裝置訊息

本節說明如何從適用於 Java 的 Azure IoT SDK 使用 ServiceClient 類別傳送雲端到裝置訊息。 解決方案後端應用程式會連線到 IoT 中樞,並將訊息傳送至使用目的地裝置編碼的 IoT 中樞。 IoT 中樞會將傳入訊息儲存至其訊息佇列,而訊息會從 IoT 中樞訊息佇列傳遞至目標裝置。

解決方案後端應用程式也可以針對傳送至 IoT 中樞的訊息,要求並接收傳遞意見反應,該訊息會透過訊息佇列傳送裝置。

新增相依性陳述式

新增相依性可在應用程式中使用 iothub-java-service-client 套件與 IoT 中樞服務進行通訊:

<dependency>
  <groupId>com.microsoft.azure.sdk.iot</groupId>
  <artifactId>iot-service-client</artifactId>
  <version>1.7.23</version>
</dependency>

新增 import 陳述式

新增這些 import 陳述式,以使用 Azure IoT Java SDK 和例外狀況處理常式。

import com.microsoft.azure.sdk.iot.service.*;
import java.io.IOException;
import java.net.URISyntaxException;

定義連線通訊協定

使用 IotHubServiceClientProtocol 來定義服務用戶端用來與 IoT 中樞通訊的應用程式層通訊協定。

IotHubServiceClientProtocol 只接受 AMQPSAMQPS_WS 列舉。

private static final IotHubServiceClientProtocol protocol =    
    IotHubServiceClientProtocol.AMQPS;

建立 ServiceClient 物件

建立 ServiceClient 物件,並提供 Iot 中樞連接字串和通訊協定。

private static final String connectionString = "{yourhubconnectionstring}";
private static final ServiceClient serviceClient (connectionString, protocol);

開啟應用程式與 IoT 中樞之間的連線

開啟 AMQP 傳送者連線。 此方法會建立應用程式與 IoT 中樞之間的連線。

serviceClient.open();

開啟訊息傳遞意見反應的意見反應接收者

您可以使用 FeedbackReceiver,將訊息傳遞至 IoT 中樞的意見反應。 FeedbackReceiver 是特製接收者,其 Receive 方法會傳回 FeedbackBatch,而不是 Message

在此範例中,會建立 FeedbackReceiver 物件,並呼叫 open() 陳述式來等候意見反應。

FeedbackReceiver feedbackReceiver = serviceClient
  .getFeedbackReceiver();
if (feedbackReceiver != null) feedbackReceiver.open();

新增訊息屬性

您可以選擇性地使用 setProperties 來新增訊息屬性。 這些屬性包含在傳送至裝置的訊息中,而且可在收到時由裝置應用程式擷取。

Map<String, String> propertiesToSend = new HashMap<String, String>();
propertiesToSend.put(messagePropertyKey,messagePropertyKey);
messageToSend.setProperties(propertiesToSend);

建立並傳送非同步訊息

Message 物件會儲存要傳送的訊息。 在此範例中,會傳遞「雲端到裝置訊息」。

使用 setDeliveryAcknowledgement 來要求傳遞/未傳遞至 IoT 中樞訊息佇列通知。 在此範例中,要求的通知 Full 為傳遞或未傳遞。

使用 SendAsync,將非同步訊息從用戶端傳送至裝置。 或者,您可以使用 Send (非同步) 方法,但此函數會在內部同步處理,一次只允許一個傳送作業。 訊息會從應用程式傳遞至 IoT 中樞。 IoT 中樞會將訊息放入訊息佇列中,準備好傳遞至目標裝置。

Message messageToSend = new Message("Cloud to device message.");
messageToSend.setDeliveryAcknowledgementFinal(DeliveryAcknowledgement.Full);
serviceClient.sendAsync(deviceId, messageToSend);

接收訊息傳遞意見反應

從應用程式傳送訊息之後,應用程式可以呼叫接收,且沒有逾時值。 如果未提供逾時值,則會使用預設逾時。 這會傳回 FeedbackBatch 物件,其中包含可以檢查的訊息傳遞意見反應屬性。

此範例會建立 FeedbackBatch 接收者,並呼叫 getEnqueuedTimeUtc ,並列印訊息加入佇列的時間。

FeedbackBatch feedbackBatch = feedbackReceiver.receive(10000);
if (feedbackBatch != null) {
  System.out.println("Message feedback received, feedback time: "
    + feedbackBatch.getEnqueuedTimeUtc().toString());
}

SDK 傳送訊息範例

安裝 Azure IoT SDK 程式庫

在呼叫任何相關程式碼之前,請先在開發機器上安裝 azure-iot-device SDK 程式庫:

pip install azure-iot-device

有兩個 Python SDK 類別可用來將訊息傳送至 IoT 裝置或從 IoT 裝置來回傳送訊息。 此頁面各節會說明來自這些類別的訊息處理方法。

  • IoTHubDeviceClient 類別包含方法,可從裝置建立同步連線到 Azure IoT 中樞,並從 IoT 中樞接收訊息。

  • IoTHubRegistryManager 類別包含 IoT 中樞登錄管理員作業的 API。 在本文中,來自此類別的方法會示範如何連線到 IoT 中樞,並將訊息傳送至裝置。

接收雲端到裝置的訊息

本節說明如何從適用於 Python 的 Azure IoT SDK 使用 IoTHubDeviceClient 類別來接收雲端到裝置訊息。

若要讓 Python 型裝置應用程式接收雲端到裝置訊息,必須連線到 IoT 中樞,然後設定來自 IoT 中輸的回呼訊息處理常式來處理傳入訊息。

匯入 IoTHubDeviceClient 物件

新增一行程式碼,以從 azure.iot.device SDK 匯入 IoTHubDeviceClient 函數。

from azure.iot.device import IoTHubDeviceClient

連線到裝置用戶端

具現化 IoTHubDeviceClient,將 IoT 中樞連接字串傳遞至 create_from_connection_string。 這會建立從裝置到 IoT 中樞的連線。

或者,您可以使用下列其中一種方法,將 IoTHubDeviceClient 連線到裝置:

deviceConnectionString = "{your IoT hub connection string}";
client = IoTHubDeviceClient.create_from_connection_string ({deviceConnectionString})

控制代碼重新連線

IoTHubDeviceClient 預設會嘗試重新建立已卸除的連線。 重新連線行為是由 IoTHubDeviceClient connection_retryconnection_retry_interval 參數所控管。

建立訊息處理常式

建立訊息處理常式函數,以處理裝置的連入訊息。

本範例中,在收到訊息時,便會呼叫 message_handler。 訊息屬性 (.items) 會使用迴圈列印至主控台。

def message_handler(message):
    global RECEIVED_MESSAGES
    RECEIVED_MESSAGES += 1
    print("")
    print("Message received:")

    # print data from both system and application (custom) properties
    for property in vars(message).items():
        print ("    {}".format(property))

    print("Total calls received: {}".format(RECEIVED_MESSAGES))

指派訊息處理常式

使用 on_message_received 方法,將訊息處理常式方法指派給 IoTHubDeviceClient 物件。

在此範例中,名為 message_handler 的訊息處理常式方法會附加至 IoTHubDeviceClient client 物件。 client 物件會等候接收來自 IoT 中樞的雲端到裝置訊息。 此程式碼會等候最多 300 秒 (5 分鐘) 的訊息,或在按下鍵盤按鍵時結束。

try:
    # Attach the handler to the client
    client.on_message_received = message_handler

    while True:
        time.sleep(300)
except KeyboardInterrupt:
    print("IoT Hub C2D Messaging device sample stopped")
finally:
    # Graceful exit
    print("Shutting down IoT Hub Client")
    client.shutdown()

SDK 接收訊息範例

接收訊息 - 接收從 Azure IoT 中樞傳送到裝置的雲端到裝置 (C2D) 訊息。

傳送雲端到裝置訊息

本節說明如何從適用於 Python 的 Azure IoT SDK 使用 IoTHubRegistryManager 類別傳送雲端到裝置訊息。 解決方案後端應用程式會連線到 IoT 中樞,並將訊息傳送至使用目的地裝置編碼的 IoT 中樞。 IoT 中樞會將傳入訊息儲存至其訊息佇列,而訊息會從 IoT 中樞訊息佇列傳遞至目標裝置。

匯入 IoTHubRegistryManager 物件

加入下列 import 陳述式。 IoTHubRegistryManager 包含 IoT 中樞登錄管理員作業的 API。

from azure.iot.hub import IoTHubRegistryManager

線上 IoT 中樞登錄管理員

將連線到 IoT 中樞的 IoTHubRegistryManager 物件具現化,並將 IoT 中樞連接字串傳遞至 from_connection_string

IoTHubConnectionString = "{Primary connection string to an IoT hub}"
registry_manager = IoTHubRegistryManager.from_connection_string(IoTHubConnectionString)

建置和傳送此訊息

使用 send_c2d_message 將訊息透過雲端 (IoT 中樞) 傳送至裝置。

send_c2d_message 使用這些參數:

  • deviceID - 目標裝置的字串識別碼。
  • message - 雲端對裝置訊息。 訊息的類型為 str (string)。
  • properties - 類型 dict 的屬性選擇性集合。 屬性可以包含應用程式屬性和系統屬性。 預設值是 {}

此範例會將測試訊息傳送至目標裝置。

# define the device ID
deviceID = "Device-1"

# define the message
message = "{\"c2d test message\"}"

# include optional properties
props={}
props.update(messageId = "message1")
props.update(prop1 = "test property-1")
props.update(prop1 = "test property-2")
prop_text = "Test message"
props.update(testProperty = prop_text)

# send the message through the cloud (IoT Hub) to the device
registry_manager.send_c2d_message(deviceID, message, properties=props)

SDK 傳送訊息範例

send_message.py - 示範如何傳送雲端到裝置訊息。

安裝 Node.js 訊息套件

執行下列命令,在開發機器上安裝 azure-iot-deviceazure-iothub 套件:

npm install azure-iot-device --save
npm install azure-iothub --save

azure-iot-device 套件 包含與 IoT 裝置互動的物件。 本文說明從 IoT 中樞接收訊息 Client 類別程式碼。

azure-iothub 套件包含與 IoT 中樞互動的物件。 本文說明 Client 類別程式碼,這些程式碼會透過 IoT 中樞將訊息從應用程式傳送至裝置。

在裝置應用程式中接收訊息

本節說明如何在適用於 Node.js 的 Azure IoT SDK 中使用 azure-iot-device 套件來接收雲端到裝置訊息。

若要讓 Node.js 型裝置應用程式接收雲端到裝置訊息,必須連線到 IoT 中樞,然後設定來自 IoT 中輸的回呼接聽程式和訊息處理常式來處理傳入訊息。 如果裝置到 IoT 中樞訊息連線中斷,裝置應用程式也應該能夠偵測及處理中斷連線。

建立用戶端模組

azure-iot-device 套件,使用 Client 類別建立 ClientClient 類別包含裝置可用來接收和傳送至 IoT 中樞的方法。

const Client = require('azure-iot-device').Client;

選擇傳輸通訊協定

Client 物件支援這些通訊協定:

  • Amqp
  • Http - 使用 Http 時,Client 執行個體會不常檢查來自 IoT 中樞的訊息 (至少每25分鐘)。
  • Mqtt
  • MqttWs
  • AmqpWs

如需 MQTT、AMQP 和 HTTPS 支援之間差異的詳細資訊,請參閱雲端到裝置的通訊指引選擇通訊協定

此範例會將 AMQP 通訊協定指派給 Protocol 變數。 此通訊協定變數會傳遞至本文 新增連接字串 一節中的Client.fromConnectionString 方法。

const Protocol = require('azure-iot-device-mqtt').Amqp;

訊息完成、拒絕和放棄功能

視選擇的通訊協定而定,可以使用訊息完成、拒絕和放棄方法。

AMQP 和 HTTP

AMQP 和 HTTP 傳輸可以完成、拒絕或放棄訊息:

  • 完成 - 若要完成訊息,傳送雲端到裝置訊息的服務會通知已收到訊息。 IoT 中樞會從訊息佇列中移除訊息。 此方法的格式為 client.complete(message, callback function)
  • 拒絕 - 若要拒絕訊息,傳送雲端到裝置訊息的服務會通知裝置未處理訊息。 IoT 中樞會將訊息從裝置佇列中永久移除。 此方法的格式為 client.reject(message, callback function)
  • 放棄 - 若要放棄訊息,IoT 中樞會立即嘗試重新傳送訊息。 IoT 中樞將訊息保留在裝置佇列中以供未來使用。 此方法的格式為 client.abandon(message, callback function)
MQTT

MQTT 不支援訊息完成、拒絕或放棄函數。 相反地,MQTT 預設會接受訊息,並將訊息從 IoT 中樞訊息佇列中移除。

重新傳遞嘗試

如果發生導致裝置無法完成、放棄或拒絕訊息的情況,IoT 中樞在固定的逾時期間之後,會將訊息排入佇列以再次傳遞。 基於這個原因,裝置應用程式中的訊息處理邏輯必須是「等冪」,如此一來,多次接收相同訊息才會產生相同的結果。

新增 IoT 中樞字串和傳輸通訊協定

呼叫 fromConnectionString,以使用這些參數建立裝置到 IoT 中樞連線:

  • connStr - 連接字串,封裝 IoT 中樞的「裝置連線」權限。 連接字串包含主機名、裝置識別碼和共用存取金鑰,格式如下:「HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>」
  • transportCtor - 傳輸通訊協定。
const Protocol = require('azure-iot-device-mqtt').Amqp;
let client = Client.fromConnectionString(deviceConnectionString, Protocol);

建立傳入訊息處理常式

每個傳入訊息都會呼叫訊息處理常式。

成功接收訊息之後,如果使用 AMQP 或 HTTP 傳輸,請呼叫 client.complete 方法來通知 IoT 中樞,訊息可以從訊息佇列中移除。

例如,此訊息處理常式會將訊息識別碼和訊息本文列印到主控台,然後呼叫 client.complete,通知 IoT 中樞處理訊息,並安全地從裝置佇列中移除該訊息。 如果使用 MQTT 傳輸,則不需要呼叫 complete,而且可以省略。 AMQP 或 HTTPS 傳輸需要呼叫 complete

function messageHandler(msg) {
  console.log('Id: ' + msg.messageId + ' Body: ' + msg.data);
  client.complete(msg, printResultFor('completed'));
}

建立連線中斷連線處理常式

當連線己中斷時會呼叫中斷連線處理常式。 中斷連線處理常式適用於實作重新連線程式碼。

此範例會攔截並顯示主控台的中斷連線錯誤訊息。

function disconnectHandler() {
  clearInterval(sendInterval);
  sendInterval = null;
  client.open().catch((err) => {
    console.error(err.message);
  });
}

新增事件接聽程式

您可以使用 .on 方法來指定這些事件接聽程式。

  • 連線處理常式
  • 錯誤處理常式
  • 中斷連線處理常式
  • 訊息處理常式

此範例包含先前定義的訊息和中斷連線處理常式。

client.on('connect', connectHandler);
client.on('error', errorHandler);
client.on('disconnect', disconnectHandler);
client.on('message', messageHandler);

開啟連線到 IoT 中樞

使用 open 方法來開啟 IoT 裝置與 IoT 中樞之間的連線。 使用 .catch(err) 來攔截錯誤並呼叫處理常式程式碼。

例如:

client.open()
.catch((err) => {
  console.error('Could not connect: ' + err.message);
});

SDK 接收訊息範例

simple_sample_device - 會連線到 IoT 中樞,並接收雲端到裝置應用程式訊息。

傳送雲端到裝置訊息

本節說明如何從適用於 Node.js 的 Azure IoT SDK 使用 azure-iothub 套件類別傳送雲端到裝置訊息。 如先前所述,解決方案後端應用程式會連線到 IoT 中樞,並將訊息傳送至使用目的地裝置編碼的 IoT 中樞。 IoT 中樞會將傳入訊息儲存至其訊息佇列,而訊息會從 IoT 中樞訊息佇列傳遞至目標裝置。

解決方案後端應用程式也可以針對傳送至 IoT 中樞的訊息,要求並接收傳遞意見反應,該訊息會透過訊息佇列傳送裝置。

載入用戶端和訊息模組

使用來自 azure-iothub 封裝的 Client 類別宣告 Client 物件。

使用來自 azure-iot-common 封裝的 Message 類別宣告 Message 物件。

'use strict';
var Client = require('azure-iothub').Client;
var Message = require('azure-iot-common').Message;

建立 Client 物件

使用下列參數,透過 fromConnectionString 建立用戶端

  • IoT 中樞連接字串
  • 傳輸類型

在此範例中,會使用 Amqp 傳輸類型建立 serviceClient 物件。

var connectionString = '{IoT Hub connection string}';
var serviceClient = Client.fromConnectionString(connectionString,`Amqp`);

開啟用戶端連線

呼叫 Client open 方法來開啟應用程式與 IoT 中樞之間的連線。

可以搭配 open 或呼叫,而不指定 open 作業完成時所呼叫的回呼函數。

在此範例中,open 方法包含選擇性 err 開啟的連線回呼函數。 如果發生開啟錯誤,則會傳回錯誤物件。 如果開啟的連接成功,則會傳回 null 回呼值。

serviceClient.open(function (err)
if (err)
  console.error('Could not connect: ' + err.message);

建立一則訊息

訊息物件包含非同步的雲端到裝置訊息。 訊息功能在 AMQP、MQTT 和 HTTP 上的運作方式相同。

訊息物件支持數個屬性,包括這些屬性。 如需完整清單,請參閱 message 屬性。

  • ack - 傳遞意見反應。 於下一節說明。
  • properties - 對應包含用來儲存自定義訊息屬性的字串索引鍵和值。
  • messageId - 用來關聯雙向通訊。

在具現化訊息物件時新增郵件內文。 在此範例中,會新增 'Cloud to device message.' 訊息。

var message = new Message('Cloud to device message.');
message.ack = 'full';
message.messageId = "My Message ID";

傳遞通知

傳送程式可向 IoT 中樞要求每個雲端到裝置訊息的傳遞 (或到期) 通知。 此動作可讓傳送程式使用通知、重試或補償邏輯。 訊息意見反應作業和屬性的完整描述會在訊息意見反應描述。

用來接收訊息意見反應的每個訊息,都必須包含傳遞通知的值,Ack 屬性。 ack 屬性可以是下列值之一:

  • none (預設值):不會產生任何意見反應訊息。

  • sent:如果訊息已完成,則接收意見反應訊息。

  • :如果訊息已過期 (或達到最大傳遞計數),則接收意見反應訊息,而不會由裝置完成。

  • full:已傳送和未傳送結果的意見反應。

在本範例中,ack 屬性設為 full,針對一個訊息要求傳遞和未傳遞的訊息傳遞意見反應。

message.ack = 'full';

訊息意見反應接收者回呼函數會使用 getFeedbackReceiver 連結到 Client

訊息意見反應接收者會收到兩個自變數:

  • Error 物件 (可以是 Null)
  • AmqpReceiver 物件 - 用戶端收到新的意見反應訊息時發出事件。

此範例函數會接收並列印傳遞意見反應訊息至主控台。

function receiveFeedback(err, receiver){
  receiver.on('message', function (msg) {
    console.log('Feedback message:')
    console.log(msg.getData().toString('utf-8'));
  });
}

此程式碼會使用 getFeedbackReceiver,將 receiveFeedback 意見反應回呼函數連結至服務 Client 物件。

serviceClient.getFeedbackReceiver(receiveFeedback);

定義訊息完成結果處理程式

訊息傳送完成回呼函數會在傳送每個訊息之後呼叫。

此範例函數會將訊息 send 作業結果列印至主控台。 在此範例中,printResultFor 函數會以參數的形式提供給下一節所述的 send 函數。

function printResultFor(op) {
  return function printResult(err, res) {
    if (err) console.log(op + ' error: ' + err.toString());
    if (res) console.log(op + ' status: ' + res.constructor.name);
  };
}

傳送訊息

使用 send 函數,透過 IoT 中樞將非同步雲端到裝置訊息傳送至裝置應用程式。

send 支援列出這些參數:

  • deviceID - 目標裝置的裝置識別碼。
  • message - 要傳送到裝置的訊息本文。
  • done - 作業完成時要呼叫的選擇性函數。 完成會使用兩個自變數來呼叫:
    • Error 物件 (可以是 Null)。
    • 傳輸特定回應物件適用於記錄或偵錯。

此程式碼會呼叫 send,透過 IoT 中樞將雲端到裝置訊息傳送至裝置應用程式。 上一節中定義的回呼函數 printResultFor 會收到傳遞通知資訊。

var targetDevice = '{device ID}';
serviceClient.send(targetDevice, message, printResultFor('send'));

本範例是當裝置收到雲端到裝置訊息時,會如何將訊息傳送至您的裝置,並處理意見反應訊息:

serviceClient.open(function (err) {
  if (err) {
    console.error('Could not connect: ' + err.message);
  } else {
    console.log('Service client connected');
    serviceClient.getFeedbackReceiver(receiveFeedback);
    var message = new Message('Cloud to device message.');
    message.ack = 'full';
    message.messageId = "My Message ID";
    console.log('Sending message: ' + message.getData());
    serviceClient.send(targetDevice, message, printResultFor('send'));
  }
});

SDK 傳送訊息範例

send_c2d_message.js - 透過 IoT 中樞將 C2D 訊息傳送至裝置。

連線重新連線原則

本文不會示範裝置對 IoT 中樞連線或 IoT 中樞連線外部應用程式的訊息重試原則。 在生產程式碼中,您應該實作連線重試原則,如管理裝置重新連線,以建立具復原性的應用程式

訊息保留時間、重試嘗試和最大傳遞計數

從 IoT 中樞傳送雲端到裝置訊息中所述,您可以使用入口網站 IoT 中樞設定選項或 Azure CLI 來檢視及設定下列訊息值的預設值。 這些設定選項可能會影響訊息傳遞和意見反應。

  • 預設 TTL (存留時間) - 在 IoT 中樞停用訊息之前,裝置可取用訊息的時間長度。
  • 意見反應保留時間 - IoT 中樞保留意見反應的時間量,以取得雲端到裝置訊息的到期或傳遞。
  • IoT 中樞嘗試將雲端到裝置的訊息傳遞到裝置的次數。