WLED 实战为 Wemos D1 mini / Wemos32 mini 扩展板添加 OLED 状态屏与温度传感器usermod 详解【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLEDWLED 提供了 v1 usermod 机制userSetup/userConnected/userLoop三个钩子允许在不改动主代码的前提下给固件附加自定义功能。本文基于仓库中 usermods/Wemos_D1_miniWemos32_mini_shield/readme.md 及其配套源码 usermod.cpp、usermod_bme280.cpp完整讲解如何把 SSD1306 OLED 状态屏和 DS18B20 / BME280 温度传感器接入 Wemos D1 miniESP8266或 Wemos32 miniESP32扩展板包括安装方法、PlatformIO 依赖配置、引脚定义、显示刷新与自动休眠逻辑、以及每 60 秒一次的 MQTT 温湿度/气压上报实现。读完后你可以复现整套带屏幕状态指示与传感器遥测的 WLED 构建方案。这个 usermod 解决什么问题WLED 默认没有本地显示屏设备挂在墙上的灯带控制器上时你无法直接看到它的 IP 地址、连接的 WiFi、当前灯效和调色板——这些正是配网后最常被需要的信息。这个 usermod 利用扩展板Wemos shield上的 I2C OLED 把以下信息常驻显示SSID第一行与本机 IP第二行AP 模式且亮度为 0 时第二行改显示 AP 密码当前灯效mode名称与调色板palette名称第三、四行WiFi、Home、太阳/月亮亮/灭状态三个图标同时它还实现了 readme 中列出的完整功能清单功能实现依据SSD1306 128x32 或 128x64 I2C OLEDU8g2 库的U8X8_SSD1306_128X32_UNIVISION_HW_I2C/U8X8_SSD1306_128X64_NONAME_HW_I2C构造函数屏幕上显示 IP、SSID 与控制器状态开关、当前灯效userLoop()中的重绘逻辑自动熄屏以延长 OLED 寿命3 分钟无变化后调用u8x8.setPowerSave(1)Dallas 温度传感器DS18B20Dallas()快速读数函数 OneWire 库温度上报 MQTT broker以mqttDeviceTopic/temperature为主题定时发布继电器省电扩展板自带继电器从源码看用户固件本身未直接操作继电器引脚推断由 WLED 主程序的RLYPIN机制亮度为 0 时断电承担文件清单与替换规则readme 的原始安装说明默认Dallas 传感器版本把 usermod.cpp 复制并替换WLED 源码树wled00目录下的usermod.cppBME280 版本改用 usermod_bme280.cpp复制到wled00后重命名为usermod.cpp第三控制器选项Heltec WiFi-Kit-8同样带 OLED纯 DIY 硬件见下文引脚说明。WLED 的 v1 usermod 入口骨架见 wled00/usermod.cppuserSetup启动时调用一次、userConnected每次 WiFi重连时调用、userLoop每轮主循环调用。这个 usermod 正是填充这三个钩子userSetup()初始化 OLED 并触发首次传感器读数userLoop()负责 MQTT 发布与屏幕刷新userConnected()留空。usermod 的目录组织规范每个 usermod 一个文件夹、附 readme 说明所需改动可在 usermods/readme.md 中查看。引脚定义ESP8266 与 ESP32 的差异两个源文件用编译期宏区分两种主控板这是复现硬件连接的关键#ifdef ARDUINO_ARCH_ESP32 // Wemos32 mini uint8_t SCL_PIN 22; uint8_t SDA_PIN 21; uint8_t DALLAS_PIN 23; #else // ESP8266 Wemos D1 mini uint8_t SCL_PIN 5; uint8_t SDA_PIN 4; uint8_t DALLAS_PIN 13; // uint8_t RST_PIN 16; // Heltec WiFi-Kit-8 时取消注释 #endif即信号Wemos D1 miniESP8266Wemos32 miniESP32I2C SCLGPIO5GPIO22I2C SDAGPIO4GPIO21DS18B20Dallas数据脚GPIO13GPIO23OLED RESET仅 Heltec WiFi-Kit-8 需要GPIO16—Heltec WiFi-Kit-8 的 OLED 带独立 RESET 线此时需要取消RST_PIN 16及U8X8_PIN_RESET的注释并把 OLED 对象构造从U8X8_PIN_NONE改为U8X8_PIN_RESET源码中以“第三选项”注释形式给出。readme 中提到的“第三个控制器 Heltec WiFi-Kit-8”即由此实现。OLED 驱动对象的选择默认启用第一行// 第一选项廉价 128x32 0.91 I2C OLED U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // 第二选项128x64 0.96 或 1.3 //U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(...); // 第三选项Heltec WiFi-Kit-8使用 RESET 脚 //U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA);构造函数参数依次为 Reset、SCL、SDA硬件 I2C_HW_I2C意味着 SDA/SCL 必须与上表匹配否则显示不出来或显示错乱源码注释建议对照 u8g2 的 u8x8setupcpp 参考页核对。安装与 PlatformIO 依赖配置步骤一替换 usermod 文件将对应版本的.cpp放入wled00并命名/替换为usermod.cppWLED 只编译wled00/usermod.cpp这一个 v1 入口这也是 readme 中“copy and replace file in wled00 directory”的原因。步骤二声明外部库依赖readme 给出的platformio.ini配置片段如下——Dallas 传感器版本# platformio.ini ... [platformio] ... ; default_envs esp07 default_envs d1_mini ... [common] ... lib_deps_external ... #For use SSD1306 OLED display uncomment following U8g2~2.27.3 #For Dallas sensor uncomment following 2 lines DallasTemperature~3.8.0 OneWire~2.3.5 ...BME280 传感器版本# platformio.ini ... [platformio] ... ; default_envs esp07 default_envs d1_mini ... [common] ... lib_deps_external ... #For use SSD1306 OLED display uncomment following U8g2~2.27.3 #For BME280 sensor uncomment following BME280~3.0.0 ...即依赖组合为OLED 必选U8g2~2.27.3Dallas 版追加DallasTemperature~3.8.0和OneWire~2.3.5BME280 版追加BME280~3.0.0。适用前提提醒基于当前仓库实际情况上述片段中的default_envs d1_mini、esp07以及lib_deps_external段落来自原始 WLED-wemos-shield 项目readme 中列出的外部项目仓库/Wiki/预编译固件的platformio.ini。而在当前 WLED 主仓库的 platformio.ini 中并没有d1_mini/esp07构建环境也没有lib_deps_external这一键名。若你要在当前仓库的源码树上构建该 usermod正确做法是利用extra_configs机制——platformio.ini 中声明了extra_configs platformio_override.ini platformio_release.ini——即按 platformio_override.sample.ini 的样例新建一份platformio_override.ini在其中自定义d1_mini构建环境board d1_miniESP8266 平台并把U8g2、OneWire、DallasTemperature或BME280写入该环境的lib_deps。readme 中的; default_envs esp07注释也暗示原项目同时支持 ESP8266 的 esp07 环境可按同样思路扩展。步骤三编译烧录用 PlatformIO 编译你选择的d1_miniESP8266或对应 ESP32 mini 环境并烧录即可。readme 列出的实测验证环境为Wemos D1 mini 原版 v3.1 及克隆板、Wemos32 mini、PlatformIO 构建流程、SSD1306 128x32 I2C 屏、DS18B20 温度传感器、BME280 温湿度气压传感器、N.O. 瞬动按钮扩展板上的按钮由 WLED 主程序的BTNPIN机制处理。源码走读userSetup 初始化Dallas 版 usermod.cpp 的userSetup()逻辑void userSetup() { Dallas(DALLAS_PIN, 1); // 触发一次 DS18B20 转换并延时 1s保证首次读数是有效值 u8x8.begin(); u8x8.setPowerSave(0); // 退出省电模式点亮屏幕 u8x8.setFlipMode(1); // 翻转画面按屏的贴装方向调整 u8x8.setContrast(10); // 低对比度以延长 OLED 寿命需要更亮可调到 255 u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.drawString(0, 0, Loading...); }两个值得注意的细节启动即预热传感器Dallas(DALLAS_PIN, 1)的第二个参数start控制“转换—延时—重试”的循环次数。DS18B20 的0x44转换指令需要时间才能算出数据启动时先跑一轮并delay(1000)可避免后续读到上一次残留值。对比度只有 10OLED 的对比度寄存器越小画面越暗这里刻意压暗以降低有机像素的老化速度与 readme 中“auto display shutoff for extending display lifetime”的寿命策略一脉相承。Dallas 快速读数函数本身usermod.cpp是 OneWire 协议的“免库存”写法reset()总线复位后发跳过 ROM 命令0xCC和读 Scratchpad 命令0xBE取 2 字节温度低 12 位result4后按符号位扩展data[1]128时或上61440并处理了 DS18B20 的 0.5 LSB 舍入位data[0]8。返回的是 1/2 摄氏度0.5 °C 精度的整数。BME280 版 usermod_bme280.cpp 的userSetup()则额外初始化 I2C 总线并做传感器探测重试Wire.begin(SDA_PIN, SCL_PIN); while(!bme.begin()) { Serial.println(Could not find BME280I2C sensor!); delay(1000); } switch(bme.chipModel()) { case BME280::ChipModel_BME280: Serial.println(Found BME280 sensor! Success.); break; case BME280::ChipModel_BMP280: Serial.println(Found BMP280 sensor! No Humidity available.); break; default: Serial.println(Found UNKNOWN sensor! Error!); }while(!bme.begin())是死循环重试——I2C 传感器上电慢时能自恢复chipModel()区分 BME280 与 BMP280后者没有湿度通道后续发布的/humidity值会是 NaN。传感器对象BME280I2C bme默认参数为强制模式、1000 ms 待机、气压/温度/湿度均 1 次过采样、无滤波源码注释已写明。userLoop 上半段每 60 秒一次 MQTT 遥测两个版本的userLoop()都以“传感器发布”开头。Dallas 版usermod.cpptemptimer millis(); if (temptimer - lastMeasure 60000) { // 60 秒周期 lastMeasure temptimer; #ifndef WLED_DISABLE_MQTT if (mqtt ! nullptr) { // 未连接 MQTT 时跳过防止 8266 崩溃 #ifdef Celsius int16_t board_temperature Dallas(DALLAS_PIN, 0); // start0只读不再触发新转换 #else int16_t board_temperature (Dallas(DALLAS_PIN, 0) * 1.8 32); #endif String t String(mqttDeviceTopic); t /temperature; mqtt-publish(t.c_str(), 0, true, String(board_temperature).c_str()); } #endif }要点主题由 WLED UI 决定mqttDeviceTopic是 WLED 主程序全局变量在 Web UI 的 MQTT 设置里配置的设备主题usermod 追加/temperature子主题发布因此下游 Home Assistant 等系统订阅你的设备主题/temperature即可。WLED_DISABLE_MQTT条件编译如果构建时用 build flag 禁用了 MQTT这段代码不编译运行期还要检查mqtt ! nullptr——源码注释特别提到不检查会让 ESP8266 崩溃。Celsius宏决定温标定义时#define Celsius以 0.5 °C 步进的整数摄氏度发布取消定义则按×1.8 32换算为华氏度。BME280 版对应地在UpdateBME280Data()里切换BME280::TempUnit_Celsius与TempUnit_Fahrenheit压力单位固定为 Pa。start0的含义循环里每次发布前再调一次Dallas(pin, 0)只读 Scratchpad 并重新发起转换但不阻塞等待实现“读的同时预热下一次”。BME280 版发布的是三个主题usermod_bme280.cpp同一 60 秒节拍内连续发布UpdateBME280Data(); // 读取并缓存 temp / hum / pres单位所选温标、%、Pa mqtt-publish(t.c_str(), 0, true, String(SensorTemperature).c_str()); // deviceTopic/temperature mqtt-publish(p.c_str(), 0, true, String(SensorPressure).c_str()); // deviceTopic/pressure mqtt-publish(h.c_str(), 0, true, String(SensorHumidity).c_str()); // deviceTopic/humidityUpdateBME280Data()调用bme.read(pres, temp, hum, tempUnit, presUnit)后把结果写入三个全局 float初值均为NANBMP280 的湿度将保持 NaN。userLoop 下半段屏幕刷新与自动熄屏显示部分是一个“5 秒一拍、按需重绘”的节流状态机usermod.cpp节拍控制#define USER_LOOP_REFRESH_RATE_MS 5000距上次检查不足 5 秒直接return。自动熄屏lastRedraw之后 3 分钟3*60*1000ms没有任何重绘就u8x8.setPowerSave(1)关机屏并置displayTurnedOff下次需要重绘时先setPowerSave(0)唤醒。变更检测与“上次已知值”knownSsid/knownIp/knownBrightness/knownMode/knownPalette逐一比对任一项变化才置needRedraw trueif (((apActive) ? String(apSSID) : WiFi.SSID()) ! knownSsid) { needRedraw true; } else if (knownIp ! (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) { needRedraw true; } else if (knownBrightness ! bri) { ... } else if (knownMode ! strip.getMainSegment().mode) { ... } else if (knownPalette ! strip.getMainSegment().palette) { ... }注意两个细节AP 模式apActive下 IP 被固定显示为占位值4.3.2.1ESP8266 版的 SSID 也改用WiFi.softAPSSID()真实 IP 只在 STA 模式下取WiFi.localIP()效果/调色板取自strip.getMainSegment()的主段即 UI 上你正在操作的那个灯段。四行两图标布局重绘时行内容说明第 1 行SSID超过列宽截断并在末尾补~表示被截断左侧配 WiFi 图标open_iconic 80 号字形第 2 行IP或 AP 模式且bri 0时的 AP 密码左侧 Home 图标68 号字形这是“无屏配网”的实用设计——忘记密码时把灯关掉就能看到第 3 行灯效名通过extractModeName(knownMode, JSON_mode_names, ...)取 16 字符以内名称左侧太阳/月亮图标表示亮/灭bri 0时切到亮月字形 69否则 66第 4 行调色板名extractModeName(knownPalette, JSON_palette_names, ...)灯效名/调色板名的提取由 WLED 主程序提供extractModeName()定义于 wled00/util.cpp声明见 wled00/fcn_declare.h它从strip.getModeData(mode)拷贝到遇到\0或SR 扩展分隔符为止并保证写入长度不超过maxLen。usermod 传入 16 字节缓冲、上限 15正好适配 128x32 屏每行 32 列的版式。这也体现了 v1 usermod 的典型模式usermod 只做外设交互状态数据SSID、IP、亮度bri、灯段 mode/palette全部复用 WLED 全局变量与工具函数。两套版本怎么选、有哪些限制DallasDS18B20版只需温度占一个 GPIOD1 mini 的 13 / Wemos32 mini 的 23依赖OneWireDallasTemperature温度精度 0.5 °C12 位读取发布为整数。BME280 版温度 湿度 气压三合一走 I2C 与 OLED 共享 SDA/SCLWLED 的 I2C 默认引脚与此处Wire.begin(SDA_PIN, SCL_PIN)一致D1 mini 为 4/5依赖BME280~3.0.0注意若实际芯片是 BMP280湿度无意义。显示刷新是事件驱动 5 秒节拍的任何一项SSID/IP/亮度/灯效/调色板变化最坏 5 秒内上屏静态场景 3 分钟熄屏。该 usermod 属 v1 API直接替换wled00/usermod.cpp同一构建只能启用一个 v1 usermod 文件若需要多个 usermod 共存或更多 API仓库推荐转向 v2 usermod API可参考 usermods/readme.md 中提到的EXAMPLE_v2与Temperature示例。由于它直接引用mqtt、mqttDeviceTopic、bri、apActive、apPass、strip等 WLED 内部全局符号随 WLED 大版本演进存在兼容风险这与 usermods/readme.md 中“usermods 可能随 WLED 更新而损坏、维护责任在作者”的声明一致。小结这个 Wemos 扩展板 usermod 用约 200 行代码演示了 v1 usermod 的完整套路在userSetup中初始化 I2C 外设OLED 用 U8g2 的硬件 I2C 构造BME280 用带重试的begin()在userLoop中做“定时遥测 节流失效重绘 低功耗熄屏”三件事并全部复用 WLED 的全局状态与工具函数extractModeName、mqttDeviceTopic、主灯段 mode/palette。配合 readme 给出的 PlatformIO 依赖清单U8g2、OneWire/DallasTemperature或BME280再按当前仓库的platformio_override.ini机制补齐d1_mini构建环境即可得到一台带状态屏、能自我熄屏、并把环境数据持续推给 MQTT 的 WLED 控制器。【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLED创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考