news 2026/5/17 6:54:02

基于ESP32-S2与CircuitPython的智能烟雾净化器DIY全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于ESP32-S2与CircuitPython的智能烟雾净化器DIY全攻略

1. 项目概述:打造你的智能桌面空气卫士

在电子工作台前长时间焊接,或是进行3D打印、激光雕刻等操作时,产生的烟雾和挥发性有机物(VOCs)是每个创客和工程师都避不开的烦恼。传统的烟雾净化器要么笨重昂贵,要么功能单一,无法与我们的智能工作流相结合。今天,我想分享一个我最近完成并觉得非常实用的DIY项目:一个基于ESP32-S2与CircuitPython的智能烟雾净化器。它不仅仅是一个风扇,更是一个集成了实时空气质量监测、自适应风速调节和云端数据可视化的物联网(IoT)设备。

这个项目的核心在于利用Adafruit的FunHouse开发板(内置ESP32-S2)作为大脑,通过CircuitPython这一对开发者极其友好的语言进行编程。系统通过SGP30传感器精准监测空气中的总挥发性有机物(TVOC)和等效二氧化碳(eCO2)浓度,然后通过EMC2101风扇控制器动态调节一个140mm的PWM风扇转速。当检测到烟雾或污染物浓度升高时,风扇自动加速,快速净化空气;浓度降低后,风扇则恢复低速静音运行,实现节能与降噪。所有数据还能通过Wi-Fi上传到Adafruit IO平台,让你在手机或电脑上就能远程查看工作环境的空气质量历史曲线。

对于嵌入式开发者和硬件爱好者而言,这个项目是一个绝佳的练手机会。它涵盖了从硬件选型、3D打印结构设计、电路焊接、传感器驱动、PWM控制到物联网云服务集成的完整流程。更重要的是,CircuitPython的交互式特性和丰富的库支持,使得开发和调试过程变得异常简单,即使你是嵌入式新手,也能跟着一步步实现。下面,我将从设计思路、硬件搭建、代码解析到实际调试中的坑点,为你完整拆解这个智能烟雾净化器的制作过程。

2. 核心硬件选型与设计思路解析

2.1 主控板:为什么选择Adafruit FunHouse?

在这个项目中,主控板的选择至关重要,它需要具备足够的计算能力、丰富的接口、易于编程的环境以及稳定的无线连接。我最终选择了Adafruit FunHouse,原因有以下几点:

首先,ESP32-S2芯片提供了完美的平衡。它拥有单核240MHz的Xtensa处理器,性能足以流畅运行CircuitPython并处理传感器数据;集成的Wi-Fi模块让我们无需额外模块就能连接网络;其低功耗特性也适合设备长期插电运行。其次,FunHouse的板载设计极大简化了外围电路。它自带一个240x240的彩色TFT显示屏和三个物理按键,这为我们实现本地交互(显示数据、选择模式)省去了大量接线和驱动工作。板上的STEMMA QT连接器更是“神器”,采用防反插的JST SH 4Pin接口,让连接I2C传感器(如SGP30、EMC2101)变得像拼积木一样简单,避免了焊接错误的风险。

最后,也是最重要的一点,对CircuitPython的极致支持。Adafruit为FunHouse提供了深度优化的CircuitPython固件和库。这意味着我们可以直接通过USB线连接电脑,在出现的CIRCUITPY磁盘中像编辑文本文件一样修改code.py,代码保存后自动重启运行,配合串行REPL(交互式解释器)实时调试,开发体验远超传统的“编译-烧录-调试”循环。这种快速迭代的能力,对于需要不断调整参数(如风扇响应曲线、数据上传频率)的项目来说,效率提升是巨大的。

2.2 传感器与执行器:精准感知与高效响应的组合

系统的感知核心是SGP30空气质量传感器。这是一款基于金属氧化物(MOX)技术的数字气体传感器,专门用于检测TVOC和eCO2。我选择它而非更便宜的模拟传感器,是因为其内置的校准算法和温度补偿能提供更稳定、可靠的读数,并且它直接输出经过处理的数字值(单位是ppb和ppm),省去了我们进行复杂模拟信号处理和校准的麻烦。它的I2C接口也完美契合STEMMA QT生态系统。

