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

树莓派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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 03:55:02