为何Python MQTT脚本shell运行正常systemd自启收不到Mosquitto数据
MQTT接收脚本配置systemd自启后无法接收消息的常见原因及解决方案
核心代码逻辑缺陷
- 订阅时机错误:当前代码首次执行订阅逻辑
sub_topics()需要等待启动后30秒,且未在MQTT连接成功的回调on_connect中执行订阅。paho-mqtt客户端若发生断连重连,非持久会话下所有已订阅主题会失效,必须在每次连接成功后重新订阅,否则会出现断连后再也收不到消息的问题。 - 未配置自动重连:代码未开启MQTT客户端自动重连逻辑,若启动初期网络波动、broker未完全就绪导致连接断开,客户端不会主动重连,也无法接收消息。
systemd配置问题
- 执行用户不匹配:手动运行脚本时通常使用树莓派默认
pi用户,systemd服务默认以root用户执行。若脚本的MQTT用户名密码、数据库配置是从当前用户的私有配置文件、环境变量读取,root用户无法读取对应配置,会导致连接认证失败,无法订阅主题。 - 工作目录未配置:若脚本使用相对路径读取配置文件,systemd默认工作目录为
/,会导致配置文件读取失败,配置项加载错误。 - 日志缓冲导致误判:Python非终端运行时默认开启全缓冲,
print输出的内容不会实时写入systemd日志,会导致你误以为脚本未收到消息,实际是日志未刷新。 - 未配置异常重启:代码中所有异常捕获后都会直接退出进程,若启动初期数据库、MQTT broker未完全就绪导致脚本启动失败,未配置
Restart策略的话脚本会停止运行,不会自动恢复。 - 启动依赖不充分:仅配置
After=mosquitto.service仅保证服务启动顺序,不保证mosquitto已完成端口监听、可以正常接受连接,启动时可能出现脚本先连接MQTT失败退出的问题。
修复方案
- 调整MQTT逻辑:
- 在
on_connect回调中添加订阅逻辑,确保每次连接成功后自动订阅所有主题,保留原30秒刷新订阅的逻辑用于同步数据库中新增的设备ID - 添加自动重连配置,创建客户端后新增
clienteMQTT.reconnect_delay_set(min_delay=1, max_delay=128) - 在
on_connect中打印返回码rc,确认连接状态,非0返回码对应连接错误可直接定位问题
- 在
- 修正systemd单元配置,参考配置如下:
[Unit] Description=MQTT Data Receiver After=mosquitto.service mariadb.service dhcpcd.service wpa_supplicant.service [Service] User=pi Group=pi WorkingDirectory=/path/to/your/script/directory Environment="PYTHONUNBUFFERED=1" ExecStart=/usr/bin/python3 /path/to/your/script/receiver.py Restart=always RestartSec=5 ExecStartPre=/bin/sleep 10 [Install] WantedBy=multi-user.target - 检查配置加载逻辑:所有敏感配置(用户名、密码、端口等)优先使用绝对路径读取配置文件,避免用户权限导致的读取失败。
内容的提问来源于stack exchange,提问作者MauroDiamantino
相关产品推荐
相关产品推荐

