ESP32-C3 智能开关面板案例
案例概述
本例介绍采用 ESP32-C3 的 1/2/3 开零火智能开关面板。以用户提供的三开面板照片和 ESP32C3.ino 为依据,将三个物理按键分别绑定到三路继电器:短按释放后翻转对应通道,也可通过 FastBee Web 控制和查看输出状态。
资料核对完成,实物待验证。 配图是用户提供的硬件参考图,不是本次部署或测试照片;本文不代表该面板已经烧录 FastBee、完成带载测试或通过长期稳定性验收。继电器软件状态也不等于触点或灯具的实际反馈。

图 1:用户提供的《基础展示.jpg》,保留原图。图中的“1开/2开/3开”同时标示通道位置;购买的单开、双开型号可能未焊接其余通道器件,只配置实物存在的通道。
硬件准备与固件选择
| 项目 | 准备与核对要求 |
|---|---|
| 面板 | ESP32-C3 零火版,核对型号、板本、1/2/3 开数量及端子丝印 |
| 固件 | 实际确认 4MB Flash、无 PSRAM 后选择 esp32c3-F4R0;不由外观推断容量 |
| 下载与日志 | 核实板上 RXD、TXD、RST(EN)、下载模式引脚、3.3V、GND 的实际定义,采用厂商确认的 UART 下载/日志方案 |
| 配置工具 | 同一局域网的浏览器;保留当前网络、认证、MQTT 与其他外设配置的备份 |
| 测试条件 | 先确认板级供电和隔离方案,再在允许条件下检查按键、输出和状态;带载测试另行记录 |
本面板 GPIO18、GPIO19 已分别用于第 1 路继电器和第 3 路按键,而它们又是 ESP32-C3 原生 USB Serial/JTAG 的 D−、D+ 引脚。下载、日志与按键/继电器不能同时占用这两根线。先核对 USB 复用、控制台配置及已配置外设,不通过关闭冲突检查强行保存。芯片复用关系见 Espressif 内置 USB/JTAG 说明。
esp32c3-F4R0 是 4MB 单应用分区目标,不提供 A/B OTA。固件与文件系统分别使用匹配目标的制品,步骤见烧录教程与分区布局。
本例与 C3 温湿度案例是不同硬件。四设备测试中的 COM4 现有公开配置用于 DHT11、LED、OLED;不能仅因同为 C3 就把 COM4 当成此开关面板,也不能将本文继电器引脚覆盖到 COM4。专用测试配置须在实际面板身份和接线确认后建立,并与四设备配置分开管理。
引脚与极性
下表由原图和原始代码交叉核对,不套用其他 C3 开发板的 LED 或 BOOT 按键定义。
| 通道/用途 | 按键输入 | 继电器输出 | 行为 |
|---|---|---|---|
| 第 1 路 | GPIO4,内部上拉 | GPIO18 | 按键 LOW 有效;继电器 HIGH 开、LOW 关,初始化关 |
| 第 2 路 | GPIO3,内部上拉 | GPIO5 | 同上 |
| 第 3 路 | GPIO19,内部上拉 | GPIO1 | 同上 |
| 独立状态 LED | — | GPIO10 | 示例写 LOW,注释说明亮;极性仍需本板实测 |
GPIO10 是独立状态 LED,不能等同于照片上的三路开关状态灯;资料没有给三路状态灯各自独立的 GPIO,不为它们新增猜测的输出。
接线说明

