top of page
Writer's pictureRamesh G

IoT Water Level Controller using Ultrasonic

Updated: Jul 2, 2021



Here to build a water level monitoring and controller based on Internet of things. we used an ultrasonic distance sensor to measure water level, here we are also going to use the same non-contact method because of its convenience and accuracy in reading of water level.

Measuring water level is same as measuring distance of solid surfaces, the ultrasonic transducer outputs a train of ultrasonic bursts at 40 KHz which will hit the water surface and reflect back to the sensor. The time taken between sent and received ultrasonic waves are calculated by a microcontroller such as ESP8266 12E. The measured distance is converted in to percentage.




Circuit Diagram


Components Required

To make this project you need the following components:

  • ESP8266 Development Board

  • HC-SR04 Ultrasonic sensor

  • 5V 1 Channel Relay Module

  • Breadboard

  • Jumper wires

Ultrasonic:

The HC-SR04 ultrasonic module is a module that can provide non-contact measurement within the range of 2cm to 400cm with ranging accuracy that can reach 3mm. It works on the principle of echolocation.

The ultrasonic sensor as a trigger and an echo pin. The arduino provides a high signal of 10microseconds to this pin. After the HC-SR04 is triggered, it sends out eight 40Khz sound waves to the surface of the water. On getting to the surface of the water, the wave is echoed back to the sensor and the ESP8266 reads the echo pin to determine time spent between triggering and receiving of the echo. Since we know that the speed of sound is around 340m/s then we can calculate the distance using;

Distance = (time/2)*speed of sound


Ultrasonic HC-SR04 wiring to ESP8266

Ultrasonic HC-SR04 ESP8266

Vcc Pin Vin Pin

Trig Pin D1 (GPIO 5)

Echo Pin D2 (GPIO 4)

GND Pin GND


NodeMCU:

NodeMCU ESP8266-12E MCU is a development board with one analogue and many general-purpose input output (GPIO) pins. It has 4MB flash memory, and can operate at a default clock frequency of 80MHz. In this project, digital pin D4 of NodeMCU is used to control of Water Pump ON/OFF. And digital pin D1 &D2 of NodeMCU is used to read data of distance sensor HC-SR04.


Here's a nice example of a modern, flat style slider using pips. There are no labels so this kind of slider would be purely visual without much help to the user for knowing their real chosen value. In this example we make use of the .ui-slider-pip-inrange class to create the nice "filled in" effect on the pips.



The default way to use the plugin is to call the pips method on an initialized slider. This will add the markers along the slider, and place the min/max values to the beginning/end of the slider:


In this Project jQuery UI Slider Pips added in the Web page to adjust the Value between two points 0 to 100.

  • 1st Point for water Level Lower Threshold value adjustment slider to Control Motor ON.

  • 2nd Point for water Level Higher Threshold value adjustment slider to Control Motor OFF.

Cylinder Fill

The cylinder is the main component in a cylinder chart. You can understand the value being illustrated by looking at the percentage of cylinder filled.

The cylinder gauge is a real-time chart, which can update its data after specified intervals, without requiring any page refreshes. In this section, you will be shown how you can create a simple cylinder gauge.


Create a Cylinder Gauge

Use the following attributes to create a simple cylinder gauge:

  • Specify the type using the type attribute. To render Cylinder gauge, set cylinder.

  • Set the container object using renderAt attribute.

  • Specify the dimension of the chart using width and height attributes.

  • Set the type of data (JSON/XML) you want to pass to the chart object using dataFormat attribute.

  • Use the lowerLimit attribute to specify the lower limit, or the minimum value, of the gauge scale.

  • Use the upperLimit attribute to specify the upper limit, or the maximum value, of the gauge scale.

  • Use the lowerLimitDisplay attribute to specify the label to be displayed with the lower limit value on the gauge scale.

  • Use the upperLimitDisplay attribute to specify the label to be displayed with the upper limit value on the gauge scale.

  • Use the numberSuffix attribute to specify the character(s) to be appended to the end of a number.



Subscribe and Download code.


Code:

#include <ESP8266WiFi.h>

#include <HCSR04.h>

#include <ESP8266WebServer.h>


const char* ssid = "TP-Link_3200"; // your SSID

const char* password = "9500112137"; //your wifi password


