💡 划重点
- 用 SCD41 实时感知书桌 CO₂、温度与湿度,把看不见的空气质量变成灯光语言。
- ESP32-C3 做主控,蓝牙 BLE 把浓度推送到手机,无需 Wi-Fi 也能看数据。
- WS2812 灯环随 CO₂ 变色:绿光专注、黄光提醒、红光呼吸,按键一键静音。
- 整机成本约 105 元,3D 打印或亚克力灯罩即可落地,适合放在显示器旁或书架夹层。
需求洞察
目标用户是备考学生、居家办公者和长时间伏案写代码的人。真实痛点很具体:门窗紧闭的房间里,人越坐越困,却总以为是“自己不够自律”。实际上,室内 CO₂ 浓度超过 1000 ppm 后,认知表现和警觉度会明显下降;超过 1500 ppm 时,头痛、嗜睡、注意力涣散接踵而来。传统台灯只负责照明,不负责提醒你“该开窗了”。这个项目值得做,因为它把环境数据变成即时、无感的灯光反馈,不打断学习节奏,却能帮你守住专注力。
方案设计
感知层:SCD41 通过 I2C 每 5 秒读取 CO₂、温度和湿度,精度 ±(30 ppm + 3%),适合桌面场景。
控制层:ESP32-C3 运行阈值状态机,把 CO₂ 分为三段——低于 800 ppm 为绿光,800 至 1200 ppm 为黄光,高于 1200 ppm 为红光呼吸。按键用于切换“常亮/静音/夜灯”模式。
执行层:WS2812 灯环 12 颗灯珠,颜色和亮度同步变化;红光时以 2 秒周期呼吸,避免刺眼。
日志/联网层:蓝牙 BLE 广播 CO₂ 数值,手机端可用 nRF Connect 或自写 App 查看;串口同时输出日志,方便调试和长期记录。
物料清单
| 物料 | 数量 | 用途 | 估算单价 | 合计 |
|---|---|---|---|---|
| ESP32-C3 开发板 | 1 | 主控与蓝牙 | 15 元 | 15 元 |
| SCD41 模块 | 1 | CO₂/温湿度感知 | 60 元 | 60 元 |
| WS2812 灯环 12 位 | 1 | 灯光反馈 | 8 元 | 8 元 |
| 轻触按键 | 1 | 模式切换 | 0.5 元 | 0.5 元 |
| 灯罩/外壳 | 1 | 结构件 | 12 元 | 12 元 |
| USB 数据线+电源 | 1 | 供电与调试 | 5 元 | 5 元 |
| 杜邦线/洞洞板/电阻 | 若干 | 连接与保护 | 5 元 | 5 元 |
| 合计 | 105.5 元 |
总成本约 105.5 元,低于 120 元目标。若已有开发板和线材,实际支出可压到 80 元以内。
接线与结构
SCD41 接 3.3 V 和 GND,SDA 接 GPIO8,SCL 接 GPIO9。WS2812 的 DIN 接 GPIO10,5 V 和 GND 分别接电源;数据线串 330 Ω 电阻,电源并 1000 µF 电容。按键一端接 GPIO3,另一端接 GND,启用内部上拉。结构上,灯环套在灯罩顶部,SCD41 从底座侧面开孔伸出,ESP32-C3 藏入底座,按键放在正面。若 WS2812 用 5 V 供电且高电平不足,可改为 3.3 V 供电或加电平转换;GPIO 保持不变,便于代码统一。
核心代码
以下为 Arduino 骨架,基于 ESP32-C3,可编译上传。
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <SensirionI2CScd4x.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
SensirionI2CScd4x scd4x;
Adafruit_NeoPixel strip(12, 10, NEO_GRB + NEO_KHZ800);
const int buttonPin = 3;
int mode = 0;
unsigned long lastRead = 0;
BLECharacteristic *pChar;
void setup() {
Serial.begin(115200);
Wire.begin(8, 9);
scd4x.begin(Wire);
strip.begin();
strip.show();
BLEDevice::init("CO2_Lamp");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService("0000180f-0000-1000-8000-00805f9b34fb");
pChar = pService->createCharacteristic(
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pChar->addDescriptor(new BLE2902());
pService->start();
BLEAdvertising *pAdv = BLEDevice::getAdvertising();
pAdv->addServiceUUID(pService->getUUID());
pAdv->start();
}
void loop() {
if (digitalRead(buttonPin) == LOW) {
delay(50);
if (digitalRead(buttonPin) == LOW) {
mode = (mode + 1) % 3;
while (digitalRead(buttonPin) == LOW);
}
}
if (millis() - lastRead > 5000) {
lastRead = millis();
uint16_t co2;
float temperature, humidity;
if (co2 == 0) return;
String msg = "CO2=" + String(co2);
pChar->setValue(msg.c_str());
pChar->notify();
updateLED(co2);
}
}
void updateLED(uint16_t co2) {
if (mode == 1) { strip.clear(); strip.show(); return; }
uint32_t color;
if (co2 < 800) color = strip.Color(0, 80, 0);
else if (co2 < 1200) color = strip.Color(80, 80, 0);
else color = strip.Color(80, 0, 0);
for (int i = 0; i < strip.numPixels(); i++) strip.setPixelColor(i, color);
strip.setBrightness(80);
strip.show();
}
调试步骤
- 用 I2C 扫描确认 SCD41 地址为 0x62,若未识别检查 GPIO8/9 接线。
- 首次上电让 SCD41 预热 3 分钟,必要时执行强制校准。
- 单独测试 WS2812:点亮红、绿、蓝,确认数据方向正确。
- 测试按键消抖,观察模式切换是否稳定。
- 用塑料袋罩住传感器并呼气,验证 CO₂ 上升时灯环变红。
- 手机打开 BLE 调试助手,确认能收到 CO2 通知。
- 连续运行 2 小时,检查温漂和日志稳定性。