使用 MQTT 通訊協定來與 IoT 中樞通訊Communicate with your IoT hub using the MQTT protocol

IoT 中樞可使用下列項目讓裝置與 IoT 中樞裝置端點進行通訊:IoT Hub enables devices to communicate with the IoT Hub device endpoints using:

  • 連接埠 8883 上的 MQTT v3.1.1MQTT v3.1.1 on port 8883
  • 連接埠 443 上使用 WebSocket 的 MQTT v3.1.1。MQTT v3.1.1 over WebSocket on port 443.

IoT 中樞不是功能完整的 MQTT 訊息代理程式,而且不支援 MQTT v3.1.1 標準中所指定的所有行為。IoT Hub is not a full-featured MQTT broker and does not support all the behaviors specified in the MQTT v3.1.1 standard. 本文說明裝置如何使用受支援的 MQTT 行為來與 IoT 中樞通訊。This article describes how devices can use supported MQTT behaviors to communicate with IoT Hub.

注意

本文中提及的某些功能 (例如雲端對裝置傳訊、裝置對應項和裝置管理) 僅適用於 IoT 中樞的標準層。Some of the features mentioned in this article, like cloud-to-device messaging, device twins, and device management, are only available in the standard tier of IoT Hub. 如需有關基本和標準 IoT 中樞層的詳細資訊,請參閱如何選擇適合的 IoT 中樞層For more information about the basic and standard IoT Hub tiers, see How to choose the right IoT Hub tier.

與 IoT 中樞通訊的所有裝置皆必須使用 TLS/SSL 加以保護。All device communication with IoT Hub must be secured using TLS/SSL. 因此,IoT 中樞不支援透過連接埠 1883 的不安全連線。Therefore, IoT Hub doesn't support non-secure connections over port 1883.

連接到 IoT 中樞Connecting to IoT Hub

裝置可以利用下列任一選項,來使用 MQTT 通訊協定連線到 IoT 中樞。A device can use the MQTT protocol to connect to an IoT hub using any of the following options.

在許多公司和教育網路環境中,會封鎖 MQTT 連接埠 (8883)。The MQTT port (8883) is blocked in many corporate and educational networking environments. 如果您無法在防火牆中開啟連接埠 8883,建議您使用透過 Web 通訊端的 MQTT。If you can't open port 8883 in your firewall, we recommend using MQTT over Web Sockets. 透過 Web 通訊端的 MQTT 會透過連接埠 443 進行通訊,這幾乎一律會在網路環境中開放。MQTT over Web Sockets communicates over port 443, which is almost always open in networking environments. 若要了解如何在使用 Azure IoT SDK 時,指定 MQTT 和透過 Web 通訊端的 MQTT 通訊協定,請參閱使用裝置 SDKTo learn how to specify the MQTT and MQTT over Web Sockets protocols when using the Azure IoT SDKs, see Using the device SDKs.

使用裝置 SDKUsing the device SDKs

支援 MQTT 通訊協定的裝置 SDK 適用於 Java、Node.js、C、C# 和 Python。Device SDKs that support the MQTT protocol are available for Java, Node.js, C, C#, and Python. 裝置 SDK 會使用標準的 IoT 中樞連接字串來連接到 IoT 中樞。The device SDKs use the standard IoT Hub connection string to establish a connection to an IoT hub. 若要使用 MQTT 通訊協定,用戶端通訊協定參數必須設定為 MQTTTo use the MQTT protocol, the client protocol parameter must be set to MQTT. 您也可以在用戶端通訊協定參數中指定透過 Web 通訊端的 MQTT。You can also specify MQTT over Web Sockets in the client protocol parameter. 根據預設,裝置 SDK 會連接到 CleanSession 旗標設為 0 的 IoT 中樞,並使用 QoS 1 來與 IoT 中樞交換訊息。By default, the device SDKs connect to an IoT Hub with the CleanSession flag set to 0 and use QoS 1 for message exchange with the IoT hub. 雖然您可以設定 QoS 0 以加快訊息交換的速度,但您應該注意到傳遞不保證也不會被認可。While it's possible to configure QoS 0 for faster message exchange, you should note that the delivery isn't guaranteed nor acknowledged. 基於這個理由, QoS 0 通常稱為「火災別忘」。For this reason, QoS 0 is often referred as "fire and forget".

當裝置連線到 IoT 中樞時,裝置 SDK 會提供方法讓裝置使用 IoT 中樞交換訊息。When a device is connected to an IoT hub, the device SDKs provide methods that enable the device to exchange messages with an IoT hub.

下表包含每一種支援語言的程式碼範例連結,並指出要用來以 MQTT 或透過 Web 通訊端的 MQTT 通訊協定連線到 IoT 中樞的參數。The following table contains links to code samples for each supported language and specifies the parameter to use to establish a connection to IoT Hub using the MQTT or the MQTT over Web Sockets protocol.

