• Skip to main content
  • Skip to primary sidebar

Homemade Circuit Projects

Need circuit help? Post them in the comments! I've answered over 50,000!

Blog | Categories | About | Hire Me | Contact | Calculators-online
You are here: Home / Arduino Projects / Automatic Ultrasonic Water Pump Motor Controller Circuit

DIY Circuits | Learn Basics | Arduino Coding

Automatic Ultrasonic Water Pump Motor Controller Circuit

Last Updated on April 23, 2026 by Swagatam 8 Comments

This project explains how to build a fully automatic ultrasonic water level controller where the water pump motor starts automatically when the tank level goes below a preset LOW level and stops automatically when the tank becomes FULL. The whole system is wireless, reliable, and there are no corrosion problems because the ultrasonic sensor never touches the water at any point.

Design Used In The System

The design uses an HC-SR04 ultrasonic sensor to measure the water level, Arduino units at both Tx and Rx sides for processing, nRF24L01 RF modules for wireless communication between tank and pump, a relay driver stage to control the water pump motor, and LED indicators with a buzzer to show visual and audible status.

Why Ultrasonic Water Level Sensing

Traditional water level systems using float switches or probe-based sensors usually suffer from corrosion, scaling buildup, mechanical wear, and false triggering over time.

An ultrasonic sensor avoids all these problems because it does not come in contact with water. It simply measures the distance from the sensor to the water surface, and the Arduino then converts this distance value into the actual water level.

We use Arduino nano here for this project:

Transmitter Circuit Diagram

System Overview

The system is divided into two main parts, one at the tank side and the other at the pump side.

Transmitter Unit Tank Side

At the tank side, the ultrasonic sensor is mounted at the top of the tank facing the water surface. The Arduino measures the water level using the sensor data and then sends the water level status wirelessly to the receiver unit.

Receiver Unit Pump Side

At the pump side, the receiver unit receives the water level status data. Based on this information, it controls the LED indicators and buzzer and also drives a relay to switch the water pump ON or OFF automatically.

Transmitter Code (Tank Side)

// ----------- Program Developed by Homemade-circuits.com ----------- //

#include <SPI.h>
#include <RF24.h>

// nRF24L01 pins: CE = 9, CSN = 10
RF24 radio(9, 10);

// RF address (must match receiver)
const byte address[6] = "00001";

// Ultrasonic sensor pins
const int trigger = 3;
const int echo = 2;

// Messages to be transmitted
const char text_stop[] = "STOP";   // Tank FULL → Pump OFF
const char text_full[] = "FULL";
const char text_3by4[] = "3/4";
const char text_half[] = "HALF";
const char text_low[]  = "LOW";    // Tank LOW → Pump ON

// -------- USER CALIBRATION SECTION -------- //
// Actual usable water depth inside tank (meters)
float water_hold_capacity = 1.0;

// Total distance from ultrasonic sensor to tank bottom (meters)
float full_height = 1.3;
// ------------------------------------------ //

// Level thresholds
float level_full;
float level_3by4;
float level_half;
float level_quarter;

// Ultrasonic variables
long pulse_time;
float distance_cm;
float distance_m;
float water_level;
float offset_distance;

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

  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  digitalWrite(trigger, LOW);

  // nRF24L01 initialization
  radio.begin();
  radio.openWritingPipe(address);
  radio.setChannel(100);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.stopListening();   // Transmitter mode

  // Calculate level thresholds
  level_full    = water_hold_capacity;
  level_3by4    = water_hold_capacity * 0.75;
  level_half    = water_hold_capacity * 0.50;
  level_quarter = water_hold_capacity * 0.25;

  // Sensor mounting compensation
  offset_distance = full_height - water_hold_capacity;

  Serial.println("Ultrasonic Water Level Transmitter Ready");
}

