发作品签到
专业版

能联网的太阳能热水器控制器

工程标签

744
0
0
6

简介

能联网的太阳能热水器控制器 配套微信小程序:那年那月那天

简介:能联网的太阳能热水器控制器 配套微信小程序:那年那月那天

开源协议

GPL 3.0

创建时间:2024-07-31 16:02:07更新时间:2024-10-08 06:07:23

描述

一.视频链接:

B站视频--功能演示及介绍合集

二.项目简介

能联网的太阳能热水器控制器
主要解决两个问题
1.传统太阳能热水器冬天耗电高的问题

传统太阳能热水器控制器控制逻辑是这样的:每天固定两个时间点,检测当前水温是否小于设定值,如果小于,就启动电加热,加热到设定值停止;在夏天,太阳能充足,基本用不到电加热,功耗很低,但是在冬天,太阳能较少,加上太阳能热水器水箱在室外,保温效果不好,所以基本上每天都会电加热两次,功耗非常高,但是冬天的用水需求较少,这就造成了电能浪费。

现在的控制逻辑是在微信小程序上预约,如果有用热水需求,就在小程序上预约,控制器在预约时间点的前n个小时判断当前水温再决定是否电加热(n可通过小程序修改)

可能大家会觉得这样不方便,每次都要预约,太麻烦了,其实确实是这样,我也觉得很麻烦,但是考虑到我家里面实际情况,家里面不常有人,所以这样的预约机制算是比较适合我家这种情况的

2.不锈钢水塔水量检测控制

太阳能热水器控制器预留了水塔水位检测模块接口;太阳能热水器安装在顶楼,自来水水压上不去,所以加了一个不锈钢水塔作为太阳能热暑期供水来源,平时就是在一楼用水泵往这个水塔中抽水,维持太阳能热水器的供水;不锈钢水塔在没有水位传感器的情况下,过放和过充是常事,非常不方便,所以加上不锈钢水塔水位检测功能非常有必要

三.工程下各个板子介绍

(1).水塔上水控制板:

image.png
安装在 给不锈钢水塔上水的水泵 旁边,可以显示不锈钢水塔水量、太阳能热水器水箱水量、太阳能热水器水箱水温、太阳能热水器电加热状态、太阳能热水器上水状态、可以控制水泵往不锈钢水塔抽水(按目标时间或者目标水量抽水)、关闭太阳能热水器电加热、关闭太阳能热水器上水;安装好后的样子如下:

微信图片_20240927001434.jpg

当水塔水量低于8%,蜂鸣器就会报警(10分钟响一次),数码管的亮度由光敏电阻控制。

关于这块板子的电路,一开始这块板子是想做成各个模块通用的板子,各个模块都用此电路板,所以在原理图上做了一些说明,后面想把这个项目做的完美一点,就放弃了这种想法
这块板子电路部分有一个按键扩展可以说一下,原理图如下:

image.png
用BAT54C加三个GIO引脚实现7个按键检测
当时是想一板多用,所以GPIO不够用,就用此法

