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

求助:如何通过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("程序已退出")

关键改动说明

  1. 全局标志位scanning_active:用来标记是否需要执行延时摄影,避免在on_message里直接阻塞线程。
  2. mqttc.loop_start()替代loop_forever():开启后台线程处理MQTT消息,主线程可以独立运行延时摄影的控制逻辑,两者互不阻塞。
  3. 主线程循环:持续检查scanning_active状态,仅当标志为True时调用timelapse(),空闲时短暂休眠减少资源消耗。
  4. 优雅退出处理:捕获KeyboardInterrupt信号,确保退出时停止MQTT循环并关闭相机。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:10:55