void loop()
{
  delay(5000);   // Measurement interval

  // Trigger ultrasonic pulse
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);

  // Read echo pulse
  pulse_time = pulseIn(echo, HIGH, 30000); // timeout safety

  if (pulse_time == 0)
  {
    Serial.println("Sensor Error");
    return;
  }

  // Convert pulse time to distance
  distance_cm = pulse_time * 0.034 / 2;
  distance_m  = distance_cm / 100.0;

  // Convert distance to actual water level
  water_level = water_hold_capacity - (distance_m - offset_distance);

  if (water_level < 0)
    water_level = 0;

  if (water_level > water_hold_capacity)
    water_level = water_hold_capacity;

  // Debug output
  Serial.print("Water Level: ");
  Serial.print(water_level);
  Serial.println(" m");

  // -------- TRANSMISSION LOGIC -------- //

  if (water_level >= level_full)
  {
    radio.write(&text_stop, sizeof(text_stop));  // Pump OFF
    Serial.println("TX: STOP");
  }
  else if (water_level > level_3by4)
  {
    radio.write(&text_full, sizeof(text_full));
    Serial.println("TX: FULL");
  }
  else if (water_level > level_half)
  {
    radio.write(&text_3by4, sizeof(text_3by4));
    Serial.println("TX: 3/4");
  }
  else if (water_level > level_quarter)
  {
    radio.write(&text_half, sizeof(text_half));
    Serial.println("TX: HALF");
  }
  else
  {
    radio.write(&text_low, sizeof(text_low));    // Pump ON
    Serial.println("TX: LOW");
  }

  Serial.println("-----------------------------");
}

// ----------- Program Developed by Homemade-circuits.com ----------- //

Why this transmitter code looks great

Simple reason, it does ultrasonic conversion properly, so readings stay accurate, and it does what it is supposed to do.

Here tank size does not really matter here, you just change two values and it is done. No need to redesign anything, so it fits small tank big tank, whatever you have.

There is timeout protection also, so if sensor fails or gets stuck then system does not keep waiting indefinitely, it safely exits.

Relay chattering is avoided in this design, switching happens only at LOW and FULL, not in between, so relay stays calm without any clicking noise, so there is no damage over time.

This code works fully with the receiver and relay logic given below.

Important installation tip,

Sensor must face straight down, do not tilt it, otherwise readings could go wrong.

Keep around 5–10 cm clearance from tank walls, since reflections can confuse the sensor, and then values can jump.

Please avoid steam and water droplets on sensor face because that can finish of accuracy fast, and then system starts behaving rather weird.

Receiver Stage Wiring Connection Table (For Drawing Schematic)

You can literally draw the full receiver side schematic from this table.

We use Arduino NANO for the wiring:

Arduino Nano PinConnected To
D2LOW LED
D3HALF LED
D43/4 LED
D5FULL LED
D6Buzzer
D7Relay driver input
D9nRF24 CE
D10nRF24 CSN
D11nRF24 MOSI
D12nRF24 MISO
D13nRF24 SCK
5VRelay, LEDs, buzzer
3.3 VnRF24 VCC
GNDCommon ground

Receiver Code With Automatic Pump Control

Below is the receiver code with an added relay output for the motor.

Receiver Code

#include <SPI.h>
#include <RF24.h>

RF24 radio(9, 10);

const byte address[6] = "00001";

const int buzzer = 6;
const int LED_full = 5;
const int LED_three_fourth = 4;
const int LED_half = 3;
const int LED_quarter = 2;
const int relay_pin = 7;   // Pump relay

char text[32] = "";

void setup()
{
  pinMode(buzzer, OUTPUT);
  pinMode(LED_full, OUTPUT);
  pinMode(LED_three_fourth, OUTPUT);
  pinMode(LED_half, OUTPUT);
  pinMode(LED_quarter, OUTPUT);
  pinMode(relay_pin, OUTPUT);

  digitalWrite(relay_pin, LOW);   // Pump OFF at power ON

  digitalWrite(buzzer, HIGH);
  delay(300);
  digitalWrite(buzzer, LOW);

  Serial.begin(9600);

  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setChannel(100);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.startListening();
}

