ESP32+传感器打造家庭空气质量监测系统:从选型到数据校准全解析
2026/8/29 11:59:39 网站建设 项目流程

住在城市里,大家对“空气质量”这个词基本不陌生,但很多人对它的感知还停留在天气预报里的AQI指数,或者是手机上偶尔弹出的污染提醒。直到我家娃有一阵子反复咳嗽,医生随口问了一句“家里新风开不开、甲醛测过没有”,我才发现自己对每天待得最久的室内环境,几乎一无所知。也就是从那天起,我动了给自己搞一套家庭空气质量监测系统的念头。

这个项目标题叫Home Air Quality Monitoring (Part 1),听起来挺学院派,其实说白了就是:用传感器把家里看不见摸不着的东西量化出来,让自己知道空气到底好不好。Part 1 我定的范围很明确——先做一台能独立运行、实时显示、数据可查的室内空气监测节点,把 PM2.5、CO2、温湿度、TVOC 这几个核心指标跑通,后续再考虑数据上云和联动控制。这篇文章会把我的硬件选型、接线、代码、踩坑全过程都摊开来讲,适合有一定动手基础、想入门物联网或者环境监测的朋友参考。

1. 项目整体设计与思路拆解

1.1 家庭场景到底需要监测什么

很多人一上来就奔着“全都要”去,PM2.5、甲醛、CO2、TVOC、温湿度、噪声、光照,恨不得把所有能买的传感器都堆上去。我在设计这个项目时反而先做了减法,因为家庭空气监测的核心诉求其实就那么几个:

  • PM2.5 浓度:颗粒物是室内空气污染的“主角”,做饭油烟、打扫扬尘、室外渗入,都会引起它波动。它直接关系呼吸道健康,尤其是家里有老人小孩的,这是刚需指标。
  • CO2 浓度:CO2 反映的是“通风换气是否充分”。一间卧室关窗睡一夜,CO2 轻松破 2000ppm,第二天早上头昏脑涨,往往不是没睡好,而是缺氧了。这个指标对判断“什么时候该开窗”特别有指导意义。
  • 温湿度:体感舒适度的基础参数,也影响其他传感器的读数修正。比如很多 PM2.5 传感器对湿度敏感,湿度过高时测量值会偏大,没有温湿度数据你很难判断读数是环境真实值还是传感器“失真”。
  • TVOC/甲醛:TVOC 是总挥发性有机物的统称,装修污染、新家具、香薰、烹饪都会产生。甲醛严格来说需要电化学传感器才测得准,但作为家庭日常参考,TVOC 指标可以帮助发现“什么时候污染突然升高了”。

我的建议是:第一版先保证 PM2.5、CO2、温湿度这三个指标稳定可靠,TVOC 作为辅助参考。功能做少一点没关系,每个数据都准确比什么都有但什么都不准强一百倍。

1.2 传感器选型的对比与权衡

选传感器是整个项目里最花时间的一步。我前后对比了七八款,最终留下来的核心是这三颗:

传感器测量内容接口精度表现备注
Sensirion SEN55PM1.0/PM2.5/PM4/PM10、温湿度、TVOC、NOxI2C/UARTPM2.5 一致性较好,自带温湿度校准价格偏高,但一颗芯片解决多指标,省心
Sensirion SCD40CO2I2C精度 ±(50ppm + 5%)体积小,寿命长,适合长期运行
SHT40温湿度I2C温度 ±0.2°C,湿度 ±1.8%RHSEN55 自带温湿度,SHT40 作为独立校验用

这里必须说一句:如果预算有限,把最大头留给 CO2 传感器,PM2.5 可以用性价比更高的 Plantower PMS5003。PMS5003 是国内用得最多的颗粒物传感器,几十块钱,数据也很能打,只是体积比 SEN55 大不少。我这次选 SEN55 纯粹是为了缩小整机体积,顺便省掉一个温湿度传感器。

CO2 传感器有个坑要注意:市面上便宜的“CO2 传感器”很多其实是假的,用 TVOC 估算出来的 eCO2,不是真正测量二氧化碳浓度。真正靠谱的是 NDIR(非色散红外)原理的传感器,比如 SCD40、SCD30、MH-Z19B。选型时认准 NDIR 原理,别被“eCO2”这种估算值忽悠了

1.3 主控与系统架构怎么定

