树莓派systemd单元Python脚本time.sleep超60秒失效求助
问题描述
在树莓派上运行一个由systemd管理的Python脚本,实现通电自动发送温湿度数据。当time.sleep(60)时一切正常,但设置为120秒及更长时间后,仅脚本启动时发送一次数据,后续不再发送任何数据。
代码示例
import paho.mqtt.client as mqtt import Adafruit_DHT import time import ssl # 配置DHT22传感器 dht_sensor = Adafruit_DHT.DHT22 dht_pin = 4 # 传感器连接的GPIO引脚号 username = 'master:mqttuser' secret = 'ifYrtDSc' host = '192.168.0.65' port = 8883 clientID = 'raspi_ka' assetID = '3nRdfjgE0Ga' def on_connect(client, userdata, flags, rc): print("连接成功,返回码: " + str(rc)) # 在on_connect中订阅,断开重连后会自动重新订阅 mqtt_client.subscribe("$SYS/#") def on_publish(client, userdata, msg): print(msg.topic + " " + str(msg.payload)) mqtt_client = mqtt.Client(clientID) mqtt_client.username_pw_set(username, password=secret) context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) mqtt_client.tls_set_context(context) mqtt_client.on_connect = on_connect mqtt_client.on_publish = on_publish mqtt_client.connect(host, port=port) # 循环读取并发送温湿度数据 while True: humidity, temperature = Adafruit_DHT.read_retry(dht_sensor, dht_pin) if humidity is not None and temperature is not None: mqtt_client.publish(f"master/{clientID}/writeattributevalue/temperature/{assetID}", temperature) mqtt_client.publish(f"master/{clientID}/writeattributevalue/humidity/{assetID}", humidity) else: print("读取传感器数据失败") time.sleep(120) # 断开MQTT客户端连接 mqtt_client.disconnect()
解决方法
问题根源是MQTT客户端未处理网络心跳。paho-mqtt客户端需要定期和Broker交换心跳包维持连接,当time.sleep时间过长时,客户端被阻塞,无法响应Broker的ping请求,导致Broker判定连接断开,后续publish操作自然失效。
方案1:启动后台loop线程处理网络通信
这是最可靠的解决方式,让客户端在后台持续处理心跳、重连等网络操作,不受time.sleep阻塞影响。修改代码如下:
import paho.mqtt.client as mqtt import Adafruit_DHT import time import ssl # 配置DHT22传感器 dht_sensor = Adafruit_DHT.DHT22 dht_pin = 4 # 传感器连接的GPIO引脚号 username = 'master:mqttuser' secret = 'ifYrtDSc' host = '192.168.0.65' port = 8883 clientID = 'raspi_ka' assetID = '3nRdfjgE0Ga' def on_connect(client, userdata, flags, rc): print("连接成功,返回码: " + str(rc)) mqtt_client.subscribe("$SYS/#") def on_publish(client, userdata, msg): print(msg.topic + " " + str(msg.payload)) def on_disconnect(client, userdata, rc): if rc != 0: print(f"意外断开连接,返回码: {rc}") # 自动尝试重连 client.reconnect() mqtt_client = mqtt.Client(clientID) mqtt_client.username_pw_set(username, password=secret) context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) mqtt_client.tls_set_context(context) mqtt_client.on_connect = on_connect mqtt_client.on_publish = on_publish mqtt_client.on_disconnect = on_disconnect # 添加断开回调 mqtt_client.connect(host, port=port) # 启动后台线程处理MQTT网络循环 mqtt_client.loop_start() while True: humidity, temperature = Adafruit_DHT.read_retry(dht_sensor, dht_pin) if humidity is not None and temperature is not None: mqtt_client.publish(f"master/{clientID}/writeattributevalue/temperature/{assetID}", temperature) mqtt_client.publish(f"master/{clientID}/writeattributevalue/humidity/{assetID}", humidity) else: print("读取传感器数据失败") time.sleep(120) # 程序结束时停止loop线程并断开连接(实际循环不会走到这里) mqtt_client.loop_stop() mqtt_client.disconnect()
loop_start()启动后台线程,持续处理MQTT协议的网络交互,包括心跳包、重连逻辑。- 添加
on_disconnect回调,能监控连接状态,连接异常时自动尝试重连。
方案2:调整心跳超时时间(备选)
如果不想修改线程逻辑,可以延长Broker的连接超时时间,让它等待更久才判定连接断开:
在connect方法中添加keepalive参数:
# 设置keepalive为300秒(Broker会在1.5倍该时间后断开,即450秒) mqtt_client.connect(host, port=port, keepalive=300)
这种方法只能缓解问题,无法彻底解决网络波动导致的连接断开,不如方案1可靠。
内容的提问来源于stack exchange,提问作者deputy-chief-hardy
相关产品推荐
相关产品推荐