此模块使用说明(仅供自己参考,怕时间久了忘记了):

  • 模块上电默认显示不锈钢水塔水量,当水量低于8%时蜂鸣器间隔10分钟报警;六个并排的按键从左往右分别为S1、S2、S3、S4、S5、S6,上面单独的一个按键为S0,S0的功能为停止不锈钢水塔上水;
  • 短按S1,数码管会闪烁显示"20.",在闪烁显示的过程中,再次按下S1,就会开始往不锈钢水塔抽水,直到其水量达到20%停止,若在闪烁的过程中,无任何操作,5秒后,将会恢复原样;
  • 短按S2,数码管会闪烁显示"40.",在闪烁显示的过程中,再次按下S2,就会开始往不锈钢水塔抽水,直到其水量达到40%停止,若在闪烁的过程中,无任何操作,5秒后,将会恢复原样;
  • 短按S3、S4、S5、S6功能如上,分别代表50%、70%、80%、100% 。
  • 数码管在闪烁显示的过程中可以通过短按其他按键来改变选中的值。
  • 上述是按目标水量抽水,除此之外还可以按目标时间抽水,比如抽水10分钟后停止,按目标水量抽水和按目标时间抽水的切换按键为S6,长按S6(数码管闪烁时,长按无效)2.2秒,直到蜂鸣器响一下,就代表切换成功,当从按目标水量抽水切换到按目标时间抽水后,
  • 短按S1,数码管会闪烁显示"10",在闪烁显示的过程中,再次按下S1,就会开始往不锈钢水塔抽水,直到抽水10分钟后停止,若在闪烁的过程中,无任何操作,5秒后,将会恢复原样;
  • 短按S2,数码管会闪烁显示"15",在闪烁显示的过程中,再次按下S2,就会开始往不锈钢水塔抽水,直到抽水15分钟后停止,若在闪烁的过程中,无任何操作,5秒后,将会恢复原样;
  • 短按S3、S4、S5、S6功能如上,分别代表20min、25min、30min、35min。
  • 同样,数码管在闪烁显示的过程中可以通过短按其他按键来改变选中的值。
  • 不管何种形式的抽水,只要水塔水量达到100%、或者水池中无水(水泵的水来源,有一个浮球开关来检测是否有水),都会立即停止抽水。
  • 长按S1(数码管闪烁时,长按无效)2.2秒,直到蜂鸣器响一下,数码管就会显示太阳能热水器里面的水,松开后,又会恢复原样(显示水塔水量),如果长按2.2秒后,继续按住不松开,持续5秒,蜂鸣器就会再响一下,紧接着会向太阳能热水器控制模块发送关闭太阳能热水器电加热的指令。
  • 长按S2(数码管闪烁时,长按无效)2.2秒,直到蜂鸣器响一下,数码管就会显示太阳能热水器里面的水,松开后,又会恢复原样(显示水塔水量),如果长按2.2秒后,继续按住不松开,持续5秒,蜂鸣器就会再响一下,紧接着会向太阳能热水器控制模块发送关闭太阳能热水器上水电磁阀的指令。
  • 此模块引出了两个LED(实物图中圈出来的部分),分别为粉色和蓝色,分别代表太阳能热水器上水状态和电加热状态。

(2).水塔水量测量_电机版

image.png
原理图部分没啥好说的,就一个电机驱动、一个RS232转换、一个AT24C02、一个单片机。
水位测量原理:
1.上水时,水位上涨,浮球开关碰到水,编码电机就控制转盘把浮球开关往上收,直到离开水停止,如此循环
2.没有上水时,此时随着生活用水,水塔中的水量会减少,水位下降,浮球开关离开水,编码电机就控制转盘把浮球开关往下放,直到碰到水停止,如此循环
3.一旦水位改变,立即记录当前编码器的值,保存到eeprom中,配合一定的逻辑(每次上电时,如果浮球开关碰到了水,就上升到离开水;如果没有碰到水,就下降到碰到水;同时读取eeprom中的编码器值,计算出此时编码器定时器相关寄存器的值),就能实现断电后水位变化,再次上电后,水位依然能准确测量
B站视频--水塔水量测量原理介绍

水塔水量检测模块完全可以脱离这个系统单独应用在其他地方;它采用RS232总线通信,波特率9600,接收到以下数据就会返回当前水位(0~100)、模块MCU温度、故障信息:

接收
0xDD0xBB上水/用水复位故障校验和

其中"上水/用水"为0x2代表上水模式,0x0代表用水模式,"复位故障"为0x1代表复位传感器故障,传感器故障就是保险浮球开关触发了,但是编码电机测量出的水位没有到100,就会产生故障信息。校验和为:("上水/用水"+"复位故障")%256
返回数据的格式为:

返回
0xEE0xAA水量(0~100)故障信息MCU温度校验和