执行机构方面,我采用了**“一大一小”双风扇方案**。主风扇是一个140mm的Noctua PWM风扇,以其出色的风量、静音效果和耐用性著称。通过PWM信号控制其转速,可以在10%到100%之间无级调速。小风扇则是一个普通的5V微型风扇,它的作用很关键:被安装在SGP30传感器正前方,持续将周围的空气“推”向传感器气孔,确保传感器读取到的是实时、流动的空气样本,而不是设备内部停滞的空气,从而大幅提升监测的响应速度和准确性。

连接这两者的桥梁是EMC2101风扇控制器。这是一个通过I2C控制的PWM风扇驱动芯片。为什么不直接用ESP32-S2的PWM引脚驱动风扇?原因有三:一是驱动能力,ESP32-S2的GPIO引脚驱动电流有限,无法直接驱动大功率风扇;二是精度,EMC2101能提供更精细的PWM控制;三是功能扩展,EMC2101本身还带有一个温度传感器,未来可以扩展为根据设备内部温度来辅助控制风扇,增加一层保护逻辑。

2.3 结构设计与物联网架构

为了让所有部件整洁有序地工作,我设计了3D打印的外壳。结构分为前盖、后盖、内部框架和多个安装支架。后盖固定140mm主风扇和进风滤网;前盖嵌入活性炭过滤棉,用于吸附烟雾中的颗粒和异味;内部框架则承载FunHouse主板、EMC2101板和传感器支架。这种模块化设计使得组装、维修和升级都非常方便。

整个系统的数据流和控制逻辑清晰明了,形成了一个完整的物联网闭环:

  1. 感知层:SGP30持续监测空气。
  2. 决策层:FunHouse上的CircuitPython程序读取传感器数据,通过一个map_range函数将其映射为风扇目标转速百分比。
  3. 执行层:FunHouse通过I2C向EMC2101发送指令,EMC2101输出对应的PWM信号驱动风扇。
  4. 显示与交互层:本地TFT屏幕实时显示浓度和转速,三个按钮用于选择是否连接Wi-Fi及上传数据。
  5. 云平台层:数据通过Wi-Fi定期发送至Adafruit IO,生成可视化图表,实现远程监控。

这个架构的优势在于本地闭环控制保证了实时性(即使断网,净化功能照常工作),而云端连接则提供了数据记录和远程观察能力,两者互补,非常实用。

3. 硬件组装与接线全攻略

3.1 元器件清单与准备

开始动手前,请确保你备齐了所有零件。除了项目核心的几大件,一些小配件同样关键:

  • 主控与传感
    • Adafruit FunHouse (ESP32-S2) x1
    • Adafruit SGP30 空气质量传感器 x1
    • Adafruit EMC2101 风扇控制器 x1
  • 执行机构
    • Noctua NF-P14s redux-1200 PWM (140mm) 风扇 x1
    • 5V 微型风扇 (30x30mm或类似) x1
  • 结构件
    • 3D打印外壳一套(包括前盖、后盖、框架、风扇格栅、传感器支架等)
    • M3螺丝/螺母/尼龙柱套装
    • M2.5螺丝/螺母套装
    • 活性炭过滤棉 (适配前盖尺寸)
  • 连接线材
    • STEMMA QT / Qwiic 4芯电缆 (100mm) x1:连接FunHouse与EMC2101。
    • STEMMA QT / Qwiic 4芯电缆 (200mm) x1:连接EMC2101与SGP30。
    • 4芯排线 (约100mm):用于延长Noctua风扇线。
    • 2芯排线 (约110mm):用于连接微型风扇。
    • 3Pin JST SH端子转杜邦线(或直接使用带端子的线):用于将风扇连接到FunHouse的端口。
  • 工具:电烙铁、焊锡、热缩管、剥线钳、螺丝刀、剪线钳。

注意:在焊接任何线缆前,务必先穿好热缩管!这是一个看似简单却极易被遗忘,而后悔莫及的步骤。我习惯在工作台贴个便签提醒自己“先穿管,后焊接”。

3.2 风扇线缆改造详解

Noctua风扇和微型风扇的原装线缆通常不适合直接连接到我们的系统,需要进行定制化改造。

