news 2026/9/13 21:27:56

WLED LD2410_v2 Usermod 实战:用 24GHz 毫米波雷达实现移动检测与 MQTT/Home Assistant 集成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WLED LD2410_v2 Usermod 实战:用 24GHz 毫米波雷达实现移动检测与 MQTT/Home Assistant 集成

WLED LD2410_v2 Usermod 实战:用 24GHz 毫米波雷达实现移动检测与 MQTT/Home Assistant 集成

【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLED

本文基于 WLED 官方仓库中的 LD2410_v2 usermod 及其完整实现源码展开,讲解如何把 LD2410 毫米波雷达传感器接入 WLED(ESP32),实现“移动/静止”两种存在检测状态:状态不仅会显示在 WLED Web UI 的 Info 页面,还会发布到 MQTT 话题并自动完成 Home Assistant Discovery。读完本篇后,你可以独立完成该 usermod 的编译启用、串口引脚配置、MQTT 话题订阅,以及 Home Assistant 中 motion/occupancy 二进制传感器的落地,并能对照源码理解其 1 秒轮询与 5 分钟心跳保活的完整数据流。

一、功能定位与硬件前提

该 usermod 的核心功能是读取 LD2410 移动/存在(movement/presence)雷达传感器的状态,并将两类状态分别呈现:

  • 移动状态(movement):检测到运动目标;
  • 静止状态(stationary):检测到静止目标(有人但不动)。

原始文档明确了两个关键前提:

  1. 需要第二路 UART:传感器通过独立串口(ESP32 上的Serial1)通信,占用一对 GPIO 引脚;
  2. 仅在 ESP32 上经过测试:不支持 ESP8266 等平台。

从源码 LD2410_v2.cpp 还能看到第三个硬性前提:

#ifdef WLED_DISABLE_MQTT #error "This user mod requires MQTT to be enabled." #endif

也就是说,如果在构建时禁用了 MQTT,该模块会直接在编译期报错。文档中的 Dependencies 一节也对应说明:数据通过 MQTT 发布,必须先启用 WLED 的 MQTT 同步接口。

二、依赖库:ncmreynolds/ld2410

该 usermod 本身不包含 LD2410 协议实现,而是依赖 PlatformIO 注册表中的ncmreynolds/ld2410库,版本约束见 library.json:

{ "name": "LD2410_v2", "build": { "libArchive": false }, "dependencies": { "ncmreynolds/ld2410": "^0.1.3" } }

两个细节值得注意:

  • ^0.1.3表示允许 0.1.x 范围内的较新版本;
  • "build": { "libArchive": false }是 WLED usermod 的强制要求——usermod 必须直接链接进可执行文件而不是归档成静态库。构建脚本 load_usermods.py 会在构建期检查此项,缺失时会以ERROR: libArchive=false is missing on usermod(s) ...报错并终止构建。

WLED 的构建系统在启用 usermod 时,会自动把该库声明的dependencies一起解析为lib_deps,无需手工在 platformio 配置里重复声明。

三、编译启用:custom_usermods 机制

3.1 在 platformio_override.ini 中启用

原始文档给出的编译方式为:在custom_usermods中加入该模块名(例如放入 platformio_override.ini),文档示例如下:

[env:usermod_USERMOD_LD2410_esp32dev] extends = env:esp32dev custom_usermods = ${env:esp32dev.custom_usermods} LD2140_v2

勘误提示:原文档中出现的LD2140/LD2140_v2是笔误(“4”与“1”位置颠倒),且文档 H1 标题误写为 “BH1750 usermod”,均为复制残留。实际目录名为 usermods/LD2410_v2,应填写LD2410_v2(或简写LD2410)。

这里的关键在于${env:esp32dev.custom_usermods}写法:它继承所选基础环境(如esp32dev)已有的 usermod 列表并追加本模块,避免清空原有配置。仓库中的示例文件 platformio_override.sample.ini 展示了完全相同的继承模式,例如:

custom_usermods = ${env:esp32dev.custom_usermods} Temperature four_line_display_ALT

3.2 名称解析规则:为什么可以省略 _v2 后缀

从构建脚本 load_usermods.py 的find_usermod()可以看到解析逻辑:

def find_usermod(mod: str) -> Path: mp = usermod_dir / mod # 精确匹配 if mp.exists(): return mp mp = usermod_dir / f"{mod}_v2" # 尝试 name_v2 if mp.exists(): return mp mp = usermod_dir / f"usermod_v2_{mod}" # 尝试 usermod_v2_name if mp.exists(): return mp raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!")

因此写LD2410会被自动解析到usermods/LD2410_v2/目录,写LD2410_v2则直接命中。这与 AGENTS.md 中 “usermod_v2_prefix or_v2suffix can be omitted” 的规范一致。解析成功后,模块以symlink://形式注入lib_deps参与编译。

四、初始化与串口通信:setup() 的实现

启用模块后,WLED 启动阶段会调用Usermod::setup()。该模块的 setup() 实现为:

