求助:如何通过MQTT消息中断树莓派延时摄影循环?
问题根源
你的代码核心问题是MQTT客户端的消息处理线程被阻塞:当on_message回调收到StartScanning消息后,直接进入while True死循环持续调用timelapse()。而loop_forever()是单线程运行的,这个阻塞会导致客户端无法再处理新的MQTT消息(包括Quit指令),自然无法中断循环。
解决方案
改用全局标志位控制延时摄影的启停,让MQTT消息循环始终保持运行状态。具体修改如下:
修正后的代码
import time import paho.mqtt.client as mqtt from time import sleep from datetime import datetime from picamera import PiCamera import pathlib import socket # 全局控制标志:标记是否正在执行延时摄影 scanning_active = False camera = PiCamera() Broker = "192.168.1.100" Port = 1883 # topics pub_topic = "DIC/scanning" sub_topic = "DIC/keyboard" # on connect def on_connect(mqttc, obj, flags, reason_code): print(f"rc: {reason_code}") mqttc.subscribe(sub_topic) # on message def on_message(mqttc, obj, msg): global scanning_active payload = msg.payload.decode() print(f"{msg.topic} {msg.qos} {payload}") if payload == "StartScanning": # 仅设置标志位,不在这里启动循环 scanning_active = True print("延时摄影已启动") elif payload == "Quit": scanning_active = False print("延时摄影已停止") # 延时摄影函数 def timelapse(): hostName = socket.gethostname() # 创建存储目录 save_path = f'/home/pi/Desktop/DIC_{hostName}' pathlib.Path(save_path).mkdir(parents=True, exist_ok=True) # 生成文件名 fileName = datetime.now().strftime("%Y%m%d_%H-%M-%S-%f") + ".jpg" camera.resolution = (2592, 1944) camera.capture(f"{save_path}/{fileName}") sleep(1) # on subscribe def on_subscribe(mqttc, obj, mid, reason_code_list): print(f"Subscribed: {mid} {reason_code_list}") # on publish def on_publish(mqttc, obj, mid): print(f"消息已发送,message id: {mid}") # 初始化MQTT客户端 mqttc = mqtt.Client() mqttc.on_subscribe = on_subscribe mqttc.on_connect = on_connect mqttc.on_message = on_message mqttc.on_publish = on_publish mqttc.connect(Broker, Port, 60) # 启动后台MQTT消息循环,不阻塞主线程 mqttc.loop_start() # 主线程:检查标志位,控制延时摄影循环 try: while True: if scanning_active: timelapse() else: # 空闲时短暂休眠,降低CPU占用 sleep(0.1) except KeyboardInterrupt: # 捕获Ctrl+C,优雅退出 scanning_active = False mqttc.loop_stop() camera.close() print("程序已退出")
关键改动说明
- 全局标志位
scanning_active:用来标记是否需要执行延时摄影,避免在on_message里直接阻塞线程。 mqttc.loop_start()替代loop_forever():开启后台线程处理MQTT消息,主线程可以独立运行延时摄影的控制逻辑,两者互不阻塞。- 主线程循环:持续检查
scanning_active状态,仅当标志为True时调用timelapse(),空闲时短暂休眠减少资源消耗。 - 优雅退出处理:捕获
KeyboardInterrupt信号,确保退出时停止MQTT循环并关闭相机。
内容的提问来源于stack exchange,提问作者ArtB
相关产品推荐
相关产品推荐

