IoT Water Supply Chain Management System using Arduino and NodeMCU

Published  February 24, 2022   0
Water Supply Chain Management System using Arduino and NodeMCU

It is important to first understand what the project is intended to do. Way before starting my IoT & Robotics journey I always wanted to solve the problem of overflowing water tanks. So, after understanding what do Internet of Things & Machine Learning means I thought of making a project which will eliminate this traditional problem to the full extent. But I was startled to see that there were already thousands of projects covering this area. Almost every sensor out there has been used in these projects.

I think all of the projects which were made earlier have the following drawbacks:

  • In the real world scenario the water supply chain, from the water source (eg dam, water facility) to water tanks in our home is a very long one and we have to admit that the problem of water wastage starts from the initial end of the cycle and penetrates through the very last end of that cycle. All of the previous projects only focus on the very last end of the cycle ie the project only deals with the water tanks of our homes.
  • The projects were almost passive. By passive I mean that they will monitor the water level and will turn the water motor off when the water reaches a certain level. This whole computation would be done within the microprocessor and the end-user can’t get to know what is happening inside the code at the moment!
  • Less interactive projects. If one can provide some motion or life to the immobile projects then it will greatly enhance the chances of implementing the project in real life.
  • Very few of the projects use the concept of Machine Learning. Those who use the ML concepts are just using the pre-built easy structured graphs and anomaly detection things which don’t make much more sense!! So, I wanted to make a project which must be very different from the existing projects. Then I came up with the project Wheels 4 Water, a perfect amalgamation of IoT, Machine Learning & Cloud.

Let me point out the main highlights of my project, which make my project stand out from others.

  • Apart from the basic sensors, I have used many different sensors. Be it a water flow sensor, solenoid valve, or an analog multiplexer IC (CD4051), all these sensors helped me to almost nullify the water wastage through the whole water supply chain. In this manner, I focused on the whole water supply chain.
  • At every instance of the project execution, the end-user will be updated and informed about each major workflow. The project will talk with the user. Thus making the project active. To make this project more interactive, I dumped the old idea of integrating IFTTT or using the CLI. Even I have not used either the Blynk application or the normal switches in my project. Instead of all this, I have provided four custom options to control the project which include a dedicated website, NodeMCU based robot, customized cloud dashboard & voice control (I have not used any drag and drop feature of Blynk or IFTTT applications)
  • Rather than using simple and pre-built ML systems I used the Iterative Dichotomiser 3algorithm and implemented it via Python so that the robot can make decisions on its own after analyzing the dataset.

Water Management Project

Component Required for Water Management

Project Used Hardware

I2C LCD, Nodemcu ESP8266, 5V Realy, DC Motor 12V, IR Sensors, Arduino Uno, 9V Battery, Piezo Buzzer, IRF540 MOSFET. Bolt WiFi Module, Ultrasonic Sensor, Water Flow Sensor YFS-401, TCS3200 Color Sensor, 12V DC Solenoid Valve, Capacitive Touch Sensor, 1N4007 Diode, ESP8266 Motor Driver Shield, Analog Multiplexer IC CD4051, Water Lifting Submersible Pump, 3-6V Mini Submersible Water Pump, 4 Way Capacitive Touch Switch Module, Breadboard (1 small and 1 large), Robot Chasis & Jumper Wires

Project Used Software

Arduino IDE, Python, Integromat, Bootstrap Studio, Twilio, Canva, Icons8, Mega Creator

Project Hardware Software Selection

First of all, I will discuss why I have chosen the given hardware in the project. Sensors Used With ARDUINO: 5V Relay, I2C LCD, Boltduino, 9V Battery, Bolt Wifi Module, IRF540 MOSFET, Water Flow Sensor, Ultrasonic Sensor X 2, 1N4007 Rectifier Diode, 12V DC Solenoid Valve, Water Lifting Submersible Pump, 4-way Capacitive Touch Switch Module, 3-6 V Mini Micro Submersible Water Pump. As this is the stationed section of the project. So, I tried to majorly do the following things in this phase of the project:

Make the Arduino and python programs communicate with each other, keep an eye on the water level on all of the 3 water tanks, grab all of the readings from the 6 different sensors, control the solenoid valve according to the water level, gather the flowRate, time to fill and other water-related parameters, update all the major workflows in the I2C LCD. For the solenoid valve, I have to set up a different hardware setup altogether because to control it via Arduino I have to use MOSFET (to drain out the excess current), diode, and resistors. Another major outbreak in this section is the correct working of the water flow sensor. It was a challenging task for me because I tried about 50 times to just make sure that the water flow sensor is giving the correct water flow rate. The water flow sensor gives a COUNT (ie how many times the rotor inside the sensor is rotating), and then through a formula, you can find the flowRate. After many attempts, I finally figured that out.

The formula looks like this:

flowRate = ((1000.0/999.0)*count)*0.23;

Updating the I2C LCD was also a tedious task as when the program will be dynamically fetching the details, those details have to be updated and printed onto the LCD too.

Sensors Used With NODEMCU: Nodemcu, Piezo Buzzer, IR Sensor X 2, DC Motors X 2, 12V DC Adapter, TCS3200 Color Sensor, Capacitive Touch Sensor, ESP8266 Motor Driver Shield, Analog Multiplexer IC – CD4051. As of now, I barely went through an article/blog/project in which the robot is being completely driven by Nodemcu. Generally, everyone uses Arduino to control a robot. But in my case, I used ESP8266 Motor Driver Shield with the Nodemcu V2. It was quite difficult because the pin layouts of the Nodemcu are very much different and also it contains only 10 GPIO pins compared to the 14 GPIO pins in Arduino Uno. As it was my first project with Arduino and electrical things I was not pretty sure how things will fall into place. Moreover, there is only 1 analog pin present in Nodemcu but for my robot, I have to use 2 analog IR sensors (to navigate the right and left wheel of the robot). To solve this, I used the multiplexer IC to increase the 1 analog pin into 2^3 = 8 analog pins, which made my job easier. Also, as the robot has to make API calls to the IoT device and to Integromat scenarios, I have to write dedicated functions for the same and also customize them according to my needs.

Bootstrap Studio: I have a dedicated website for this project. So for designing the front-end of the website have used Bootstrap Studio. For the styling part, I have used CSS while PHP is used for the back-end & SQL is the database.

Canva, Icons8, Mega Creator: I have created the animated videos and images all by myself. So I have to use this online software. Twilio: As the user will be getting constant text SMS and WhatsApp updates, so the Twilio messaging API will be used.

Circuit Diagram

Water Tank Overflow Circuit Diagram

Water Tank Overflow Circuit Diagram

One can break down my project into two major parts. One is the immobile Boltduino/Arduino and the mobile NodeMCU based robot. I will discuss the functioning of each of both sections.

Arduino / Boltduino

In this project as I will be using an IoT device so I used Bolt's WiFi module to interact with the cloud. For this project, one can either use an Arduino / Boltduino (which is a variant of Arduino made by Bolt). Any of the two will be good to go as they are identical in functioning. In the project setup, there will be 3 water tanks. You can assume the first one to be the main water facility, the second one to be the nearest water tower, and the third one to be the water tanks in homes. The main water facility will get the water from the dam and the water lifting submersible pump will be turned ON and now, the solenoid valve will be turned LOW. Whenever the water level in the nearest water tower will be less than 20% then the solenoid valve will turn ON and thus the water tower will get filled to a certain threshold (say 95%). When the water tower will be filled then the DC water motor will start pumping out the water from the tower to the water tanks in our home. At the time of pumping the water flow rate will be calculated through the YS-401 water sensor. Then the total time to fill the water tank will be calculated and accordingly, the instructions will be sent to the robot so that it can reach the destination in time to inform the user. One major aspect of the Arduino setup is that I have to make the Arduino and the python program communicate with each other. I have to do this as Bolt Wifi Module can understand Python language, not Arduino’s language. So I have to make the Arduino pass some certain keywords to the Python program and then the Python program will act accordingly. For this, I used serial communication through the COM port. This was a tricky part as the Arduino has to pass about 6 parameters to the python program and then the python program has to proceed accordingly. To make the passed variable understandable to the python code, I used the decode and strip methods. In this case, the decode() method converts the string from UTF-8 encoding to binary encoding. Another problem after using this decoding method was that say for example the passed variable was “stop” then the decode method will append some escape sequences to the variable and now the variable will look like “stop/n/r”. To remove the extra escape sequences and also not affect the binary encoding, I used the strip method as it removes any spaces or specified characters at the start and end of a string. This solved the problem of inter-communication between Arduino and python code. The python code also comes into the picture here.