void setup() { Serial1.begin(256000, SERIAL_8N1, uart_rx_pin, uart_tx_pin); Serial.print(F("\nLD2410 radar sensor initialising: ")); if(radar.begin(Serial1)){ Serial.println(F("OK")); } else { Serial.println(F("not connected")); } initDone = true; }

要点:

  • 使用 ESP32 的Serial1(第二路 UART),波特率256000,8N1 格式——这是 LD2410 模块的出厂通信参数;
  • 默认引脚:default_uart_rx = 19default_uart_tx = 18(源码 L18-L19);
  • 初始化结果会打印到串口监视器(OK/not connected),但注意:即使radar.begin()返回失败,initDone仍会置为 true,后续loop()会持续尝试,并在每秒的连接检查中更新sensorFound标志。

五、主循环逻辑:1 秒轮询 + 状态变化发布 + 5 分钟心跳

loop()每轮主循环被调用一次,其完整逻辑(源码 L103-L133)可以拆解为四层:

  1. 快速退出if (!enabled || strip.isUpdating()) return;—— 模块被禁用、或 LED 灯带正在刷新时直接返回。注释中特别提示:在超长灯带上strip.isUpdating()可能恒为 true,此时轮询会被永久跳过,需要“update accordingly”;
  2. 每秒一次采样radar.read()每次都会执行,但状态评估与发布被节流到1000ms 间隔curr_time - lastTime > 1000);
  3. 连接检查优先sensorFound = radar.isConnected(),未连上传感器时直接 return,不发布任何状态;
  4. 变化触发发布 + 心跳
    • presenceDetected()得到静止状态,movingTargetDetected()得到移动状态;
    • 仅当状态相对上一次发生变化时才发布 MQTT 消息;
    • 若 5 分钟内没有任何状态变化,会主动重发当前两个状态作为“活着”的心跳(curr_time - last_mqtt_sent > 1000*60*5),保证 HA 侧的expire_after不会误判离线。
stationary_detected = radar.presenceDetected(); if(stationary_detected != last_stationary_state){ if (WLED_MQTT_CONNECTED){ publishMqtt("/ld2410/stationary", stationary_detected ? "ON":"OFF", false); last_stationary_state = stationary_detected; } } movement_detected = radar.movingTargetDetected(); if(movement_detected != last_movement_state){ if (WLED_MQTT_CONNECTED){ publishMqtt("/ld2410/movement", movement_detected ? "ON":"OFF", false); last_movement_state = movement_detected; } }

其中WLED_MQTT_CONNECTED是 WLED 核心提供的宏,定义于 wled00/wled.h:#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected()),即“MQTT 客户端存在且已连接”。所有发布都通过它做双重保护(循环内判断一次,publishMqtt()内部再判断一次),避免未连接时调用mqtt->publish()崩溃。

六、MQTT 话题结构与 Home Assistant Discovery

6.1 状态话题

原文档说明状态发布到/movement/stationary话题;结合 源码 中publishMqtt()的拼接逻辑(mqttDeviceTopic+ 子话题),实际完整话题为:

话题载荷触发时机
<WLED设备话题>/ld2410/movementON/OFF移动状态变化、5 分钟心跳
<WLED设备话题>/ld2410/stationaryON/OFF静止状态变化、5 分钟心跳
<WLED设备话题>/ld2410/statusI am alive!MQTT 连接建立且传感器已连接时(onMqttConnect)

所有消息均为非保留(retain = false)发布。

6.2 Home Assistant 自动发现

源码中HomeAssistantDiscovery默认为true(L25)。MQTT 首次连接后,_mqttInitialize()会调用_createMqttSensor()为两个状态各发布一条发现配置(L44-L85):

  • 配置话题homeassistant/binary_sensor/<mqttClientID>/Movement/config.../Stationary/config
  • 设备类:Movement 为motion,Stationary 为occupancy
  • 载荷约定payload_on = "ON"payload_off = "OFF"
  • 离线判定expire_after = 1800(30 分钟无消息 HA 判定实体离线——与第五节的 5 分钟心跳配合,正常情况下不会误报);
  • 设备聚合:两个传感器挂在同一虚拟设备下(identifiers = wled-sensor-<mqttClientID>,manufacturer 为WLED,model 为FOSS,sw_version 取当前固件版本串),在 HA 中呈现为一个 WLED 设备下的两个二进制传感器。

这意味着在 WLED 中开启 MQTT 同步后,Home Assistant 中无需手动建模即可出现“移动”和“占用”两个传感器实体。

七、Web UI Info 页面展示

addToJsonInfo()(L136-L156)向/json/infou(usermod)对象中追加两个数组,Web UI 的 Info 区块会显示为两行文本:

场景"LD2410 Stationary" 显示"LD2410 Movement" 显示
模块被禁用disableddisabled
未检测到传感器LD2410 Not Found(空)
正常工作Sta ON/Sta OFFMov ON/Mov OFF

这是无需 MQTT 客户端即可肉眼确认传感器是否在线、状态是否正常跳变的最快途径。

