Tasmota 集成 Sensirion SEN5X Arduino 驱动库解析:从 CHANGELOG 看版本演进与空气质量传感器接入实践
【免费下载链接】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
Sensirion I2C SEN5X 是一套用于读取 SEN50/SEN54/SEN55 空气质量传感器数据的 Arduino 驱动库,在本仓库中它被 Tasmota 的xsns_103_sen5x驱动直接调用,负责通过 I2C 采集 PM1.0/PM2.5/PM4/PM10 颗粒物浓度、温湿度以及 VOC/NOx 指数。本文以该库的 CHANGELOG.md 为主线,结合仓库内的源码、示例与 Tasmota 驱动实现,完整梳理 0.1.0 到 0.3.0 的功能演进、关键修复的底层原理,并给出从接线、安装到在 Tasmota 中启用的完整实战路径。
一、库的定位与支持型号
该库是 Sensirion 官方为 Arduino 平台提供的 SEN5X 系列 I2C 驱动(README.md),使用模块的 I2C 接口与传感器通信。其声明支持三种型号:
| 型号 | 能力说明 |
|---|---|
| SEN50 | 仅提供颗粒物(particulate matter)信号,即 PM 浓度 |
| SEN54 | 无 NOx 信号(无 NOx 传感器),其余功能可用 |
| SEN55 | 全功能集:PM + 温湿度 + VOC + NOx |
这一型号差异直接反映在库的 API 设计上:readMeasuredValues()返回的noxIndex参数注释明确指出"对于 SEN54 该值为 NAN",而 library.properties 中版本号为0.3.0,与 CHANGELOG 最新发布版本一致,说明当前仓库中的驱动即 0.3.0 时代码。
在 Tasmota 侧,该库对应 I2C 设备表项 76(I2CDEVICES.md),驱动文件为 xsns_103_sen5x.ino,I2C 地址固定为0x69,用于输出气体(VOC/NOx 指数)与空气质量(PM1/PM2.5/PM4/PM10)数据。
二、CHANGELOG 版本演进总览
原 CHANGELOG 完整记录了库的三个正式版本,时间跨度从 2022 年初到 2023 年初:
| 版本 | 发布日期 | 核心变更 |
|---|---|---|
| 0.1.0 | 2022-01-05 | 初始发布(Initial release) |
| 0.2.0 | 2022-03-30 | 新增 SEN50 支持 |
| 0.3.0 | 2023-01-19 | 修复readMeasuredPmValues中 typicalParticleSize 的缩放;修复readMeasuredPmValuesAsIntegers的注释 |
| Unreleased | - | 待定 |
下文分别深入每一版本的实现细节与修复的底层原因。
三、v0.1.0:初始发布的 API 骨架
作为初始版本,0.1.0 奠定了整个库的功能边界。从 SensirionI2CSen5x.h 可以看到,驱动以SensirionI2CSen5x类为核心,通过begin(TwoWire&)绑定 Arduino 的 Wire 总线对象,之后所有命令都以 16 位命令字的形式写入 I2C。
3.1 测量控制类 API
startMeasurement():启动连续测量,对应命令字0x21。启动后约 1 秒内首个结果就绪,可用readDataReady()(命令0x0202)轮询数据是否就绪。startMeasurementWithoutPm():启动不含 PM 的低功耗测量模式(仅温湿度/VOC/NOx),激光与风扇关闭,仅 SEN54/SEN55 支持。stopMeasurement():停止测量返回 idle 模式,对应命令字0x104。
3.2 数据读取类 API
初始版本即提供了三套读数接口,区别在于返回类型与缩放处理:
| API | 返回值类型 | 无效值表示 |
|---|---|---|
readMeasuredValues() | float | NAN |
readMeasuredValuesAsIntegers() | 整数(带缩放) | 0xFFFF(uint16)/0x7FFF(int16) |
readMeasuredRawValues() | 原始整数 tick | 0xFFFF/0x7FFF |
从 SensirionI2CSen5x.cpp 的实现可见,readMeasuredValues()内部先调用readMeasuredValuesAsIntegers()(命令字0x3C4,读取 24 字节),再按下述缩放因子换算为物理量:
- PM 质量浓度(PM1.0/PM2.5/PM4.0/PM10.0):除以 10 →
[µg/m³] - 环境湿度:除以 100 →
RH [%] - 环境温度:除以 200 →
T [°C] - VOC/NOx 指数:除以 10
无效值(未就绪、测量未运行)会被转换为 NAN 向上层传递,这正是 Tasmota 驱动中大量isnan()判断的由来。
3.3 配置与设备信息 API
初始版本已包含温度补偿、VOC/NOx 算法调参、风扇自动清洁间隔、产品信息与版本读取、设备状态与复位等一整套接口,其中与 Tasmota 集成最相关的是deviceReset()(命令0xD304)与getVersion()/getSerialNumber()/getProductName()——Tasmota 驱动初始化时正是用这几个接口完成设备探测与日志记录。
四、v0.2.0:新增 SEN50 支持
0.2.0 的核心变更是Add support for SEN50。SEN50 是 SEN5X 系列中仅提供颗粒物信号的型号,没有温湿度、VOC、NOx 输出。
对应的实现是 readMeasuredValuesSen50():它只暴露 PM1.0/PM2.5/PM4.0/PM10.0 四个 float 输出参数,内部实际复用readMeasuredValues()读取全部数据后丢弃温湿度/VOC/NOx 占位参数(ambientHumidityDummy、vocIndexDummy等),避免调用方为无关信号分配逻辑。
这一设计也解释了 Tasmota 驱动为何统一使用完整版readMeasuredValues():对驱动层而言,只需在展示数据时对 SEN54/SEN50 缺失的信号(如 NOx)做 NAN 判断即可,无需按型号分支调用不同读取函数。
五、v0.3.0:两个修复的底层原理
0.3.0 发布于 2023-01-19,包含两项变更,均与颗粒物扩展读取接口相关:
5.1 修复 typicalParticleSize 的缩放
变更内容为"Fix scaling of typicalParticleSize for readMeasuredPmValues"。对比 SensirionI2CSen5x.cpp 的当前实现:
typicalParticleSize = typicalParticleSizeInt == UINT_INVALID ? NAN : typicalParticleSizeInt / 1000.0f;即典型粒径的换算因子为1000(Size [µm] = value / 1000),与质量浓度、数量浓度的因子 10 明显不同。这个修复的意义在于:readMeasuredPmValues()返回的是物理量 float,若此处仍沿用10.0f的通用因子,粒径会整体放大 100 倍,造成严重的数据失真。修复后库内readMeasuredPmValues()与其整数版本readMeasuredPmValuesAsIntegers()的缩放语义保持一致。
5.2 修复 readMeasuredPmValuesAsIntegers 的注释
第二项变更是"Fix comments for readMeasuredPmValuesAsIntegers",属于文档一致性修正。SensirionI2CSen5x.h 中该接口的注释明确标注了每个输出参数的缩放因子与无效值语义:
- PM 质量浓度与数量浓度均按因子 10 缩放;
typicalParticleSize按因子 1000 缩放(Size [µm] = value / 1000);- 未知值时全部返回
0xFFFF。
该接口对应命令字0x413,一次读取 30 字节,包含 10 个 uint16 字段(4 个质量浓度 + 5 个数量浓度 + 1 个典型粒径),实现代码 按序解析。这类注释修复虽然不改变行为,但对二次开发者而言是关键的"协议文档",避免误用缩放因子。
六、硬件接线与库安装
6.1 引脚连接
SEN5X 模块提供 6 引脚接口(README.md),与 Arduino 标准 I2C 总线连接如下:
| SEN5X | Arduino | 跳线颜色 |
|---|---|---|
| VCC | 5V | 红 |
| GND | GND | 黑 |
| SDA | SDA | 绿 |
| SCL | SCL | 黄 |
| SEL | GND(选择 I2C) | 蓝 |
引脚定义说明:
| 引脚 | 名称 | 说明 | 备注 |
|---|---|---|---|
| 1 | VCC | 电源 | 5V ±10% |
| 2 | GND | 地 | |
| 3 | SDA | I2C 数据输入/输出 | 兼容 TTL 5V 与 LVTTL 3.3V |
| 4 | SCL | I2C 时钟输入 | 兼容 TTL 5V 与 LVTTL 3.3V |
| 5 | SEL | 接口选择 | 拉低到 GND 选择 I2C |
| 6 | NC | 不要连接 |
6.2 安装方式
- 下载该库最新 release 的 .zip 包;
- 在 Arduino IDE 中通过
Sketch => Include Library => Add .ZIP Library...添加; - 同样方式安装其唯一依赖Sensirion Core(本仓库中对应
lib_i2c/arduino-core),否则编译会因缺少<SensirionCore.h>头文件失败。
打开示例工程:File => Examples => Sensirion I2C SEN5X => exampleUsage,编译上传后打开 Serial Monitor / Serial Plotter,波特率设为115200即可观察测量值。
七、示例程序逐段解读
仓库自带 exampleUsage.ino,其流程可拆解为四步,与 Tasmota 驱动初始化逻辑几乎一一对应:
- 初始化:
Wire.begin()启动 I2C 总线,sen5x.begin(Wire)绑定总线; - 复位与身份识别:调用
deviceReset()复位传感器,随后getSerialNumber()/getProductName()/getVersion()读取设备身份与固件/硬件版本。注意示例代码用USE_PRODUCT_INFO宏(要求 I2C 缓冲区 ≥ 48 字节)保护这些命令,因为产品名/序列号读取命令最长可达 48 字节,部分 Arduino 默认 Wire 缓冲区不足; - 温度补偿:
setTemperatureOffsetSimple(0.0)设置温度偏移(摄氏度,默认 0)。传感器默认已对模块自热做补偿,若将模块设计进整机,需要按 Sensirion 温度补偿应用说明重新校准; - 启动与轮询:
startMeasurement()启动测量,loop()中每秒调用readMeasuredValues()读取 8 个物理量,并用isnan()对 SEN54 缺失的 NOx 等信号做兜底输出。
八、Tasmota 中的集成:xsns_103_sen5x 驱动
本文档关联的库在本仓库中的真实消费方是 xsns_103_sen5x.ino,该驱动揭示了库 API 在真实固件中的调用方式:
- I2C 地址:
SEN5X_ADDRESS 0x69,注册为 I2C 设备表第 76 项(XI2C_76),对应 I2CDEVICES.md 中的USE_SEN5X开关; - 初始化流程(
sen5x_Init()):上电后等待 60ms 让传感器完成启动,随后依次执行deviceReset()(失败会重试一次,参见源码注释引用的 Tasmota 讨论 24452)、getVersion()、getSerialNumber()、getProductName(),全部成功后delay(1100)再调用startMeasurement()——与示例程序的顺序完全一致; - 被动模式:
SetOption156(Settings->flag6.sen5x_passive_mode)可切换为被动模式,用于总线上存在其他 I2C 主设备(如宜家 Vindstyrka)的场景——此时跳过设备初始化与持续测量,改为每 10 秒(SEN5X_PASSIVE_MODE_INTERVAL)轮询一次; - 数据采集:
SEN5XUpdate()在FUNC_EVERY_SECOND事件中每秒调用一次readMeasuredValues(),这是因为 VOC 基线补偿算法需要每秒更新一次才能正常工作(源码注释明确说明); - 输出:JSON 上报字段为
SEN5X对象下的PM1/PM2.5/PM4/PM10/NOx/VOC/Temperature/Humidity/AHum,网页端则复用HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION等模板输出。
从源码结构可以推断,0.3.0 的 typicalParticleSize 缩放修复对 Tasmota 驱动无直接影响——驱动只消费readMeasuredValues()的 8 个标准物理量,并未调用 PM 扩展读取接口;但该修复保证了库面向其他用户时数据语义的正确性。
九、版本演进对二次开发者的启示
回顾三个版本,可以提炼出几条对集成者有用的经验:
- 缩放因子是错误高发区:同一条 PM 读取命令里,质量浓度/数量浓度用因子 10,典型粒径却用因子 1000(见
readMeasuredPmValuesAsIntegers注释)。任何自行解析原始字节的实现都必须按字段区分因子,0.3.0 的修复正是此类问题。 - 无效值语义要区分函数:float 接口用 NAN 表示无效(如 SEN54 的 NOx、上电后前 10~11 秒的 NOx),整数接口用
0xFFFF/0x7FFF上限值表示无效。消费端代码必须同时处理这两种形态。 - 型号差异集中在 NOx:SEN50/SEN54/SEN55 的差异全部体现在"哪些输出字段恒为 NAN/无效"上,
readMeasuredValues()这一套 API 即可覆盖全家族,这也是 Tasmota 驱动不按型号分叉代码的原因。
十、总结
Sensirion I2C SEN5X 库的 CHANGELOG 虽短,却精确记录了从 2022 年初初始发布、同年 3 月 SEN50 支持,到 2023 年 1 月粒径缩放修复的完整演进路径。透过 SensirionI2CSen5x.cpp、SensirionI2CSen5x.h 与 xsns_103_sen5x.ino 的对照阅读,可以看到这套驱动在 Tasmota 固件中被如何落地为每秒钟一次的空气质量数据采集链路。无论是独立 Arduino 项目还是 Tasmota 环境,理解版本变更背后的缩放语义与无效值约定,都是避免数据采坑的关键。
【免费下载链接】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),仅供参考