主控我选了 ESP32,理由很直接:自带 Wi-Fi 和蓝牙,后续要做数据上报、远程查看,不需要再外接网络模块。同时它的 ADC、I2C、UART 接口资源充足,带 OLED 屏幕完全无压力。

架构上我走了“传感器数据采集 + 本地 OLED 显示 + 串口日志输出”的最小可用方案,没有一上来就接 Home Assistant 或者云平台。为什么这样设计?

把第一版做得简单,是为了先验证硬件链路和数据质量。很多项目的失败不是因为代码写不出来,而是传感器数据不准、不稳定,后续所有功能都建于流沙之上。先把采集端做扎实,再考虑数据去哪。

系统框图大致是这样的:ESP32 作为主控,通过 I2C 总线挂载 SEN55 和 SCD40,电源用 5V 输入经稳压给传感器供电,ESP32 的 3.3V 给 OLED 屏幕供电。数据采集循环里,每 2 秒读取一次传感器数据,经过简单的平滑处理后推送到屏幕刷新。整个系统不依赖外部网络,上电即用。

2. 核心元器件与硬件连接细节

2.1 元器件采购清单与避坑建议

我列一下我这个项目实际用到的物料,方便大家直接照着买:

  • ESP32 DevKitC V4 开发板,买的时候注意选 CP2102/CP2104 串口芯片版本,驱动兼容性好
  • Sensirion SEN55 空气质量传感器模组
  • Sensirion SCD40 CO2 传感器模组
  • 0.96 寸 SSD1306 OLED 显示屏(I2C 接口,128x64 分辨率)
  • AMS1117-3.3 稳压模块(如果直接用 5V 供电给 ESP32 就不需要额外降压)
  • 10kΩ 电阻 2 个(I2C 上拉,虽然大部分模块自带,但准备着没坏处)
  • 面包板、杜邦线若干、外壳(我用的 3D 打印)

这里有几个采购时的注意事项:

SEN55 和 SCD40 都是 SMD 贴片封装,没有现成的插针模组的话,焊接起来比较痛苦,建议直接买商家做好的转接板版本。SEN55 的转接板一般会引出标准的 1.27mm 间距排针,SCD40 转接板则是 2.54mm 标准排针,接线方便很多。

电源部分我要多说两句。ESP32 的 WiFi 开启瞬间电流会冲到 500mA 左右,传感器工作电流小,但 SCD40 内部有加热元件,启动时也有一个短暂的电流尖峰。如果用稳压模块,必须确保它能稳定输出 3.3V/1A 以上,我用的是 MP1584 降压模块,输入 6-12V,输出设定为 5V,再通过开发板自带的 AMS1117 转为 3.3V。这样比你直接用 USB 供电要稳不少,尤其后面要长期通电运行。

2.2 I2C 总线的接线与电平匹配

I2C 是这项目的“血管主干道”,SEN55 和 SCD40 都挂在同一条 I2C 总线上。接线方式如下:

传感器引脚ESP32 GPIO说明
SEN55 VCC5VSEN55 支持 5V 供电,不能接 3.3V
SEN55 GNDGND共地
SEN55 SDAGPIO21I2C 数据线
SEN55 SCLGPIO22I2C 时钟线
SEN55 SELGND拉低选择 I2C 模式(悬空默认 UART)
SCD40 VIN3.3VSCD40 支持 3.3V 供电
SCD40 GNDGND共地
SCD40 SDAGPIO21与 SEN55 共用 SDA
SCD40 SCLGPIO22与 SEN55 共用 SCL
OLED VDD3.3V屏幕供电
OLED SDA/SCLGPIO21/GPIO22同样挂载 I2C 总线

接线看起来不复杂,但里面藏着两个特别容易踩的坑,我一开始就都踩了一遍:

第一个坑是SEN55 的 SEL 引脚不接直接默认走 UART 模式。这个传感器出厂默认是 UART 输出,你把它接上 I2C 总线后扫描设备地址,死活找不到它。手册里的原话是:SEL 引脚悬空 = UART,拉低 = I2C。我刚开始图省事没接这颗线,结果 I2C 扫描只有 SCD40 响应,排查了半天才发现是这个问题。