The python code does the following things:

  • Use the ID3 algorithm to predict where the person should be in? For this evaluation, I have made the following custom dataset: The dataset has 5 attributes named WEEKEND, PHASE, TIME, TEMP, PLACE. The last attribute ie the PLACE attribute is the prediction attribute which means that the ID3 algorithm will use the first 4 attribute's values to find the place. The whole process is dynamic and will be done every time the motor will be started. After evaluating the place, the same is admin/uploaded to a google sheet so that the user can have a log of the periods and all other details about the water tank. A couple of scenarios are there ie for fetching the data and also admin/uploading the predicted values to the google sheet.
  • To make the project more active, I have used Twilio’s API to send Whatsapp updates for every major workflow. A total of 04 Whatsapp updates will be posted on the user’s registered number. But what if there is no Internet connectivity with the user? Then, in this case, 04 normal text SMS will be also sent which makes the project more relatable to the real world. I just want to tell you that the I2C LCD will be updated several times during the project. Be it updating and printing the predicted value or displaying the total time to fill, one can easily keep a track of important parameters through the LCD. There could be many possibilities in which the user may not be able to turn the motor off. In those scenarios, the Arduino will use the TTF (Time To Fill) to turn off the motor, when the TTF is about to be reached. So, in this way, the project becomes quite interactive and the user also gets timely updates regarding the whole project. As earlier I told you that the python program and Arduino code will communicate via serial communication. According to the project, the Arduino code will have to convey 6 variables to the python code so that the Bolt Wifi module can work accordingly.

Those 6 variables are as follows:

  1. start: Turning the water motor on when the nearest water tower is full
  2. TimeToFill: By the YS-401 water sensor, calculate the time needed to fill the water tank. Has to be reflected on the LCD screen.
  3. robot/noRobot: If the robot will take more time to reach the place than the ttf, the robot should not be deployed which is conveyed by the noRobot variable. If this is not the case then the robot variable is transferred.
  4. stop/stopped: After reaching the place, did the user press the touch sensor or use any of the 4 mediums to turn the motor off. If he did that then the variable will be set to stop and if the user for any reason did not turn it off the variable stop will be sent so that the autonomous execution can proceed.
  5. true/false: If the robot has gone for the destination and still not reached the final place due to some obstruction then the prediction variable will be set to false & if it reaches the final place then it will be set to true
  6. comm/comm1/comm2/comm3: Passing the variable through which the program will get to know that the user has chosen which option out of the 4 to turn the motor off. So, that at the end of execution there is clarity for the program.

NodeMCU based Robot

The first work for the robot is to fetch the place attribute so that it can find the place where it has to go. Once the robot fetches that value then the TCS3200 color sensor comes into the picture. Basically in the dataset, there are 03 values for place attributes which are balcony, bedroom, and hall. From the starting point of the robot to the final destination, I had laid down 03 different colored lines so that the color sensor will follow a particular colored line after getting the predicted value.

The place has the following colors: Red – Bedroom Blue – Balcony Green – Hall So, the robot will find the path through the custom-made direction functions. When the robot will reach to the end then it will wait for 20 seconds and then it will check whether the user clicked on the capacitive touch sensor. If yes, then the NodeMCU will send an API request to the Bolt WiFi cloud and in this manner, the water motor will be switched off in time. In the hardware configurations, there were two most challenging and tough parts. These were using the ESP8266 motor driver shield & using the multiplexer IC with the motor driver shield. Using the ESP8266 motor shield was difficult because in the shield’s official datasheet nothing is clearly explained. But after several repeated attempts I sorted the overall functioning of the shield. NodeMCU is placed on the top of the shield so that both become one in the other. A total of 2 DC motors can be connected so that is why I used a 02 wheeled robot which was controlled through the DC motors while the Caster wheel provides the stability to the overall chassis. As I used 02 12V DC motors I have to either use a 12V DC cell combination or can use a 12V DC power adapter to power up the motors. The major drawback of using the 12V cell combination was that the cells get discharged very quickly so this option doesn’t seem viable at that moment. That’s why I turned up for the 12V DC adapter solution as it seamlessly provides enough power to the motor shield and motors. Do note that I have short-circuited the Vin and Vm pins of the motor shield so that the power coming from the motors can also be utilized for powering up NodeMCU. Using the multiplexer IC with the motor driver shield was also quite a bit of a challenge as the CD4051 multiplexer IC is a 03 select line-based (S0, S1, and S2) multiplexer. This means that we can insert 23 = 8 analog sensors with this IC and use the single port i.e. A0 of the NodeMCU to read all 8 values. But in my case, I used only 2 IR sensors which means I don’t know what I have to do with the third select pins? In many attempts, the third select line was giving random values which were not even needed. After some trials, I got to know that the third select line must be provided a voltage of 0 so that the pin should not float.

 

