基于STM32与光电传感器的宠物智能水位监测器设计与实现
1. 项目缘起一个被忽视的日常痛点养过宠物的人尤其是养猫养狗的朋友应该都遇到过这个场景你正忙着手头的工作或者沉浸在追剧的快乐中家里的毛孩子突然跑过来用爪子扒拉你或者在你脚边焦躁地转圈。你一开始可能不明所以直到它把你引到它的水碗边你低头一看——碗里空空如也一滴水都不剩了。那一刻愧疚感瞬间涌上心头。我们总想着给它们最好的食物、最舒适的窝却常常忽略了最基础、也最关键的饮水问题。宠物缺水尤其是猫咪可能不会像饿了那样明显叫唤但它们长期饮水不足的后果却很严重比如泌尿系统疾病、肾脏负担加重等。我自己就曾因为工作太投入连续两天忘记给家里的猫主子添水直到发现它频繁去厕所却尿不出来才惊出一身冷汗赶紧送去医院。那次经历让我意识到依赖记忆和肉眼检查来保证水碗常满实在是太不可靠了。于是一个简单的想法诞生了为什么不做一个“空水碗警报器”呢它不需要多复杂核心功能就一个——当水碗里的水低于某个阈值时自动提醒主人。这个项目听起来简单但真要动手实现从传感器选型、电路设计到提醒方式每一步都有不少门道。今天我就把自己从构思到实现这个“空水碗警报器”的全过程包括踩过的坑和最终验证有效的方案详细分享出来。无论你是电子爱好者还是单纯的宠物家长想亲手为爱宠做点小东西这篇内容都能给你提供一条清晰的路径。2. 核心需求拆解与方案选型动手之前我们先别急着画电路图或写代码。一个好的项目始于对需求的清晰理解。这个“空水碗警报器”到底要做什么我们把它的核心需求拆解成几个具体的技术指标。2.1 功能边界定义首先它不是一个自动饮水机。自动饮水机是主动提供循环流动的水而我们的警报器是一个被动的监测装置。它的核心使命是“监测”和“报警”不负责“供给”。明确了这一点我们就能避免把简单问题复杂化。具体功能包括水位检测能准确判断碗中的水位是否低于预设的安全线。状态提示当水位过低时能发出明确、不易被忽略的提醒。低功耗与安全由于需要长期插电或使用电池工作功耗必须低。同时整个装置必须绝对防水且使用安全电压防止宠物啃咬或水溅造成危险。非侵入式安装最好能不改变宠物原有的饮水习惯不占用碗内太多空间易于清洗。2.2 传感器选型为什么是光电式水位检测是项目的核心。常见的水位检测方案有好几种我们需要根据家用宠物水碗的场景逐一分析。浮球开关机械结构简单便宜。但宠物水碗通常不深浮球需要一定行程才能触发精度不高。而且机械部件在碗内宠物喝水时可能碰到产生误触发或损坏。清洗碗时也很麻烦。导电式探针利用水的导电性。需要将两个金属探针伸入水中通过检测探针间电阻来判断水位。缺点很明显金属探针长期浸泡在水中容易电解、氧化影响可靠性如果使用直流电还可能加速电解反应同样存在清洗不便和宠物可能触碰的问题。电容式传感器可以做到非接触式检测将传感器贴在碗的外壁通过检测介电常数的变化来感知水位。这是一个很好的方向但对碗的材质厚度、均匀度有要求且校准相对复杂不同材质的碗陶瓷、不锈钢、塑料响应曲线不同。光电式传感器红外对管这是我最终选择的方案。它由一个红外发射管和一个红外接收管组成。当它们之间没有水时红外光直接照射到接收管输出一种状态比如高电平当水位上升漫过传感器探头时红外光在水与空气的界面发生折射大部分光线无法到达接收管输出状态翻转变为低电平。选择光电式传感器的理由很充分非接触式检测相对传感器可以封装在一个防水探头内只有探头尖端需要接触水大大减少了与水接触的面积和腐蚀风险。无机械活动部件可靠性高不怕宠物拨弄。响应速度快光电转换是瞬间的没有机械延迟。易于安装可以设计成夹在碗边或者用一个重物底座沉入碗底探头朝上检测特定高度水位。当然它也有缺点如果水中有很多漂浮物比如宠物毛、灰尘或者气泡可能会干扰光线传播造成误判。但在相对干净的饮用水中这个问题不突出。我们可以通过软件防抖逻辑连续检测到几次低水位才报警来进一步规避。2.3 提醒方式如何有效触达主人报警方式必须有效。在厨房里放个蜂鸣器你在卧室可能根本听不见。因此我考虑了多层提醒方案本地声光报警作为基础提醒在设备上集成一个LED灯和一个小蜂鸣器。当你在家时可以第一时间注意到。无线网络推送核心这是解决“人不在家”或“人在其他房间”问题的关键。通过Wi-Fi模块将报警信息推送到手机App如通过MQTT协议到Home Assistant、或使用微信/钉钉机器人或者发送一条短信/电话。这样无论你在公司上班还是在卧室睡觉都能即时收到提醒。冗余设计可以考虑增加一个物理按键用于手动测试设备状态和消音。基于以上分析我的方案框架确定为STM32或其他低功耗MCU作为主控 光电水位传感器 Wi-Fi模块如ESP-01S 本地声光报警。这个组合在成本、功耗和功能上取得了较好的平衡。3. 硬件设计与实现细节方案定了接下来就是把想法变成实物。硬件部分是整个项目的基石需要仔细考量每一个细节。3.1 主控芯片选型STM32与ESP8266的权衡很多人可能会直接想到用ESP8266比如NodeMCU或ESP-01S作为主控因为它自带Wi-Fi开发简单。我最初也是这么想的但仔细评估后我选择了STM32F103C8T6俗称“蓝色药丸”作为主控而将ESP-01S仅作为Wi-Fi从机使用。理由如下功耗控制更精细STM32在低功耗模式下的电流可以做到微安级而ESP8266即使在深度睡眠下功耗也相对较高。我们的设备需要7x24小时待机功耗是重要指标。STM32可以大部分时间处于停机Stop模式仅定时唤醒比如每10秒检测一次传感器检测完立刻又进入睡眠。而ESP8266只在需要发送报警信息时才由STM32唤醒发送完毕后立即进入深度睡眠。这种主从架构比ESP8266全程待机要省电得多。I/O资源与可靠性STM32的GPIO更多驱动能力更强处理传感器信号和本地声光报警更稳定。将通信任务剥离给专门的Wi-Fi模块也使得系统架构更清晰万一网络部分出问题不影响核心的检测功能。成本与灵活性STM32F103和ESP-01S都是极其廉价且常见的模块组合起来成本可控。未来如果想升级为蓝牙报警或增加其他传感器STM32的扩展性也更好。3.2 水位传感器模块制作这是硬件部分的核心。我购买了一对常用的3mm红外发射管和接收管。关键步骤在于封装并排固定将发射管和接收管并排间隔约3-5mm固定在一小段热缩管或塑料管内。注意管子的发射/接收窗口要对齐且朝同一方向。灌胶防水使用环氧树脂AB胶进行灌封。这是至关重要的一步必须确保胶水完全覆盖焊点并延伸到导线部分形成完整的防水层。灌胶前最好用硅胶模具做出一个光滑的探头形状。我第一次做的时候防水没做好探头根部渗水导致内部电路短路报废。测试与校准封装完成后万用表测电阻确认绝缘性。然后搭建一个简单电路给发射管串联一个150-220欧姆的限流电阻接电源3.3V接收管接一个10K的上拉电阻到3.3V输出端接STM32的GPIO。将探头放入空碗和满水碗中观察输出电平的变化。正常情况下空碗空气中接收管导通输出低电平约0V浸入水中后输出变为高电平约3.3V。这个逻辑可以根据你的电路设计调整。注意红外对管对可见光也有一定敏感性。最好在探头外部包裹一层深色热缩管或涂黑以减少环境光干扰。也可以在软件上采用发射管间歇性点亮比如点亮10ms熄灭90ms接收端只在点亮窗口期采样的方式来有效抵抗环境光干扰。3.3 电路连接与电源考虑整体电路原理并不复杂STM32的某个GPIO配置为推挽输出控制红外发射管电源。接收管的输出信号连接到STM32的另一个GPIO配置为上拉输入。STM32的另一个GPIO控制一个LED灯和一个有源蜂鸣器。STM32的串口UART与ESP-01S的TXD/RXD交叉连接用于AT指令通信。ESP-01S的CH_PD和RST引脚也由STM32的GPIO控制以便彻底断电或复位。电源部分需要重点设计。如果打算长期使用电池推荐使用18650锂电池搭配TP4056充电模块和升压模块将3.7V升到5V或3.3V。如果靠近插座使用5V/1A的USB电源适配器更省心。务必在电源入口处加上滤波电容如100uF电解并联0.1uF瓷片以稳定电压。3.4 结构设计与安装硬件不能只是堆在桌面上。我使用了一个小型防水接线盒Junction Box作为外壳。将STM32核心板、ESP-01S、蜂鸣器等集成在里面。水位传感器的探头通过密封格兰头电缆防水接头引出。外壳可以放在水碗旁边。对于探头安装我设计了两种方式沉底式用一根硬质电线如包塑铁丝将探头弯成一个倒L形末端用耐水胶粘一个配重如不锈钢螺母。这样探头可以直立在水碗底部检测固定高度的水位。优点是安装简单缺点是可能会被好奇的宠物拨动。侧壁夹持式3D打印一个夹子可以夹在碗的边缘探头水平伸入碗内。通过调节夹子的高度可以精确设定报警水位线。这种方式更稳固且易于调整。4. 软件逻辑与避坑指南硬件搭好了接下来就是赋予它灵魂的软件部分。软件的核心是低功耗管理和可靠的报警逻辑。4.1 STM32主程序流程我的程序基于HAL库开发主要流程是一个大循环但大部分时间MCU都在睡眠。// 伪代码逻辑 int main() { 硬件初始化GPIO, UART, RTC... 配置RTC定时唤醒例如10秒 首次读取传感器状态记录当前水位 while(1) { // 1. 进入停机模式等待RTC唤醒 HAL_PWR_EnterSTOPMode(...); // 2. 被唤醒后首先重新初始化系统时钟HAL库要求 SystemClock_Config(); // 3. 检测水位传感器 点亮红外发射管 HAL_Delay(5); // 短暂稳定 读取接收管GPIO状态 熄灭红外发射管 // 4. 逻辑判断 if (当前状态 低水位 上次状态 高水位) { // 水位刚刚下降到阈值以下 低水位计数器; if (低水位计数器 3) { // 连续3次检测确认防抖 触发本地报警LED闪烁蜂鸣器响 唤醒ESP-01S并发送网络报警 将“报警已触发”标志位置位 } } else if (当前状态 高水位) { // 水位正常或在阈值以上 低水位计数器 0; // 清零计数器 if (“报警已触发”标志位有效) { 停止本地报警 通知ESP-01S发送“水位已恢复”消息可选 清除“报警已触发”标志位 } } // 5. 更新状态准备下一次睡眠 上次状态 当前状态 // 如果处于报警状态可以缩短睡眠时间比如改为2秒检测一次 根据报警标志位重新配置RTC唤醒时间 } }4.2 与ESP-01S的通信AT指令让STM32控制ESP-01S发送网络报警是软件部分的一个小难点。ESP-01S通常工作在AT指令模式。通信逻辑如下唤醒与初始化当需要发送报警时STM32先拉高ESP-01S的CH_PD引脚使其上电然后延迟几百毫秒等待模块启动。接着通过串口发送“AT\r\n”测试指令等待“OK”回应。确保模块就绪。连接Wi-Fi发送ATCWJAP你的SSID,你的密码\r\n等待连接成功。建立TCP连接假设你有一个内网的服务器比如跑着Node-RED或简单TCP服务程序的电脑。发送ATCIPSTARTTCP,服务器IP,端口号\r\n。发送数据连接成功后发送ATCIPSEND数据长度\r\n收到“”提示后发送实际的报警数据例如“PET_WATER_LOW”。清理与休眠发送完成后发送ATCIPCLOSE\r\n关闭连接。最后发送ATGSLP0\r\n让ESP-01S进入深度睡眠如果支持或者直接拉低CH_PD引脚断电。踩坑记录AT指令的响应处理一定要做好超时和错误重试机制。我一开始没有处理“ERROR”响应当Wi-Fi信号不好时指令失败程序就卡死了。后来加入了每条指令发送后等待特定响应或超时失败则重试3次的逻辑稳定性大大提升。另外发送完CIPSEND指令后一定要等待“”提示符再发数据否则数据会丢失。4.3 服务器端与消息推送为了接收ESP-01S发来的报警信息我用了最简单的方法在家庭局域网内的一台旧电脑树莓派更好上用Python写了一个简单的TCP服务器。# 简易TCP服务器示例 (Python) import socket HOST 0.0.0.0 # 监听所有接口 PORT 12345 # 与ESP-01S中设置的端口一致 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() print(f服务器监听在 {PORT} 端口...) while True: conn, addr s.accept() with conn: print(连接来自:, addr) data conn.recv(1024) if data: message data.decode(utf-8).strip() print(收到消息:, message) if message PET_WATER_LOW: # 在这里触发推送调用短信API、发送邮件、或通知Home Assistant print(触发低水位报警推送) # 例如调用Home Assistant的REST API触发一个自动化 # requests.post(http://homeassistant:8123/api/..., ...)这个服务器收到“PET_WATER_LOW”消息后可以进一步调用其他服务比如Home Assistant通过其REST API触发一个自动化在手机App上发送一条通知。钉钉/微信机器人调用机器人Webhook发送消息到群聊。短信/电话API使用云服务商的API如阿里云、腾讯云发送紧急短信。我选择了集成到Home Assistant中因为它本身就是一个家庭自动化平台可以很方便地设置“当收到TCP消息时向所有家庭成员手机推送通知”的自动化并且可以记录历史报警事件。5. 实测、优化与扩展思考电路焊好了代码烧录了服务器也跑起来了。接下来就是最激动人心的实测阶段也是问题集中爆发的阶段。5.1 初期测试与问题排查我把组装好的设备放在猫咪的水碗旁探头用沉底式安装。头几个小时一切正常。但到了晚上问题出现了误报警。明明水还有大半碗手机却收到了报警通知。排查过程如下检查硬件探头防水完好电路连接正常。用手电筒照探头发现即使在水里如果光线从特定角度射入接收管还是能收到一些反射光导致状态翻转。检查软件防抖我已经设置了连续3次检测到低水位才报警按理说能过滤瞬时干扰。观察现场我蹲在旁边观察了很久终于发现了原因。猫咪喝水时舌头会快速舔动水面造成水面剧烈波动和产生大量气泡。当气泡覆盖在探头表面时会形成短暂的“空气层”导致传感器误判为“无水状态”。虽然每次波动时间很短但我的检测周期是10秒一次如果某次采样刚好捕捉到了气泡覆盖的瞬间就会被记录一次“低水位”。连续几次采样都可能遇到这种情况从而触发误报。5.2 针对性优化措施找到了根因解决思路就清晰了软件层面加强滤波将“连续检测到低水位”的次数阈值从3次提高到5次或6次。同时引入“状态稳定时间”判断。只有低水位状态持续超过一定时间比如30秒才最终确认报警。这能有效过滤喝水引起的瞬时波动。硬件层面改善探头在探头头部套上一小段致密的海绵套类似某些水质检测笔的护套。海绵可以被水浸湿但能阻隔大的气泡直接附着在光学窗口上同时水分子可以自由通过不影响检测。这是一个非常有效且低成本的改进。调整检测周期在非报警状态下将检测周期从10秒延长到30秒甚至60秒。这既降低了功耗也减少了“撞上”猫咪喝水瞬间的概率。一旦进入报警状态再将检测周期缩短以便在水加满后快速恢复正常状态提示。经过这些优化后设备运行了一周再也没有发生误报警只有在真正水快喝完时才会可靠地提醒我。5.3 功耗实测与续航评估优化后我用万用表串联测量了设备在正常工作模式睡眠60秒唤醒检测一次下的平均电流。STM32在停机模式下电流约20μA唤醒工作瞬间电流约10mA但持续时间极短几十毫秒。ESP-01S仅在报警时被唤醒工作发送数据过程持续约5-8秒期间电流约70mA。粗略估算一下假设一天报警2次每次ESP-01S工作10秒。那么STM32部分日均功耗 ≈ (20μA * 24h) (10mA * 24*3600/60 * 0.05s) 非常小可忽略。ESP-01S部分日均功耗 ≈ 70mA * 10s * 2 / 3600 ≈ 0.39 mAh。 如果使用一颗2000mAh的18650电池理论续航可以达到2000 / (0.39/24) ≈ 1230天超过三年当然这是理想情况实际要考虑电池自放电、电路静态功耗等但支撑几个月到一年绝对没问题。如果使用USB供电则完全无需担心续航。5.4 项目扩展方向这个基础版本实现后还可以根据需求进行很多有趣的扩展水质监测增加一个TDS总溶解固体传感器探头可以粗略了解水的洁净度提醒你该换水了而不仅仅是没水了。饮水统计通过水位变化的频率和幅度粗略估算宠物一天的饮水次数和总量生成简单的统计图表对于关注宠物健康的家长很有价值。多碗管理如果你家有多个水点可以设计一个主控设备搭配多个无线水位探头使用Zigbee或LoRa实现集中监控。联动自动化与智能插座联动报警后自动打开水泵为水碗补水但这需要改造水碗复杂度上升背离了初衷。这个“空水碗警报器”项目从发现需求到最终稳定运行花了我几个周末的时间。最大的收获不是做出了一个设备而是在这个过程中系统地实践了从需求分析、方案选型、硬件制作、软件编程到调试优化的完整流程。它解决了一个真实、细微却重要的生活痛点。现在我可以更安心地专注于工作因为我知道当猫咪的水碗空了我的手机会第一时间告诉我。这种通过自己动手创造的小小确定性带来的满足感远超项目本身。如果你也有类似的困扰不妨也尝试动手做一个过程中的思考和解决问题的乐趣才是最宝贵的。