ESP8266与KiwisIoT实现低成本远程水位监测与告警系统
2026/9/24 10:22:23 网站建设 项目流程

水位监测这件事,说简单也简单,一个浮球开关加个蜂鸣器就能报警;说复杂也复杂,要远程看数据、要历史曲线、要多人同时收到告警,那就得把传感器、主控、云平台、供电这几块都串起来。我这次做的方案是用 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.0V(NodeMCU 开发板内部有分压,实际可测 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 接 GND,SIG 接 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);

这里的emptyVoltagefullVoltage必须自己标定。方法是:把传感器完全离开水,读一串 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 你的密钥"); StaticJsonDocument<200> 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(比如 D1),GND 接 GND,SIG 接 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% 以上才恢复,这样避免在阈值附近反复告警。

通知渠道我配了邮件。平台还支持短信和 Webhook,Webhook 可以对接其他系统,比如推送到企业微信或者钉钉群。如果你想要手机推送,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.6V,3.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 加外置天线,信号会好很多。

这套系统我从画接线图到跑通,前后花了大概一个周末。硬件部分没什么难度,主要时间花在传感器标定和平台配置上。最深的体会是:模拟传感器项目,电源和滤波决定了数据质量的上限,代码再怎么优化也救不了硬件噪声。另外,平台侧的告警静默期一定要设,不然真的会被自己的系统烦死。如果你也在做类似的水位监测,希望这些经验能帮你少走点弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询