💡 划重点

  • 用 ESP32-S3 搭配 INMP441 数字麦克风,在卧室里实时采集呼吸声与鼾声;通过 FFT 提取低频能量,驱动 WS2812 灯环做柔光渐变。呼吸平稳时灯光缓慢呼吸,鼾声出现时灯光轻微增亮提醒,同时可经 Wi-Fi 上报日志。整套物料控制在 90 元内,适合床头低侵入部署。

需求洞察

目标用户是关注睡眠质量的普通人、轻度打鼾者、以及被伴侣鼾声影响的同睡者。真实痛点有三个:一是普通夜灯只能照明,无法感知睡眠状态;二是半夜醒来开灯刺眼,重新入睡困难;三是手机睡眠监测应用需要整晚录音,隐私感差且耗电。这个项目值得做,是因为它把“呼吸声”变成一种非接触式信号,不需要穿戴设备,也不直接诊断疾病,只用柔光反馈和本地日志帮助用户感知睡眠节奏。对老人卧室或婴儿房,也能作为呼吸活动提示的轻量辅助。

方案设计

感知层:INMP441 以 I2S 输出 24 位数字音频,避免模拟麦克风在卧室长线下的底噪。采样率设为 16 kHz,每帧 512 点,覆盖 50 到 500 Hz 的呼吸与鼾声主频段。

控制层:ESP32-S3 负责 I2S 读取、FFT 计算、能量平滑和阈值判断。低频段能量均值经过一阶低通滤波,避免单次翻身或环境噪声误触发。

执行层:WS2812 灯环使用暖白到淡蓝的柔光渐变。呼吸平稳时亮度低、色温暖;鼾声能量升高时,灯光在 1 秒内轻微增亮,随后缓慢回落,不突然闪烁。

日志与联网层:串口输出能量值用于调试;Wi-Fi 开启后可按分钟聚合,通过 MQTT 或 HTTP 上报到本地服务器。若不需要联网,可仅保留本地灯效,降低隐私顾虑。

物料清单

物料 数量 用途 估算单价 合计
ESP32-S3 开发板 1 主控与 Wi-Fi 32 元 32 元
INMP441 麦克风模块 1 呼吸声采集 10 元 10 元
WS2812B 灯环 12 位 1 柔光反馈 12 元 12 元
5V 电源与 USB 线 1 供电 10 元 10 元
杜邦线、洞洞板 1 套 接线与固定 8 元 8 元
磨砂柔光罩/外壳 1 遮光与扩散 10 元 10 元
合计 82 元

接线与结构

INMP441 与 ESP32-S3 按给定引脚连接:SCK=4,SD=5,WS=6。模块 VDD 接 3.3V,GND 接地,L/R 接 GND 选择左声道。WS2812 数据引脚接 GPIO 10,5V 供电,GND 共地。若灯环较远,数据线串 330Ω 电阻,电源端并 1000µF 电容。结构上,麦克风朝床铺方向开小孔,灯环藏在磨砂罩内,避免直射眼睛。ESP32-S3 放在床头塑料盒中,USB 供电即可。

核心代码

以下为 Arduino 骨架,依赖 driver/i2s.h、arduinoFFT、Adafruit_NeoPixel。


#include <Arduino.h>
#include <driver/i2s.h>
#include <arduinoFFT.h>
#include <Adafruit_NeoPixel.h>

#define I2S_SCK 4
#define I2S_SD  5
#define I2S_WS  6
#define LED_PIN 10
#define LED_COUNT 12
#define SAMPLE_RATE 16000
#define FFT_SIZE 512

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
ArduinoFFT FFT = ArduinoFFT();
double vReal[FFT_SIZE];
double vImag[FFT_SIZE];

void setup() {
  Serial.begin(115200);
  strip.begin();
  strip.show();

  i2s_config_t cfg = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 4,
    .dma_buf_len = 256,
    .use_apll = false
  };
  i2s_driver_install(I2S_NUM_0, &cfg;, 0, NULL);
  i2s_pin_config_t pin = {
    .bck_io_num = I2S_SCK,
    .ws_io_num = I2S_WS,
    .data_out_num = I2S_PIN_NO_CHANGE,
    .data_in_num = I2S_SD
  };
  i2s_set_pin(I2S_NUM_0, &pin;);
}

void loop() {
  for (int i = 0; i < FFT_SIZE; i++) {
    int32_t sample = 0;
    size_t bytesRead = 0;
    i2s_read(I2S_NUM_0, &sample;, sizeof(sample), &bytesRead;, portMAX_DELAY);
    vReal[i] = (double)(sample >> 8);
    vImag[i] = 0;
  }

  double energy = 0;
  for (int i = 1; i < 40; i++) energy += vReal[i];
  energy /= 39.0;

  static double smooth = 0;
  smooth = smooth * 0.8 + energy * 0.2;
  int brightness = constrain(map((long)smooth, 200, 3000, 8, 160), 8, 160);

  for (int i = 0; i < LED_COUNT; i++) {
    uint8_t r = brightness * 0.65;
    uint8_t g = brightness * 0.50;
    uint8_t b = brightness * 0.30 + (brightness * i / LED_COUNT) * 0.15;
  }
  strip.show();

  Serial.println(smooth);
  delay(10);
}

调试步骤

第一步,只烧录 I2S 读取代码,串口观察是否有原始数据,确认 SCK、WS、SD 接对。第二步,加入 FFT 并打印低频能量,安静卧室下记录基线值。第三步,对着麦克风轻声呼吸和模拟鼾声,观察能量峰值,把阈值设在基线 2 到 3 倍处。第四步,调节灯环亮度和渐变速度,确保不刺眼。第五步,连续运行一晚,检查是否因翻身、空调声误触发。第六步,装上磨砂罩后重新校准,因为外壳会衰减高频并改变麦克风灵敏度。

设计图

睡眠呼吸声监测夜灯结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报