void loop()
{
  if (radio.available())
  {
    radio.read(&text, sizeof(text));
    Serial.println(text);

    // ---------- STOP / FULL ----------
    if (text[0] == 'S' || (text[0] == 'F' && text[1] == 'U'))
    {
      digitalWrite(relay_pin, LOW);   // Pump OFF

      digitalWrite(LED_full, HIGH);
      digitalWrite(LED_three_fourth, HIGH);
      digitalWrite(LED_half, HIGH);
      digitalWrite(LED_quarter, HIGH);
    }

    // ---------- LOW ----------
    if (text[0] == 'L' && text[1] == 'O' && text[2] == 'W')
    {
      digitalWrite(relay_pin, HIGH);  // Pump ON

      digitalWrite(LED_full, LOW);
      digitalWrite(LED_three_fourth, LOW);
      digitalWrite(LED_half, LOW);
      digitalWrite(LED_quarter, HIGH);
    }

    // ---------- INTERMEDIATE LEVELS ----------
    if (text[0] == '3')
    {
      digitalWrite(LED_full, LOW);
      digitalWrite(LED_three_fourth, HIGH);
      digitalWrite(LED_half, HIGH);
      digitalWrite(LED_quarter, HIGH);
    }

    if (text[0] == 'H')
    {
      digitalWrite(LED_full, LOW);
      digitalWrite(LED_three_fourth, LOW);
      digitalWrite(LED_half, HIGH);
      digitalWrite(LED_quarter, HIGH);
    }
  }
}

Relay and Pump Wiring Details

Use a ready-made opto-isolated relay module, that is better and safer.

Relay COM goes to Phase input, then Relay NO goes to pump phase wire, so pump switches ON and OFF from relay.

Neutral wire goes directly to pump, no switching there. Mains voltage is dangerous, so if you are unsure at any point, then consult a qualified electrician, do not take risk.

Ultrasonic Sensor Mounting Tips

Mount the HC-SR04 exactly at the center of the tank lid, not here and there. Keep minimum 5–10 cm clearance from walls, otherwise readings go wrong.

Avoid tilted mounting, sensor must face straight down.

Do not allow water droplets on sensor face, since that will confuse the echo.

Advantages of This Design

No water contact sensors, so nothing corrodes. Long wireless range, works comfortably. Fully automatic, no manual switching. No false triggering, readings stay stable.

Suitable for overhead tanks, common use. Easily expandable, you can add more features later.

Wrapping Up

This ultrasonic water level controller is reliable, scalable and works well for domestic and industrial water tanks. With simple parameter changes in the code, the same design can be used for any tank height or shape, so no redesign needed.

If you build this project, then feel free to share your experience or ask for modifications in the comments.

UPDATE:

As per the suggestions given by Mr. Dhurairaj, I have upgraded the above codes.

Here is a clean, TX + RX pair codes with the following features:

What Makes This Version Strong

First thing, pump turns OFF if signal goes missing, so it just stops, safe side.

Full string match is used, so no false trigger happens, random noise will not confuse it....

It works fine with +PA+LNA modules, so now range side becomes stronger...

Also easy to expand later, you can add more stuff when needed, no restrictions.

Installation Notes (Important)

Use external 3.3V regulator, do not depend on weak onboard supply, since that causes trouble.

Add 10µF capacitor across nRF VCC-GND, this helps stability, otherwise module may behave strange.

When testing, use PA_LOW but when final setup is done then switch to PA_MAX for long range.

Keep antennas in line of sight if you want near 500m range, if obstacles come then range drops, so placement matters.

Transmitter Code

// ----------- Program Developed by Homemade-circuits.com ----------- //

#include <SPI.h>
#include <RF24.h>

RF24 radio(9, 10);

const byte address[6] = "00001";

// Ultrasonic pins
const int trigger = 3;
const int echo = 2;

// Messages
const char text_stop[] = "STOP";
const char text_full[] = "FULL";
const char text_3by4[] = "3/4";
const char text_half[] = "HALF";
const char text_low[]  = "LOW";

// -------- USER SETTINGS -------- //
float water_hold_capacity = 1.0;
float full_height = 1.3;
// -------------------------------- //

float level_full;
float level_3by4;
float level_half;
float level_quarter;

long pulse_time;
float distance_cm;
float distance_m;
float water_level;
float offset_distance;

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

  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  digitalWrite(trigger, LOW);

  radio.begin();
  radio.openWritingPipe(address);
  radio.setChannel(100);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);   // Use LOW for testing, MAX for final deployment
  radio.stopListening();

  level_full    = water_hold_capacity;
  level_3by4    = water_hold_capacity * 0.75;
  level_half    = water_hold_capacity * 0.50;
  level_quarter = water_hold_capacity * 0.25;

  offset_distance = full_height - water_hold_capacity;

  Serial.println("TX Ready");
}