const char index_html[] PROGMEM={"<!DOCTYPE html>\n"

"<html>\n"

"<head>\n"

"<title>IOT Based Water Level Controller Using Ultrasonic</title>\n"

"<script type=\"text/javascript\" src=\"http://static.fusioncharts.com/code/latest/fusioncharts.js\"></script>\n"

"<script type=\"text/javascript\" src=\"http://static.fusioncharts.com/code/latest/themes/fusioncharts.theme.fint.js?cacheBust=56\"></script>\n"

"<script src=\"https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js\"></script>\n"

"<script src=\"https://simeydotme.github.io/jQuery-ui-Slider-Pips/dist/js/jquery-plus-ui.min.js\"></script>\n"

"<script src=\"https://simeydotme.github.io/jQuery-ui-Slider-Pips/dist/js/jquery-ui-slider-pips.js\"></script>\n"

"<link rel=\"stylesheet\" href=\"https://simeydotme.github.io/jQuery-ui-Slider-Pips/dist/css/jqueryui.min.css\">\n"

"<link rel=\"stylesheet\" href=\"https://simeydotme.github.io/jQuery-ui-Slider-Pips/dist/css/jquery-ui-slider-pips.min.css\">\n"

"<link rel=\"stylesheet\" href=\"https://simeydotme.github.io/jQuery-ui-Slider-Pips/dist/css/app.min.css\">\n"

"<style>\n"

".raphael-group-7-background rect {\n"

"fill: rgb(255, 255, 255) !important;\n"

"}\n"

"[id*=flat-slider].ui-slider.ui-slider-vertical {\n"

"\theight: 320px;\n"

"\tmargin-top: 90px;\n"

" margin-right: 15%;\n"

" margin-bottom: 90px;\n"

" margin-left: 15%;\n"

"}\n"

"$bg: #609fd2;\n"

"[id*=flat-slider].ui-slider,\n"

"[id*=flat-slider].ui-slider .ui-slider-pip .ui-slider-line {\n"

" background: darken($bg, 15%);\n"

"}\n"

"[id*=flat-slider].ui-slider .ui-slider-handle .ui-slider-tip:after {\n"

" border-left-color: #609fd2;\n"

"}\n"

"[id*=flat-slider].ui-slider .ui-slider-handle.ui-state-hover, \n"

"[id*=flat-slider].ui-slider .ui-slider-handle.ui-state-focus, \n"

"[id*=flat-slider].ui-slider .ui-slider-handle.ui-state-active {\n"

" border-color: white; }\n"

"body {\n"


" \n"

" font-family: \"Roboto\";\n"

"}\n"

".stuff { \n"

" padding: 10px 5px 5px;\n"

" max-width: 150px; \n"

"\tmax-height: 550px; \n"

"}\n"

"div.inline { float:left; }\n"

".clearBoth { clear:both; }\n"

"\n"

"</style>\n"

"<script>\n"

"$(document).ready(function() {\n"

" setInterval(\"get_motor_status()\", 2000);\n"

" });\n"

"\t\t\t\t\n"

" function get_motor_status() {\n"

" var someUrl = \"/motor_status\";\n"

" $.ajax({url: someUrl,dataType: \"text\",success: function(response) {\n"

" if (response == \"on\")\n"

" $(\"#status\").html(\"Water Pump ON\")\n"

" else\n"

" $(\"#status\").html(\"Water Pump OFF\")\n"

" }})}\t\t\n"

"\t\t\t\t\n"

" </script>\n"

"\t\n"

"<script type=\"text/javascript\">\n"

" FusionCharts.ready(function(){\n"

" var fusioncharts = new FusionCharts({\n"

" \"type\": \"cylinder\",\n"

" \"dataFormat\": \"json\",\n"

" \"id\": \"fuelMeter\",\n"

" \"renderAt\": \"chart-container\",\n"

" \"width\": \"300\",\n"

" \"height\": \"450\",\n"

" \"dataSource\": {\n"

" \"chart\": {\n"

" \"theme\": \"fint\",\n"

" \"caption\": \"Tank Water Level Controller\",\n"

" \"subcaption\": \"using ultra sonic\",\n"

" \"lowerLimit\": \"0\",\n"

" \"upperLimit\": \"100\",\n"

" \"lowerLimitDisplay\": \"Empty\",\n"

" \"upperLimitDisplay\": \"Full\",\n"

" \"numberSuffix\": \" % of Liter\",\n"

" \"showValue\": \"1\",\n"

" \"chartBottomMargin\": \"10\"\n"

" },\n"

" \"value\": \"10\"\n"

" },\n"

" \"events\": {\n"

" \"rendered\": function(evtObj, argObj) {\n"

"\tsetInterval(function() {\n"

"\tvar someUrl = \"/level\";\n"

"\t\t\t\t\t$.ajax({\n"

"\t\t\t\t\t\turl: someUrl,\n"

"\t\t\t\t\t\tdataType: \"text\",\n"

"\t\t\t\t\t\tsuccess: function(response) {\n"

"\t\t\t\t\t\t\t evtObj.sender.feedData(\"&value=\" + response);\n"

"\t\t\t\t\t\t},\n"

"\t\t\t\t\t\ttimeout: 1000\n"

"\t\t\t\t\t})\t\n"

"\t\t\n"

" }, 1000); \n"

" }\n"

"}\n"

"});\n"

" fusioncharts.render();\n"

" });\n"

"</script>\n"

"</head>\n"

"<body>\n"

"<div style=\"width:600px;margin:auto;\">\n"

"\n"

"<div class=\"stuff\">\n"

" \n"

" <main> \n"

" <div class=\"inline\" id=\"flat-slider-vertical-1\"></div> \n"

" </main>\n"

" \n"

"</div>\n"

" <div style=\"margin-left: 10px;\" class=\"outline\" id=\"chart-container\">FusionCharts XT will load here!</div>\n"

"\t<div class=\"inline\" id=\"status\" style=\"background-color: white;\n"

" width: 200px;\n"


" margin: 1px;\">Water Pump OFF</div>\n"

" </div>\n"

"\n"

"<script>\n"

"$.extend( $.ui.slider.prototype.options, { \n"

" animate: 300\n"

"});\n"

"\n"

"\n"

"$(\"#flat-slider-vertical-1\")\n"

" .slider({\n"

" max: 100,\n"

" min: 0,\n"

" range: true,\n"

" values: [20, 75],\n"

" orientation: \"vertical\",\n"

"\t\t\n"

"\t\tslide: function( event, ui ) {\n"

"\t\tconsole.log(ui.values);\n"

"\t\tvar someUrl = \"/configRange?lower=\" + ui.values[0]+\"&upper=\"+ui.values[1];\n"

" $.ajax(\n"

"\t\t\t{\n"

"\t\t\t\turl: someUrl,dataType: \"text\",success: function(response) {}\n"

"\t\t\t}) \n"

" }\n"

" })\n"

" .slider(\"pips\", {\n"

" first: \"pip\",\n"

" last: \"pip\"\n"

" })\n"

" .slider(\"float\");\n"

"</script>\n"

"\n"

"\t</body>\n"

"</html>"

};





