基于ESP8266与TLC59116的16路LED Web控制方案详解
1. 项目概述与核心价值
如果你手头有一堆LED灯带,或者想给家里的照明系统做个智能升级,但又不想被那些成品智能灯具的封闭生态和价格劝退,那这个基于ESP8266的16路Web控制项目可能就是你的菜。我折腾这个的初衷很简单:我需要一个能独立运行、不依赖任何云服务、并且能让我通过手机或电脑浏览器就能精细控制每一路灯光亮度的系统。ESP8266这颗几块钱的Wi-Fi芯片,加上一个I2C接口的LED驱动芯片,就能轻松实现这个目标。
这个项目的核心,是构建一个运行在ESP8266上的嵌入式Web服务器。它不像你手机访问的百度、淘宝那样需要庞大的数据中心,而是直接把网页文件(HTML、CSS、JavaScript)存储在ESP8266自己的闪存(SPIFFS)里。当你用设备连接到ESP8266创建的热点或者同一个局域网时,打开浏览器输入它的IP地址,就能看到一个专属的控制面板。在这个面板上,一个房间布局图直观地展示了16个LED的位置,点击对应的区域就能开关;更关键的是,旁边16个垂直滑块,让你能像调节手机屏幕亮度一样,从0到255无级调节每一路LED的亮度,这就是PWM调光的魔力。
PWM,也就是脉宽调制,是微控制器控制模拟输出(比如LED亮度、电机速度)的经典方法。它通过快速开关数字引脚,改变一个周期内“开”状态的时间比例(占空比)来模拟不同的电压水平。占空比0%就是常关,100%就是常开,50%就是半亮。ESP8266本身的GPIO虽然也能输出PWM,但引脚数量和驱动能力有限。所以,我选择了TLC59116这款专门的16通道恒流LED驱动芯片,通过I2C总线与ESP8266通信,一颗芯片就能优雅地解决16路LED的独立PWM控制和供电问题,让主控芯片从繁重的IO管理中解放出来。
整个系统的工作流程是这样的:你在网页上拖动一个滑块,JavaScript会立刻把这个动作(比如“第3路LED,亮度调到180”)通过一个HTTP GET请求发送给ESP8266的服务器。服务器解析这个请求,通过I2C向TLC59116芯片写入对应的PWM寄存器值。芯片随即改变对应输出通道的占空比,LED的亮度瞬间发生变化。同时,网页会通过另一个定时请求,从服务器获取所有LED的当前亮度值,并实时更新滑块位置和房间布局图中对应区域的边框颜色,实现状态同步。这一切都在你的本地网络中进行,响应速度快,没有隐私担忧,硬件成本极低,可玩性和可定制性却非常高。
2. 硬件架构与核心器件选型
2.1 ESP8266:物联网的“瑞士军刀”
选择ESP8266(我常用的是NodeMCU或Wemos D1 mini开发板)作为主控,几乎是这类项目的标准答案。原因有三:第一是性价比无敌,集成了Wi-Fi和TCP/IP协议栈,让你用最低成本接入网络;第二是生态成熟,Arduino Core for ESP8266提供了极其友好的开发环境,网络、文件系统、Web服务器等都有现成库支持;第三是性能足够,80MHz的主频和几十KB的RAM,运行一个轻量级Web服务器并处理I2C通信绰绰有余。
这里有个实操细节:ESP8266的闪存(Flash)通常有4MB,我们将其划分为两部分,一部分存放程序固件,另一部分则用作SPIFFS(SPI Flash File System)来存储网页文件。在Arduino IDE中,你需要使用“ESP8266 Sketch Data Upload”工具,将编写好的HTML、CSS、JS文件上传到SPIFFS分区。这样,你的网页界面就成为了固件的一部分,设备上电后就能直接提供服务,无需依赖外部SD卡。
2.2 TLC59116:16路LED的专职“管家”
为什么不用ESP8266的GPIO直接控制16个LED?首先,GPIO数量可能不够(尤其是像D1 mini这种板子);其次,驱动能力有限,每个引脚只能输出十几毫安电流,点亮高亮度LED或灯带力不从心;最后,软件模拟16路PWM会严重消耗CPU资源。TLC59116完美解决了所有问题。
这是一款通过I2C总线控制的16通道恒流LED驱动器。每个通道都有独立的8位PWM寄存器和可编程的电流增益寄存器。简单来说,你只需要连接两根I2C线(SDA, SCL)到ESP8266,再给芯片供上电(3.3V或5V),它就能帮你管理16路LED。每路最大可提供120mA的恒定电流,足以驱动普通的LED灯珠或小功率灯带。它的I2C地址可以通过硬件地址引脚(A0-A3)配置,这意味着一条I2C总线上可以挂载多个TLC59116,轻松扩展出32、48甚至更多路控制,这是单纯使用GPIO无法比拟的扩展性。
接线时务必注意:ESP8266的I2C引脚通常是D1(SCL)和D2(SDA)。TLC59116的VCC接3.3V或5V(需与ESP8266逻辑电平匹配),GND共地。每个LED通道的输出端(OUT0-OUT15)串联一个限流电阻后接LED阳极,LED阴极接地。芯片的/OE(输出使能)引脚可以接一个GPIO用于全局开关,但在本项目中我们直接将其接地,让芯片始终使能,通过PWM寄存器来控制亮灭。
注意:电源隔离与滤波。当同时驱动多路大功率LED时,瞬间的电流变化可能引起电源电压波动,干扰ESP8266的稳定运行。一个可靠的方案是,为TLC59116的功率部分(VCC和LED电源)使用独立于ESP8266的电源供电,两地之间在靠近芯片的位置用一颗100uF的电解电容并联一颗0.1uF的陶瓷电容进行滤波。如果使用同一电源,则必须确保其额定电流足够,并在靠近两个芯片的电源引脚处都放置去耦电容。
2.3 整体电路连接与布局要点
一个典型的连接示意图如下,但实际焊接或使用面包板时,有几点必须注意:
- I2C上拉电阻:ESP8266的I2C总线(SDA, SCL)必须接上拉电阻到3.3V,阻值通常在4.7kΩ到10kΩ之间。很多开发板已内置,如果使用裸芯片或自定义PCB,务必自行添加。
- 电平匹配:确保TLC59116的逻辑电平与ESP8266的3.3V匹配。如果TLC59116采用5V供电,其I2C引脚是否能容忍3.3V输入需要查 datasheet。稳妥起见,整个系统使用3.3V供电最方便。
- 布线:功率线(给LED供电的VCC)和信号线(I2C、GPIO)尽量分开走线,避免噪声耦合。如果线路较长,可以考虑使用双绞线。
ESP8266 (NodeMCU) TLC59116 3.3V --------------- VCC GND --------------- GND D1 (SCL) ------------ SCL (接4.7k上拉至3.3V) D2 (SDA) ------------ SDA (接4.7k上拉至3.3V) /OE ------------ GND (始终使能) OUT0~OUT15 ----[限流电阻]---- LED+ (共16路) LED- ------------ GND3. 固件程序设计:Web服务器与业务逻辑
项目的固件代码是核心,它需要完成网络连接、Web服务器搭建、I2C通信、PWM控制等多个任务。代码结构清晰,主要分为几个模块:主程序设置、网络凭证管理、HTTP请求处理、工具函数以及TLC59116驱动。
3.1 网络连接与Web服务器初始化
在setup()函数中,我们完成了所有初始化工作。首先,设备会尝试读取EEPROM中保存的Wi-Fi凭证(SSID和密码)。如果存在,则连接现有Wi-Fi网络;如果不存在或连接失败,ESP8266会启动一个软接入点(SoftAP),默认SSID为“ESP_LED_TLC59116”,密码“12345678”。这样,即使用户身处没有配置过的网络环境,也能通过连接这个热点来访问控制页面并配置Wi-Fi。
// 设置软AP参数 const char *softAP_ssid = "ESP_LED_TLC59116"; const char *softAP_password = "12345678"; WiFi.softAP(softAP_ssid, softAP_password); // 启动DNS服务器,实现强制门户(Captive Portal)效果,手机连上AP自动弹出配置页 dnsServer.start(DNS_PORT, "*", apIP);接着,初始化SPIFFS文件系统,并配置Web服务器。关键的一步是使用server.serveStatic将特定的URL路径映射到SPIFFS中的文件夹。例如,server.serveStatic("/", SPIFFS, "/index.html")意味着当访问根路径时,服务器会自动寻找并发送SPIFFS中/index.html文件。同理,/js、/css、/img路径分别对应存放JavaScript、样式表和图片的文件夹。这种静态文件服务的方式,使得前端资源的加载和管理变得非常高效。
// 配置静态文件服务 server.serveStatic("/", SPIFFS, "/index.html"); server.serveStatic("/js", SPIFFS, "/js"); server.serveStatic("/css", SPIFFS, "/css"); server.serveStatic("/img", SPIFFS, "/img");3.2 HTTP路由与业务处理
Web服务器的核心是路由,即定义不同的URL该由哪个函数来处理。我们使用server.on()方法来绑定路由。
/LEDpwm:处理PWM调光请求。当网页滑块被拖动时,会发送如/LEDpwm?LED=3&PWM=180的请求。handleLED_pwm()函数解析URL中的参数(LED编号和PWM值),更新内部的亮度数组,并调用Set_LED_PWM()函数通过I2C设置TLC59116的对应寄存器。/LEDswitch:处理LED开关请求。请求如/LEDswitch?LED=5会切换第5路LED的开关状态(如果当前亮度>127则关,否则开)。不带参数的/LEDswitch请求则会切换所有LED的状态。/readLED:前端定时轮询或需要同步状态时调用。handleStatusLED()函数将当前16路LED的亮度数组封装成一个JSON字符串(例如{"LEDpwm": ["32","64","255","0",...]})返回给前端。/upload:提供文件上传接口,允许用户通过网页上传新的界面图片、CSS或JS文件到ESP8266的SPIFFS中,实现UI的无线更新。/reboot:重启ESP8266设备。/wifi和/wifisave:提供Wi-Fi配置页面,用户可以在浏览器中扫描并选择网络、输入密码,新的凭证会被保存到EEPROM,设备随后尝试连接。
handleLED_pwm()函数的实现展示了典型的请求处理流程:
void handleLED_pwm() { BLINKPIN_ON(); // 用状态LED指示有操作发生 // 解析URL参数,例如 /LEDpwm?LED=3&PWM=180 int ledIndex = server.arg(0).toInt(); // 获取第一个参数"LED"的值 int pwmValue = server.arg(1).toInt(); // 获取第二个参数"PWM"的值 if (server.args() > 1 && ledIndex >=0 && ledIndex <16) { BRIGHTNESS_Array[ledIndex] = pwmValue; // 更新内部数组 Set_LED_PWM(ledIndex, pwmValue); // 通过I2C设置硬件 send_LED_ALL_Array(); // 更新用于JSON序列化的字符串 } // 发送302重定向,让浏览器跳转回首页,实现操作后页面刷新 server.sendHeader("Location", "/", true); server.send(302, "text/plane", ""); BLINKPIN_OFF(); }实操心得:状态同步与防抖。在类似的控制系统中,状态同步是关键。这里采用了“前端主动查询”的方式:页面加载后,JavaScript定时(例如每秒)向
/readLED发送请求,获取所有LED的最新亮度并更新UI。这种方式简单可靠,但会产生持续的HTTP请求。另一种更高效的方案是WebSocket,它允许服务器主动向客户端推送状态变化,实现真正的实时同步,但代码复杂度会稍高。对于16路LED控制,1秒的轮询间隔完全足够,且对ESP8266负载很小。
3.3 TLC59116驱动函数详解
与TLC59116的通信完全通过I2C(Wire库)进行。芯片的I2C地址是0xC0(7位地址模式为0x60)。驱动函数主要做三件事:初始化、设置单路PWM、设置所有路PWM。
初始化init_TLC59116():这个函数在上电时执行一次,通过I2C向TLC59116写入一系列配置寄存器。关键设置包括:
- 设置模式寄存器(MODE1, MODE2),通常保持默认值即可。
- 将所有16个PWM寄存器(0x02-0x11)清零,即初始亮度为0。
- 设置LED输出状态寄存器(0x14-0x17)为
0xAA。这个寄存器的每两位控制一个通道的输出模式:00为关,01为全开,10为PWM模式,11为组调光模式。0xAA的二进制是1010 1010,即每个通道都设置为10,也就是PWM模式,这是我们需要的。 - 设置组控制寄存器等,在本项目中未使用组功能,可忽略。
设置单路PWMSet_LED_PWM(int LED, int PWM):这是最常用的函数。它根据LED编号(1-16)计算出对应的PWM寄存器地址(寄存器0x02对应LED1,所以地址是0x01 + LED),然后通过I2C写入目标亮度值(0-255)。同时,更新内部的BRIGHTNESS_Array数组以保持状态一致。
设置所有路PWMSet_LED_ALL(int PWM):这个函数使用了TLC59116的“自动地址递增”功能。首先写入起始寄存器地址0x82(即0x02寄存器,并设置自动递增位),然后连续写入16个相同的PWM值。I2C传输结束后,芯片会自动将这16个值依次填入0x02到0x11寄存器,效率远高于循环调用16次Set_LED_PWM。
避坑指南:I2C通信稳定性。在实际焊接或使用面包板时,I2C通信可能因干扰或上拉电阻不当而失败。如果发现LED控制无反应或时好时坏,请按以下步骤排查:
- 检查硬件连接:确认SDA、SCL、VCC、GND连接牢固,上拉电阻已正确安装。
- 降低I2C时钟频率:在
Wire.begin()后尝试Wire.setClock(100000),将时钟从默认的100kHz降为标准模式100kHz,有时能提高长距离或干扰环境下的稳定性。- 添加错误处理:在
Wire.endTransmission()后检查返回值。如果非零(通常是4),表示通信失败(从机无应答)。可以在代码中加入重试逻辑。- 电源噪声:确保电源干净,尤其在LED开关瞬间。加大电源处的滤波电容。
4. 前端界面设计与交互实现
一个友好的控制界面是项目成功的一半。我们的前端由一个HTML文件、CSS样式和JavaScript脚本构成,它们被上传到ESP8266的SPIFFS中。
4.1 界面布局与视觉设计
HTML结构非常简单:一个标题栏,一个SVG绘制的房间地图,以及一个动态生成的滑块区域。CSS负责美化,重点在于自定义了垂直滑块(input[type="range"])的样式。通过CSS3的transform: rotate(270deg),我们将水平的滑块旋转90度,变成了垂直滑块,更符合亮度控制的直觉。同时,我们美化了滑块的轨道和拇指(thumb),使其看起来更现代。
房间地图使用SVG(可缩放矢量图形)实现。<image>标签嵌入了一张背景图(living_room_demo.png),上面叠加了16个可点击的<rect>(矩形)元素,每个矩形对应一路LED。矩形的stroke(边框)颜色会根据对应LED的亮度值动态改变,提供直观的视觉反馈。
4.2 JavaScript:动态交互与数据通信
JavaScript是前端的大脑,它负责三件事:生成UI、响应用户操作、与后端同步状态。
动态生成滑块:页面加载时,<script>标签内的代码通过一个循环,动态生成16个滑块的HTML字符串,并插入到id="sliderHTML"的<div>中。这样做比在HTML里写死16个滑块要优雅和易于维护。
响应用户操作:每个滑块都绑定了oninput事件,调用UpdateLEDdim(ledNumber, this.value)函数。这个函数会立即将新的亮度值通过XMLHttpRequest(AJAX)以GET请求的方式发送到ESP8266的/LEDpwm接口。同样,点击SVG地图上的矩形,会触发UpdateLED(ledNumber),发送到/LEDswitch接口。这种“操作即发送”的模式提供了即时的控制反馈。
状态同步:为了确保网页上显示的状态(滑块位置、边框颜色)与硬件实际状态一致,我们定义了getData()函数。它向/readLED接口发起请求,获取包含16个亮度值的JSON数组。成功返回后,解析JSON,并更新16个滑块的value属性、滑块下方的数值显示以及SVG矩形的边框颜色(亮度大于48显示为绿色渐变,否则为红色,直观表示“亮”与“暗”)。
function getData() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var obj = JSON.parse(this.responseText); for (var i = 1; i < 17; i++) { var brightness = parseInt(obj["LEDpwm"][i-1]); // 更新滑块值 document.getElementById("LEDsilder" + i).value = brightness; // 更新数字显示 document.getElementById("wertLED_K" + i).innerHTML = brightness; // 更新地图颜色 var color = brightness > 48 ? "rgb(0," + brightness + ",0)" : "red"; document.getElementById("Feld_LED_K" + i).style.stroke = color; } } }; xhttp.open("GET", "./readLED", true); xhttp.send(); }为了让状态自动同步,我们在页面加载完成后立即调用一次getData(),并可以设置一个定时器(例如setInterval(getData, 1000))每秒轮询一次。这样,即使你在另一个浏览器标签页或另一台设备上改变了灯光状态,当前页面也会在一秒内自动更新。
前端优化技巧:减少请求与防抖。虽然轮询简单,但频繁的HTTP请求在客户端很多时会增加服务器负担。一个优化点是:在
UpdateLEDdim或UpdateLED函数发送控制请求后,可以不立即调用getData(),而是设置一个短暂的延时(例如300毫秒)后再调用,或者取消未完成的旧轮询请求,发起一个新的。这可以避免在用户快速拖动滑块时产生“请求风暴”。更高级的做法是使用WebSocket,但当前轮询方案对于小规模、局域网内的控制完全可行且易于实现。
5. 文件系统管理与无线更新
SPIFFS(SPI Flash File System)是ESP8266的片上闪存文件系统,它让我们可以像操作SD卡一样存储网页文件、配置文件等。项目中利用它存储了整个Web界面(index.html, CSS, JS, 图片)。
5.1 文件上传功能实现
固件代码中为/upload路径注册了两个处理器:HTTP_GET方法返回一个简单的文件上传表单页面(upload.html),HTTP_POST方法则处理文件上传的数据流(handleFileUpload函数)。
handleFileUpload函数是核心,它处理HTTP文件上传的三种状态:
UPLOAD_FILE_START:上传开始。根据文件后缀名(.jpg,.css,.js等)决定文件在SPIFFS中的存储路径(/img/,/css/,/js/),并打开文件准备写入。UPLOAD_FILE_WRITE:正在上传。将接收到的数据块写入已打开的文件。UPLOAD_FILE_END:上传结束。关闭文件,并在串口打印上传成功的信息,同时更新内存中的存储空间统计。
这个功能极其有用。当你需要修改网页的logo、调整CSS样式、或者修复一个JavaScript bug时,你不需要重新编译和烧录整个固件,只需要通过这个上传页面,把新的文件传上去覆盖旧的即可。这大大简化了后期维护和UI迭代的流程。
5.2 SPIFFS使用注意事项
- 空间限制:ESP8266的SPIFFS分区大小在编译时确定(例如1MB)。你需要确保所有网页文件的总大小不超过这个限制。可以使用
SPIFFS.info()函数在代码中检查剩余空间。 - 文件路径:SPIFFS是扁平的文件系统,不支持真正的子目录。但通过
/在文件名中模拟目录是常见做法,如/css/style.css。服务器端的getContentType函数就是根据文件后缀名来返回正确的MIME类型,浏览器才能正确解析。 - 首次烧录:在Arduino IDE中,你需要先通过“工具”->“Flash Size”选择合适的分区方案(例如“4MB (FS:3MB OTA:~512KB)”),然后使用“工具”->“ESP8266 Sketch Data Upload”将包含网页文件的
data文件夹上传到SPIFFS。这个操作会擦除SPIFFS分区原有内容,所以务必先上传数据,再上传程序固件。
6. 系统集成、调试与扩展思路
6.1 完整部署流程
- 硬件焊接:按照原理图连接ESP8266、TLC59116和16路LED。建议先在一个通道上测试,成功后再扩展。
- 环境搭建:安装Arduino IDE和ESP8266开发板支持。安装必要的库:
ESP8266WiFi,ESP8266WebServer,DNSServer,ESP8266mDNS,EEPROM,Wire。 - 准备网页文件:在Arduino项目目录下创建一个
data文件夹,将编写好的index.html、CSS、JS和图片文件放入其中。 - 修改与配置:
- 在代码中,你可能需要根据实际硬件修改I2C引脚定义(
TLC59116_SDA,TLC59116_SCL)和状态指示灯引脚(BLINKPIN)。 - 修改软AP的SSID和密码(
APSSID,APPSK)。 - 检查TLC59116的I2C地址是否与代码中
B1100000(即0x60,7位地址)一致。如果你的芯片地址跳线不同,需要修改此处。
- 在代码中,你可能需要根据实际硬件修改I2C引脚定义(
- 烧录与上传:
- 选择正确的开发板和端口。
- 首先,使用“ESP8266 Sketch Data Upload”将
data文件夹内容上传到SPIFFS。 - 然后,编译并上传主程序固件。
- 测试与配置:
- 打开串口监视器(波特率9600),查看启动日志。设备会打印AP的IP地址(通常是
192.168.4.1)和尝试连接的Wi-Fi状态。 - 用手机或电脑连接设备发出的AP(ESP_LED_TLC59116),在浏览器打开
192.168.4.1。 - 点击“WIFI”链接,扫描并配置你的家庭Wi-Fi,保存后设备会自动重启并尝试连接。连接成功后,串口日志会显示设备获取到的局域网IP,此后你就可以通过这个IP在局域网内访问控制页面了。
- 打开串口监视器(波特率9600),查看启动日志。设备会打印AP的IP地址(通常是
6.2 常见问题排查速查表
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 上电后串口无输出 | 电源问题,USB线仅供电,串口芯片故障 | 检查USB线是否支持数据传输,尝试更换USB口或线,检查开发板上的电源指示灯。 |
| 能连接AP,但无法打开192.168.4.1 | DNS劫持(强制门户)未生效,浏览器缓存 | 尝试使用http://192.168.4.1/wifi直接访问,或清除浏览器缓存,使用手机浏览器。 |
| 网页能打开,但控制LED无反应 | I2C通信失败,TLC59116未正确初始化,LED接线错误 | 1. 检查串口日志,看init_TLC59116是否有错误。2. 用万用表测量SDA/SCL电压,应为3.3V且上拉正常。 3. 单独测试一个LED通道,确认正负极和限流电阻。 |
| 控制有反应但LED不亮或常亮 | PWM值设置错误,LED输出模式寄存器配置错误 | 检查init_TLC59116函数中LED输出状态寄存器(0x14-0x17)是否设置为0xAA(PWM模式)。检查Set_LED_PWM函数写入的值是否在0-255之间。 |
| 文件上传失败 | SPIFFS空间不足,文件路径错误,上传文件过大 | 检查串口日志中SPIFFS的存储信息。确认上传的文件后缀名与代码中handleFileUpload判断的路径匹配。 |
| 网页样式错乱或JS不执行 | 浏览器缓存了旧文件,SPIFFS文件损坏 | 强制刷新浏览器(Ctrl+F5)。通过上传功能重新上传CSS/JS文件。检查浏览器开发者控制台(F12)的Network和Console标签页,看是否有404错误。 |
| 设备频繁重启 | 电源功率不足,代码中有内存泄漏或看门狗超时 | 使用外部5V/2A以上电源适配器为系统供电,避免仅靠USB。检查代码中是否在长时间循环中调用了delay()而未处理看门狗(yield()或ESP.wdtFeed())。 |
6.3 项目扩展与进阶玩法
这个16路Web控制框架是一个强大的起点,你可以在此基础上进行多种扩展:
- 多区域与场景控制:在前端页面上增加“场景”按钮,如“阅读模式”、“影院模式”、“聚会模式”。点击后,JavaScript一次性发送16个预设的PWM值到后端,后端可以新增一个
/setScene接口来处理。 - 定时与自动化:在ESP8266固件中加入NTP(网络时间协议)客户端,获取精确时间。然后可以实现定时开关、日出日落模拟等自动化功能。需要小心处理ESP8266的深度睡眠与定时唤醒的功耗平衡。
- 安全加固:目前的Web界面没有密码保护。你可以实现一个简单的HTTP基本认证,或者在
/wifi配置页后,要求用户设置一个控制页面的密码,并将其保存在EEPROM中。 - 接入主流智能家居平台:通过模拟MQTT协议,将ESP8266作为客户端连接到本地的Home Assistant、OpenHAB或云端的阿里云、腾讯云IoT平台。这样,你就可以用语音助手(天猫精灵、小爱同学)或这些平台更强大的自动化规则来控制你的灯光了。
- 硬件扩展:如前所述,I2C总线可以挂载多个TLC59116。只需修改代码,为每个芯片分配不同的I2C地址(通过A0-A3引脚设置),并扩展驱动函数,就能控制32、48甚至更多路LED。这对于控制大型LED矩阵或全屋灯光非常有用。
这个项目从硬件选型到代码实现,再到前端交互,完整地展示了一个物联网设备从零到一的构建过程。它没有依赖任何复杂的框架或云服务,所有代码都清晰可见,可控可改。无论你是想学习ESP8266网络编程、I2C设备驱动,还是想打造一个真正属于自己的智能灯光系统,它都是一个绝佳的实践案例。