void loop()
{
  delay(5000);   // heartbeat interval

  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);

  pulse_time = pulseIn(echo, HIGH, 30000);

  if (pulse_time == 0)
  {
    Serial.println("Sensor Error");
    return;
  }

  distance_cm = pulse_time * 0.034 / 2;
  distance_m  = distance_cm / 100.0;

  water_level = water_hold_capacity - (distance_m - offset_distance);

  if (water_level < 0) water_level = 0;
  if (water_level > water_hold_capacity) water_level = water_hold_capacity;

  Serial.print("Level: ");
  Serial.print(water_level);
  Serial.println(" m");

  // -------- TRANSMIT -------- //

  if (water_level >= level_full)
  {
    radio.write(text_stop, sizeof(text_stop));
    Serial.println("TX: STOP");
  }
  else if (water_level > level_3by4)
  {
    radio.write(text_full, sizeof(text_full));
    Serial.println("TX: FULL");
  }
  else if (water_level > level_half)
  {
    radio.write(text_3by4, sizeof(text_3by4));
    Serial.println("TX: 3/4");
  }
  else if (water_level > level_quarter)
  {
    radio.write(text_half, sizeof(text_half));
    Serial.println("TX: HALF");
  }
  else
  {
    radio.write(text_low, sizeof(text_low));
    Serial.println("TX: LOW");
  }

  Serial.println("---------------------");
}

// ----------- End ----------- //

Receiver Code:

// ----------- Program Developed by Homemade-circuits.com ----------- //

#include <SPI.h>
#include <RF24.h>
#include <string.h>

RF24 radio(9, 10);

const byte address[6] = "00001";

const int buzzer = 6;
const int LED_full = 5;
const int LED_3by4 = 4;
const int LED_half = 3;
const int LED_quarter = 2;
const int relay_pin = 7;

char text[32] = "";

unsigned long lastReceivedTime = 0;
const unsigned long timeout = 10000;   // 10 seconds failsafe

void setup()
{
  pinMode(buzzer, OUTPUT);
  pinMode(LED_full, OUTPUT);
  pinMode(LED_3by4, OUTPUT);
  pinMode(LED_half, OUTPUT);
  pinMode(LED_quarter, OUTPUT);
  pinMode(relay_pin, OUTPUT);

  digitalWrite(relay_pin, LOW);   // Pump OFF at startup

  digitalWrite(buzzer, HIGH);
  delay(300);
  digitalWrite(buzzer, LOW);

  Serial.begin(9600);

  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setChannel(100);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);   // LOW for testing, MAX for deployment
  radio.startListening();

  lastReceivedTime = millis();

  Serial.println("RX Ready");
}

void loop()
{
  // -------- RECEIVE -------- //
  if (radio.available())
  {
    radio.read(&text, sizeof(text));
    Serial.println(text);

    lastReceivedTime = millis();   // update heartbeat

    // -------- LOGIC -------- //

    if (strcmp(text, "STOP") == 0 || strcmp(text, "FULL") == 0)
    {
      digitalWrite(relay_pin, LOW);   // Pump OFF

      digitalWrite(LED_full, HIGH);
      digitalWrite(LED_3by4, HIGH);
      digitalWrite(LED_half, HIGH);
      digitalWrite(LED_quarter, HIGH);
    }
    else if (strcmp(text, "LOW") == 0)
    {
      digitalWrite(relay_pin, HIGH);  // Pump ON

      digitalWrite(LED_full, LOW);
      digitalWrite(LED_3by4, LOW);
      digitalWrite(LED_half, LOW);
      digitalWrite(LED_quarter, HIGH);
    }
    else if (strcmp(text, "3/4") == 0)
    {
      digitalWrite(LED_full, LOW);
      digitalWrite(LED_3by4, HIGH);
      digitalWrite(LED_half, HIGH);
      digitalWrite(LED_quarter, HIGH);
    }
    else if (strcmp(text, "HALF") == 0)
    {
      digitalWrite(LED_full, LOW);
      digitalWrite(LED_3by4, LOW);
      digitalWrite(LED_half, HIGH);
      digitalWrite(LED_quarter, HIGH);
    }
  }

  // -------- FAILSAFE -------- //
  if (millis() - lastReceivedTime > timeout)
  {
    digitalWrite(relay_pin, LOW);   // Pump OFF

    Serial.println("Failsafe: No Signal → Pump OFF");
  }
}

