// Define globals
const float VCC = 3.3; // ESP32 supply voltage
const int ADC_MAX = 4095; // 12-bit ADC resolution
// Thermal sensor variables
const float THERM_R0 = 78000.0; // Thermistor resistance at T0 (e.g., 10kΩ)
const float THERM_T = 298.15; // T0 in Kelvin (25°C + 273.15)
const float THERM_B_VALUE = 4100.0; // Thermistor's Beta value (from datasheet)
const float THERM_SERIES_RESISTOR = 50000; // Fixed resistor value
//
const int PIN_THERM = 34; // ADC pin for thermal sensor/diode / analog input
const int PIN_MOISTURE = 35; // ADC pin for moisture sensor / analog input
const int PIN_PUMP = 25; // water pump / digital output
const int PIN_ESTUFA = 23;
const int PIN_LED = 27;
const int PIN_FAN = 26;
//
int ct = 0; // current time in seconds
int dct = 0;
int ctDay = 3600*24; // seconds of day
int curDay = 0; // 0 = day1, 1=day2... until 6=day7 and repeat to 0
int cntDay = 0, chkDay=0;
int delayValue = 50; // sleep of main loop 20-1000ms
// statistic counting variables
int cnt = 0;
int cnt_delay = 0;
int cnt_loop = 0;
int pos=0;
//
int cntFailTemp = 0;
int cntOkTemp = 0;
//
int heat_start = false;
int heat_done = false;
int heat_count = 0;
int heat_last = 0; // ct
//
int fan_start = false;
int fan_done = false;
int fan_count = 0;
int fan_last = 0;
//
time_t currentTime;
struct tm timeinfo;
//
struct FanRun {
int timeON = 0;
int timeOFF = 0;
int ct_start = -1;
//bool start = false;
//bool done = false;
//int count = 0;
};
struct FanRun afr[10];
//
struct Days {
int dayHours = 18; // hours of light per day
int dayTemperature = 28; // celsious at day
int nightTemperature = 25; // celsious at night
};
struct Days timetable[6]; // time table for 7days in a week
//--
//
void get_moisture() {
int val = analogRead(PIN_MOISTURE);
Serial.print("Moisture val: ");
Serial.println(val);
}
//
float get_thermal() {
Serial.println("get_thermal() START.");
int val = analogRead(PIN_THERM);
// 1. Calculate Voltage at ADC Pin (Vout)
float vout = (float)val * (VCC / ADC_MAX);
// 2. Calculate Thermistor Resistance (Rth) using Voltage Divider
// Rth = R_series * (Vout / (VCC - Vout))
float r_th = THERM_SERIES_RESISTOR * (vout / (VCC - vout));
// 3. Calculate Temperature (Kelvin) using Beta Equation
// 1/T = 1/T0 + (1/B) * ln(Rth/R0)
float temp_kelvin = 1.0 / ((1.0 / THERM_T) - (1.0 / THERM_B_VALUE) * log(r_th / THERM_R0));
// 4. Convert Kelvin to Celsius
float temp_celsius = temp_kelvin - 273.15;
char debug[256];
sprintf(debug,"DEBUG get_thermal() ADC: %i, vout: %.1f, rth: %.1f, tk: %.1f tc: %.1f",val, vout, r_th, temp_kelvin, temp_celsius);
Serial.println(debug);
return temp_celsius;
}
//
void fan_on(int timeON, int timeOFF) {
Serial.println("fan_on() START.");
//
if( fan_count==0 ) {
// Turn fan on
Serial.println("Turn fan on for Xsec");
fan_count = ct+timeON;
fan_start = true;
fan_done = false;
digitalWrite(PIN_FAN,LOW);
}
else if( fan_count < 0 ) {
Serial.println("Waiting for fan...");
if( cnt_delay>=1000) fan_count++;
}
else if( fan_count > ct ) {
Serial.println("Waiting for fan to turn it off...");
}
else if( fan_count <= ct && fan_done==false ) {
Serial.println("Turning off fan...");
fan_off();
}
else if( ct >= fan_count ) {
// Turn fan off
Serial.println("Setting Turn fan off for Xsec");
fan_count = timeOFF;
}
}
//
void fan_off() {
Serial.println("fan_off() START.");
fan_done = true;
fan_start = false;
fan_count = 0;
fan_last = ct;
digitalWrite(PIN_FAN,HIGH);
}
//
void heat_on(int timeON, int timeOFF) {
Serial.println("heat_on() START.");
//
if( heat_count==0 ) {
// Turn fan on
Serial.println("Turn heat on for Xsec");
heat_count = ct+timeON;
heat_start = true;
heat_done = false;
digitalWrite(PIN_ESTUFA,LOW);
}
else if( heat_count < 0 ) {
Serial.println("Waiting for heat...");
if( cnt_delay>=1000) heat_count++;
}
else if( heat_count > ct ) {
Serial.println("Waiting for heat to turn it off...");
}
else if( heat_count <= ct && heat_done==false ) {
Serial.println("Turning off heat...");
heat_off();
}
else if( ct >= heat_count ) {
// Turn heat off
Serial.println("Setting Turn heat off for Xsec");
heat_count = timeOFF;
}
}
//
void heat_off() {
Serial.println("heat_off() START.");
heat_done = true;
heat_start = false;
heat_count = 0;
heat_last = ct;
digitalWrite(PIN_ESTUFA,HIGH);
}
//
void heating_on() {
Serial.println("heating_on() START.");
heat_on(100,-100);
if( (fan_last+3)<ct ) {
fan_on(2,-3);
}
}
//
void heating_off() {
Serial.println("heating_off() START.");
if( !heat_done ) {
heat_off();
}
if( !fan_done ) {
fan_off();
}
}
//
void light_on() {
Serial.println("light_on() START.");
digitalWrite(PIN_LED,LOW);
}
//
void light_off() {
Serial.println("light_off() START.");
digitalWrite(PIN_LED,HIGH);
}
//
void set_time(time_t configTime) {
//
dct = (int)configTime;
// Convert struct tm to time_t
time_t epoch = configTime;
// Create struct timeval from time_t
struct timeval tv;
tv.tv_sec = epoch;
tv.tv_usec = 0; // Microseconds (0-999999)
// Set the system time
int result = settimeofday(&tv, NULL);
if (result == 0) {
Serial.println("Time set successfully");
} else {
Serial.println("Failed to set time");
}
}
// Configure setup
void setup() {
delay(500);
//
Serial.begin(115200);
//--
//
pinMode(PIN_FAN,OUTPUT); // led
digitalWrite(PIN_FAN,HIGH); // off
// Light LED
pinMode(PIN_LED,OUTPUT);
digitalWrite(PIN_LED,HIGH);
// WATER PUMP - off
pinMode(PIN_PUMP,OUTPUT);
digitalWrite(PIN_PUMP,HIGH);
// ESTUFA - HEATER
pinMode(PIN_ESTUFA,OUTPUT);
digitalWrite(PIN_ESTUFA,HIGH); // HIGH = Off for Relay
//digitalWrite(PIN_ESTUFA,LOW);
// MOISTURE SensOr - problem!
/*analogWrite(32,500);
pinMode(32,OUTPUT); // led
digitalWrite(32,LOW); // off*/
// Define timetable for a week
timetable[0] = (Days){18,28,25};
timetable[1] = (Days){18,28,25};
timetable[2] = (Days){18,28,25};
timetable[3] = (Days){18,28,25};
timetable[4] = (Days){18,28,25};
timetable[5] = (Days){18,28,25};
timetable[6] = (Days){18,28,25};
// start_ts, start, done
afr[0] = (FanRun){10, false, false};
set_time(6780);
}
// Program loop
void loop() {
// Get current time as seconds since the Unix epoch (January 1, 1970)
//time_t currentTime = time(nullptr); // Note: nullptr is valid in Arduino for C++11+
currentTime = time(¤tTime); // Note: nullptr is valid in Arduino for C++11+
ct = currentTime;
cntDay = (ct/ctDay);
// reset current time to zerro after day 7 is finished
if( curDay>6 ) {
Serial.println("Weekend is over. Roots should be out...");
curDay = 0;
}
if( chkDay!=cntDay) {
chkDay=cntDay;
curDay++;
dct=0;
}
//
Days ttable = timetable[curDay];
// Print by second
if( cnt_delay==1000 ) {
// calculate secunds of light per day depend on dayHours
int sol = (60*60)*ttable.dayHours; // 60sec * 60sec = 1hour of sec * dayHours
int dtemp = ttable.dayTemperature;
int ntemp = ttable.nightTemperature;
// day ct. Useful for days 2-7
//int dct = (curDay * ctDay)-ct;
//int dct = ct;
//if( curDay>0 ) dct = ((curDay+1) * ctDay)-ct;
// Convert to local time
struct tm *timeInfo = localtime(¤tTime);
// Format the timestamp
char buffer[64];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo);
Serial.println(buffer);
Serial.println(currentTime);
//
float temp = get_thermal();
// DEBUG
char tmp[256];
sprintf(tmp,"Loop cft: %i, cd: %i, sol: %i, t: %.1f/%i/%i, dct: %i, ct: %i, pos: %i, cnt: %i, cnt_loop: %i", cntFailTemp, curDay, sol, temp,dtemp,ntemp, dct, ct, pos, cnt, cnt_loop);
Serial.println(tmp);
// CHECK SOL
if( dct<sol ) { // Should be LIGHT
//
light_on();
//
if( temp < dtemp ) { // START HEAT
if( cntFailTemp>= 5 ) {
// start heat
cntOkTemp=0;
heating_on();
}
cntFailTemp++;
}
else {
if( cntOkTemp >= 5 ) {
// stop heat
cntFailTemp = 0;
if( !heat_done ) {
heating_off();
}
}
else if( cntFailTemp>0 ) {
heating_on();
}
//}
cntOkTemp++;
}
}
else { // Should be NIGHT
//
light_off();
//
if( temp < ntemp ) { // START HEAT
if( cntFailTemp>= 5 ) {
// start heat
cntOkTemp=0;
heating_on();
}
cntFailTemp++;
}
else {
if( cntOkTemp >= 5 ) {
// stop heat
cntFailTemp = 0;
if( !heat_done ) {
heating_off();
}
}
else if( cntFailTemp>0 ) {
heating_on();
}
//}
cntOkTemp++;
}
}
}
// Reset cnd on 25 or X
if( cnt==(1000/delayValue) ) {
pos+=1;
cnt=0;
cnt_loop=0;
}
// Count cnt every second. Important variables: cnt_delay and delayValue
if( cnt_delay>= 1000 ) {
cnt_delay = 0;
cnt += 1;
dct++;
}
//
cnt_delay += delayValue;
cnt_loop+=1;
//
delay(delayValue);
}