基于MQTT的温湿度采集服务
1. 项目概述
thdetect是一个基于RS485的温湿度采集服务程序,通过Modbus-RTU协议读取传感器数据,并将数据通过MQTT协议发布到消息代理服务器。该服务可以作为后台守护进程运行,为上层应用提供实时的温湿度数据。
2. 开发环境
- 处理器:AM3354
- 显示屏:支持触摸功能的LCD屏幕
- 操作系统:Linux 3.2
- LVGL版本:v8.3
- 构建工具:CMake 3.16+
- 交叉编译工具链:arm-arago-linux-gnueabi-gcc 4.5.3
- 源码路径:https://gitcode.com/am335xt3/lvgl/tree/main/servers
PS:gitcode要求打开源码页面,需要先登录账号。
3. 系统架构
系统主要由以下几个部分组成:
- 串口通信模块:负责与RS485温湿度传感器进行Modbus-RTU通信
- 数据采集模块:实现温湿度数据的读取和解析
- MQTT客户端模块:负责将采集到的数据发布到MQTT代理服务器
- 守护进程模块:支持以守护进程方式运行
4. 功能模块设计
4.1 串口通信模块
-
串口配置
- 波特率:4800bps(默认)
- 数据位:8位
- 停止位:1位
- 校验位:无
- 流控制:无
-
关键函数
int serial_config(int fd) // 配置串口参数 int modbus_init(const char *port_name) // 初始化串口设备 void modbus_cleanup(void) // 清理串口资源
4.2 数据采集模块
-
Modbus通信协议
- 从机地址:0x01
- 功能码:0x03(读取保持寄存器)
- 起始寄存器:0x0000
- 寄存器数量:2个(温度和湿度)
-
数据解析
- 湿度值:直接转换(原始值/10)
- 温度值:补码转换(原始值/10)
-
关键函数
int modbus_read_th(float *temperature, float *humidity) // 读取温湿度数据 static uint16_t calc_crc16(const uint8_t *data, int len) // CRC16校验
4.3 MQTT客户端模块
4.3.1 MQTT发布客户端模块
MQTT客户端模块基于mosquitto实现,mosquitto移植请参考:
mosquitto移植到AM335x+Linux系统
-
MQTT配置
- 默认代理服务器:localhost
- 默认主题:sensors/th
- 消息格式:JSON
{"temperature":18.7,"humidity":58.1}
-
关键函数实现
// MQTT客户端初始化 int mqtt_client_init(const char *broker_address, const char *topic) { // 初始化mosquitto库 mosquitto_lib_init(); // 创建MQTT客户端实例 g_mosq = mosquitto_new(NULL, true, NULL); if (g_mosq == NULL) { return -1; } // 设置回调函数 mosquitto_connect_callback_set(g_mosq, on_connect); mosquitto_disconnect_callback_set(g_mosq, on_disconnect); // 连接到MQTT服务器 if (mosquitto_connect(g_mosq, broker_address, 1883, 60) != MOSQ_ERR_SUCCESS) { return -1; } // 启动网络线程 if (mosquitto_loop_start(g_mosq) != MOSQ_ERR_SUCCESS) { return -1; } return 0; } // 发布温湿度数据 int mqtt_client_publish(float temperature, float humidity) { // 构建JSON格式的消息 char message[128]; snprintf(message, sizeof(message), "{\"temperature\":%.1f,\"humidity\":%.1f}", temperature, humidity); // 发布消息 int rc = mosquitto_publish(g_mosq, NULL, g_topic, strlen(message), message, 0, false); return (rc == MOSQ_ERR_SUCCESS) ? 0 : -1; } // 清理MQTT客户端资源 void mqtt_client_cleanup(void) { if (g_mosq != NULL) { mosquitto_loop_stop(g_mosq, true); mosquitto_disconnect(g_mosq); mosquitto_destroy(g_mosq); g_mosq = NULL; } mosquitto_lib_cleanup(); }
4.3.2 MQTT订阅客户端
这里直接使用mosquitto提供的订阅工具查看:
#./mosquitto_sub -t sensors/th -h 192.168.0.232 -p 18 -v
sensors/th {"temperature":18.7,"humidity":58.1}
4.3.3 MQTT服务端
测试之前需要先启动MQTT服务端:
#./mosquitto -c /etc/mosquitto/mosquitto.conf
4.4 守护进程模块
-
支持通过命令行参数-d启动为守护进程
-
实现标准的守护进程初始化流程
- 创建子进程
- 设置新会话
- 修改工作目录
- 关闭标准输入输出
-
关键函数实现
int daemon_init(void) { pid_t pid; // 创建子进程 pid = fork(); if (pid < 0) { perror("fork"); return -1; } // 父进程退出 if (pid > 0) { exit(0); } // 创建新会话 if (setsid() < 0) { perror("setsid"); return -1; } // 改变工作目录 if (chdir("/") < 0) { perror("chdir"); return -1; } // 重设文件创建掩码 umask(0); // 关闭标准输入输出和错误输出 close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); // 重定向标准输入输出和错误输出到/dev/null open("/dev/null", O_RDWR); dup(0); dup(0); return 0; }
5. 命令行参数
Usage: thdetect [options]
Options:
-d, --daemon 运行为守护进程
-h, --help 显示帮助信息
-p, --port PORT 串口设备(默认:/dev/ttyS1)
-b, --broker HOST MQTT代理服务器地址(默认:localhost)
-t, --topic TOPIC MQTT主题(默认:sensors/th)
6. 数据流程
- 初始化串口设备和MQTT客户端
- 定期通过Modbus-RTU协议读取传感器数据
- 解析温湿度数据
- 将数据打包为JSON格式
- 通过MQTT发布数据到代理服务器
7. 错误处理
-
串口通信错误处理
- 设备打开失败
- 参数配置失败
- 数据读写超时
- 响应数据校验失败
-
MQTT错误处理
- 连接失败重试
- 发布消息失败处理
- 断线重连机制
8. 注意事项
- 确保串口设备权限正确
- 波特率需与传感器配置一致
- MQTT代理服务器需要提前配置和启动
- 建议使用守护进程方式运行以提供稳定服务