Project: A Smart Water Dispenser

A Smart Water Dispenser

Table of Contents Example

Table of Contents

1.What does it do?

The "Smart Water Dispenser" is a system that dispenses a specific volume of water automatically. It works by measuring the water flow rate using a flow sensor and stopping the water flow once the desired volume is reached. Users can access the dispenser by using a smart card that is programmed with their personal information, such as their name, account balance, and water usage history.

Project Sketching

vscode

2.Who's done this beforehand?

I was inspired by the Company HOW TO ELECTRONICS which was Build DIY Water Filling Machine using Flow Sensor & Arduino and Final Project of Tariq Ahmed Shaikh which is Automatic Hot Water Dispenser

vscode

3.What did you design?

I designed a Smart Water Dispenser casing by Laser Cutter. I also designed an embedded system connected to a RFID Module,LCD Screen, Flow Sensor, Three input Buttons,Obstacle Sensor and Solenoid valve wich will used for measuring the water flow rate using a flow sensor and stopping the water flow once the desired volume is reached

4. What materials and components were used?

      1. Microcontroller (ESP-wrom-32): Microcontroller which will be used to control the flow of water.
      2. Water flow sensor (YF-S201): A flow sensor can be used to measure the amount of water flowing through the dispenser.
      3. Smart card reader: A card reader can be used to read information from the smart card.
      4. Solenoid valve: A solenoid valve can be used to control the flow of water.
      5. LCD screen (20X4): An LCD screen can be used to display the amount of water dispensed and other information.
      6. Power supply: A power supply can be used to power the microcontroller and other components.
      7. Button: providing an input interface for users to select the desired dispensing option.
      8. RFID Card:RFID card can be used to grant access or authorize specific users to dispense water and loading money
      9. Voltage Regulator IC: A voltage regulator IC is used to regulate and stabilize the voltage (3V)level in a circuit.
      10. MOSFET: It is a type of transistor that can control the flow of current in a circuit. MOSFETs are often used as switches
      11. Button_Switch: Is a mechanical switch that is activated by pressing a button.
      12. Resistors: They are used to control the amount of current or voltage in a circuit, to limit current flow, and to provide specific resistance values.
      13. Capacitors: Capacitors store electrical energy in an electric field and release it when needed.
      14. LED_SMD: LEDs are commonly used as visual indicators in electronic circuits
      15. Connectors: Connectors are mechanical devices used to join or disconnect electrical circuits.
      16. Buzzer: It is commonly used to generate audible alerts or notifications in electronic systems
      17. Acrylic: Acrylic Will be used for the enclosure or casing of the dispenser.
      18. Copper PCB: A Copper PCB (Printed Circuit Board) is a board made of insulating material with a layer of copper
      19. Obstacle avoidance sensor: is designed to detect an obstacle or the difference in reflective services

5.Where did they come from?

I got all the electronic components and material used in my project from FabLabRwanda

6.How much did they cost?

Table Example
No ITEM NAMES SPECIFICATIONS QUANTITY UNIT PRICE(Rwf) TOTAL PRICE(Rwf)
1. Microcontroller ESP-wrom-32 1 15000 15000
2. Water flow sensor YF-S201 1 8000 8000
3. Solenoid valve G1/2 AC 220V 1 13800 13800
4. RFID Reader Module 13.56Mhz 1 7000 7000
5. RFID Card 125Khz 3 1000 3000
6. MOSFET IRFZ44N 1 1000 1000
7. Voltage Regulator 5V AMS1117 1 500 500
8. LCD Display 20×4 1 11000 11000
9. Copper PCB single side 7x10cm 1 2000 2000
10. Jumper Wires and others Male,Female 1 6000 6000
11. Acrylic 40x40x3 1 80000 80000
12. Power Supply HLK-5M12 12V 5W 1 10000 10000
13. Water pipe Small 3 1000 3000
14. Capacitors Small 3 1000 3000
15. LED Small 3 1000 3000
16. Button_Switch Small 3 1000 3000
17. Buzzer 5V 1 500 500
18. Voltage Regulator IC 3V 1 500 500
19. Obstacle avoidance sensor Infrared 1 2500 2500
TOTAL N/A 29 154,800 162,800

