Things used in this project

Hardware components:
102110017%206
MediaTek Labs LinkIt Smart 7688 Duo
×1
28BYJ-48 5V
×1
ULN2003 5-12V Stepper Motor Driver Board
×1
Adafruit industries ada161 image 75px
Photo resistor
×1
Kingbright wp7113srd d image
5 mm LED: Red
×1
50x70mm Prototyping PCB
×1
DS18B20 waterproof
×1
Neopixel strip
NeoPixel strip
×1
11026 02
Jumper wires (generic)
×1
2pcs 3x15mm screw and nuts
×1
Mfr 25frf52 10k sml
Resistor 10k ohm
×1
Resistor 220 ohm
×1
Resistor 4,7k ohm
×1
Software apps and online services:
Microsoft Visual Studio Code
Ide web
Arduino IDE
Blynk logo avatars
Blynk
Hand tools and fabrication machines:
09507 01
Soldering iron (generic)
Screwdriver set
Pliers set

Custom parts and enclosures

main_body
Main body of the IOT Aquarium controller
Feeding mechanism P1
Feeding mechanism P2
Feeding mechanism P3
Feeding mechanism small P3
neopixel_strip

Schematics

iotaquarium_sckxOcBI84.fzz
iotaquarium_sckxOcBI84.fzz

Code

IOTAquarium.inoC/C++
/***************  IOTAquarium   ***********************
  This is a project to help you manage your fish tank. Folowing functions are currently implemented:
      -fish feed
      -empty food tank allert
      -water temperature monitoring
      -light controler(using 5v neopixel)

  Used pins:
  28BYJ-48 motor/ULN2003A (IN1,IN2,IN3,IN4) <-> Smart7688 DUO(13,12,11,10)
  DS18B20 (red,yellow,gray) <-> Smart7688 DUO(5V,D3,GND)+4,7k betwen 5V and DATA
  LDR (VCC,data) <-> Smart7688 DUO(5V,A5)+10k betwen GND and DATA
 ******************************************************/

#include <stdlib.h>

//******  Steper library
#include <Stepper.h>//include stepper library for moving the feeder
// change this to fit the number of steps per revolution for your mottor

//configure the steper on the connected pins
const int s1 = 13;
const int s2 = 12;
const int s3 = 11;
const int s4 = 10;
int del = 2000;//delay betwen steps
//*******************************

//******  LDR
int ldrPin = A5; //pin on wich is connected the LDR
int ldrValue = 0; //initial value for the LDR value
//*******************************

//****** Temperature
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 3// Data wire is plugged into pin 3
OneWire oneWire(ONE_WIRE_BUS);// Setup a oneWire instance to communicate with any OneWire devices
DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature.
//*******************************

//****** Neopixel
#include <Adafruit_NeoPixel.h>
#define PIN            8// We use pin * for comunicating with 5v neopixel strip
#define NUMPIXELS      16//curently I had only 4 neopixel. I need here a improvement
Adafruit_NeoPixel light = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
//colors
byte R = 0;
byte G = 0;
byte B = 0;
//intensity
byte I = 255;
//*******************************

//****** Serial port comunication
#include <SerialCommand.h>
SerialCommand sCmd;     //This SerialCommand object will be used to comunicate betwen Atmega32U4 and MT7688
//*******************************


//****** Keeping up with the time
#include <TimeLib.h>
#include <TimeAlarms.h>
AlarmId a1, a2, a3;//needed alarms objects
String days_to_feed = "";//variable needed for understanding in wich days feeding needs to happen

void setup() {
  Serial.begin(9600); //sets serial port for communication
  Serial1.begin(57600);  // open internal serial connection to MT7688AN
  sensors.begin();  // start up the library
  light.setBrightness(255);// start with full brighness
  light.begin(); // this initializes the NeoPixel library.

  // Define recognized commands callbacks for SerialCommand
  sCmd.addCommand("FEED",   feed);          // function to feed the fish
  sCmd.addCommand("L",     lights);  // function to start/stop the lights and establish color with intensity
  sCmd.addCommand("T",     times);  // time sincronization
  sCmd.addCommand("A",     alarms);  // alarm setup
  sCmd.setDefaultHandler(unrecognized);      // handler for command that isn't matched  (says "What?")

  //allocate functions to each alarm
  a1 =  Alarm.alarmRepeat(1, 1, 1, light_on);
  a2 =  Alarm.alarmRepeat(1, 1, 1, light_off);
  a3 =  Alarm.alarmRepeat(1, 1, 1, feed_me);
  //configure stepper pins as output
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(s4, OUTPUT);

}

