news 2026/9/13 5:55:42

Tasmota 空气质量监测实战:Adafruit_PM25AQI 库解析与 PMSA003I 传感器接入指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Tasmota 空气质量监测实战:Adafruit_PM25AQI 库解析与 PMSA003I 传感器接入指南

Tasmota 空气质量监测实战:Adafruit_PM25AQI 库解析与 PMSA003I 传感器接入指南

【免费下载链接】TasmotaAlternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at项目地址: https://gitcode.com/GitHub_Trending/ta/Tasmota

导读

本文以 Tasmota 仓库内置的 Adafruit_PM25AQI-1.0.6 驱动库为核心,系统讲解 Plantower PMSA003I 系列 PM2.5 空气质量传感器的数据协议、驱动库 API 用法,以及它在 Tasmota 固件中的完整接入路径——从 I2C 设备扫描、编译开关、数据读取、校验和验证,到 JSON/MQTT/WebUI 上报的端到端流程。读完本文,你将能够独立完成 PMSA003I 传感器的硬件接线、Arduino 裸机驱动编写,以及在 Tasmota 中启用 xsns_104_pmsa003i.ino 驱动实现本地化空气质量监测。

一、传感器与驱动库概览

1.1 库是什么

Adafruit PM25AQI 是 Adafruit 为 PM2.5 空气质量传感器(PMSA003I 等 Plantower 系列)编写的 Arduino 驱动库,采用 BSD 许可。本仓库以1.0.6版本内置在lib/lib_i2c/目录下,用于支撑 Tasmota 的 PMSA003I 传感器驱动。

根据 library.properties 的声明:

  • 名称:Adafruit PM25 AQI Sensor
  • 类别:Sensors
  • 架构*(全平台兼容)
  • 唯一依赖:Adafruit BusIO

该库同时支持I2CUART两种物理接口,其适用前提是传感器固件版本必须支持对应协议:PMSA003I 同时支持 I2C 与 UART,而多数 PMSA003 系列老型号仅支持 UART 输出。

1.2 从源码结构看库的组成

库目录结构非常精简,仅包含 4 个源码/配置文件与 1 个示例工程:

lib/lib_i2c/Adafruit_PM25AQI-1.0.6/ ├── Adafruit_PM25AQI.h # 数据结构与类声明 ├── Adafruit_PM25AQI.cpp # I2C/UART 读取与校验实现 ├── library.properties # Arduino 库元信息 ├── license.txt # BSD 许可 └── examples/PM25_test/PM25_test.ino # 官方测试例程

二、核心数据结构:PM25_AQI_Data

传感器的每次上报数据被封装为PM25_AQI_Data结构体(定义见 Adafruit_PM25AQI.h)。理解这个结构是解读后续所有代码的前提:

字段类型含义
framelenuint16_t数据帧长度(字节数)
pm10_standarduint16_t标准浓度 PM1.0(μg/m³)
pm25_standarduint16_t标准浓度 PM2.5(μg/m³)
pm100_standarduint16_t标准浓度 PM10.0(μg/m³)
pm10_envuint16_t环境浓度 PM1.0(μg/m³)
pm25_envuint16_t环境浓度 PM2.5(μg/m³)
pm100_envuint16_t环境浓度 PM10.0(μg/m³)
particles_03umuint16_t≥0.3μm 颗粒数(每 0.1L 空气)
particles_05umuint16_t≥0.5μm 颗粒数(每 0.1L 空气)
particles_10umuint16_t≥1.0μm 颗粒数(每 0.1L 空气)
particles_25umuint16_t≥2.5μm 颗粒数(每 0.1L 空气)
particles_50umuint16_t≥5.0μm 颗粒数(每 0.1L 空气)
particles_100umuint16_t≥10.0μm 颗粒数(每 0.1L 空气)
unuseduint16_t保留字段
checksumuint16_t数据帧校验和

需要区分两类浓度值:

  • 标准浓度(standard):经 EPA 标准换算系数修正后的质量浓度;
  • 环境浓度(environmental):传感器基于原始计数直接计算的浓度。

