
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该库同时支持I2C和UART两种物理接口其适用前提是传感器固件版本必须支持对应协议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_I2CI2C 模式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 0x12PMSA003I 仅有唯一 I2C 地址底层通过依赖库 Adafruit BusIO 的Adafruit_I2CDevice完成总线探测参数theWire默认指向全局Wire实例多总线场景可传入自定义TwoWire对象返回false表示总线上未发现设备。3.2 begin_UARTUART 模式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 中的完整流程为I2C 路径一次性读取 32 字节UART 路径先循环跳过非0x42字节以同步到帧头最多跳 32 字节再读取 32 字节数据帧头检查buffer[0]必须等于0x42否则返回false校验和计算对前 30 字节求和sum buffer[i]与帧尾checksum比对不一致返回false大小端处理Plantower 协议为大端代码将 30 个原始字节重组为 15 个uint16_tbuffer_u16[i] buffer[2i*21]; buffer_u16[i] (buffer[2i*2] 8);从而屏蔽平台字节序差异填充结构体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 #2pin #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 flag0x00040000会被置位见 support_features.ino在 I2CDEVICES.md 的 I2C 设备表中登记为I2cDriver 78XI2C_78设备地址0x12。5.2 初始化流程驱动在FUNC_INIT阶段调用pmsa003i_Init()见 xsns_104_pmsa003i.inovoid 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); // 标记设备已激活 } }三个值得注意的设计设备登记先通过I2cSetDevice()检查地址冲突成功后才尝试begin_I2C()避免与其他 I2C 外设争抢地址预热机制PMSA003I_WARMUP_DELAY默认 30 秒宏定义于文件头部#ifndef PMSA003I_WARMUP_DELAY可在用户配置中覆盖。传感器启动初期读数不稳定驱动用warmup_counter倒计时期间Pmsa003iUpdate()直接返回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.inoTelePeriod 周期性 JSONMQTT 遥测消息字段映射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_CONCENTRATION与HTTP_SNS_PARTICALS_BEYOND模板在 Web 传感器页展示环境浓度与六档颗粒计数。六、常见问题与排查清单begin_I2C()返回 false检查接线 SDA/SCLPMSA003I 需要上拉电阻多数面包板适配器已内置用控制台I2Cscan命令确认0x12地址是否可见确认固件已启用USE_PMSA003I且I2cDriver78处于使能状态。UART 模式读不到数据波特率必须为 9600软件串口与硬件串口二选一切勿同时绑定两个流检查read()的帧同步逻辑UART 路径会先丢弃帧头0x42之前的杂散字节若长期超时多半是波特率或接线错误。读数长时间为 0 或恒定确认预热期默认 30 秒已结束传感器需要稳定的气流环境密闭腔体或防尘棉堵塞会导致计数偏低。校验和失败频繁缩短 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),仅供参考