DIY Water Usage Meter

Water Meter

Category: Water
Communication: NodeMCU WiFi
Components: External
Created By: Anonymous
Difficulty Level: Intermediate
Input Sensor: Flow sensor
Microcontroller: NodeMCU
Output Device: LED
Prototyped by: Anonymous
Status: In Progress

This solution is built with a NodeMCU microcontroller.

This microcontroller is used specifically for IoT solutions, when you need to send sensor data over WiFi to another device.

Find more info here.

Objective: To measure the amount of water used at a tap using a flow sensor, and send the data online to a ThingSpeak channel over WiFi.

  • Click here to get code.

    /*     Prototype Name : Water Meter with NodeMCU
           Input Sensor   : Flow Sensor
           Output Device  : LED, ThingSpeak
           Libraries Used : LiquidCrystalPCF584 and FastLED to turn off from use. 
    */
    
    #include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
    #include <SoftwareSerial.h>
    //needed for library
    #include <DNSServer.h>
    #include <ESP8266WebServer.h>
    #include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
    #include <LiquidCrystal_I2C.h>
    
    String apiKey = "enter your api key";//Channel 22
    const char* host = "rbiot.solveninja.org";
    
    WiFiClient client;
    
    //LCD
    LiquidCrystal_I2C lcd(0x3F, 16, 2); // check the lcd i2c number
    //LiquidCrystal_I2C lcd(0x27, 16, 2);
    
    //Enter Sensor config here
    
    #define PULSE_PIN D6  //gpio4
    #define LED_PIN D7    //gpio13
    
    volatile long pulseCount = 0;
    float calibrationFactor = 6.0;
    float flowRate;
    unsigned int flowMilliLitres;
    unsigned long totalMilliLitres;
    
    unsigned long oldTime;
    
    void ICACHE_RAM_ATTR pulseCounter()
    {
      pulseCount++;
    }
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200);
      lcd.init();   // initializing the LCD
      lcd.backlight();
      lcd.print("Connect to Wifi");
      pulseCount        = 0;
      flowRate          = 0.0;
      flowMilliLitres   = 0;
      totalMilliLitres  = 0;
      oldTime           = 0;
    
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, HIGH);  // We have an active-low LED attached
     
      pinMode(PULSE_PIN, INPUT);
    //  pinMode(PULSE_PIN, INPUT_PULLUP);
    //  digitalWrite(PULSE_PIN, HIGH);   ????
      attachInterrupt(PULSE_PIN, pulseCounter, FALLING);
      // WiFiManager
      WiFiManager wifiManager;
      wifiManager.setTimeout(180);
    
      if (!wifiManager.autoConnect("SetUpWifiOnBreathe")) {
        Serial.println("failed to connect and hit timeout");
        delay(3000);
        //reset and try again, or maybe put it to deep sleep
        ESP.reset();
        delay(5000);
      }
      //if you get here you have connected to the WiFi
      Serial.println("connected...yeey :)");
    }
    
    void loop() {
      lcd.clear();
      {
       if((millis() - oldTime) > 1000)    // Only process counters once per second
      {
        detachInterrupt(PULSE_PIN);
        flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
        oldTime = millis();
        flowMilliLitres = (flowRate / 60) * 1000;
        totalMilliLitres += flowMilliLitres;    
        unsigned int frac;  
        Serial.print("Flow rate: ");
        Serial.print(int(flowRate));  // Print the integer part of the variable
        Serial.print(".");             // Print the decimal point
        frac = (flowRate - int(flowRate)) * 10;
        Serial.print(frac, DEC) ;      // Print the fractional part of the variable
        Serial.print("L/min");
        Serial.print("  Current Liquid Flowing: ");             // Output separator
        Serial.print(flowMilliLitres);
        Serial.print("mL/Sec");
        Serial.print("  Output Liquid Quantity: ");             // Output separator
        Serial.print(totalMilliLitres);
        Serial.println("mL");
    
        pulseCount = 0;
    
        attachInterrupt(PULSE_PIN, pulseCounter, FALLING);
      }
      }
      showonlcd();
      senddata();
    }
    
    //Functions written now on
    
    void senddata() {
      //WiFiClient client;
      const int httpPort = 3000; //Port 3000 is commonly used for www
      //---------------------------------------------------------------------
      //Connect to host, host(web site) is define at top
      if (!client.connect(host, httpPort)) {
        Serial.println("Connection Failed");
        delay(300);
        return; //Keep retrying until we get connected
      }
      String Link = "GET /update?api_key=" + apiKey + "&field1="; //Requeste webpage
      Link = Link + totalMilliLitres;
      Link = Link + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n";
      client.print(Link);
      delay(100);
    
      //---------------------------------------------------------------------
      //Wait for server to respond with timeout of 5 Seconds
      int timeout = 0;
      while ((!client.available()) && (timeout < 1000))    //Wait 5 seconds for data
      {
        delay(10);  //Use this with time out
        timeout++;
      }
    
      //---------------------------------------------------------------------
      //If data is available before time out read it.
      if (timeout < 500)
      {
        while (client.available()) {
          Serial.println(client.readString()); //Response from ThingSpeak
        }
      }
      else
      {
        Serial.println("Request timeout..");
      }
    
      delay(20000);  //Read Web Page every 40 seconds
    }
    
    void showonlcd() {
      lcd.setCursor(0, 0);
      lcd.print("Flowing..");
      lcd.setCursor(0, 1);
      lcd.print("Flow:");
      lcd.print(totalMilliLitres/1000);
      delay(500);
    }