user database

serial communication code

custom webhook

W4W Motor Stats

twilio alerts

Code
#include <NewPing.h>
#include <LiquidCrystal_I2C.h>
//General Variables
float ttf = 0;
float wpcm = 480;
float flowRate = 0.0;
float left_volume = 0.0;
int robot_max_time = 32;
volatile int count = 0;
String place = "";
String prediction = "";
unsigned long start_seconds = 0;
//Pin Related Variables
#define Trig1 10
#define Echo1 11
#define Echo2 5
#define Trig2 6
#define valve 4
#define flowPin 2
#define DC_Motor A0
#define sensorInterrupt 0
//Variables for the touchpad
int touchPad[4] = {3,7,8,9};
NewPing sonar[2] = {  
  NewPing(Trig1,Echo1,200),
  NewPing(Trig2,Echo2,200)
};
// Function for handling the interrupt on GPIO 2
void calculate_waterFlow()
{
  attachInterrupt(sensorInterrupt,flow, RISING);
  delay(1000);
  detachInterrupt(sensorInterrupt);
}
// ISR or Interrupt Handler for water flow sensor
void flow()
{ count++; }

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

  //Declaring the necessary mode of operation for the pins
  pinMode(valve, OUTPUT);
  pinMode(DC_Motor,INPUT);
  pinMode(flowPin, INPUT);
  digitalWrite(flowPin,HIGH);

  //pinModes for the touchpad
  for(byte i=0; i <=3; i++)
  { pinMode(touchPad[i],INPUT); }

  //Step1: Solenoid valve will be switched on
  digitalWrite(valve,HIGH);

  //Step2: Turn off the water pump when the water level in the water tower is >90%
  while(true)
  {
    int water_level = sonar[0].ping_cm();
    
    if(water_level <= 5) {
      digitalWrite(valve,LOW);
      break;
    }

    delay(200);
    yield();
  }

  //Step3: Calculate the volume of the secondary tank to be filled
  delay(100);
  int water_level = sonar[1].ping_cm();
  left_volume = (water_level - 6) * wpcm;

  lcd_display();

  //Step4: Send the message to python ,via serial comm, for turning on the motor
  Serial.println("start");
  delay(1500);
  start_seconds = millis()/1000;

  //loop to check the input entered by the user via the touchpad
  while(((millis()/1000) - start_seconds) < 1)
  {
    String comm="comm";
    for(byte i=0; i <=3; i++)
    {
      if(digitalRead(touchPad[i]) == 1)
      {
        comm = comm+(i+1);
        Serial.println(comm);
        break;
      }
    }
    Serial.println(comm);
    delay(1000);
  }

  calculate_waterFlow();

  //flowRate in ml/sec
  flowRate = ((1000.0/999.0)*count)*0.23;

  //Step6: Calculating the ttf (in seconds) as now I have left_volume and flowRate
  ttf = left_volume / flowRate;
  Serial.println(ttf);

  //now the ttf will be displayed to the lcd
  lcd_display();
 
  if(ttf < robot_max_time)
  { Serial.println("noRobot");  }

  else if (ttf > robot_max_time)
  {
    Serial.println("robot");  

    //Gathering the variable from the serial comm.
    while(true)
    {
      if(Serial.available() > 0)
      {
        place = Serial.readStringUntil('\n');
        break;
      }  
    }
 
  }
 
  //This now will display the place in the lcd
  lcd_display();

  //Step7: Constantly check if time to fill has been reached or not
  while(true)
  {
    int elapsed_seconds = (millis()/1000) - start_seconds;

    if((ttf - elapsed_seconds) <= 5)
    {
      // check if the motor is still on
      if(digitalRead(DC_Motor) ==  1)
      {
        //Used serial comm. to stop the motor
        prediction = "False";
        Serial.println(prediction);
        Serial.println("stop");
        break;
      }

      // if motor is already off
      else if(digitalRead(DC_Motor) == 0)
      {
        Serial.println("stopped");
        prediction = "True";
        Serial.println(prediction);
        break;
      }
    }
    delay(200);
  }
 
  lcd_display();
 
}