LanguageLanguage MQTT 通訊協定參數MQTT protocol parameter 透過 Web 通訊端的 MQTT 通訊協定參數MQTT over Web Sockets protocol parameter
Node.jsNode.js azure-iot-device-mqtt.Mqttazure-iot-device-mqtt.Mqtt azure-iot-device-mqtt.MqttWsazure-iot-device-mqtt.MqttWs
JavaJava IotHubClientProtocol.MQTTIotHubClientProtocol.MQTT IotHubClientProtocol.MQTT_WSIotHubClientProtocol.MQTT_WS
CC MQTT_ProtocolMQTT_Protocol MQTT_WebSocket_ProtocolMQTT_WebSocket_Protocol
C#C# TransportType.MqttTransportType.Mqtt 如果 MQTT 失敗,TransportType.Mqtt 會回復為透過 Web 通訊端的 MQTT。TransportType.Mqtt falls back to MQTT over Web Sockets if MQTT fails. 若要只指定透過 Web 通訊端的 MQTT,請使用 TransportType.Mqtt_WebSocket_OnlyTo specify MQTT over Web Sockets only, use TransportType.Mqtt_WebSocket_Only
PythonPython 預設支援 MQTTSupports MQTT by default 在呼叫中新增 websockets=True 以建立用戶端Add websockets=True in the call to create the client

下列片段示範如何在使用 Azure IoT node.js SDK 時,指定透過 Web 通訊端的 MQTT 通訊協定:The following fragment shows how to specify the MQTT over Web Sockets protocol when using the Azure IoT Node.js SDK:

var Client = require('azure-iot-device').Client;
var Protocol = require('azure-iot-device-mqtt').MqttWs;
var client = Client.fromConnectionString(deviceConnectionString, Protocol);

下列片段示範如何在使用 Azure IoT Python SDK 時,指定透過 Web 通訊端的 MQTT 通訊協定:The following fragment shows how to specify the MQTT over Web Sockets protocol when using the Azure IoT Python SDK:

from azure.iot.device.aio import IoTHubDeviceClient
device_client = IoTHubDeviceClient.create_from_connection_string(deviceConnectionString, websockets=True)

預設 keep-alive 逾時Default keep-alive timeout

為了確保用戶端/IoT 中樞連線保持運作,服務與用戶端會定期互傳 keep-alive Ping。In order to ensure a client/IoT Hub connection stays alive, both the service and the client regularly send a keep-alive ping to each other. 使用 IoT SDK 的用戶端會以下表所定義的間隔傳送 keep-alive:The client using IoT SDK sends a keep-alive at the interval defined in this table below:

LanguageLanguage 預設 keep-alive 間隔Default keep-alive interval 可設定Configurable
Node.jsNode.js 180 秒180 seconds No
JavaJava 230 秒230 seconds No
CC 240 秒240 seconds Yes
C#C# 300 秒300 seconds Yes
PythonPython 60 秒60 seconds No

MQTT 規格之後,IoT 中樞的 keep-alive ping 間隔是用戶端保持運作值的1.5 倍。Following the MQTT spec, IoT Hub's keep-alive ping interval is 1.5 times the client keep-alive value. 不過,IoT 中樞會將最大伺服器端逾時限制為 29.45 分鐘 (1767秒),因為所有 Azure 服務都會繫結至 Azure 負載平衡器 TCP 閒置逾時,這是 29.45 分鐘。However, IoT Hub limits the maximum server-side timeout to 29.45 minutes (1767 seconds) because all Azure services are bound to the Azure load balancer TCP idle timeout, which is 29.45 minutes.

例如,使用 JAVA SDK 的裝置會傳送 keep-alive ping,然後中斷網路連線。For example, a device using the Java SDK sends the keep-alive ping, then loses network connectivity. 230 秒之後,裝置會失去 keep-alive Ping,因為其離線。230 seconds later, the device misses the keep-alive ping because it's offline. 不過,IoT 中樞不會立即關閉連線 - 其會等待另一個 (230 * 1.5) - 230 = 115 秒,再中斷裝置的連線,錯誤為 404104 DeviceConnectionClosedRemotelyHowever, IoT Hub doesn't close the connection immediately - it waits another (230 * 1.5) - 230 = 115 seconds before disconnecting the device with the error 404104 DeviceConnectionClosedRemotely.

您可以設定的最大用戶端 keep-alive 值是 1767 / 1.5 = 1177 秒。The maximum client keep-alive value you can set is 1767 / 1.5 = 1177 seconds. 任何流量都會重設 keep-alive。Any traffic will reset the keep-alive. 例如,成功的 SAS 權杖重新整理會重設 keep-alive。For example, a successful SAS token refresh resets the keep-alive.

將裝置應用程式從 AMQP 移轉至 MQTTMigrating a device app from AMQP to MQTT

如果您使用 裝置 sdk,從使用 AMQP 切換至 MQTT 需要變更用戶端初始化中的通訊協定參數,如先前所述。If you are using the device SDKs, switching from using AMQP to MQTT requires changing the protocol parameter in the client initialization, as stated previously.

這麼做時,請務必檢查下列項目︰When doing so, make sure to check the following items:

  • AMQP 在許多情況下會傳回錯誤,而 MQTT 會終止連線。AMQP returns errors for many conditions, while MQTT terminates the connection. 因此,可能需要稍微變更您的例外狀況處理邏輯。As a result your exception handling logic might require some changes.

  • MQTT 在接收雲端到裝置訊息時不支援「拒絕」作業。MQTT does not support the reject operations when receiving cloud-to-device messages. 如果您的後端應用程式需要接收來自裝置應用程式的回應,請考慮使用直接方法If your back-end app needs to receive a response from the device app, consider using direct methods.

  • Python SDK 不支援 AMQP。AMQP is not supported in the Python SDK.

在 C 中使用 MQTT 的範例(不含 Azure IoT SDK)Example in C using MQTT without an Azure IoT SDK

