Pump Motor DC is ON while it supposed to be OFF if meet desire above threshold moisture

Hi guys, currently i am working on my project which is smart irrigation. Here the wiring detail, all component is working, but the main is the pump doesn't work correctly as the code, like i want the pump off if the soil moisture is above 30%, but when already above 30% the pump still pumping the water, and i see the relay led is turn on the red and the green one, please help me what's wrong?

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define WIFI_SSID "xxxxx"
#define WIFI_PASSWORD "xxxxx"

#define THINGSBOARD_SERVER "thingsboard.cloud"
#define TOKEN "xxxxxxx"  // Access token dari ThingsBoard
#define MQTT_PORT 1883

#define SOIL_MOISTURE_PIN A0
#define THRESHOLD_MOISTURE 30  // Dalam %
#define PUMP_PIN 14  // GPIO14 = D5

WiFiClient espClient;
PubSubClient client(espClient);
LiquidCrystal_I2C lcd(0x27, 16, 2);

unsigned long lastSend = 0;
bool isPumpOn = false;

void connectToWiFi() {
  Serial.print("Connecting to WiFi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi");
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("WiFi Connected");
  lcd.setCursor(0, 1);
  lcd.print(WIFI_SSID);
}

void connectToThingsBoard() {
  while (!client.connected()) {
    Serial.print("Connecting to ThingsBoard...");
    if (client.connect("ESP8266", TOKEN, NULL)) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" retrying in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(9600);
  pinMode(PUMP_PIN, OUTPUT);

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Connecting...");

  connectToWiFi();
  client.setServer(THINGSBOARD_SERVER, MQTT_PORT);
}

void loop() {
  if (!client.connected()) {
    connectToThingsBoard();
  }

  client.loop();

  if (millis() - lastSend > 3000) {
    sendTelemetry();
    lastSend = millis();
  }
}

void sendTelemetry() {
  int soilAnalog = analogRead(SOIL_MOISTURE_PIN);
  int soilMoisture = map(soilAnalog, 800, 300, 0, 100);
  soilMoisture = constrain(soilMoisture, 0, 100);

  // Kontrol pompa otomatis
  if (soilMoisture < THRESHOLD_MOISTURE) {
    digitalWrite(PUMP_PIN, LOW);
    isPumpOn = true;
    Serial.println("Pompa ON (otomatis)");
  } else {
    digitalWrite(PUMP_PIN, HIGH);
    isPumpOn = false;
    Serial.println("Pompa OFF");
  }

  // Tampilkan ke LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Moisture:");
  lcd.print(soilMoisture);
  lcd.print("%");

  lcd.setCursor(0, 1);
  lcd.print("Pump:");
  lcd.print(isPumpOn ? "ON " : "OFF");

  Serial.print("Soil analog: ");
  Serial.println(soilAnalog);
  Serial.print("Soil moisture (%): ");
  Serial.println(soilMoisture);

  // Kirim ke ThingsBoard
  String payload = "{";
  payload += "\"soilMoisture\":" + String(soilMoisture) + ",";
  payload += "\"pumpStatus\":\"" + String(isPumpOn ? "ON" : "OFF") + "\"";
  payload += "}";

  Serial.print("Sending: ");
  Serial.println(payload);

  client.publish("v1/devices/me/telemetry", payload.c_str());
}

Welcome to the forum

Please post your sketch, using code tags when you do

Posting your code using code tags prevents parts of it being interpreted as HTML coding and makes it easier to copy for examination

In my experience the easiest way to tidy up the code and add the code tags is as follows

Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

It is also helpful to post error messages in code tags as it makes it easier to scroll through them and copy them for examination

okay, done!

What part does the Uno play in your project ?
It is not designed to be used as a power supply if that is what you are using it for

In your code you have

#define PUMP_PIN 14  // GPIO14 = D5

but in your picture there is no connection to pin D5

In any case, why not use the 'D' pin number in the code ?

Oh i am so sorry, there's a typo, i'm using D5 esp8266 for the input of relay and The uno i use for the source to relay and lcd i2c which is these two need a 5v input

why not use the 'D' pin number in the code is because the esp8266 uses a numbering system where some pins might be labeled "D0", "D1", "D2", etc., on development boards. These labels correspond to specific GPIO numbers (e.g., GPIO16, GPIO1, GPIO0, etc.). I see there's many more example code related to esp8266 is different than the uno when mention the pin it must be mention the GPIO number, if i stay at D there will be an error like this "Compilation error: 'D5' was not declared in this scope"

Make your loop non-blocking.

void loop() {
    connectCheck();
    moistureCheck();
    if (client.connected()) 
    {
        client.loop();
        if (millis()-lastSend > 3000) 
        {
            sendTelemetry();
            lastSend = millis();
        }
    }
}
void connectCheck() {

    static bool      waiting = false;
    static uint32_t  t;

    if (waiting  &&  (millis()-t >= 5000)) waiting = false;

    if (!waiting  &&  !client.connected()) 
    {
        Serial.print("Connecting to ThingsBoard...");
        if (client.connect("ESP8266", TOKEN, NULL)){
            Serial.println("connected");
        } else {
            Serial.print("failed, rc=");
            Serial.print(client.state());
            Serial.println(" retrying in 5 seconds");
            waiting = true;
            t = millis();
        }
    }
}

thankyou for the help, but i have some problem when compile it with your code
Compilation error: 'moistureCheck' was not declared in this scope

any solution?

I wrote an example (though not complete) to show how to write non-blocking code, which helps carry out all necessary operations without delays caused by other parts of the program (such as waiting loops or delays). Now, what should the missing function do? It needs to handle reading the values and controlling the relay—things you've already written in the sendTelemetry function.

That is a very bad hardware set-up.
You should not use an Uno as a power source.
Your relay may not work with the 3,3V signal from the 8266
Connecting a 5V relay to the 8266 may damage the 8266.

What relay module do you have?

:)))), Relay module 1 channel 5V

i see, but still not working too

Need more info.
Post the datasheet or a link to the website for the module.
In the meantime disconnect everything so that you don't damage the 8266

Which ESP8266 board are you using and what have you got the target board set to in the IDE ?

I lost the website link where I purchased it, but I sent this link which is similar to the type of relay I use https://images.app.goo.gl/SzuQY

okay, thankyou for the reminder!

Module NodeMCU Lua ESP8266 ESP12E V3

in the IDE i choose Generic ESP8266 Module

what i mean still not working is, the output still the same as my problem, above the threshold but still on

First you have to make the hardware correct, then you can fix the softwate.
You need to connect the relay like this:

But you are not using a Generic ESP8266. Set the board to one of the NodeMCU variants and you will be able to use the 'D' pin names. This will avoid the need to convert the pin number shown on the board to a chip GPIO pin number

okay, thanks for the reference, but is there any other solution besides me having to find a 5v source, I don't know what to replace the 5v, is there any ways like replace a suitable type of relay or something?

i see, thankyou for the information!

You can use the same battery pack that powers the pump to also power the relay.
Note the diode in the positive lead to the relay

1 Like