校验和为:("水量"+"故障信息"+"MCU温度")%256

水塔上水控制模块在使用前需要校准一次,校准方法:
将模块断电,用手转动绳盘将绳子收缩回来,收到你认为的代表水塔水量100%的位置(要低于保险浮球开关的位置),然后按住校准按键再通电,通电后松开按键,绳子会自动往下放,放到你认为的代表水塔水量0%的地方后,再按一下此按键,就完成了校准。在校准过程中,水塔中最好不要有水,校准完成后重新上电,然后就能正常使用了

安装好后是这个样子的

a2c36be5e23daa0f87a8072b98daf3a.png

B站视频--水塔水量测量模块工作演示

B站视频--水塔水量测量模块安装

(3).太阳能热水器控制板

image.png

原理图设计的过于保守(用料过多),主要体现在电磁阀和继电器的驱动以及供电部分;供电部分采用了两个海凌科的HLK-10M12模块,总功率可以到20w,tb上单买很便宜(签到券购买)

3c36f0fbb5b3c2f3ff32182ba802d77.jpg
用现成的AC-DC电源模块,主打一个专业的事交给专业的人,省时省力又省心(其实就是不会电源~)

一路12V 10w给板子供电,另一路12V 10w给电磁阀(3.6w)和RS232供电,也就是RS232接口供电能力有6.4w
12V经三个LDO,分别给主控、LoRa模块、MAX232供电

B站视频--控制模块介绍

太阳能热水器控制模块程序部分难点为 四线太阳能热水器传感器 的驱动,驱动方法在后面会讲

板子实物图

067926977d56661ea8b36ab520a9b22.jpg

a6d3abbf133f4aac1b7b04286688093.jpg

da600960d1ab44b9160e0dd60f5d987.jpg

cbc2e2c90f5aa41c60cbb1419a360a9.jpg

88dc06bad5df7893525b05fb9db351e.jpg
(4).PCB7和PCB8

两个圆盘,配合智能小车轮子做成卷线轮

(5).中继模块(工程中没有)
由一个LoRa模块(HC-14)与一个ESP8266组成,LoRa模块最好单独供电
电路部分很简单,直接用的第一版的中继模块,所以第二版中就没有中继模块的电路
【ESP12F中继模块】 https://www.bilibili.com/video/BV1xaxjejEZL/?share_source=copy_web&vd_source=68337adbea96c8cef50403a4b2809df6

四.软件部分

(1).模块间通信协议设计
个人认为,这种有多个模块通信的项目,在写程序之前(可以先把驱动部分写好),应该先明确需求,搞清楚各个模块之间要传哪些数据,充分考虑需求之后,再设计各个模块间的通信协议,将其写成文档或者做成表格,然后再开始写程序,此时只要依据你的通信协议去写代码,效率会高很多,并且能更好的应对后续出现的问题或者增加新的功能。此项目通信协议截图如下,详细的就不拿出来了。

批注 2024-09-26 233138.jpg

此项目通信框图如下

image.png

注意事项:中继模块、太阳能热水器控制模块、水塔上水模块都是通过无节点机制的LoRa模块来传输数据的,也就是任意一方发送数据,其他两方都能接收到,在程序设计时需要考虑这点;另外如果一方在发送数据时,另一方也开始发送数据,这样就会造成LoRa模块通信故障,所以在设计通信协议时要避免这个问题(任意时刻不能出现两个模块同时发送数据);除此之外传输的数据帧必须加上校验码、重要的指令需加入应答机制。

(2).看门狗
真正做项目时,只要单片机有看门狗,那就一定要用上!在逻辑较复杂的应用中,能避免意想不到的逻辑BUG;同时也能增强产品在恶劣环境中的温度性。

(3).四线太阳能热水器传感器驱动