void loop() {
  ldrValue = analogRead(ldrPin); // read the value from the sensor
  sensors.requestTemperatures(); // send the command to get temperatures
  String tmp = "";//temporary variable to make the message that will be sent over serial
  tmp = tmp + sensors.getTempCByIndex(0);
  tmp = tmp + ";";
  tmp = tmp + ldrValue;
  Serial1.println(tmp); //send the values to the MT7688
  sCmd.readSerial();     // see if MT7688 is telling us something
  //digitalClockDisplay();//just for debugging if you need to see what time it is
  Alarm.delay(5); // wait a little for the alarms to work

}

//function to set color and brightness for the neopixel
void becuri(byte R, byte G, byte B, byte J) {
  for (int i = 0; i < 16; i++) {
    light.setPixelColor(i, light.Color(0, 0, 0)); //establish neopixel colors
  }


  for (int i = 0; i < map(J, 0, 100, 0, 16); i++) {
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    light.setPixelColor(i, light.Color(R, G, B)); //establish neopixel colors
  }
  light.show(); // this sends the updated pixel color to the hardware.


}

//function to move the motor and feed the fish
void feed() {

  for (int i = 0; i <= 80; i++) {
    forwardsFull();
  };
  for (int i = 0; i <= 80; i++) {
    backwardsFull();
  };
  motorOff();

}

//function for lights with 4 parameters that reads the message from MT7688 and makes the Atmega32U4 to act acordingly
void lights() {
  int aNumber, bNumber, cNumber, intens;
  char *arg;
  arg = sCmd.next();
  if (arg != NULL) {
    aNumber = atoi(arg);    // converts a char string to an integer
    //Serial.print("First argument was: "); //only debuging
    //Serial.println(aNumber); //only debuging
  }
  else {
    aNumber = 0;
  }

  arg = sCmd.next();
  if (arg != NULL) {
    bNumber = atol(arg);
    // Serial.print("Second argument was: ");
    // Serial.println(bNumber);
  }
  else {
    bNumber = 0;
  }

  arg = sCmd.next();
  if (arg != NULL) {
    cNumber = atol(arg);
    // Serial.print("3 argument was: ");
    // Serial.println(cNumber);
  }
  else {
    cNumber = 0;
  }

  arg = sCmd.next();
  if (arg != NULL) {
    intens = atol(arg);
    // Serial.print("4 argument was: ");
    //  Serial.println(intens);
  }
  else {
    intens = 0;
  }
  R = aNumber; G = bNumber; B = cNumber; I = intens;
  becuri(R, G, B, I);

}

//function for arduino time sincronization
void times() {
  time_t bNumber;
  char *arg;

  arg = sCmd.next();
  if (arg != NULL) {
    int tmp;
    bNumber = 0;
    for (int i = 0; i < 10; i++) {
      tmp = (int)arg[i] - 48;
      bNumber = (10 * bNumber) + tmp;
    }
  }
  else {
    bNumber = 0;
  }
  setTime(bNumber);
  //Serial.print(bNumber);
}

//Get the defined alarms from MT7688 and set them in our arduino time alarm library
void alarms() {
  int aNumber;
  long bNumber, cNumber;
  String dNumber;
  char *arg;

  arg = sCmd.next();
  if (arg != NULL) {
    aNumber = atoi(arg);
  }
  else {
    aNumber = 0;
  }
  arg = sCmd.next();
  if (arg != NULL) {
    bNumber = atol(arg);
  }
  else {
    bNumber = 0;
  }


  arg = sCmd.next();
  if (arg != NULL) {
    cNumber = atol(arg);
  }
  else {
    cNumber = 0;
  }

  arg = sCmd.next();
  if (arg != NULL) {
    dNumber = arg;
  }
  else {
    dNumber = "";
  }
  byte h, m, s;



  if (aNumber == 1)
  {
    Alarm.free(a1);
    Alarm.free(a2);
    h = bNumber / (60 * 60);
    m = (bNumber % (60 * 60)) / 60;
    s = ((bNumber % (60 * 60)) % 60);
    Alarm.disable(a1);
    a1 =  Alarm.alarmRepeat(h, m, s, light_on);
    Alarm.enable(a1);
    //Serial.println(Alarm.read(a1));
    //Serial.print(h);
    //Serial.print(" ");
    //Serial.print(m);
    //Serial.print(" ");
    //Serial.println(s);
    h = cNumber / (60 * 60);
    m = (cNumber % (60 * 60)) / 60;
    s = ((cNumber % (60 * 60)) % 60);
    //Serial.print(h);
    //Serial.print(" ");
    //Serial.print(m);
    //Serial.print(" ");
    //Serial.println(s);
    Alarm.disable(a2);
    a2 =  Alarm.alarmRepeat(h, m, s, light_off);
    Alarm.enable(a2);
    //Serial.println(Alarm.read(a2));
  }

  else if (aNumber == 2)
  {
    h = bNumber / (60 * 60);
    m = (bNumber % (60 * 60)) / 60;
    s = ((bNumber % (60 * 60)) % 60);
    days_to_feed = dNumber;
    //Serial.print(h);
    //Serial.print(" ");
    //Serial.print(m);
    //Serial.print(" ");
    //Serial.println(s);
    Alarm.disable(a3);
    a3 =  Alarm.alarmRepeat(h, m, s, feed_me);
    Alarm.enable(a3);


  }

}

