You are bought right. When I put it like you said in void loop() it goes on for 1sec and off for 1 sec. And when I put it in NO_ACTION case like cattledog said with your test condition "&& currentState == NO_ACTION"
it wont come out of RELAY_ON and RELAY_OFF loop when time gets to 17 o'clock. Do you want me to post the whole code, or should I remove unessessary stuff for this problem?
Here is the whole code so far:
enum states
{
NO_ACTION,
RELAY_ON,
RELAY_OFF
};
#include <LiquidCrystal.h>
#include <dht.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS3231.h>
DS3231 rtc(SDA, SCL); // Init the DS3231 using the hardware interface
Time t; // Init a Time-data structure
#define dataPin 30 // Defines pin number to which the sensor is connected
dht DHT; // Creats a DHT object
LiquidCrystal lcd(27, 26, 25, 24, 23, 22);
//some global variables available anywhere in the program
int currentState;
unsigned long startTime;
unsigned long currentTime;
const unsigned long relayOnTime = 6000; // period of time relay is ON in ms
const unsigned long relayOffTime = 600000; // period of time relay is OFF in ms
// RELAYS
const int SprinkleRelay = 3; //prskalica1
//const int Sprinkle2Relay = 4; //prskalica2
const int LightsRelay = 5; //svijetlo
const int HeaterRelay =6; //grijač
/*//BUTTONS
const int FeedingButton = 7;
const int HeaterButton = 18;*/
//SENSORS
const int IRSensor = 7;
const int TempSensor = 18;
//LEDS
const int LightsLED = 8;
const int SprinkleLED = 9; //sigPrskalica1
//const int Sprinkle2LED = 10; //sigPrskalica2
//const int FeedingLED = 11; //
const int HeaterLED = 12; //sigGrijač
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // initialize serial communications:
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
//lcd.print("hello, world!"); // Print a message to the LCD.
//INPUTS, OUTPUTS
//pinMode(IRSensor, INPUT);
//pinMode(TempSensor, INPUT);
pinMode(SprinkleRelay, OUTPUT);
pinMode(SprinkleLED, OUTPUT);
//pinMode(Sprinkle2Relay, OUTPUT);
//pinMode(Sprinkle2LED, OUTPUT);
pinMode(LightsRelay, OUTPUT);
pinMode(LightsLED, OUTPUT);
pinMode(HeaterRelay, OUTPUT);
pinMode(HeaterLED, OUTPUT);
//pinMode(FeedingLED, OUTPUT);
//CLOCK SETTING
rtc.begin(); // Initialize the rtc object
// The following lines can be uncommented to set the date and time
//rtc.setDOW(SATURDAY); // Set Day-of-Week to SUNDAY
//rtc.setTime(21, 32, 0); // Set the time to 12:00:00 (24hr format)
//rtc.setDate(28, 12, 2019); // Set the date to DD/MM/YYYY
t = rtc.getTime(); // Get data from the DS3231
if (t.hour >= 9 && t.hour <= 17) {
currentState = RELAY_ON;
startTime = millis(); //initial start time
}else{ currentState = NO_ACTION;
}
}
void loop() {
// put your main code here, to run repeatedly:
currentTime = millis(); // capture the latest value of millis()
DisplayData();
switch (currentState)
{
case NO_ACTION:
//no code to execute
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
DisplayTime();
if (t.hour >= 9 && t.hour <= 17 && currentState == NO_ACTION){
currentState = RELAY_ON;
startTime = millis(); //initial start time
}else{ currentState = NO_ACTION;
}
break;
case RELAY_ON:
digitalWrite(SprinkleRelay, LOW);
digitalWrite(SprinkleLED, HIGH); // Set Sprinkle LED On
Serial.println("Navodnjavanje");
Serial.println("--------------------------------");
lcd.setCursor(0, 1);
lcd.print("Magla jos =");
lcd.setCursor(12, 1);
lcd.print((relayOnTime - (currentTime - startTime)) / 1000);
lcd.print("s");
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOnTime )
{
//do something
currentState = RELAY_OFF;
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
lcd.clear();
}
break;
case RELAY_OFF:
//code here to test whether the relay should still be off
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
Serial.println("Navodnjavanje završeno");
Serial.println("--------------------------------");
lcd.setCursor(0, 1);
lcd.print("Sledeca =");
lcd.setCursor(10, 1);
lcd.print((relayOffTime - (currentTime - startTime)) / 1000);
lcd.print("s");
if (currentTime - startTime >= relayOffTime )
{
//do something
currentState = RELAY_ON;
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
lcd.clear();
}
break;
}
}
void DisplayData() {
int readData = DHT.read11(dataPin); // Reads the data from the sensor
float tmp = DHT.temperature; // Gets the values of the temperature
float hmd = DHT.humidity; // Gets the values of the humidity
// Printing the results on the serial monitor
Serial.print("Temperatura = ");
Serial.print(tmp);
Serial.print(" *C ");
Serial.println();
Serial.print("Vlaznost vazduha = ");
Serial.print(hmd);
Serial.println(" % ");
// LCD display data
lcd.setCursor(0, 0);
lcd.print("tmp=");
lcd.print(tmp, 0); //'float' formatting with 0 digits
lcd.print("*C");
lcd.setCursor(10, 0);
lcd.print("vl=");
lcd.print(hmd, 0);//'float' formatting with 0 digits
lcd.print("%");
delay(2000); // Delays 2 secods, as the DHT11 sampling rate is 0.5Hz
}
void DisplayTime() {
t = rtc.getTime(); // Get data from the DS3231
// Send time date over serial connection
Serial.print("Vrijeme: ");
Serial.print(t.hour, DEC);
Serial.print(":");
Serial.print(t.min, DEC);
Serial.print(":");
Serial.print(t.sec, DEC);
Serial.println();
Serial.print("Datum: ");
Serial.print(t.date, DEC);
Serial.print("/");
Serial.print(t.mon, DEC);
Serial.print("/");
Serial.print(t.year, DEC);
Serial.println();
// Send Day-of-Week and time
Serial.print("Dan u nedjelji: ");
Serial.print(t.dow, DEC);
Serial.println();
Serial.println("--------------------------------");
// LCD Print time and date
lcd.setCursor(0, 1);
if (t.hour < 10)
lcd.print("0");
lcd.print(t.hour, DEC);
lcd.print(":");
if (t.min < 10)
lcd.print("0");
lcd.print(t.min, DEC);
lcd.setCursor(6, 1);
if (t.date < 10)
lcd.print("0");
lcd.print(t.date, DEC);
lcd.print("/");
if (t.mon < 10)
lcd.print("0");
lcd.print(t.mon, DEC);
lcd.print("/");
lcd.print(t.year, DEC);
}
when and if you have time check it all and give me your toughts. And let me know if you need clean code. I mean without librarys and lcd stuff. Thanks!
Thanks for posting complete code. You are correct in that all states need access to the time.
This statement should be at the top of loop().
t = rtc.getTime(); // Get data from the DS3231
I think there are other places, and within functions where you also get the time. It is best to minimize the constant banging on the i2c bus, and keep access to the rtc to a minimum. Access once at the top of loop should cover everything as t is global. There is an alternative architecture using the Time Library and periodic synchronization with the rtc which is more robust, but that issue is for a latter time.
Then the case NO_ACTION should contain this code which will start the relay in the time window.
if (t.hour >= 9 && t.hour <= 17)
{
currentState = RELAY_ON;
}
case RELAY_ON and RELAY_OFF should contain as the following as the last lines in the case before the break statement. This will switch back to NO_ACTION if the time period is not true.
if (t.hour < 9 or t.hour > 17)
{
currentState = NO_ACTION;
}
case RELAY_ON and RELAY_OFF should contain as the following as the last lines in the case before the break statement. This will switch back to NO_ACTION if the time period is not true.
I remember now why I suggested putting the time check and switch to the NO_ACTION state in loop(). Doing it that way allows whatever state the system is in at the time to be terminated immediately and for the system to go into its dormant state
Thank you guys for solutuons. What if:
case RELAY_OFF:
//code here to test whether the relay should still off
if (currentTime - startTime >= relayOffTime )
{
//do something
currentState = NO_ACTION;
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
When in RELAY_OFF state i let it go trough NO_ACTION state instead of back to RELAY_ON state. I think it should still work. And Im gonna try both solutions and let you know what I get. Thanks guys!
This is my final code, and it works just how I wanted.
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // initialize serial communications:
t = rtc.getTime(); // Get data from the DS3231
if (t.hour >= 9 && t.hour < 17) {
currentState = RELAY_ON;
startTime = millis(); //initial start time
}else{ currentState = NO_ACTION;
}
}
void loop() {
// put your main code here, to run repeatedly:
t = rtc.getTime(); // Get data from the DS3231
currentTime = millis(); // capture the latest value of millis()
switch (currentState)
{
case NO_ACTION:
//no code to execute
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
if (t.hour >= 9 && t.hour < 17){
currentState = RELAY_ON;
startTime = millis(); //initial start time
}else{ currentState = NO_ACTION;
}
break;
case RELAY_ON:
digitalWrite(SprinkleRelay, LOW);
digitalWrite(SprinkleLED, HIGH); // Set Sprinkle LED On
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOnTime )
{
//do something
currentState = RELAY_OFF;
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
}
break;
case RELAY_OFF:
//code here to test whether the relay should still be off
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
if (currentTime - startTime >= relayOffTime )
{
//do something
currentState = NO_ACTION;
}
break;
}
}
I moved t = rtc.getTime();
to loop() as cattledog suggested. And it works. Thank you guys one more time, could not make it without you!
OK, it works but I have some comments (no surprise there !)
First, you really don't need to cycle through the 3 states as you are doing, which to my mind is clumsy, simply bounce between the ON and OFF states as you have done previously whilst the system is active. Put the "is it time to go to sleep" test in loop() and if true turn off the relay and set the state to NO_ACTION. In retrospect I wish I had suggested naming it DORMANT. When it comes time to wake up set the state to RELAY_ON, turn on the relay and LED, save startTime and off you go again.
I know that it was my suggestion, but you don't actually need a NO_ACTION state at all if you introduce a boolean that is true when the system is active and false when it is not controlled by the time test in loop(). Wrap the whole switch/case in a test of the boolean to activate/deactivate it
Secondly, although there is no harm in constantly writing to an LED or relay, doing so has always looked clumsy to me when there is no need. What I usually do when using a state machine is to set what I would call the entry position before leaving the previous state. For example in your code I would do
case RELAY_ON:
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOnTime )
{
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_OFF;
}
break;
All of the above comments are more to do with personal preferences and style rather than show stopping problems. The important thing is that you now have more programming ammunition available to you than when you started, and a working program, of course
Don't have anything against your comments. The more you comment better I will get it. Don't wanna be annoying either. I did it in the way I said because I can't get it to work in other way. Sadly I don't know how to use boolean although I would like to use it. I like when code is not messy but my C programing knowledge is poor thats why I mees it up...
I have tried to put it like this, but it just wont work
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // initialize serial communications:
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
//INPUTS, OUTPUTS
//pinMode(IRSensor, INPUT);
//pinMode(TempSensor, INPUT);
pinMode(SprinkleRelay, OUTPUT);
pinMode(SprinkleLED, OUTPUT);
//pinMode(Sprinkle2Relay, OUTPUT);
//pinMode(Sprinkle2LED, OUTPUT);
pinMode(LightsRelay, OUTPUT);
pinMode(LightsLED, OUTPUT);
pinMode(HeaterRelay, OUTPUT);
pinMode(HeaterLED, OUTPUT);
//pinMode(FeedingLED, OUTPUT);
//CLOCK SETTING
rtc.begin(); // Initialize the rtc object
// The following lines can be uncommented to set the date and time
//rtc.setDOW(SATURDAY); // Set Day-of-Week to SUNDAY
//rtc.setTime(11, 27, 3); // Set the time to 12:00:00 (24hr format)
//rtc.setDate(28, 12, 2019); // Set the date to DD/MM/YYYY
t = rtc.getTime(); // Get data from the DS3231
if (t.hour < 9 && t.hour >= 17) {
currentState = DORMANT;
}else{ currentState = RELAY_ON;
startTime = millis(); //initial start time
}
}
void loop() {
// put your main code here, to run repeatedly:
t = rtc.getTime(); // Get data from the DS3231
currentTime = millis(); // capture the latest value of millis()
//DisplayData();
if (t.hour < 9 && t.hour >= 17) {
currentState = DORMANT;
}else{ currentState = RELAY_ON;
startTime = millis(); //initial start time
}
switch (currentState)
{
case DORMANT:
//no code to execute
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
DisplayTime();
break;
case RELAY_ON:
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOnTime )
{
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
lcd.setCursor(0, 1);
lcd.print("Magla jos =");
lcd.setCursor(12, 1);
lcd.print((relayOnTime - (currentTime - startTime)) / 1000);
lcd.print("s");
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_OFF;
lcd.clear();
}
break;
case RELAY_OFF:
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOffTime )
{
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
lcd.setCursor(0, 1);
lcd.print("Sledeca =");
lcd.setCursor(10, 1);
lcd.print((relayOffTime - (currentTime - startTime)) / 1000);
lcd.print("s");
//startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = DORMANT;
lcd.clear();
}
break;
}
}
. I'm gonna google and try to implement boolean into this like you sugested. Thanks!
Can I do it like this?
boolean booleanState = 1;
void loop() {
if (t.hour < 9 && t.hour >= 17) {
booleanState = !booleanState;
}else{currentState = RELAY_ON;
startTime = millis(); //initial start time
}
. Now just somehow to "Wrap the whole switch/case in a test of the boolean to activate/deactivate it"
Here's an example of how to use a boolean control on the switch state and eliminate the DORMANT state. You will not need the time reading and state establishment in setup, as it will be done in loop. There are two new variables
boolean relayEnabled = false;
boolean startingEnabledPeriod = true;
The startingEnabledPeriod is to set up the startTime and State on first entry into the active time period.
Whether you find this more simple or complex than the 3 state approach is TBD.
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // initialize serial communications:
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
//INPUTS, OUTPUTS
//pinMode(IRSensor, INPUT);
//pinMode(TempSensor, INPUT);
pinMode(SprinkleRelay, OUTPUT);
pinMode(SprinkleLED, OUTPUT);
//pinMode(Sprinkle2Relay, OUTPUT);
//pinMode(Sprinkle2LED, OUTPUT);
pinMode(LightsRelay, OUTPUT);
pinMode(LightsLED, OUTPUT);
pinMode(HeaterRelay, OUTPUT);
pinMode(HeaterLED, OUTPUT);
//pinMode(FeedingLED, OUTPUT);
//CLOCK SETTING
rtc.begin(); // Initialize the rtc object
// The following lines can be uncommented to set the date and time
//rtc.setDOW(SATURDAY); // Set Day-of-Week to SUNDAY
//rtc.setTime(11, 27, 3); // Set the time to 12:00:00 (24hr format)
//rtc.setDate(28, 12, 2019); // Set the date to DD/MM/YYYY
//t = rtc.getTime(); // Get data from the DS3231
boolean relayEnabled = false;
boolean startingEnabledPeriod = true;
// if (t.hour < 9 && t.hour >= 17) {
// currentState = DORMANT;
// } else {
// currentState = RELAY_ON;
// startTime = millis(); //initial start time
// }
}
void loop() {
// put your main code here, to run repeatedly:
t = rtc.getTime(); // Get data from the DS3231
currentTime = millis(); // capture the latest value of millis()
//DisplayData();
if (t.hour >= 9 && t.hour <= 17) {
relayEnabled = true;
} else {
relayEnabled = false;
startingEnabledPeriod = true;
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
// DisplayTime();
}
if (relayEnabled)
{
if(startingEnabledPeriod)
{
startingEnabledPeriod = false;
startTime = millis();
currentState = RELAY_ON;
}
switch (currentState)
{
case RELAY_ON:
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOnTime )
{
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
lcd.setCursor(0, 1);
lcd.print("Magla jos =");
lcd.setCursor(12, 1);
lcd.print((relayOnTime - (currentTime - startTime)) / 1000);
lcd.print("s");
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_OFF;
lcd.clear();
}
break;
case RELAY_OFF:
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOffTime )
{
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
lcd.setCursor(0, 1);
lcd.print("Sledeca =");
lcd.setCursor(10, 1);
lcd.print((relayOffTime - (currentTime - startTime)) / 1000);
lcd.print("s");
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_ON;
lcd.clear();
}
break;
}
}
}
Thank you cattledog for this example I will give it a try and let you know about the result. I have to learn about boolean couse it confuses me...
I have to learn about boolean couse it confuses me..
You will slap your forehead when you realise how simple booleans are
A boolean can only have one of 2 values, true or false. What could be simpler
You can test the value of a boolean in the usual way by using ==
if (theBoolean == true)
{
//do stuff
}
Slightly more confusing, but it does the same thing is
if (theBoolean)
{
//do stuff
}
This is much easier to understand if you use a sensible name for the boolean as in cattledog's code
if (relayEnabled)
{
//do stuff
}
Ok I get the boolean now, but for some reason it gets stuck. I used part of the code cattledog suggested with case/state:
enum states
{
DORMANT,
RELAY_ON,
RELAY_OFF
};
boolean relayEnabled = false;
boolean startingEnabledPeriod = true;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // initialize serial communications:
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
}
void loop() {
// put your main code here, to run repeatedly:
t = rtc.getTime(); // Get data from the DS3231
currentTime = millis(); // capture the latest value of millis()
if (t.hour >= 9 && t.hour <= 17) {
relayEnabled = true;
}else{relayEnabled = false;
startingEnabledPeriod = true;
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
DisplayTime();
}
if (relayEnabled){
if(startingEnabledPeriod){
startingEnabledPeriod = false;
startTime = millis();
currentState = RELAY_ON;
}
switch (currentState)
{
case RELAY_ON:
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOnTime )
{
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
lcd.setCursor(0, 1);
lcd.print("Magla jos =");
lcd.setCursor(12, 1);
lcd.print((relayOnTime - (currentTime - startTime)) / 1000);
lcd.print("s");
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_OFF;
lcd.clear();
}
break;
case RELAY_OFF:
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOffTime )
{
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
lcd.setCursor(0, 1);
lcd.print("Sledeca =");
lcd.setCursor(10, 1);
lcd.print((relayOffTime - (currentTime - startTime)) / 1000);
lcd.print("s");
//startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_ON;
lcd.clear();
}
break;
}
}
}
void DisplayData() {
int readData = DHT.read11(dataPin); // Reads the data from the sensor
float tmp = DHT.temperature; // Gets the values of the temperature
float hmd = DHT.humidity; // Gets the values of the humidity
// LCD display data
lcd.setCursor(0, 0);
lcd.print("tmp=");
lcd.print(tmp, 0); //'float' formatting with 0 digits
lcd.print("*C");
lcd.setCursor(10, 0);
lcd.print("vl=");
lcd.print(hmd, 0);//'float' formatting with 0 digits
lcd.print("%");
delay(2000); // Delays 2 secods, as the DHT11 sampling rate is 0.5Hz
}
void DisplayTime() {
// LCD Print time and date
lcd.setCursor(0, 1);
if (t.hour < 10)
lcd.print("0");
lcd.print(t.hour, DEC);
lcd.print(":");
if (t.min < 10)
lcd.print("0");
lcd.print(t.min, DEC);
lcd.setCursor(6, 1);
if (t.date < 10)
lcd.print("0");
lcd.print(t.date, DEC);
lcd.print("/");
if (t.mon < 10)
lcd.print("0");
lcd.print(t.mon, DEC);
lcd.print("/");
lcd.print(t.year, DEC);
}
it gets stuck at
if(startingEnabledPeriod){//here stuck, never trigers RELAY_ON state
startingEnabledPeriod = false;
startTime = millis();
currentState = RELAY_ON;
}
never trigers RELAY_ON state for some reason
Print the value of relayEnabled and startingEnabledPeriod immediately before this
if (relayEnabled)
{
if (startingEnabledPeriod)
{
I suggest that you print a text label for each so that you can distinguish them. You will get 0 if the boolean is false and 1 if it is true. What do you see ?
I get "1010101010101010..." few seconds, than nothing few seconds, than again "1010101010101010..." and soo on, when I put Serial.print(relayEnabled); and Serial.print(startingEnabledPeriod);
Serial.print(relayEnabled);
Serial.print(startingEnabledPeriod);
if (relayEnabled){
if(startingEnabledPeriod){
startingEnabledPeriod = false;
startTime = millis();
currentState = RELAY_ON;
}
On a serial monitor.
Sorry guys I messed it up with digitalWrite(SprinkleRelay, HIGH); instead of digitalWrite(SprinkleRelay, LOW); It works, Thanks!
Here is final code for now.
enum states
{
RELAY_ON,
RELAY_OFF
};
#include <LiquidCrystal.h>
#include <dht.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS3231.h>
DS3231 rtc(SDA, SCL); // Init the DS3231 using the hardware interface
Time t; // Init a Time-data structure
#define dataPin 30 // Defines pin number to which the sensor is connected
dht DHT; // Creats a DHT object
LiquidCrystal lcd(27, 26, 25, 24, 23, 22);
//temperature sensor
#define RT0 10000 // Ω
#define B 3977 // K
#define VCC 5 //Supply voltage
#define R 9900 //R=10KΩ
//some global temperature variables
float RT, VR, ln, TX, T0, VRT;
boolean relayEnabled = false;
boolean startingEnabledPeriod = true;
//some global time variables available anywhere in the program
int currentState;
unsigned long startTime;
unsigned long currentTime;
const unsigned long relayOnTime = 6000; // period of time relay is ON in ms
const unsigned long relayOffTime = 900000; // period of time relay is OFF in ms
// RELAYS
const int SprinkleRelay = 3; //prskalica1
//const int Sprinkle2Relay = 4; //prskalica2
const int LightsRelay = 5; //svijetlo
const int HeaterRelay =6; //grijač
/*//BUTTONS
const int FeedingButton = 7;
const int HeaterButton = 18;*/
//LEDS
const int LightsLED = 8;
const int SprinkleLED = 9; //sigPrskalica1
//const int Sprinkle2LED = 10; //sigPrskalica2
const int HeaterLED = 12; //sigGrijač
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // initialize serial communications:
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
//Temperature T0 from datasheet, conversion from Celsius to kelvin
T0 = 25 + 273.15;
//OUTPUTS
pinMode(SprinkleRelay, OUTPUT);
pinMode(SprinkleLED, OUTPUT);
//pinMode(Sprinkle2Relay, OUTPUT);
//pinMode(Sprinkle2LED, OUTPUT);
pinMode(LightsRelay, OUTPUT);
pinMode(LightsLED, OUTPUT);
pinMode(HeaterRelay, OUTPUT);
pinMode(HeaterLED, OUTPUT);
//CLOCK SETTING
rtc.begin(); // Initialize the rtc object
// The following lines can be uncommented to set the date and time
//rtc.setDOW(SATURDAY); // Set Day-of-Week to SUNDAY
//rtc.setTime(12, 46, 3); // Set the time to 12:00:00 (24hr format)
//rtc.setDate(28, 12, 2019); // Set the date to DD/MM/YYYY
}
void loop() {
// put your main code here, to run repeatedly:
//Temperature calculations
VRT = analogRead(A0); //Acquisition analog value of VRT
VRT = (5.00 / 1023.00) * VRT; //Conversion to voltage
VR = VCC - VRT;
RT = VRT / (VR / R); //Resistance of RT
ln = log(RT / RT0);
TX = (1 / ((ln / B) + (1 / T0))); //Temperature from thermistor
TX = TX - 273.15; //Conversion to Celsius
DisplayTemp();
// Get data from the DS3231
t = rtc.getTime();
currentTime = millis(); // capture the latest value of millis()
if (t.hour >= 9 && t.hour < 20) {
relayEnabled = true;
}else{relayEnabled = false;
startingEnabledPeriod = true;
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
DisplayTime();
DisplayDate();
}
if (relayEnabled){
if(startingEnabledPeriod){
startingEnabledPeriod = false;
startTime = millis();
currentState = RELAY_ON;
}
switch (currentState)
{
case RELAY_ON:
CountdownON();
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOnTime ){
//prepare for the target state
digitalWrite(SprinkleRelay, HIGH);
digitalWrite(SprinkleLED, LOW); // Set Sprinkle LED Off
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_OFF;
}
break;
case RELAY_OFF:
CountdownOFF();
//code here to test whether the relay should still be on
if (currentTime - startTime >= relayOffTime ){ //prepare for the target state
digitalWrite(SprinkleRelay, LOW);
digitalWrite(SprinkleLED, HIGH); // Set Sprinkle LED Off
startTime = currentTime; //IMPORTANT to save the start time of the current RELAY state.
currentState = RELAY_ON;
}
break;
}
}
}
void DisplayTemp() {
lcd.setCursor(0, 0);
lcd.print("T=");
lcd.print(TX);
lcd.print("C");
if (TX <= 23) {
digitalWrite(HeaterRelay, LOW);
digitalWrite(HeaterLED, LOW);
lcd.setCursor(10, 0);
lcd.print("Gr=(*)");
}else{
digitalWrite(HeaterRelay, HIGH);
digitalWrite(HeaterLED, HIGH);
lcd.setCursor(10,0);
lcd.print("Gr=( )");
}
}
void DisplayTime() {
// LCD Print time
lcd.setCursor(0, 1);
if (t.hour < 10)
lcd.print("0");
lcd.print(t.hour, DEC);
lcd.print(":");
if (t.min < 10)
lcd.print("0");
lcd.print(t.min, DEC);
}
void DisplayDate() {
// LCD Print date
lcd.setCursor(6, 1);
if (t.date < 10)
lcd.print("0");
lcd.print(t.date, DEC);
lcd.print("/");
if (t.mon < 10)
lcd.print("0");
lcd.print(t.mon, DEC);
lcd.print("/");
lcd.print(t.year, DEC);
}
void CountdownON() {
//LCD countdown
lcd.setCursor(6, 1);
lcd.print("Pr(*)= ");
lcd.print((relayOnTime - (currentTime - startTime)) / 1000);
lcd.print("s");
DisplayTime();
}
void CountdownOFF() {
//LCD countdown
lcd.setCursor(6, 1);
lcd.print("Pr( )=");
lcd.print((relayOffTime - (currentTime - startTime)) / 1000);
lcd.print("s");
DisplayTime();
}
Suggestions are welcome!
// RELAYS
const int SprinkleRelay = 3; //prskalica1
//const int Sprinkle2Relay = 4; //prskalica2
const int LightsRelay = 5; //svijetlo
const int HeaterRelay = 6; //grijač
/*//BUTTONS
const int FeedingButton = 7;
const int HeaterButton = 18;*/
//LEDS
const int LightsLED = 8;
const int SprinkleLED = 9; //sigPrskalica1
//const int Sprinkle2LED = 10; //sigPrskalica2
const int HeaterLED = 12; //sigGrijač
A minor point, but none of these need to be ints. byte would do just fine and would save a little memory. Not important here but one day it might be.
A more obscure suggestion. Instead of
int currentState;
if you use
states currentState;
then the compiler will warn you if you do not use all of the members of the enum. Again, not a problem here but useful to know
Changed it. Thank you for all you'r good advices. Gonna miss solutions and great explanations of every part of code. Thanks, can't wait new projects.