点灯加持!3天DIY一套智能灌溉系统-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1791|回复: 3

[分享] 点灯加持!3天DIY一套智能灌溉系统

[复制链接]
发表于 2021-3-30 00:27 | 显示全部楼层 |阅读模式
大概是大一放暑假,因为在宿舍养了一棵多肉,第一次萌生了希望有一套自动浇水的装置的想法,当时也只是想想。

在事隔若干年后,因为做菜的葱蒜总是用不完,在窗边弄了两个泡沫箱种着,又因为懒得浇水,试着就把智能灌溉系统给实现了。

整套系统基于 arduino,结合 点灯·blinker 的平台加持,实现在线控制和数据显示,好处是编程简单、模块丰富,控制电路图如下:


目录
一、第一天
  1.1 硬件准备
  1.2 软件准备
二、第二天
  2.1 设计一个浇水按钮
  2.2 设置自动浇水开关
  2.3 显示实时湿度和历史图表
三、第三天
  3.1 实物连接
  3.2 设备外壳
  3.3 湿度传感器
后记

一、第一天

1.1 硬件准备

买材料,等快递,完。

板子我用的是 D1 mini,优点是小巧,带ESP8266芯片,可以物联网。

其它主要部件有:土壤湿度传感器、5V一路继电器、小水泵、配套水管。

零散的部件:杜邦线、micro数据线(旧安卓数据线,用于D1板子烧录和供电)、废旧塑料瓶等…

主控板子


土壤湿度传感器

电磁继电器

水泵和管子
1.2 软件准备