IOT MQTT 範例存放庫中,您會發現幾個 C/c + + 示範專案,示範如何傳送遙測訊息,以及如何透過 iot 中樞接收事件,而不需要使用 Azure IOT C SDK。In the IoT MQTT Sample repository, you'll find a couple of C/C++ demo projects showing how to send telemetry messages, and receive events with an IoT hub without using the Azure IoT C SDK.

這些範例會使用 Eclipse Mosquitto 程式庫,將訊息傳送至 IoT 中樞內所執行的 MQTT 訊息代理程式。These samples use the Eclipse Mosquitto library to send messages to the MQTT Broker implemented in the IoT hub.

若要瞭解如何調整範例以使用 Azure Iot 即插即 用慣例,請參閱 教學課程-使用 MQTT 來開發 IoT 隨插即用裝置用戶端To learn how to adapt the samples to use the Azure IoT Plug and Play conventions, see Tutorial - Use MQTT to develop an IoT Plug and Play device client.

此存放庫包含:This repository contains:

若為 Windows:For Windows:

  • TelemetryMQTTWin32:包含程式碼,可將遙測訊息傳送至在 Windows 電腦上建置和執行的 Azure IoT 中樞。TelemetryMQTTWin32: contains code to send a telemetry message to an Azure IoT hub, built and run on a Windows machine.

  • SubscribeMQTTWin32:包含程式碼,可訂閱 Windows 機器上特定 IoT 中樞的事件。SubscribeMQTTWin32: contains code to subscribe to events of a given IoT hub on a Windows machine.

  • DeviceTwinMQTTWin32:包含程式碼,可查詢和訂閱 Windows 機器上 Azure IoT 中樞內裝置的裝置對應項事件。DeviceTwinMQTTWin32: contains code to query and subscribe to the device twin events of a device in the Azure IoT hub on a Windows machine.

  • PnPMQTTWin32:包含程式碼,可將具有 IoT 隨插即用裝置功能的遙測訊息傳送至 Azure IoT 中樞,並在 Windows 電腦上建立及執行。PnPMQTTWin32: contains code to send a telemetry message with IoT Plug and Play device capabilities to an Azure IoT hub, built and run on a Windows machine. 您可以深入瞭解IoT 即插即You can read more on IoT Plug and Play

若為 Linux:For Linux:

  • MQTTLinux:包含要在 Linux 上執行的程式碼和組建指令碼 (到目前為止已測試過 WSL、Ubuntu 和 Raspbian)。MQTTLinux: contains code and build script to run on Linux (WSL, Ubuntu, and Raspbian have been tested so far).

  • LinuxConsoleVS2019:包含相同的程式碼,但位於以 WSL 為目標的 VS2019 專案中 (Windows Linux 子系統系統)。LinuxConsoleVS2019: contains the same code but in a VS2019 project targeting WSL (Windows Linux sub system). 此專案可讓您從 Visual Studio,逐步偵錯在 Linux 上執行的程式碼。This project allows you to debug the code running on Linux step by step from Visual Studio.

若為 mosquitto_pub:For mosquitto_pub:

此資料夾包含兩個範例命令,與 Mosquitto.org 所提供的 mosquitto_pub 公用程式工具搭配使用。This folder contains two samples commands used with mosquitto_pub utility tool provided by Mosquitto.org.

  • Mosquitto_sendmessage:將簡單的文字簡訊傳送至充當裝置的 Azure IoT 中樞。Mosquitto_sendmessage: to send a simple text message to an Azure IoT hub acting as a device.

  • Mosquitto_subscribe:查看 Azure IoT 中樞發生的事件。Mosquitto_subscribe: to see events occurring in an Azure IoT hub.

直接使用 MQTT 通訊協定 (作為裝置)Using the MQTT protocol directly (as a device)

如果裝置無法使用裝置 SDK,它仍可使用連接埠 8883 上的 MQTT 通訊協定連線到公用裝置端點。If a device cannot use the device SDKs, it can still connect to the public device endpoints using the MQTT protocol on port 8883. CONNECT 封包中,裝置應使用下列值:In the CONNECT packet, the device should use the following values:

  • 在 [ClientId] 欄位中,使用 deviceIdFor the ClientId field, use the deviceId.

  • 在 [Username] 欄位中,使用 {iothubhostname}/{device_id}/?api-version=2018-06-30,其中 {iothubhostname} 是 IoT 中樞的完整 CName。For the Username field, use {iothubhostname}/{device_id}/?api-version=2018-06-30, where {iothubhostname} is the full CName of the IoT hub.

    例如,如果您的 IoT 中樞名稱是 contoso.azure-devices.net ,而且如果您的裝置名稱是 MyDevice01,則完整的 [Username] 欄位應包含:For example, if the name of your IoT hub is contoso.azure-devices.net and if the name of your device is MyDevice01, the full Username field should contain:

    contoso.azure-devices.net/MyDevice01/?api-version=2018-06-30

  • 在 [Password] 欄位中,使用 SAS 權杖。For the Password field, use a SAS token. SAS 權杖的格式與 HTTPS 和 AMQP 通訊協定的格式相同:The format of the SAS token is the same as for both the HTTPS and AMQP protocols:

    SharedAccessSignature sig={signature-string}&se={expiry}&sr={URL-encoded-resourceURI}

    注意

    如果您使用 X.509 憑證驗證,則不需要 SAS 權杖密碼。If you use X.509 certificate authentication, SAS token passwords are not required. 如需詳細資訊,請參閱在 您的 Azure IoT 中樞中設定 x.509 安全性 ,並遵循 TLS/SSL 設定一節中的程式碼指示。For more information, see Set up X.509 security in your Azure IoT Hub and follow code instructions in the TLS/SSL configuration section.

    如需如何產生 SAS 權杖的詳細資訊,請參閱使用 IoT 中樞安全性權杖的裝置一節。For more information about how to generate SAS tokens, see the device section of Using IoT Hub security tokens.

    測試時,您也可以使用 適用于 Visual Studio Code 的跨平臺 Azure IoT 工具 或 CLI 擴充功能命令 az IoT hub 產生 sas 權杖,以快速產生 sas 權杖,讓您可以複製並貼到您自己的程式碼中。When testing, you can also use the cross-platform Azure IoT Tools for Visual Studio Code or the CLI extension command az iot hub generate-sas-token to quickly generate a SAS token that you can copy and paste into your own code.

