#include <LiquidCrystal.h>
#include <NewPing.h>
#include <SimpleDHT.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
// Pin definities
#define TRIGGER_PIN 13
#define ECHO_PIN 13
#define TEMP_PIN A0
#define BUTTON_PIN 2
#define LED_LOW 5 // RED
#define LED_MEDIUM 4 // YELLOW
#define LED_HIGH 3 // GREEN
#define LDR_PIN A1 // Pin voor de LDR
#define LCD_BACKLIGHT_PIN 6 // Pin voor de LCD-achtergrondverlichting
#define RELAY_PIN A2 // Pin voor het relais
#define RED_LED_PIN 0 // Pin voor de rode WAARSCHUWINGS/ALARM LED
// LCD pinnen: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
NewPing sonar(TRIGGER_PIN, ECHO_PIN, 200); // Maximum ultrasone sensorafstand 200 cm
SimpleDHT11 dht11(TEMP_PIN);
const int numReadings = 12; // Aantal metingen voor filtering
int readings[numReadings]; // Array voor metingen
int readIndex = 0; // Huidige index van de array
int total = 0; // Totale som van de metingen
int average = 0; // Gemiddelde van de metingen
unsigned long previousMillis = 0; // Tijdstip van de laatste meting
const long interval = 180000; // Interval tussen metingen (3 minuten)
unsigned long pumpStartTime = 0; // Tijdstip van het starten van de pomp
const long pumpDuration = 900000; // Duur van de pompwerking (15 minuten)
unsigned long ledBlinkMillis = 0; // Tijdstip van de laatste LED-knippering
const long ledBlinkInterval = 500; // Interval voor LED-knippering
unsigned long buttonHoldStartTime = 0; // Tijdstip van het ingedrukt houden van de knop
unsigned long lastDebounceTime = 0; // Tijdstip van de laatste knopverandering
const long debounceDelay = 50; // Debounce vertraging in milliseconden
volatile bool buttonPressed = false; // Variabele om knopdruk bij te houden
volatile unsigned long buttonPressTime = 0; // Tijdstip van knopdruk
volatile bool longPressDetected = false; // Variabele om lange druk te detecteren
volatile bool pumpActive = false; // Variabele om de pompstatus bij te houden
volatile bool pumpPaused = false; // Variabele om de pomp-pauzestatus bij te houden
int maxWaterHeight = 180; // Maximale waterhoogte in cm
int minWaterThreshold = 50; // Minimale waterdrempel in cm
void setup() {
lcd.begin(16, 2); // Initialiseer het LCD-scherm
pinMode(BUTTON_PIN, INPUT); // Stel de knop in als invoer
pinMode(LED_LOW, OUTPUT); // Stel de LED's in als uitvoer
pinMode(LED_MEDIUM, OUTPUT);
pinMode(LED_HIGH, OUTPUT);
pinMode(LCD_BACKLIGHT_PIN, OUTPUT); // Stel de LCD-achtergrondverlichting in als uitvoer
pinMode(RELAY_PIN, OUTPUT); // Stel het relais in als uitvoer
pinMode(RED_LED_PIN, OUTPUT); // Stel de rode LED in als uitvoer
lcd.noDisplay(); // Zet het LCD-scherm uit om stroom te besparen
// Interrupt voor de knop
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, CHANGE);
// Zet de Arduino in slaapmodus
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
}
void loop() {
unsigned long currentMillis = millis();
// Controleer of het tijd is voor een nieuwe meting
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
total = total - readings[readIndex]; // Verwijder de oude meting uit de som
readings[readIndex] = getFilteredDistance(); // Voeg de nieuwe meting toe
total = total + readings[readIndex]; // Voeg de nieuwe meting toe aan de som
readIndex = (readIndex + 1) % numReadings; // Verhoog de index en reset indien nodig
average = total / numReadings; // Bereken het gemiddelde
updateLEDs(average); // Werk de LED's bij op basis van de nieuwe meting
// Controleer of het waterniveau onder de minimale drempel is
if (average < minWaterThreshold && !pumpActive && !pumpPaused) {
activatePump(); // Activeer de pomp
}
}
// Controleer of de knop kort is ingedrukt
if (buttonPressed) {
buttonPressed = false;
adjustBacklight(); // Pas de achtergrondverlichting aan op basis van de LDR
lcd.display(); // Zet het LCD-scherm aan
lcd.setCursor(0, 0);
lcd.print("Waterstand: ");
lcd.print(average);
lcd.print(" cm");
lcd.setCursor(0, 1);
lcd.print("Temp: ");
lcd.print(getTemperature());
lcd.print(" C");
displayWaterLevel(average); // Toon de grafische weergave van de waterhoogte
delay(5000); // Wacht 5 seconden
lcd.noDisplay(); // Zet het LCD-scherm weer uit
}
// Controleer of de knop lang is ingedrukt
if (longPressDetected) {
longPressDetected = false;
adjustWaterLevels(); // Pas de waterniveaus aan indien nodig
}
// Controleer of de pomp actief is en de tijd is verstreken
if (pumpActive) {
unsigned long elapsedMillis = currentMillis - pumpStartTime;
if (elapsedMillis >= pumpDuration) {
deactivatePump(); // Deactiveer de pomp
displayNewWaterLevel(); // Toon het nieuwe waterniveau
} else {
displayPumpTimer(pumpDuration - elapsedMillis); // Toon de afteltimer
}
}
// Laat de rode LED knipperen als de pomp actief is
if (pumpActive && (currentMillis - ledBlinkMillis >= ledBlinkInterval)) {
ledBlinkMillis = currentMillis;
blinkRedLED(); // Wissel de status van de rode LED
}
// Controleer of de knop tijdens het pompen meer dan 10 seconden is ingedrukt
if (pumpActive && digitalRead(BUTTON_PIN) == HIGH) {
if (buttonHoldStartTime == 0) {
buttonHoldStartTime = currentMillis;
} else if (currentMillis - buttonHoldStartTime >= 10000) {
pausePump(); // Pauzeer de pomp
askToContinuePumping(); // Vraag of er verder gepompt mag worden
buttonHoldStartTime = 0; // Reset de knop-houdtijd
}
} else {
buttonHoldStartTime = 0; // Reset de knop-houdtijd als de knop niet ingedrukt is
}
// Zet de Arduino in slaapmodus om stroom te besparen
sleep_cpu();
}
// Functie om gefilterde afstand te verkrijgen
int getFilteredDistance() {
int distances[numReadings];
for (int i = 0; i < numReadings; i++) {
distances[i] = getCorrectedDistance(); // Verkrijg gecorrigeerde afstand
delay(50); // Korte pauze tussen metingen
}
return median(distances, numReadings); // Bereken de mediane waarde
}
// Functie om gecorrigeerde afstand te verkrijgen
int getCorrectedDistance() {
float temperature = getTemperature(); // Verkrijg de temperatuur
float speedOfSound = 331.3 + 0.606 * temperature; // Snelheid van geluid in m/s
float distance = sonar.ping_cm(); // Verkrijg de afstand in cm
return distance * (331.3 / speedOfSound); // Corrigeer de afstand voor temperatuur
}
// Functie om de mediane waarde van een array te berekenen
int median(int *array, int size) {
int sorted[size];
memcpy(sorted, array, size * sizeof(int)); // Kopieer de array
sort(sorted, size); // Sorteer de array
return sorted[size / 2]; // Retourneer de mediane waarde
}
// Functie om een array te sorteren
void sort(int *array, int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (array[i] > array[j]) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
// Functie om de temperatuur te verkrijgen
float getTemperature() {
byte temperature = 0;
dht11.read(&temperature, NULL, NULL); // Lees de temperatuur uit de DHT11 sensor
return temperature;
}
// Functie om de LED's bij te werken op basis van de gemeten afstand
void updateLEDs(int distance) {
if (distance < minWaterThreshold) {
digitalWrite(LED_LOW, HIGH);
digitalWrite(LED_MEDIUM, LOW);
digitalWrite(LED_HIGH, LOW);
} else if (distance < maxWaterHeight) {
digitalWrite(LED_LOW, LOW);
digitalWrite(LED_MEDIUM, HIGH);
digitalWrite(LED_HIGH, LOW);
} else {
digitalWrite(LED_LOW, LOW);
digitalWrite(LED_MEDIUM, LOW);
digitalWrite(LED_HIGH, HIGH);
}
}
// Functie om de waterniveaus aan te passen indien nodig
void adjustWaterLevels() {
int currentDistance = getFilteredDistance(); // Verkrijg de huidige afstand
// Controleer of de maximale hoogte verhoogd kan worden
if (currentDistance > maxWaterHeight) {
maxWaterHeight = currentDistance;
}
// Controleer of de minimale waterdrempel verlaagd kan worden
if (currentDistance < minWaterThreshold) {
minWaterThreshold = currentDistance;
}
// Toon de nieuwe waarden op het LCD-scherm
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Max hoogte: ");
lcd.print(maxWaterHeight);
lcd.print(" cm");
lcd.setCursor(0, 1);
lcd.print("Min drempel: ");
lcd.print(minWaterThreshold);
lcd.print(" cm");
delay(5000); // Wacht 5 seconden
lcd.noDisplay(); // Zet het LCD-scherm weer uit
}
// Functie om de grafische weergave van de waterhoogte te tonen
void displayWaterLevel(int waterHeight) {
int barLength = map(waterHeight, 0, maxWaterHeight, 0, 16); // Bereken de lengte van de balk
lcd.setCursor(0, 1);
for (int i = 0; i < barLength; i++) {
lcd.write(byte(255)); // Teken de balk
}
for (int i = barLength; i < 16; i++) {
lcd.write(' '); // Vul de rest van de regel met spaties
}
}
// Functie om de achtergrondverlichting aan te passen op basis van de LDR
void adjustBacklight() {
int ldrValue = analogRead(LDR_PIN); // Lees de waarde van de LDR
int backlightValue = map(ldrValue, 0, 1023, 0, 255); // Schaal de waarde naar 0-255
analogWrite(LCD_BACKLIGHT_PIN, backlightValue); // Pas de achtergrondverlichting aan
}
// Functie om de pomp te activeren
void activatePump() {
analogWrite(RELAY_PIN, 1023); // Schakel het relais in
pumpStartTime = millis(); // Noteer het tijdstip van het starten van de pomp
pumpActive = true; // Zet de pompstatus op actief
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Pomp actief!");
lcd.setCursor(0, 1);
lcd.print("Water laag!");
showWarning(); // Toon de waarschuwing
}
// Functie om de pomp te deactiveren
void deactivatePump() {
analogWrite(RELAY_PIN, 0); // Schakel het relais uit
pumpActive = false; // Zet de pompstatus op inactief
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Pomp uit!");
lcd.setCursor(0, 1);
lcd.print("Water OK");
delay(5000); // Wacht 5 seconden
lcd.noDisplay(); // Zet het LCD-scherm weer uit
}
// Functie om de pomp te pauzeren
void pausePump() {
analogWrite(RELAY_PIN, 0); // Schakel het relais uit
pumpActive = false; // Zet de pompstatus op inactief
pumpPaused = true; // Zet de pomp-pauzestatus op actief
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Pomp gepauzeerd");
lcd.setCursor(0, 1);
lcd.print("Verder pompen?");
delay(5000); // Wacht 5 seconden
lcd.noDisplay(); // Zet het LCD-scherm weer uit
}
// Functie om de rode LED te laten knipperen
void blinkRedLED() {
static bool ledState = false;
ledState = !ledState;
digitalWrite(RED_LED_PIN, ledState);
}
// Functie om de waarschuwing te tonen en te verwijderen bij knopdruk
void showWarning() {
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Waarschuwing!");
lcd.setCursor(0, 1);
lcd.print("Pomp actief!");
}
void clearWarning() {
lcd.noDisplay(); // Zet het LCD-scherm uit
digitalWrite(RED_LED_PIN, LOW); // Zet de rode LED uit
}
// Functie om de timer weer te geven
void displayPumpTimer(unsigned long remainingMillis) {
int remainingSeconds = remainingMillis / 1000;
int minutes = remainingSeconds / 60;
int seconds = remainingSeconds % 60;
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Pomp actief: ");
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) {
lcd.print("0");
}
lcd.print(seconds);
lcd.setCursor(0, 1);
lcd.print("Water laag!");
}
// Functie om het nieuwe waterniveau weer te geven
void displayNewWaterLevel() {
int newWaterLevel = getFilteredDistance(); // Verkrijg het nieuwe waterniveau
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Nieuw niveau: ");
lcd.print(newWaterLevel);
lcd.print(" cm");
lcd.setCursor(0, 1);
lcd.print("Pomp uit!");
delay(5000); // Wacht 5 seconden
lcd.noDisplay(); // Zet het LCD-scherm weer uit
}
// Functie om te vragen of er verder gepompt mag worden
void askToContinuePumping() {
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Verder pompen?");
lcd.setCursor(0, 1);
lcd.print("Druk op knop");
unsigned long startMillis = millis();
while (millis() - startMillis < 5000) {
if (digitalRead(BUTTON_PIN) == HIGH) {
resumePump(); // Hervat het pompen
return;
}
}
lcd.noDisplay(); // Zet het LCD-scherm weer uit
}
// Functie om het pompen te hervatten
void resumePump() {
analogWrite(RELAY_PIN, 1023); // Schakel het relais in
pumpStartTime = millis(); // Reset de starttijd van de pomp
pumpActive = true; // Zet de pompstatus op actief
pumpPaused = false; // Zet de pomp-pauzestatus op inactief
lcd.display();
lcd.setCursor(0, 0);
lcd.print("Pomp hervat!");
lcd.setCursor(0, 1);
lcd.print("Water laag!");
delay(5000); // Wacht 5 seconden
lcd.noDisplay(); // Zet het LCD-scherm weer uit
}
// Interrupt service routine voor de knop
void buttonISR() {
unsigned long currentMillis = millis();
if ((currentMillis - lastDebounceTime) > debounceDelay) {
if (digitalRead(BUTTON_PIN) == HIGH) {
buttonPressTime = currentMillis; // Noteer het tijdstip van de knopdruk
} else {
if ((currentMillis - buttonPressTime) >= 3000) {
longPressDetected = true; // Lange druk gedetecteerd
} else {
buttonPressed = true; // Korte druk gedetecteerd
clearWarning(); // Verwijder de waarschuwing bij knopdruk
}
}
lastDebounceTime = currentMillis; // Reset de debounce timer
}
}