两者单位均为 μg/m³;六档颗粒计数单位是"每 0.1L 空气中的颗粒数",不是浓度。Tasmota 的 WebUI 与 JSON 上报默认采用环境浓度,正是从该结构体中读取。

三、驱动库 API 详解

Adafruit_PM25AQI类(见 Adafruit_PM25AQI.h)对外仅暴露 3 个方法,使用门槛极低:

class Adafruit_PM25AQI { public: Adafruit_PM25AQI(); bool begin_I2C(TwoWire *theWire = &Wire); // I2C 模式初始化 bool begin_UART(Stream *theStream); // UART 模式初始化 bool read(PM25_AQI_Data *data); // 读取一帧数据 };

3.1 begin_I2C:I2C 模式

bool Adafruit_PM25AQI::begin_I2C(TwoWire *theWire) { if (!i2c_dev) { i2c_dev = new Adafruit_I2CDevice(PMSA003I_I2CADDR_DEFAULT, theWire); } if (!i2c_dev->begin()) { return false; } return true; }

实现要点(对应 Adafruit_PM25AQI.cpp):

  • 设备地址硬编码为PMSA003I_I2CADDR_DEFAULT 0x12(PMSA003I 仅有唯一 I2C 地址);
  • 底层通过依赖库 Adafruit BusIO 的Adafruit_I2CDevice完成总线探测;
  • 参数theWire默认指向全局Wire实例,多总线场景可传入自定义TwoWire对象;
  • 返回false表示总线上未发现设备。

3.2 begin_UART:UART 模式

bool Adafruit_PM25AQI::begin_UART(Stream *theSerial) { serial_dev = theSerial; return true; }

该方法只做指针绑定,波特率需调用方自行配置(PMSA003 系列 UART 默认 9600 baud)。可传入HardwareSerial(如Serial1)或SoftwareSerial,这一点在官方例程中有明确演示。

3.3 read:读取与校验

read()是库的核心,Adafruit_PM25AQI.cpp 中的完整流程为:

  1. I2C 路径:一次性读取 32 字节;
  2. UART 路径:先循环跳过非0x42字节以同步到帧头(最多跳 32 字节),再读取 32 字节数据;
  3. 帧头检查buffer[0]必须等于0x42,否则返回false
  4. 校验和计算:对前 30 字节求和(sum += buffer[i]),与帧尾checksum比对,不一致返回false
  5. 大小端处理:Plantower 协议为大端,代码将 30 个原始字节重组为 15 个uint16_tbuffer_u16[i] = buffer[2+i*2+1]; buffer_u16[i] += (buffer[2+i*2] << 8);),从而屏蔽平台字节序差异;
  6. 填充结构体memcpy((void *)data, (void *)buffer_u16, 30),把前 30 字节数据映射到PM25_AQI_Data(不含framelen的 2 字节偏移由字节重组方式天然跳过)。

值得注意的是:read()返回true仅代表这一帧数据通过了帧头与校验和验证,调用方仍应关注数据的时间有效性(见下文 Tasmota 的预热策略)。

四、官方示例:PM25_test.ino 逐段解析

仓库自带的 PM25_test.ino 是完整可运行的测试工程,覆盖三种接线模式:

4.1 setup:三种连接方式切换

