* Update some code bugs on 3/16/16
About 3 years ago I started to incubate eggs in my homemade incubator (glorified dorm refrigerator.) I had extremely good success, but wanted to take it to the next level. I needed an app. I built vb.net apps to talk to the incubator and send me notifications, but I wanted full control. Blynk gave me exactly what I was looking for. I debated marketing it, but if it were not for open-source I never would have got this far.
Fig 1. Incubator (295 quail eggs) heated via a 75 watt bulb. Second heat hookup programmed and available, but not shown here. Humidity controlled via a MOSFET and a fan.
Fig. 2 Cam system with stepper motor to eliminate the over-rotation, and reduce strain on the motor.
Fig 3. PCB origanally designed with buttons on the board, but eliminated with Blynk. More room for sensors now!
Multiple sensors attached and more to come. Terminal being used as a menu instead of buttons to make best use of real-estate . Any chance Blynk could reduce the size of the email and push notification widgets?
Biggest challenge with the project was getting the stepper motor to run without using delays. The link below is what helped the most with getting steppers and Blynk to agree. Blynk.run() in other loops
Below is my code. I apologize for the lack of comments. It needs cleaned up as well, but check it out and let me know if you can think of any improvements.
#include <BlynkSimpleSerial.h>
#define BLYNK_PRINT Serial
#include <LiquidCrystal_I2C.h> //LCD Library
#include <Wire.h> //Wire Library for I2C LCD
#include "DHT.h" //Humidity Library
#include <OneWire.h> //Library for one wire measurement (TEMP)
#include <DallasTemperature.h> //Temperature Library
#include <SimpleTimer.h> //Timer Rotation Library
//**********DEFINE PINS****************************
#define DHTPIN 4
int Bt3 = 5;
int Bt2 = 6;
int Bt1 = 7;
#define DIR_PIN 8
#define STEP_PIN 9 //Stepper Driver Direction Pin
int transis=10; //Transistor Fan Control
int ssr1=11; //Relay Control 1
#define ONE_WIRE_BUS 12 //Temperature Probes
int ssr2=13; //Relay Control 2
#define DHTTYPE DHT22
OneWire oneWire(ONE_WIRE_BUS); //Setup a oneWire instance to communicate with Temperature Probe
DallasTemperature sensors(&oneWire); //Pass oneWire reference to Dallas Temperature Library
DHT dht(DHTPIN, DHTTYPE);
char auth[] = "auth code";
float temps=99.5; // the initial temperature setpoint on startup
float humids=60; // the initial humidity setpoint on startup
float dtr=20; // the total number of days to rotate (20 default)
float rpd=6; // the number of rotation scheduled per day (6 default)********************************************************************************************************************************
unsigned long msdelay; // the delay time between rotations in ms
float temp1; // the temperature from dallas temp 1
float temp2; // the temperature from dallas temp 2
float temph; // the temperature value from the temperature probe
float humid; // the humidity
long rotatetime;
int nextturn;
int remain; // the total time remaining until rotations stop
const int numReadings = 10; // the total number of reading that go into the average temp
float readings[numReadings]; // the readings from the analog input
float readings2[numReadings];
float total = 0; // the running total
float total2 = 0;
float average = 0; // the average
float average2 = 0;
int index = 0; // the index of the current reading
int index2 = 0;
int turns=0; // the total number of rotations completed thus far
boolean homestate = false; // the location of Stepper Motor
int POWER;
int POWER2;
int menub;
int rotating=0;
int termlevel=0;
int manrote=0;
WidgetTerminal terminal(V1);
SimpleTimer sensortimer;
WidgetLCD lcdb(V0);
WidgetLED led1(V13);
WidgetLED led2(V14);
WidgetLED led3(V15);
void setup() {
Serial.begin(9600); //Start Serial Port
Blynk.begin(auth);
sensors.begin(); //Start Temp Sensors
pinMode(A0, OUTPUT); //Defines as Output
pinMode(Bt1,INPUT); //Defines as Input
pinMode(Bt2,INPUT); //Defines as Input
pinMode(Bt3,INPUT); //Defines as Input
pinMode(transis,OUTPUT); //Defines as Output
pinMode(ssr1, OUTPUT); //Defines as Output
pinMode(ssr2, OUTPUT); //Defines as Output
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
msdelay = 86400000/rpd; //Calculates the number of milliseconds delay for rotations based on the times per day set
rotatetime=millis()+ msdelay; //Timer that will run rotate Subroutine every "msdelay" milliseconds
for (int thisReading = 0; thisReading < numReadings; thisReading++) //initialize all the readings to 0:
readings[thisReading] = 0; //sets reading to zero
digitalWrite (transis,LOW);
dht.begin();
rotate(-800, .02);
sensortimer.setInterval(2500L, sensorchecks);
terminalmenu(); //**************************************************************
}
void loop() {
if (rotating!=1){
sensortimer.run();
Blynk.run();}
sensors.requestTemperatures();
temp1 = sensors.getTempCByIndex(1) * 1.8 + 32; //Calculates tempF (deg F) from tempC
temp2 = sensors.getTempCByIndex(0) * 1.8 + 32; //Calculates tempF (deg F) from tempC
total= total - readings[index]; // subtract the last reading:
total2= total2 - readings2[index];
readings[index] = temp1; // read from the sensor:
readings2[index] = temp2;
total= total + readings[index]; // add the reading to the total:
total2= total2 + readings2[index];
index = index + 1; // advance to the next position in the array:
if (index >= numReadings){ // if we're at the end of the array...
index = 0;} // ...wrap around to the beginning:
average = total / numReadings; // calculate the average:
average2 = total2 / numReadings; // calculate the average:
timerotate(millis());}
void sensorchecks(){
humid= dht.readHumidity();
temph=dht.readTemperature(true);
if (humid< humids){
digitalWrite (transis,HIGH);
led3.on();}
else {
digitalWrite (transis,LOW);
led3.off();}
if (average > temps + 0.01){
digitalWrite (ssr1, HIGH);
POWER=0;
led1.off();}
if (average < temps - 0.01){
digitalWrite (ssr1, LOW);
POWER=1;
led1.on();}
if (average2 > temps + 0.01){
digitalWrite (ssr2, HIGH);
POWER2=0;
led2.off();}
if (average2 < temps - 0.01){
digitalWrite (ssr2, LOW);
POWER2=1;
led2.on();}
remain=(dtr-millis()/86400000);
displays();
// Blynk.email("my_email@example.com", "Subject", "Your message goes here");
}
void timerotate(unsigned long timestamp){
nextturn=(rotatetime-timestamp)/60000;
if (timestamp > rotatetime){
rotates();
rotatetime=millis()+ msdelay;
turns= (turns + 1);}}
void rotates(){
digitalWrite (ssr1, HIGH);
digitalWrite (ssr2, HIGH);
if (homestate==true && rpd != 0){
rotate(-1600, .02);}
else if (homestate==false && rpd != 0){
rotate(1600, .02);}
homestate=!homestate;
if (millis() >= dtr*86400000){
humids=80;}}
void rotate(int steps, float speed){
float ms;
int dir = (steps > 0)? HIGH:LOW;
steps = abs(steps);
digitalWrite(DIR_PIN,dir);
float usDelay = (1/speed) * 70;
for(int i=0; i < steps; i++){
digitalWrite(STEP_PIN, HIGH);
ms=millis()+usDelay/1000;
while(ms > millis()){}
Blynk.run();
digitalWrite(STEP_PIN, LOW);
ms=millis()+usDelay/1000;
while(ms > millis()){}
Blynk.run();} }
void displays(){
if(menub==0){
lcdb.clear();
lcdb.print(3, 0, "TEMP1:");
lcdb.print(10, 0, temp1);
lcdb.print(0, 1, "HUMIDITY: ");
lcdb.print(10, 1, humid);
menub=1;}
else if(menub==1){
lcdb.clear();
lcdb.print(3, 0, "TEMP2:");
lcdb.print(10, 0, temp2);
lcdb.print(0, 1, " H TEMP: ");
lcdb.print(10, 1, temph);
menub=0;}
Blynk.virtualWrite(V2, temp1);
Blynk.virtualWrite(V3, temp2);
Blynk.virtualWrite(V4, temph);
Blynk.virtualWrite(V5, humid);}
BLYNK_WRITE(V1){
double term= param.asDouble();
rotating=1;
int termi=term;
switch (termlevel){
case 0:
if (termi==1){
terminal.println("Range (80-105)");
terminal.println("Set Temperature: ");
terminal.flush();
termlevel=1;}
else if (termi==2){
terminal.println("Range (50-100)");
terminal.println("Set Humidity: ");
terminal.flush();
termlevel=2;}
else if (termi==3){
terminal.println("Range (0-96)");
terminal.println("Set Rotations Per Day: ");
terminal.flush();
termlevel=3;}
else if (termi==4){
terminal.println("Range (0-50)");
terminal.print("Set Days to Rotate: ");
terminal.flush();
termlevel=4;}
else{
termlevel=0;
terminalmenu();
}
break;
case 1:
if (term>=80 && term<=105){
temps=term;
termlevel=0;
terminalmenu();}
else{invalid();}
break;
case 2:
if (term>=0 && term<=100){
humids=term;
termlevel=0;
terminalmenu();}
else{invalid();}
break;
case 3:
if (term>=0 && term<=1200){
rpd=term;
msdelay = 86400000/rpd;
rotatetime=millis()+ msdelay;
termlevel=0;
terminalmenu();}
else{invalid();}
break;
case 4:
if (term>=0 && term<=50){
dtr=term;
termlevel=0;
terminalmenu();}
else{invalid();}
break;
default:
termlevel=0;
terminalmenu();
break;}
rotating=0;}
void invalid(){
termlevel=0;
terminalmenu();
terminal.println("Invalid Input");}
void terminalmenu(){
terminal.println("Blynkubator Settings Menu");
terminal.print("1= Set Temperature: ");
terminal.println(temps);
terminal.print("2= Set Humidity: ");
terminal.println(humids);
terminal.print("3= Set Rotations Per Day: ");
terminal.println(rpd);
terminal.print("4= Set Days to Rotate: ");
terminal.println(dtr);
terminal.print(" *Days Remaining: ");
terminal.println(remain);
terminal.print(" *Rotation Total: ");
terminal.print(turns);
terminal.print(" Next: ");
terminal.print(nextturn);
terminal.println("min");
termlevel=0;
terminal.flush();}
Thank you Blynk for the great app and the help.