void loop()
{
}
void lcd_display()
{
  LiquidCrystal_I2C lcd(0x27, 16, 2);
  byte drop[8] = {
    0b00000,0b00100,0b01110,0b11111,
    0b11111,0b11111,0b01110,0b00000
  };
  byte alert[8] = {
    0b00100,0b01110,0b01110,0b01110,
    0b01110,0b11111,0b00000,0b00100
  };
  byte tick[8] = {
    0b00000,0b00000,0b00001,0b00011,
    0b10110,0b11100,0b01000,0b00000
  };
  byte cross[8] = {
    0b00000,0b10001,0b11011,0b01110,
    0b01110,0b11011,0b10001,0b00000
  };
  // initialize the LCD
  lcd.begin();
  // Turn on the blacklight and print a message.
  lcd.backlight();
  lcd.createChar(0,drop);
  lcd.createChar(1,alert);
  lcd.createChar(2,tick);
  lcd.createChar(3,cross);
  lcd.home();
  if(flowRate == 0.0) {
    lcd.print(" 0.00ml/s ");
  }
  else {
    lcd.print(" ");
    lcd.print(flowRate);
    lcd.print("ml/s ");
  }

  if(left_volume == 0) {
    lcd.print(left_volume);
    lcd.print("L");
  }
  else {
    lcd.print(left_volume/1000);
    lcd.print("L");
  }
  lcd.setCursor(0,1);
  lcd.write(1);
  if (ttf == 0) {
    lcd.print("TTF");
  }
  else{
    lcd.print(ttf);  
  }
  if(place=="")
  {
    lcd.setCursor(8,1);
    lcd.print("Place");
  }
  else if(place == "Hall") {
    lcd.setCursor(8,1);
    lcd.print(place);
  }
  else if(place=="Balcony" || place=="Bedroom")
  {
    lcd.setCursor(7,1);
    lcd.print(place);
  }
  if(prediction=="False")
  {
    lcd.setCursor(15,1);
    lcd.write(3);  
  }
  else if(prediction=="True")
  {
    lcd.setCursor(15,1);
    lcd.write(2);
  }
}

.................................................................................................................................................................

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

const char* ssid = "wifi-ssid";
const int httpsPort = 443;
const char* password = "wifi-pwd";

//Connection variables for the Integromat Scenario
const char* host = "hook.integromat.com";
const char* fingerprint = "83a72e6c37833814cba8bbb90376dabef88ac179";

//Connection variables for the Cloud Request API
const char* host1 = "cloud.boltiot.com";
const char* fingerprint1 = "f219db233aded965dd5cfa95f727576b269341ad";

String place="", line="";

//Variables for the 4051 IC
const int selectPins[2] = {D5, D0};
const int analogInput = A0;

int IR1 = 0;
int IR2 = 0;

//Variables for the TCS300 color sensor
const int s0 = D6;
const int s1 = D7;
const int s2 = 10;//SD3
const int s3 = 9;//SD2   
const int out = D8;

int red = 0;
int green = 0;
int blue = 0;

int touch_value = 0;
int robot_max_time = 32;
unsigned long go_back_time = 0;
unsigned long wait_time = 0, start_time = 0;
unsigned long sense_line = 0, follow_line = 0;
unsigned long begin_time = 0, turn_back_time = 0;

