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!
Anson He
Published

Mini Water Quality Station Using Seeeduino XIAO

Water Quality Station using Seeeduino XIAO that detects TDS, turbidity, and water level.

BeginnerFull instructions provided1 hour4,119

Things used in this project

Hardware components

Seeed Studio Seeeduino XIAO
×1
Seeed Studio Grove - TDS Sensor
×1
Seeed Studio Grove - Water Level Sensor (10cm)
×1
Seeed Studio Grove - Turbidity Sensor
×1
Seeed Studio Grove - Button
×1
Breadboard (generic)
Breadboard (generic)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

WaterQuality.ino

C/C++
#include <Wire.h>
#include <U8g2lib.h>

U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ A7, /* data=*/ A8, /* reset=*/ U8X8_PIN_NONE);

const unsigned char waterlevel[] PROGMEM = {
  0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 
  0x00, 0x30, 0x03, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0x18, 0x06, 0x00, 
  0x00, 0x0C, 0x0C, 0x00, 0x00, 0x06, 0x18, 0x00, 0x00, 0x07, 0x38, 0x00, 
  0x00, 0x03, 0x30, 0x00, 0x80, 0x01, 0x60, 0x00, 0xC0, 0x18, 0xC0, 0x00, 
  0xC0, 0x3C, 0xC0, 0x00, 0x60, 0x66, 0x88, 0x01, 0x60, 0x66, 0x9C, 0x01, 
  0x30, 0x7C, 0x0E, 0x03, 0x30, 0x38, 0x07, 0x03, 0x30, 0x80, 0x03, 0x03, 
  0x30, 0xC0, 0x01, 0x03, 0x30, 0xE0, 0x00, 0x03, 0x30, 0x70, 0x00, 0x03, 
  0x30, 0x38, 0x0F, 0x03, 0x30, 0x9C, 0x0F, 0x03, 0x60, 0x8E, 0x99, 0x01, 
  0xE0, 0x80, 0xCF, 0x01, 0xC0, 0x00, 0xCF, 0x00, 0x80, 0x03, 0x70, 0x00, 
  0x00, 0x0F, 0x38, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0xF0, 0x03, 0x00, 
  };

const unsigned char turbidity[] PROGMEM = {
  0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x00, 
  0xC0, 0x18, 0x00, 0x00, 0x40, 0x30, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 
  0x30, 0x60, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 
  0x08, 0x80, 0x80, 0x00, 0x04, 0x80, 0xC1, 0x01, 0x0C, 0x00, 0x61, 0x03, 
  0x1C, 0x00, 0x31, 0x06, 0x14, 0x00, 0x11, 0x04, 0x14, 0x00, 0x19, 0x0C, 
  0x1C, 0x80, 0x09, 0x08, 0x2C, 0x80, 0x09, 0x0A, 0x68, 0x80, 0x08, 0x0A, 
  0xD8, 0xC1, 0x08, 0x0B, 0x70, 0x78, 0xD8, 0x0D, 0xC0, 0x3F, 0x31, 0x06, 
  0x00, 0x80, 0xE3, 0x03, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x40, 0x0C, 0x00, 
  0x00, 0x60, 0x0C, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0xA0, 0x08, 0x00, 
  0x00, 0xE0, 0x0D, 0x00, 0x00, 0x60, 0x0C, 0x00, 0x00, 0xC0, 0x07, 0x00, 
  };

const unsigned char tds[] PROGMEM = {
  0x00, 0xE0, 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x36, 0x1B, 0x00, 
  0x00, 0x3F, 0x3F, 0x00, 0x80, 0x09, 0x64, 0x00, 0xC0, 0x00, 0xC0, 0x00, 
  0x80, 0xE1, 0x61, 0x00, 0x80, 0xF1, 0x63, 0x00, 0xE0, 0x18, 0xC6, 0x01, 
  0x60, 0x08, 0x84, 0x01, 0x20, 0x0C, 0x0C, 0x01, 0x60, 0x0C, 0x8C, 0x01, 
  0xE0, 0x18, 0xC6, 0x01, 0xC0, 0xF9, 0xE7, 0x00, 0x80, 0xF1, 0x63, 0x00, 
  0xC0, 0x01, 0xE0, 0x00, 0x80, 0x01, 0x60, 0x00, 0x80, 0x1F, 0x7E, 0x00, 
  0x00, 0x3F, 0x3F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 
  0x02, 0x06, 0x18, 0x10, 0x8F, 0x3F, 0x7F, 0x3C, 0xFC, 0xF1, 0xE3, 0x0F, 
  0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x8F, 0x3F, 0x7F, 0x3C, 0xFC, 0xF1, 0xE3, 0x0F, 0x20, 0xC0, 0x00, 0x01, 
  };


#define SERIAL Serial

#define TDSPin A0
#define turPin A1
#define BUTTON 2

unsigned char low_data[8] = {0};
unsigned char high_data[12] = {0};
int level;

#define NO_TOUCH       0xFE
#define THRESHOLD      100
#define ATTINY1_HIGH_ADDR   0x78
#define ATTINY2_LOW_ADDR   0x77

void getHigh12SectionValue(void)
{
  memset(high_data, 0, sizeof(high_data));
  Wire.requestFrom(ATTINY1_HIGH_ADDR, 12);
  while (12 != Wire.available());

  for (int i = 0; i < 12; i++) {
    high_data[i] = Wire.read();
  }
  delay(10);
}

