多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

ESP8266与KiwisIoT实现低成本远程水位监测与告警系统

ESP8266与KiwisIoT实现低成本远程水位监测与告警系统 水位监测这件事说简单也简单一个浮球开关加个蜂鸣器就能报警说复杂也复杂要远程看数据、要历史曲线、要多人同时收到告警那就得把传感器、主控、云平台、供电这几块都串起来。我这次做的方案是用 ESP8266 做主控配合 KiwisIoT 这个物联网平台搭一套能远程查看水位、超限自动告警的小系统。整套东西成本不到五十块适合家里有水箱、楼顶水塔、鱼塘或者小型农业灌溉场景的朋友参考。ESP8266 这颗芯片玩过的人都知道自带 WiFi、价格便宜、Arduino IDE 生态成熟入门门槛低KiwisIoT 则负责把数据接住、存起来、画成图表省得自己搭服务器。下面我把整个项目的设计思路、接线细节、代码逻辑、平台配置和踩过的坑都摊开讲一遍尽量让第一次接触物联网的朋友也能跟着做出来。1. 为什么选 ESP8266 加 KiwisIoT 这套组合1.1 主控选型的几个现实考量市面上做水位监测的主控方案不少STM32、Arduino UNO、树莓派、ESP32 都能干这活。我最终选 ESP8266主要是从三个维度权衡的结果。第一是联网能力。水位监测的核心价值在于远程可见如果只是本地亮个灯那用不着物联网。ESP8266 内置完整的 TCP/IP 协议栈一根天线就能连 WiFi不需要额外挂以太网模块或者 4G 模块硬件成本直接压下来。相比之下Arduino UNO 本身不带网络要加 ESP-01 做透传接线和调试都更麻烦。第二是价格和供货。ESP8266 模块常见的是 ESP-12F 或者 NodeMCU 开发板单价在十几到二十几块之间批量做的话更便宜。STM32 加网络模块的组合成本会翻倍树莓派就更不用说了拿来做水位监测属于杀鸡用牛刀。第三是开发效率。Arduino IDE 对 ESP8266 的支持已经非常成熟装个开发板管理器选好型号就能烧录。库生态也丰富连 WiFi、发 HTTP 请求、解析 JSON 都有现成的库不用从寄存器层面啃。当然 ESP8266 也有短板比如 ADC 只有一个、精度一般、GPIO 数量有限。但水位监测这个场景对 ADC 的要求并不高后面会讲到怎么用模拟传感器配合它工作。1.2 KiwisIoT 在整套系统里扮演什么角色很多人做物联网项目卡在数据往哪发这一步。自己搭 MQTT 服务器或者 Web 服务器要买云主机、配域名、写后端、做前端图表一套下来工作量比硬件部分还大。KiwisIoT 这类平台的价值就在于把这些脏活累活包了。它提供的主要能力包括设备接入给每个设备分配唯一标识和密钥、数据存储把上报的数据按时间序列存下来、可视化自动生成折线图、仪表盘、告警规则设定阈值超限触发通知。你只需要在设备端按它的协议格式发数据剩下的它来处理。我选 KiwisIoT 而不是其他平台一个很实际的原因是它的接入协议对 ESP8266 友好HTTP 和 MQTT 都支持文档里给的示例代码改改就能用。另一个原因是免费额度对个人项目足够几个设备、几千条数据完全够用。1.3 整套系统的数据流向把架构理清楚后面写代码才不会乱。这套系统的数据流是这样的水位传感器采集模拟电压信号ESP8266 的 ADC 引脚读取这个电压换算成水位百分比或者实际高度。ESP8266 连上 WiFi 后按固定间隔比如每 30 秒把数据打包通过 HTTP POST 或者 MQTT 发布到 KiwisIoT。平台收到数据后存库同时按预设规则判断是否超限。如果超限平台触发告警可以通过邮件、短信或者平台内消息通知。用户打开手机或电脑浏览器登录平台就能看到实时水位和历史曲线。这个链路里ESP8266 是数据采集和上传端KiwisIoT 是数据接收和展示端传感器是感知端。三者职责清晰任何一环出问题都容易定位。2. 水位传感器的原理与选型细节2.1 常见水位传感器的几种类型水位传感器按原理分常见的有这么几类各有各的适用场景。浮球式开关最简单也最便宜靠浮子上下移动触发干簧管通断输出的是开关量只能告诉你到某个位置了或者没到没法给出连续的水位值。适合做上下限报警不适合做曲线监测。超声波测距式装在容器顶部向下发射超声波根据回波时间算水面距离。非接触式不怕水腐蚀但价格偏高而且水面波动、蒸汽、泡沫都会影响精度。压力式投入式丢到水底根据水压换算水深。精度不错适合深井、水池但需要防水处理接线也麻烦。电阻式/电容式贴片利用水的导电性或介电常数变化输出模拟电压。便宜、体积小但长期泡水容易腐蚀精度受水质影响大。我这次用的是电阻式模拟水位传感器就是市面上常见的那种带一排裸露走线的板子配合一个信号调理模块输出 0 到 3.3V 的模拟电压。选它的理由很简单便宜几块钱、接口简单一根信号线进 ADC、够用家里水箱监测不需要毫米级精度。2.2 电阻式传感器的工作原理解析这种传感器本质上是一块 PCB上面印了一排平行的裸露铜线相邻两条线之间是断开的。当水位上升水淹没的走线越来越多水作为导体把相邻走线连通等效电阻随水位变化。信号调理模块把这个电阻变化转换成电压输出。具体来说模块内部通常是一个分压电路传感器作为下臂电阻和一个固定电阻串联。水位越高传感器等效电阻越小分压点电压越高。ESP8266 的 ADC 读到这个电压就能反推水位。这里有个关键点要注意ESP8266 的 ADC 输入范围是 0 到 1.0VNodeMCU 开发板内部有分压实际可测 0 到 3.3V但裸芯片是 0 到 1.0V。如果你用的是裸 ESP-12F 模块直接接 3.3V 的传感器信号会烧 ADC。NodeMCU 开发板因为板载了分压电阻可以接受 0 到 3.3V。这一点在选板子的时候必须搞清楚我后面会专门讲。2.3 传感器安装位置对读数的影响传感器装在哪直接决定数据准不准。我踩过的坑是一开始把传感器垂直贴在水箱内壁结果水位上升时水沿着壁面爬升读数比实际水位偏高。后来改成用支架让传感器稍微离开壁面读数就正常了。另外传感器的有效测量段是有限的比如 4 厘米或者 10 厘米。你要根据水箱的实际高度选量程。如果水箱有 1 米深用 4 厘米量程的传感器那只能测最上面 4 厘米没意义。正确做法是让传感器的测量段覆盖你最关心的水位区间比如正常水位到溢流水位之间。还有一点传感器长期泡水会电解腐蚀尤其是通电状态下。延长寿命的办法是间歇供电——只在测量的时候给传感器通电测完就断电。这个后面代码部分会讲怎么实现。3. 硬件接线与 ESP8266 的 ADC 使用要点3.1 元器件清单与成本核算先把要买的东西列清楚方便你一次性备齐。元器件型号/规格数量参考单价主控板NodeMCU ESP8266 (CH340)115-20 元水位传感器电阻式模拟水位传感器模块15-8 元供电Micro USB 数据线 5V 充电头1已有可省连接线杜邦线若干1 套3-5 元外壳防水接线盒可选15-10 元整套下来不到 50 块。如果你要监测的是户外水塔建议加个防水盒把 ESP8266 装进去只把传感器探头伸到水里。3.2 NodeMCU 与传感器的接线方式接线本身不复杂但有几个细节容易出错。传感器模块一般有三个引脚VCC、GND、SIG信号。NodeMCU 这边VCC 接 3.3V注意不是 5V虽然模块标称支持 5V但为了和 ADC 电平匹配用 3.3V 更安全GND 接 GNDSIG 接 A0。这里要特别说明NodeMCU 的 A0 引脚板载了一个 100k 和 220k 的分压电阻网络把外部 0 到 3.3V 的信号衰减到 0 到 1.0V 再进芯片 ADC。所以你直接接 3.3V 的传感器信号是安全的。但如果你用的是 ESP-12F 裸模块就必须自己加分压电阻否则超过 1.0V 会损坏芯片。还有一个坑NodeMCU 的 A0 只有一个如果你还想接其他模拟传感器就得用外部 ADC比如 ADS1115通过 I2C 扩展。水位监测单传感器场景用不上但心里要有数。3.3 供电稳定性对 ADC 读数的影响ESP8266 在 WiFi 发射瞬间电流会冲到 200mA 以上如果供电不足或者电源纹波大ADC 读数会跳。我实测过用劣质充电头供电时水位读数能上下浮动 5% 以上换成质量好一点的 5V/2A 充电头波动降到 1% 以内。所以供电这块别省。另外如果传感器和 ESP8266 共用电源传感器信号线上最好加一个 0.1uF 的滤波电容到地能明显抑制高频噪声。这个电容焊在传感器模块的 SIG 和 GND 之间就行。如果要做电池供电的户外版本就得考虑低功耗设计比如用 ESP8266 的 deep sleep 模式定时唤醒测量上传。不过 deep sleep 模式下 GPIO16 要接 RST 引脚才能唤醒接线会多一根线这个属于进阶内容先把基础版跑通再说。4. 固件开发从 ADC 采样到数据上报4.1 Arduino IDE 环境搭建与开发板配置如果你还没装 Arduino IDE先去官网下载安装。装好后要添加 ESP8266 的开发板支持步骤是打开文件-首选项在附加开发板管理器网址里填入 ESP8266 的板管理器地址这个地址在 GitHub 的 esp8266/Arduino 仓库文档里有直接复制。然后打开工具-开发板-开发板管理器搜索 esp8266安装。安装完成后在开发板列表里选NodeMCU 1.0 (ESP-12E Module)。端口选你插上 USB 后出现的那个 COM 口。如果没出现端口多半是 CH340 驱动没装去搜 CH340 驱动装一下。这里有个新手常遇到的问题烧录时报错a fatal esptool.py error occurred: failed to connect to esp8266: timed out waiting for packet header。这个错误的原因通常是这几种一是开发板型号选错了二是 USB 线是纯充电线没有数据线芯三是驱动没装好四是烧录时没有按住 FLASH 键。NodeMCU 一般不用手动按但有些板子需要。排查顺序就按这个来。4.2 ADC 采样与水位换算的代码实现ESP8266 的 ADC 是 10 位精度读数范围 0 到 1023对应 0 到 1.0V芯片引脚电压。NodeMCU 因为板载分压实际对应外部 0 到 3.3V。换算关系是// 读取 ADC 原始值 int rawValue analogRead(A0); // 换算成电压NodeMCU 外部电压 float voltage rawValue * (3.3 / 1023.0); // 换算成水位百分比需要先标定空水位和满水位的电压值 float emptyVoltage 0.4; // 传感器完全没入水时的电压需实测 float fullVoltage 2.8; // 传感器完全浸没时的电压需实测 float levelPercent (voltage - emptyVoltage) / (fullVoltage - emptyVoltage) * 100.0; // 限制在 0 到 100 之间 levelPercent constrain(levelPercent, 0, 100);这里的emptyVoltage和fullVoltage必须自己标定。方法是把传感器完全离开水读一串 ADC 值取平均算出电压再把传感器浸到最高水位同样读平均。这两个值填进去换算才准。为了减少噪声采样时不要只读一次而是连续读 20 次取平均float readAverageVoltage() { long sum 0; for (int i 0; i 20; i) { sum analogRead(A0); delay(10); } float avgRaw sum / 20.0; return avgRaw * (3.3 / 1023.0); }4.3 连接 WiFi 与上报数据的完整逻辑连 WiFi 用 ESP8266WiFi 库核心代码就几行#include ESP8266WiFi.h const char* ssid 你的WiFi名称; const char* password 你的WiFi密码; void setupWiFi() { WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(WiFi connected); }上报数据用 HTTPClient 库发 POST 请求。KiwisIoT 的接入方式是在平台创建设备后拿到一个上报地址和密钥把数据按它的格式发过去。假设平台要求 JSON 格式代码大概是这样#include ESP8266HTTPClient.h #include ArduinoJson.h void uploadData(float levelPercent) { if (WiFi.status() ! WL_CONNECTED) return; HTTPClient http; http.begin(http://api.kiwisot.com/v1/device/你的设备ID/data); http.addHeader(Content-Type, application/json); http.addHeader(Authorization, Bearer 你的密钥); StaticJsonDocument200 doc; doc[water_level] levelPercent; doc[voltage] readAverageVoltage(); String payload; serializeJson(doc, payload); int httpCode http.POST(payload); Serial.println(httpCode); http.end(); }主循环里定时调用这两个函数比如每 30 秒测一次、传一次。注意delay会阻塞如果要做其他事情可以用millis()做非阻塞定时。4.4 传感器间歇供电降低腐蚀的实操前面提到传感器长期通电会电解腐蚀。解决办法是用一个 GPIO 控制传感器的 VCC测量时才拉高测完拉低。接线改成传感器 VCC 接 GPIO比如 D1GND 接 GNDSIG 接 A0。代码里#define SENSOR_POWER D1 void measureAndUpload() { digitalWrite(SENSOR_POWER, HIGH); delay(100); // 等传感器稳定 float v readAverageVoltage(); digitalWrite(SENSOR_POWER, LOW); float level (v - emptyVoltage) / (fullVoltage - emptyVoltage) * 100.0; level constrain(level, 0, 100); uploadData(level); }这样传感器每天只通电几十秒寿命能延长很多倍。这个技巧是我在实际部署中总结出来的官方文档一般不会提。5. KiwisIoT 平台侧配置与告警规则5.1 设备创建与数据接入配置登录 KiwisIoT 后第一步是创建设备。平台会给你分配一个设备 ID 和一个密钥token。这两个东西要填到 ESP8266 代码里作为身份凭证。然后要定义数据点datastream也就是你要上报哪些字段。比如我定义了water_level水位百分比和voltage原始电压两个数据点。数据点的类型要选对水位是浮点数电压也是浮点数。如果选成整数小数部分会被截断。数据接入协议方面KiwisIoT 支持 HTTP 和 MQTT。HTTP 简单适合低频上报MQTT 长连接适合高频、低延迟场景。水位监测 30 秒一次HTTP 完全够用而且代码简单不用处理断线重连。所以我用的 HTTP。5.2 告警阈值设定与通知渠道平台侧最有价值的功能是告警。我设了两条规则水位低于 20% 触发缺水告警高于 90% 触发溢水告警。规则里可以设触发条件和恢复条件比如低于 20% 触发回到 25% 以上才恢复这样避免在阈值附近反复告警。通知渠道我配了邮件。平台还支持短信和 WebhookWebhook 可以对接其他系统比如推送到企业微信或者钉钉群。如果你想要手机推送Webhook 是最灵活的方案。这里有个经验告警规则一定要设静默期比如触发后 30 分钟内不重复通知。否则水位一直在阈值附近波动你会被邮件轰炸。这个设置在平台的告警规则高级选项里。5.3 数据可视化面板的搭建KiwisIoT 自带可视化面板可以拖拽组件。我搭了一个面板包含一个实时水位仪表盘显示当前百分比、一个历史曲线图显示过去 24 小时水位变化、一个数值卡片显示最新电压值。仪表盘要设好量程0 到 100%。曲线图的时间范围可以选我一般看 24 小时和 7 天两个视图。7 天视图能看出用水规律比如每天早上水位下降晚上补水回升。面板可以分享链接家里人用手机打开就能看不用装 App。这个对非技术用户很友好。6. 实测中遇到的坑与排查过程6.1 ADC 读数跳动严重的排查链路第一次跑起来发现水位读数在 30% 到 45% 之间乱跳根本没法用。排查过程是这样的先怀疑传感器把传感器拿出来擦干读数应该接近 0结果还是在跳说明不是水位问题。然后怀疑代码把采样次数从 10 次加到 50 次跳动幅度小了一点但还在。接着用万用表量传感器 SIG 对地电压发现电压本身就在抖说明是硬件问题。换了个质量好的 USB 充电头跳动明显减小。又在线路上加了 0.1uF 滤波电容基本稳定了。最后确认根因是供电纹波大加上信号线没有滤波。这个坑告诉我模拟传感器项目电源质量比什么都重要。6.2 WiFi 断线重连的处理ESP8266 长时间运行偶尔会掉线。如果不处理数据就断了。我在主循环里加了状态检查if (WiFi.status() ! WL_CONNECTED) { Serial.println(WiFi lost, reconnecting...); WiFi.disconnect(); WiFi.begin(ssid, password); delay(5000); }另外HTTP 请求失败也要重试。我设了最多重试 3 次每次间隔 2 秒。如果 3 次都失败就跳过这次上报等下一个周期。不要死循环重试否则会卡住整个程序。6.3 烧录失败与串口异常的常见原因前面提到的timed out waiting for packet header错误我遇到过好几次原因各不相同。有一次是开发板选成了Generic ESP8266 Module改成NodeMCU 1.0就好了。有一次是 USB 线的问题换了根线解决。还有一次是 COM 口被其他软件占用了关掉串口监视器再烧录就行。串口输出乱码也是常见问题多半是波特率不对。ESP8266 默认串口波特率是 74880但 Arduino 代码里通常用 115200。如果你在 setup 里写了Serial.begin(115200)串口监视器也要设成 115200否则就是乱码。7. 系统优化与功能扩展方向7.1 降低功耗适配电池供电如果监测点没有市电就得考虑电池供电。ESP8266 的 deep sleep 模式能把电流降到 20uA 左右定时唤醒测量上传。实现方式是测量上传完成后调用ESP.deepSleep(30e6)睡 30 秒。注意 GPIO16 要接 RST 引脚否则唤醒不了。电池选 18650 锂电池加一个升压模块或者直接用 3.7V 锂电供电ESP8266 工作电压 3.0 到 3.6V3.7V 锂电加个二极管降压就行。按 30 秒唤醒一次算2000mAh 电池大概能撑一两周。如果改成 5 分钟一次能撑几个月。7.2 增加本地显示与手动控制远程看数据方便但有时候站在水箱旁边也想直接看。加一个 0.96 寸 OLED 屏I2C 接口接 D1/D2本地显示当前水位成本十几块。代码用 U8g2 库很简单。手动控制方面可以加一个继电器控制水泵。水位低于 20% 自动开泵高于 90% 自动关泵。这个逻辑可以放在 ESP8266 本地做也可以放在平台侧通过 Webhook 下发指令。本地做响应快平台做更灵活看需求。7.3 多设备组网与数据集中管理如果你有多个水箱要监测每个水箱一个 ESP8266都上报到 KiwisIoT 的同一个账号下。平台支持设备分组可以把同一区域的设备放一组面板上对比看。设备多了以后命名规范很重要比如楼顶水箱-01地下室水池-02不然自己都分不清。多设备场景下还要注意 WiFi 覆盖。如果水箱在楼顶路由器在一楼信号可能不够。解决办法是加一个 WiFi 中继或者用 ESP8266 的固定 IP 减少连接时间。实在不行就换 ESP32 加外置天线信号会好很多。这套系统我从画接线图到跑通前后花了大概一个周末。硬件部分没什么难度主要时间花在传感器标定和平台配置上。最深的体会是模拟传感器项目电源和滤波决定了数据质量的上限代码再怎么优化也救不了硬件噪声。另外平台侧的告警静默期一定要设不然真的会被自己的系统烦死。如果你也在做类似的水位监测希望这些经验能帮你少走点弯路。
返回列表