第二个坑是I2C 总线上多设备地址冲突。SEN55 的 I2C 地址是 0x69,SCD40 是 0x62,OLED 是 0x3C,三者互不冲突,接线前最好确认一下你手上模块的实际地址。如果某块转接板带了 A0/A1 跳线可以改地址,改之前先查数据手册,不要拍脑袋乱跳线。

2.3 传感器上电初始化顺序

硬件接好以后,上电顺序也有讲究。我的习惯是先给 ESP32 上电,等它跑起来后再给传感器通电(用杜邦线手动插拔也行,或者给传感器加一个由 GPIO 控制的 MOSFET 开关)。为什么?

SEN55 和 SCD40 这类传感器都有启动自检和预热过程,SEN55 大约需要 10-15 秒预热,SCD40 在首次上电后需要一段时间让内部的参考值稳定。如果所有设备同时上电,ESP32 在这段时间里可能已经把 I2C 总线“锁死”了——传感器还没准备好接收指令,主控却在拼命重试,结果就是 I2C 通信异常。稳妥的做法是:

  1. 先把代码烧录好,烧录时断开传感器电源
  2. 给 ESP32 上电,等待 5 秒
  3. 再给传感器模组通电
  4. 观察串口日志,等传感器返回正常数据

后面我为了图省事,把传感器直接接在 ESP32 的 5V 引脚上,靠开发板统一上电。实测下来只要代码里加了一个 10 秒钟的启动延时,就基本不会出问题。启动延时是这里的关键设计,不是可有可无的装饰

3. 数据采集代码实现与本地展示

3.1 开发环境与依赖库准备

软件层面我用的是 Arduino IDE 搭配 ESP32 开发板支持包,版本用的 2.x 系列。选 Arduino 而不是 ESP-IDF 的理由很简单:这个项目体量不大,Arduino 丰富的第三方库能让我把精力集中在业务逻辑上,而不是去跟底层协议死磕。

需要安装的第三方库:

  • Sensirion I2C SEN5x:SEN55 官方库
  • SparkFun SCD40 和 SCD41:SCD40 官方库
  • U8g2:OLED 显示库,对各种字体和屏幕驱动支持很好
  • Wire:Arduino 内置的 I2C 库

装库的时候有个要注意的点:Sensirion 官方库对 Arduino 的适配版本要求比较高,如果编译报错,先检查库版本是不是太旧。我一开始装的是老版本,编译死活过不去,升级到 1.0.4 之后问题才解决。

3.2 核心代码实现与注释

我的代码分三个文件:主程序、传感器管理模块、显示模块。这里只贴最关键的部分,完整的项目文件我放到文末的资源链接里。

首先是主程序的初始化逻辑:

#include <Arduino.h> #include <Wire.h> #include <SensirionI2cSen5x.h> #include <SparkFun_SCD40_Arduino_Library.h> #include <U8g2lib.h> SensirionI2cSen5x sen55; SCD40 scd40; U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // 全局变量,保存各类传感器读数 struct AirData { float pm25; float co2; float temperature; float humidity; float tvoc; bool valid; }; AirData airData = {0, 0, 0, 0, 0, false}; void setup() { Serial.begin(115200); Wire.begin(21, 22); // SDA, SCL // 关键:给传感器留足上电启动时间 delay(10000); // 初始化 SEN55 sen55.begin(Wire); sen55.deviceReset(); delay(500); // 初始化 SCD40 scd40.begin(); scd40.setMeasurementMode(SCD40_MEASUREMENT_MODE_PERIODIC); scd40.setPeriodicMeasurement(true); // 开始测量 sen55.startMeasurement(); u8g2.begin(); u8g2.setFont(u8g2_font_6x12_tr); Serial.println("Home Air Quality Monitor v1.0"); Serial.println("Sensor init done."); }

这段代码里最值得说的是sen55.deviceReset()这一句。SEN55 使用前最好无条件执行一次软复位,作用是把传感器恢复到已知状态。如果你之前跑过其他程序、传感器内部状态已经乱了,不复位的话接下来可能读到异常的 PM 值。SCD40 则不需要额外复位,直接用begin()即可。

再看读取逻辑,我放在loop()里,每 2 秒执行一次:

