本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

基于ESP8266的植物浇水监控器

发布时间:2022-09-22
分享到:

基于ESP8266的植物浇水监控器

发布时间:2022-09-22
分享到:

NodeMCU ESP8266 板可监控植物的土壤水分,并在需要浇水时通过 Telegram 通知您!

为什么要做这个项目?
我可能是万千个一直忘记给植物浇水的人其中的一份子,有多少植物因为你忘记了你甚至在家里有它们而枯萎?

我就是其中之一,因此我决定创建一个项目,让我知道我什么时候没有给我的鳄梨植物浇水。

目标
起初的目标只是需要知道我什么时候需要给植物浇水。但既然我正在开发这个工具,为什么不添加一些额外的选项,比如能够按需检查鳄梨的表现。

硬件
我使用了一个 Arduino 兼容板“WeMos D1 NodeMcu Lua V3 CH340G ESP8266”,可以在 eBay 上购买。

还选择了“ESP8266板”,因为内置wifi功能和便宜的价格。我们不需要太多的电力,所以没有必要使用 ESP-32 板。

要知道鳄梨是否需要浇水,我使用了土壤湿度传感器 YL-69(或 YL-39)。通过它的电极,我们可以确定植物土壤的干燥程度。该传感器也可在 eBay 上购买。

传感器有一个电位器,可以校准返回的值。

该板将使用 VIN 和 GND 引脚由 9V 电池供电。

注意:根据您使用的电路板,输入电压可能会有所不同。在某些情况下,允许的输入会写在板上。

软件
Arduino IDE 用于该项目。

第一步是创建一个 Telegram 机器人。由于网上已经有很多关于如何做到这一点的教程,这一步我就不做过多解释。请参阅下面的链接以开始使用。

如果您不想使用 Telegram 机器人,可以使用IFTTT 。

为了与机器人通信,我使用了 Giancarlo Bacchio 开发的“ ESP8266-TelegramBot ”库,该库可在找到。

为了能够在我需要给植物浇水时收到通知,我设置了一个 Telegram 机器人来向我发送通知。每隔 24 小时,系统会检查状态并在达到关键限制时通知我。

由于 Telegram 机器人为我们提供了相当大的自由度,因此我实现了一个额外的命令来随时读取传感器值。

根据土壤的不同,从传感器读取的值可能与我的示例不同。以下是电位器完全逆时针旋转(最小值)时返回的值。

  • 浇水后: 460
  • 24 小时后:420
  • 48 小时后:380

我通常每 2 天给鳄梨浇一次水,所以我决定使用400作为临界值。一旦读取的值低于此值,我将收到通知。

警告
为避免损坏传感器,我们仅在读取土壤湿度时才将其通电。因此,它不是直接连接到 3.3V 引脚,而是连接到数字引脚之一。

未来的拓展
这个项目的一个改进是添加一些视觉效果,也许是一个 LED,它可以通过将颜色从绿色变为黄色再变为红色来为您提供状态。

另一种选择是通过使用运行在 3.3V/8MHz 的 Arduino Pro Mini 和 ESP-01 来延长电池寿命。

如果您想更在此基础上更进一步,您还可以使用水泵构建一个自动浇水系统!

Avocado Watering Monitor:

/*
   Avocado Watering Monitor
   Board used: WeMos D1 NodeMcu Lua V3 ESP8266
   Sensor: YL-69 / YL-39 Soil Moisture Sensor
   By g4x - 01/2018
*/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266TelegramBOT.h>

// YL-69 sensor
#define moistureCriticalLevel 400
byte pinMoistureSensor = A0;
byte pinMoistureVCC = 4; // D2
int  moistureValue;

// protothreading
int  moistureReadingInterval = 86400;   // interval in seconds between sensor reading (every 24h)
long moistureLastRead = 0;              // last time the moisture was read

int  botScanInterval = 1;               // interval time between scan messages (seconds)
long botLastScan;                       // last time messages' scan has been done

long nowMillis;

// WiFi connection
const char* ssid     = "Mr.Robot";      // wifi name
const char* password = "********";      // wifi password

