WLED Temperature Usermod:基于 DS18B20 的温度传感器集成与 MQTT 上报实战指南
【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLED
本篇指南围绕 WLED 官方 usermods 目录下的 Temperature usermod(usermods/Temperature/readme.md)展开:它将 OneWire 总线的 Dallas 温度传感器(DS18B20 等)接入 ESP32/ESP8266 灯光控制器,实现 Web UI Info 页显示、MQTT/temperature主题上报(含 Home Assistant 自动发现),并额外提供一个用灯带渲染温度的内置特效。读完后,你将掌握该 usermod 的 PlatformIO 编译安装方式、编译期与运行期全部配置项、底层非阻塞测温的实现原理,以及传感器缺失时的容错行为。
一、功能概览:这个 usermod 做什么
Temperature usermod 脱胎于社区中优秀的QuinLED_Dig_Uno_Temp_MQTTusermod(srg74 和 400killer 作品),由 @blazoncek 维护。其核心能力包括:
- 传感器读取:通过 OneWire 协议读取外接 DS18B20 温度传感器(该传感器常见于 QuinLED Dig-Uno 主板),源码中还兼容 DS18S20、DS1822、DS1825、DS28EA00 等家族器件(UsermodTemperature.h、Temperature.cpp);
- Web UI 展示:温度值写入
/json/info的u.Temperature与sensor.temperature字段,显示在 WLED 网页 Info 区; - MQTT 发布:若启用 MQTT,则发布到
<mqttDeviceTopic>/temperature(摄氏度)和<mqttDeviceTopic>/temperature_f(华氏度),并推送 Home Assistant 传感器自动发现配置,以及可选的 Domoticz 虚拟传感器消息; - 自动禁用机制:启动时若检测不到传感器,该 usermod 将自动禁用,避免在没接传感器的板子上持续做无效读取;
- 附加特效:传感器就绪后自动注册
Temperature@Min,Max特效(effect ID 255),用灯带颜色渲染当前温度。
从源码结构看,该 usermod 被官方文档 usermods/readme.md 作为 v2 usermod API 的完整范例推荐(“You can take a look atTemperaturefor a completed v2 usermod!”),是学习编写 WLED 自定义插件的良好参考。
二、安装:在 platformio_override.ini 中启用
2.1 编译期启用
将Temperature加入custom_usermods列表即可。官方 readme 给出的示例platformio_override.ini如下:
[env:usermod_temperature_esp32dev] extends = env:esp32dev custom_usermods = ${env:esp32dev.custom_usermods} Temperature其工作机制可由仓库源码印证:
- platformio.ini 中每个构建环境都有
custom_usermods键; - 构建脚本 pio-scripts/load_usermods.py 解析该键(
raw_usermods = env.GetProjectOption("custom_usermods", "")),把名字对应到usermods/下的各插件文件夹并作为本地库参与编译; - platformio_override.sample.ini 中也有现成注释样例:
custom_usermods = ${env:esp32dev.custom_usermods} Temperature,并可通过-D TEMPERATURE_PIN=13覆盖编译期默认引脚; - 仓库内 platformio_override.sample.ini 的
wemos_shield_esp32环境(-D TEMPERATURE_PIN=23)就是 srg74 Wemos 扩展板上实际启用该 usermod 的配置。
插件的依赖声明在 usermods/Temperature/library.json:
{ "name": "Temperature", "build": { "libArchive": false }, "dependencies": { "paulstoffregen/OneWire": "~2.3.8" } }即自动拉取 paulstoffregen 的 OneWire 库 ~2.3.8 版本。custom_usermods中多个 usermod 之间用空格分隔,名字取自各插件library.json的name字段。
2.2 硬件接线要点
- 数据线:DS18B20 的 DQ 接到某 GPIO(ESP32 默认GPIO18,ESP8266 默认GPIO14,见 UsermodTemperature.h 中
TEMPERATURE_PIN定义,可通过-D TEMPERATURE_PIN=x修改); - 寄生供电(parasitic power):若传感器未接 Vcc(仅 3 线接法),需在 Usermods 设置页开启
parasite-pwr并指定驱动外部 MOSFET 的parasite-pwr-pin。源码中requestTemperatures()发起转换时会将该引脚拉高,转换完成后readTemperature()再拉低(Temperature.cpp),对应 DS18B20 寄生供电时序要求。
三、配置项详解:编译期宏 + 运行期设置页
3.1 编译期选项
| 选项 | 说明 | 默认值 |
|---|---|---|
USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL | 两次测量之间的间隔(毫秒) | 60000(60 秒),见 UsermodTemperature.h |
TEMPERATURE_PIN | 传感器 OneWire 数据引脚 | ESP32: 18;ESP8266: 14 |
注意 readme 特别强调:所有参数(包括引脚、摄氏/华氏、测量间隔)都可以在运行时的 Usermods 设置页配置,编译期宏只是兜底默认值。
3.2 运行期设置页字段(cfg.json 持久化)
由addToConfig()/readFromConfig()实现(Temperature.cpp),cfg.json 中对应结构为:
{"Temperature": {"pin": 18, "degC": true, "enabled": true, "read-interval-s": 60, "parasite-pwr": false, "parasite-pwr-pin": -1, "domoticz-idx": -1, "resolution": 3}}| 字段 | 类型 | 说明 |
|---|---|---|
enabled | bool | 是否启用该 usermod |
pin | int8 | OneWire 数据 GPIO |
degC | bool | true为摄氏度,false为华氏度 |
read-interval-s | int | 读取间隔(秒),源码中限定在10~120 秒(min(120,max(10,...)) * 1000,Temperature.cpp) |
parasite-pwr | bool | 传感器是否寄生供电 |
parasite-pwr-pin | int8 | 寄生供电 MOSFET 驱动引脚 |
domoticz-idx | int | Domoticz 虚拟传感器 idx(-1 表示不发送 Domoticz 消息) |
resolution | 0–3 | 转换分辨率:0=9-bit(0.5°C)、1=10-bit(0.25°C)、2=11-bit(0.125°C)、3=12-bit(0.0625°C);设置页选项文案由appendConfigData()生成,且对 DS18S20 无效 |
引脚变更时的热重初始化的实现细节:readFromConfig()检测到新引脚与旧值不同时,会delete oneWire、通过PinManager::deallocatePin()释放旧引脚(占用者标识为PinOwner::UM_Temperature,见 pin_manager.h),然后重新调用setup()——即换引脚无需重启设备。
四、底层实现:非阻塞测温与容错
4.1 启动检测(setup)
setup()的执行链(Temperature.cpp):
- 通过
PinManager::allocatePin()申请 OneWire 引脚; - 调用
oneWire->reset()探测总线,成功则进入findSensor():先reset_search(),再search()遍历器件,校验 8 字节 ROM 地址的 CRC,并按家族码识别 DS18S20(0x10)/DS1822(0x22)/DS18B20(0x28)/DS1825(0x3B)/DS28EA00(0x42); - 找不到传感器时最多重试 10 次(每次
delay(25));sensorFound保持为 0,loop()会因此直接返回,usermod 事实上被禁用; - 传感器找到且
initDone未置位时,注册Temperature@Min,Max特效(strip.addEffect(255, &mode_temperature, ...))。
4.2 非阻塞测量状态机(loop)
2020-09-12 版本起改为异步非阻塞实现。loop()(Temperature.cpp)是一个两段式状态机:
- 未到采样时刻:
now - lastMeasurement < readingInterval直接返回; - 发起转换:
waitingForConversion为假时调用requestTemperatures()——OneWire reset → skip ROM → 写0x44(转换命令,第 2 字节携带寄生供电标志),置位waitingForConversion; - 等待转换完成:DS18B20 数据手册标称转换时间 93.75 ms(12-bit),实际可达 750 ms,代码以750 ms作为安全阈值,到期后调用
readTemperature()读出结果并更新时间戳。
lastMeasurement只在实际读取完成后才更新,因此间隔计时天然包含了转换耗时。
4.3 快速读取与数值解码(readDallas)
readDallas()是 Peter Scargill 的快速读法:reset → skip ROM → 写0xBE(读暂存器)→ 一次read_bytes取 9 字节,前两字节即温度,第 9 字节为 CRC(Temperature.cpp)。解码规则:
- DS18S20:9-bit 精度,
temp = raw × 0.5; - DS18B20/DS1822/DS1825/DS28EA00:12-bit 精度,
temp = raw × 0.0625(2^-4),并按resolution对低位做截断以匹配 9/10/11-bit 精度; - 错误判定:
readDallas()末尾对 9 字节做 AND 折叠,全 0xFF(线浮空典型表现)或读值-127°C均视为无效读。-127恰好在 DS18B20 量程(最低 -50°C)之外,被用作“传感器错误”哨兵值。
WLED_DEBUG 构建下还会逐字节打印 CRC 校验失败的原始数据,便于排查接线问题。
4.4 异常处理与自动恢复
- 单次读到
< -100°C的值不发布 MQTT(防止曲线图被异常尖刺污染),并立即安排 300 ms 后的重测; - 连续 10 次错误读后
sensorFound清零,usermod 进入“未找到传感器”状态; - Web UI Info 页对
temperature <= -100显示0 / " Sensor Error!"(addToJsonInfo())。
4.5 版本演进(readme Change Log 完整继承)
- 2020-09-12:改为异步非阻塞实现;不向 MQTT 上报错误低温;传感器未检测到时禁用插件;Info 屏在未读到时显示“距首次读取还有多少秒”而非传感器错误;
- 2021-04:适配运行时配置;
- 2023-05:按新版 usermod 规范重写;曾推荐 @blazoncek 的 OneWire for ESP32 fork 以规避 Sensor error;
- 2024-09:OneWire 升级到 2.3.8(含 stickbreaker 与 garyd9 的 ESP32 修复),不再需要 fork——与 library.json 中
~2.3.8声明一致。
五、MQTT 接口与 Home Assistant 集成
5.1 发布主题
当WLED_MQTT_CONNECTED且读值有效(> -100°C)时(Temperature.cpp):
<mqttDeviceTopic>/temperature:摄氏度,retained = false;<mqttDeviceTopic>/temperature_f:华氏度,retained = false;- 若
domoticz-idx > 0,另向domoticz/in发布{"idx": x, "RSSI": ..., "nvalue": 0, "svalue": "xx.x"}。
5.2 Home Assistant 自动发现
每次 MQTT(重)连接后(onMqttConnect())发布一条 retained 配置到homeassistant/sensor/<escapedMac>/config:
{ "name": "<serverDescription> Temperature", "state_topic": "<mqttDeviceTopic>/temperature", "device_class": "temperature", "unique_id": "<MAC>", "unit_of_measurement": "°C" }即 Home Assistant 会零配置地出现一个温度传感器实体。注意 HA 配置的单位固定为 °C(见publishHomeAssistantAutodiscovery()中unit_of_measurement),摄氏/华氏切换只影响 WLED 自身显示与temperature_f主题。
六、附加特效:Temperature@Min,Max
传感器就绪后自动注册的特效(effect ID 255,Temperature.cpp)把整个片段填充为按温度映射的调色板颜色:
- 速度(speed)映射下限:0–255 → -150°C ~ 150°C(默认 15°C);
- 强度(intensity)映射上限:0–255 → 300°C ~ 600°C(默认 30°C);
- 当前摄氏温度 ×10 提升精度后夹在 [low, high] 区间,线性映射到调色板索引 0–248。
效果数据串Temperature@Min,Max;;!;01;pal=54,sx=255,ix=0指定默认调色板等参数;实际使用时可在 WLED 中把 Speed 拉到目标下限、Intensity 拉到目标上限来设定自己关心的量程。
七、与其他 usermod 的协作
PWM_fan 插件可直接复用本 usermod 的温度读数:usermods/PWM_fan/PWM_fan.cpp中通过UsermodManager::lookup(USERMOD_ID_TEMPERATURE)拿到UsermodTemperature实例(USERMOD_ID_TEMPERATURE = 3,定义于 wled00/const.h),实现“按温度调速风扇”的组合方案——这正是 readme 所述“可能在未来扩展支持更多传感器类型”思路的实例化。
八、故障排查清单
| 现象 | 排查点 |
|---|---|
| Info 显示 "Sensor Error!" | 接线/DQ 引脚/上拉电阻;开启parasite-pwr+ MOSFET 引脚(3 线接法时必须);WLED_DEBUG 构建下查看串口 CRC 打印 |
| MQTT 无数据 | 确认 MQTT 已连接;检查read-interval-s是否在 10–120 范围;读值 < -100°C 会被刻意丢弃 |
| 换引脚不生效 | 设置页保存后会自动重建 OneWire(readFromConfig()检测到 pin 变化即重初始化),确认保存的配置值确实改变 |
| 编译找不到插件 | custom_usermods名字须与 library.json 的name(Temperature)完全一致,且每行独立书写 |
适用前提与限制:本 usermod 目前仅支持 OneWire/Dallas 家族温度传感器(readme 明确“可能在未来扩展支持其他类型”);读取间隔被限制在 10–120 秒;resolution选项对 DS18S20 无效;MQTT/HA/Domoticz 相关功能仅在未以-D WLED_DISABLE_MQTT编译时才存在。
【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLED
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考