Adafruit_PM25AQI aqi = Adafruit_PM25AQI(); void setup() { Serial.begin(115200); while (!Serial) delay(10); delay(1000); // 等待传感器上电自检完成 // 三选一: if (! aqi.begin_I2C()) { // ① I2C 模式 //if (! aqi.begin_UART(&Serial1)) { // ② 硬件串口模式 //if (! aqi.begin_UART(&pmSerial)) { // ③ 软件串口模式 Serial.println("Could not find PM 2.5 sensor!"); while (1) delay(10); } }

关键操作细节:

  • UART 模式必须先行初始化串口并设置波特率Serial1.begin(9600)或软件串口pmSerial.begin(9600),否则读取必然失败;
  • 软件串口接线建议(示例注释):传感器 TX 接 UNO 的 pin #2,pin #3 悬空,声明为SoftwareSerial pmSerial(2, 3)
  • begin_I2C()失败时程序进入死循环,便于串口监视器直接观察。

4.2 loop:读取与打印全部测量量

void loop() { PM25_AQI_Data data; if (! aqi.read(&data)) { Serial.println("Could not read from AQI"); delay(500); return; } // 标准浓度 Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_standard); Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_standard); Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_standard); // 环境浓度 Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_env); // 六档颗粒计数 Serial.print(F("Particles > 0.3um / 0.1L air:")); Serial.println(data.particles_03um); // ... 0.5um / 1.0um / 2.5um / 5.0um / 10um delay(1000); }

该例程完整打印了结构体中全部 12 个测量量,可作为裸机项目(非 Tasmota)接入时的参考模板。读取间隔建议 ≥1 秒,与传感器自身刷新周期匹配。

五、Tasmota 集成:从编译开关到数据上报

Tasmota 将上述库封装为传感器驱动 xsns_104_pmsa003i.ino,实现了完整的生命周期管理。

5.1 编译开关(默认关闭,需手动启用)

在 my_user_config.h 中取消注释即可启用:

#define USE_PMSA003I // [I2cDriver78] Enable PMSA003I Air Quality Sensor (I2C address 0x12) (+1k8 code)

说明:

  • 该开关依赖USE_I2C,启用后固件增加约 1.8KB 代码;
  • 对应的编译选项也出现在 tasmota_configurations.h 与 tasmota_configurations_ESP32.h 中,ESP32 构建时同样适用;
  • 启用后固件的"特性标志位"(feature flag)0x00040000会被置位,见 support_features.ino;
  • 在 I2CDEVICES.md 的 I2C 设备表中登记为I2cDriver 78XI2C_78),设备地址0x12

5.2 初始化流程

驱动在FUNC_INIT阶段调用pmsa003i_Init()(见 xsns_104_pmsa003i.ino):

void pmsa003i_Init(void) { if (!I2cSetDevice(PMSA003I_ADDRESS)) { return; } // 登记 I2C 地址 if (Pmsa003i.aqi.begin_I2C()) { Pmsa003i.type = true; Pmsa003i.warmup_counter = PMSA003I_WARMUP_DELAY; // 进入预热期 I2cSetActiveFound(PMSA003I_ADDRESS, "PMSA003I"); // 标记设备已激活 } }

三个值得注意的设计:

  1. 设备登记:先通过I2cSetDevice()检查地址冲突,成功后才尝试begin_I2C(),避免与其他 I2C 外设争抢地址;
  2. 预热机制PMSA003I_WARMUP_DELAY默认 30 秒(宏定义于文件头部#ifndef PMSA003I_WARMUP_DELAY,可在用户配置中覆盖)。传感器启动初期读数不稳定,驱动用warmup_counter倒计时,期间Pmsa003iUpdate()直接返回;
  3. I2C 使能守卫:入口处if (!I2cEnabled(XI2C_78)) return false;,即只有通过控制台I2cDriver78命令启用后驱动才会执行。

5.3 周期读取与数据就绪标志

void Pmsa003iUpdate(void) { if (Pmsa003i.warmup_counter > 0) { Pmsa003i.warmup_counter--; return; } Pmsa003i.ready = false; PM25_AQI_Data data; if (! Pmsa003i.aqi.read(&data)) { return; } // 校验失败则保持 not ready Pmsa003i.data = data; Pmsa003i.ready = true; }

驱动挂在FUNC_EVERY_SECOND(每秒执行一次)回调上,ready标志确保只有通过帧头与校验和验证的新数据才会进入上报环节。结合read()内部逻辑可知:校验和失败或帧头错位的帧会被静默丢弃,等待下一周期重试

5.4 JSON / MQTT / WebUI 上报

Pmsa003iShow(bool json)将 12 个测量量完整输出(见 xsns_104_pmsa003i.ino):

TelePeriod 周期性 JSON(MQTT 遥测消息)字段映射:

JSON 键来源字段含义
CF1/CF2.5/CF10pm10_standard/pm25_standard/pm100_standard标准浓度
PM1/PM2.5/PM10pm10_env/pm25_env/pm100_env环境浓度
PB0.3/PB0.5/PB1particles_03um/particles_05um/particles_10um颗粒计数
PB2.5/PB5/PB10particles_25um/particles_50um/particles_100um颗粒计数

对应的典型 MQTT JSON 片段形如:

"PMSA003I":{"CF1":3,"CF2.5":5,"CF10":9,"PM1":3,"PM2.5":5,"PM10":9,"PB0.3":180,"PB0.5":30,"PB1":8,"PB2.5":6,"PB5":1,"PB10":0}

Domoticz 联动(启用USE_DOMOTICZ时):环境浓度 PM1/PM2.5/PM10 分别映射到 Domoticz 的计数器(DZ_COUNT)、电压(DZ_VOLTAGE)与电流(DZ_CURRENT)类型。

WebUI(启用USE_WEBSERVER时):通过HTTP_SNS_ENVIRONMENTAL_CONCENTRATIONHTTP_SNS_PARTICALS_BEYOND模板,在 Web 传感器页展示环境浓度与六档颗粒计数。

六、常见问题与排查清单

  1. begin_I2C()返回 false

    • 检查接线 SDA/SCL(PMSA003I 需要上拉电阻,多数面包板适配器已内置);
    • 用控制台I2Cscan命令确认0x12地址是否可见;
    • 确认固件已启用USE_PMSA003II2cDriver78处于使能状态。
  2. UART 模式读不到数据

    • 波特率必须为 9600;软件串口与硬件串口二选一,切勿同时绑定两个流;
    • 检查read()的帧同步逻辑:UART 路径会先丢弃帧头0x42之前的杂散字节,若长期超时,多半是波特率或接线错误。
  3. 读数长时间为 0 或恒定

    • 确认预热期(默认 30 秒)已结束;
    • 传感器需要稳定的气流环境,密闭腔体或防尘棉堵塞会导致计数偏低。
  4. 校验和失败频繁

    • 缩短 I2C 总线距离、降低总线速率;UART 模式下避免使用过长杜邦线,必要时降低串口速率或改用硬件串口。

七、总结

Adafruit_PM25AQI 库以极简的三方法 API 封装了 Plantower 协议的两大核心难点——大端字节序解析帧校验和验证,一次read()即可拿到 PM1.0/PM2.5/PM10 的两种浓度与六档颗粒计数。在 Tasmota 中,该库被 xsns_104_pmsa003i.ino 封装为 I2cDriver78,配合 30 秒预热保护、每秒轮询与校验门控,通过 MQTT JSON、Domoticz 与 WebUI 三条通道完整暴露 12 个测量量,实现了纯本地的空气质量监测方案。若需继续深入,可对照阅读 Adafruit_PM25AQI.cpp 的字节重组细节、PM25_test.ino 的裸机接入范例,以及 I2CDEVICES.md 中完整的 I2C 设备清单。

【免费下载链接】TasmotaAlternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at项目地址: https://gitcode.com/GitHub_Trending/ta/Tasmota

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 5:54:34

STM32F4+MPU6500轻量卡尔曼滤波姿态解算实战

简介&#xff1a;本资源是一套面向嵌入式开发者与机甲大师参赛队伍的MPU6500传感器驱动与卡尔曼滤波融合实践方案&#xff0c;聚焦STM32F4平台下的高精度姿态解算实现。针对MPU6500原始数据噪声大、姿态漂移等问题&#xff0c;提供完整的硬件接口配置、IC通信读取、六轴数据融合…

作者头像 李华
网站建设 2026/9/13 5:53:05

SpringBoot集成OpenAPI实现自动化API文档

1. SpringBoot集成OpenAPI的背景与价值在现代Web应用开发中&#xff0c;API文档的维护一直是个痛点。传统的手写文档方式存在更新滞后、与代码不同步的问题&#xff0c;而OpenAPI规范&#xff08;原Swagger&#xff09;通过代码自动生成文档的方式解决了这一难题。SpringBoot作…

作者头像 李华
网站建设 2026/9/13 5:51:12

RAG技术解析:检索增强生成的核心架构与实战应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 5:50:49

COMSOL三维多孔介质建模技术与工程应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华