// ----------- End ----------- //

You'll also like:

  • capacitive fluid meter circuit compressedCapacitive Fluid Meter Circuit for Sealed Tanks
  • 1 2PIC Tutorial- From Registers to Interrupts
  • waterlevelsensorLight Activated Water Level Controller Circuit
  • Programmable Auto Starter Circuit for Diesel Water PumpProgrammable Automatic Starter Circuit for Diesel Water Pump

Filed Under: Arduino Projects, Water Controller Tagged With: Automatic, Controller, Motor, Pump, Ultrasonic, Water

About Swagatam

I am an electronics engineer and doing practical hands-on work from more than 15 years now. Building real circuits, testing them and also making PCB layouts by myself. I really love doing all these things like inventing something new, designing electronics and also helping other people like hobby guys who want to make their own cool circuits at home.

And that is the main reason why I started this website homemade-circuits.com, to share different types of circuit ideas..

If you are having any kind of doubt or question related to circuits then just write down your question in the comment box below, I am like always checking, so I guarantee I will reply you for sure!

Previous Post: « Make this EV Battery Charger Circuit
Next Post: Control a Relay ON OFF Using SIM Card, Mobile Phone, and Arduino »

Reader Interactions

Comments

DHURAIRAJ says:
April 25, 2026 at 9:55 am

Dear Sir,
Further i am in pleasure to share the developed version of the sketch from my side which will serve as a single skecth for both Transmitter and Receiver by shares variables of radio details in common as to avoid the error like address mismatch, data rate also will have the ready reference what we have the payload string for both as a single sketch.
Only thing we need to change a single line before compling according to the falshing of T/R.
Please have you comments and if any thing notable error to correct i am feel free to share the same from you.
Best Regards
-Dhurairaj.
—————sketch follows————

/******************************************************************
WATER LEVEL CONTROL SYSTEM
SINGLE SKETCH – ROLE BASED

Change ONLY this line before upload:

ROLE_TRANSMITTER
ROLE_RECEIVER
******************************************************************/

#define ROLE_TRANSMITTER 1
#define ROLE_RECEIVER 2
//————————————————————-

#define DEVICE_ROLE ROLE_TRANSMITTER
// Example:
//#define DEVICE_ROLE ROLE_RECEIVER

#include
#include
#include

/******************************************************************
SHARED RADIO CONFIGURATION
******************************************************************/

RF24 radio(9, 10); // CE=9, CSN=10
const byte address[6] = “00001”;

#define RADIO_CHANNEL 100
#define RADIO_RATE RF24_250KBPS
#define RADIO_POWER RF24_PA_MAX
// Change to RF24_PA_MAX for final deployment for long distance
// Change to RF24_PA_LOW for testing and short distance

/******************************************************************
================= TRANSMITTER SECTION =================
******************************************************************/

/* Ultrasonic pins */
const int trigger = 3;
const int echo = 2;

/* Messages */
const char text_stop[] = “STOP”;
const char text_full[] = “FULL”;
const char text_3by4[] = “3/4”;
const char text_half[] = “HALF”;
const char text_low[] = “LOW”;

/* USER CALIBRATION */
float water_hold_capacity = 1.0; // meters
float full_height = 1.3; // meters

float level_full;
float level_3by4;
float level_half;
float level_quarter;

long pulse_time;
float distance_cm;
float distance_m;
float water_level;
float offset_distance;

/******************************************************************
TRANSMITTER SETUP
******************************************************************/

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

pinMode(trigger, OUTPUT);
pinMode(echo, INPUT);

digitalWrite(trigger, LOW);

radio.begin();
radio.flush_tx();

// — Mandatory reliability settings —……………….
radio.setAutoAck(true); // Enable acknowledgement
radio.setRetries(5, 15); // Retry delay and count
radio.setCRCLength(RF24_CRC_16); // ADD THIS LINE
radio.disableAckPayload(); // ADD
//———————————————————-

radio.openWritingPipe(address);
radio.setChannel(RADIO_CHANNEL);
radio.setDataRate(RADIO_RATE);
radio.setPALevel(RADIO_POWER);

#if DEVICE_ROLE == ROLE_TRANSMITTER
radio.stopListening();
#endif

level_full = water_hold_capacity;
level_3by4 = water_hold_capacity * 0.75;
level_half = water_hold_capacity * 0.50;
level_quarter = water_hold_capacity * 0.25;