#define MAX_HEIGHT 27 // tank height 27 cm manually enter here for automatic empty tank //scan refer post https://www.dofbot.com/post/water-level-monitoring


#define MOTOR_CONTROL_PIN D4


UltraSonicDistanceSensor distanceSensor(D1,D2); //D1 trig, D2=echo


int waterLevelLowerThreshold=15;

int waterLevelUpperThreshold=90;


float volume = 0;

float liters = 0;


WiFiClient client;


String inputString = ""; // a string to hold incoming data

String dataToSend="";

int waterLevelDownCount=0,waterLevelUpCount=0;


ESP8266WebServer server(80);

void handleRoot() {

server.send_P(200, "text/html;charset=UTF-8", index_html);

}


void handleLevelRequest(){

server.send(200,"text",String(liters));

}


void handleNotFound(){

String message = "File Not Found\n\n";

server.send(404, "text/plain", message);

}

void handleStatus()

{

if(digitalRead(MOTOR_CONTROL_PIN)==0)//MOTOR ON

server.send(200, "text/plain","on");

else server.send(200, "text/plain","off");

}

void handleRangeSetting(){

waterLevelLowerThreshold=(server.arg(0)).toInt();

waterLevelUpperThreshold=(server.arg(1)).toInt();

Serial.print(waterLevelLowerThreshold);

Serial.print(":");

Serial.println(waterLevelUpperThreshold);

server.send(200, "text/plain", "");

}


void measure_Volume()

{

float heightInch=1*distanceSensor.measureDistanceCm();

Serial.println(heightInch);

volume=(MAX_HEIGHT-heightInch)/28;//MAX_HEIGHT-distance will give actual height, 1 cm for // offset adjustment

liters=volume*100 ; // for percentage

Serial.println(liters);


if(liters<=waterLevelLowerThreshold)

waterLevelDownCount++;

else waterLevelDownCount=0;


if(liters>=waterLevelUpperThreshold)

waterLevelUpCount++;

else waterLevelUpCount=0;



if(waterLevelDownCount==3)

{//TURN ON RELAY

Serial.println("motor turned on");

digitalWrite(MOTOR_CONTROL_PIN,LOW);//Relay is active LOW

}

if(waterLevelUpCount==3)

{//TURN OFF RELAY

Serial.println("motor turned off");

digitalWrite(MOTOR_CONTROL_PIN,HIGH);//Relay is active LOW

}

}

void runPeriodicFunc()

{

static const unsigned long REFRESH_INTERVAL1 = 1000; // 2.1sec

static unsigned long lastRefreshTime1 = 0;

if(millis() - lastRefreshTime1 >= REFRESH_INTERVAL1)

{

measure_Volume();

lastRefreshTime1 = millis();

}

}



void setup(void){

Serial.begin(115200);

delay(100);

pinMode(MOTOR_CONTROL_PIN, OUTPUT);

WiFi.begin(ssid, password);

Serial.println("");

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

}

Serial.print("IP address:");

Serial.println(WiFi.localIP());


server.on("/", handleRoot);

server.on("/level",handleLevelRequest);

server.on("/configRange",handleRangeSetting);

server.on("/motor_status",handleStatus);

server.onNotFound(handleNotFound);


server.begin();

Serial.println("HTTP server started");

}


void loop(void){

runPeriodicFunc();


server.handleClient();

}


Then, upload the code to your NodeMCU board. Make sure you have selected the right board and COM port. Also, make sure you’ve inserted your WiFi Credentials in the code.

After a successful upload, open the Serial Monitor at a baud rate of 115200. Press the “EN/RST” button on the ESP8266 board. Now it should print its IP address.

Open Browser and type ip address in the address bar and see the below result.

Subscribe and Download code.

3,810 views0 comments

Comments


bottom of page