You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python实现Azure IoT Hub设备消息收发?解决单设备无法同时连接问题

问题描述

我正尝试用Python编写代码向Azure IoT Hub发送温度数据,同时用另一段Python代码接收该数据,两段代码都通过命令提示符运行。但目前同一设备只能建立一个连接,无法同时实现收发,请问是否可以按下图的架构实现该功能?

设备与IoT Hub通信架构图

发布代码

from azure.iot.device import IoTHubDeviceClient, Message
import random
import time

# 设备连接字符串
CONNECTION_STRING = "HostName=iothub-jein02-np-eas-ua-eztr01.azure-devices.net;DeviceId=NodeMCU;SharedAccessKey=pOkHxKaDejoJUSgUU3ZdmKqG/KV3XOcbgILSX8ZDiMk="

# 创建设备客户端实例
device_client = IoTHubDeviceClient.create_from_connection_string(CONNECTION_STRING)

try:
    # 连接到IoT Hub
    device_client.connect()
    time.sleep(5) 

    # 生成随机温度数据
    temperature = random.randint(0, 100)
    message_payload = { "temperature": temperature } 

    # 创建并发送消息
    message = Message(str(message_payload))
    device_client.send_message(message)
    
    print("消息已成功发送到Azure IoT Hub。")
except Exception as ex:
    print(f"发生意外错误: {ex}")
finally:
    # 断开连接
    device_client.disconnect()

订阅代码

from azure.iot.device import IoTHubDeviceClient, Message

# 设备连接字符串
CONNECTION_STRING = "<your-device-connection-string>"

# 消息接收回调函数
def message_received_callback(message):
    print("从Azure IoT Hub收到消息:")
    print(f"    数据: {message.data}")
    print(f"    属性: {message.custom_properties}")

# 创建设备客户端实例
device_client = IoTHubDeviceClient.create_from_connection_string(CONNECTION_STRING)

# 设置消息接收回调
device_client.on_message_received = message_received_callback

# 连接到IoT Hub
device_client.connect()

# 保持程序运行
input("按回车键退出...\n")

# 断开连接
device_client.disconnect()
解决方案

核心限制说明

Azure IoT Hub对同一设备ID仅允许一个活跃连接,如果用同一设备ID启动两个独立连接,后建立的连接会强制断开前一个,因此无法通过两个独立设备客户端进程实现同时收发。

可行实现方案

方案1:单进程单客户端同时处理收发

将发送和接收逻辑整合到同一个Python进程中,使用同一个IoTHubDeviceClient实例,这样一个连接即可支持双向通信。示例代码如下:

from azure.iot.device import IoTHubDeviceClient, Message
import random
import time
import threading

# 设备连接字符串
CONNECTION_STRING = "HostName=iothub-jein02-np-eas-ua-eztr01.azure-devices.net;DeviceId=NodeMCU;SharedAccessKey=pOkHxKaDejoJUSgUU3ZdmKqG/KV3XOcbgILSX8ZDiMk="

# 消息接收回调
def message_received_callback(message):
    print("\n从IoT Hub收到消息:")
    print(f"    数据: {message.data}")
    print(f"    属性: {message.custom_properties}")

# 发送温度数据的线程函数
def send_temperature_data(client):
    while True:
        try:
            temperature = random.randint(0, 100)
            payload = {"temperature": temperature}
            message = Message(str(payload))
            client.send_message(message)
            print(f"\n已发送温度数据: {temperature}°C")
            time.sleep(5)  # 每5秒发送一次
        except Exception as ex:
            print(f"发送消息出错: {ex}")
            break

def main():
    # 创建设备客户端
    device_client = IoTHubDeviceClient.create_from_connection_string(CONNECTION_STRING)
    # 设置接收回调
    device_client.on_message_received = message_received_callback
    
    try:
        # 连接到IoT Hub
        device_client.connect()
        print("已连接到Azure IoT Hub")
        
        # 启动发送数据的线程
        send_thread = threading.Thread(target=send_temperature_data, args=(device_client,))
        send_thread.daemon = True
        send_thread.start()
        
        # 保持主线程运行,等待接收消息
        input("按回车键退出...\n")
    except Exception as ex:
        print(f"连接或运行出错: {ex}")
    finally:
        # 断开连接
        device_client.disconnect()
        print("已断开与IoT Hub的连接")

if __name__ == "__main__":
    main()

方案2:分进程,接收端使用服务端SDK

如果必须分开两个独立进程,接收端不要使用设备端SDK,改用Azure IoT Hub的服务端SDK(azure-iot-hub),通过Event Hub兼容端点接收设备上传的消息。示例接收代码(服务端):

from azure.eventhub import EventHubConsumerClient
import json

# IoT Hub Event Hub兼容连接字符串(从IoT Hub共享访问策略中获取)
EVENT_HUB_CONNECTION_STR = "<your-event-hub-compatible-connection-string>"
EVENT_HUB_NAME = "<your-event-hub-name>"

# 消息处理回调
def on_event(partition_context, event):
    print(f"\n从分区 {partition_context.partition_id} 收到消息:")
    # 解析设备上传的消息
    message_data = json.loads(event.body_as_str())
    print(f"    温度数据: {message_data.get('temperature')}°C")
    # 更新检查点
    partition_context.update_checkpoint(event)

def main():
    client = EventHubConsumerClient.from_connection_string(
        EVENT_HUB_CONNECTION_STR,
        consumer_group="$Default",
        eventhub_name=EVENT_HUB_NAME
    )
    try:
        with client:
            client.receive(
                on_event=on_event,
                starting_position="-1"  # 从最早未读取的消息开始
            )
    except KeyboardInterrupt:
        print("接收程序已停止")

if __name__ == "__main__":
    main()

总结

如果要按你提供的架构图实现,推荐使用方案1,通过单客户端单进程结合多线程的方式,在一个连接内同时处理消息的发送和接收,既符合IoT Hub的连接限制,也能满足你的需求。

内容的提问来源于stack exchange,提问作者sai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:18:17