offset_distance = full_height – water_hold_capacity;

Serial.println(“MODE: TRANSMITTER READY”);
}

/******************************************************************
TRANSMITTER LOOP
******************************************************************/

void loop()
{
delay(5000);

digitalWrite(trigger, HIGH);
delayMicroseconds(10); //time for sensor to read
digitalWrite(trigger, LOW);

pulse_time = pulseIn(echo, HIGH, 30000); // getting the values

if (pulse_time == 0)
{
Serial.println(“Sensor Error”);
return;
}

distance_cm = pulse_time * 0.034 / 2.0;
distance_m = distance_cm / 100.0;

water_level =
water_hold_capacity – (distance_m – offset_distance);

if (water_level water_hold_capacity)
water_level = water_hold_capacity;

Serial.print(“Water Level: “);
Serial.print(water_level);
Serial.println(” m”);

if (water_level >= level_full)
{
sendMessage(text_stop);
}
else if (water_level > level_3by4)
{
sendMessage(text_full);
}
else if (water_level > level_half)
{
sendMessage(text_3by4);
}
else if (water_level > level_quarter)
{
sendMessage(text_half);
}
else
{
sendMessage(text_low);
}

Serial.println(“———————“);
}

/******************************************************************
SAFE RADIO SEND FUNCTION
******************************************************************/
void sendMessage(const char *msg)
{
bool ok = radio.write(msg, strlen(msg) + 1);

Serial.print(“TX: “);
Serial.print(msg);

if (radio.failureDetected)
{
Serial.println(” RADIO FAILURE”);
return;
}

if (ok)
Serial.println(” SENT”);
else
Serial.println(” NOT DELIVERED”);
}

/******************************************************************
================= RECEIVER SECTION =================
******************************************************************/
#if DEVICE_ROLE == ROLE_RECEIVER

/* OUTPUT PINS */

const int buzzer = 6;
const int LED_full = 5;
const int LED_3by4 = 4;
const int LED_half = 3;
const int LED_quarter = 2;
const int relay_pin = 7;

/* FAILSAFE */

unsigned long lastReceivedTime = 0;
const unsigned long timeout = 10000;

char text[32];

/******************************************************************
RECEIVER SETUP
******************************************************************/

void setup()
{
pinMode(buzzer, OUTPUT);
pinMode(LED_full, OUTPUT);
pinMode(LED_3by4, OUTPUT);
pinMode(LED_half, OUTPUT);
pinMode(LED_quarter, OUTPUT);
pinMode(relay_pin, OUTPUT);

/* SAFE DEFAULT */

digitalWrite(relay_pin, LOW); // Pump OFF

digitalWrite(buzzer, HIGH);
delay(300);
digitalWrite(buzzer, LOW);

Serial.begin(9600);

radio.begin();

radio.openReadingPipe(0, address);

radio.setChannel(RADIO_CHANNEL);
radio.setDataRate(RADIO_RATE);
radio.setPALevel(RADIO_POWER);

radio.startListening();

lastReceivedTime = millis();

Serial.println(“MODE: RECEIVER READY”);
}

/******************************************************************
RECEIVER LOOP
******************************************************************/

void loop()
{
if (radio.available())
{
radio.read(&text, sizeof(text));

Serial.print(“RX: “);
Serial.println(text);

lastReceivedTime = millis();

processMessage();
}

/* FAILSAFE */

if (millis() – lastReceivedTime > timeout)
{
digitalWrite(relay_pin, LOW);

Serial.println(
“Failsafe: No Signal -> Pump OFF”
);
}
}

/******************************************************************
MESSAGE PROCESSING
******************************************************************/

void processMessage()
{
if (strcmp(text, “STOP”) == 0 ||
strcmp(text, “FULL”) == 0)
{
digitalWrite(relay_pin, LOW);

digitalWrite(LED_full, HIGH);
digitalWrite(LED_3by4, HIGH);
digitalWrite(LED_half, HIGH);
digitalWrite(LED_quarter, HIGH);
}

else if (strcmp(text, “LOW”) == 0)
{
digitalWrite(relay_pin, HIGH);

digitalWrite(LED_full, LOW);
digitalWrite(LED_3by4, LOW);
digitalWrite(LED_half, LOW);
digitalWrite(LED_quarter, HIGH);
}

else if (strcmp(text, “3/4”) == 0)
{
digitalWrite(LED_full, LOW);
digitalWrite(LED_3by4, HIGH);
digitalWrite(LED_half, HIGH);
digitalWrite(LED_quarter, HIGH);
}

else if (strcmp(text, “HALF”) == 0)
{
digitalWrite(LED_full, LOW);
digitalWrite(LED_3by4, LOW);
digitalWrite(LED_half, HIGH);
digitalWrite(LED_quarter, HIGH);
}
}