//ligt ON at alarm trigger
void light_on() {
  if (((R == 0) & (G == 0) & (B == 0)) || (I == 0)) {
    becuri(255, 255, 255, 100);
  }
  else {
    becuri(R, G, B, I);
  }
  //Serial.println(R);
  //Serial.println(G);
  //Serial.println(B);
  //Serial.println(I);
  //Serial.println("ON");
}

//ligt OFF at alarm trigger
void light_off() {
  becuri(0, 0, 0, 0);
  //Serial.println("OFF");
}

//feed at alarm trigger
void feed_me() {
  String tmp = "";
  if (weekday() == 1) {
    tmp = "7";
  }
  else
  {
    tmp = String(weekday() - 1);
  }
  if (find_text(tmp, days_to_feed) != -1) {
    feed();
  }
  //Serial.println("FEED");

}
// This gets set as the default handler, and gets called when no other command matches.
void unrecognized(const char *command) {
  Serial.println("What?");
}


//3 helping aid functions
void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
}

void printDigits(int digits) {
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}


int find_text(String needle, String haystack) {
  int foundpos = -1;
  for (int i = 0; i <= haystack.length() - needle.length(); i++) {
    if (haystack.substring(i, needle.length() + i) == needle) {
      foundpos = i;
    }
  }
  return foundpos;
}
//stop motor
void motorOff() {
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(s4, LOW);
}
//move backward
void backwardsFull() {

  digitalWrite(s1, HIGH);
  digitalWrite(s2, HIGH);
  digitalWrite(s3, LOW);
  digitalWrite(s4, LOW);
  delayMicroseconds(del * 2);

  digitalWrite(s1, LOW);
  digitalWrite(s2, HIGH);
  digitalWrite(s3, HIGH);
  digitalWrite(s4, LOW);
  delayMicroseconds(del * 2);

  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, HIGH);
  digitalWrite(s4, HIGH);
  delayMicroseconds(del * 2);

  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(s4, HIGH);
  delayMicroseconds(del * 2);

}
//move forward
void forwardsFull() {

  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(s4, HIGH);
  delayMicroseconds(del * 2);

  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, HIGH);
  digitalWrite(s4, LOW);
  delayMicroseconds(del * 2);

  digitalWrite(s1, LOW);
  digitalWrite(s2, HIGH);
  digitalWrite(s3, LOW);
  digitalWrite(s4, LOW);
  delayMicroseconds(del * 2);

  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(s4, LOW);
  delayMicroseconds(del * 2);

}
IOTAquarium.jsJava
 //include moment module for working with time 
var moment = require('moment-timezone'); 
var q = require('moment'); 
//include blynk module to be able to comunicate with our app 
var Blynk = require('blynk-library'); 
var AUTH = '98fd3b118cc84d8e9e54f90ed085449b';//you will get this key from your blynk project in your phone app 
var blynk = new Blynk.Blynk(AUTH);//create the link betwen your app and the IOT device 
//include serial module to be able to facilitate the comunication betwen MT7688 and ATMEGA32U4  
var com = require("serialport"); 
//default serial port for this comunication with the configuration parameters 
var serialPort = new com.SerialPort("/dev/ttyS0", { 
 baudrate: 57600, 
 parser: com.parsers.readline('\r\n') 
}); 
//If everything is ok write on the console that port is open 
serialPort.on('open', function () { 
 console.log('Port open...'); 
}); 
//else write a error message 
serialPort.on('error', function () { 
 console.log('Error...'); 
}); 
var t = "";//variable to keep time 
var f = 0;//variable to know when to feed 
var R = 0, 
 B = 0, 
 G = 0, 
 I = 255;//RGB and Intensity values 
var ziua;//day to feed 
var v0 = new blynk.VirtualPin(0);//light 
var v1 = new blynk.VirtualPin(1);//feeding schedlue 
var v2 = new blynk.VirtualPin(2);//feed buttom 
var v3 = new blynk.VirtualPin(3);//display temperature 
var v4 = new blynk.VirtualPin(4);//brigness 
var v5 = new blynk.VirtualPin(5);//lighting color 
var v6 = new blynk.VirtualPin(6);//status of the food 
//include sntp module to be sync our clock and know exact time from the internet 
var Sntp = require('sntp'); 
// Request server time  
var options = { 
 host: 'pool.ntp.org', // Defaults to pool.ntp.org  
 port: 123, // Defaults to 123 (NTP)  
 resolveReference: true, // Default to false (not resolving)  
 timeout: 1000 // Defaults to zero (no timeout)  
}; 
Sntp.time(options, function (err, time) { 
 if (err) { 
   console.log('Failed: ' + err.message); 
 } 
}); 
function time_su() { 
 //**********************************/ 
 now = Sntp.now(); 
 var time = moment.tz(now, "Europe/Bucharest");//change here if you are not living in ROMANIA 
 var time_string = time.format(); 
 var ta = now + q.parseZone(time_string).utcOffset() * 60 * 1000; 
 serialPort.write("T " + ta + "\r\n"); 
 //**convert time to local timezone and send it to ATMEGA32U4 so that we can use it in our arduino schetc */ 
 var date = new Date(); 
//************make an email alert once per day in case food container is empty */ 
 if( (f>=1000)&&(ziua!=date.getDate())) 
 { 
   blynk.email("IOTAquarium","It's time to replace your fish food container!");//here is the email alert message 
   ziua=date.getDate(); 
 } 
 setTimeout(time_su, 60000);//repeate this every 5 minute 
} 
time_su(); 
//below is the code that decide what to do when interacting with various widgets from our blynk app  
v0.on('write', function (param) { 
 //console.log(param); 
 serialPort.write("A 1 " + param[0] + " " + param[1] + " " + param[3] + "\r\n"); 
}); 
v1.on('write', function (param) { 
 serialPort.write("A 2 " + param[0] + " " + "12" + " " + param[3] + "\r\n"); 
}); 
v2.on('write', function (param) { 
 serialPort.write("FEED\r\n"); 
}); 
v3.on('read', function () { 
 v3.write(t); 
}); 
v6.on('read', function () { 
 if (f > 1000) { 
 v6.write( "EMPTY"); 
 } else { 
  v6.write("OK"); 
 } 
}); 
v4.on('write', function (param) { 
 I = param[0]; 
 serialPort.write("L " + R + " " + G + " " + B + " " + I + "\r\n"); 
 //console.log(R, G, B, I); 
}); 
v5.on('write', function (param) { 
 R = param[0]; 
 G = param[1]; 
 B = param[2]; 
 serialPort.write("L " + R + " " + G + " " + B + " " + I + "\r\n"); 
 //console.log(R, G, B, I); 
}); 
serialPort.on('data', function (data) { 
 var arr = data.split(";"); 
 t = arr[0]; 
 f = arr[1]; 
 parseInt(f, 10); 
}); 

Credits

Replications

Did you replicate this project? Share it!

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

Solar Smart Greenhouse using Vertical Aquaponic Towers
Intermediate
  • 1,207
  • 22

Work in progress

Feed your family with 22 sqm greenhousing by combining permaculture, aquaponic vertical towers and IOT.

Vehicle Artificial Perception-Building Experimental Systems
Intermediate
  • 1,516
  • 15

Work in progress

Exploring Vehicle Artificial Perception in Self-driving technology with DragonBoard 410c and Raspberry Pi 3

4 Wheel Drive, DC Motor Control for Raspberry Pi
Intermediate
  • 1,282
  • 10

Full instructions

Base project for implementing DC motor control using the Raspberry Pi's I2C interface and an Adafruit 16-Channel Servo Shield.

Overkill GENIE garage door opener
Intermediate
  • 1,070
  • 11

Work in progress

Web app garage door opener with up/down direction detection, https password protection, lots of error detection and activity/error logging.

Arduino - Motor PID Speed Control
Intermediate
  • 806
  • 4

Full instructions

Make a program for the Arduino Pro Mini in Visual Studio to control motor speed with PID which can archive it exactly.

Stairway To Lights
Intermediate
  • 1,871
  • 12

Full instructions

Using LED strips, Raspberry PI and PIR sensors, see your path into the stairway to lights.

Add projectSign up / Login
Respect project