Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Md. Khairul Alam
Published © Apache-2.0

Automatic Water Flow Controller for a Building

This project controls the water pump automatically for a multi-storied building and saves water and electricity.

IntermediateWork in progress10 hours422
Automatic Water Flow Controller for a Building

Things used in this project

Hardware components

SparkFun MicroMod Single Pair Ethernet Kit
×1
SparkFun Distance Sensor
×1
Gravity: Analog Spear Tip pH Sensor / Meter Kit
DFRobot Gravity: Analog Spear Tip pH Sensor / Meter Kit
×1
Seeed Studio Grove - ORP Sensor
×1
4-Channel 16-Bit ADC for Raspberry Pi (ADS1115)
Seeed Studio 4-Channel 16-Bit ADC for Raspberry Pi (ADS1115)
×1
SparkFun Qwiic Single Relay
SparkFun Qwiic Single Relay
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Connection Diagram

This is the connection for the water tank side.

Code

Tank Side Code

Arduino
This code is for the Artemis processor installed in the water tank side with connected sensors.
#include "SparkFun_SinglePairEthernet.h"
#include <Arduino_JSON.h>
#include <Wire.h>
#include <DFRobot_ADS1115.h>
#include "SparkFun_VL53L1X.h" //Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X

DFRobot_ADS1115 ads(&Wire);
SinglePairEthernet adin1110;
SFEVL53L1X distanceSensor;


#define phSensorPin 0            //pH meter Analog output to Arduino Analog Input 0
#define Offset 41.02740741      //deviation compensate
#define samplingInterval 20
#define ArrayLenth  40    //times of collection
int pHArray[ArrayLenth];   //Store the average value of the sensor feedback
int pHArrayIndex = 0;

#define orpSensorPin 1            //pH meter Analog output to Arduino Analog Input 0

JSONVar lastSensorData;
unsigned long last_report;
int sample_data_num = 0;

byte deviceMAC[6] = {0x00, 0xE0, 0x22, 0xFE, 0xDA, 0xC9};
byte destinationMAC[6] = {0x00, 0xE0, 0x22, 0xFE, 0xDA, 0xCA};

void setup() 
{
    Serial.begin(115200);
    while(!Serial);

    Serial.println("Single Pair Ethernet - Example 3a Transmit String from Sensor(BME280) data");
    /* Start up adin1110 */
    if (!adin1110.begin(deviceMAC)) 
    {
      Serial.print("Failed to connect to ADIN1110 MACPHY. Make sure board is connected and pins are defined for target.");
      while(1); //If we can't connect just stop here  
    }
    
    Serial.println("Coonfigured ADIN1110 MACPHY");

    /* Wait for link to be established */
    Serial.println("Device Configured, waiting for connection...");
    while (adin1110.getLinkStatus() != true);

    Wire.begin();

    ads.setAddr_ADS1115(ADS1115_IIC_ADDRESS1);   // 0x48
    ads.setGain(eGAIN_TWOTHIRDS);   // 2/3x gain
    ads.setMode(eMODE_SINGLE);       // single-shot mode
    ads.setRate(eRATE_128);          // 128SPS (default)
    ads.setOSMode(eOSMODE_SINGLE);   // Set to start a single-conversion
    ads.init();
    
    if (distanceSensor.begin() != 0) //Begin returns 0 on a good init
    {
      char msg[] = "Sensor failed to begin. Please check wiring. Freezing...";
      adin1110.sendData((byte *)msg, sizeof(msg));
      delay(1000); //Freeze
      while (1)
      ;
    }

}

#define diff(a,b,max_diff) ((a>=b+max_diff) || (a<=b-max_diff))

void loop() {
    unsigned long now;
    bool force_report = false;

    //Collect the BME sensor data in an object
    JSONVar sensorData;
    sensorData["distance"] = measure_distance();
    sensorData["ph"] = measure_ph();
    sensorData["orp"] = measure_orp();


    //If any sensors have significantly changed, send a new report right away
    if( diff((double)sensorData["distance"], (double)lastSensorData["distance"], 1) || 
        diff((double)sensorData["ph"], (double)lastSensorData["ph"], 0.5) || 
        diff((double)sensorData["orp"], (double)lastSensorData["orp"], 3)) 
    {
        force_report = true;
    }

    now = millis();
    if(now-last_report >= 5000 || force_report)
    {
      if (adin1110.getLinkStatus())
      {
        String jsonString = JSON.stringify(sensorData);
        adin1110.sendData( (byte *)jsonString.c_str(), strlen(jsonString.c_str()) + 1 );
        Serial.print("Sent (");   
        Serial.print(strlen(jsonString.c_str()));
        Serial.print(") bytes :\t");  
        Serial.println(jsonString.c_str());
        
        lastSensorData = sensorData;
        last_report = now;
      }
      else
      {
        Serial.println("Waiting for link to resume sending");
      }
    }

    delay(100);
} 