这种传感器本质上就是可变电阻,用单片机ADC采集电压然后将电压转换成我们需要的目标值就行了,需要注意的是,分压后的目标电压要加上电压跟随器,再输入到单片机的ADC,因为这种传感器它的阻值较大,如果直接连接,由于ADC输入端存在一定的阻抗,可能会与外部分压电阻形成并联关系,导致实际分压值与理论值不符,从而影响采集精度。另外要长久温度运行的系统,最好在ADC引脚上加上钳位二极管。

难点:如何将ADC值转换成我们需要的目标值;tb卖这种传感器的商家基本上不会提供有用的数据,网上的资料也很少,基本找不到,所以要想使用这种传感器,就必须要我们自己测量数据进行校准。

水位传感器(红蓝线):
单片机以400ms周期采集水位传感器ADC值,输出到串口助手,同时将水位传感器缓慢放入水中,至完全浸入水中,再缓慢拿出来,然后将串口助手收到的数据导入Excel中,绘制数据的曲线图。
这样多次测量,并且更换不同温度,不同水质,不同容器,最后得到所有的数据曲线,如下所示:

image.png

不同颜色的曲线代表不同的环境,由曲线可以看出,各种情况下的数据都呈5段的趋势,然后在曲线上找出不同段之间阈值(要满足不同颜色的曲线),这样我们只需要将测量的ADC值与这4个阈值(5段只有4个阈值)比较,就能得到当前水位处于哪一段,然后我们将这5段分别定义为水量的0%、20%、50%、80%、100%(原控制器是这么定义的),这样我们就得到了太阳能热水器水箱中的水量。

水温传感器(白绿线):
先采集温度传感器的ADC值,观察其值发现其是一种正温度系数的电阻,但是阻值不符合常见的PT100、PT1000等热敏电阻,好在我们对水温的精度要求不高,所以我们可以用一种能准确测量温度的传感器,来校准这个水温传感器,我这里用的校准温度传感器为10K的B3950 NTC热敏电阻(负温度系数);
首先将水温传感器和NTC热敏电阻都放入电水壶中,然后单片机通过串口输出NTC热敏电阻测量的温度和ADC采集到的水温传感器原始ADC值,如下所示:

image.png

第一个数据为NTC热敏电阻测量的温度,第二个为采集到的水温传感器原始ADC值,第三个为水量传感器ADC值

然后开始电水壶加热,一只加热到NTC热敏电阻输出76度,这样我们就得到了不同的温度下,水温传感器对应的ADC原始值,然后将这两组数值导入一个线性回归分析网站,如下所示:

批注 2024-08-21 231753.jpg

由图可以看出,所有数据基本都落在一条直线上面,数据非常线性,根据网站计算出的直线函数我们就能用水温传感器的ADC原始值算出大概的真实温度,计算关系如下

image.png

(4).数据存储

没有用到数据库。预约事件、近24小时历史水温、近24小时历史水量、运行模式、阈值温度、执行提前这些数据都保存在中继模块中;用户信息保存在微信小程序常量的代码中(就7个用户)。

五.微信小程序

微信小程序名称:那年那月那天9
不要问为啥搞这个名字,问就是太阳能热水器相关名字都被占用了。

小程序需要输入密钥验证成功后才能控制我家的设备,为什么用这种原始的验证方式,而不用手机号码一键验证用户信息?因为凡是涉及到用户隐私的,微信官方审核非常严格,我作为个人开发者,没有任何资质担保,就别妄想获取用户的手机号码了。可能有人会问,为啥要验证才能使用?因为微信小程序本身是开放的,人人都能用,如果不需要验证,那我家的设备岂不是所有人都能随便控制了。

微信小程序共四个页面
操作页面:
微信图片_20240927130806.jpg

实时数据页面:
微信图片_20240927130807.jpg

历史数据页面:
微信图片_20240927130808.jpg

拓展页面:
微信图片_20240927130809.jpg