若為 Azure IoT ToolsFor Azure IoT Tools

  1. 展開 Visual Studio Code 左下角的 [AZURE IOT 中樞裝置] 索引標籤。Expand the AZURE IOT HUB DEVICES tab in the bottom left corner of Visual Studio Code.

  2. 以滑鼠右鍵按一下您的裝置,然後選取 [產生裝置的 SAS 權杖]。Right-click your device and select Generate SAS Token for Device.

  3. 設定 [到期時間],然後按 'Enter' 鍵。Set expiration time and press 'Enter'.

  4. SAS 權杖已建立並複製到剪貼簿。The SAS token is created and copied to clipboard.

    產生的 SAS 權杖具有下列結構:The SAS token that's generated has the following structure:

    HostName={your hub name}.azure-devices.net;DeviceId=javadevice;SharedAccessSignature=SharedAccessSignature sr={your hub name}.azure-devices.net%2Fdevices%2FMyDevice01%2Fapi-version%3D2016-11-14&sig=vSgHBMUG.....Ntg%3d&se=1456481802

    使用 MQTT 連線時,此權杖中作為 [Password] 欄位的部分是︰The part of this token to use as the Password field to connect using MQTT is:

    SharedAccessSignature sr={your hub name}.azure-devices.net%2Fdevices%2FMyDevice01%2Fapi-version%3D2016-11-14&sig=vSgHBMUG.....Ntg%3d&se=1456481802

對於 MQTT 的連接和中斷連接封包,IoT 中樞會對 作業監視 通道發出事件。For MQTT connect and disconnect packets, IoT Hub issues an event on the Operations Monitoring channel. 此事件具有其他資訊,可協助您對連線問題進行疑難排解。This event has additional information that can help you to troubleshoot connectivity issues.

裝置應用程式可以在 CONNECT 封包中指定 Will 訊息。The device app can specify a Will message in the CONNECT packet. 裝置應用程式應該使用 devices/{device_id}/messages/events/devices/{device_id}/messages/events/{property_bag} 作為 Will 主題名稱,以定義要當作遙測訊息轉送的 Will 訊息。The device app should use devices/{device_id}/messages/events/ or devices/{device_id}/messages/events/{property_bag} as the Will topic name to define Will messages to be forwarded as a telemetry message. 在此情況下,如果網路連線已關閉,但先前並未接收到來自裝置的 DISCONNECT 封包,則 IoT 中樞會將 CONNECT 封包中提供的 Will 訊息傳送到遙測通道。In this case, if the network connection is closed, but a DISCONNECT packet was not previously received from the device, then IoT Hub sends the Will message supplied in the CONNECT packet to the telemetry channel. 遙測通道可以是預設的 事件 端點,或是 IoT 中樞路由所定義的自訂端點。The telemetry channel can be either the default Events endpoint or a custom endpoint defined by IoT Hub routing. 訊息具有 iothub-MessageType 屬性,且已為它指派 Will 值。The message has the iothub-MessageType property with a value of Will assigned to it.

直接使用 MQTT 通訊協定 (作為模組)Using the MQTT protocol directly (as a module)