void getLow8SectionValue(void)
{
  memset(low_data, 0, sizeof(low_data));
  Wire.requestFrom(ATTINY2_LOW_ADDR, 8);
  while (8 != Wire.available());

  for (int i = 0; i < 8 ; i++) {
    low_data[i] = Wire.read(); // receive a byte as character
  }
  delay(10);
}

int check()
{
  int sensorvalue_min = 250;
  int sensorvalue_max = 255;
  int low_count = 0;
  int high_count = 0;
  while (1)
  {
    uint32_t touch_val = 0;
    uint8_t trig_section = 0;
    low_count = 0;
    high_count = 0;
    getLow8SectionValue();
    getHigh12SectionValue();

    for (int i = 0; i < 8; i++)
    {
      if (low_data[i] >= sensorvalue_min && low_data[i] <= sensorvalue_max)
      {
        low_count++;
      }
      if (low_count == 8)
      {
      }
    }
    for (int i = 0; i < 12; i++)
    {

      if (high_data[i] >= sensorvalue_min && high_data[i] <= sensorvalue_max)
      {
        high_count++;
      }
      if (high_count == 12)
      {
      }
    }

    for (int i = 0 ; i < 8; i++) {
      if (low_data[i] > THRESHOLD) {
        touch_val |= 1 << i;

      }
    }
    for (int i = 0 ; i < 12; i++) {
      if (high_data[i] > THRESHOLD) {
        touch_val |= (uint32_t)1 << (8 + i);
      }
    }

    while (touch_val & 0x01)
    {
      trig_section++;
      touch_val >>= 1;
    }

    level = trig_section *5; //water level
    return level;
  }
}

int tdsRaw = 0;
float tdsValue = 0;
float Voltage_tds = 0;
int turbidityRaw = 0;
float Voltage_tur = 0;

bool flag = false;
void count() {
  flag = true;
}

void setup(){
    SERIAL.begin(115200);  
    Wire.begin();
    u8g2.begin();
    pinMode(TDSPin, INPUT);
    pinMode(turPin, INPUT);
    pinMode(BUTTON, INPUT);

    attachInterrupt(digitalPinToInterrupt(BUTTON), count, FALLING);
}


uint8_t cnt = 1;

void loop(){
    tdsRaw = analogRead(TDSPin);
    Voltage_tds = tdsRaw*5/1024.0; //Convert analog reading to Voltage
    tdsValue=(133.42*Voltage_tds*Voltage_tds*Voltage_tds - 255.86*Voltage_tds*Voltage_tds + 857.39*Voltage_tds)*0.5; //Convert voltage value to TDS value
//    Serial.print("TDS Value = "); 
//    SERIAL.print(tdsValue);
//    Serial.println(" ppm");

    turbidityRaw = analogRead(turPin);
    Voltage_tur = turbidityRaw * (5.0 / 1024.0);
//    Serial.print("Turbidity Value = ");
    SERIAL.println(Voltage_tur);

    check();
//    SERIAL.println(level);

    if (flag) {
      cnt++;
      flag = false;
      if (cnt==4) {
        cnt = 1;
      }
    }
//    Serial.println(cnt);
    select_mode(cnt);
    delay(2000);
}

void select_mode(int n)
{
  switch (n)
  {
    case 1:
      u8g2.firstPage();
      do {
        u8g2.setFont(u8g2_font_t0_16b_mr);
        u8g2.drawXBMP(49, 16, 30, 30, tds);
        u8g2.setCursor(40, 60);
        u8g2.print(tdsValue); // write something to the internal memory
        u8g2.print("ppm");
      } while (u8g2.nextPage());
      break;
    case 2:
      u8g2.firstPage();
      do {
        u8g2.setFont(u8g2_font_t0_16b_mr);
        u8g2.drawXBMP(49, 16, 30, 30, turbidity);
        u8g2.setCursor(45, 60);
        u8g2.print(Voltage_tur); // write something to the internal memory
        u8g2.print("V");
      } while (u8g2.nextPage());
      break;
    case 3:
      u8g2.firstPage();
      do {
        u8g2.setFont(u8g2_font_t0_16b_mr);
        u8g2.drawCircle(8, 55, 8, U8G2_DRAW_ALL);
        if (level >= 5 && level < 25) {
          u8g2.drawDisc(8, 55, 8, U8G2_DRAW_UPPER_LEFT);
        }
        if (level >= 25 & level < 50) {
          u8g2.drawDisc(8, 55, 8,  U8G2_DRAW_UPPER_RIGHT | U8G2_DRAW_UPPER_LEFT);
        }
        if (level >= 50 && level < 75) {
          u8g2.drawDisc(8, 55, 8,  U8G2_DRAW_LOWER_LEFT | U8G2_DRAW_UPPER_RIGHT | U8G2_DRAW_UPPER_LEFT);
        }
        if (level >= 75) {
          u8g2.drawDisc(8, 55, 8,  U8G2_DRAW_ALL);
        }
        u8g2.drawXBMP(49, 16, 30, 30, waterlevel);
        u8g2.setCursor(56, 60);
        u8g2.print(level); // write something to the internal memory
        u8g2.print("%");
      } while (u8g2.nextPage());
      break;
  }
}

Credits

Anson He

Anson He

4 projects • 0 followers

Comments