八、配置项详解:enabled 与 UART 引脚

8.1 持久化配置

addToConfig()/readFromConfig()(L158-L188)定义了写入 cfg.json 的键(节点名LD2410Usermod):

键名类型默认值说明
enabledbooltrue启用/禁用 usermod
uart_rx_pinint819Serial1 的 GPIO 输入引脚
uart_tx_pinint818Serial1 的 GPIO 输出引脚

readFromConfig()中使用了三参数getJsonValue()的缺省回退写法——即使 cfg.json 被手工编辑导致某个键缺失,也能用默认值兜底(源码注释明确说明这一设计考虑)。

8.2 一个需要留意的实现细节

原文档称 “Usermod 设置页可以配置 RX/TX 引脚”。但从源码结构看,当前实现没有重写appendConfigData()(该方法在 Usermod 基类 中用于向设置页注入 UI 控件),因此设置页面上实际没有可编辑的引脚滑杆;addToConfig()每次保存设置时写入的也是编译期默认值19/18。也就是说,若要改用其他 UART 引脚,只能修改源码中的default_uart_rx/default_uart_tx后重新编译——这是使用与二开该模块时最容易被文档与代码差异“坑到”的一点。

九、注册机制与唯一 ID

模块通过 WLED 的 linker-section 注册机制接入主循环:

static LD2410Usermod ld2410_v2; REGISTER_USERMOD(ld2410_v2);

其中REGISTER_USERMOD宏定义在 wled00/fcn_declare.h,本质是把模块实例指针放入名为usermods的 DYNARRAY 链接段,UsermodManager启动时遍历该段完成 setup/loop 调度。

本模块重写了getId()并返回USERMOD_ID_LD2410(值为 52,注册于 wled00/const.h)。按 AGENTS.md 的规范,唯一 ID 只在需要跨 usermod 查找、PinManager 引脚所有权、或在/json/infoum数组中可识别时才必须——本模块采用固定 ID 使其在 JSON info 输出中可被明确辨识。

十、排障清单

结合源码与文档,常见故障可按以下路径排查:

  1. Info 页显示 "LD2410 Not Found"radar.isConnected()为 false。确认接线是否接对了 Serial1 的 RX/TX(交叉连接:WLED TX → 模块 RX,WLED RX → 模块 TX)、供电是否正常、串口监视器中是否打印了not connected
  2. MQTT 一直无消息:先确认 WLED 已启用 MQTT 同步接口且WLED_MQTT_CONNECTED为真(可在 HA 中观察.../ld2410/status话题的I am alive!消息是否收到);未连接时模块按设计不发布任何状态;
  3. 构建报错 “This user mod requires MQTT to be enabled.”:当前构建环境定义了WLED_DISABLE_MQTT,需更换启用 MQTT 的环境;
  4. 超长灯带上状态永远不更新strip.isUpdating()恒真导致loop()提前返回,这是源码注释中明确提示的已知限制;
  5. 名称写错导致编译找不到模块find_usermod()会抛出Couldn't locate module ...,注意区分LD2410(正确)与文档笔误LD2140

十一、版本沿革

文档 Change log 记录:2024 年 6 月由 @wesleygas 创建。当前仓库中的实现(1 秒轮询、HA Discovery、5 分钟心跳、I am alive!状态话题)即为该 v2 版本的完整形态,代码位于 usermods/LD2410_v2/LD2410_v2.cpp,依赖声明位于 usermods/LD2410_v2/library.json。

参考文件

  • 模块文档:usermods/LD2410_v2/readme.md
  • 模块实现:usermods/LD2410_v2/LD2410_v2.cpp
  • 依赖声明:usermods/LD2410_v2/library.json
  • Usermod 基类与注册宏:wled00/fcn_declare.h
  • Usermod ID 定义:wled00/const.h
  • MQTT 连接状态宏:wled00/wled.h
  • usermod 构建解析脚本:pio-scripts/load_usermods.py
  • 构建配置示例:platformio_override.sample.ini
  • Usermod 开发规范:AGENTS.md

【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLED

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

FPGA电平转换器实战避坑指南:从选型到时序约束全链路解析

1. 这不是“接根线就能用”的小玩意儿&#xff1a;电平转换器的真实角色与我的踩坑起点电平转换器&#xff0c;这三个字在FPGA开发者的BOM清单里出现频率极高&#xff0c;但真正把它当回事的人却不多。我第一次接触它&#xff0c;是在调试一块Xilinx Artix-7 FPGA核心板驱动一块…

作者头像 李华
网站建设 2026/9/13 21:24:50

F28335上实现SVPWM+FOC闭环控制的硬实时关键技术

简介&#xff1a;本资源是基于TI TMS320F28335浮点DSP芯片的电机控制算法实践项目&#xff0c;面向嵌入式电机控制初学者与进阶开发者&#xff0c;聚焦SVPWM空间矢量调制、FOC磁场定向控制及主控时钟/开关频率&#xff08;Major KPS&#xff09;配置等核心环节&#xff0c;解决…

作者头像 李华