void setup() {
 
  //pinModes for the Analog Multiplexer (4051 IC)
  for (int i=0; i < 2; i++)
  {
    pinMode(selectPins[i], OUTPUT);
    digitalWrite(selectPins[i], HIGH);
  }

  //As an indication measure use the Builtin Led
  pinMode(LED_BUILTIN,OUTPUT);
  digitalWrite(LED_BUILTIN,LOW);
 
  //pinModes for the Color sensor
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(out, INPUT);

  //2% frequency scailing for TCS300
  digitalWrite(s0, LOW);  
  digitalWrite(s1, HIGH);

  //pinModes for Motor Pins (D0-D4)
  pinMode(D1,OUTPUT);
  pinMode(D2,OUTPUT);
  pinMode(D3,OUTPUT);
  pinMode(D4,OUTPUT);

  //default value function for DC Motors
  back_2_normal();

  //connecting esp8266 to the wifi network
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  { delay(500); }

  Serial.println(millis()/1000);
  //Step 1: Loop to fetch the predicted value
  while(true)
  {
    get_place_from_integromat();
    if(place!="NA")
    {
      digitalWrite(s0,HIGH);
      delay(250);
      digitalWrite(s0,LOW);
      break;
    }
    delay(1500);
  }

  //Step 2: Loop to find the line which has to be followed
  while(true)
  {
    line_color();
    if(place == line)
    {
        sense_line = millis();
        while((millis() - sense_line) <= 200)
        { robot_motion(); }
        back_2_normal();
        start_time = millis();
        while((millis()-start_time) < 350)
        { move_right(); }
        back_2_normal();
        break;
    }

    //head to the next colored line
    follow_line = millis();
    while((millis() - follow_line) <= 1050)
    { robot_motion(); }
    back_2_normal();
  }

  begin_time = millis()/1000;

  //assigning robot_max_time according to the destination
  if(place == "Bedroom") {
    robot_max_time = 44;
  } else if (place == "Balcony") {
    robot_max_time = 33;
  }

  //Step 3: Making the robot reach the destination
  while(((millis()/1000) - begin_time) <= robot_max_time)
  { robot_motion(); yield(); }

  back_2_normal();

  //Step 4: Run the song via buzzer and in btw waiting for users input
  Serial.println("Starting the party song");
  buzzer();

  get_touch_input();
  if(touch_value > 600)
  {
     execute_cloud_request();
  }

  //Step 5: Making the robot come back to the starting point  
  turn_back_time = millis();
  while((millis() - turn_back_time) < 750)
  { move_left(); }

  back_2_normal();

  go_back_time = millis()/1000;
  while(((millis()/1000) - go_back_time) <= robot_max_time)
  { robot_motion(); yield(); }
}

void loop() {
}

void get_place_from_integromat()
{
  WiFiClientSecure httpsClient;
  httpsClient.setFingerprint(fingerprint);
  httpsClient.setTimeout(15000);
  delay(1000);

  int r=0;
  while((!httpsClient.connect(host, httpsPort)))
  { delay(100); }

  String url = "/es9u64fct1m914xu59qkey1iio9e9j9n";

  httpsClient.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +               
               "Connection: close\r\n\r\n");

  while (httpsClient.connected())
  {
    String line = httpsClient.readStringUntil('\n');
    if (line == "\r")
    { break;  }
  }

  String line;
  while(httpsClient.available())
  {        
    line = httpsClient.readStringUntil('\n');
    
    if(line.startsWith("Hall"))
    { place = "Hall"; }

    else if(line.startsWith("Bedroom"))
    { place = "Bedroom";  }

    else if(line.startsWith("Balcony"))
    { place = "Balcony";  }

    else if(line.startsWith("Place") || line.startsWith("Accepted"))
    { place = "NA";   }
  }

}

void execute_cloud_request()
{
  WiFiClientSecure httpsClient;
  httpsClient.setFingerprint(fingerprint1);
  httpsClient.setTimeout(15000);
  delay(1000);

  int r=0;
  while((!httpsClient.connect(host1, httpsPort)))
  { delay(100); }

  String url = "/remote/e719e4f0-cc5d-427b-a0aa-6b9d1ceb0f28/digitalWrite?pin=0&state=LOW&deviceName=BOLT8024008";

  httpsClient.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host1 + "\r\n" +               
               "Connection: close\r\n\r\n");

  while (httpsClient.connected())
  {
    String line = httpsClient.readStringUntil('\n');
    if (line == "\r")
    { break;  }
  }

  String line;
  while(httpsClient.available())
  { line = httpsClient.readStringUntil('\n'); }
}

