先锁定S3固件和RGB灯条,再谈氛围灯
WLED把灯光控制、网页、分段和预设集成在上游固件中,本篇使用官方预编译v16.0.1,不把它叫本站Arduino或IDF例程。本次成品是可检查的安装方案、14文件下载包、两段颜色配置与HA操作路径;本站没有刷板、点灯、连Wi-Fi或运行HA。安装器和镜像检查通过,与这些物理结果分别记录。
固定官方DevKitC-1 v1.1 / WROOM-1-N8R8:8MB Quad SPI Flash加8MB OPI PSRAM。WLED指定资产名_ESP32-S3_8MB_opi中的opi指PSRAM;不能据此套用另一块OPI Flash板的启动文件。官方控制器文档仍把S3列为实验性并不建议生产使用,本篇保持桌面学习范围,不宣称长期稳定或整屋照明适用。
灯条固定Adafruit PID3812、未裁切1m/30颗RGB SK6812,三线和24位GRB;它不是SK6812 RGBW。厂商其他SKU和批次曾换芯片,不能只看到“NeoPixel”就照抄白光通道或电流参数。
- 做到这里,你应该看到
- 板后缀、Flash、PSRAM、灯条SKU和RGB通道全部能对应具体来源。
参考:[1] WLED v16.0.1官方发布与指定S3_8MB_opi资产[2] 固定WebInstaller:S3、存储后缀和清单偏移[4] 官方控制器支持:S3仍注明实验性[5] Adafruit PID3812具体RGB SK6812灯条、电流两种口径和端点[6] PID3812厂家链接SK6812 Rev01:24位GRB与DIN/DOUT
板上GPIO只传数据,灯条电源从端子分路
采用TI SN74AHCT125N的PDIP14封装,按缺口/点确定顶视pin1。芯片供电4.5–5.5V时高输入门限2V、低门限0.8V,适合把S3的3.3V数据变成5V输出。GPIO12接2/1A,3/1Y经靠近灯条的330Ω到白线DIN,1/OE接地使能。14/VCC接5V、7/GND共地,14↔7就近100nF。未用OE4/10/13接5V、A5/9/12接地,Y6/8/11留空;不能用双向I2C转换板替代。
只使用密封稳压5V适配器PID1466的低压输出,正中心端子先核极性:板5V/J1-21走1A额定DC保险分支,灯条和缓冲器走2A分支,负端到所有GND。每支线、绝缘端子和保险座按其额定电流选用;灯条大电流不穿开发板、面包板轨或GPIO线。输入端并1000µF≥10V电容,+到5V、−到地。PID3812说这SKU不必串数据电阻,本例仍按同厂系统指南选330Ω。
USB安装与外部供电运行是两个阶段:安装时外部5V及灯条/缓冲器支路完全断开;运行灯条前拔掉全部USB,再用单适配器同时给板和灯条供电。所有改线都断电,可靠焊接排针与端子固定,鳄鱼夹只接灯条自带线到隔离端子,不夹相邻裸针。5V不能进3V3或GPIO。
| 端点 | 连接 |
|---|---|
| GPIO12 | AHCT125 pin2/1A |
| AHCT125 pin3/1Y | 330Ω→PID3812白线DIN |
| AHCT125 pin1/1OE | GND |
| AHCT125 pin14/7 | 5V/GND;100nF就近跨接 |
| DevKit5V/J1-21、GND/J1-22 | 单适配器的板分支;运行时USB拔掉 |
| 灯条红/黑线 | 5V灯条分支/GND;输入端并极性电容 |
| 未用门 | OE4/10/13到5V,A5/9/12到GND,Y6/8/11空置 |
- 做到这里,你应该看到
- 逐端追线后能指明灯条电流路径与数据路径,两个供电阶段不重叠。
参考:[5] Adafruit PID3812具体RGB SK6812灯条、电流两种口径和端点[7] TI SN74AHCT125 SCLS264R:PDIP引脚、TTL门限与未用输入[8] Adafruit NeoPixel电容、电阻、5V电平和供电次序[9] 指定稳压5V/4A适配器PID1466:输出与正中心端点[10] DevKitC-1 v1.1固定排针与互斥供电方式
先按保守电流留容量,亮度限制只是软件估算
PID3812同页既有约4.8W/m的描述,也给每段最大60mA;本例按后者预算30×60mA=1.8A、5V时9W,并另留板和缓冲器负载容量。这是选电源的计算,不是本站测得电流;4A代表适配器容量,不会强迫负载吸4A。分支保险也不能凭本文数字就宣称已完成短路动作测试。
配置只用500mA自动亮度限制和32/255初始亮度,限制器根据模型估计LED电流,并不测量导线、接触或短路。线材与保护不能按“软件已限500mA”降低容量。首次从低亮度单色红绿蓝开始,用合适量程电流表及万用表记输入/远端电压,观察端子和线材温升,逐步核真实负载;不从全白满亮开始,不把卷起/覆盖的灯条当持续散热条件。
- 做到这里,你应该看到
- 把保守预算、软件估值、额定容量与真实测量分成四个字段。
参考:[5] Adafruit PID3812具体RGB SK6812灯条、电流两种口径和端点[8] Adafruit NeoPixel电容、电阻、5V电平和供电次序[9] 指定稳压5V/4A适配器PID1466:输出与正中心端点[12] WLED16.0.1 LED设置页:Custom电流、ABL、启动亮度和预设
先只接桥USB,用安装器选8MB和S3 OPI PSRAM
保留旧固件/配置的私有备份,再在桌面Chrome或Edge打开官方安装器,选择Advanced→16.0.1→Plain→8MB→PSRAM(S3 OPI)→Flash mode Default;Basic默认4MB,不能当N8R8配置。等固件下载检测完成才点Install。本站实际打开该UI并读取生成清单,S3部分是bootloader@0、分区表@0x8000、指定app@0x10000,镜像检验为S3/8MB,应用1,232,640B能放入2MiB OTA槽;没有执行串口连接或写入。
选插拔确认的USB-to-UART桥口、关闭监视器,必要时BOOT+EN进下载,成功后松BOOT再EN。只有已备份旧内容才选择擦除;不能把应用单文件写到0,也不能用经典ESP32.bin代替S3。实际镜像报告IDF4.4.8.240628,本篇未用本站其他教程的IDF5.5.5或Arduino3.3.12重新编译这份WLED。
首次按官方默认WLED-AP/wled1234连接,AP内开4.3.2.1,Config→WiFi Setup填自己的2.4GHz网络和新AP密码。保存后电脑回同一LAN,用路由器租约查真实IP;4.3.2.1是AP地址,不是加入家庭网络后的固定地址。发现失败用IP,私有配置不入仓库,不将控制界面端口映射到公网。
- 做到这里,你应该看到
- 能从板存储类型选对资产,并区分AP地址、LAN地址与串口写入结果。
参考:[1] WLED v16.0.1官方发布与指定S3_8MB_opi资产[2] 固定WebInstaller:S3、存储后缀和清单偏移[3] 固定安装器boot资产的用途与分区[10] DevKitC-1 v1.1固定排针与互斥供电方式[11] 固定QuickStart:AP与LAN地址分开
下载包的只读检查器能核镜像,不能代替刷板
assets.lock.json固定三资产的来源、字节数、SHA和偏移;boot/分区链接固定安装器commit,应用来自官方v16.0.1 release。先在电脑安装requirements.txt里的esptool5.3.1,再把这三个官方文件按原名放同一assets目录,运行下面脚本。只检查已有文件,不会下载、打开USB或向设备发请求。完整命令见README;默认不传assets目录时只检查本地JSON并明确跳过镜像。
实际运行验证了两个S3镜像的checksum/hash、分区MD5、偏移不重叠、8MiB结尾和2MiB app0容量。SHA是本站本次下载的身份摘要,不是上游签名证书;校验成功也不能推出PSRAM、无线、供电或LED驱动已在板上工作。WLED仍为EUPL1.2+,本站包内仅原创MIT方案/检查器和上游链接,不重新分发固件。
# SPDX-License-Identifier: MIT
"""Read-only checks. Never opens a serial port, flashes or sends network commands."""
import argparse
import hashlib
import json
import pathlib
import struct
import subprocess
import sys
BASE = pathlib.Path(__file__).resolve().parent
def check_payloads():
plan = json.loads((BASE / "settings-plan.json").read_text())
assert plan["wledType"] == 22 and plan["length"] == 30
assert plan["gpio"] == 12 and plan["maxCurrentMA"] == 500
for name in ("warm-state.json", "cool-state.json"):
state = json.loads((BASE / name).read_text())
assert state["bri"] == 32 and state["on"] is True
assert [(s["id"], s["start"], s["stop"]) for s in state["seg"]] == [(0, 0, 15), (1, 15, 30)]
assert all(s["fx"] == 0 and len(s["col"][0]) == 3 for s in state["seg"])
print("PASS local JSON setup plan and two segment payloads. Not a WLED parser/runtime check.")
def check_assets(folder):
lock = json.loads((BASE / "assets.lock.json").read_text())
assert [p["offset"] for p in lock["parts"]] == [0, 0x8000, 0x10000]
assert lock["parts"][0]["bytes"] <= 0x8000
assert 0x8000 + lock["parts"][1]["bytes"] <= 0x9000
for part in lock["parts"]:
path = folder / part["name"]
content = path.read_bytes()
assert len(content) == part["bytes"], path
assert hashlib.sha256(content).hexdigest() == part["sha256"], path
assert part["offset"] + len(content) <= lock["flashBytes"]
print("PASS hash/size", part["name"], len(content))
if part["name"] != "partitions_s3_8m.bin":
subprocess.run([sys.executable, "-m", "esptool", "image-info", str(path)], check=True)
raw = (folder / "partitions_s3_8m.bin").read_bytes()
entries = []
found_md5 = False
for i in range(0, len(raw), 32):
row = raw[i:i + 32]
magic = struct.unpack_from("<H", row)[0]
if magic == 0xFFFF:
break
if magic == 0xEBEB:
assert hashlib.md5(raw[:i]).digest() == row[16:32], "partition MD5"
found_md5 = True
break
assert magic == 0x50AA, "partition magic"
_, kind, subtype, offset, size, label, flags = struct.unpack("<HBBII16sI", row)
entries.append((label.rstrip(b"\0").decode(), kind, subtype, offset, size, flags))
assert found_md5, "partition MD5 entry missing"
ordered = sorted(entries, key=lambda e: e[3])
assert all(a[3] + a[4] <= b[3] for a, b in zip(ordered, ordered[1:])), "overlapping partitions"
app = next(e for e in entries if e[0] == "app0")
assert app[3] == 0x10000 and app[4] == 0x200000
assert lock["parts"][2]["bytes"] < app[4], "application exceeds OTA slot"
assert max(e[3] + e[4] for e in entries) == 0x800000
print("PASS partition MD5, 2MiB app0 slot, non-overlap with boot/partition files, 8MiB end.")
print("No firmware compilation, USB/flash, PSRAM, radio, strip or HA runtime was tested.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--assets-dir", type=pathlib.Path, help="Existing downloaded official files; no download occurs")
args = parser.parse_args()
check_payloads()
if args.assets_dir:
check_assets(args.assets_dir)
else:
print("Asset checks skipped: supply --assets-dir after downloading the three pinned files.")
参考:[1] WLED v16.0.1官方发布与指定S3_8MB_opi资产[2] 固定WebInstaller:S3、存储后缀和清单偏移[3] 固定安装器boot资产的用途与分区
只建一个RGB输出,先让颜色和电流参数对应
灯条仍断开时,在Config→LED Preferences只保留一个WS281x RGB输出,GPIO12、Start0、Length30、GRB;不是SK6812 RGBW。mA/LED选择Custom再填60;勾Enable automatic brightness limiter,取消Use per-output limiter,Maximum PSU Current填500mA。其他按钮/继电器若占GPIO12须移除该占用。settings-plan.json是人看的核对单,不能作为完整cfg.json导入。
首次接线检查把Bootup brightness设32、Apply preset设0,取消Turn LEDs on after power up/reset,先让启动保持暗。保存、断电拔USB、接好单外部5V方案后上电,再从网页以低亮度手动开单色。红绿蓝与实际像素逐项核对;颜色错先查GRB、RGB/RGBW,尾部不亮先查30颗数量、输入箭头、接触与真实电压,不随机换一堆固件。
- 做到这里,你应该看到
- 真实单色检查、实际电压/电流与保存后的配置都有记录;网页响应不是光学证明。
参考:[5] Adafruit PID3812具体RGB SK6812灯条、电流两种口径和端点[6] PID3812厂家链接SK6812 Rev01:24位GRB与DIN/DOUT[8] Adafruit NeoPixel电容、电阻、5V电平和供电次序[12] WLED16.0.1 LED设置页:Custom电流、ABL、启动亮度和预设
把0…29分成两段,Stop端点不包含
Segment0设Start0/Stop15覆盖0…14,Segment1设Start15/Stop30覆盖15…29,Grouping1、Spacing0,不重叠;删掉或禁用额外段。网页颜色/效果会同时作用于已选中段,展开哪段不代表只选了哪段。先用Solid,把动画和布局问题分开。
warm-state.json是两段低亮度目标配置,cool-state.json在包中给第二组完整目标色;它们不是本站灯光照片或测量结果。确认供电设置后,从电脑对真实IP的/json/state发送完整文件,读回on/bri/seg/start/stop/col,再看实际像素。README的192.0.2.1是故意不可达的文档地址,必须换成路由器实际租约;命令不会自动寻找或控制陌生设备。
{
"on": true,
"bri": 32,
"transition": 7,
"mainseg": 0,
"seg": [
{
"id": 0,
"start": 0,
"stop": 15,
"grp": 1,
"spc": 0,
"of": 0,
"on": true,
"bri": 255,
"col": [
[
255,
128,
16
],
[
0,
0,
0
],
[
0,
0,
0
]
],
"fx": 0,
"sx": 128,
"ix": 128,
"pal": 0,
"sel": true
},
{
"id": 1,
"start": 15,
"stop": 30,
"grp": 1,
"spc": 0,
"of": 0,
"on": true,
"bri": 255,
"col": [
[
96,
32,
0
],
[
0,
0,
0
],
[
0,
0,
0
]
],
"fx": 0,
"sx": 128,
"ix": 128,
"pal": 0,
"sel": false
}
]
}
- 做到这里,你应该看到
- 像素14在第一段、15在第二段,30这个下标不属于灯条。
预设必须保存亮度和边界,再验证重启恢复
先读/presets.json备份已有列表,选未用ID;本文示例ID1/2若已有内容会被覆盖。应用warm-state后以psave=1、n=DeskWarm、ib=true、sb=true保存;应用cool-state同理存2/DeskCool。psave走异步保存,不能凭一次HTTP响应宣布已持久化;稍后读回预设文件并核名称/亮度/边界/颜色,再用ps=1调用验证。不要把每帧动画保存到Flash。
网页Create Preset时选择Use current state、Include brightness、Save segment bounds。启动预设另在LED设置中指定为已验证的1,之后重新上电检查两段范围和低亮度;未保存的当前状态不等于重启配置。Security & Updates里的Backup & Restore分配置和预设两份;恢复前断开灯条电源,使用同硬件/固件的私有备份,恢复后重查GPIO/count/ABL再接灯。/edit路径也能按官方文档取presets.json,但受OTA锁/文件编辑权限约束。
cfg.json/私有备份可能含网络与安全信息,不能加入Git或公开分享。下载包的settings-plan不是完整备份,不能上传冒充cfg.json。包内README保留从冷启动、误配到桥USB重写的恢复顺序,没有本站恢复成功记录。
curl --fail --max-time 5 -H 'Content-Type: application/json' --data-binary @warm-state.json http://192.0.2.1/json/state
curl --fail --max-time 5 -H 'Content-Type: application/json' --data '{"psave":1,"n":"DeskWarm","ib":true,"sb":true}' http://192.0.2.1/json/state- 做到这里,你应该看到
- 读回确认与真实重启后观察分开记录,覆盖已有ID前先保留备份。
参考:[12] WLED16.0.1 LED设置页:Custom电流、ABL、启动亮度和预设[14] WLED16.0.1 JSON解析:范围/颜色/预设[15] 固定预设文档:保存亮度/边界、psave及备份[16] WLED16.0.1预设异步保存实现[17] WLED16.0.1 Security备份/恢复页
HA按真实预设名控制,最后分层排查离线与不亮
HA Core2026.10.2在设置→设备与服务→添加集成→WLED,发现不到就填真实IP;官方要求WLED≥0.14。本例两段应对应各自灯实体及主灯,预设通过Preset select按名称选择。先确认实际选项已有DeskWarm/DeskCool并记entity_id,再把包中完整ha-package.yaml的占位ID替换为自己的实体。合并已有packages入口,执行用户HA自己的配置检查并按需重载;本站只做YAML语法与固定源码核对,没有运行HA检查/集成/脚本。
包内两脚本只供手动选择预设,没有自动触发。HA动作完成后仍逐层对照WLED状态和实际灯光。停止HA时,本地WLED网页是否能用另测;路由器断开后的恢复热点取决于你设定的AP策略,不能保证改过策略仍总出现WLED-AP。网络错先核租约/SSID/AP密码,完全不可达时断开外部灯电源,回桥USB安装并使用自己的备份。
验收依次记录低亮度RGB、0/14/15/29边界、预设1→2→1、启动预设、HA手动调用、HA关闭、本地网页、网络丢失/AP策略与备份恢复;近端/末端电压、电流和端子温升用实测值填写。整条不亮先核电源极性/共地/DIN/缓冲器OE和GPIO,只有部分不亮先核数量/分段/供电。observations.csv仍只有表头,所有这些实物与HA项保持pending。
# Replace this entity with the real WLED Preset select entity after integration.
# Merge packages into an existing HA configuration; do not duplicate top-level keys.
script:
h08_desk_warm:
alias: H08 DeskWarm preset
sequence:
- action: select.select_option
target:
entity_id: select.replace_with_real_wled_preset
data:
option: DeskWarm
h08_desk_cool:
alias: H08 DeskCool preset
sequence:
- action: select.select_option
target:
entity_id: select.replace_with_real_wled_preset
data:
option: DeskCool
- 做到这里,你应该看到
- 能够指出故障出在设备/网络/HA/配置/光学哪一层,不拿成功响应替灯光实测。
参考:[11] 固定QuickStart:AP与LAN地址分开[17] WLED16.0.1 Security备份/恢复页[18] HA WLED官方集成:版本、分段、主灯和预设[19] HA2026.10.2预设select按实际名称选择
资料来源与版本说明
实读固定WLED/安装器/文档与HA源码、具体厂家引脚和PDF;实际检查官方镜像及安装器UI,没有本站重编、刷板或HA运行。资料核对日期:。资料核对、程序构建与实板测试分别记录,不互相替代。
- WLED v16.0.1官方发布与指定S3_8MB_opi资产
- 固定WebInstaller:S3、存储后缀和清单偏移
- 固定安装器boot资产的用途与分区
- 官方控制器支持:S3仍注明实验性
- Adafruit PID3812具体RGB SK6812灯条、电流两种口径和端点
- PID3812厂家链接SK6812 Rev01:24位GRB与DIN/DOUT
- TI SN74AHCT125 SCLS264R:PDIP引脚、TTL门限与未用输入
- Adafruit NeoPixel电容、电阻、5V电平和供电次序
- 指定稳压5V/4A适配器PID1466:输出与正中心端点
- DevKitC-1 v1.1固定排针与互斥供电方式
- 固定QuickStart:AP与LAN地址分开
- WLED16.0.1 LED设置页:Custom电流、ABL、启动亮度和预设
- 固定分段文档:Stop排除、选中段与分组
- WLED16.0.1 JSON解析:范围/颜色/预设
- 固定预设文档:保存亮度/边界、psave及备份
- WLED16.0.1预设异步保存实现
- WLED16.0.1 Security备份/恢复页
- HA WLED官方集成:版本、分段、主灯和预设
- HA2026.10.2预设select按实际名称选择