7.What parts and systems were made?

My system was made by using the differents skills and knowldge we got from fabacademy

a. Computer-aided design

2D & 3D Design

b.Computer-controlled cutting

lasercutter

c. Embedded programming

ESP-wrom-32

d.Electronics design and production

CircuitDesign, PCB Milling and Soldaling compomnents

e.Input Devices

RFID system and Buttonsand Water flow sensor

f.Output Devices

LCD Display, and Solenoid valve, Buzzer

8.What processes were used?

a. Designing the Smart Water Dispenser case

By using skills I gain from Computer-aided design (2D and 3D Design) I designed the smart Water Dispenser case which will hold all system. the below Image shows the process we used.

This is Back side

vscode

vscode

This is Right side

vscode

vscode

This is Left side

vscode

vscode

This is Button side

vscode

vscode

This is Top side

vscode

vscode

This is Front side

vscode

vscode

vscode

This is Water Dispenser case after assembling all parts

vscode

vscode

vscode

b. Cutting with lasercutter and Engraving Machine

By using skills I gain from Computer-controlled cutting (Laser Cutter) I Cutted the smart Water Dispenser case which will hold all system. the below Image shows the process we used.

This is Water Dispenser case after Cutting on lasercutter

vscode

vscode

vscode

After assembling all parts

vscode

c. Designing and 3D Printing the RFID Card Holder and Obstacle avoidance sensor

The following Image shows the RFID Card Holder and Obstacle avoidance sensor

vscode

The following Image shows the RFID Card Holder and Obstacle avoidance sensor printed by 3D Printer

vscode

The following images shows after inserting the RFID Card Holder and Obstacle avoidance sensor

vscode

vscode

d. Circuit and PCB Design

By using skills I gain from Electronics design and production (CircuitDesign, PCB Milling and Soldaling compomnents) I designed the smart Water Dispenser Board which will hold all compomnents of the system. the below Image shows the process we used.

I started by designing, Milling, soldering PCB

Here is Schematic

vscode

Here is PCB Design

vscode

Here is PCB Design in 3D

vscode

Here is we started generate G-Codes for Milling with Roland SRM 20

vscode

vscode

vscode

Here is PCB after Milling

vscode

Here I started soldiring compomnents on PCB

vscode

Here after soldiring compomnents

vscode

vscode

Inside of the case

vscode

vscode

Outside of the Case

vscode

e. Embedded programming,Input Devices,Output Devices Embedded Networking and Communications and Interface Application Programming

By using skills I gain from Embedded programming,Input Devices,Output Devices Embedded Networking and Communications and Interface Application Programming (2D and 3D Design) I designed the smart Water Dispenser case which will hold all system. the below Image shows the process we used.

We started by designing Flow Chat Diagram

vscode

The following Image shows when I started testing and debug my system compomnents

vscode

The Microcontroller now can read, the Obstacle avoidance sensor, RFID Card and check the balance

vscode