void line_color()      
{    
  digitalWrite(s2, LOW);  
  digitalWrite(s3, LOW);
 
  red = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
 
  digitalWrite(s3, HIGH);
  blue = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
 
  digitalWrite(s2, HIGH);
  green = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);

  //Red Line -> Bedroom
  if (red < blue && red < green)
  { line = "Bedroom"; Serial.println("RED COLOR"); }

  //Blue Line -> Balcony
  else if (blue < red && blue < green)    
  { line = "Balcony"; Serial.println("BLUE COLOR"); }

  //Green Line -> Hall
  else if (green < red && green < blue)
  { line = "Hall"; Serial.println("GREEN COLOR"); }
}

//Line Following Robot Code
void robot_motion()
{
  //Get the value of IR sensors:
   get_IR_values();

  //forward motion
  if(IR1 < 200 && IR2 < 200)
  { move_fwd();}

  //left motion
  else if(IR1 < 200 && !IR2 < 200)
  { move_left();}

  //right motion
  else if(!IR1 < 200 && IR2 < 200)
  { move_right();}

  //stop motion
  else if(!IR1 < 200 && !IR2 < 200)
  { back_2_normal();}
}

void get_IR_values()
{
  // Loop through the 02 input pins ie A0 and A1
  for (byte pin=0; pin <= 1; pin++)
  {
      for (int i=0; i < 2; i++)
      { digitalWrite(selectPins[i], pin & (1 << i)?HIGH:LOW); }
      
      if(pin==0)
      { IR1 = analogRead(analogInput);  }
      
      else if(pin==1)
      { IR2 = analogRead(analogInput);  }
  }
}

void get_touch_input()
{
  // Loop through the A2 pin only
  byte pin = 2;
 
  for (int i=0; i < 2; i++)
  { digitalWrite(selectPins[i], pin & (1 << i)?HIGH:LOW); }
 
  touch_value = analogRead(analogInput);
}

//functions directing the robot
void move_fwd()
{
  back_2_normal();
  analogWrite(D1,150);
  analogWrite(D2,150);
}

void move_left()
{
  back_2_normal();
  digitalWrite(D3,HIGH);
  analogWrite(D1,200);
  analogWrite(D2,200);
}

void move_right()
{
  back_2_normal();
  digitalWrite(D4,HIGH);
  analogWrite(D1,200);
  analogWrite(D2,200);
}

void back_2_normal()
{
  analogWrite(D1,0);
  analogWrite(D2,0);
  digitalWrite(D3,LOW);
  digitalWrite(D4,LOW);
}

void testing(int x)
{
  digitalWrite(s0,HIGH);
  delay(x);
  digitalWrite(s0,LOW);
}