下载并安装 Arduino IDE,安装开发版的库(具体操作自行搜)。实际上程序我也是第一天写好的,实现自动浇水的关键代码:
  1. // 设置湿度临界值
  2. int auto_moisture = 100;


  3. void setup() {
  4.   // D1 控制继电器
  5.   pinMode(D1, OUTPUT);
  6.   // A0 读取湿度
  7.   pinMode(A0, INPUT);
  8. }


  9. void loop() {
  10.   // 读取湿度模拟值,转化成表现值
  11.   int moisture = 1024 - analogRead(A0);
  12.   // 如果湿度小于阈值则启动水泵
  13.   if (moisture != 0 && moisture < auto_moisture) {
  14.     digitalWrite(D1, HIGH);
  15.     // 浇水持续时间
  16.     delay(5000);
  17.     digitalWrite(D1, LOW);
  18.   }
复制代码


以上代码从A0口读取土壤湿度传感器的模拟值,根据设定阈值,自动启动水泵浇水的过程。

注意这里读取的并不是真正的湿度值,而是 0~1024 范围的模拟电信号,湿度越大值越小;我为了更易于人类理解,把它和1024相减,使湿度越大表现值越大。


二、第二天

以上代码实现了本地控制,但我们肯定不满足于此。下一步是试其联网,远程控制、在线显示数据,这也是我用带WIFI板子的目的。物联网部分,我使用 blinker 的方案。

blinker 是一套物联网设备开发部署方案,核心是制定了设备和设备间、设备和客户端间通信及交互标准。用户可自己拖拽布局设备控制界面,自由打造你的物联网设备。

官网文档:https://diandeng.tech/doc/getting-start-8266

下载安装 blinker APP,新建设备,获取秘钥。IDE 安装 blinker Arduino 库,示例代码,配置WIFI、秘钥,这些官网文档都有,不赘述。

2.1 设计一个浇水按钮

APP 中新建一个按钮,数据健名「btn-water」;新建一个数据控件,键名「num-water」。

添加浇水按钮

结合以下代码,就能在自动浇水的基础上,实现远程手动浇水的功能。按一下开关水泵启动 5 秒,如果管子较长,这个值可以稍微设大一些。浇水完成后计数器 +1 并返回浇水的次数。
  1. #define BLINKER_WIFI
  2. #include <Blinker.h>

  3. char auth[] = "你的token";
  4. char ssid[] = "热点名";
  5. char pswd[] = "热点密码";

  6. // 新建组件对象
  7. BlinkerButton BtnWater("btn-water");
  8. BlinkerNumber NumWater("num-water");

  9. // 手动浇水计数
  10. int counter = 0;
  11. // 设置湿度临界值
  12. int auto_moisture = 100;

  13. void setup() {
  14.   // D1 控制继电器
  15.   pinMode(D1, OUTPUT);
  16.   // A0 读取湿度
  17.   pinMode(A0, INPUT);
  18.   // 初始化 blinker
  19.   Blinker.begin(auth, ssid, pswd);
  20.   // 绑定按钮事件
  21.   BtnWater.attach(BtnWater_callback);
  22. }

  23. void loop() {
  24.   Blinker.run();
  25.   // 读取湿度模拟值,转化成表现值
  26.   int moisture = 1024 - analogRead(A0);
  27.   // 如果湿度小于阈值则启动水泵
  28.   if (moisture != 0 && moisture < auto_moisture) {
  29.     digitalWrite(D1, HIGH);
  30.     // 浇水持续时间
  31.     Blinker.delay(5000);
  32.     digitalWrite(D1, LOW);
  33.   }
  34. }

  35. // 按下浇水按钮
  36. void BtnWater_callback(const String & state) {
  37.   if (state == "tap" && digitalRead(D1) == 0) {
  38.     digitalWrite(D1, HIGH);
  39.     Blinker.delay(5000);
  40.     digitalWrite(D1, LOW);
  41.     counter++;
  42.     // 发送计数
  43.     NumWater.print(counter);
  44.   }
  45. }
复制代码


2.2 设置自动浇水开关

如果我不想自动浇水,怎么办?我们可以在设置一个自动浇水开关,设置为打开时,执行检测湿度自动浇水的代码。(篇幅有限,这里只给出关键代码,需融会贯通,下同)
  1. //……此处省略部分非关键代码

  2. // 新建组件对象
  3. BlinkerButton BtnAuto("btn-auto");

  4. // 自动浇水默认开关
  5. bool auto_water = false;

  6. //……此处省略部分非关键代码

  7. void loop() {
  8.   Blinker.run();
  9.   // 读取湿度模拟值,转化成表现值
  10.   int moisture = 1024 - analogRead(A0);
  11.   // 如果湿度小于阈值则启动水泵
  12.   if (auto_water && moisture != 0 && moisture < auto_moisture) {
  13.     digitalWrite(D1, HIGH);
  14.     // 浇水持续时间
  15.     Blinker.delay(5000);
  16.     digitalWrite(D1, LOW);
  17. }

  18. // 自动浇水开关
  19. void BtnAuto_callback(const String & state) {
  20.   if (state == "on") {
  21.     auto_water = true;
  22.   } else {
  23.     auto_water = false;
  24.   }
  25. }
复制代码


2.3 显示实时湿度和历史图表

怎样湿度实时显示在 APP 上呢?方法和 2.1 中显示计数是一样的,APP中新建数据控件,代码中绑定控件。
  1. //……此处省略部分非关键代码

  2. // 新建组件对象
  3. BlinkerNumber NumMoisture("num-moisture");

  4. void setup() {
  5.   //……此处省略部分非关键代码

  6.   // 历史数据图表
  7.   // Blinker.attachDataStorage(func, time, times);
  8.   // func, 对应的回调函数
  9.   // time, 对应数据采集时间-默认60 s, 最少60 s
  10.   // times, 对应采集次数后上传到云端-默认2次, 最多不超过4次
  11.   Blinker.attachDataStorage(dataStorage, 60 , 2);
  12. }

  13. // 设备需要上传数据到云端时会调用对应的回调函数
  14. void dataStorage() {
  15.   int moisture = 1024 - analogRead(MOIST);
  16.   Blinker.dataStorage("moisture", moisture);
  17. }
复制代码


但这里我们还需要加入心跳包,以便在一打开设备页面的时候就返回数据,后面每 30~60s 会定期返回一次心跳包。
  1. void setup() {
  2.   //……此处省略部分非关键代码

  3.   // 心跳绑定
  4.   Blinker.attachHeartbeat(heartbeat);
  5. }

  6. // 发送实时数据
  7. void heartbeat() {
  8.   NumMoisture.print(1024 - analogRead(MOIST));
  9.   // 以下是返回开关状态
  10.   btnSwitch(BtnAuto, STRING_format(auto_water ? "on" : "off"));
  11. }
复制代码


三、第三天

3.1 实物连接

下面是我制作实物的一些经验。把基本部件按以下线路连接,另外我们还需要储水罐、防水外壳。我用的是潜水泵,放到储水罐中,出水口连接软管到植物处。



3.2 设备外壳

整套装置我是打算放在窗台外的,所以必须考虑防水,外壳我用一个饮料瓶倒立放置。把元件全塞进去,娃哈哈某款饮料瓶口刚刚好。


瓶盖打三个孔,孔直径等于线的直径,引出三根导,分别是主板电源线、湿度传感器导线、水泵电源线。



3.3 湿度传感器

湿度传感器插针和导线焊接,用热缩管做最后的包裹。


这里我的经验之谈是做滴蜡处理,防止洒水的时候渗入到插针处,造成传感器不准。

后记

最后成品的效果,我把装置固定在窗边,用快递袋包裹遮太阳,从窗边引入一根电源线到室内接电源,储水罐用坏了的烧水壶。


手机控制端,当然后面程序上还做了一些升级优化,比如湿度数值取平均数,防止某一次取值偏差,增加浇水微信通知之类的。



整套东西做好了有一段时间,这篇文章陆陆续续写了快四个月。

再次证明了「一鼓作气,再而衰,三而竭」,以至于后面有些细节忘了,代码也是从最终版本中抠出来简化的,有 bug 别怪我 ╮( ̄▽ ̄)╭ ,如果有朋友需要可以完整开源,但我希望你有一点基础,有排错的能力,而不是纯伸手。

感谢点灯提供的平台和库,让物联网开发变得简单、便捷!后面我还做了同时支持APP、天猫精灵、小爱同学(我用小米手环5)控制的氛围彩灯,支持不同闪动模式,后续希望加入读AUX音频信号,随音乐节奏跳动,但也一直拖着没动,有能力和兴趣的朋友可以一起探讨完善。

对了,还有舵机+激光逗猫的玩具,可是没有猫。

Made with love, just for fun!

未经许可禁止转载。

发表于 2021-3-30 19:23 | 显示全部楼层
图需要上传下,都看不到
 楼主| 发表于 2021-4-1 10:20 | 显示全部楼层
本帖最后由 Cp0204 于 2021-4-1 10:26 编辑
奈何col 发表于 2021-3-30 19:23
图需要上传下,都看不到

好的,但我好像没法编辑。直接从某文档复制过来的,之前还能显示。可能有防盗链
 楼主| 发表于 2021-4-1 11:04 | 显示全部楼层
奈何col 发表于 2021-3-30 19:23
图需要上传下,都看不到

已编辑重发,本帖请做删帖处理。dz论坛编辑器真是太恶心了。。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-11-28 13:31 , Processed in 0.090128 second(s), 16 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表