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!

I made one

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

Give feedback

Comments

Similar projects you might like

Human-Following Robot with Kinect
Intermediate
  • 2,153
  • 22

Full instructions

Instead of using single camera and complicated image recognition algorithms we can take advantage of Kinect libraries.

Using Temperature Sensor
Intermediate
  • 278
  • 3

Protip

Using the Temperature Sensor from Adafruit

DIY Vending Machine with Cortana Skills and Bot Framework
Intermediate
  • 851
  • 5

Full instructions

Build your own vending machine by turning any dispenser to accept payments using Cortana Skills and Bot Framework on Raspberry Pi.

Arduino with Vb.net GUI control
Intermediate
  • 74
  • 0

Work in progress

This project is related to Arduino and Vb.net.

Rover (connected to Azure)
Intermediate
  • 278
  • 2

Full instructions

The Rover project used Azure

Rover with LEDs
Intermediate
  • 402
  • 1

Full instructions

A rover project with blinking LEDs.

Add projectSign up / Login