#endif
————————–sketch ends——————–

Reply
Swagatam says:
April 25, 2026 at 5:20 pm

Dear Dhurairaj,
Your updated sketch is very well designed and I really appreciate the effort you have made to improve reliability and simplifying the configuration. The idea of using a single sketch with role selection is excellent and it avoids many common mistakes….

You have also correctly added important RF features such as Auto Acknowledgement, retries and CRC which makes the communication much more stronger. The failsafe mechanism on the receiver side is also a very important and correct addition.

But I can notice a few issues which need correction:

Both transmitter and receiver have separate setup() and loop() functions but the transmitter section is not enclosed inside a conditional compilation block. This can cause compilation conflicts. Please wrap both TX and RX sections using:

#if DEVICE_ROLE == ROLE_TRANSMITTER
// TX code
#endif

#if DEVICE_ROLE == ROLE_RECEIVER
// RX code
#endif

The code uses smart quotes (“ ”) instead of standard quotes (” “) which can cause compilation errors. Please replace all of them.
Required header files are missing. Please include:
#include
#include
#include
There is a small typo in this line:
if (water_level water_hold_capacity)
which should be corrected to:
if (water_level > water_hold_capacity)
The line checking radio.failureDetected may not be supported in all RF24 libraries so it is safer to remove it….

Once these corrections are applied then only your design will be very solid and suitable for real practical installation…

Reply
Dhurairaj says:
April 19, 2026 at 9:36 pm

dear sir,
the above circuit is not working.
at transmitter I checked and serial monitor i can see the sensor working and giving calculated values but at receiver side I expect leds to light norespo se only beeper works at reset as per code
the only difference i am is using nRF24L01 +PA+LNB for both transmitter and receiver.
will it not be compatible with our sketch.

kindly revert
-dhurairaj
tnd285@gmail.com
+91-9884317582 (wa)

Reply
Swagatam says:
April 20, 2026 at 8:56 am

Hello Dhurairaj,
I have posted the full schematic, please check it in the above article. Also, please read the following and modify the design accordingly

the +PA+LNA version is fully compatible with the sketch, so that is not the issue. The problem is mostly due to power and RF stability.

These modules draw high current (100 mA+) and the Arduino 3.3V pin cannot supply it properly. Because of this the receiver does not get any valid data, which is why only the buzzer works at startup and no LEDs respond.

To fix this please do the following:

Use a separate 3.3V regulator (like AMS1117-3.3) for both transmitter and receiver modules
Add a 10µF capacitor across VCC and GND of the nRF24 module
Reduce PA level in both codes:
radio.setPALevel(RF24_PA_LOW);
Keep at least 1–2 meters distance between TX and RX
Double check wiring connections carefully

Reply
Dhurairaj says:
April 22, 2026 at 8:17 am

Dear Sir,
Thanks for your kind response.
what is an advantage or purpose to reduce PA level in both codes as LOW
please brief out and what is the 1-2 meters distance between TX and RX and i am unable to understand this point.

the main idea of using this circuit is as i wanted to deploy this for one of the school buildings where tank and the pump house switch beyond distance due to a children playgound is located and hardly possible to take the water level signal by wire hence planed for wireless this Radio method (wifi valid out that area)

thinking that may be communication possible as 400-500mts distance betwee pump switch room away the main builidng of tank located at 6th floor so tring this nRF240L +PA+LNA moudule as efficient one but setting PA as LOW means what is an idea behind this point.

kinldy revert
Dhurairaj
+91-9884317582 (WA)
tnd285@gmail.com

Reply
Swagatam says:
April 22, 2026 at 2:06 pm