使用模組身分識別透過 MQTT 連線到 IoT 中樞,類似于 使用 MQTT 通訊協定直接作為裝置) 一節中 所述的裝置 (,但您必須使用下列各項:Connecting to IoT Hub over MQTT using a module identity is similar to the device (described in the section on using the MQTT protocol directly as a device) but you need to use the following:

  • 將用戶端識別碼設定為 {device_id}/{module_id}Set the client ID to {device_id}/{module_id}.

  • 如果以使用者名稱和密碼來進行驗證,請將使用者名稱設定為 <hubname>.azure-devices.net/{device_id}/{module_id}/?api-version=2018-06-30,並使用與模組身分識別相關聯的 SAS 權杖來作為密碼。If authenticating with username and password, set the username to <hubname>.azure-devices.net/{device_id}/{module_id}/?api-version=2018-06-30 and use the SAS token associated with the module identity as your password.

  • 使用 devices/{device_id}/modules/{module_id}/messages/events/ 作為用來發佈遙測的主題。Use devices/{device_id}/modules/{module_id}/messages/events/ as topic for publishing telemetry.

  • 使用 devices/{device_id}/modules/{module_id}/messages/events/ 作為 WILL 主題。Use devices/{device_id}/modules/{module_id}/messages/events/ as WILL topic.

  • GET 和 PATCH 這對主題在模組和裝置中都一樣。The twin GET and PATCH topics are identical for modules and devices.

  • 這對狀態主題在模組和裝置中都一樣。The twin status topic is identical for modules and devices.

TLS/SSL 組態TLS/SSL configuration

若要直接使用 MQTT 通訊協定,您的用戶端「必須」透過 TLS/SSL 進行連線。To use the MQTT protocol directly, your client must connect over TLS/SSL. 嘗試略過此步驟會因連線錯誤而發生失敗。Attempts to skip this step fail with connection errors.

為了建立 TLS 連線,您可能必須下載並參考「DigiCert Baltimore 根憑證」。In order to establish a TLS connection, you may need to download and reference the DigiCert Baltimore Root Certificate. 此憑證是 Azure 用來保護連線的唯一憑證。This certificate is the one that Azure uses to secure the connection. 您可以在 Azure-iot-sdk-c 存放庫中找到此憑證。You can find this certificate in the Azure-iot-sdk-c repository. 如需有關這些憑證的詳細資訊,請瀏覽 DigiCert 網站More information about these certificates can be found on Digicert's website.

以下提供一個如何使用 Eclipse Foundation 所提供的 Python 版 Paho MQTT 程式庫 來進行實作的範例。An example of how to implement this using the Python version of the Paho MQTT library by the Eclipse Foundation might look like the following.

首先,從您的命令列環境安裝 Paho 程式庫:First, install the Paho library from your command-line environment:

pip install paho-mqtt

接著,以 Python 指令碼實作用戶端。Then, implement the client in a Python script. 取代下列各項的預留位置:Replace the placeholders as follows:

  • <local path to digicert.cer> 是包含 DigiCert Baltimore 根憑證的本機檔案路徑。<local path to digicert.cer> is the path to a local file that contains the DigiCert Baltimore Root certificate. 您可以在「適用 C 的 Azure IoT SDK」中,從 certs.c 複製憑證資訊來建立此檔案。包含 -----BEGIN CERTIFICATE----------END CERTIFICATE----- 這兩行、移除每一行開頭和結尾的 " 標記,以及移除每一行結尾的 \r\n 字元。You can create this file by copying the certificate information from certs.c in the Azure IoT SDK for C. Include the lines -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----, remove the " marks at the beginning and end of every line, and remove the \r\n characters at the end of every line.

  • <device id from device registry> 是您新增至 IoT 中樞的裝置識別碼。<device id from device registry> is the ID of a device you added to your IoT hub.

  • <generated SAS token> 是所建立裝置的 SAS 權杖,如本文前面所述。<generated SAS token> is a SAS token for the device created as described previously in this article.

  • <iot hub name> 是 IoT 中樞的名稱。<iot hub name> the name of your IoT hub.

from paho.mqtt import client as mqtt
import ssl

path_to_root_cert = "<local path to digicert.cer file>"
device_id = "<device id from device registry>"
sas_token = "<generated SAS token>"
iot_hub_name = "<iot hub name>"


def on_connect(client, userdata, flags, rc):
    print("Device connected with result code: " + str(rc))


def on_disconnect(client, userdata, rc):
    print("Device disconnected with result code: " + str(rc))


def on_publish(client, userdata, mid):
    print("Device sent message")


client = mqtt.Client(client_id=device_id, protocol=mqtt.MQTTv311)

client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_publish = on_publish

client.username_pw_set(username=iot_hub_name+".azure-devices.net/" +
                       device_id + "/?api-version=2018-06-30", password=sas_token)

client.tls_set(ca_certs=path_to_root_cert, certfile=None, keyfile=None,
               cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
client.tls_insecure_set(False)

client.connect(iot_hub_name+".azure-devices.net", port=8883)

client.publish("devices/" + device_id + "/messages/events/", "{id=123}", qos=1)
client.loop_forever()

若要使用裝置憑證進行驗證,請使用下列變更來更新上述程式碼片段 (請參閱如何取得 x.509 CA 憑證,以了解如何準備憑證型驗證):To authenticate using a device certificate, update the code snippet above with the following changes (see How to get an X.509 CA certificate on how to prepare for certificate-based authentication):

# Create the client as before
# ...

# Set the username but not the password on your client
client.username_pw_set(username=iot_hub_name+".azure-devices.net/" +
                       device_id + "/?api-version=2018-06-30", password=None)

# Set the certificate and key paths on your client
cert_file = "<local path to your certificate file>"
key_file = "<local path to your device key file>"
client.tls_set(ca_certs=path_to_root_cert, certfile=cert_file, keyfile=key_file,
               cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)

# Connect as before
client.connect(iot_hub_name+".azure-devices.net", port=8883)

傳送裝置到雲端訊息Sending device-to-cloud messages

成功連線之後,裝置可以使用 devices/{device_id}/messages/events/devices/{device_id}/messages/events/{property_bag} 作為 主題名稱,將訊息傳送至 IoT 中樞。After making a successful connection, a device can send messages to IoT Hub using devices/{device_id}/messages/events/ or devices/{device_id}/messages/events/{property_bag} as a Topic Name. {property_bag} 項目可讓裝置以 URL 編碼格式傳送具有其他屬性的訊息。The {property_bag} element enables the device to send messages with additional properties in a url-encoded format. 例如:For example:

RFC 2396-encoded(<PropertyName1>)=RFC 2396-encoded(<PropertyValue1>)&RFC 2396-encoded(<PropertyName2>)=RFC 2396-encoded(<PropertyValue2>)…

注意

這個 {property_bag} 元素與 HTTPS 通訊協定中的查詢字串使用相同的編碼。This {property_bag} element uses the same encoding as query strings in the HTTPS protocol.

以下為 IoT 中樞實作特有的行為清單:The following is a list of IoT Hub implementation-specific behaviors:

  • 「IoT 中樞」不支援 QoS 2 訊息。IoT Hub does not support QoS 2 messages. 如果裝置應用程式發佈 QoS 2 的訊息,IoT 中樞會關閉網路連接。If a device app publishes a message with QoS 2, IoT Hub closes the network connection.

  • 「IoT 中樞」不會保存「保留」訊息。IoT Hub does not persist Retain messages. 如果裝置傳送的訊息的 保留 旗標設為1,則 IoT 中樞會將 mqtt-保留 應用程式屬性新增至訊息。If a device sends a message with the RETAIN flag set to 1, IoT Hub adds the mqtt-retain application property to the message. 在此情況下,「IoT 中樞」不會保存保留訊息,而是會傳遞給後端應用程式。In this case, instead of persisting the retain message, IoT Hub passes it to the backend app.

  • IoT 中樞僅支援每個裝置有一個作用中 MQTT 連接。IoT Hub only supports one active MQTT connection per device. 代表相同裝置識別碼的任何新 MQTT 連線都會使 IoT 中樞卸載現有的連線,而 400027 ConnectionForcefullyClosedOnNewConnection 將會登入 Iot 中樞記錄Any new MQTT connection on behalf of the same device ID causes IoT Hub to drop the existing connection and 400027 ConnectionForcefullyClosedOnNewConnection will be logged into IoT Hub Logs

如需詳細資訊,請參閱傳訊開發人員指南For more information, see Messaging developer's guide.

接收雲端到裝置訊息Receiving cloud-to-device messages

若要從 IoT 中樞接收訊息,裝置應該使用 devices/{device_id}/messages/devicebound/# 做為 主題篩選 來進行訂閱。To receive messages from IoT Hub, a device should subscribe using devices/{device_id}/messages/devicebound/# as a Topic Filter. 「主題篩選」中的多層級萬用字元 # 僅供用來允許裝置接收主題名稱中的額外屬性。The multi-level wildcard # in the Topic Filter is used only to allow the device to receive additional properties in the topic name. IoT 中樞不允許使用 #? 萬用字元來篩選子主題。IoT Hub does not allow the usage of the # or ? wildcards for filtering of subtopics. 由於「IoT 中樞」不是一般用途的發行/訂閱傳訊訊息代理程式,因此它只支援已記載的主題名稱和主題篩選。Since IoT Hub is not a general-purpose pub-sub messaging broker, it only supports the documented topic names and topic filters.

裝置在成功訂閱其裝置特定端點(由主題篩選器表示)之前,不會收到來自 IoT 中樞的任何訊息 devices/{device_id}/messages/devicebound/#The device does not receive any messages from IoT Hub until it has successfully subscribed to its device-specific endpoint, represented by the devices/{device_id}/messages/devicebound/# topic filter. 建立訂閱之後,裝置將會接收在訂閱之後傳送給它的雲端到裝置訊息。After a subscription has been established, the device receives cloud-to-device messages that were sent to it after the time of the subscription. 如果裝置是在 CleanSession 旗標設定為 0 的情況下連線,訂閱將會跨不同的工作階段持續保留。If the device connects with CleanSession flag set to 0, the subscription is persisted across different sessions. 在此情況下,下次裝置以 CleanSession 0 進行連線時,就會收到中斷連線時傳送給它的任何未送訊息。In this case, the next time the device connects with CleanSession 0 it receives any outstanding messages sent to it while disconnected. 如果裝置使用設定為 1CleanSession 旗標,則必須等到訂閱 IoT 中樞的裝置端點之後,才會收到來自 IoT 中樞的訊息。If the device uses CleanSession flag set to 1 though, it does not receive any messages from IoT Hub until it subscribes to its device-endpoint.

IoT 中樞會附上 主題名稱devices/{device_id}/messages/devicebound/devices/{device_id}/messages/devicebound/{property_bag} (如果有訊息屬性) 來傳遞訊息。IoT Hub delivers messages with the Topic Name devices/{device_id}/messages/devicebound/, or devices/{device_id}/messages/devicebound/{property_bag} when there are message properties. {property_bag} 包含訊息屬性的 url 編碼索引鍵/值組。{property_bag} contains url-encoded key/value pairs of message properties. 屬性包中只會包含應用程式屬性和使用者可設定的系統屬性 (例如 messageIdcorrelationId)。Only application properties and user-settable system properties (such as messageId or correlationId) are included in the property bag. 系統屬性名稱具有前置詞 $ ,但應用程式屬性則會使用沒有前置詞的原始屬性名稱。System property names have the prefix $, application properties use the original property name with no prefix. 如需屬性包格式的其他詳細資料,請參閱傳送 裝置到雲端訊息For additional details about the format of the property bag, see Sending device-to-cloud messages.

在雲端到裝置的訊息中,屬性包中的值會以下表的方式表示:In cloud-to-device messages, values in the property bag are represented as in the following table:

屬性值Property value 表示法Representation 描述Description
null key 只有索引鍵出現在屬性包中Only the key appears in the property bag
空字串empty string key= 索引鍵,後面接著等號且沒有值The key followed by an equal sign with no value
非 null、非空白的值non-null, non-empty value key=value 後面接著等號和值的索引鍵The key followed by an equal sign and the value

下列範例顯示內容包,其中包含三個應用程式屬性: prop1 ,其值為 nullthis.prop2, ( "" 的空字串 ) ;並以 "a string" 的值 prop3The following example shows a property bag that contains three application properties: prop1 with a value of null; prop2, an empty string (""); and prop3 with a value of "a string".

/?prop1&prop2=&prop3=a%20string

當裝置應用程式訂閱具有 QoS 2 的主題時,IoT 中樞會在 SUBACK 封包中授與最大 QoS 層級 1。When a device app subscribes to a topic with QoS 2, IoT Hub grants maximum QoS level 1 in the SUBACK packet. 之後,IoT 中樞會使用 QoS 1 將訊息傳遞給裝置。After that, IoT Hub delivers messages to the device using QoS 1.

擷取裝置對應項屬性Retrieving a device twin's properties

首先,裝置會訂閱 $iothub/twin/res/#,以接收作業的回應。First, a device subscribes to $iothub/twin/res/#, to receive the operation's responses. 然後,它會傳送空白訊息給主題 $iothub/twin/GET/?$rid={request id},其中已填入 要求 ID 的值。Then, it sends an empty message to topic $iothub/twin/GET/?$rid={request id}, with a populated value for request ID. 服務接著會使用和要求相同的 要求 ID,傳送內含關於 $iothub/twin/res/{status}/?$rid={request id} 主題之裝置對應項資料的回應訊息。The service then sends a response message containing the device twin data on topic $iothub/twin/res/{status}/?$rid={request id}, using the same request ID as the request.

根據 IoT 中樞訊息開發人員指南,要求識別碼可以是任何有效的訊息屬性值,而狀態會驗證為整數。Request ID can be any valid value for a message property value, as per the IoT Hub messaging developer's guide, and status is validated as an integer.

回應本文包含裝置對應項的 properties 區段,如以下回應範例所示:The response body contains the properties section of the device twin, as shown in the following response example:

{
    "desired": {
        "telemetrySendFrequency": "5m",
        "$version": 12
    },
    "reported": {
        "telemetrySendFrequency": "5m",
        "batteryLevel": 55,
        "$version": 123
    }
}

可能的狀態碼如下︰The possible status codes are:

狀態Status 描述Description
200200 SuccessSuccess
429429 要求過多 (已節流),根據 IoT 中樞節流Too many requests (throttled), as per IoT Hub throttling
5**5** 伺服器錯誤Server errors

如需詳細資訊,請參閱《 裝置 twins 開發人員指南》For more information, see the Device twins developer's guide.

更新裝置對應項的報告屬性Update device twin's reported properties

為了更新所報告的屬性,裝置會透過對指定 MQTT 主題進行發佈,將要求發給 IoT 中樞。To update reported properties, the device issues a request to IoT Hub via a publication over a designated MQTT topic. 處理該要求之後,IoT 中樞會透過對另一個主題進行發佈,來回應更新作業的成功或失敗狀態。After processing the request, IoT Hub responds the success or failure status of the update operation via a publication to another topic. 裝置可以訂閱本主題,以收到其對應項更新要求結果的通知。This topic can be subscribed by the device in order to notify it about the result of its twin update request. 為了在 MQTT 中實作此類型的要求/回應互動,我們會利用裝置一開始在其更新要求中所提供的要求識別碼標記法 ($rid)。To implement this type of request/response interaction in MQTT, we leverage the notion of request ID ($rid) provided initially by the device in its update request. 此要求識別碼也會包含在來自 IoT 中樞的回應,以允許裝置讓回應與其先前的特定要求相互關聯。This request ID is also included in the response from IoT Hub to allow the device to correlate the response to its particular earlier request.

下列順序說明在 IoT 中樞的裝置對應項中,裝置如何更新報告的屬性︰The following sequence describes how a device updates the reported properties in the device twin in IoT Hub:

  1. 裝置必須訂閱 $iothub/twin/res/# 主題,才能從 IoT 中樞接收作業的回應。A device must first subscribe to the $iothub/twin/res/# topic to receive the operation's responses from IoT Hub.

  2. 裝置會將包含裝置對應項新的訊息傳送至 $iothub/twin/PATCH/properties/reported/?$rid={request id} 主題。A device sends a message that contains the device twin update to the $iothub/twin/PATCH/properties/reported/?$rid={request id} topic. 此訊息包含 要求 ID 值。This message includes a request ID value.

  3. 服務接著會傳送回應訊息,其中包含$iothub/twin/res/{status}/?$rid={request id} 主題上報告之屬性集合的新 ETag 值。The service then sends a response message that contains the new ETag value for the reported properties collection on topic $iothub/twin/res/{status}/?$rid={request id}. 這個回應訊息使用和要求相同的 要求 IDThis response message uses the same request ID as the request.

要求訊息本文會包含 JSON 文件,其包含已報告屬性的新值。The request message body contains a JSON document, that contains new values for reported properties. JSON 文件中的每個成員會在裝置對應項的文件中更新或新增對應的成員。Each member in the JSON document updates or add the corresponding member in the device twin's document. null 從包含物件中刪除成員的成員集。A member set to null deletes the member from the containing object. 例如:For example:

{
    "telemetrySendFrequency": "35m",
    "batteryLevel": 60
}

可能的狀態碼如下︰The possible status codes are:

狀態Status 描述Description
204204 成功 (不會傳回任何內容)Success (no content is returned)
400400 不正確的要求。Bad Request. JSON 格式錯誤Malformed JSON
429429 要求過多 (已節流),根據 IoT 中樞節流Too many requests (throttled), as per IoT Hub throttling
5**5** 伺服器錯誤Server errors

下列 Python 程式碼片段示範透過 MQTT (使用 Paho MQTT 用戶端) 來進行的對應項報告屬性更新程序:The python code snippet below, demonstrates the twin reported properties update process over MQTT (using Paho MQTT client):

from paho.mqtt import client as mqtt

# authenticate the client with IoT Hub (not shown here)

client.subscribe("$iothub/twin/res/#")
rid = "1"
twin_reported_property_patch = "{\"firmware_version\": \"v1.1\"}"
client.publish("$iothub/twin/PATCH/properties/reported/?$rid=" +
               rid, twin_reported_property_patch, qos=0)

在上述對應項報告屬性更新作業成功時,來自 IoT 中樞的發佈訊息會有下列主題:$iothub/twin/res/204/?$rid=1&$version=6,其中 204 是表示成功的狀態碼、$rid=1 對應至裝置在程式碼中提供的要求識別碼,$version 則對應至更新之後裝置對應項報告屬性區段的版本。Upon success of twin reported properties update operation above, the publication message from IoT Hub will have the following topic: $iothub/twin/res/204/?$rid=1&$version=6, where 204 is the status code indicating success, $rid=1 corresponds to the request ID provided by the device in the code, and $version corresponds to the version of reported properties section of device twins after the update.

如需詳細資訊,請參閱《 裝置 twins 開發人員指南》For more information, see the Device twins developer's guide.

接收所需屬性更新通知Receiving desired properties update notifications

當連接裝置時,IoT 中樞傳送通知給主題 $iothub/twin/PATCH/properties/desired/?$version={new version},其中包含解決方案後端所執行的更新內容。When a device is connected, IoT Hub sends notifications to the topic $iothub/twin/PATCH/properties/desired/?$version={new version}, which contain the content of the update performed by the solution back end. 例如:For example:

{
    "telemetrySendFrequency": "5m",
    "route": null,
    "$version": 8
}

和屬性更新一樣,null 值表示將要刪除的 JSON 物件成員。As for property updates, null values mean that the JSON object member is being deleted. 另請注意,$version 指出對應項所需屬性區段的新版本。Also, note that $version indicates the new version of the desired properties section of the twin.

重要

IoT 中樞只會在連接裝置時產生變更通知。IoT Hub generates change notifications only when devices are connected. 請務必實作裝置重新連線流程,以便讓 IoT 中樞與裝置應用程式兩者所需的屬性保持同步。Make sure to implement the device reconnection flow to keep the desired properties synchronized between IoT Hub and the device app.

如需詳細資訊,請參閱《 裝置 twins 開發人員指南》For more information, see the Device twins developer's guide.

回應直接方法Respond to a direct method

首先,裝置必須訂閱 $iothub/methods/POST/#First, a device has to subscribe to $iothub/methods/POST/#. IoT 中樞會將方法要求傳送至主題 $iothub/methods/POST/{method name}/?$rid={request id},其中含有有效的 JSON 或空白本文。IoT Hub sends method requests to the topic $iothub/methods/POST/{method name}/?$rid={request id}, with either a valid JSON or an empty body.

若要回應,裝置會將具有有效 JSON 的或內文空白的訊息傳送至 $iothub/methods/res/{status}/?$rid={request id} 主題。To respond, the device sends a message with a valid JSON or empty body to the topic $iothub/methods/res/{status}/?$rid={request id}. 在此訊息中,要求識別碼 必須與要求訊息中的相符,且 狀態 必須是整數。In this message, the request ID must match the one in the request message, and status must be an integer.

如需詳細資訊,請參閱 直接方法開發人員指南For more information, see the Direct method developer's guide.

其他考量Additional considerations

作為最後的考量,如果您需要自訂雲端的 MQTT 通訊協定行為,您應檢視 Azure IoT 通訊協定閘道As a final consideration, if you need to customize the MQTT protocol behavior on the cloud side, you should review the Azure IoT protocol gateway. 此軟體可讓您部署高效能的自訂通訊協定閘道,而且可直接與 IoT 中樞連接。This software enables you to deploy a high-performance custom protocol gateway that interfaces directly with IoT Hub. Azure IoT 通訊協定閘道器可讓您自訂裝置通訊協定,以順應要重建的 MQTT 部署或其他自訂通訊協定。The Azure IoT protocol gateway enables you to customize the device protocol to accommodate brownfield MQTT deployments or other custom protocols. 不過,這種方法會要求您執行及操作自訂通訊協定閘道。This approach does require, however, that you run and operate a custom protocol gateway.

後續步驟Next steps

若要深入了解 MQTT 通訊協定,請參閱 MQTT 文件To learn more about the MQTT protocol, see the MQTT documentation.

若要深入了解如何規劃 IoT 中樞部署,請參閱:To learn more about planning your IoT Hub deployment, see:

若要進一步探索 IoT 中樞的功能,請參閱︰To further explore the capabilities of IoT Hub, see: