Project tutorial
Smart Aquarium

Smart Aquarium © MIT

Phone app to monitor and control vitals of fish in a home aquarium via ESP32.

  • 8 views
  • 0 comments
  • 0 respects

Components and supplies

Necessary tools and machines

Apps and online services

About this project

The Smart Aquarium project was developed by an elite team of students at the National Institue of Applied Science and Technology (INSAT) in Spring 2018.

The Team was sponsored by Business&Decisions and was build inside Aerobotix INSAT Club Labs.

Check the Project on GitHub: https://github.com/KaremBenChikha/SmartAquarium

Visit my personal portfolio: karembenchikha.me

The team participated in various Robotics competitions and Hackathons and won the following:

  • 2nd Place Winner Award at IoT TUNISIA National Competition
  • 1st Place Winner Award at TUNIROBOTS'18 National Projects of Expositions
  • 1st Place Winner Award at IEEE' Biological IOT on Campus Competition

The Smart Aquarium aims to monitor and control the vitals of fish inside a home aquarium.

Smart Aquarium Video Simulation

As you saw in the YouTube video, a mobile app connected to the internet has access to monitor and control the aquarium. It can :

  • Feed the fish either manually by specifying the amount of food and click on the feed button or by setting a schedule to choose the time and date of when to feed the fish.
  • Control the lighting inside the aquarium, you have the possibility to choose from an RGB color palette. a night mode linked to a light sensor will turn automatically the white light on when it too dark for the fish.
  • Measure the temperature of the aquarium by a temperature waterproof sensor.
  • Control the oxygen inside the aquarium. the are two modes; Low and High.

The App was designed with Android Studio:

After Prototype: a custom PCB was designed and manufactured:

and the render:

All Parts were designed and either 3D printed or CNC manufactured. we Used Solidworks for CAD Design.


Code

codeC/C++
/***************************************************
  SMART AQUARIUM BETA VERSION CODE 
 ****************************************************/
#include <String.h>
#include <ESP8266WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include <WiFiClientSecure.h>
#include <OneWire.h>

/************************* WiFi Access Point *********************************/

#define WLAN_SSID       "your hotspot"
#define WLAN_PASS       "your password"

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME    "username"
#define AIO_KEY         "API KEY"

/************************* IFTT SMS Setup *********************************/

const char* host = "maker.ifttt.com";
const int httpsPort = 443;

// Make a POST or GET web request to
String temp_url = "/trigger/Temperature/with/key/kSBX3NcCsB2Xz2z-ngJYu7U6jhBoiDKXzK8DkY7r1QZ";
String feed_url = "/trigger/Feeding/with/key/kSBX3NcCsB2Xz2z-ngJYu7U6jhBoiDKXzK8DkY7r1QZ";

/************ Global State ******************/

// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_USERNAME, AIO_KEY);

/****************************** Feeds ***************************************/

Adafruit_MQTT_Subscribe Food = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/Food", MQTT_QOS_1);

Adafruit_MQTT_Subscribe RGB = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/RGB", MQTT_QOS_1);

Adafruit_MQTT_Subscribe PUMP = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/Oxygen", MQTT_QOS_1);

Adafruit_MQTT_Subscribe Temperature = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/Temperature", MQTT_QOS_1);

Adafruit_MQTT_Publish Temp = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Temperature");

// System control : push current state
//Adafruit_MQTT_Publish State_push = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Notification");


/*************************** Sketch Code ************************************/

//DS18B20 temeprature sensor parameters
OneWire ds(2);
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];

// RGB parameters 
#define RED_PIN     14
#define GREEN_PIN   15
#define BLUE_PIN    13

// other system parameters
#define PUMP_PIN    12

// light sensor config 
const int sensorPin = 10;

// stepper config 
#define pin1 16
#define pin2 5
#define pin3 4
#define pin4 0

#define delaytime         5
#define numberOfSteps     520
#define MAX_FOOD_AMOUNT   520

int food_revolution;
String nightMode;

// timer parameters
int sec;
int minn;
int hour;

int timeZone = -4; // utc-4 eastern daylight time (nyc)

////////////////////////////////////////////// Temperature /////////////////////////////////

void temperatureCallback(double x) {
  // read temperature feed
  // Serial.print("Hey we re in a temperature callback, the current temp value is: ");
  // Serial.println(x);  
}


////////////////////////////////////////////// Oxygen pump setup /////////////////////////////////

void pumpCallback(char *data, uint16_t len) {
  // read oxygen feed
  //Serial.print("Hey we re in a ogygen callback, the current pump state is: ");
  //Serial.println(data);
  String state = (char *)data;
  if(state == "low") 
  {
    //Serial.println("low");
    digitalWrite(PUMP_PIN,HIGH);  
  }
  else 
  {
    //Serial.println("Height");
    digitalWrite(PUMP_PIN,LOW);
  }
}

/////////////////////////////////////////////// Timer //////////////////////////////////////

void timecallback(uint32_t current) {

  // adjust to local time zone
  current += (timeZone * 60 * 60);

  // calculate current time
  sec = current % 60;
  current /= 60;
  minn = current % 60;
  current /= 60;
  hour = current % 24;

  // print hour
  if(hour == 0 || hour == 12)
    Serial.print("12");
  if(hour < 12)
    Serial.print(hour);
  else
    Serial.print(hour - 12);

  // print mins
  Serial.print(":");
  if(minn < 10) Serial.print("0");
  Serial.print(minn);

  // print seconds
  Serial.print(":");
  if(sec < 10) Serial.print("0");
  Serial.print(sec);

  if(hour < 12)
    Serial.println(" am");
  else
    Serial.println(" pm");

}

////////////////////////////////////////// RGB control ///////////////////////////////////////

void rgbCallback(char *data, uint16_t len) {
  // Serial.print("Hey we're in a rgb callback, the color hex value is: ");
  // Serial.println(data);
  String colorHex = (char *)data;
          // Convert it to integer
          int number = (int) strtol( &colorHex[2], NULL, 16);

          // Split them up into r, g, b values
          int r = number >> 16;
          int g = number >> 8 & 0xFF;
          int b = number & 0xFF;
          // Serial.println(r);
          // Serial.println(g);
          // Serial.println(b);
          setColor(r,g,b);
}

////////////////////////////////////////// Feeding control ///////////////////////////////////

void foodCallback(double amount) {
  // Serial.print("Hey we're in a onoff callback, the button value is: ");
  // Serial.println(amount);
  int steps = (int) amount;
  feed(steps);
}

////////////////////////////////////////////// Stability /////////////////////////////////

void stateCallback(double x) {
  // read state feed
//  Serial.print("Hey we re in a state callback, the current state is: ");
//  Serial.println(x);  
}

void setup() {
//  Serial.begin(115200);
//  delay(100);
//
//  Serial.println(F("Adafruit MQTT demo"));
//
//  // Connect to WiFi access point.
//  
//  Serial.println(); Serial.println();
//  Serial.print("Connecting to ");
//  Serial.println(WLAN_SSID);
//
  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
 //   Serial.print(".");
  }
//  Serial.println();
//
//  Serial.println("WiFi connected");
//  Serial.println("IP address: "); Serial.println(WiFi.localIP());

// init food revolution
  food_revolution = 0;

// initialize light sensor
  pinMode(sensorPin, INPUT);

// pin setup
  pinMode(pin1,OUTPUT);
  pinMode(pin2,OUTPUT);
  pinMode(pin3,OUTPUT);
  pinMode(pin4,OUTPUT);


//  pinMode(REGULATION_PIN,OUTPUT);
//  pinMode(EVACUATION_PIN,OUTPUT);

 //  Serial.println("wselt 8adi");
  
  pinMode(RED_PIN,OUTPUT);
  pinMode(GREEN_PIN,OUTPUT);
  pinMode(BLUE_PIN,OUTPUT);

  pinMode(PUMP_PIN,OUTPUT);
  
// set callbacks 
  Food.setCallback(foodCallback);
  RGB.setCallback(rgbCallback);
  Temperature.setCallback(temperatureCallback);
  PUMP.setCallback(pumpCallback);
//  State_sub.setCallback(stateCallback);
  
  // Setup MQTT subscription for time feed.
  mqtt.subscribe(&Food);
  mqtt.subscribe(&RGB);
  mqtt.subscribe(&Temperature);
  mqtt.subscribe(&PUMP);

  // set PUMP default mode 
  digitalWrite(PUMP_PIN,LOW);  
  
  // connect to Adafruit MQTT
  MQTT_connect();

}

uint32_t x=0;

void loop() {
  // Ensure the connection to the MQTT server is alive (this will make the first
  // connection and automatically reconnect when disconnected).  See the MQTT_connect
  // function definition further below.
  
  if (Temp.publish(getTemperature()))
  {
  //  Serial.print("temperature : ");
  //  Serial.println(getTemperature());
    if(getTemperature()< 7 || getTemperature()> 27)
    {
      sendSMS("temp");
    }
  }



  int level = analogRead(sensorPin);
   Serial.printf("Light level: %d\n", level);

  if(level == 1023) 
  {
    setColor(255,255,255);
    nightMode = "on";
  }
  else if(nightMode == "on")
  {
    setColor(0,255,0); // by default set to blue color 
    nightMode = "off";
  }
   
   //delay(5000);
        
  // this is our 'wait for incoming subscription packets and callback em' busy subloop
  // try to spend your time here:
  mqtt.processPackets(5000);
  
  // ping the server to keep the mqtt connection alive
  // NOT required if you are publishing once every KEEPALIVE seconds

  
//  if(! mqtt.ping()) {
//    mqtt.disconnect();
//  }
}

////////////////////////////// MQTT Connect ///////////////////////
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) 
  {
    return;
  }

 // Serial.print("Connecting to MQTT... ");

  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
      // Serial.println(mqtt.connectErrorString(ret));
      // Serial.println("Retrying MQTT connection in 10 seconds...");
       mqtt.disconnect();
       delay(10000);  // wait 10 seconds
       retries--;
       if (retries == 0) {
         // basically die and wait for WDT to reset me
         while (1);
       }
  }
  // Serial.println("MQTT Connected!");
  // setColor(255,255,255);
}

////////////////////////////// Temperature Sensor ///////////

float getTemperature()
{
  
  if ( !ds.search(addr))
  {
    ds.reset_search();
    delay(200);
  }
  if (OneWire::crc8(addr, 7) != addr[7])
  {
//    Serial.println("CRC is not valid!");
  }
  switch (addr[0])
  {
    case 0x10:
      type_s = 1;
      break;
    case 0x28:
      type_s = 0;
      break;
    case 0x22:
      type_s = 0;
      break;
    default: ;
  }
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1); // start conversion, with parasite power on at the end
  delay(100);
  present = ds.reset();
  ds.select(addr);
  ds.write(0xBE); // Read Scratchpad
  for ( i = 0; i < 9; i++)
    data[i] = ds.read();
  // Convert the data to actual temperature
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s)
  {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10)
      raw = (raw & 0xFFF0) + 12 - data[6];
  }
  else
  {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  }
  return ((float)raw / 16.0);
}


void stepA()
{
  digitalWrite(pin1,1);
  digitalWrite(pin2,0);
  digitalWrite(pin3,0);
  digitalWrite(pin4,0);
}
void stepB()
{
  digitalWrite(pin1,0);
  digitalWrite(pin2,1);
  digitalWrite(pin3,0);
  digitalWrite(pin4,0);
}
void stepC()
{
  digitalWrite(pin1,0);
  digitalWrite(pin2,0);
  digitalWrite(pin3,1);
  digitalWrite(pin4,0);
}
void stepD()
{
  digitalWrite(pin1,0);
  digitalWrite(pin2,0);
  digitalWrite(pin3,0);
  digitalWrite(pin4,1);
}

void forward()
{
  stepA();
  delay(delaytime);
  stepB();
  delay(delaytime);
  stepC();
  delay(delaytime);
  stepD();
  delay(delaytime);
}

void backward()
{
  stepD();
  delay(delaytime);
  stepC();
  delay(delaytime);
  stepB();
  delay(delaytime);
  stepA();
  delay(delaytime);
}

void stepOff()
{
  digitalWrite(pin1,0);
  digitalWrite(pin2,0);
  digitalWrite(pin3,0);
  digitalWrite(pin4,0);
}

/////////////////////////// Feeding Mecanism ////////////////

void feed(int steps)
{
  int s = numberOfSteps;
  switch(steps) 
  {
    case 20:
      s = 104;
      food_revolution += 20;
      break;
      
    case 40:
      s = 208;
      food_revolution += 40;
      break;

    case 60:
      s = 312;
      food_revolution += 60;
      break;

    case 80:
      s = 416;
      food_revolution += 80;
      break;

    case 100:
      s = 520;
      food_revolution += 100;
      break;
  }
  
  stepOff();
  while(s>0)
  {
    forward();
    s--;
  }
  
  if(food_revolution > MAX_FOOD_AMOUNT)
  {
    sendSMS("food");  
  }
  
//  Serial.println("5raj me stepper");
}

///////////////////////////// RGB controller /////////////////

void setColor(int red, int green, int blue) 
{
 // invert RGB values for common anode LEDs
  analogWrite(RED_PIN, red); 
  analogWrite(GREEN_PIN, green); 
  analogWrite(BLUE_PIN, blue); 
}

////////////////////////////// SMS Sender /////////////////////

void sendSMS(String issue) 
{

  WiFiClientSecure client;
//  Serial.print("connecting to ");
//  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
//    Serial.println("connection failed");
    return;
  }
 
//  Serial.print("requesting URL: ");
  if(issue == "temp") 
  {
//    Serial.println(temp_url);
    client.print(String("GET ") + temp_url + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "User-Agent: BuildFailureDetectorESP8266\r\n" +
                 "Connection: close\r\n\r\n");
//    Serial.println("request sent");
  }
  
  if(issue == "food")
  {
//    Serial.println(feed_url);
    client.print(String("GET ") + feed_url + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "User-Agent: BuildFailureDetectorESP8266\r\n" +
                 "Connection: close\r\n\r\n");
//    Serial.println("request sent");
    
  }   

  while (client.connected()) {
    String line = client.readStringUntil('\n');
    if (line == "\r") {
      // Serial.println("headers received");
      break;
    }
  }
  
  String line = client.readStringUntil('\n');
//  Serial.println("reply was:");
//  Serial.println("==========");
//  Serial.println(line);
//  Serial.println("==========");
//  Serial.println("closing connection");
     
}

Custom parts and enclosures

renderaqua_0i5i5bewAM.JPG
Renderaqua 0i5i5bewam
design_VtzY8r7WjZ.7z
design_VtzY8r7WjZ.7z

Schematics

aquabit_IAJczjxkHo.fzz
aquabit_IAJczjxkHo.fzz
Electrical Desgin
Conception electrique 5qbe0omazf

Comments

Similar projects you might like

Octopod: Smart IoT Home/Industry Automation Project

Project tutorial by Saksham Bhutani

  • 16,620 views
  • 12 comments
  • 48 respects

Scent-terrific Smart Candle

Project tutorial by Darian Johnson

  • 5,182 views
  • 0 comments
  • 35 respects

Smart Plant IoT

Project tutorial by 3 developers

  • 15,817 views
  • 3 comments
  • 46 respects

Smart Battery Charger Multiplexer with Smart Display

Project tutorial by leonzak

  • 7,285 views
  • 9 comments
  • 23 respects

Smart Coffee Table with Nano and HX711

Project tutorial by TheTNR

  • 5,814 views
  • 3 comments
  • 14 respects
Add projectSign up / Login