图 2:用户提供的《接线参考.jpg》,保留原图。图示 N 为零线、L 为火线输入,L1/L2/L3 为对应负载的受控输出;本型号必须有零线,不能当作单火开关使用。实际接线以实物丝印和该型号说明书为准。
市电接线由具备资质的人员在断电、验电后完成。隔离方式未经核实时,不在接通市电的同时连接电脑 USB/UART 调试;照片中的 3.3V 标记不代表已经确认的安全供电注入点。先取得板级供电、隔离及下载接线资料,不猜测低压地与市电是否隔离。
图示 AC220V 和负载标签仅是资料标识,不能据此推定每路或整机的触点额定值、隔离等级、感性/容性负载能力或带载实测结果。按键低压逻辑检查与市电负载验收分开记录。
原始 Arduino 示例
下载原始 ESP32C3.ino。该文件按原样保留,来源为用户提供的“ESP32按键控制继电器ArduinoIDE示列/ESP32C3”资料。
示例需要 Arduino ESP32 开发环境及 OneButton 库;原文件未锁定库版本,复现时记录使用的版本。它是独立按键演示,不包含 FastBee Web、MQTT、配置持久化或规则引擎,不应覆盖进 FastBee 工程的主循环。
OneButton button4(4, true)、button3(3, true)、button19(19, true)定义三个低电平有效按键,setup()将对应 GPIO 设为INPUT_PULLUP。- 三个
attachClick回调分别执行 GPIO4 → GPIO18、GPIO3 → GPIO5、GPIO19 → GPIO1 的读取、取反和写回。 setup()将 GPIO18、5、1 写 LOW,使继电器初始化关闭;GPIO10 同样写 LOW,但原注释表示状态 LED 亮。loop()持续调用三个tick()推进按键状态机,没有在示例循环中加入阻塞等待。回调表示库识别的单击,不是按下、释放两沿各翻转一次。
初始化写 LOW 只说明软件开始运行后的设定,不能证明复位、下载或上电瞬间没有脉冲;这部分必须测量实际输出和负载。
FastBee Web 配置
1. 备份与准备
按快速开始完成配网,使用实际 STA 地址登录。先导出本机配置,并在高级配置用当前密码开启开发模式,再在“外设配置”核对现有 GPIO 占用;本案例只新增经过确认的通道,不导入其他板卡的整套配置,也不改动本机网络和平台凭据。首次配置先保持规则禁用,核对输入与输出后逐条启用。
2. 创建受管按键和继电器
在“外设配置”中为每个实际存在的通道新增两个外设。三开型号使用以下 ID,单开/双开只保留对应行:
| 按键 ID | 类型 / 引脚 | 输出 ID | 类型 / 引脚 |
|---|---|---|---|
panel_btn1 | GPIO 数字输入上拉(type: 13)/ 4 | panel_relay1 | GPIO 数字输出(type: 12)/ 18 |
panel_btn2 | GPIO 数字输入上拉(type: 13)/ 3 | panel_relay2 | GPIO 数字输出(type: 12)/ 5 |
panel_btn3 | GPIO 数字输入上拉(type: 13)/ 19 | panel_relay3 | GPIO 数字输出(type: 12)/ 1 |
按键的“输入电气模式”选择“内部上拉”(params.inputMode: 2),不勾选“反相逻辑”(params.invertLogic: false),去抖时间从 50ms 开始(params.debounceMs: 50),实测后记录最终值。低有效由上拉按键类型与实际按下电平决定,不需为此额外启用反相。
继电器选择原生 GPIO,初始状态“低电平”(params.initialState: 0);本板高有效,开为 HIGH、关为 LOW。保持普通受管输出,不设为被动输出、不启用 PWM。以下是第 1 路字段示意,不是可直接导入的配置包:
{
"peripherals": [
{"id":"panel_btn1","name":"面板按键1","type":13,"enabled":false,"pins":[4],"params":{"inputMode":2,"invertLogic":false,"debounceMs":50}},
{"id":"panel_relay1","name":"面板继电器1","type":12,"enabled":false,"pins":[18],"params":{"initialState":0,"passive":false,"invertLogic":false}}
]
}通过页面保存并检查预检结果;发生引脚占用、板型不符或资源拒绝时先解决冲突。不要用裸 digitalWrite() 回调绕过 FastBee 外设管理。
独立状态 LED 为可选项:确认 GPIO10 无其他用途后才新增普通数字输出。若核实该板 LOW 亮,要区分“低电平”与“关闭”的含义;不将它纳入三路继电器的开关规则。
3. 配置单击联动
进入“外设执行”,每一路创建一条规则,触发类型选“事件触发”,事件选“按键单击”,明确选择该路按键作为触发外设;动作选“电平翻转”,目标选择对应继电器,动作参数留空。
| 规则 | 触发外设 triggerPeriphId | 事件 eventId | 动作目标 targetPeriphId |
|---|---|---|---|
| 第 1 路单击翻转 | panel_btn1 | button_click | panel_relay1 |
| 第 2 路单击翻转 | panel_btn2 | button_click | panel_relay2 |
| 第 3 路单击翻转 | panel_btn3 | button_click | panel_relay3 |
对应真实规则字段为 triggerType: 4、actionType: 30、actionValue: ""、useReceivedValue: false。第 1 路核心配置示意如下;完整规则由页面保存,不把片段当作配置包导入:
{
"triggers": [{"triggerType":4,"triggerPeriphId":"panel_btn1","eventId":"button_click"}],
"actions": [{"targetPeriphId":"panel_relay1","actionType":30,"actionValue":"","useReceivedValue":false,"syncDelayMs":0,"execMode":0}]
}当前 FastBee 源码在去抖后的释放时判断完整短按:该按键没有双击规则时,短按释放立即发出单击;配置双击规则后才等待默认 300ms 的多击窗口。本例仅配置单击。按住达到 2 秒属于长按,释放不再发出本例的单击;持续按住也不会周期翻转。它与 OneButton 的“单击回调翻转”目标一致,但长按阈值和多击识别时序不保证与未锁版本的 OneButton 完全相同。
不要同时绑定 button_press、button_release 或通用电平变化来翻转同一路,否则一次按放可能产生两次动作。核验依据为固件的 PeriphExecScheduler.cpp、PeripheralExecution.h 及当前 Web 表单;实际部署后仍须验证快速连按与按住行为。
4. Web 手动控制与状态同步
在“外设执行”的对应规则行点击“执行一次”,即可从 Web 手动翻转同一路继电器,无需模拟按键事件。先读回初始 LOW,再执行一次检查 HIGH,再执行一次检查 LOW,并核对实际通道。需要明确开/关动作时,其动作类型分别为“高电平”(actionType: 0)和“低电平”(actionType: 1);不要使用反转高低电平动作来控制本板。“外设配置”的启用/禁用按钮控制外设生命周期,不是继电器开/关按钮。
物理按键规则和 Web 控制必须指向同一个 panel_relayN,由同一受管输出更新状态。操作后重新读取该外设状态;调试时可使用已认证的只读接口 GET /api/peripherals/read?id=panel_relay1,对应接口要求见 API 参考。再测试“Web 关闭 → 按键单击打开”和“按键关闭 → Web 打开”。配置中的初始状态不等于实时状态,界面成功提示不等于触点实际吸合;显示未更新时检查请求错误、SSE/轮询恢复和日志,不凭旧值判定成功。
本地按键规则不依赖 MQTT 或浏览器常开。断网时是否仍能正常控制、恢复联网后的状态同步与重启后的配置保持,需要下述实际验收确认。
首次检查与验收
所有项目初始均为待验证;只在实际面板、供电和负载条件已确认时执行。记录芯片/MAC、板本、固件/Web 摘要、配置导出、测试时间、观察人和异常;公开报告不包含网络或 MQTT 密钥。
| 项目 | 操作与期望 | 当前证据 |
|---|---|---|
| 身份与映射 | 确认实际面板和通道数量,三路按键、Web 输出与实物一一对应 | 资料已核对,实物待验证 |
| 单次短按 | 每路连续进行至少 10 次完整按放,每次只翻转对应通道一次 | 待验证 |
| 按住与连按 | 短按释放生效;按住超过 2 秒不重复切换;按去抖能力测试快速连按并记录间隔 | 待验证 |
| 默认关闭 | 冷启动、复位和软件重启后初始化关闭;测量启动瞬间是否有异常脉冲 | 待验证 |
| Web 同步 | 桌面/手机交替控制,再按实物按键;读回与实际通道一致,无永久加载或旧值误报 | 待验证 |
| 配置恢复 | 保存、重新读取、重启后仍保留正确引脚/规则,网络和认证未被覆盖 | 待验证 |
| 离线控制 | 断开网络后本地短按仍可用;恢复网络后 Web 显示实际状态 | 待验证 |
| 负载与长稳 | 合格条件下另做真实负载及连续运行检查,记录温升、复位、丢事件和网络异常 | 待验证 |
故障排查
| 现象 | 核对方向 |
|---|---|
| 按键一次却切换两次 | 是否同时绑定按下/释放/单击,是否存在重复规则;检查去抖与实际事件日志 |
| 长按释放没有切换 | 本例使用完整短按事件,FastBee 达到 2 秒走长按路径;不是默认故障 |
| 第 1/3 路异常或 USB 消失 | 检查 GPIO18/19 的 USB 复用与下载/日志方案,不强行共享 |
| 按第 1 路却切换其他负载 | 对照 GPIO4→18、GPIO3→5、GPIO19→1 和目标外设 ID,核对实物端子 |
| 全部按键不生效 | 规则是否启用、触发外设是否填写、输入是否上拉、读数是否随按放改变 |
| 开关方向相反 | 继电器 HIGH 开、LOW 关;检查是否误用反相动作;GPIO10 LED 单独判断 |
| 重启时负载闪动 | 软件初始 LOW 不覆盖启动早期;停止带载调试并核查硬件偏置与启动波形 |
| 页面已开但灯不亮 | 分开检查软件读回、继电器触点与负载,不能把 UI 状态当物理反馈 |
| 保存被拒绝 | 查看引脚/资源预检提示和实际板型,勿删除保护或套用另一台 C3 配置 |