Thank you Dhurairaj, for the good question,
actually reducing PA level to LOW is only for testing and stability. At high power (PA_MAX), the nRF24L01 +PA+LNA module draws high current and if the power supply is not strong, communication fails. Also when transmitter and receiver are very close, high power can overload the receiver and cause data loss.

So during testing we reduce PA level and keep about 1 to 2 meters distance between modules to ensure stable communication.

But, for your actual application (400 to500 meters) you should use PA_MAX, but only after ensuring you have a high current and stable 3.3V power supply with proper capacitors. Also use antenna-type modules and keep them in a clear line of sight.

Reply
Dhurairaj says:
April 22, 2026 at 11:56 pm

Dear Sir,
Thank you for you kind clarification regarding PA max / low decleration in the sketch and let me follow as advised for testing as low and at final i can flash with high before to deploy the units.

I am wondering why the sketch does not have any heartbeat funciton because i am worried if power outage at transmitter side then it fails to send the pump off string and the receiver already under pump on then motor continuosuly on and over flow happens hence why dont you implement the heartbeat as an additional string like “ROK” as waterlevel, pump off and on just for radio ok, at every interval of 5 sec which confirms transmitter under operational both power available and communication ok and if reciver senses more than 10sec missing ROK signal then immediately pump should off as the communication fails in order to get the actual pump off signal subsequently possible.

please revert so that let me update with your latest sketch for both accrodinly and use it
Regards,
-Dhurairaj.

Reply
Swagatam says:
April 23, 2026 at 8:21 am

Thank you Dhurairaj,

Your idea of adding a heartbeat signal is correct and is a very good safety improvement.

I have updated the codes accordingly, please see the new codes at the end of the above post…

In this design since the transmitter is already sending data every 5 seconds, we can treat each received message as a heartbeat signal. So instead of adding a separate “ROK” message, we can implement a timeout in the receiver.

If the receiver does not receive any valid data for more than 10 seconds, it can automatically turn OFF the pump. This ensures that in case of transmitter power failure or communication loss, the pump will not continue running.

Reply

Need Help? Please Leave a Comment! We value your input—Kindly keep it relevant to the above topic! Cancel reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

circuit simulator image

Subscribe to get New Circuits in your Email

Categories

  • Arduino Projects (96)
  • Audio and Amplifier Projects (133)
  • Automation Projects (18)
  • Automobile Electronics (103)
  • Battery Charger Circuits (87)
  • Datasheets and Components (109)
  • Electronics Theory (149)
  • Energy from Magnets (27)
  • Games and Sports Projects (11)
  • Grid and 3-Phase (20)
  • Health related Projects (27)
  • Home Electrical Circuits (13)
  • Indicator Circuits (16)
  • Inverter Circuits (96)
  • Lamps and Lights (159)
  • Meters and Testers (72)
  • Mini Projects (28)
  • Motor Controller (68)
  • Oscillator Circuits (28)
  • Pets and Pests (15)
  • Power Supply Circuits (91)
  • Remote Control Circuits (50)
  • Renewable Energy (12)
  • Security and Alarm (64)
  • Sensors and Detectors (106)
  • SMPS and Converters (41)
  • Solar Controller Circuits (60)
  • Temperature Controllers (43)
  • Timer and Delay Relay (50)
  • Voltage Control and Protection (43)
  • Water Controller (37)
  • Wireless Circuits (31)

Other Links

  • Privacy Policy
  • Cookie Policy
  • Disclaimer
  • Copyright
  • Videos
  • Sitemap

People also Search

555 Circuits | 741 Circuits | LM324 Circuits | LM338 Circuits | 4017 Circuits | Ultrasonic Projects | SMPS Projects | Christmas Projects | MOSFETs | Radio Circuits | Laser Circuits | PIR Projects |

Social Profiles

  • Twitter
  • YouTube
  • Instagram
  • Pinterest
  • My Facebook-Page
  • Stack Exchange
  • Linkedin

Recent Comments

  • Swagatam on Automatic Ultrasonic Water Pump Motor Controller Circuit
  • Swagatam on Single Phase Variable Frequency Drive VFD Circuit
  • Swagatam on Making an EGS002 Equivalent Board using Arduino
  • Swagatam on EGS002 Datasheet, Circuit Diagram Explained
  • DHURAIRAJ on Automatic Ultrasonic Water Pump Motor Controller Circuit

© 2026 · Swagatam Innovations