乍一看可能会觉得比较复杂,其实多数功能和数据不需要关心,需要人为干涉的就只有两个,一个是往不锈钢水塔上水,另一个是预约事件;太阳能水箱会自动上水(不锈钢水塔水量大于8%时,每天凌晨1点自动上水到100%)、太阳能电加热会根据预约事件和实时温度以及执行提前来决定是否需要开启电加热。

不同的用户用不同的密钥验证,微信小程序根据输入的密钥来区分不同用户,每一个用户都对应阿里云公共实列中的一个设备,如下所示:

批注 2024-09-27 053653.jpg

预约事件查看方式如下:

772ca6914032c99a19e94c36f0a3a1c.jpg
一个预约事件由 用户名字+具体日期时间+水温组成,每个预约事件被执行后会自动删除,最多只能存在50个预约事件,用户不能删除其他用户的预约事件,小程序添加或删除预约事件时,向中继模块发送的数据格式如下:

image.png

中继模块向小程序客户端上报预约数据的格式如下:

image.png

中继模块向小程序客户端上报预约数据源码如下

void yy_event_updata(){
  mqtt_tbuff[0] = 0x95;//更新的是预约事件
  mqtt_tbuff[1] = yy_event_num+1;//总事件数,必须+1处理!
  uint8_t con = 0;
  for(uint8_t i=0;i<50;i++){
    if(yy_event_list[i].xh!=0xFA){//说明此位置是有效预约事件
      mqtt_tbuff[2+con*7] = yy_event_list[i].xh+1;//序号+1处理
      mqtt_tbuff[4+con*7] = ((yy_event_list[i].time&0xFF000000)>>24);//时间戳左边第1个字节
      mqtt_tbuff[5+con*7] = ((yy_event_list[i].time&0xFF0000)>>16);//时间戳左边第2个字节
      mqtt_tbuff[6+con*7] = ((yy_event_list[i].time&0xFF00)>>8);//时间戳左边第3个字节
      mqtt_tbuff[7+con*7] = (yy_event_list[i].time&0xFF);//时间戳左边第4个字节
      //更改+1处理,因为对于时间戳,有可能一个字节正好是255,而+1就正好又回到0,用此+1方法不可能解决这个问题,所以加一个单独的字节记录是否为0,这个字
      //节的低4位分别记录时间戳的四个字节是否为0,而最高位的1,是确保此字节不为0的
      mqtt_tbuff[3+con*7] = 0x80;//确保此字节不为0
      for(uint8_t t=0;t<4;t++)//遍历四个时间戳字节,看是否有为0的字节
        if(mqtt_tbuff[4+con*7 + t]==0){ 
          //保证发送的不为0 此时这一字节时间戳数据已经用不到了,小程序那边检测到mqtt_tbuff[3+con*7] 右边第t位为1,直接将这个字节做0处理
          mqtt_tbuff[4+con*7 + t]+=1;
          mqtt_tbuff[3+con*7] += 0x01<<(3-t);//告诉小程序,这个字节的时间戳数据为0
        }
      mqtt_tbuff[8+con*7] = yy_event_list[i].temp;//这里是真实温度,范围40~80,所以不用+1处理
      con++;
    }
  }
  mqtt_tbuff[8+con*6] = 0;//在最后加上0
  logln(con);logln(yy_event_num);
  pubMQTTmsg((char*)mqtt_tbuff);
}

