1. 项目概述从零打造一台物联网饮品售卖机几年前当我第一次在展会上看到那些酷炫的自动咖啡机时心里就痒痒的能不能自己动手做一台不是那种动辄几十万的商用机器而是一个从电路板到外壳从云端到手机App全部自己掌控的智能饮品售卖机原型。这个想法一直搁置着直到我遇到了ESP32和Arduino生态发现实现它的门槛比想象中低得多。今天分享的这个“Drinkify”项目就是我带着几个朋友一起折腾出来的成果。它不仅仅是一个能出水的机器更是一个完整的物联网系统用户用手机App扫码支付机器收到云端指令后通过超声波传感器确认杯子就位再控制水泵精准出液。整个过程硬件、软件、云端、交互一个不少。这个项目非常适合那些已经玩过Arduino基础项目想向更复杂的物联网和嵌入式系统开发迈进的爱好者。你会接触到WT32-SC01这种带屏的ESP32开发板学习如何驱动它显示复杂的用户界面你会弄明白如何让设备稳定地连接Wi-Fi并与Firebase这样的云端服务进行实时数据同步你还会实战继电器控制大功率水泵、超声波传感器进行距离检测等经典电路设计。更重要的是你会经历一个产品从想法、设计、打样、调试到最终演示的全过程这其中的坑和收获远比单纯调通一个模块要多得多。2. 核心硬件选型与设计思路拆解2.1 主控单元为什么选择WT32-SC01在项目初期主控芯片的选择让我们纠结了一阵。标准的ESP32开发板如ESP32 DevKitC价格低廉、资源丰富但需要额外连接显示屏、按键等外设集成度和美观度会打折扣。而市面上一些集成屏幕的ESP32模块要么屏幕太小要么驱动复杂。最终我们锁定了WT32-SC01这是一块集成了3.5英寸电容触摸屏的ESP32开发板它几乎是为这类物联网人机交互设备量身定做的。核心考量点如下All-in-One设计板载ESP32-WROVER模组支持4MB PSRAM、RGB IPS显示屏480*320分辨率和电容触摸芯片。这意味着我们无需再为屏幕驱动、触摸接口和主控之间的连线烦恼大大简化了硬件设计和结构装配。强大的图形处理能力ESP32本身性能足够加上PSRAM可以流畅运行LVGLLight and Versatile Graphics Library这类嵌入式图形库。我们可以设计出包含图片、中文、动画和二维码的复杂用户界面用户体验直接上了一个台阶。充足的GPIO引脚尽管集成了屏幕它依然将许多常用的ESP32 GPIO引脚通过排针引出方便我们连接超声波传感器、继电器等外设。我们项目中用到的IO14、IO12、IO22等引脚都是直接可用的。供电与尺寸单路5V供电即可驱动整个板子包括屏幕功耗控制得不错。其尺寸也便于我们安装在自制的外壳内。注意WT32-SC01的屏幕排线接口比较精密在反复插拔或弯折时需要格外小心我们曾因排线接触不良导致花屏排查了很久。2.2 执行与感知单元水泵、继电器与超声波传感器水泵是整个系统的“手”负责将饮品从储液罐中泵出。我们选用的是12V直流隔膜泵。这种泵的优点在于其自吸能力、脉冲式出液易于通过控制通电时间来粗略控制流量以及对粘稠液体的适应性如果未来想卖果汁。其缺点是噪音相对较大且需要12V/2A左右的驱动能力远超ESP32 GPIO引脚的直接驱动能力。这就引入了继电器。我们使用了一个普通的5V单路继电器模块。ESP32的GPIO如IO22输出高电平3.3V即可控制继电器线圈吸合从而用继电器的触点开关来控制12V水泵电源的通断。这里的关键设计是使用了继电器的常开NO触点。这意味着在设备待机时继电器线圈不通电触点是断开的水泵的电源回路是切断的确保了安全。只有当用户支付成功ESP32给出触发信号时继电器才吸合接通水泵电源。超声波传感器HC-SR04则充当了系统的“眼睛”用于检测杯具是否放置到位。其原理是发射超声波并接收回波通过时间差计算距离。我们将它安装在出水口正下方设定一个检测范围例如2cm-5cm。当检测到该范围内有物体时才允许水泵工作一旦杯子被移开距离超出范围立即停止水泵。这个设计至关重要它避免了在无容器时误触发导致的液体洒漏是产品安全性的基本保障。2.3 电源与电路设计稳定性的基石整个系统的供电需求比较复杂WT32-SC01需要5V水泵需要12V继电器模块逻辑部分需要5V或3.3V兼容。我们采用了一个外置的12V/3A直流电源适配器作为总输入。电源电路的核心是MP1584EN降压模块。这是一个非常常用的DC-DC降压芯片我们将12V输入降压到稳定的5V为WT32-SC01和继电器模块供电。这里有一个极易踩坑的细节MP1584EN是一个可调降压模块上电前必须使用螺丝刀调节其上的可变电阻并用万用表测量输出端确保其精确输出5V绝不能直接焊接上电否则过高的电压会瞬间烧毁昂贵的WT32-SC01。我们在调试时就因为疏忽烧坏过一块板子损失惨重。为了抑制DC-DC电路可能产生的电压纹波提高系统稳定性我们在MP1584EN的输入和输出端都并联了100μF的电解电容。水泵属于感性负载在启停瞬间会产生很大的电压尖峰和反向电动势这个电容能起到一定的缓冲和保护作用。电路连接逻辑梳理12V适配器正极接入一个接线端子方便连接和断开。从该端子引出两路一路直接给水泵的12V供电回路经过继电器开关另一路接入MP1584EN的Vin。MP1584EN的Vout5V接至WT32-SC01的5V引脚和继电器模块的VCC。超声波传感器的Vcc接WT32-SC01的3.3V引脚其Trig和Echo引脚分别接IO14和IO12。继电器模块的IN引脚接ESP32的IO22控制信号地GND共地。继电器的COM端接12V正极NO端接水泵正极。水泵负极直接接12V电源负极。3. 嵌入式软件与物联网通信实现3.1 开发环境与核心库搭建我们使用Arduino IDE进行开发因为它对ESP32和众多库的支持非常友好。首先需要在开发板管理器中安装“Espressif Systems”的ESP32开发板支持包。对于WT32-SC01这块特殊的板子还需要安装其专用的显示驱动库通常是LovyanGFX它完美适配了这块屏幕的控制器并提供了LVGL图形库的底层驱动。核心库列表及作用WiFi.hESP32内置的Wi-Fi连接库用于让设备接入局域网和互联网。FirebaseESP32.h这是与Google Firebase Realtime Database进行通信的关键库。它允许设备以客户端身份监听云端数据库特定路径的数据变化实现云端指令的实时下发。LovyanGFXLVGL前者是硬件驱动层后者是图形界面框架。我们需要在代码中初始化LVGL并创建按钮、标签、二维码等UI组件。QRCode.h用于生成二维码位图数据的库。我们将随机生成的订单令牌字符串编码成二维码显示在屏幕上。软件框架的核心是一个状态机。设备上电后首先尝试连接预设的Wi-Fi。连接成功后初始化屏幕和LVGL并显示主界面。同时开启一个对Firebase数据库特定路径如devices/[device_id]/dispenserData/status的数据流监听。这个status字段是一个布尔值默认为false。3.2 二维码生成与云端握手流程这是实现“扫码支付-设备响应”的关键交互逻辑。流程如下设备端生成令牌设备启动后运行一个generateRandomString()函数生成一个8-10位的随机字母数字字符串作为本次服务的唯一“令牌Token”。这个令牌必须足够随机以防被猜测。令牌上传与显示将这个令牌字符串通过Firebase库的setString函数写入到云端数据库的另一个路径如devices/[device_id]/dispenserData/token。同时调用QRCode库将这个令牌字符串生成二维码位图并使用LVGL的API将其绘制到屏幕的指定区域。此时用户看到屏幕上显示着一个二维码。移动端扫码与支付用户使用Drinkify手机AppFlutter开发扫描这个二维码。App解析出其中的令牌字符串然后引导用户完成支付确认扣减App内余额。云端状态更新App在支付成功后向Firebase的同一个设备路径下的status字段写入true。注意这里App同时也会上传它扫描到的那个令牌用于后续验证可以放在另一个字段如verifiedToken中。设备端触发响应设备端一直在监听status字段。一旦发现其值从false变为true它不会立即动作而是先进行令牌验证读取云端刚写入的verifiedToken与本地内存中保存的当前令牌进行比较。只有两者完全一致才认为这是一次合法的支付请求而非其他错误操作或网络干扰。验证通过后设备才进入“准备出液”状态。状态重置与循环在出液完成或超时后设备会将云端的status重置为false并清空token字段。然后设备再次生成一个新的随机令牌更新到云端和屏幕等待下一次扫码。这样就确保了每个二维码只能使用一次安全可靠。实操心得Firebase的监听回调函数可能被快速调用多次直接在里面执行水泵开启等硬件操作可能导致异常。我们的做法是在监听回调里只改变一个软件状态标志位如bool shouldDispense true而在主循环loop()中根据这个标志位去执行具体的硬件控制逻辑这样更稳定。3.3 水泵控制与超声波防洒逻辑当设备通过令牌验证进入出液状态后核心控制逻辑如下// 伪代码逻辑 void controlPumpAndSensor() { if (shouldDispense) { long distance measureDistance(); // 读取超声波传感器距离 if (distance 2 distance 5) { // 杯子在有效位置2-5cm digitalWrite(PUMP_RELAY_PIN, HIGH); // 打开继电器启动水泵 updateRemainingTime(); // 更新已出液时间 if (totalDispenseTime TARGET_TIME) { // 达到目标时间如17.3秒 digitalWrite(PUMP_RELAY_PIN, LOW); // 关闭水泵 shouldDispense false; resetSystem(); // 重置状态生成新二维码 } } else { // 杯子被拿走或未放好 digitalWrite(PUMP_RELAY_PIN, LOW); // 立即停止水泵 // 记录当前已出液的时间以便杯子放回后继续 pauseDispensing(); } } }关键设计点时间定量而非流量定量由于隔膜泵的流量在一定电压下相对稳定我们采用控制开启时间的方式来粗略控制出液量。通过实验如Step 12所述我们测出灌满350ml所需平均时间为17.338秒就将此设为TARGET_TIME。这是一种低成本、易实现的方案。更精确的方案需要加入流量传感器成本会增加。中途中断续灌我们使用了一个变量elapsedTime来累计水泵实际开启的时间。如果中途杯子移开水泵停止elapsedTime会暂停累加。当杯子再次放回水泵继续工作直到elapsedTime累计达到TARGET_TIME为止。这避免了用户因调整杯子位置导致的出液量不足。死循环保护在代码中必须加入超时保护。例如从状态变为true开始一个全局计时器开始计时。如果超过2分钟仍未完成出液可能因为杯子一直没放好则强制重置整个系统关闭水泵清除状态防止设备卡死。4. 结构设计与外壳加工实战4.1 3D建模与功能分区我们使用Autodesk Fusion 360进行三维设计。设计核心围绕几个功能分区设备舱位于主体上部用于放置储液罐1L的Jerigen方形桶、水泵、主控电路板。需要考虑水泵进出水口的管道连接以及电路板的固定孔位。出水与传感舱位于设备舱下方核心是托盘Tray。这个部件是我们3D打印的。它需要设计一个凹槽用于牢固地放置和固定超声波传感器确保其探头垂直向上正对即将放置的杯口。同时托盘要引导出水管路并设计漏水孔万一滴漏液体可以流走而不积存。人机交互舱位于设备正面用于嵌入WT32-SC01屏幕。我们设计了一个托盘盖Tray-cover它既能作为屏幕的面板又能遮盖下方的线材。支撑与密封我们打印了四个支撑柱Support Pillar/Segel用于连接和固定各层结构并确保设备整体的稳固。注意3D建模时所有需要配合的孔位如螺丝孔、传感器卡槽一定要预留公差。我们最初设计的传感器卡槽太紧导致超声波传感器塞不进去后来不得不修改模型将卡槽尺寸放宽了0.3mm才解决。4.2 材料选择与低成本加工为了控制成本和加工难度我们没有选择全机身3D打印因为那会非常耗时且昂贵。我们采用了混合材料策略核心受力与精密结构托盘、托盘盖、支撑柱这些对尺寸精度和结构强度要求较高的部件使用PLA材料进行3D打印。主体外壳与设备舱采用聚苯乙烯泡沫板Polyfoam。这种材料非常轻易于用美工刀、热切割丝进行切割和塑形成本极低并且具备一定的防水性。我们用泡沫板切割出设备的外壁、隔层然后用胶水粘合形成了一个轻便且足够坚固的箱体。装配顺序建议先加工好泡沫板主体结构。将3D打印的支撑柱用胶水或螺丝固定在泡沫板的关键承重位置。安装设备舱内的组件固定储液罐和水泵连接好水管。将焊接好所有元件的PCB板固定在设备舱内预留的位置。安装托盘将超声波传感器卡入凹槽并连接其导线到PCB。将WT32-SC01屏幕安装到托盘盖上然后整体扣合到设备正面连接排线和电源线。最后进行整体走线整理用扎带固定确保没有线材干涉运动部件或散热。5. 移动应用与云端后台构建5.1 Flutter移动应用开发要点手机App是用户交互的直接入口。我们使用Flutter框架进行开发主要实现以下页面和功能用户登录/注册基于Firebase Authentication实现邮箱密码或手机号登录。钱包与余额显示每个用户在Firebase Firestore或Realtime Database中有一个文档记录其当前余额。扫码页面调用手机摄像头扫描设备屏幕上的二维码解析出令牌。支付确认页面扫码后跳转显示本次消费金额如固定3元用户确认支付。支付逻辑用户确认后App首先检查本地余额是否充足。若充足则执行两件事1) 向云端数据库对应设备的status字段写入true2) 向verifiedToken字段写入扫描到的令牌。同时更新用户云端余额减去消费金额。这个过程必须是一个原子操作或者使用Firebase的事务Transaction功能以防止并发操作导致余额扣减错误。关键点App与设备之间没有直接通信全部通过Firebase数据库这个“中间人”进行异步、解耦的交互。这大大简化了网络编程的复杂度避免了需要处理设备IP地址、端口、内网穿透等棘手问题。5.2 Firebase云端服务配置Firebase在本项目中扮演了实时通信中枢和后端服务器的双重角色省去了自建服务器的麻烦。创建项目与数据库在Firebase控制台创建新项目启用“Realtime Database”实时数据库。选择“以锁定模式启动”以保证安全后期再配置规则。数据库结构设计我们采用了类似下面的结构{ devices: { device_id_abc123: { dispenserData: { status: false, token: a1B2c3D4, verifiedToken: } } }, users: { user_id_xyz789: { balance: 5000, name: 张三 } } }安全规则配置这是重中之重错误的规则会导致数据被任意读写。我们的规则大致如下{ rules: { devices: { $deviceId: { dispenserData: { .read: true, // 设备、App都可以读状态和令牌 status: { .write: auth ! null, // 只有登录用户App可以写status }, token: { .write: root.child(devices).child($deviceId).child(authKey).val() newData.parent().parent().child(authKey).val() // 只有持有预共享密钥的设备可以写token防止App恶意生成 } } } }, users: { $userId: { .read: auth ! null auth.uid $userId, .write: auth ! null auth.uid $userId // 用户只能读写自己的数据 } } } }我们为每个设备在数据库中预设了一个authKey长随机字符串设备端代码中保存这个密钥。当设备要更新token时必须同时在请求中写入这个authKey与云端存储的比对一致才允许写入。这防止了任何未经授权的客户端伪造二维码令牌。5.3 管理后台网站Next.js的作用我们还用Next.js开发了一个简单的网站部署在Vercel上。它的主要功能是模拟充值渠道。在实际商业场景中这可能对接的是支付网关。在我们的原型中网站生成一个固定的充值二维码或充值码用户用App扫描后后台将对应的用户余额增加5000印尼盾模拟充值。这个网站的存在使得整个用户闭环充值-消费得以演示让项目更加完整。6. 系统集成调试与故障排查实录6.1 上电顺序与联调步骤将硬件、软件、云端全部打通的过程是最考验人的。我们总结了一个可靠的联调步骤硬件单体测试不接主控直接给水泵通12V电看其是否正常运转。用Arduino示例代码单独测试超声波传感器确认其能正确测距。用3.3V电压触碰继电器IN脚听其是否有吸合声并用万用表测量触点通断。主控基础功能测试仅给WT32-SC01烧录一个简单的Wi-Fi连接和LVGL显示例程确保屏幕能亮、能触摸、能联网。Firebase通信测试编写一个最简单的ESP32程序只做一件事连接Wi-Fi然后监听Firebase数据库某个路径。在电脑端用Firebase控制台手动修改数据观察串口打印确认设备能收到变化。再测试设备向Firebase写数据在控制台查看是否写入成功。功能模块逐步集成在成功联网和显示的基础上加入二维码生成与显示功能。再加入超声波传感器读取逻辑在屏幕上显示实时距离。最后集成继电器控制逻辑并和Firebase状态监听绑定。端到端全流程测试设备上电显示二维码。用手机App扫码完成支付。观察设备屏幕状态变化听继电器吸合声看水泵是否启动。放入杯子观察水泵是否持续工作移开杯子观察水泵是否立即停止放回杯子观察是否继续工作直至完成。6.2 常见问题与解决方案速查表问题现象可能原因排查步骤与解决方案屏幕白屏或花屏1. 电源电压不足或不稳。2. 屏幕排线接触不良。3. LVGL初始化失败。1. 用万用表测量供给WT32-SC01的5V引脚电压确保在4.8V-5.2V之间。2. 重新插拔屏幕排线确保完全插到底座并锁紧。3. 检查串口输出确认LVGL初始化代码无误堆栈大小设置足够。Wi-Fi连接不稳定1. 信号弱。2. ESP32 Wi-Fi库配置问题。3. 路由器设置了MAC过滤或特殊加密。1. 将设备靠近路由器测试。2. 在代码中增加Wi-Fi断开重连机制并打印连接状态。3. 尝试将路由器加密方式改为WPA2-PSK (AES)。无法监听Firebase变化1. 数据库规则禁止读取。2. 设备时间未同步Firebase需要校验时间。3. 网络库如FirebaseESP32版本不兼容。1. 暂时将数据库规则设为.read: true, .write: true进行测试。2. 在代码开始时调用configTime()同步网络时间。3. 检查并更新FirebaseESP32库到最新版本。水泵不工作1. 继电器未吸合。2. 水泵电源未接通或损坏。3. 控制逻辑未触发。1. 测量继电器IN脚电压确认ESP32输出了高电平。听继电器是否有“咔嗒”声。2. 用万用表测量水泵两端是否有12V电压。直接给水泵接12V电源测试好坏。3. 在控制水泵的代码前后加串口打印确认逻辑执行到了。超声波传感器读数不准1. 供电电压不足要求5V接3.3V可能不稳定。2. 传感器前方有障碍物干扰。3. 代码中测量脉冲宽度的函数精度不够。1. 确保传感器Vcc接5V可从MP1584的5V输出取。2. 清理传感器探头表面确保检测区域开阔。3. 使用pulseIn()函数时设置超时参数并考虑多次测量取中值滤波。App扫码后设备无反应1. 设备与Firebase连接已断开。2. 令牌验证失败。3. App写入的数据库路径错误。1. 查看设备串口日志确认Wi-Fi和Firebase连接状态。2. 在Firebase控制台实时查看确认App是否正确写入了status: true和verifiedToken。3. 对比设备代码和App代码中的Firebase数据库路径是否完全一致大小写敏感。6.3 性能优化与未来改进方向在项目完成后我们回顾了可以优化的地方低功耗设计目前设备持续联网、亮屏功耗较高。可以加入人体红外PIR传感器无人时关闭屏幕进入浅睡眠模式或设置定时开关机。多饮品支持可以扩展为多个水泵和储液罐对应不同饮品。在App端选择饮品后云端下发的指令包含通道编号设备控制对应的继电器动作。精准计量加入微型流量传感器替换时间控制实现更精确的定量出液不受电压波动和泵体磨损影响。状态上报设备除了接收指令还应主动上报状态如液位低可通过浮子开关或重量传感器、故障信息等到Firebase便于远程运维。OTA升级集成ESP32的OTA功能未来可以通过网络直接更新设备固件无需物理接触。这个项目从电路焊接、代码调试、结构组装到云端配置走完了一个物联网产品原型开发的全流程。最大的收获不是做出了一台能出水的机器而是理解了如何让硬件、嵌入式软件、移动端和云端四者安全、可靠地对话。每一个环节的坑踩过去都是实实在在的经验。如果你也想深入物联网开发不妨从这个项目开始亲手搭建一遍遇到问题就去解决这个过程会让你对“连接”二字有全新的认识。