本帖最后由 PY学习笔记 于 2026-6-2 09:07 编辑
首先,感谢DFROBOT提供的C4002毫米波人体存在传感器模块。 我原本计划基于 ESPHome 制作一套智能家居方案,用于客厅人体存在感应,实现人在自动亮灯、人走自动熄灯,同时播报进出提示音。但 C4002 传感器检测灵敏度太高,客厅环境复杂、干扰多,设备始终判定区域内有人,无法完成空载校准。因此我将设备转移至书房使用,关闭房间门窗,构建干净的无干扰环境,顺利完成功能测试。 1、硬件介绍
1.1 C4002 毫米波雷达C4002 是 DFRobot 推出的 24GHz 毫米波人体存在传感器模块。模块突破了传统PIR传感器只能检测大幅运动的局限,可在10x10m的有效检测范围内,同步侦测运动人体与静止/微动人体,并支持运动速度检测、运动方向识别(靠近/远离)及环境光检测功能。 工作频率为 24GHz~24.25GHz 检测距离:运动最远 11 米、微动 / 静止最远 10 米,支持参数配置 可检测人体运动、静止存在状态,同时识别运动方向与运动速度 探测角度:120°×120° 采用 UART 通信接口,波特率 115200bps 模块内置光照传感器,检测范围 0~50lux 整体尺寸为 22mm × 26mm
1.2 主控与外围主控选用 ESP32-C3(4MB Flash),负责运行 ESPHome 程序以及 WiFi 通信 搭配 SSD1306 128×64 I2C OLED 显示屏,用来本地展示设备状态与探测距离 外接 MAX98357A I2S 功放模块,实现 RTTL 格式音频播报 搭载 LED 补光灯,接入 GPIO7 引脚,实现夜间人体感应亮灯功能
1.3 接线图2、ESPHome 配置
2.1 组件修复:最大探测距离设置无效官方提供的自定义组件C4002存在一处BUG,在 HA 中设置最大探测距离后,参数无法生效,雷达依旧可以探测到设定范围外的人员。经排查,组件初始化函数仅具备读取雷达参数的能力,无法向设备写入配置,我通过自定义组件修复了该问题。 2.2 组件新增:光照强度传感器C4002 自带环境光传感器,会通过 UART 持续上传光照数据。官方组件虽然能够解析相关数据,但并未将其封装为 Home Assistant 可用实体。我在自定义组件中补充了光照强度传感器功能。 2.3 OLED 显示屏设备搭载 OLED 显示屏,第一行展示设备状态,分为无目标、静止存在、运动中三种提示,第二行根据当前状态显示对应的探测距离。
- # I2C 总线
- i2c:
- - id: i2c_bus
- scl: GPIO6
- sda: GPIO5
-
- # 显示屏 (Display): OLED
- display:
- - platform: ssd1306_i2c
- id: oled128
- model: "SSD1306 128x64"
- i2c_id: i2c_bus
- address: 0x3C
- flip_x: false
- update_interval: 500ms
- lambda: |-
- it.fill(COLOR_OFF);
- // 第一行:目标状态
- it.printf(10, 10, id(cn_font), "状态:%s", id(target_status_text).state.c_str());
- // 第二行:根据状态显示对应距离
- // 运动中 → 显示运动距离(existTargetDist 会滞后)
- // 静止中 → 显示存在距离
- // 无目标 → 显示 --
- int status = id(target_status_sensor).state;
- if (status == 2) {
- // 运动中:显示运动距离
- if (!isnan(id(movement_distance_sensor).state)) {
- it.printf(10, 42, id(cn_font), "距离:%.1fm(M)", id(movement_distance_sensor).state);
- } else {
- it.printf(10, 42, id(cn_font), "距离:--(M)");
- }
- } else if (status == 1) {
- // 静止存在:显示存在距离
- if (!isnan(id(existing_distance_sensor).state)) {
- it.printf(10, 42, id(cn_font), "距离:%.1fm", id(existing_distance_sensor).state);
- } else {
- it.printf(10, 42, id(cn_font), "距离:--");
- }
- } else {
- it.printf(10, 42, id(cn_font), "距离:--");
- }
复制代码
2.4 音乐播报设备借助 MAX98357A 模块播放 RTTTL 格式铃声,检测到人员进入时播放上行音阶,人员离开时播放下行音阶。 - # I2S 音频总线
- i2s_audio:
- - id: i2s_bus
- i2s_bclk_pin: GPIO3 # ← SCK
- i2s_lrclk_pin: GPIO4 # ← WS
-
- # MAX 98357A
- speaker:
- - platform: i2s_audio
- id: box_speaker
- i2s_audio_id: i2s_bus
- i2s_dout_pin: GPIO19
- dac_type: external
- sample_rate: 16000
- bits_per_sample: 16bit
- channel: right # MAX 98357A默认是右声道
- buffer_duration: 100ms
-
- # RTTTL 播放器
- rtttl:
- id: rtttl_player
- speaker: box_speaker
复制代码
2.5 LED 灯本次测试使用 GPIO7 外接的普通 LED 灯模拟智能灯具,设备会结合光照传感器数据,判断是否需要点亮灯光。 - # LED 灯 (GPIO7)
- output:
- - platform: gpio
- pin: GPIO7
- id: led_output
-
- light:
- - platform: binary
- output: led_output
- name: "LED灯"
- id: led_light
复制代码
2.6 即时状态检测脚本这是项目的核心逻辑,通过全局变量记录上一次的雷达状态,每 200 毫秒检测一次状态变化。 - # 脚本:音乐播报 + LED灯控制
- script:
- # 有人来了
- - id: on_arrive
- mode: single
- then:
- - rtttl.play:
- rtttl: "come:d=16,o=5,b=240:16c6,16e6,16g6,8c7"
- - if:
- condition:
- lambda: |-
- float lux = id(light_sensor).state;
- float threshold = id(light_threshold_lux);
- return !isnan(lux) && lux < threshold;
- then:
- - light.turn_on: led_light
- - logger.log:
- format: "光线暗,开启补光灯"
- tag: "c4002"
- else:
- - logger.log:
- format: "光线充足,无需补光"
- tag: "c4002"
-
- # 人离开
- - id: on_leave
- mode: single
- then:
- - rtttl.play:
- rtttl: "leave:d=16,o=5,b=240:16c7,16g6,16e6,8c6"
- - if:
- condition:
- light.is_on: led_light
- then:
- - light.turn_off: led_light
- - logger.log:
- format: "人已离开,关闭补光灯"
- tag: "c4002"
-
- # 状态变化检测
- - id: status_monitor
- mode: single
- then:
- - lambda: |-
- int raw = id(target_status_sensor).state;
- if (isnan(raw)) return;
-
- int prev = id(prev_raw_status);
-
- // 状态没变,跳过
- if (prev == raw) return;
-
- // 记录新状态
- id(prev_raw_status) = raw;
-
- // 刚启动时 prev<0,不触发
- if (prev < 0) return;
-
- // 无人(0) → 有人(1/2)
- if (prev == 0 && raw != 0) {
- ESP_LOGI("c4002", "检测到有人进入 (状态: %d)", raw);
- id(on_arrive).execute();
- }
- // 有人(1/2) → 无人(0)
- else if (prev != 0 && raw == 0) {
- ESP_LOGI("c4002", "检测到人已离开");
- id(on_leave).execute();
- }
-
- # 定时器:每 200ms 检测一次状态变化
- interval:
- - interval: 200ms
- then:
- - script.execute: status_monitor
复制代码
整体逻辑仅识别无人与有人两种状态的切换,人体在区域内运动和静止的相互切换,不会触发灯光与音效动作,避免灯具频繁开关。 3、编译与烧录
3.1 编译固件由于国内网络环境限制,本地编译固件容易出现依赖包下载失败的问题,推荐使用 GitHub Actions workflows 进行云端编译。 编译好的固件详见附件。 3.2 烧录固件使用 ESPHome 官方在线烧录工具完成固件写入,操作步骤如下: 将开发板通过 USB 数据线连接至电脑,进入下载模式:按住 BOOT 键和 RST 键,先释放 RST 键,再释放 BOOT 键 在在线工具页面点击 CONNECT 按钮,在弹出的设备列表中选择对应的串口(如 COM12,可通过设备管理器查看) 连接成功后,点击 INSTALL 按钮,选择 Custom firmware,上传刚才下载的固件文件(.bin 格式) 点击 INSTALL 开始烧录,工具会自动擦除并写入新固件 烧录完成后,按开发板上的 RST 键重启设备
4、毫米波雷达测试
4.1 基础功能验证烧录完重启后,设备会自动连接 WiFi,可被 Home Assistant 自动发现并添加,所有传感器数据都能实时查看。 毫米波雷达容易受到外界环境干扰,正式使用前必须完成设备校准。C4002模块灵敏度较高,在客厅环境下无法进入无目标状态,因此选择在书房完成校准。 根据测试范围调整最大探测范围为3m 
4.2 人走进/走出测试校准完成后开展人体进出测试: 人员从远处走近,显示运动中状态,探测距离数值不断减小,同时识别出靠近的运动方向 人员原地站定,等待 1 至 2 秒,设备切换为静止存在状态,探测距离数值保持稳定 人员离开检测区域,设备变为无目标状态,同时播放离开提示音 夜间环境下,当光照传感器数值低于25 时,检测到人员后会自动点亮 LED 灯 详见视频。
5、小结C4002 毫米波雷达最大探测距离可达 11 米,探测灵敏度较高,适配大面积场景使用,非常适合安装在工厂、工地、仓库、停车场、写字楼、体育馆等场所,可稳定实现人体存在智能感应,实现人来开灯、人走关灯、关空调等自动化场景。 虽然该模块支持自定义最大探测距离,理论上可适配小户型家庭环境,但由于灵敏度过高,在家用小空间内容易受细微环境干扰,出现数据波动、空载校准困难等问题,综合来看家用场景的适配性与性价比一般,存在性能过剩的情况。后续再使用Micropython测试一下,看看是否能有效降低干扰。
|