void buzzer()
{
  #define NOTE_B0  31
  #define NOTE_C1  33
  #define NOTE_CS1 35
  #define NOTE_D1  37
  #define NOTE_DS1 39
  #define NOTE_E1  41
  #define NOTE_F1  44
  #define NOTE_FS1 46
  #define NOTE_G1  49
  #define NOTE_GS1 52
  #define NOTE_A1  55
  #define NOTE_AS1 58
  #define NOTE_B1  62
  #define NOTE_C2  65
  #define NOTE_CS2 69
  #define NOTE_D2  73
  #define NOTE_DS2 78
  #define NOTE_E2  82
  #define NOTE_F2  87
  #define NOTE_FS2 93
  #define NOTE_G2  98
  #define NOTE_GS2 104
  #define NOTE_A2  110
  #define NOTE_AS2 117
  #define NOTE_B2  123
  #define NOTE_C3  131
  #define NOTE_CS3 139
  #define NOTE_D3  147
  #define NOTE_DS3 156
  #define NOTE_E3  165
  #define NOTE_F3  175
  #define NOTE_FS3 185
  #define NOTE_G3  196
  #define NOTE_GS3 208
  #define NOTE_A3  220
  #define NOTE_AS3 233
  #define NOTE_B3  247
  #define NOTE_C4  262
  #define NOTE_CS4 277
  #define NOTE_D4  294
  #define NOTE_DS4 311
  #define NOTE_E4  330
  #define NOTE_F4  349
  #define NOTE_FS4 370
  #define NOTE_G4  392
  #define NOTE_GS4 415
  #define NOTE_A4  440
  #define NOTE_AS4 466
  #define NOTE_B4  494
  #define NOTE_C5  523
  #define NOTE_CS5 554
  #define NOTE_D5  587
  #define NOTE_DS5 622
  #define NOTE_E5  659
  #define NOTE_F5  698
  #define NOTE_FS5 740
  #define NOTE_G5  784
  #define NOTE_GS5 831
  #define NOTE_A5  880
  #define NOTE_AS5 932
  #define NOTE_B5  988
  #define NOTE_C6  1047
  #define NOTE_CS6 1109
  #define NOTE_D6  1175
  #define NOTE_DS6 1245
  #define NOTE_E6  1319
  #define NOTE_F6  1397
  #define NOTE_FS6 1480
  #define NOTE_G6  1568
  #define NOTE_GS6 1661
  #define NOTE_A6  1760
  #define NOTE_AS6 1865
  #define NOTE_B6  1976
  #define NOTE_C7  2093
  #define NOTE_CS7 2217
  #define NOTE_D7  2349
  #define NOTE_DS7 2489
  #define NOTE_E7  2637
  #define NOTE_F7  2794
  #define NOTE_FS7 2960
  #define NOTE_G7  3136
  #define NOTE_GS7 3322
  #define NOTE_A7  3520
  #define NOTE_AS7 3729
  #define NOTE_B7  3951
  #define NOTE_C8  4186
  #define NOTE_CS8 4435
  #define NOTE_D8  4699
  #define NOTE_DS8 4978

  int melody[] = {
    NOTE_AS4, NOTE_AS4, NOTE_AS4, NOTE_AS4,
    NOTE_AS4, NOTE_AS4, NOTE_AS4, NOTE_AS4,
    NOTE_AS4, NOTE_AS4, NOTE_AS4, NOTE_AS4,
    NOTE_AS4, NOTE_AS4, NOTE_AS4, NOTE_AS4,
    NOTE_AS4, NOTE_AS4, NOTE_AS4, NOTE_AS4,
    NOTE_D5, NOTE_D5, NOTE_D5, NOTE_D5,
    NOTE_C5, NOTE_C5, NOTE_C5, NOTE_C5,
    NOTE_F5, NOTE_F5, NOTE_F5, NOTE_F5,
    NOTE_G5, NOTE_G5, NOTE_G5, NOTE_G5,
    NOTE_G5, NOTE_G5, NOTE_G5, NOTE_G5,
    NOTE_G5, NOTE_G5, NOTE_G5, NOTE_G5,
    NOTE_C5, NOTE_AS4, NOTE_A4, NOTE_F4,
    NOTE_G4, 0, NOTE_G4, NOTE_D5,
    NOTE_C5, 0, NOTE_AS4, 0,
    NOTE_A4, 0, NOTE_A4, NOTE_A4,
    NOTE_C5, 0, NOTE_AS4, NOTE_A4,
    NOTE_G4,0, NOTE_G4, NOTE_AS5,
    NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5,
    NOTE_G4,0, NOTE_G4, NOTE_AS5,
    NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5,
    NOTE_G4, 0, NOTE_G4, NOTE_D5,
    NOTE_C5, 0, NOTE_AS4, 0,
    NOTE_A4, 0, NOTE_A4, NOTE_A4,
    NOTE_C5, 0, NOTE_AS4, NOTE_A4,
    NOTE_G4,0, NOTE_G4, NOTE_AS5,
    NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5,
    NOTE_G4,0, NOTE_G4, NOTE_AS5,
    NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5
  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  int noteDurations[] = {
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  };
 
  for (int thisNote = 40; thisNote < 112; thisNote++) {
   
    int noteDuration = 750 / noteDurations[thisNote];
    tone(s0, melody[thisNote], noteDuration);

    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    
    noTone(s0);
  }
}


Have any question realated to this Article?

Ask Our Community Members