/* Aquarium Add Water With Display And Buttons. - Version 2
Arduino Uno + HC-SR04 + DHT-11 + 1x Relay + 3x Float Sensor's + 3x LED's + 20x4 LCD + 3x Buttons + 1x Jumper.
Add water timeout:
The system will not add water until ADD_WATER_TIMEOUT_MINUTES (20.minutes) pass after it powers up,
or after ADD_WATER_TIMEOUT_MINUTES pass if high water level warning is on for more than 1 minute,
it starts to count down after high water level warning goes away.
Its so the tank has time to equalise, when the pump starts then it needs to pump the sump almost dry before
the aquarium starts the siphon and sends all the excess water back to the sump, and in the meantime we dont
want to start adding more water to the sump, then it will be overfull. This takes about 10-15.min.
Holding tank has a 3x float sensor's.
Aquarium has 1x HC-SR04 ultrasonic sensor with DHT-11 hum/temp sensor.
3x LED's for water level status in the holding tank.
The red LED will start to blink it the tank is empty, and wont stop untill tank gets 50% water.
The red LED will indicade the status of the pump protection, blink = pump protection is activated.
Jumper:
Jumper On = Add water pump protection OFF, Jumper Off = Add water pump protection ON.
Virtual jumper is true = Add water pump protection OFF, Virtual jumper is false = Add water pump protection ON.
There is a physical jumper in the circuit and virtual jumper in the code.
Holding_Water_Tank_Function() controls that protection if its on (Jumper off),
so the pump wont turn on/off constantly when the tank is almost empty.
This bool > Add_Water_Pump_Okay
The thought behind that jumper is to be able to connect solenoid valve to the system and skip the holding water tank.
Add's water from holding tank or *water solenoid to a aquarium.
Jumper needs to be ON, or pump protection OFF in menu (Virtual jumper = true).
NOTE: Physical jumper is NOT IN USE ! He was turing the pump protection off sometimes when tank was empty.
Display shows:
Water level, Estimated holding tank level, And if the add water pump protection is on or off.
System Info line (first line) will show:
If there is error with the HC-SR04 sensor.
If the add water is on timeout. (When the system wants to add water)
If adding water is in count down.
If the system is adding water.
Buttons: 3x
1x Plus button, 1x Minus button and 1x Ok / Menu button.
In menu you can:
Set the height from sensor to sump tanks botton.
Set the height from sensor to MAX water level.
Set the aquarium percent of the sump tank when the system is powered on.
Set the virtual jumper. (On / Off) < Too turn of the Add Water Pump protection.
Add water on at X percent. (Default is 95.0.%)
Turn off the add water timeout (the system might turn it back on). < Not stored in EEPROM
** All values set by buttons are stored in EEPROM
NOTE: When the menu is entered and add water is on, the relay will be turned off
and back on when the menu is exited and percentage is okay. "(percentage <= (ADD_WATER_OFF - 2.0F))"
*/
// Version
#define AQUARIUM_ADD_WATER_VERSION (F("2.0.0")) // Version
// Serial Print On / Off
const bool Serial_Print = false; // Serial Print false = Off
//const bool Serial_Print = true; // Serial Print true = On
// Libraries
#include <DHT.h> // DHT Sensor - For HC-SR04 Sensor
#include <NewPing.h> // HC-SR04 Ultrasonic Sensor Library
#include <LiquidCrystal_I2C.h> // LCD Library
#include <EEPROM.h> // Eeprom Library
// Local Libraries
#include "Pins.h" // Pins
#include "Variables.h" // Variables
#include "Uptime.h"
/*// Set The Eeprom < Only For One Time Use !
void set_The_EEPROM() { // Set The Eeprom < Only For One Time Use !
EEPROM.put(HEIGHT_TO_SENSOR_ADD, 63); // Store The Height To Sensor Value
EEPROM.put(MAX_WATER_HEIGHT_ADD, 28); // Store The Max Water Height Value
EEPROM.put(AQUARIUM_PCT_ADD, 20); // Store The Aquarium Percent Value
EEPROM.put(VIRTUAL_JUMPER_ADD, false); // Store The Virtual Jumper Value
EEPROM.put(ADD_WATER_ON_ADD, 95.0F); // Store The Add Water On
} // */
void set_Simulator_Value() { // For The Simulator
height_TO_SENSOR = 63; // Read The Height From Sensor Too Bottom Of The Tank. - X.cm
max_WATER_HEIGHT = 28; // Read The Height From Sensor Too Max Water level. - X.cm
aquarium_PCT = 20; // Read The Aquarium Percent Of The Sump Tank. - X.%
virtual_Jumper = false; // Read The Virtual Jumper Status - For Add Water Pump Protection
add_WATER_ON = 95.0F; // Get The Add Water On - X.%
}
void setup() { // Main Setup
// Start The Serial
if (Serial_Print) { // Start The Serial
Serial.begin(115200); // Start The Serial @ Baud Rate
delay(200UL); // Wait For Serial To Wake Up
Serial.println(F("Automatic Aquarium Add Water System.")); // Serial Print
Serial.print(F("Verison: ")); // Serial Print
Serial.println(AQUARIUM_ADD_WATER_VERSION); // Serial Print
Serial.print(F("\n")); // Serial Print
}
else { // For Simulator Testing
Serial.begin(115200); // Start The Serial @ Baud Rate
delay(200UL); // Wait For Serial To Wake Up
}
// LCD Display
LCD_Setup(); // LCD Display Setup
// Buttons
pinMode(PLUS_BUTTON_PIN, INPUT_PULLUP); // Plus Button Pin - Input With Pullup
pinMode(MINUS_BUTTON_PIN, INPUT_PULLUP); // Minus Button Pin - Input With Pullup
pinMode(OK_BUTTON_PIN, INPUT_PULLUP); // Ok Button Pin - Input With Pullup
// Relay
pinMode(ADD_WATER_PIN, OUTPUT); // Add Water Relay - Output
digitalWrite(ADD_WATER_PIN, OFF); // Add Water Relay - OFF
// LED's
pinMode(HOLD_WATER_RED_PIN, OUTPUT); // Red LED
pinMode(HOLD_WATER_GREEN_PIN, OUTPUT); // Green LED
pinMode(HOLD_WATER_BLUE_PIN, OUTPUT); // Blue LED
digitalWrite(HOLD_WATER_RED_PIN, HIGH); // Red LED ON
digitalWrite(HOLD_WATER_GREEN_PIN, HIGH); // Green LED ON
digitalWrite(HOLD_WATER_BLUE_PIN, HIGH); // Blue LED ON
// Float Sensor's
pinMode(LOWEST_FLOAT_SENSOR_PIN, INPUT); // Float Sensor Lowest
pinMode(MIDDLE_FLOAT_SENSOR_PIN, INPUT); // Float Sensor Middle
pinMode(HIGHEST_FLOAT_SENSOR_PIN, INPUT); // Float Sensor Highest
// DHT Sensor
dht_HCSR04.begin(); // Start The DHT-11 Sensor For HC-SR04
// Delay For LED's Test
delay(2000UL); // Delay For LED's Test
// Get All The Values From The Eeprom
set_Simulator_Value(); // For The Simulator
/*//set_The_EEPROM(); // Set The Eeprom - Done !
height_TO_SENSOR = EEPROM.read(HEIGHT_TO_SENSOR_ADD);// Read The Height From Sensor Too Bottom Of The Tank. - X.cm
max_WATER_HEIGHT = EEPROM.read(MAX_WATER_HEIGHT_ADD);// Read The Height From Sensor Too Max Water level. - X.cm
aquarium_PCT = EEPROM.read(AQUARIUM_PCT_ADD); // Read The Aquarium Percent Of The Sump Tank. - X.%
virtual_Jumper = EEPROM.read(VIRTUAL_JUMPER_ADD); // Read The Virtual Jumper Status - For Add Water Pump Protection
EEPROM.get(ADD_WATER_ON_ADD, add_WATER_ON); // Get The Add Water On - X.%
*/
// Set The MAX Water Height And Offset The Sensor
max_Water_Level = (float)height_TO_SENSOR - ((float)max_WATER_HEIGHT + HCSR_OFFSET); // Set The MAX Water Height And Offset The Sensor
// Set The Add Water Startup Timeout
Set_The_Add_Water_Timeout_Function(); // Set The Add Water Timeout
// Serial Print
if (Serial_Print) { // Serial Print Tank Settings
Serial.print(F("Height From Sensor Too Bottom Of The Tank: "));
Serial.print(height_TO_SENSOR); Serial.println(F(".cm"));
Serial.print(F("Height From Sensor Too Max Water level: "));
Serial.print(max_WATER_HEIGHT); Serial.println(F(".cm"));
Serial.print(F("Aquarium Percent Of The Sump Tank: "));
Serial.print(aquarium_PCT); Serial.println(F(".%"));
Serial.print(F("Max Water Level In The Tank: "));
Serial.print(max_Water_Level, 1); Serial.println(F(".cm\n"));
}
// Clear The Display
lcd.clear(); // Clear The Display
}
void loop() { // Main Loop
// Main Loop
Water_Level_Function(); // Water Level Function
//LCD_Print_Function(); // LCD Print Function < In Water_Level_Function & Button_Menu_Function
//Button_Menu_Function(); // Buttons Menu Function
//Uptime_Function(); // Uptime Function
}
// Test
void HC_SR04_Test() {
// HC-SR04 Test Function
if (millis() - Water_Level_Wait >= WATER_LEVEL_WAIT_TIME) {
// Function Timer's
const uint32_t _STARTMILLIS = millis(); // Start Millis Time
uint32_t stopMillis = 0UL; // Stop Millis Time
uint8_t _delayCount = 0;
float _ping = hc_SR04.ping(); // Ping Variable
// HC-SR04 - Error
if (_ping == 0.0F) { // HC-SR04 Sensor - Error
Serial.println(F("HC-SR04 - Error."));
}
// HC-SR04 - Okay
else { // HC-SR04 Sensor - Okay
// Calculate The Speed Of Sound
hum = dht_HCSR04.readHumidity(); // Get The Humidity
temp = dht_HCSR04.readTemperature(); // Get The Temperature
const float _SOUNDSP = 331.4F + (0.606F * temp) + (0.0124F * hum); // Calculate the Speed of Sound in M/S
const float _SOUNDCM = _SOUNDSP / 10000.0F; // Convert to cm/ms
/*// Get The Ping
_ping = 0.0F; // Reset The Ping Variable
for (uint8_t i = 1; i <= NUMREADING; i++) { // Get The Ping
HCSR04_delay(29UL); // Delay Between Ping's
//delay(29UL); // Delay Between Ping's
_delayCount++;
//_ping += (hc_SR04.ping_median(NUMREADING / 2) / 2.0F) * _SOUNDCM; // Ping: NUMREADING * (NUMREADING / 2) = 510.ms
_ping += (hc_SR04.ping() / 2.0F) * _SOUNDCM; // Ping In cm
}//*/ // 50.8.cm & 45.8.%
// Get The Ping
_ping = 0.0F; // Reset The Ping Variable
uint16_t _rawPing = 0U; // Raw Ping Variable
uint8_t _rawPingCount = 0; // Count How Often We Have Pinged For Timeout
uint8_t _successfulPingCount = 0; // Successful Ping Counter
while (_successfulPingCount < NUMREADING) { // Get The Ping X Times
HCSR04_delay(29UL); // Delay Between Ping's
//delay(29UL); // Delay Between Ping's
_delayCount++; // For TEST
_rawPingCount++; // Add To: Raw Ping Count
_rawPing = hc_SR04.ping(); // Raw Ping In Microseconds
if (_rawPing > 0) { // We Got A Value
_ping += (_rawPing / 2.0F) * _SOUNDCM; // Add To: Ping In cm
_successfulPingCount++; // Add To: Successful Ping Count
}
if (_rawPingCount >= NUMREADING + 3) { // Allow 3x Fails Attempt Before Timeout
if (Serial_Print) Serial.println(F("Ping Timeout..")); // Serial Print
break; // Break The While Function
}
} // float: 50.8.cm & 45.8.% - uint16_t: 50.8.cm & 45.8.%
Serial.print("_successfulPingCount: "); Serial.println(_successfulPingCount); // = 6 < er 6 // */
// Average The Ping
const float _DISTANCE = _ping / _successfulPingCount; // Calculate The Distance In cm
// Calculate The Water Level Percentage
percentage = ((max_Water_Level - (_DISTANCE - (float)max_WATER_HEIGHT)) / max_Water_Level * 100.0F) + (float)aquarium_PCT; // Calculate The Water Level Percentage
percentage = constrain(percentage, 0.0F, 200.0F); // Keep The Value In Range
stopMillis = millis(); // Stop Millis Time
// Serial Print
Serial.print(F("Distance: "));
Serial.print(_DISTANCE, 1);
Serial.println(F(".cm"));
Serial.print(F("Percentage: "));
Serial.print(percentage, 1);
Serial.println(F(".%"));
Serial.print(F("Delay Count: ")); Serial.println(_delayCount);
}
Serial.print("Millis: "); Serial.println(stopMillis - _STARTMILLIS); // Function Run Time
Water_Level_Wait = millis(); // Keep Track Of The Time
}
}
void HCSR04_delay(uint32_t ms) { // Delay For HC-SR04
// Special Delay So The Button Will Be Monitored
if (ms == 0UL) return;
uint32_t start = micros();
while (ms > 0UL) {
yield();
Button_Menu_Function(); // Monitor The Menu Button
while (ms > 0UL && (micros() - start) >= 1000UL) {
ms--;
start += 1000UL;
Button_Menu_Function(); // Monitor The Menu Button
}
}
}
uint16_t ping_Median(uint8_t it) { // Multiple pings, discard out of range pings and return median in microseconds.
// Variables
const uint16_t _MAXECHOTIME = 28528U; // The maximum distance in uS.
const uint16_t _NO_ECHO = 0U; // Value returned if there's no ping echo
uint16_t uS[it], last; // uint16_t Variables
uint8_t j, i = 0; // uint8_t Variables
uS[0] = _NO_ECHO; // Set The Value
// Get The Pings
while (i < it) { // Get The Pings
Button_Menu_Function(); // Monitor The Menu Button
last = hc_SR04.ping(); // Send ping.
if (last == _NO_ECHO) { // Ping out of range.
it--; // Skip, don't include as part of median.
last = _MAXECHOTIME; // Adjust "last" variable so delay is correct length.
}
else { // Ping in range, include as part of median.
if (i > 0) { // Don't start sort till second ping.
for (j = i; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop.
uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion.
}
else j = 0; // First ping is starting point for sort.
uS[j] = last; // Add last ping to array in sorted position.
i++; // Move to next ping.
}
if (i < it) HCSR04_delay(29UL - (last >> 10U)); // Millisecond delay between pings.
}
return (uS[it >> 1]); // Return the ping distance median.
}
void Add_Water_Timeout_Function() { // Add Water Timeout Function
// Timeout Is On
if (Add_Water_Timeout_State == true) { // Timeout Is On
if (millis() - Add_Water_Timeout_Wait >= ADD_WATER_TIMEOUT_TIME) { // Wait For The Timeout Time
Add_Water_Timeout_State = false; // Bool For Add Water Timeout
if (Add_Water_State == ON) { // We Are Waiting After Timeout To Add Water
digitalWrite(ADD_WATER_PIN, ON); // Turn ON Add Water Relay
if (Serial_Print) Serial.println(F("Timeout Done - Turn On Add Water Relay.")); // Serial Print
}
}
// Print - The Timeout Is On, And The System Wants To Add Water
if (Add_Water_State == ON && Add_Water_Timeout_State) { // If Add Water Relay Should Be ON
if (Serial_Print) Serial.println(F("Add Water Is On Timeout.")); // Serial Print
}
}
}
void Set_The_Add_Water_Timeout_Function() { // Set The Add Water Timeout Function
// When The System Powers On Or The Water Level Goes Over High Water Alert
Add_Water_Timeout_Wait = millis(); // Keep Track Of The Time
Add_Water_Timeout_State = true; // Bool For Add Water Timeout
// Timeout Turns Off In Add_Water_Timeout_Function
}
void Holding_Water_Tank_Function() { // Holding Water Tank Function
// Holding Water Tank Level.
// Bool:
// "Add_Water_Pump_Okay = false" = Add Water Pump is OFF until Holding Water Tank gets 50% water or more.
// Float Sensor's Connection:
// Common = VCC ( With 1.k between )
// Lowest = NO ( In water = NC ) = Needs Pull Down 10.k
// Middle = NO ( In water = NC ) = Needs Pull Down 10.k
// Higest = NO ( In water = NC ) = Needs Pull Down 10.k
// Jumper = NO ( When on = Common jumped to Higest sensor pin)
// Read The Float Sensor's
const uint8_t _HOLD_WATER_LOWEST_SENSOR = digitalRead(LOWEST_FLOAT_SENSOR_PIN); // HIGH = 50.% to 10.% - Water Okay For Pump
const uint8_t _HOLD_WATER_MIDDLE_SENSOR = digitalRead(MIDDLE_FLOAT_SENSOR_PIN); // HIGH = 50.% to 90.%
const uint8_t _HOLD_WATER_HIGHEST_SENSOR = digitalRead(HIGHEST_FLOAT_SENSOR_PIN); // HIGH = 100.%
// Dont Be Getting Nonsens Reading's
static uint8_t _LowSensorOffDelay = 0U; // Get A Few Readings Before Setting The State
static uint8_t _LowSensorOnDelay = 0U; // Get A Few Readings Before Setting The State
static uint8_t _MidSensorOffDelay = 0U; // Get A Few Readings Before Setting The State
static uint8_t _MidSensorOnDelay = 0U; // Get A Few Readings Before Setting The State
static uint8_t _HigSensorOffDelay = 0U; // Get A Few Readings Before Setting The State
static uint8_t _HigSensorOnDelay = 0U; // Get A Few Readings Before Setting The State
const uint8_t _SENSOR_DELAY_NR = 3U; // Nr Of Reading Before Setting The State
// Jumper Is On
if (virtual_Jumper) { // Jumper Is On
//if (_HOLD_WATER_HIGHEST_SENSOR == HIGH && _HOLD_WATER_LOWEST_SENSOR == LOW || virtual_Jumper) { // Jumper Is On
if (Serial_Print) Serial.println(F("Holding Tank: Jumper Is On")); // Serial Print
Add_Water_Pump_Okay = true; // Add Water Pump Okay To Turn On
digitalWrite(HOLD_WATER_BLUE_PIN, HIGH); // Blue LED ON
digitalWrite(HOLD_WATER_RED_PIN, LOW); // Red LED OFF
digitalWrite(HOLD_WATER_GREEN_PIN, LOW); // Green LED OFF
holdingTankLevel = 100; // Holding Tank Level For Display
//virtual_Jumper = true; // Virtual Jumper - For Add Water Pump Protection
// Reset
_LowSensorOffDelay = 0U; // Reset
_LowSensorOnDelay = 0U; // Reset
_MidSensorOffDelay = 0U; // Reset
_MidSensorOnDelay = 0U; // Reset
_HigSensorOffDelay = 0U; // Reset
_HigSensorOnDelay = 0U; // Reset
}
// Jumper Is Not On
else { // Jumper Is Not On
// Lowest Sensor
if (_HOLD_WATER_LOWEST_SENSOR == HIGH) { // 10.% - Red LED ON
_LowSensorOnDelay++; // Count
if (_LowSensorOnDelay >= _SENSOR_DELAY_NR) { // Dont Get Nonsens
_LowSensorOnDelay = _SENSOR_DELAY_NR; // Hold The Counter At Max Nr
if (Add_Water_Pump_Okay) // Add Water Pump Okay To Turn On
digitalWrite(HOLD_WATER_RED_PIN, HIGH); // Red LED ON
_LowSensorOffDelay = 0U; // Reset
}
}
else if (_HOLD_WATER_LOWEST_SENSOR == LOW) { // 0.%
_LowSensorOffDelay++; // Count
if (_LowSensorOffDelay >= _SENSOR_DELAY_NR) { // Dont Get Nonsens
_LowSensorOffDelay = _SENSOR_DELAY_NR; // Hold The Counter At Max Nr
digitalWrite(ADD_WATER_PIN, OFF); // Turn OFF Add Water Relay
Add_Water_State = OFF; // Add Water Relay State = OFF
if (Add_Water_Pump_Okay) // Add Water Pump Okay To Turn On
if (Serial_Print) Serial.println(F("Holding Tank: 0.%")); // Serial Print
Add_Water_Pump_Okay = false; // Add Water Pump Not Okay To Turn On
_LowSensorOnDelay = 0U; // Reset
holdingTankLevel = 0; // Holding Tank Level For Display
}
}
// Middle Sensor
if (_HOLD_WATER_MIDDLE_SENSOR == HIGH) { // 50.% to 90.% - Green LED ON
_MidSensorOnDelay++; // Count
if (_MidSensorOnDelay >= _SENSOR_DELAY_NR) { // Dont Get Nonsens
_MidSensorOnDelay = _SENSOR_DELAY_NR; // Hold The Counter At Max Nr
digitalWrite(HOLD_WATER_GREEN_PIN, HIGH); // Green LED ON
Add_Water_Pump_Okay = true; // Add Water Pump Okay To Turn On
_MidSensorOffDelay = 0U; // Reset
holdingTankLevel = 50; // Holding Tank Level For Display
}
}
else if (_HOLD_WATER_MIDDLE_SENSOR == LOW) { // 10.% to 50.% - Green LED OFF
_MidSensorOffDelay++; // Count
if (_MidSensorOffDelay >= _SENSOR_DELAY_NR) { // Dont Get Nonsens
_MidSensorOffDelay = _SENSOR_DELAY_NR; // Hold The Counter At Max Nr
digitalWrite(HOLD_WATER_GREEN_PIN, LOW); // Green LED OFF
if (_HOLD_WATER_LOWEST_SENSOR == HIGH) { // Lowest Sensor Is In Water
if (Add_Water_Pump_Okay == true) { // Add Water Pump Okay To Turn On
if (Serial_Print) Serial.println(F("Holding Tank: 10-50.%")); // Serial Print
holdingTankLevel = 10; // Holding Tank Level For Display
}
}
_MidSensorOnDelay = 0U; // Reset
}
}
// Highest Sensor
if (_HOLD_WATER_HIGHEST_SENSOR == HIGH) { // 100.% - Blue LED ON
_HigSensorOnDelay++; // Count
if (_HigSensorOnDelay >= _SENSOR_DELAY_NR) { // Dont Get Nonsens
_HigSensorOnDelay = _SENSOR_DELAY_NR; // Hold The Counter At Max Nr
digitalWrite(HOLD_WATER_BLUE_PIN, HIGH); // Blue LED ON
digitalWrite(HOLD_WATER_GREEN_PIN, HIGH); // Green LED ON
digitalWrite(HOLD_WATER_RED_PIN, HIGH); // Red LED ON
if (Serial_Print) Serial.println(F("Holding Tank: 100.%")); // Serial Print
_HigSensorOffDelay = 0U; // Reset
holdingTankLevel = 100; // Holding Tank Level For Display
}
}
else if (_HOLD_WATER_HIGHEST_SENSOR == LOW) { // 50.% to 90.% - Blue LED OFF
_HigSensorOffDelay++; // Count
if (_HigSensorOffDelay >= _SENSOR_DELAY_NR) { // Dont Get Nonsens
_HigSensorOffDelay = _SENSOR_DELAY_NR; // Hold The Counter At Max Nr
digitalWrite(HOLD_WATER_BLUE_PIN, LOW); // Blue LED OFF
if (_HOLD_WATER_LOWEST_SENSOR == HIGH && _HOLD_WATER_MIDDLE_SENSOR == HIGH) { // Lowest & Middle Sensor's Are In Water
if (Serial_Print) Serial.println(F("Holding Tank: 50-90.%")); // Serial Print
holdingTankLevel = 50; // Holding Tank Level For Display
}
_HigSensorOnDelay = 0U; // Reset
}
}
// No Water In The Tank - So The Pump Wont Turn On/Off nonstop.
// Sensor is okay until the pump turns on, then the water comes back in the tank and the sensor will say okay to turn pump on.
if (Add_Water_Pump_Okay == false) { // Add Water Pump Not Okay To Turn On - Red LED Blink
if (digitalRead(HOLD_WATER_RED_PIN) == HIGH) // LED Is On
digitalWrite(HOLD_WATER_RED_PIN, LOW); // Red LED OFF
else // LED Is Off
digitalWrite(HOLD_WATER_RED_PIN, HIGH); // RED LED ON
digitalWrite(ADD_WATER_PIN, OFF); // Turn OFF Add Water Relay
Add_Water_State = OFF; // Add Water Relay State = OFF
if (Serial_Print) Serial.println(F("Holding Tank: Empty !")); // Serial Print
holdingTankLevel = 0; // Holding Tank Level For Display
}
}
}
void Water_Level_Function() { // Water Level Function
if (millis() - Water_Level_Wait >= WATER_LEVEL_WAIT_TIME) { // Wait For Function Timeout
Holding_Water_Tank_Function(); // Call: Holding Water Tank Function
Add_Water_Timeout_Function(); // Call: Add Water Timeout Function
// HC-SR04 Sensor Uses DHT Sensor To Get More Accurate Measurement With Speed Of Sound
if (millis() - DHT_Wait >= DHT_Wait_Time) { // Get The Temperature And Humidity Every X Time
DHT_Wait = millis(); // Keep Track Of The Time
// Set The DHT Run Time
if (DHT_Startup == false) { // DHT Startup - To Set The DHT Time
DHT_Startup_Count++; // DHT Run Counter
if (DHT_Startup_Count >= DHT_STARTUP_COUNTS) { // Counter Is Equal Or Over X Counts
DHT_Wait_Time = DHT_TIME; // Set The DHT Time
DHT_Startup = true; // DHT Startup Run Done - Set The Time To DHT_Time
}
}
else { // DHT Startup Is Done
DHT_Startup_Count = 0; // Reset The DHT Run Counter
DHT_Wait_Time = DHT_TIME; // Set The DHT Time
}
// Get The Measurement
const float raw_Hum = dht_HCSR04.readHumidity() + DHT_HUM_OFFSET; // Get Raw Humidity Value
const float raw_Temp = dht_HCSR04.readTemperature() - DHT_TEMP_OFFSET; // Get Raw Temperature Value
hum = constrain(raw_Hum, 1.0, 100.0); // Keep The Value In Range
temp = constrain(raw_Temp, -10.0, 100.0); // Keep The Value In Range
// DHT Error / Offline
if (isnan(raw_Temp) || isnan(raw_Hum)) { // DHT Error / Offline
if (isnan(raw_Temp) && isnan(raw_Hum)) { // DHT Temperature & Humidity
if (Serial_Print) Serial.println(F("DHT Error - Hum & Temp.")); // Serial Print
temp = DHT_ERR_TEMP; // Set The Temp Manually
hum = DHT_ERR_HUM; // Set The Hum Manually
}
else if (isnan(raw_Hum)) { // DHT Humidity
if (Serial_Print) Serial.println(F("DHT Error - Hum.")); // Serial Print
hum = DHT_ERR_HUM; // Set The Hum Manually
}
else if (isnan(raw_Temp)) { // DHT Temperature
if (Serial_Print) Serial.println(F("DHT Error - Temp.")); // Serial Print
temp = DHT_ERR_TEMP; // Set The Temp Manually
}
DHT_Startup = false; // DHT Startup - To Set The DHT Time
DHT_Wait_Time = DHT_TIME / 100UL; // Set The DHT Time
}
}
// HC-SR04 - Function's
// .ping() - Send a ping and get the echo time (in microseconds) as a result.
// .ping_cm() - Send a ping and get the distance in whole centimeters.
// .ping_median(iterations) - Do multiple pings (default=5), discard out of range pings and return median in microseconds.
// Get The Ping
const uint16_t _PING = ping_Median(NUMREADING); // Ping Variable
// HC-SR04 Sensor - Error
if (_PING == 0U) { // HC-SR04 Sensor - Error
if (hcsr04_Fail >= HCSR04_FAILS) { // Ping Failed
if (Add_Water_State == ON) { // Add Water Is On
digitalWrite(ADD_WATER_PIN, OFF); // Turn OFF Add Water Relay
Add_Water_State = OFF; // Add Water State = OFF
hcsr04_Fail = HCSR04_FAILS; // Keep The Value In Faild State
}
percentage = 0.0F; // Percentage = 0.%
if (Serial_Print) // Serial Print
Serial.println(F("HC-SR04 Error - Automatic Add Water OFF !"));
}
else { // Less Than HCSR04_FAILS
hcsr04_Fail++; // Add To The HC-SR04 Fail Count
if (Serial_Print) Serial.println(F("HC-SR04 Failed.")); // Serial Print
}
}
// HC-SR04 Sensor - Okay
else { // HC-SR04 Sensor - Okay
// Reset HC-SR04 Fail Counts
hcsr04_Fail = 0; // Reset HC-SR04 Fail Counts
// Calculate The Speed Of Sound
const float _SOUNDSP = 331.4F + (0.606F * temp) + (0.0124F * hum); // Calculate the Speed of Sound in M/S
const float _SOUNDCM = _SOUNDSP / 10000.0F; // Convert to cm/ms
// Calculate The Distance In Cm
const float _DISTANCE = ((float)_PING / 2.0F) * _SOUNDCM; // Calculate The Distance In Cm
// Calculate The Water Level Percentage
const float _PERCENTAGE = ((max_Water_Level - (_DISTANCE - (float)max_WATER_HEIGHT)) / max_Water_Level * 100.0F) + (float)aquarium_PCT; // Calculate The Water Level Percentage
// Water Level Percentage - Variables
static float _lastPercentage = percentage; // Try to keep big dips away. (like sensor error's)
percentage = _PERCENTAGE; // Set The Water Level Percentage
percentage = constrain(percentage, 0.0F, 200.0F); // Keep The Value In Range
// Level Did Fall About 10% Or More From The Last Reading
static bool _holdTheValue = false; // Hold The Value Bool
static uint16_t _holdValueCounter = 0U; // Hold The Value Counter
const uint16_t _HOLDVALUECOUNTS = ((1000U / WATER_LEVEL_WAIT_TIME) * 60U) * 2U; // Hold The Value For X Minutes
// Level Did Fall About 10% Or More From The Last Reading
if (_lastPercentage - percentage >= 10.0F) { // Level Did Fall About 10% Or More From The Last Reading
// Try to clean big dips.
// example: Water level is now 99% next will be 35% (sensor reading error).
// That happens from time to time.
// From High To Low
percentage = _lastPercentage; // Set The Water Level Percentage
// Dont Hold The Value Forever
if (!_holdTheValue) { // Start The Hold Value Counter
_holdTheValue = true; // Hold The Value - Counter On
_holdValueCounter = 0U; // Hold The Value Counter - Reset
}
if (_holdTheValue) { // Count
_holdValueCounter++; // Hold The Value Counter
}
if (_holdValueCounter >= _HOLDVALUECOUNTS) { // Count Time Is Up
percentage = _PERCENTAGE; // Set The Water Level Percentage
_holdTheValue = false; // Hold The Value - Counter Off
}
// From Low To High - Skip The Count Time
if (_PERCENTAGE >= add_WATER_ON + 1.0F && _holdTheValue) { // Water Level Is Over X And The Timer Is On
percentage = _PERCENTAGE; // Set The Water Level Percentage
_holdTheValue = false; // Hold The Value - Counter Off
_holdValueCounter = 0U; // Set The Value For Serial Print
}
// Serial Print
if (Serial_Print) { // Serial Print
Serial.print(F("Last Percentage Was: "));
Serial.print(_lastPercentage, 1);
Serial.println(F(".%"));
Serial.print(F("Else Percentage Is: "));
Serial.print(_PERCENTAGE, 1);
Serial.println(F(".%"));
if (!_holdTheValue && _holdValueCounter == 0U) // Skip The Count Time
Serial.println(F("Hold The Value - Skip."));
else if (!_holdTheValue) // Count Time Is Up
Serial.println(F("Hold The Value - Count Time Is Up."));
}
}
// The Level Value Is On Hold And The Value Is Okay Now
else if (_holdTheValue) { // Hold The Value - Counter Is On
_holdTheValue = false; // Hold The Value - Counter Off
_holdValueCounter = 0U; // Hold The Value Counter - Reset
if (Serial_Print) Serial.println(F("Hold The Value - Reset.")); // Serial Print
}
percentage = constrain(percentage, 0.0F, 200.0F); // Keep The Value In Range
_lastPercentage = percentage; // Store The Last Percentage
if (Serial_Print) { // Serial Print - Info
/*// DHT
Serial.print(F("DHT Sensor = Sound: "));
Serial.print(_SOUNDSP, 1);
Serial.print(F(".m/s, Humid: "));
Serial.print(hum, 1);
Serial.print(F(".%, Temp: "));
Serial.print(temp, 1);
Serial.println(F("°C"));
// HC-SR04 * /
Serial.print(F("Percentage: "));
Serial.print(percentage, 1);
Serial.print(F(".% - Distance: "));
Serial.print(_DISTANCE, 2);
Serial.println(F(".cm")); //*/
// HC-SR04
Serial.print(F("Percentage: "));
Serial.print(percentage, 1);
Serial.println(F(".%")); // */
}
//Serial.print(F("Distance: "));Serial.print(_DISTANCE, 2);Serial.println(F(".cm"));
//--------------------------------------------- Tank Monitoring --------------------------------------------------------//
// Low - Turn Add Water On
if (percentage <= add_WATER_ON) { // Low - Turn Add Water On
if (Add_Water_Pump_Okay == true) { // Add Water Pump Okay / Okay To Turn On - Set By Holding Water Tank
if (Add_Water_State == OFF) { // If Add Water Relay Is OFF
if ((millis() - startTime_Add_Water_Wait) >= 1000UL) { // Count Down Every Second
startTime_Add_Water_Wait = millis(); // Keep Track Of The Count Down Time
// Serial Print Count Down
if (Serial_Print) { // Serial Print Count Down
const int _dpSec = sec_Add_Water % 60; // Display Seconds
const int _dpMin = (sec_Add_Water / 60) % 60; // Display Minuets
const int _dpHour = (sec_Add_Water / 60) / 60; // Display Hours
Serial.print(F("Count Down Add Water Wait: "));
if (_dpHour > 0) { // More Than 1.Hour
Serial.print(_dpHour); // Print Hour
Serial.print(F(".Hour & "));
}
if (_dpMin > 0) { // More Than 1.Minute
Serial.print(_dpMin); // Print Minutes
if (_dpSec > 0) { // X.Minutes And Some Seconds
Serial.print(F(".Min & "));
Serial.print(_dpSec); // Print Seconds
Serial.println(F(".Sec"));
} else Serial.println(F(".Minute")); // Only Minutes
}
else { // Less Than 1.Minute
if (_dpSec > 0) { // Some Seconds
Serial.print(_dpSec); // Print Seconds
Serial.println(F(".Seconds"));
} else Serial.println(F("Count Down Is Done.")); // Count Down Is Done
}
}
// If The Count Down Is Done
if (sec_Add_Water <= 0) { // If The Count Down Is Done
// Add Water - Reset The Add Water Delay Time
sec_Add_Water = ADD_WATER_DELAY_TIME; // Reset The Add Water Delay Time
startTime_Add_Water_Wait = millis(); // Keep Track Of The Count Down Time
if (!Add_Water_Timeout_State) // If The Add Water Is Not On Timeout
digitalWrite(ADD_WATER_PIN, ON); // Turn ON Add Water Relay
Add_Water_State = ON; // Add Water Relay State = ON
if (Serial_Print) Serial.println(F("Turn Add Water ON.")); // Serial Print
}
else { // Time Is Not Up Yet.. Keep Counting
if (!skip_First_Count) sec_Add_Water--; // Add Water Countdown Time
skip_First_Count = false; // Skip The First Add Water Count - For Display
}
add_Water_Count_State = true; // Add Water Countdown State - For Display
}
}
}
else { // NOT Okay For Add Water Pump To Start
if (Serial_Print) Serial.println(F("No Water In The Holding Tank !")); // Serial Print
}
}
// Okay - And Add Water Is Off
if (percentage > add_WATER_ON && percentage <= ADD_WATER_OFF && Add_Water_State == OFF) { // Okay - And Add Water Is Off
if (Serial_Print) Serial.println(F("Add Water Is OFF.")); // Serial Print
}
// Full - Turn Add Water Off If It Is On
if (percentage >= (ADD_WATER_OFF - 1.0F) && Add_Water_State == ON) { // Full - Turn Add Water Off If It Is On - (ADD_WATER_OFF - 1) NEW Buffer
if (Add_Water_State == ON) { // If Add Water Relay Is ON
// Turn Add Water Relay Off
digitalWrite(ADD_WATER_PIN, OFF); // Turn Off Add Water Relay
Add_Water_State = OFF; // Add Water Relay State = OFF
if (Serial_Print) Serial.println(F("Turn Add Water OFF.")); // Serial Print
}
}
// Little Too High - Turn Add Water Off !
if (percentage >= (ADD_WATER_OFF + 1.0F) && percentage < HIGH_WATER_ALERT) { // Little Too High - Turn Add Water Off
if (Add_Water_State == ON) { // If Add Water Relay Is ON
// Turn Add Water Relay Off
digitalWrite(ADD_WATER_PIN, OFF); // Turn Off Add Water Relay
Add_Water_State = OFF; // Add Water Relay State = OFF
if (Serial_Print) Serial.println(F("Turn Add Water OFF !")); // Serial Print
}
}
// Too High - Water Level Warnings
if (percentage >= HIGH_WATER_ALERT) { // Too High - Water Level Warnings
// Turn Add Water Relay Off
if (Add_Water_State == ON) { // If Add Water Relay Is ON
// Turn Add Water Off
digitalWrite(ADD_WATER_PIN, OFF); // Turn Off Add Water Relay
Add_Water_State = OFF; // Water Pump State = OFF
}
// Put The Add Water Back On Timeout
if (millis() - Add_Water_High_Alert_Wait >= ADD_WATER_HIGH_ALERT_TIME) { // Wait For The Time To Pass
Set_The_Add_Water_Timeout_Function(); // Set The Add Water Timeout
Add_Water_High_Alert_Wait = millis(); // Keep Track Of The Time < Here To Slow Down This Function
if (Serial_Print) Serial.println(F("Add Water Back On Timeout.")); // Serial Print
}
// Serial Print
if (Serial_Print) { // Serial Print
Serial.print(F("Water Level Over: "));
Serial.print(HIGH_WATER_ALERT);
Serial.println(F(".%"));
}
}
else { // Not Too High - For Add Water Back On Timeout
// If The Pump Turns Off Then The Water Level Will Go High,
// Then When The Pump Turns Back On The Water Level Will Go Low,
// But We Can Not Add Water Until The Tank Equalise,
// So We Need To Put The Timeout On Again.
Add_Water_High_Alert_Wait = millis(); // Keep Track Of The Time
}
// Add Water - Reset The Add Water Delay Time
if (percentage > add_WATER_ON) { // Add Water - Reset The Add Water Delay Time
// Add Water - Reset The Add Water Delay Time
sec_Add_Water = ADD_WATER_DELAY_TIME; // Reset The Add Water Delay Time
startTime_Add_Water_Wait = millis(); // Keep Track Of The Count Down Time
// Reset Add Water State's - For Display
add_Water_Count_State = false; // Add Water Countdown State - For Display
skip_First_Count = true; // Skip The First Add Water Count - For Display
}
}
LCD_Print_Function(); // LCD Print Function
Water_Level_Wait = millis(); // Keep Track Of The Time
}
}
void LCD_Print_Function() { // LCD Print Function
// Error & System Info & Add Water
static int16_t _last_sec_Add_Water = sec_Add_Water; // Keep Track Of The Value
static bool _clear_System_Info = false; // Clear The System Info For Count Down
static bool _last_Hcsr04_Fail = false; // Keep Track Of The State
static bool _last_Add_Water_Timeout_State = Add_Water_Timeout_State; // Keep Track Of The State
static bool _last_Add_Water_State = Add_Water_State; // Keep Track Of The State
static bool _last_Add_Water_Pump_Okay = Add_Water_Pump_Okay; // Keep Track Of The State
// Error - HC-SR04 Ping Faild
if (hcsr04_Fail >= HCSR04_FAILS) { // Error - HC-SR04 Ping Faild
_last_Hcsr04_Fail = true; // Set The State
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F("Error! Add Water Off")); // Display Print
}
// Clear The Error
else if (_last_Hcsr04_Fail) { // Clear The Error
_last_Hcsr04_Fail = false; // Set The State
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
// System Info & Add Water
if (!_last_Hcsr04_Fail) { // No Error
// System Info & Add Water - Count Down
if (Add_Water_State == OFF) { // If The Add Water Relay Is Off
// Clear The Line
if (_last_Add_Water_State == ON) { // If The Add Water Relay Did Turn On
if (!add_Water_Count_State) { // Add Water Counter Is Not On
_last_Add_Water_State = OFF; // Set The State
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
}
// System Info
if (!add_Water_Count_State) { // Add Water Counter Is Not On
_clear_System_Info = true; // Clear The System Info For Count Down
lcd.setCursor(4, 0); // Set The Display Cursor
lcd.print(F("System Info.")); // Display Print
}
// Add Water - Count Down
else { // Adding Water Starting
// Clear The Line
if (_clear_System_Info) { // Clear The Line At First Count
_clear_System_Info = false; // Clear The System Info For Count Down
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
if (!Add_Water_Pump_Okay) { // Add Water Pump Not Okay To Turn On - Red LED Blink
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F("Add Water - No Water")); // Display Print
_last_Add_Water_Pump_Okay = Add_Water_Pump_Okay; // Set The State
}
else { // Water In Holding Tank
/*// Add Water Count Down In Seconds
if (_last_sec_Add_Water >= 10 && sec_Add_Water < 10 || // Clear The Last Value
_last_sec_Add_Water >= 100 && sec_Add_Water < 100) {
lcd.setCursor(13, 0); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
_last_sec_Add_Water = sec_Add_Water; // Keep Track Of The Value
_last_Add_Water_Timeout_State = true; // Set The State < To Clear This Line In Adding Now
_last_Add_Water_State = ON; // Set The State < To Clear This Line In System Info
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F("Add Water In")); // Display Print
lcd.setCursor(13, 0); // Set The Display Cursor
lcd.print(sec_Add_Water); // Display Print
if (sec_Add_Water < 10) lcd.setCursor(14, 0); // Set The Display Cursor
else if (sec_Add_Water >= 10 && sec_Add_Water < 100) lcd.setCursor(15, 0); // Set The Display Cursor
else lcd.setCursor(16, 0); // Set The Display Cursor
lcd.print(F(".sec")); // Display Print
//*/
// Add Water Count Down In Hours, Minutes And Seconds
const int _dpSec = sec_Add_Water % 60; // Display Seconds
const int _dpMin = (sec_Add_Water / 60) % 60; // Display Minuets
const int _dpHour = (sec_Add_Water / 60) / 60; // Display Hours
static bool _clearTime = true; // Clear The Time State
if (sec_Add_Water == ADD_WATER_DELAY_TIME) _clearTime = true;// Reset Clear The Time State
if (!_last_Add_Water_Pump_Okay) { // Holding Tank Was Empty
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
_last_Add_Water_Pump_Okay = Add_Water_Pump_Okay; // Set The State
}
const uint8_t _FIRST_COL = 13; // First Column Number
uint8_t _col = _FIRST_COL; // Column Number
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F("Add Water In")); // Display Print
lcd.setCursor(_FIRST_COL, 0); // Set The Display Cursor
// SS.sec
if (sec_Add_Water < 60) { // Less Than 1 Minute
if (_last_sec_Add_Water >= 10 && sec_Add_Water < 10) { // Clear The Last Value - From 10.Sec To 9.Sec
lcd.print(F(" ")); // Display Print
lcd.setCursor(_FIRST_COL, 0); // Set The Display Cursor
}
if (sec_Add_Water <= 1) { // Clear The Last Value - From 2.Sec To 1.Sec
if (_clearTime) { // Clear The Last Value
_clearTime = false; // Set Clear The Time State
lcd.print(F(" ")); // Display Print
lcd.setCursor(_FIRST_COL, 0); // Set The Display Cursor
}
}
_col++; // Add To The Column Number
lcd.print(sec_Add_Water); // Display Print
if (_dpSec >= 10) _col++; // Set The Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
if (sec_Add_Water <= 1) lcd.print(F(".sec")); // Display Print
else lcd.print(F(".secs")); // Display Print
if (sec_Add_Water > 1 && !_clearTime) _clearTime = true; // Set Clear The Time State
}
// H:MM:SS
else if (_dpHour >= 1) { // 1 Hour Or More
if (_dpSec == 0 && _dpMin == 0) { // @ Whole Hour
if (_clearTime) { // Clear The Last Value
_clearTime = false; // Set Clear The Time State
lcd.print(F(" ")); // Display Print
lcd.setCursor(_FIRST_COL, 0); // Set The Display Cursor
}
_col++; // Add To The Column Number
lcd.print(_dpHour); // Display Print
if (_dpHour >= 10) _col++; // Set The Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
if (_dpHour == 1) lcd.print(F(".hour")); // Display Print
else lcd.print(F(".hours")); // Display Print
}
else { // Minutes And Seconds
_clearTime = true; // Set Clear The Time State
if (_last_sec_Add_Water >= 36000 && sec_Add_Water < 36000) { // Clear The Last Value - From 10.Hours To 9.Hours
lcd.print(F(" ")); // Display Print
lcd.setCursor(_FIRST_COL, 0); // Set The Display Cursor
}
_col++; // Add To The Column Number
lcd.print(_dpHour); // Display Print
if (_dpHour >= 10) _col++; // Set The Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
lcd.print(F(":")); // Display Print
_col++; // Add To Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
if (_dpMin < 10) { // Add 0 To Min
lcd.print(F("0")); // Display Print
_col++; // Add To Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
}
lcd.print(_dpMin); // Display Print
if (_dpMin >= 10) _col++; // Set The Column Number
_col++; // Add To Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
lcd.print(F(":")); // Display Print
_col++; // Add To Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
if (_dpSec < 10) { // Add 0 To Sec
lcd.print(F("0")); // Display Print
_col++; // Add To Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
}
lcd.print(_dpSec); // Display Print
}
}
// MM:SS.s
else { // 1 Minute Or More And Less Than 1 Hour
if (_dpSec == 0) { // @ Whole Minute
if (_clearTime) { // Clear The Last Value
_clearTime = false; // Set Clear The Time State
lcd.print(F(" ")); // Display Print
lcd.setCursor(_FIRST_COL, 0); // Set The Display Cursor
}
_col++; // Add To The Column Number
lcd.print(_dpMin); // Display Print
if (_dpMin >= 10) _col++; // Set The Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
if (_dpMin == 1) lcd.print(F(".min")); // Display Print
else lcd.print(F(".mins")); // Display Print
}
else { // Minutes And Seconds
_clearTime = true; // Set Clear The Time State
if (_last_sec_Add_Water >= 600 && sec_Add_Water < 600) { // Clear The Last Value - From 10.Min To 9.Min
lcd.print(F(" ")); // Display Print
lcd.setCursor(_FIRST_COL, 0); // Set The Display Cursor
}
_col++; // Add To The Column Number
lcd.print(_dpMin); // Display Print
if (_dpMin >= 10) _col++; // Set The Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
lcd.print(F(":")); // Display Print
_col++; // Add To The Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
if (_dpSec < 10) { // Add 0 To Sec
lcd.print(F("0")); // Display Print
_col++; // Add To Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
}
lcd.print(_dpSec); // Display Print
if (_dpSec >= 10) _col++; // Set The Column Number
_col++; // Add To The Column Number
lcd.setCursor(_col, 0); // Set The Display Cursor
lcd.print(F(".s")); // Display Print
}
}
}
_last_sec_Add_Water = sec_Add_Water; // Keep Track Of The Value
_last_Add_Water_Timeout_State = true; // Set The State < To Clear This Line In Adding Now
_last_Add_Water_State = ON; // Set The State < To Clear This Line In System Info
}
}
// Add Water - Timeout & Now
else { // If The Add Water Relay Is On
_last_Add_Water_State = ON; // Keep Track Of The State
if (Add_Water_Timeout_State) { // Add Water Is On Timeout
_last_Add_Water_Timeout_State = true; // Set The State
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F("Add Water On Timeout")); // Display Print
}
else { // Adding Water
if (_last_Add_Water_Timeout_State) { // If The Add Water Was On Timeout
_last_Add_Water_Timeout_State = false; // Set The State
lcd.setCursor(0, 0); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
lcd.setCursor(2, 0); // Set The Display Cursor
lcd.print(F("Adding Water Now")); // Display Print
}
}
}
// Water Level
static uint8_t _lastPercentage = percentage; // Keep Track Of The Value
if (_lastPercentage >= 100 && percentage < 100.0F || // If The Value Has Changed
percentage >= 100.0F && _lastPercentage < 100) {
_lastPercentage = percentage; // Keep Track Of The Last State
lcd.setCursor(13, 1); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
if (_lastPercentage >= 10 && percentage < 10.0F || // If The Value Has Changed
percentage >= 10.0F && _lastPercentage < 10) {
_lastPercentage = percentage; // Keep Track Of The Last State
lcd.setCursor(13, 1); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
lcd.setCursor(0, 1); // Set The Display Cursor
lcd.print(F("Water level: ")); // Display Print
lcd.setCursor(13, 1); // Set The Display Cursor
lcd.print(percentage, 1); // Display Print
if (percentage < 10.0F) lcd.setCursor(16, 1); // Set The Display Cursor
else if (percentage >= 10.0F && percentage < 100.0F)lcd.setCursor(17, 1); // Set The Display Cursor
else lcd.setCursor(18, 1); // Set The Display Cursor
lcd.print(F(".%")); // Display Print
// Holding Tank
static uint8_t _lastHoldingTankLevel = holdingTankLevel; // Keep Track Of The Last State
if (_lastHoldingTankLevel != holdingTankLevel) { // If The State Has Changed
_lastHoldingTankLevel = holdingTankLevel; // Keep Track Of The Last State
lcd.setCursor(9, 2); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
lcd.setCursor(0, 2); // Set The Display Cursor
lcd.print(F("Storage: ")); // Display Print
lcd.setCursor(9, 2); // Set The Display Cursor
if (holdingTankLevel == 0) lcd.print(F("0.%")); // Display Print
else if (holdingTankLevel == 10) lcd.print(F("10-50.%")); // Display Print
else if (holdingTankLevel == 50) lcd.print(F("50-90.%")); // Display Print
else lcd.print(F("100.%")); // Display Print
// Pump Protection "Jumper"
lcd.setCursor(0, 3); // Set The Display Cursor
lcd.print(F("Pump protection: ")); // Display Print
lcd.setCursor(17, 3); // Set The Display Cursor
if (virtual_Jumper) lcd.print(F("Off")); // Display Print
else lcd.print(F("On")); // Display Print
}
void LCD_Setup() { // LCD Display Setup
lcd.init(); // LCD Init
lcd.backlight(); // LCD Backlight
lcd.setCursor(5, 0); // Set The Display Cursor
lcd.print(F("Automatic")); // Display Print
lcd.setCursor(1, 1); // Set The Display Cursor
lcd.print(F("Aquarium Add Water")); // Display Print
lcd.setCursor(7, 2); // Set The Display Cursor
lcd.print(F("System")); // Display Print
lcd.setCursor(3, 3); // Set The Display Cursor
lcd.print(F("Version:")); // Display Print
lcd.setCursor(12, 3); // Set The Display Cursor
lcd.print(AQUARIUM_ADD_WATER_VERSION); // Display Print
}
void Button_Menu_Function() { // Button Menu Function
//if (digitalRead(PLUS_BUTTON_PIN) == LOW) Serial.println("Plus Button Pressed.");
//if (digitalRead(MINUS_BUTTON_PIN) == LOW) Serial.println("Minus Button Pressed.");
if (digitalRead(OK_BUTTON_PIN) == LOW) { // Go To Menu
// Serial Print
if (Serial_Print) Serial.println(F("Ok / Menu Button Pressed.")); // Serial Print
// If The Add Water Is On Then Turn It Off
if (Add_Water_State == ON) { // If The Add Water Is On Then Turn It Off
digitalWrite(ADD_WATER_PIN, OFF); // Turn Off Add Water Relay
//Add_Water_State = OFF; // Add Water Relay State = OFF
}
// Variables
uint8_t _menuWindow = 0; // Menu Window Nr
const uint8_t _MENU_HEIGHT_TO_SENSOR = 0; // Menu For Height To Sensor
const uint8_t _MENU_MAX_WATER_HEIGHT = 1; // Menu For MAX Water Height
const uint8_t _MENU_AQUARIUM_PCT = 2; // Menu For Aquarium Percent
const uint8_t _MENU_PUMP_PROTECTION = 3; // Menu For Pump Protection - Virtual Jumper
const uint8_t _MENU_ADD_WATER_ON = 4; // Menu For Add Water ON Value
const uint8_t _MENU_ADD_WATER_TIMEOUT = 5; // Menu For Add Water Timeout
const uint8_t _MENU_WINDOWS = 6; // Menu For Exit
bool _update_HEIGHT_TO_SENSOR = false; // Update Height To Sensor
bool _update_MAX_WATER_HEIGHT = false; // Update MAX Water Height
bool _update_AQUARIUM_PCT = false; // Update Aquarium Percent
bool _update_PUMP_PROTECTION = false; // Update Pump Protection - Virtual Jumper
bool _update_ADD_WATER_ON = false; // Update Add Water ON Value
const uint8_t _BUTTON_DELAY = 200; // Delay For Button
bool _add_Water_Timeout = Add_Water_Timeout_State; // Get The Add Water Timeout State
int16_t _lastValue = 0; // Keep Track Of The Value Too Clear The Line
const int16_t _MAXVALUE = 200; // No Value Can Go Over This
uint32_t _timeOut = millis(); // Keep Track Of The Time
const uint32_t _TIMEOUT_TIME = 1000UL * 30UL; // Time In Seconds
// Display Print
lcd.clear(); // Clear The Display
lcd.setCursor(4, 0); // Set The Display Cursor
lcd.print(F("System Setup.")); // Display Print
lcd.setCursor(4, 1); // Set The Display Cursor
lcd.print(F("From sensor")); // Display Print
lcd.setCursor(3, 2); // Set The Display Cursor
lcd.print(F("to tank bottom")); // Display Print
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(height_TO_SENSOR); // Display Print
if (height_TO_SENSOR < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (height_TO_SENSOR >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".cm")); // Display Print
delay(_BUTTON_DELAY); // Delay For Button
// While In Menu
while (true) { // While In Menu
if (millis() - _timeOut >= _TIMEOUT_TIME) { // Timeout
if (Serial_Print) Serial.println(F("Menu - Timeout")); // Serial Print
lcd.clear(); // Clear The Display
break; // Stop The While Loop
}
if (digitalRead(PLUS_BUTTON_PIN) == LOW) { // Plus Button Pressed
if (_menuWindow == _MENU_HEIGHT_TO_SENSOR) { // Height To Sensor Menu
_update_HEIGHT_TO_SENSOR = true; // Update Height To Sensor
height_TO_SENSOR++; // Add To The Value
if (height_TO_SENSOR >= _MAXVALUE) height_TO_SENSOR = _MAXVALUE; // Dont Go Over This
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(height_TO_SENSOR); // Display Print
if (height_TO_SENSOR < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (height_TO_SENSOR >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".cm")); // Display Print
}
else if (_menuWindow == _MENU_MAX_WATER_HEIGHT) { // MAX Water Height Menu
_update_MAX_WATER_HEIGHT = true; // Update MAX Water Height
max_WATER_HEIGHT++; // Add To The Value
if (max_WATER_HEIGHT >= _MAXVALUE) max_WATER_HEIGHT = _MAXVALUE; // Dont Go Over This
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(max_WATER_HEIGHT); // Display Print
if (max_WATER_HEIGHT < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (max_WATER_HEIGHT >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".cm")); // Display Print
}
else if (_menuWindow == _MENU_AQUARIUM_PCT) { // Aquarium Percent Menu
_update_AQUARIUM_PCT = true; // Update Aquarium Percent
aquarium_PCT++; // Add To The Value
if (aquarium_PCT >= _MAXVALUE) aquarium_PCT = _MAXVALUE; // Dont Go Over This
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(aquarium_PCT); // Display Print
if (aquarium_PCT < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (aquarium_PCT >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".%")); // Display Print
}
else if (_menuWindow == _MENU_PUMP_PROTECTION) { // Pump Protection Menu
_update_PUMP_PROTECTION = true; // Update Pump Protection - Virtual Jumper
lcd.setCursor(9, 3); // Set The Display Cursor
if (!virtual_Jumper) { // Jumper Is Not In Use
virtual_Jumper = true; // Change The Jumper State
lcd.print(F("Off")); // Display Print
}
else { // Jumper Is In Use
virtual_Jumper = false; // Change The Jumper State
lcd.print(F(" ")); // Display Print
lcd.setCursor(9, 3); // Set The Display Cursor
lcd.print(F("On")); // Display Print
}
}
else if (_menuWindow == _MENU_ADD_WATER_ON) { // Add Water On Menu
_update_ADD_WATER_ON = true; // Update Add Water ON Value
add_WATER_ON += 0.1F; // Add To The Value
if (add_WATER_ON >= ADD_WATER_OFF - 1.0F) add_WATER_ON = ADD_WATER_OFF - 1.0F; // Dont Go Over This
lcd.setCursor(7, 3); // Set The Display Cursor
lcd.print(add_WATER_ON, 1); // Display Print
//lcd.setCursor(11, 3); // Set The Display Cursor
//lcd.print(F(".%")); // Display Print
}
else if (_menuWindow == _MENU_ADD_WATER_TIMEOUT) { // Add Water Timeout
lcd.setCursor(9, 3); // Set The Display Cursor
if (!_add_Water_Timeout) { // Add Water Timeout Is Not On
_add_Water_Timeout = true; // Change The Add Water Timeout State
//Add_Water_Timeout_State = true; // Bool For Add Water Timeout
lcd.print(F(" ")); // Display Print
lcd.setCursor(9, 3); // Set The Display Cursor
lcd.print(F("On")); // Display Print
}
else { // Timeout Is On
_add_Water_Timeout = false; // Change The Add Water Timeout State
//Add_Water_Timeout_State = false; // Bool For Add Water Timeout
lcd.print(F("Off")); // Display Print
}
}
//if (Serial_Print) Serial.println(F("+")); // Serial Print
delay(_BUTTON_DELAY); // Delay For Button
_timeOut = millis(); // Keep Track Of The Time
}
if (digitalRead(MINUS_BUTTON_PIN) == LOW) { // Minus Button Pressed
if (_menuWindow == _MENU_HEIGHT_TO_SENSOR) { // Height To Sensor Menu
_update_HEIGHT_TO_SENSOR = true; // Update Height To Sensor
if (height_TO_SENSOR == 10) { // Value Is At 10 - Clear The Line
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
else if (_lastValue >= 100 && height_TO_SENSOR <= 100) { // Value Went Below 100
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
_lastValue = height_TO_SENSOR; // Keep Track Of The Value
if (height_TO_SENSOR >= _MAXVALUE) height_TO_SENSOR = _MAXVALUE; // Dont Go Over This
height_TO_SENSOR--; // Subtract From The Value
if (height_TO_SENSOR <= 0) height_TO_SENSOR = 0; // Dont Let The Value To Go Negative
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(height_TO_SENSOR); // Display Print
if (height_TO_SENSOR < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (height_TO_SENSOR >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".cm")); // Display Print
}
else if (_menuWindow == _MENU_MAX_WATER_HEIGHT) { // MAX Water Height Menu
_update_MAX_WATER_HEIGHT = true; // Update MAX Water Height
if (max_WATER_HEIGHT == 10) { // Value Is At 10 - Clear The Line
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
else if (_lastValue >= 100 && max_WATER_HEIGHT <= 100) { // Value Went Below 100
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
_lastValue = max_WATER_HEIGHT; // Keep Track Of The Value
if (max_WATER_HEIGHT >= _MAXVALUE) max_WATER_HEIGHT = _MAXVALUE; // Dont Go Over This
max_WATER_HEIGHT--; // Subtract From The Value
if (max_WATER_HEIGHT <= 0) max_WATER_HEIGHT = 0; // Dont Let The Value To Go Negative
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(max_WATER_HEIGHT); // Display Print
if (max_WATER_HEIGHT < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (max_WATER_HEIGHT >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".cm")); // Display Print
}
else if (_menuWindow == _MENU_AQUARIUM_PCT) { // Aquarium Percent Menu
_update_AQUARIUM_PCT = true; // Update Aquarium Percent
if (aquarium_PCT == 10) { // Value Is At 10 - Clear The Line
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
else if (_lastValue >= 100 && aquarium_PCT <= 100) { // Value Went Below 100
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(F(" ")); // Display Print
}
_lastValue = aquarium_PCT; // Keep Track Of The Value
if (aquarium_PCT >= _MAXVALUE) aquarium_PCT = _MAXVALUE; // Dont Go Over This
aquarium_PCT--; // Subtract From The Value
if (aquarium_PCT <= 0) aquarium_PCT = 0; // Dont Let The Value To Go Negative
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(aquarium_PCT); // Display Print
if (aquarium_PCT < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (aquarium_PCT >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".%")); // Display Print
}
else if (_menuWindow == _MENU_PUMP_PROTECTION) { // Pump Protection Menu
_update_PUMP_PROTECTION = true; // Update Pump Protection - Virtual Jumper
lcd.setCursor(9, 3); // Set The Display Cursor
if (!virtual_Jumper) { // Jumper Is Not In Use
virtual_Jumper = true; // Change The Jumper State
lcd.print(F("Off")); // Display Print
}
else { // Jumper Is In Use
virtual_Jumper = false; // Change The Jumper State
lcd.print(F(" ")); // Display Print
lcd.setCursor(9, 3); // Set The Display Cursor
lcd.print(F("On")); // Display Print
}
}
else if (_menuWindow == _MENU_ADD_WATER_ON) { // Add Water On Menu
_update_ADD_WATER_ON = true; // Update Add Water ON Value
add_WATER_ON -= 0.1F; // Subtract From The Value
if (add_WATER_ON <= 10.0F) add_WATER_ON = 10.0F; // Dont Let The Value To Go Negative
lcd.setCursor(7, 3); // Set The Display Cursor
lcd.print(add_WATER_ON, 1); // Display Print
//lcd.setCursor(11, 3); // Set The Display Cursor
//lcd.print(F(".%")); // Display Print
}
else if (_menuWindow == _MENU_ADD_WATER_TIMEOUT) { // Add Water Timeout
lcd.setCursor(9, 3); // Set The Display Cursor
if (!_add_Water_Timeout) { // Add Water Timeout Is Not On
_add_Water_Timeout = true; // Change The Add Water Timeout State
lcd.print(F(" ")); // Display Print
lcd.setCursor(9, 3); // Set The Display Cursor
lcd.print(F("On")); // Display Print
}
else { // Timeout Is On
_add_Water_Timeout = false; // Change The Add Water Timeout State
lcd.print(F("Off")); // Display Print
}
}
//if (Serial_Print) Serial.println(F("-")); // Serial Print
delay(_BUTTON_DELAY); // Delay For Button
_timeOut = millis(); // Keep Track Of The Time
}
if (digitalRead(OK_BUTTON_PIN) == LOW) { // Ok / Menu Button Pressed
// Go To Next Menu
_menuWindow++; // Go To Next Menu
// Display Print
if (_menuWindow != _MENU_WINDOWS) { // Display Print
lcd.clear(); // Clear The Display
lcd.setCursor(4, 0); // Set The Display Cursor
lcd.print(F("System Setup.")); // Display Print
}
// Set The Next Menu
if (_menuWindow == _MENU_MAX_WATER_HEIGHT) { // MAX Water Height Menu
lcd.setCursor(4, 1); // Set The Display Cursor
lcd.print(F("From sensor")); // Display Print
lcd.setCursor(1, 2); // Set The Display Cursor
lcd.print(F("to MAX water level")); // Display Print
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(max_WATER_HEIGHT); // Display Print
if (max_WATER_HEIGHT < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (max_WATER_HEIGHT >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".cm")); // Display Print
_lastValue = max_WATER_HEIGHT; // Keep Track Of The Value
}
else if (_menuWindow == _MENU_AQUARIUM_PCT) { // Aquarium Percent Menu
lcd.setCursor(2, 1); // Set The Display Cursor
lcd.print(F("Aquarium takes X")); // Display Print
lcd.setCursor(0, 2); // Set The Display Cursor
lcd.print(F("percent of the sump")); // Display Print
lcd.setCursor(8, 3); // Set The Display Cursor
lcd.print(aquarium_PCT); // Display Print
if (aquarium_PCT < 10) lcd.setCursor(9, 3); // Set The Display Cursor
else if (aquarium_PCT >= 100) lcd.setCursor(11, 3); // Set The Display Cursor
else lcd.setCursor(10, 3); // Set The Display Cursor
lcd.print(F(".%")); // Display Print
_lastValue = aquarium_PCT; // Keep Track Of The Value
}
else if (_menuWindow == _MENU_PUMP_PROTECTION) { // Pump Protection Menu
lcd.setCursor(2, 2); // Set The Display Cursor
lcd.print(F("Pump protection:")); // Display Print
lcd.setCursor(9, 3); // Set The Display Cursor
if (virtual_Jumper) lcd.print(F("Off")); // Display Print - Jumper Is In Use
else lcd.print(F("On")); // Display Print - Jumper Is Not In Use
}
else if (_menuWindow == _MENU_ADD_WATER_ON) { // Add Water On Menu
lcd.setCursor(2, 2); // Set The Display Cursor
lcd.print(F("Add water on at:")); // Display Print
lcd.setCursor(7, 3); // Set The Display Cursor
lcd.print(add_WATER_ON, 1); // Display Print
lcd.setCursor(11, 3); // Set The Display Cursor
lcd.print(F(".%")); // Display Print
}
else if (_menuWindow == _MENU_ADD_WATER_TIMEOUT) { // Add Water Timeout
if (Add_Water_Timeout_State) { // If Add Water Timeout Is On
lcd.setCursor(1, 2); // Set The Display Cursor
lcd.print(F("Add water timeout:")); // Display Print
lcd.setCursor(9, 3); // Set The Display Cursor
lcd.print(F("On")); // Display Print - Add Water Timeout Is On
} else _menuWindow++; // Else If Add Water Timeout Is Off - Go To Next Menu
}
// Exit The Menu
if (_menuWindow >= _MENU_WINDOWS) { // Exit The Menu
delay(_BUTTON_DELAY); // Delay For Button
lcd.clear(); // Clear The Display
break; // Stop The While Loop
}
delay(_BUTTON_DELAY); // Delay For Button
_timeOut = millis(); // Keep Track Of The Time
}
}
// Store The Values To Eeprom - If They Change
if (_update_HEIGHT_TO_SENSOR) // Update Height To Sensor
EEPROM.put(HEIGHT_TO_SENSOR_ADD, height_TO_SENSOR); // Store The Height To Sensor Value
if (_update_MAX_WATER_HEIGHT) // Update MAX Water Height
EEPROM.put(MAX_WATER_HEIGHT_ADD, max_WATER_HEIGHT); // Store The Max Water Height Value
if (_update_AQUARIUM_PCT) // Update Aquarium Percent
EEPROM.put(AQUARIUM_PCT_ADD, aquarium_PCT); // Store The Aquarium Percent Value
if (_update_PUMP_PROTECTION) // Update Pump Protection - Virtual Jumper
EEPROM.put(VIRTUAL_JUMPER_ADD, virtual_Jumper); // Store The Virtual Jumper Value
if (_update_ADD_WATER_ON) // Update Add Water ON Value
EEPROM.put(ADD_WATER_ON_ADD, add_WATER_ON); // Store The Add Water On
// Set The MAX Water Height And Offset The Sensor
if (_update_HEIGHT_TO_SENSOR || _update_MAX_WATER_HEIGHT) { // Set The MAX Water Height And Offset The Sensor
max_Water_Level = (float)height_TO_SENSOR - ((float)max_WATER_HEIGHT + HCSR_OFFSET); // Set The MAX Water Height And Offset The Sensor
if (Serial_Print) { // Serial Print
Serial.print(F("Max Water Level In The Tank: "));
Serial.print(max_Water_Level, 1); Serial.println(F(".cm"));
}
}
// Set The Add Water Timeout & Turn The Add Water On If It Should Be On
if (Add_Water_Timeout_State != _add_Water_Timeout) { // Add Water Timeout State Did Changed
Add_Water_Timeout_State = _add_Water_Timeout; // Set The Add Water Timeout
}
if (Add_Water_State == ON && !Add_Water_Timeout_State) { // If The Add Water Was On Then Turn It Back On
if (percentage <= (ADD_WATER_OFF - 2.0F)) // Water Level Still Low
digitalWrite(ADD_WATER_PIN, ON); // Turn On Add Water Relay
else // Water Level Is Okay
Add_Water_State = OFF; // Add Water Relay State = OFF
}
// LCD Print Function
LCD_Print_Function(); // LCD Print Function
}
}
// End Of File.