对于Noctua PWM风扇(4线制): 标准的4线分别是:黑色(GND)黄色(+12V)绿色(测速TACH)蓝色(PWM控制)。我们的目标是将其接入EMC2101控制器和FunHouse的5V电源。

  1. 裁剪与延长:将风扇原线剪短至约5cm,焊接上约10cm长的4芯排线。务必做好颜色对应或做好标签(如:黑-黑,黄-红,绿-绿,蓝-蓝)。
  2. 制作接口:延长线的另一端,需要制作成可以连接到EMC2101和FunHouse A0端口的形式。你需要将**黑线(GND)红线(经过改造的+5V)合并接入一个3Pin JST端子(对应FunHouse A0端口的GND和5V)。而绿线(TACH)蓝线(PWM)**则分别焊接至另一个接插件的对应引脚,用于连接EMC2101的TACH和FAN引脚。
  3. 电压匹配:这是关键!Noctua风扇标称12V,但实际在5V下也能启动并低速运行,这对于我们的吸烟场景通常足够,且噪音更小。如果你需要最大风量,可以考虑通过外部12V电源供电,但需要修改电路设计。本项目采用5V驱动简化设计。

对于5V微型风扇(2线制): 这个简单很多。通常红线为正极(+5V),黑线为负极(GND)。用一段2芯排线延长后,另一端焊接上一个2Pin或3Pin的JST端子,用于连接FunHouse的A1端口(5V和GND)。

实操心得:焊接风扇线时,由于线材较细且可能含有多股漆包线,建议先给线头上锡。焊接完成后,用万用表通断档仔细检查每一条线路,确保没有虚焊、短路,特别是电源正负极绝对不能接反,否则可能损坏控制器或风扇。

3.3 3D打印与机械组装

所有结构件的STL文件可以从项目源地址下载。使用PLA材料打印即可,无需支撑。

  • 打印参数建议

    • 层高:0.2mm
    • 填充率:10%-15%(Gyroid填充模式在强度和耗材间取得良好平衡)
    • 打印温度:按你使用的PLA规格,通常210-220°C
    • 热床:60°C
    • 特别提示——风扇格栅:这个部件利用了切片软件的“纯填充”技巧。在切片时,将顶面/底面层数设置为0,选择你喜欢的填充图案(如线条、网格、Gyroid),设置10%-20%的填充密度。这样打印出来的就是一个网状格栅,既美观又能有效防止异物进入。
  • 组装顺序

    1. 后盖与主风扇:使用M4螺丝(通常风扇自带)或M3螺丝配合螺母,将140mm风扇固定在后盖内部。注意风扇方向,确保风向是向机箱内吹风(将空气从后部吸入,经过设备从前部排出)。
    2. 内部框架:将PCB安装板用M3螺丝和尼龙柱固定在内部框架上。
    3. 传感器模块:将SGP30传感器用M2.5螺丝固定在传感器支架中心。然后将微型风扇用螺丝固定在支架上,使其出风口正对传感器进气孔。最后将这个整体用M3螺丝安装到前盖内侧。
    4. 电路集成:将EMC2101板用M2.5螺丝固定在PCB安装板上。然后,将FunHouse主板对齐安装孔,用M3螺丝固定。
    5. 线缆连接
      • 用100mm STEMMA线连接FunHouse的STEMMA端口与EMC2101的STEMMA端口。
      • 用200mm STEMMA线连接EMC2101的另一个STEMMA端口与SGP30传感器。
      • 将改造好的Noctua风扇线缆:电源线(红、黑)插入FunHouse的A0端口(注意引脚对应),控制线(蓝、绿)插入EMC2101的对应FAN和TACH引脚。
      • 将微型风扇的JST端子插入FunHouse的A1端口。
    6. 总装:将活性炭过滤棉放入前盖的卡槽。先将内部框架组件与后盖组件扣合,再将前盖组件扣合到框架上。通常设计为卡扣式,无需螺丝,方便日后更换滤棉。

组装完成后,检查所有连接是否牢固,线缆是否整齐,避免被风扇叶片刮到。

4. CircuitPython环境配置与项目代码深度解析