// Telegram bot
#define botMyChatID "********"          // reference to my phone's chat
#define botToken "********"
#define botName "********";
#define botUsername "********"
TelegramBOT bot(botToken, botName, botUsername);

String botCommand;
String botResponse;


void setup() {
  Serial.begin(9600);
  delay(1000);

  // init the moisture sensor
  pinMode(pinMoistureSensor, INPUT);

  pinMode(pinMoistureVCC, OUTPUT);
  digitalWrite(pinMoistureVCC, LOW);    // by default, we do not power the sensor

  // connect to wifi
  Serial.print("Connecting to \"");
  Serial.print(ssid);
  Serial.println("\"");

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected (");
  Serial.print(WiFi.localIP());
  Serial.println(")");
  Serial.println("");

  // start bot
  bot.begin();
}


void loop() {
  checkSoilMoisture();
  handleBotMessages();
}


void checkSoilMoisture() {
  nowMillis = millis();

  if ((nowMillis > moistureLastRead + (moistureReadingInterval * 1000)) or moistureLastRead == 0) {
    moistureLastRead = nowMillis;

    moistureValue = readMoisture();

    if (moistureValue < moistureCriticalLevel) {
      // send value to Telegram chat
      botResponse = "Avocado: Water me! (Humidity Level [0-1023]: ";
      botResponse.concat(moistureValue);
      botResponse.concat(")");
      bot.sendMessage(botMyChatID, botResponse, "");    // send notification to my phone
    }

    Serial.print("*************** Humidity Level (0-1023): ");
    Serial.println(moistureValue);
    Serial.println("");
  }
}


int readMoisture() {
  digitalWrite(pinMoistureVCC, HIGH); // power up sensor

  delay(500);
  int value = analogRead(pinMoistureSensor);

  digitalWrite(pinMoistureVCC, LOW); // power down sensor

  return 1023 - value;
}


/* Check if the bot received any message */
void handleBotMessages() {
  nowMillis = millis();

  if (nowMillis > botLastScan + (botScanInterval * 1000)) {
    botLastScan = millis();

    bot.getUpdates(bot.message[0][1]);   // launch API GetUpdates up to xxx message

    // loop at messages received
    for (int i = 1; i < bot.message[0][0].toInt() + 1; i++)      {
      handleBotCommands(i);
    }
    bot.message[0][0] = "";   // All messages have been replied - reset new messages
  }
}


/* Execute command sent to the bot */
void handleBotCommands(int line) {
  botCommand = bot.message[line][5]; // message reiceived
  botCommand.toUpperCase();  // not case sensitive anymore

  if (botCommand.equals("/READ")) {

    // read data
    moistureValue = readMoisture();

    //botResponse = "Sensor value: ";
    botResponse = "Humidity Level (0-1023): ";
    botResponse.concat(moistureValue);
    if (moistureValue < moistureCriticalLevel) {
      botResponse.concat(" (critical)");
    }

  } else if (botCommand.equals("/HELP")) {

    botResponse = "Allowed commands are:";
    bot.sendMessage(bot.message[line][4], botResponse, "");
    botResponse = "/read - Read soil moisture";
    bot.sendMessage(bot.message[line][4], botResponse, "");
    botResponse = "/ip - Get local IP address";

  } else if (botCommand.equals("HI") or botCommand.equals("HELLO") or botCommand.equals("COUCOU") or botCommand.equals("SALUT")) {

    botResponse = "Hello " + bot.message[line][2] + " !";  // user's name
    
  } else if (botCommand.equals("/IP")) {
    
    botResponse = "Local IP address: ";
    botResponse.concat(WiFi.localIP().toString());
    
  } else {

    botResponse = "Unknown command, use /help for command list.";

  }
  bot.sendMessage(bot.message[line][4], botResponse, "");    // bot.message[line][4] is chat ID
}

如果您对此项目有任何想法、意见或问题,请在下方留言。

以上内容翻译自网络,原作者:g4x,如涉及侵权,可联系删除。

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论