The following Images shows when we start assembling all parts of Smart Water Despenser (Case and Electronics )

    
      #include  
        #include 
        #include 
        #include 
        #define RST_PIN         15           // Configurable, see typical pin layout above
        #define SS_PIN          5          // Configurable, see typical pin layout above
        
        MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.
        
        MFRC522::MIFARE_Key key;
        LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display
          
            
        uint32_t CardBalance = 0;
        uint32_t Cost=1;
        uint32_t total_cost=0;
        String Card="";
        uint32_t consumed_volume=0;
        uint32_t Card_Balance=0;
        int cardsensor= 17;
        int progress=0;
        int valve=13;
        const unsigned long period = 1000;
        int incrementbutton=2;
        int decrementbutton=4;
        int confirmbutton=14;
        int button_state1=0;
        int button_state2=0;
        int button_state3=0;
        int cardstate=0;
        float volume=0.0;
        uint32_t unit_cost=1;
        
        
        #define FLOWSENSOR 27
        
        FlowMeter Meter = FlowMeter(27);
        
        /**
         * Initialize.
         */
        void setup() {
            Serial.begin(115200);	// Initialize serial communications with the PC
            while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
               SPI.begin();		// Init SPI bus
           lcd.init();
           lcd.backlight();
            mfrc522.PCD_Init();	// Init MFRC522 card
        
            for (byte i = 0; i < 6; i++) {
                key.keyByte[i] = 0xFF;
            }
        
            pinMode(incrementbutton,INPUT_PULLUP);
            pinMode(decrementbutton,INPUT_PULLUP);
            pinMode(confirmbutton,INPUT_PULLUP);
            pinMode(valve,OUTPUT);
            
            Serial.println(F("insert your card"));
               pinMode(cardsensor, INPUT);
             attachInterrupt(digitalPinToInterrupt(cardsensor),cardpresent,CHANGE);  //  function for creating external interrupts at pin2 on Rising (LOW to HIGH vice versa)
             request_Card();
        }
        
        /**
         * Main loop.
         */
        void loop() {
        
         Meter.tick(period);
        
          while(cardstate==0)
                {
                    mfrc522.PCD_StopCrypto1();
                    Card="";
                    total_cost=0;
                    Meter.setTotalVolume(0.0f);
                    CardBalance=0;
                    cardstate = 4;
                    detachInterrupt(FLOWSENSOR);
                }
           while(cardstate==1)
                { 
        
                    Serial.print(" Card present = ");
                    checkcardinfo();
                    Card_info_screen();
                    delay(3000);
                    if(CardBalance>=unit_cost){
                       Serial.print(" Card Stored  ");
                    Serial.print(" balance=  ");
                    Serial.print(CardBalance);
                    progress=1;
                    while(progress==1){
                      confirm_Volume();
        
                    }
                    total_cost= unit_cost * volume;
                    if(total_cost < CardBalance){
                      charge();
                    attachInterrupt(FLOWSENSOR, MeterISR, RISING);
                    open_valve();
                     lcd.clear();
                    cardstate=2;
                      
                    }
                    else { 
                      close_valve();
                      recharge_card_screen();
                    
                   }
                    
                    } else {
                      close_valve();
                      recharge_card_screen();
                    
                    }
                   
                                
                  
        
                }
             while(cardstate==2)
                { 
                  if(consumed_volume>=total_cost){
                    close_valve();
                  }
                  else{
                    fetching();
                  }
                  
          
        }
        }
          
          
        void screen(){
           lcd.setCursor(3,0);
          lcd.print("CARD: " +String(Card));
            lcd.setCursor(1,1);
           lcd.print("Balance: " +String(CardBalance));
        Serial.println ("screeen printint"+String(Card)+"Balance: " +String(CardBalance));
        }
        
        void MeterISR() {
            // let our flow meter count the pulses
            Meter.count();
            consumed_volume = (Meter.getTotalVolume())*100;
           
         }
        
        
        void charge(){
              // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
            if ( ! mfrc522.PICC_IsNewCardPresent())
                return;
        
            // Select one of the cards
            if ( ! mfrc522.PICC_ReadCardSerial())
                return;
         byte sector         = 1;
            byte valueBlockB    = 6;
            byte trailerBlock   = 7;
            MFRC522::StatusCode status;
            byte buffer[18];
            byte size = sizeof(buffer);
            int32_t value;
        
            
            // Authenticate using key A
          
            status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("PCD_Authenticate() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            byte trailerBuffer[] = {
                255, 255, 255, 255, 255, 255,       // Keep default key A
                0, 0, 0,
                0,
                255, 255, 255, 255, 255, 255};      // Keep default key B
        
            mfrc522.MIFARE_SetAccessBits(&trailerBuffer[6], 0, 6, 6, 3);
        
        
            status = mfrc522.MIFARE_Read(trailerBlock, buffer, &size);
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("MIFARE_Read() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            // Check if it matches the desired access pattern already;
            // because if it does, we don't need to write it again...
            if (    buffer[6] != trailerBuffer[6]
                ||  buffer[7] != trailerBuffer[7]
                ||  buffer[8] != trailerBuffer[8]) {
                // They don't match (yet), so write it to the PICC
                Serial.println(F("Writing new sector trailer..."));
                status = mfrc522.MIFARE_Write(trailerBlock, trailerBuffer, 16);
                if (status != MFRC522::STATUS_OK) {
                    Serial.print(F("MIFARE_Write() failed: "));
                    Serial.println(mfrc522.GetStatusCodeName(status));
                    return;
                }
            }
        
            // Authenticate using key B
            
            status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("PCD_Authenticate() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            
            status = mfrc522.MIFARE_Decrement(valueBlockB, total_cost);
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("MIFARE_Decrement() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            status = mfrc522.MIFARE_Transfer(valueBlockB);
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("MIFARE_Transfer() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            // Show the new value of valueBlockB
            status = mfrc522.MIFARE_GetValue(valueBlockB, &value);
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("mifare_GetValue() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            
        
            Serial.println();
        
            mfrc522.PCD_StopCrypto1();
        }
        
        
          ////////////////////////////////////////////////////////////////////////////////////
        /*                 checking new card information  and storing them                      */
          ///////////////////////////////////////////////////////////////////////////////////////
          
        void checkcardinfo(){
              // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
            if ( ! mfrc522.PICC_IsNewCardPresent())
                return;
        
            // Select one of the cards
            if ( ! mfrc522.PICC_ReadCardSerial())
                return;
        
            // Show some details of the PICC (that is: the tag/card)
            Serial.print(F("Card UID:"));
        //    dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 
        Card="";
              
              for (byte i = 0; i < mfrc522.uid.size; i++) 
              {
                Card+=String(mfrc522.uid.uidByte[i],HEX);
                Card.toUpperCase();
        }   
              Serial.println ("new card = "+String(Card));
              
               screen();
           
        
            // In this sample we use the second sector,
            // that is: sector #1, covering block #4 up to and including block #7
            byte sector         = 1;
            byte valueBlockB    = 6;
            byte trailerBlock   = 7;
            MFRC522::StatusCode status;
            byte buffer[18];
            byte size = sizeof(buffer);
            int32_t value;
        
            // Authenticate using key A
          
            status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("PCD_Authenticate() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            byte trailerBuffer[] = {
                255, 255, 255, 255, 255, 255,       // Keep default key A
                0, 0, 0,
                0,
                255, 255, 255, 255, 255, 255};      // Keep default key B
        
            mfrc522.MIFARE_SetAccessBits(&trailerBuffer[6], 0, 6, 6, 3);
        
        
            status = mfrc522.MIFARE_Read(trailerBlock, buffer, &size);
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("MIFARE_Read() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            // Check if it matches the desired access pattern already;
            // because if it does, we don't need to write it again...
            if (    buffer[6] != trailerBuffer[6]
                ||  buffer[7] != trailerBuffer[7]
                ||  buffer[8] != trailerBuffer[8]) {
                // They don't match (yet), so write it to the PICC
                Serial.println(F("Writing new sector trailer..."));
                status = mfrc522.MIFARE_Write(trailerBlock, trailerBuffer, 16);
                if (status != MFRC522::STATUS_OK) {
                    Serial.print(F("MIFARE_Write() failed: "));
                    Serial.println(mfrc522.GetStatusCodeName(status));
                    return;
                }
            }
        
            // Authenticate using key B
            
            status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("PCD_Authenticate() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            
            // Show the new value of valueBlockB
            status = mfrc522.MIFARE_GetValue(valueBlockB, &value);
            CardBalance=value;
            if (status != MFRC522::STATUS_OK) {
                Serial.print(F("mifare_GetValue() failed: "));
                Serial.println(mfrc522.GetStatusCodeName(status));
                return;
            }
            
        
            Serial.println();
        
            mfrc522.PCD_StopCrypto1();
        }
        
        
        
          ////////////////////////////////////////////////////////////////////////////////////
              /*         checking if card is present or absent                */
          ///////////////////////////////////////////////////////////////////////////////////////
        
        void cardpresent()
        {
          if(digitalRead(cardsensor) == LOW){
            cardstate =1; 
          }
          else{
            close_valve();
            cardstate =0; 
          }
           
        }
        
        
        
        
          ////////////////////////////////////////////////////////////////////////////////////
              /*         Confirming volume                */
          ///////////////////////////////////////////////////////////////////////////////////////
        
        
        
        void confirm_Volume()
        {
          volume_screen();
              if((digitalRead(incrementbutton)== LOW) && button_state1==0){
                    Serial.println("incrementbutton pressed");
                    volume=volume+1;
                    button_state1=1;  
                  
                 }
               else if(digitalRead(incrementbutton)== HIGH){
                    button_state1=0;
                 }
               else if((digitalRead(decrementbutton)== LOW) && button_state2==0 && volume >=0.0 ){
                     Serial.println("decrementbutton pressed");
                     volume=volume-1;
                     button_state2=1;
                     
                 }
               else if(digitalRead(decrementbutton)== HIGH){
                     button_state2=0;
                 }
               if(digitalRead(confirmbutton)== LOW)
                 {
                   
                   
                    progress=0;
                  }
        }
        
        
        
        void request_Card()
        {
           lcd.clear();
           lcd.setCursor(3,1);
           lcd.print("insert your");
           lcd.setCursor(7,2);
           lcd.print("CARD");
        }
        
        void Card_info_screen()
        {
           lcd.clear();
           lcd.setCursor(3,1);
           lcd.print("CARD= " +String(Card));
           lcd.setCursor(1,2);
           lcd.print("Balance= "+ String(CardBalance));
        }
        void volume_screen()
        {
          
           lcd.setCursor(3,1);
           lcd.print("CARD= " +String(Card));
           lcd.setCursor(1,2);
           lcd.print("Requsting: "+ String(volume)+"L");
        }
        
        
        void recharge_card_screen()
          {
           lcd.clear();
           lcd.setCursor(3,1);
           lcd.print("INSUFIENT balance");
           lcd.setCursor(1,2);
           lcd.print("please Recharge");
          
        
        }
        
        
        
        void fetching()
          {
           
         
           lcd.setCursor(2,0);
           lcd.print("CARD: "+String(Card));
           lcd.setCursor(1,1);
           lcd.print("Requested: "+ String(volume)+"L");
           lcd.print("Volume: "+ String(consumed_volume)+"L");
           lcd.setCursor(2,2);
           lcd.print("balance: "+ String(CardBalance)+ "Rwf");
          
        
        }
        
        
        
        void button_screen()
        {
            lcd.clear();
            lcd.setCursor(3,1);
            lcd.print("volume= "+ String(volume));
          }
        
         void open_valve(){
          digitalWrite(valve, HIGH);
         }
         void close_valve(){
          digitalWrite(valve, LOW);
         }
        
    
  

9.What questions were answered?

This project Smart Water Dispenser will applied in different sector and plays the important role of providing clean water on affordable cost.

Applications of Smart Water Dispenser:

      1. Offices and Workplaces: This Smart Water dispenser can be used in office settings to promote hydration among employees, track water consumption, and encourage sustainable practices.
      2. Educational Institutions: Schools, colleges, and universities can install smart water dispensers to provide clean water to students and faculty while raising awareness about water conservation.
      3. Public Spaces: Smart water dispensers can be placed in public parks, shopping malls, airports, and other communal areas to offer convenient access to clean drinking water for the general public on affordable cost
      4. Healthcare Facilities: Smart water dispensers can be installed in hospitals, clinics, and nursing homes to ensure a clean and safe water supply for patients, staff, and visitors.

10.How the system works (Smart Water Dispenser)

To use the system you follow the following steps:

1st. Power on the system :

When you turn on the system with 12V and by using Voltage Regulators 5v and 3.3V for powering the least of parts of the system. When we start the system the LCD will display a message Insert your CARD

vscode

2nd. Insert the card and the system checks card balance :

If the balance is not sufficient the system display a message Insufficiant Balance please recharge

vscode

vscode

vscode

vscode

Once the balance is greater or equal to 100 (the cost of one litter of water) the system diplay Requesting Volume of water in(Volume)

vscode

By using 3 buttons you will set the volume of water you will request, (Button for increasing volume, Button for dencreasing and other for confirming the volume you want to request)

vscode

After confirm 4 Litters of water we will display the below message, the system will go to rechack if the available balance will be equivalent to requested volume.

vscode

Final results of how the system works

vscode

The video shows how the system works

If you want to learn about my Designs, kindly click here