自组净水器(带水驱零陈水)
自上次小米净水器厨下式改装之后正常使用了一段时间,换了除RO膜的所有滤芯之后,虽然出水TDS只有2,但最近家人喝水一直觉得有股塑料味儿。不知道是不是耗材的原因,耗材都购买于某宝诺华清源店。因此,工作六年的净水器还是下定决心把其全换掉。净水器依然选择可更换的通用滤芯,由于我家水槽下方空间无法放下通用滤芯钢架组的净水器,只能分散放置。某宝北方水处理店陶氏RO膜全NSF认证配件的净水器成品与自己组成本相差无几,因此水槽下方有空间放置的可以不用折腾直接买成品(北方水处理带零陈水的净水器需注意每次制水后水驱就运行,稍不合理)。
▲参考水路图
进压力桶的逆止阀改为2分进水电磁阀,废水电磁阀实际是2分进水电磁阀,未使用低压开关,净废水比例通过旁路针阀来调节。
净水器材料、滤芯及膜壳几乎全采用带NSF认证的产品。这次净水器控制主板没有采用现成的成品模块,而是照例采用ESP32控制,实时水质监测本想利用小米拆机探头,可小米主板只接水质探头会报错。网上买带通信的水质探头模块还挺贵的,暂时未考虑在线水质监测,后续再考虑如何实现。主要材料清单如下表:
名称 | 参数 | 数量 | 备注 |
---|---|---|---|
RO膜 | 3012、500G规格 | 1 | 陶氏FilmTEC,这个膜挺贵的 |
水泵 | 400G增压水泵 | 1 | 三角洲品牌,400G水泵配500G膜是可行的 |
PE管道 | 2分、3分 按需 | 台湾CCK | |
膜壳 | 3012RO膜壳、10寸滤芯壳 | 4 | 台湾CCK |
管件 | 三通、逆止阀等 | 按需 | 中荷 |
高压开关 | 2分 | 1 | 南洋 |
电磁阀 | 3分,24V | 2 | 科博 |
电磁阀 | 2分,24V | 1 | 科博 |
压力桶 | 1.5G | 1 | 光跃 |
浸水开关 | 3分 | 1 | 泡棉浸水后顶开开关关闭进水 |
净水出水龙头 | 2分管接口 | 1 | 我买的箭牌 |
安信可ESP32模块+电气材料 | 利用Arduino做控制 | 1 | 见电路图 |
4路光耦继电器 | 4路输入、4路继电器常开输出 | 1 | 某宝买成品模块 |
24VDC电源 | 24V 4A | 1 | 原净水器拆机 |
水路组装
按照水路图组装就可以了,为了运行稳定,逆止阀每处我多加了一个。
▲水路组装完成
电路图
▲实际电路
工作逻辑
1.冲洗
(1)按自复位冲洗键,冲洗30s;
(2)制水累计2h,自动冲洗30s。(因为净水器有水驱功能,此功能可不用。)
设备动作:
(1)进水电磁阀(开)
(2)废水电磁阀(开)
(3)水泵(开)
2.制水
打开水龙头,开始制水。
设备动作:
(1)高压开关闭合
(2)进水电磁阀(开)
(3)水泵(开)
3.水驱
制水1h后运行水驱
设备动作:
(1)进水电磁阀(开)
(2)水驱电磁阀(开)
(3)废水电磁阀(开)
(4)水泵(开)
4.保护
单次制水工作超过15分钟,则停止工作,以防高压开关或输入电路损坏引起自动工作。
调试及代码
净水器的时序动作通过上次折腾小米净水器已经摸索出经验,运行了几天比较稳定,目前这款陶氏RO膜在前置2个PP棉+1个活性炭和1个后置T33的情况下,进水TDS200,出水TDS约为6左右。我把净水器的运行状态数据接入了点灯科技,可以手机随时查看状态,点灯科技相关资料可查看SHTC3温湿度计这篇文章。由于记录RO膜使用时长用到ESP32的EEPROM,网上说EEPROM擦些次数有限,因此我以10min计时为一次写入,避免频繁擦写ROM的问题。
▲手机查看运行状态
代码如下
代码只是实现功能,未优化。
//water-purifier-v2.2
//hihaoer 2023-10-06
#include <Arduino.h>
#define BLINKER_WIFI
#include <Blinker.h> //引入点灯库
#include <EEPROM.h> //引入EEPROM库
#define EEPROM_SIZE 1000 //定义EEPROM容量大小
int in_valve = 19; //定义进水电磁阀
int pump = 18; //定义水泵
int water_valve = 5; //定义水驱电磁阀
int waste_valve =17; //定义废水电磁阀
int high_switch =25; //定义高压开关信号,高压断开,低压闭合。
int bottom = 14; //定义自复位按钮
int pure = 0; //纯水制水启动标志
int shuiqu = 0; //水驱启动标志位
int wash = 0; //手动冲洗标志位
int auto_wash = 0; //自动冲洗标志位
int time1 = 0; //关水龙头后多久启动水驱计时
int time2 = 0; //水驱运行时间计时
int time3 = 0; //手动冲洗RO计时
int time4 = 0; //制纯水时间累积
int time5 = 0; //自动冲洗RO计时
int time6 = 0;
int time7 = 0; //单次工作最大时间保护
int time8 = 0;
int RO_Time = 0; //制纯水总累积时间,计算RO膜寿命。
int mid = 0; //定义一个中间标志位
int result = 0;
int pure_data_read = 0;
int shuiqu_data_read = 0;
int time1_data_read = 0;
int rotime_data_read = 0;
BlinkerNumber Bl_pure("pure_data"); //在Blinker APP 中创建“数据组件”
BlinkerNumber Bl_shuiqu("shuiqu_data"); //在Blinker APP 中创建“数据组件”
BlinkerNumber Bl_time1("time1_data"); //在Blinker APP 中创建“数据组件”
BlinkerNumber Bl_rotime("rotime_data"); //在Blinker APP 中创建“数据组件”
char auth[] = "***"; //上一步中在app中获取到的Secret Key
char ssid[] = "***"; //你的WiFi热点名称
char pswd[] = "***"; //你的WiFi密码
void heartbeat() //利用心跳包把数据上传到blinker(WiFi一分钟一次)
{
Bl_pure.print(pure_data_read);
Bl_shuiqu.print(shuiqu_data_read);
Bl_time1.print(time1_data_read);
Bl_rotime.print(rotime_data_read);
}
void dataStorage() //云存储水驱数据函数
{
Blinker.dataStorage("pure_data", pure_data_read); //存储水驱启动参数
Blinker.dataStorage("shuiqu_data", shuiqu_data_read); //存储水驱启动参数
Blinker.dataStorage("time1_data", time1_data_read); //存储启动水驱时间计时参数
Blinker.dataStorage("rotime_data", rotime_data_read); //存储膜制水时间
}
void setup()
{
//Serial Port begin
Serial.begin (9600);
//Define inputs and outputs
pinMode(high_switch, INPUT);
pinMode(bottom, INPUT);
pinMode(in_valve, OUTPUT);
pinMode(pump, OUTPUT);
pinMode(water_valve, OUTPUT);
pinMode(waste_valve, OUTPUT);
EEPROM.begin(EEPROM_SIZE);
RO_Time = EEPROM.get(4, RO_Time); //读取RO膜总的工作时间
BLINKER_DEBUG.stream(Serial);
Blinker.begin(auth, ssid, pswd); //初始化blinker
Blinker.attachHeartbeat(heartbeat); //将传感器获取的数据传给blinker APP上
Blinker.attachDataStorage(dataStorage); //主循环中调用这个函数,每次循环的时候就会调用上面的dataStorage函数,达到可以将每次获得的数据云存储的效果.
}
void loop()
{
Blinker.run();
pure_data_read = pure;
shuiqu_data_read = shuiqu;
time1_data_read = time1;
rotime_data_read = RO_Time;
//打开水龙头
if(digitalRead(high_switch) == 0) //这里是高压开关信号,表示水龙头打开。上拉电阻,水龙头打开置0。
{
pure = 1;
time1 = 0;
mid = 1;
time7++;
digitalWrite(in_valve, 1); //打开进水电磁阀
digitalWrite(pump, 1); //启动水泵
}
else
{
pure = 0;
time7 = 0;
digitalWrite(pump, 0); //关闭水泵
digitalWrite(in_valve, 0); //关闭进水电磁阀
}
//使用纯水累计时间
if (pure == 1)
{
time4++;
time6++;
}
//下面是关水龙头后开始计时
if (mid == 1)
{
time1++;
}
//到规定间隔时间启动水驱
if(time1 > 3600) //开水后启动水驱间隔时间,单位是秒。3600S
{
shuiqu = 1;
digitalWrite(in_valve, 1); //打开进水电磁阀
digitalWrite(water_valve, 1); //打开水驱电磁阀
digitalWrite(pump, 1); //启动水泵
time2++;
}
if(time2 > 75) //水驱运行时间75s
{
digitalWrite(pump, 0); //关闭水泵
digitalWrite(in_valve, 0); //关闭进水电磁阀
digitalWrite(water_valve, 0); //关闭水驱电磁阀
digitalWrite(waste_valve, 1); //打开废水电磁阀
time1 = 0;
shuiqu = 0;
mid = 0;
time8++;
}
if (time8 > 80)
{
digitalWrite(waste_valve, 0); //关闭废水电磁阀
time2 = 0;
time8 = 0;
}
//制水累积30分钟,冲洗30s!!!这里改很大或屏蔽程序,因为水驱运行就相当于冲洗了。
if (time4 > 180000 && pure == 0 && shuiqu == 0)
{
auto_wash = 1;
digitalWrite(in_valve, 1); //打开进水电磁阀
digitalWrite(waste_valve, 1); //打开废水电磁阀
digitalWrite(pump, 1); //启动水泵
time5++;
}
if (time5 > 30)
{
auto_wash = 0;
digitalWrite(pump, 0); //关闭水泵
digitalWrite(in_valve, 0); //关闭进水电磁阀
digitalWrite(waste_valve, 0); //关闭废水电磁阀
time4 =0;
time5 =0;
}
//保护设置
if (time7 > 900) //单次工作超过15分钟,则停止工作,以防高压开关或输入电路损坏引起自动工作。
{
digitalWrite(pump, 0); //关闭水泵
digitalWrite(in_valve, 0); //关闭进水电磁阀
}
//按冲洗键冲洗RO膜,长按时间尽量超过1S,因为扫描周期为1S。
if(digitalRead(bottom) == 0) //按下了冲洗键
{
wash = 1;
}
if(wash == 1 && pure == 0 && shuiqu == 0)
{
digitalWrite(in_valve, 1); //打开进水电磁阀
digitalWrite(waste_valve, 1); //打开废水电磁阀
digitalWrite(pump, 1); //启动水泵
time3++;
}
else
{
wash = 0; //若在按的时候有在制水等状态则不启动冲洗
}
if (time3 > 30)
{
wash = 0;
time3 = 0;
digitalWrite(pump, 0); //关闭水泵
digitalWrite(in_valve, 0); //关闭进水电磁阀
digitalWrite(waste_valve, 0); //关闭废水电磁阀
}
// 保存RO膜工作时间到EEPROM
result = time6 / 600; //RO_Time RO膜总运行时间以10分钟计。
if (result >= 1)
{
RO_Time++;
EEPROM.put(4, RO_Time);
EEPROM.commit();
time6 = 0;
}
Serial.print(" RO_Time=");
Serial.print(RO_Time);
Serial.print(" in_valve=");
Serial.print(digitalRead(in_valve));
Serial.print(" waste_valve=");
Serial.print(digitalRead(waste_valve));
Serial.print(" water_valve=");
Serial.print(digitalRead(water_valve));
Serial.print(" pump=");
Serial.print(digitalRead(pump));
Serial.print(" high_switch=");
Serial.print(digitalRead(high_switch));
Serial.print(" bottom=");
Serial.print(digitalRead(bottom));
Serial.print(" pure=");
Serial.print(pure);
Serial.print(" shuiqu=");
Serial.print(shuiqu);
Serial.print(" wash=");
Serial.print(wash);
Serial.print(" time1=");
Serial.print(time1);
Serial.print(" time2=");
Serial.print(time2);
Serial.print(" time4=");
Serial.println(time4);
Blinker.delay(1000);
}