4.1 固件烧录与开发环境搭建

FunHouse到手后,第一步是刷入CircuitPython固件。

  1. 获取固件:访问CircuitPython官网,找到Adafruit FunHouse的页面,下载最新的.uf2.bin文件。.uf2方式最简单。
  2. 进入Bootloader模式:用一根数据线(确保不是充电线)连接FunHouse和电脑。快速双击主板上的Reset按钮。此时,电脑上会出现一个名为HOUSEBOOT的U盘。
  3. 拖放烧录:将下载好的.uf2文件直接拖入HOUSEBOOT盘符。完成后,设备会自动重启,出现一个名为CIRCUITPY的新盘符,这表明CircuitPython系统已成功运行。
  4. 安装库文件:项目依赖于多个库。最简单的方法是下载项目的“项目包”(Project Bundle),它包含了所有必要的库和code.py。解压后,将lib文件夹内的所有.mpy文件复制到CIRCUITPY盘符下的lib目录中(如果没有就新建一个)。同时,将项目包中的code.py.bmp位图文件和字体文件复制到CIRCUITPY盘的根目录。

4.2 代码结构与核心逻辑剖析

项目的核心代码在code.py中。我们分段来理解其精妙之处。

初始化与硬件设置

import time import board import simpleio import adafruit_sgp30 import displayio import adafruit_imageload from adafruit_emc2101 import EMC2101 from adafruit_funhouse import FunHouse i2c = board.I2C() # 初始化I2C总线 sgp30 = adafruit_sgp30.Adafruit_SGP30(i2c) # 初始化SGP30传感器 emc = EMC2101(i2c) # 初始化EMC2101风扇控制器 funhouse = FunHouse(default_bg=0x0F0F00) # 初始化FunHouse对象,设置默认背景色

代码开头导入所有必需的库。board.I2C()会自动选择硬件I2C引脚。通过adafruit_funhouse库,我们可以用非常高级的抽象来控制显示屏、按钮和网络,极大简化了代码。

状态机与用户界面: 这是本项目代码设计的亮点。它没有使用复杂的多线程或异步,而是用一个简单的状态机(State Machine)通过几个布尔变量(run,connected,start_up)和按钮事件来管理复杂的流程(启动、连接网络、主循环)。

run = False # 主程序是否运行 connected = False # 是否已连接Wi-Fi并上传数据 start_up = False # 是否处于启动连接过程 clock = 0 # 用于定时发送数据的计时器

程序启动后,显示一个启动画面。用户按下中间按钮(Select),则尝试连接Wi-Fi,显示“连接中”画面;按下下按钮(Down),则跳过Wi-Fi连接,直接进入主程序。这种设计给了用户灵活的选择权。

核心控制算法——数据映射: 智能调节的核心在于将传感器读数映射为风扇转速。这里使用了simpleio.map_range()函数。

# 使用TVOC读数 (范围假设为10-1000 ppb) 映射到风扇转速百分比 (10-100%) fumes = sgp30.TVOC mapped_val = simpleio.map_range(fumes, 10, 1000, 10, 100) # 如果使用eCO2读数 (范围假设为400-2500 ppm) # fumes = sgp30.eCO2 # mapped_val = simpleio.map_range(fumes, 400, 2500, 10, 100) emc.manual_fan_speed = int(mapped_val) # 设置风扇转速

这里的映射范围(10-1000, 400-2500)是需要根据你的实际环境校准的关键参数!在非常洁净的空气中,SGP30的TVOC基线值可能在0-50 ppb,而在焊接烟雾附近可能飙升到500 ppb以上。你需要观察REPL(串口)打印的数值,调整映射的输入范围,使得风扇在空气良好时低速安静运行,在检测到烟雾时能迅速提升到一个有效的净化转速。

网络连接与数据上传: 连接Wi-Fi的功能被封装在funhouse.network.connect()中,需要在settings.toml文件中预先配置好你的Wi-Fi SSID和密码。数据上传则通过两个函数实现:

def send_fume_data(solder_fumes): funhouse.network.push_to_io("fumes", solder_fumes) def send_fan_data(fan_rpm): funhouse.network.push_to_io("fan-speed", fan_rpm)