小程序客户端解析中继模块发来的预约事件,源码如下:

}else if(payload[0]==0x95){//预约事件
      var str = ''//'旭华 2024-02-13 10:00 40℃'
      this.globalData.yuyueshijian_data=[]//清空原来的预约事件
      for(i=0;i<(payload[1]-1);i++){//事件总数,那边是+1发过来的,为了防止有0
        str=this.globalData.u_n_font[payload[i*7+2]-1]//序号也是+1发过来的
        let sjc = 0;
        if((payload[i*7+3]&(0x08))!=0)sjc=0;
        else sjc=payload[i*7+4]<<24;
        if((payload[i*7+3]&(0x04))!=0)sjc+=0;
        else sjc+=payload[i*7+5]<<16;
        if((payload[i*7+3]&(0x02))!=0)sjc+=0;
        else sjc+=payload[i*7+6]<<8
        if((payload[i*7+3]&(0x01))!=0)sjc+=0;
        else sjc+=payload[i*7+7];
        let dt = new Date(sjc*1000)//这里传进去的单位要是ms
        if((dt.getMonth()+1)<10)
          str +=' '+dt.getFullYear().toString()+'-0'+(dt.getMonth()+1).toString()+'-'
        else
          str +=' '+dt.getFullYear().toString()+'-'+(dt.getMonth()+1).toString()+'-'
        if(dt.getDate()<10)str += '0'+dt.getDate().toString()
        else str += dt.getDate().toString()
        if(dt.getHours()<10)str +=' 0'+dt.getHours().toString()+':'          
        else str +=' ' +dt.getHours().toString()+':'          
        if(dt.getMinutes()<10)str += '0'+dt.getMinutes().toString()
        else str += dt.getMinutes().toString()
        str += ' '+payload[i*7+8]+'℃'//这里是真实温度,范围40~80
        this.globalData.yuyueshijian_data=this.globalData.yuyueshijian_data.concat(str)
      }
      if(this.globalData.esp_ack_enable)this.globalData.esp_ack = 2//中继执行完成应答
      console.log("收到预约事件")
    }

中继模块上报预约事件、以及微信小程序解析预约事件都是根据规定的协议来的,所以只要实现设计好通信协议,代码部分就很简单了。

微信小程序中用户验证时,如果验证成功,会先后弹出"验证成功"->"MQTT连接中..."->"等待中继应答"->"数据获取成功",如果网络通畅,整个过程耗时不会超过3秒

image.png

image.png

image.png
如果没有收到中继模块发来的数据,就会弹出对话框提示用户

image.png

所有的操作部分都会有对话框来二次询问用户是否确定执行操作

image.png

image.png

image.png

image.png

image.png

image.png
......

实时数据页面的仪表和历史数据页面的图表都是用ECharts组件来实现的

image.png

当时考虑过的上位机方案:
1.用Flutter做APP
2.用 HomeAssistant
3.微信小程序
这三个技术领域对我来说都是陌生的,我一开始选择的是HomeAssistant 方案,虽然不会,但是学就完了,当时跟着B站 王铭东 老师的视频在学,但是学到后面感觉用HomeAssistant限制太大,我想要的仪表组件、预约机制都不好实现(应该是学的不深入),于是就重新选择了微信小程序开发,现在庆幸当时选对了,微信小程序开发对于新手来说非常非常友好,官方文档齐全,网上教程很多,非常容易上手;并且当你懂一点微信小程序开发之后,你还能了解到一些前端开发的知识,因为它们技术栈很相似,微信小程序的开发主要使用JavaScript、WXML(类似于前端的HTML)、WXSS(类似于前端的CSS)和JSON文件(并不重要)来构建界面和逻辑,这些都是前端开发中常用的技术。
我个人认为,学习一种新技术,要以面向应用的心态去学,这样会比较好上手;首先确定好你的应用中需要实现哪些功能,实现这些功能需要哪些细分的技术栈,然后去一一学习这些细分的技术栈,逐个击破,就能实现你的应用。

六.阿里云物联网公共实列

免费好用,适合个人DIY项目,网上教程很多。

此文仅用来记录,本项目不适合复刻,技术问题欢迎探讨

设计图

未生成预览图,请在编辑器重新保存一次

BOM

暂无BOM

附件

序号文件名称下载次数
暂无数据
克隆工程
添加到专辑
0
0
分享
侵权投诉

工程成员

评论

全部评论(1)
按时间排序|按热度排序
粉丝0|获赞0
相关工程
暂无相关工程

底部导航