float measure_distance(void){
   distanceSensor.startRanging(); //Write configuration bytes to initiate measurement
   while (!distanceSensor.checkForDataReady())
   {
    delay(1);
   }
   int distance = distanceSensor.getDistance(); //Get the result of the measurement from the sensor
   distanceSensor.clearInterrupt();
   distanceSensor.stopRanging();

   float distanceInCM = distance / 10.0;
   return distanceInCM;
}

float measure_ph(void){
   static unsigned long samplingTime = millis();
   static float pHValue, voltage;
   if (millis() - samplingTime > samplingInterval)
   {
     if (ads.checkADS1115())pHArray[pHArrayIndex++] = ads.readVoltage(phSensorPin);
     if (pHArrayIndex == ArrayLenth)pHArrayIndex = 0;
     voltage = avergearray(pHArray, ArrayLenth);
     pHValue = -19.18518519 * voltage + Offset;
     samplingTime = millis();
   }
   return pHValue;
}

float measure_orp(void){
   static unsigned long samplingTime = millis();
   static float orpValue, voltage;
   if (millis() - samplingTime > samplingInterval)
   {
     if (ads.checkADS1115())pHArray[pHArrayIndex++] = ads.readVoltage(orpSensorPin);
     if (pHArrayIndex == ArrayLenth)pHArrayIndex = 0;
     voltage = avergearray(pHArray, ArrayLenth);
     orpValue=((30*5000)-(75*voltage))/75;
     samplingTime = millis();
   }
   return orpValue;
}

double avergearray(int* arr, int number) {
  int i;
  int max, min;
  double avg;
  long amount = 0;
  if (number <= 0) {
    return 0;
  }
  if (number < 5) { //less than 5, calculated directly statistics
    for (i = 0; i < number; i++) {
      amount += arr[i];
    }
    avg = amount / number;
    return avg;
  } else {
    if (arr[0] < arr[1]) {
      min = arr[0]; max = arr[1];
    }
    else {
      min = arr[1]; max = arr[0];
    }
    for (i = 2; i < number; i++) {
      if (arr[i] < min) {
        amount += min;      //arr<min
        min = arr[i];
      } else {
        if (arr[i] > max) {
          amount += max;  //arr>max
          max = arr[i];
        } else {
          amount += arr[i]; //min<=arr<=max
        }
      }//if
    }//for
    avg = (double)amount / (number - 2);
  }//if
  return avg;
}

Pump Side Code

Arduino
This code will turn on/off pump based on the data received from tank
#include "SparkFun_SinglePairEthernet.h"
#include <Arduino_JSON.h>
#include <Wire.h>
#include "SparkFun_Qwiic_Relay.h"

#define RELAY_ADDR 0x18 // Alternate address 0x19

SinglePairEthernet adin1110;
Qwiic_Relay relay(RELAY_ADDR); 
int data_update = 0;
int distance;
int ph;
int orp;

byte deviceMAC[6] = {0x00, 0xE0, 0x22, 0xFE, 0xDA, 0xCA};

static void rxCallback(byte * data, int dataLen, byte * senderMAC)
{
    JSONVar sensorData = JSON.parse((char *)data);
    
    distance = (int)sensorData["distance"];
    ph = (int)sensorData["ph"];
    orp = (int)sensorData["orp"];
    data_update = 1;
}

void linkCallback(bool linkStatus)
{
 ;
}

void setup() 
{
    Wire.begin();
    Wire.setClock(100000);
    
    Serial.begin(115200);
    while(!Serial);

    Serial.println("Single Pair Ethernet - Example 3b Recieve String from 3a and Display on SerLCD");
    /* Start up adin1110 */
    if(!adin1110.begin(deviceMAC)) 
    {
      Serial.print("Failed to connect to ADIN1110 MACPHY. Make sure board is connected and pins are defined for target.");
      while(1); //If we can't connect just stop here     
    }
    Serial.println("Connected to ADIN1110 MACPHY");

    /* Set up callback, to control what we do when data is recieved and when link changed*/
    adin1110.setRxCallback(rxCallback);
    adin1110.setLinkCallback(linkCallback);

    while (adin1110.getLinkStatus() != true);

    if(!relay.begin())
      Serial.println("Check connections to Qwiic Relay.");
    else
      Serial.println("Ready to flip some switches.");

    float version = relay.singleRelayVersion();
    Serial.print("Firmware Version: ");
    Serial.println(version);

    relay.turnRelayOn(); 
    delay(500);
    relay.turnRelayOff(); 
}

void loop() {
    unsigned long now = millis();
      
    if(data_update)
    {
        if(distance<15) relay.turnRelayOff(); //water level is high enough
        else if(distance>35) relay.turnRelayOn(); //water level is too low
                
        data_update = 0;
    }
    delay(5);
}

Credits

Md. Khairul Alam

Md. Khairul Alam

68 projects • 587 followers
Developer, Maker & Hardware Hacker. Currently working as a faculty at the University of Asia Pacific, Dhaka, Bangladesh.

Comments