在主循环中,通过检查connected状态和clock计时器,每15秒调用一次这些函数,将数据推送到Adafruit IO上名为fumesfan-speed的Feed中。

4.3 Adafruit IO云端仪表盘配置

硬件和代码就绪后,我们需要在云端创建一个数据接收和展示的界面。

  1. 创建Feeds(数据流):登录Adafruit IO,在“Feeds”页面创建两个新的Feed,名称必须与代码中的push_to_io函数调用一致,即fumesfan-speed
  2. 创建Dashboard(仪表盘):在“Dashboards”页面创建一个新的仪表盘,例如命名为“Workspace Air Quality”。
  3. 添加图表块:进入刚创建的仪表盘,点击“+”号或设置图标创建新块(Block)。选择“Line Chart”(折线图)。在配置页面,勾选上一步创建的fumesfan-speedFeed(可以创建两个独立的图表块,也可以在一个图表中显示两条线)。设置好图表标题、坐标轴标签等。
  4. 获取密钥:在Adafruit IO的“IO Key”页面,你可以找到你的用户名(Username)和活跃密钥(Active Key)。这些信息需要填入FunHouse的settings.toml配置文件,设备才能被授权上传数据。

完成这些步骤后,启动设备并连接网络,你就能在Adafruit IO的仪表盘上看到实时更新的空气质量与风扇转速曲线了。这种可视化让你能清晰地了解设备的工作状态和历史趋势。

5. 调试心得、常见问题与优化建议

5.1 上电调试与问题排查

组装并烧录程序后,第一次上电可能会遇到一些问题。以下是一个系统的排查清单:

现象可能原因排查步骤与解决方案
FunHouse无反应,CIRCUITPY盘未出现1. USB线仅为充电线。
2. 固件未正确烧录。
3. 主板损坏。
1. 更换为确认可传输数据的USB线。
2. 重新进入Bootloader模式(双击Reset),检查HOUSEBOOT盘是否出现,重新拖入.uf2文件。
3. 尝试另一台电脑或USB端口。
屏幕亮但无显示/花屏1. 显示库或图形文件缺失。
2. 代码中图形初始化错误。
1. 检查CIRCUITPY盘根目录下是否有scene1_fume.bmp等位图文件。
2. 通过串口REPL(如Mu编辑器、Thonny)查看是否有Python错误输出。
传感器读数始终为0或异常1. I2C接线错误或接触不良。
2. 传感器损坏。
3. 库文件版本不匹配。
1. 检查STEMMA QT线缆是否插紧,确认连接顺序为 FunHouse -> EMC2101 -> SGP30。
2. 在REPL中手动输入import board; i2c=board.I2C(); i2c.scan()查看I2C地址是否被识别(SGP30地址0x58,EMC2101地址0x4C)。
3. 确保使用的adafruit_sgp30库是最新版。
风扇不转1. 电源线接反或未接。
2. PWM控制信号问题。
3. 风扇最低启动电压不足。
1. 用万用表测量连接器是否有5V输出。
2. 检查代码中emc.manual_fan_speed是否被成功赋值(在REPL中打印mapped_val)。
3. 尝试将映射的最小输出值从10%提高到20%或30%。某些风扇在极低占空比下无法启动。
无法连接Wi-Fi1.settings.toml配置错误。
2. 网络环境问题(如2.4G/5G频段)。
3. 路由器屏蔽了新设备。
1. 仔细检查CIRCUITPY盘下的settings.toml文件,确保CIRCUITPY_WIFI_SSIDCIRCUITPY_WIFI_PASSWORD填写正确(注意大小写和特殊字符)。
2. ESP32-S2通常只支持2.4GHz Wi-Fi,请确保连接的是2.4GHz网络。
3. 重启路由器,或在路由器后台查看是否有新设备被拦截。
数据无法上传到Adafruit IO1. Adafruit IO Feed名称不匹配。
2. IO密钥错误或配额超限。
3. 网络连接不稳定。
1. 确认代码中push_to_io的第一个参数与IO上创建的Feed名称完全一致(包括大小写)。
2. 检查settings.toml中的CIRCUITPY_AIO_USERNAMECIRCUITPY_AIO_KEY
3. 在REPL中查看打印的“data sent”信息是否出现,以及是否有连接错误提示。