void loop() { readSensors(); updateDisplay(); printSerialLog(); delay(2000); } void readSensors() { unsigned long startTime = millis(); // 读取 SEN55 数据 float pm1_0, pm2_5, pm4_0, pm10, humidity, temperature, tvoc, nox; uint16_t error; char errorMessage[256]; error = sen55.readMeasuredValues( pm1_0, pm2_5, pm4_0, pm10, humidity, temperature, tvoc, nox ); if (error != NO_ERROR) { Serial.print("SEN55 read failed: "); errorToString(error, errorMessage, 256); Serial.println(errorMessage); airData.valid = false; } else { airData.pm25 = pm2_5; airData.temperature = temperature; airData.humidity = humidity; airData.tvoc = tvoc; } // 读取 SCD40 数据 if (scd40.measurementReady()) { scd40.readMeasurement(); airData.co2 = scd40.getCO2(); } // 防止循环执行过快导致传感器频繁重读 unsigned long elapsed = millis() - startTime; if (elapsed < 1000) { delay(1000 - elapsed); } }

这里有几个性能上的细节:

SEN55 的读取间隔不要低于 1 秒。它内部的采样频率是 1Hz,你 2 秒读一次是合理的选择,读取太频繁白白占用 I2C 带宽,还可能引发“设备繁忙”错误。SCD40 的measurementReady()机制是它的特色,只有数据准备好了才去读,避免读到无效值。

另外注意,sen55.readMeasuredValues()一次调用能拿回全部 8 个指标,你不需要分多次读,这样既减少了 I2C 通信次数,也避免了多次读取之间数据不一致的问题。

3.3 OLED 屏幕布局与刷新策略

OLED 显示部分我采用了“四象限”布局,一屏装下所有核心数据,刷起来一眼就能看完。屏幕只有 128x64 像素,空间很紧张,必须想清楚优先级:

┌─────────────────────┐ │ PM2.5 028 µg/m³ │ │ CO2 650 ppm │ │ Temp 24.5 °C │ │ RH 56 % │ │ TVOC 120 µg/m³ │ └─────────────────────┘

对应的显示代码:

void updateDisplay() { char line[32]; u8g2.clearBuffer(); snprintf(line, sizeof(line), "PM2.5 %05.0f ug/m3", airData.pm25); u8g2.drawStr(0, 12, line); snprintf(line, sizeof(line), "CO2 %05.0f ppm", airData.co2); u8g2.drawStr(0, 26, line); snprintf(line, sizeof(line), "Temp %04.1f C", airData.temperature); u8g2.drawStr(0, 40, line); snprintf(line, sizeof(line), "RH %03.0f %%", airData.humidity); u8g2.drawStr(0, 54, line); u8g2.sendBuffer(); }

刷新策略上我踩过一个坑:OLED 的 I2C 写入如果太频繁,会导致传感器读取的时序被干扰。这是因为I2C 总线上多设备通信时,屏幕刷新占用了大量总线时间。我的解决方法是把显示刷新降到 1 秒一次,传感器读取保持 2 秒一次,两者错开执行。实际效果是屏幕没有出现闪烁,传感器数据也没有再出现过丢失。

3.4 数据平滑处理:为什么不能直接用原始值

传感器读回来的原始数据是跳动的。PM2.5 尤其明显,你看着屏幕,数值从 25 跳到 40 再跳到 30,非常影响观感。这不全是传感器的错——空气中的颗粒物本身就是动态分布的,激光散射法测的就是瞬时粒子数。

我做了三层处理:

第一层是中值滤波,取最近 5 次采样值的中位数。中值滤波对去除脉冲型噪声特别有效,比如偶尔一次大颗粒物经过造成的尖峰。相比平均值,中位数不会被极端值带偏。

第二层是加权滑动平均,公式是:

smoothed = smoothed * 0.7 + newValue * 0.3

这个系数要按传感器响应速度灵活调整,0.7/0.3 是我实测下来比较平衡的配置,既保留了变化的趋势,又不会让数值跳来跳去。如果你觉得显示太迟钝,可以改成 0.5/0.5;如果觉得太跳,就改成 0.85/0.15。

第三层是变化量阈值控制,如果新采样值与当前平滑值相差不足 2 个单位,直接不更新显示。这能避免屏幕数值在低浓度区间频繁跳动。

void updateWithSmoothing(float newValue, float &smoothedValue) { if (smoothedValue == 0) { smoothedValue = newValue; return; } smoothedValue = smoothedValue * 0.7 + newValue * 0.3; if (abs(newValue - smoothedValue) < 2.0) { // 变化量过小,维持原值 } }

4. 传感器校准与数据可靠性实战

4.1 校准的意义:一颗准的传感器比十颗不准的更重要

传感器上电就能读数,但读数准不准,完全是另一回事。坦白说,刚装完这台设备时,我对屏幕上的数字是打问号的——PM2.5 和官方监测站的数据对不上,CO2 在开窗通风后也没有立刻降到预期值。这时候才意识到,校准和验证是系统真正可用的关键一环。

校准的思路是:用已知参照物给传感器找偏差。室外空气是最容易获取的参照物。在空气质量较好、风速较大的日子里,把设备放到窗口通风处,让室内外空气充分交换,这时候传感器的理论读数应该和所在城市的官方 PM2.5 发布值比较接近。如果偏差超过 20%,就要检查传感器内部是否有污染或者气流通道是否被遮挡。

CO2 校准更简单。找一个通风良好的清晨,把设备放窗边,此时室外 CO2 浓度约为 420ppm,SCD40 读数如果稳定在 400-450ppm 之间,说明传感器状态正常。如果偏差大,可以通过 SCD40 提供的setSensorAltitude()接口做高度补偿,或者直接使用 FORCE_RECALIBRATE 命令手动校准到 420ppm。

一个很多人忽略的点:SCD40 还有个自动自校准机制(ASC),它会根据一段时间内传感器检测到的最低 CO2 值,默认认为是新鲜空气(约 420ppm),自动修正偏移。但这种机制有个前提——传感器必须经历至少 7 天的正常运行,且期间确实出现过通风良好的低浓度环境。如果你家长期不开窗,ASC 反而可能把基准越拉越偏。我建议前两周关闭 ASC,手动校准一次后再开启,确保初始基准正确。

4.2 放置位置:比你想的更影响数据质量

传感器放哪,直接决定数据有没有参考价值。这里有几条硬规矩:

不要放在墙角。墙角空气流动最差,污染物容易滞留,测出来的数值会偏高。不要放在厨房门口正对油烟机的位置。做饭时的 PM 暴增会掩盖你实际想监测的“日常环境浓度”。不要放在窗户正下方。开窗瞬间会有一波涌流,读数会剧烈波动。

我自己的经验是放在房间的中心区域,距离地面 1.2-1.5 米,远离空调出风口和加湿器。这个高度接近于人体呼吸带,数据会更贴近“人在这个房间里实际呼吸到的空气”。如果家里有多个房间也没关系,Part 2 我会讲怎么做多个节点的对比监测,一台一台来。

还有一点容易忽略的是加热源的距离。CO2 传感器的工作依赖于热导率测量,SCD40 内部有一个红外光源,它工作时会微热。如果环境温度变化太快(比如旁边开了一台取暖器),读数会短暂失真。留出至少 30 厘米距离,问题就不大了。

4.3 湿度对 PM 传感器的影响与补偿策略

这是我在实测中发现最典型的现象:雨后或者在浴室、厨房等潮湿环境里,PM2.5 读数会明显偏大。原因在于水蒸气在颗粒物表面凝结,让颗粒物的粒径“变大”了,光学传感器把它误判为更多或更大的颗粒物。

SEN55 的固件内部其实已经做了湿度补偿,这是它贵的一个重要原因。但还是不能完全依赖它,我实测在 90%RH 以上高湿环境下,读数仍然存在明显偏高的情况。

我的补偿策略很简单:在数据展示层做一个“可信度降级”的提示。如果湿度超过 75%,在屏幕上把 PM2.5 的数值标成黄色或者加一个“*”标记,提示当前数据可能受湿度影响。这种做法本质上是坦诚面对传感器在当前环境下的局限性,而不是强行修正成你认为“正确”的数值。

4.4 与官方监测数据的对比验证

前几天外面空气不错,我把设备搬到窗台外面,人为制造了“室内外同气”的条件,跟当地生态环境局的 PM2.5 实时发布数据做了一次对比:

时间设备读数 PM2.5官方站点 PM2.5偏差
10:0012 µg/m³11 µg/m³+1
10:3015 µg/m³14 µg/m³+1
11:0018 µg/m³19 µg/m³-1
11:3020 µg/m³21 µg/m³-1

10 分钟内的平均偏差在 ±2µg/m³ 左右,整体趋势完全一致。这个精度对于家庭日常监测来说已经足够。如果你测出来偏差特别大,先别怀疑传感器,检查一下设备是不是放在了空气滞留区,或者传感器进气口是不是被灰尘堵住了。

5. 常见问题与实操心得

5.1 问题速查表

按照我这个方案搭建,最可能遇到的是以下四类问题,我把排查思路整理成一个速查表:

现象可能原因排查方法
I2C 扫描不到 SEN55SEL 引脚未拉低,处于 UART 模式确认 SEL 接 GND,重启设备
I2C 扫描不到 SCD40供电电压不足测量 VIN 对地电压是否稳定 3.3V
传感器数据始终为 0上电初始化顺序不对,传感器未就绪增加启动延时,或改用手动上电
PM2.5 数值异常偏高传感器进气口堵塞或传感器受潮检查传感器表面,必要时用无水酒精清洁
CO2 数值长期不降房间密闭、通风不足,或传感器基准偏移开窗通风后观察 30 分钟,若仍异常则手动校准

5.2 我踩过的三个比较典型的坑

坑一是烧录时传感器不吃电。我用的是面包板供电,烧录程序时 ESP32 会断开一部分 GPIO 的输出,导致传感器瞬间掉电再上电,程序开始运行后传感器还在启动中,I2C 通信失败。这个是硬件设计层面的问题,不是代码 bug。我的解决方法是给传感器单独加了一个带电容的电源滤波模块,确保在 USB 供电波动时也能维持稳定的电压输出。

坑二是内存堆栈溢出导致死机。SEN55 官方库在频繁调用readMeasuredValues()时,会动态分配内存。如果 Arduino 默认的堆栈设置不够大,长时间运行后系统会崩溃重启。我通过 Arduino IDE 的EspExceptionDecoder工具分析了崩溃日志,发现是堆栈溢出,把loopTaskStackSize从默认的 8192 调整到 16384 后问题解决。这个参数在menuconfig或者Arduino-ESP32的编译选项里都可以改,新手容易一头雾水,搜“ESP32 loopTaskStackSize 调整”就能找到具体步骤。

坑三是让传感器一直通电导致的寿命损耗。空气监测是需要长期运行的设备,但让传感器 7x24 小时不间断工作,风扇一直转,寿命会快速衰减。PMS 系列传感器的风扇设计寿命一般在 3-5 年,但如果你家 PM2.5 浓度高,风扇负担大,寿命更短。我最后加了一个简单的“每小时工作 55 分钟,休息 5 分钟”的调度逻辑,牺牲了极小的采样连续性,换来了更长的维护周期。

5.3 对 Part 2 的扩展规划

Part 1 到这里,一个可靠的本地空气质量监测节点算是完成了。它现在能自证数据可信,能实时显示,能通过串口输出数据。但单机运行的监测节点只解决了“看到数据”的问题,离我最初设想的“改善空气”还差得远。

Part 2 我会做几件事:

第一,把数据通过 MQTT 协议上报到本地 Home Assistant,实现手机端远程查看,同时把历史数据存入 InfluxDB,用 Grafana 画趋势图。这样就能回答“过去一周室内 CO2 有没有超标”“下雨天 PM2.5 会不会升高等”这类时间维度的问题。

第二,做联动控制。通过自动化规则,当 CO2 超过 1000ppm 时自动打开新风系统,PM2.5 超过 75µg/m³ 时自动启动空气净化器。这才是监测的最终价值所在——让数据驱动设备,而不是人肉看屏幕再手动操作。

第三,如果家里面积大,可以做多节点布点,把卧室、客厅、厨房分别放一个监测设备,汇总到一个总控界面。Part 1 的设备直接复用,不需要重新设计硬件,只需要在软件层面增加上报功能即可。

说实话,做完这台设备之后我最大的感受是:空气净化器和新风系统不是“买了就是赚了”,装在哪、什么时候开、开多久,完全依赖监测数据才能做出合理决定。以前我习惯性开着净化器,现在看到 PM2.5 在 5µg/m³ 以下就果断关掉,既省电又避免滤芯浪费;以前从不开窗通风,现在一看到 CO2 突破 900ppm 就立刻开窗,整个人的精神状态都好了不少。这套系统的价值,远不止“看个数字”这么简单。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询