5.2 性能调优与功能扩展建议

基础功能运行稳定后,你可以考虑以下优化和扩展,让这个项目更贴合你的个人需求:

  1. 动态基线校准:SGP30传感器需要12小时以上的稳定运行才能建立准确的基线。代码中写死了一个基线值(0x8973, 0x8AAE),这是不准确的。你应该在空气洁净的环境中,让设备通电运行至少12小时,然后从REPL中读取sgp30.baseline_eCO2sgp30.baseline_TVOC的值,并更新到set_iaq_baseline函数中。更高级的做法是定期将基线值保存到FunHouse的存储中,断电后重新加载。

  2. 控制算法优化:当前的线性映射map_range虽然简单,但可能不是最优的。例如,可以引入一个“死区”阈值,当TVOC低于某个值(如50ppb)时,风扇保持最低速或关闭;当超过阈值后,再按比例或阶梯式增加转速。这可以减少风扇在临界值附近的频繁启停。你还可以尝试加入简单的PID控制,让风扇转速的变化更平滑。

  3. 增加本地报警功能:利用FunHouse板载的RGB LED(DotStar)或蜂鸣器(如果有)。当检测到污染物浓度超过安全阈值时,让LED闪烁红光或发出提示音,提供更直接的本地反馈。

  4. 集成更多传感器:FunHouse还有多余的GPIO和ADC引脚。你可以考虑添加一个温湿度传感器(如SHT40),同时监测环境舒适度;或者添加一个激光粉尘传感器(如PMS5003),监测PM2.5/PM10颗粒物。在代码中融合多传感器数据,制定更复杂的净化策略。

  5. 降低功耗与离线存储:如果你希望它用电池供电,需要深入优化。可以在监测到长时间无污染时,让ESP32-S2进入深度睡眠模式,定时唤醒检测。同时,可以将传感器数据先保存到本地文件(如CSV格式),等连接Wi-Fi后再批量上传到云端,避免数据丢失。

这个项目就像一个乐高底座,核心的物联网框架和硬件交互已经搭建完成。剩下的,就看你如何发挥创意,用它来解决你工作环境中遇到的实际问题了。从我的体验来看,最大的成就感不仅在于它成功运转,更在于它实实在在地改善了工作台边的空气,并且整个过程充满了学习和探索的乐趣。希望这份详细的拆解能帮助你顺利复现并创造出属于你自己的智能空气净化方案。

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

Awesome-GPTs:社区驱动的GPTs精品导航与高效使用指南

1. 项目概述:为什么我们需要一个“Awesome-GPTs”?如果你最近也在捣鼓GPTs,或者想找一个特定功能的GPT来帮你解决工作、学习中的某个具体问题,那你大概率和我一样,经历过一段“大海捞针”的时光。OpenAI的GPT商店&…

作者头像 李华
网站建设 2026/5/17 6:39:28

从零构建GitHub Pages静态博客:Jekyll实战与自动化部署指南

1. 项目概述:一个静态博客的诞生与演进 “RyansGhost/RyansGhost.github.io”,这个看似简单的GitHub仓库名,背后是一个典型的个人开发者从零开始构建、部署并持续维护一个静态博客的完整故事。它不是一个复杂的商业系统,但对于任…

作者头像 李华
网站建设 2026/5/17 6:35:48

AI编程助手安全规则实战:从SQL注入防御到团队安全基线构建

1. 项目概述:当AI编程助手遇上安全红线最近在GitHub上看到一个挺有意思的项目,叫“cursor-security-rules”。光看名字,你大概能猜到它和Cursor这个AI编程工具有关,而且重点是“安全规则”。没错,这个项目本质上是一个…

作者头像 李华
网站建设 2026/5/17 6:33:50

Python自动化股票分析工具:从数据采集到可视化报告全流程实战

1. 项目概述:一个面向个人投资者的自动化股票分析工具如果你和我一样,是个对A股市场有点兴趣,但又没时间天天盯盘的上班族,那你肯定也经历过这种纠结:早上开盘前想看看心仪的几只股票有没有什么异动,结果一…

作者头像 李华