From 195d753d812eae5544603ddc5a69f3d07d8dd5b2 Mon Sep 17 00:00:00 2001 From: Armel van Ravels Date: Mon, 4 May 2026 22:30:50 +0200 Subject: [PATCH] Complete rewrite of Application --- Button.cpp | 62 +++++++++++++ Button.h | 31 +++++++ DisplayManager.cpp | 34 +++++++ DisplayManager.h | 27 ++++++ Menu.cpp | 72 +++++++++++++++ Menu.h | 37 ++++++++ SensorManager.cpp | 26 ++++++ SensorManager.h | 25 +++++ drybox.ino | 226 +++++++++------------------------------------ 9 files changed, 360 insertions(+), 180 deletions(-) create mode 100644 Button.cpp create mode 100644 Button.h create mode 100644 DisplayManager.cpp create mode 100644 DisplayManager.h create mode 100644 Menu.cpp create mode 100644 Menu.h create mode 100644 SensorManager.cpp create mode 100644 SensorManager.h diff --git a/Button.cpp b/Button.cpp new file mode 100644 index 0000000..250c0f2 --- /dev/null +++ b/Button.cpp @@ -0,0 +1,62 @@ +#include "Button.h" + +Button::Button(uint8_t pin) + : pin(pin), + stableState(HIGH), + lastReading(HIGH), + prevStableState(HIGH), + lastDebounceTime(0), + pressStart(0) {} + +void Button::begin() { + pinMode(pin, INPUT_PULLUP); + + stableState = digitalRead(pin); + lastReading = stableState; + prevStableState = stableState; + + lastDebounceTime = millis(); + + if (stableState == LOW) { + pressStart = millis(); + } +} + +void Button::update(unsigned long now) { + prevStableState = stableState; + + bool reading = digitalRead(pin); + + if (reading != lastReading) { + lastDebounceTime = now; + lastReading = reading; + } + + if ((now - lastDebounceTime) > debounceDelay) { + if (stableState != reading) { + stableState = reading; + + // Button just became pressed (active LOW) + if (stableState == LOW) { + pressStart = now; + } + } + } +} + +bool Button::pressed() { + return (prevStableState == HIGH && stableState == LOW); +} + +bool Button::released() { + return (prevStableState == LOW && stableState == HIGH); +} + +bool Button::isDown() { + return stableState == LOW; +} + +bool Button::held(unsigned long ms) { + if (!isDown()) return false; + return (millis() - pressStart >= ms); +} \ No newline at end of file diff --git a/Button.h b/Button.h new file mode 100644 index 0000000..ee9316a --- /dev/null +++ b/Button.h @@ -0,0 +1,31 @@ +#ifndef BUTTON_H +#define BUTTON_H + +#include + +class Button { +private: + uint8_t pin; + + bool stableState; + bool lastReading; + bool prevStableState; + + unsigned long lastDebounceTime; + const unsigned long debounceDelay = 50; + + unsigned long pressStart; + +public: + Button(uint8_t pin); + + void begin(); + void update(unsigned long now); + + bool pressed(); + bool released(); + bool isDown(); + bool held(unsigned long ms); +}; + +#endif \ No newline at end of file diff --git a/DisplayManager.cpp b/DisplayManager.cpp new file mode 100644 index 0000000..90aff00 --- /dev/null +++ b/DisplayManager.cpp @@ -0,0 +1,34 @@ +#include "DisplayManager.h" + +DisplayManager::DisplayManager() + : lcd(0x27, 16, 2), lastUpdate(0) {} + +void DisplayManager::begin() { + lcd.init(); + lcd.backlight(); + lcd.setCursor(0, 0); + lcd.print("Humidity controll"); +} + +bool DisplayManager::ready(unsigned long now) { + if (now - lastUpdate < interval) return false; + lastUpdate = now; + return true; +} + +void DisplayManager::showText(String line1, String line2) { + if (line1 == lastLine1 && line2 == lastLine2) { + return; + } + + lastLine1 = line1; + lastLine2 = line2; + + lcd.clear(); + + lcd.setCursor(0, 0); + lcd.print(line1); + + lcd.setCursor(0, 1); + lcd.print(line2); +} \ No newline at end of file diff --git a/DisplayManager.h b/DisplayManager.h new file mode 100644 index 0000000..afbffa6 --- /dev/null +++ b/DisplayManager.h @@ -0,0 +1,27 @@ +#ifndef DISPLAY_MANAGER_H +#define DISPLAY_MANAGER_H + +#include +#include + +class DisplayManager { +private: + LiquidCrystal_I2C lcd; + + unsigned long lastUpdate; + const unsigned long interval = 1000; + + String lastLine1; + String lastLine2; + +public: + DisplayManager(); + + void begin(); + + bool ready(unsigned long now); + + void showText(String line1, String line2); +}; + +#endif \ No newline at end of file diff --git a/Menu.cpp b/Menu.cpp new file mode 100644 index 0000000..7878aee --- /dev/null +++ b/Menu.cpp @@ -0,0 +1,72 @@ +#include "Menu.h" + +Menu::Menu() { + type = MENU_MAIN; + index = 0; +} + +int Menu::getSize(MenuType type) { + switch (type) { + case MENU_MAIN: return MAIN_SIZE; + case MENU_SETUP: return SETUP_SIZE; + } + return 0; +} + +const char* Menu::getItem(MenuType type, int index) { + switch (type) { + case MENU_MAIN: + switch (index) { + case 0: return "Start"; + case 1: return "Setup"; + case 2: return "Version"; + } + break; + + case MENU_SETUP: + switch (index) { + case 0: return "Temperature"; + case 1: return "Humidity"; + case 2: return "Back"; + } + break; + } + + return ""; +} + +void Menu::next() { + index = (index + 1) % getSize(type); +} + +void Menu::prev() { + index--; + if (index < 0) index = getSize(type) - 1; +} + +void Menu::enter() { + if (type == MENU_MAIN) { + if (index == 1) type = MENU_SETUP; + } + index = 0; +} + +void Menu::back() { + if (type != MENU_MAIN) { + type = MENU_MAIN; + index = 0; + } +} + +const char* Menu::getCurrent() { + return getItem(type, index); +} + +const char* Menu::getNext() { + int nextIndex = (index + 1) % getSize(type); + return getItem(type, nextIndex); +} + +MenuType Menu::getType() { + return type; +} \ No newline at end of file diff --git a/Menu.h b/Menu.h new file mode 100644 index 0000000..92d0f73 --- /dev/null +++ b/Menu.h @@ -0,0 +1,37 @@ +#ifndef MENU_H +#define MENU_H + +#include + +enum MenuType { + MENU_MAIN, + MENU_SETUP, +}; + +class Menu { +private: + MenuType type; + int index; + + static const int MAIN_SIZE = 3; + static const int SETUP_SIZE = 3; + + const char* getItem(MenuType type, int index); + int getSize(MenuType type); + +public: + Menu(); + + void next(); + void prev(); + + void enter(); + void back(); + + const char* getCurrent(); + const char* getNext(); + + MenuType getType(); +}; + +#endif \ No newline at end of file diff --git a/SensorManager.cpp b/SensorManager.cpp new file mode 100644 index 0000000..6c77d0c --- /dev/null +++ b/SensorManager.cpp @@ -0,0 +1,26 @@ +#include "SensorManager.h" + +SensorManager::SensorManager(uint8_t pin) + : sensor(pin), temperature(NAN), humidity(NAN), lastRead(0) {} + +void SensorManager::begin() { + sensor.begin(); +} + +void SensorManager::update(unsigned long now) { + if (now - lastRead < interval) return; + lastRead = now; + + if (sensor.read() == AM2302::AM2302_READ_OK) { + humidity = sensor.get_Humidity(); + temperature = sensor.get_Temperature(); + } +} + +float SensorManager::getTemp() const { + return temperature; +} + +float SensorManager::getHumidity() const { + return humidity; +} \ No newline at end of file diff --git a/SensorManager.h b/SensorManager.h new file mode 100644 index 0000000..d1cc0d9 --- /dev/null +++ b/SensorManager.h @@ -0,0 +1,25 @@ +#ifndef SENSOR_MANAGER_H +#define SENSOR_MANAGER_H + +#include + +class SensorManager { +private: + AM2302::AM2302_Sensor sensor; + float temperature; + float humidity; + + unsigned long lastRead; + const unsigned long interval = 2000; + +public: + SensorManager(uint8_t pin); + + void begin(); + void update(unsigned long now); + + float getTemp() const; + float getHumidity() const; +}; + +#endif \ No newline at end of file diff --git a/drybox.ino b/drybox.ino index e448d71..6fc338a 100644 --- a/drybox.ino +++ b/drybox.ino @@ -1,192 +1,58 @@ -#include -#include +#include "DisplayManager.h" +#include "SensorManager.h" +#include "Button.h" +#include "Menu.h" -LiquidCrystal_I2C lcd(0x27, 16, 2); +DisplayManager display; +SensorManager sensor(7); -constexpr unsigned int SENSOR_PIN {7U}; -AM2302::AM2302_Sensor am2302{SENSOR_PIN}; +Button downButton(8); +Button upButton(9); +Button okButton(10); +Button backButton(11); -const int potPin = A1; -const int buttonPin = 8; +Menu menu; - -// ---------------- STATE MACHINE ---------------- -enum State { - SET_MAX_TEMP, - SET_HUMIDITY, - CONFIRM, - VIEW -}; - -State state = SET_MAX_TEMP; - -// ---------------- SENSOR VALUES ---------------- -float temperature = NAN; -float humidity = NAN; - -// ---------------- SETTINGS ---------------- -float maxTemperature = 30.0; -float targetHumidity = 50.0; - -// ---------------- CONFIRM ---------------- -bool confirmYes = false; - -// ---------------- TIMING ---------------- -unsigned long lastLcdUpdate = 0; -unsigned long lastSensorRead = 0; - -const unsigned long lcdInterval = 500; -const unsigned long sensorInterval = 2000; - -// ---------------- BUTTON ---------------- -bool lastButtonState = HIGH; - -// ---------------- SENSOR ---------------- -void readSensor(unsigned long now) { - if (now - lastSensorRead >= sensorInterval) { - lastSensorRead = now; - - if (am2302.read() == AM2302::AM2302_READ_OK) { - humidity = am2302.get_Humidity(); - temperature = am2302.get_Temperature(); - } - } -} - -// ---------------- BUTTON HANDLER ---------------- -void handleButton() { - static bool lastReading = HIGH; - static unsigned long lastDebounce = 0; - const unsigned long debounceDelay = 50; - - bool reading = digitalRead(buttonPin); - - if (lastReading == HIGH && reading == LOW) { - - // CONFIRM LOGIC - if (state == CONFIRM) { - - if (confirmYes) { - state = VIEW; // accept settings - } else { - state = SET_MAX_TEMP; // restart setup - } - } - else { - // NORMAL FLOW - if (state == SET_MAX_TEMP) { - state = SET_HUMIDITY; - } - else if (state == SET_HUMIDITY) { - state = CONFIRM; - } - else if (state == VIEW) { - state = SET_MAX_TEMP; - } - } - } - - lastReading = reading; -} - -// ---------------- LCD ---------------- -void updateLCD(unsigned long now) { - if (now - lastLcdUpdate < lcdInterval) return; - lastLcdUpdate = now; - - lcd.clear(); - - int potValue = analogRead(potPin); - - // ---------------- SET MAX TEMP ---------------- - if (state == SET_MAX_TEMP) { - maxTemperature = map(potValue, 0, 1023, 20, 60); - - lcd.setCursor(0, 0); - lcd.print("Set Max Temp:"); - - lcd.setCursor(0, 1); - lcd.print(maxTemperature); - lcd.print(" C"); - - return; - } - - // ---------------- SET HUMIDITY ---------------- - if (state == SET_HUMIDITY) { - targetHumidity = map(potValue, 0, 1023, 0, 80); - - lcd.setCursor(0, 0); - lcd.print("Set Humidity:"); - - lcd.setCursor(0, 1); - lcd.print(targetHumidity); - lcd.print("%"); - - return; - } - - // ---------------- CONFIRM ---------------- - if (state == CONFIRM) { - - confirmYes = (potValue < 512); - - lcd.setCursor(0, 0); - lcd.print("Confirm Settings"); - - lcd.setCursor(0, 1); - - if (confirmYes) { - lcd.print("> YES NO"); - } else { - lcd.print(" YES > NO"); - } - - return; - } - - // ---------------- VIEW MODE ---------------- - lcd.setCursor(0, 0); - lcd.print("AH:"); - lcd.print(humidity); - lcd.print("%"); - - lcd.setCursor(0, 1); - lcd.print("AT:"); - lcd.print(temperature); - lcd.print("C"); - - // show target humidity - - // show target - lcd.setCursor(10, 1); - lcd.print("TH:"); - lcd.print(targetHumidity); - - // show target - lcd.setCursor(10, 0); - lcd.print("TT:"); - lcd.print(maxTemperature); -} - -// ---------------- SETUP ---------------- void setup() { - lcd.init(); - lcd.backlight(); + display.begin(); + sensor.begin(); - am2302.begin(); - - pinMode(buttonPin, INPUT_PULLUP); - - lcd.setCursor(0, 0); - lcd.print("System Start"); + upButton.begin(); + downButton.begin(); + okButton.begin(); + backButton.begin(); } -// ---------------- LOOP ---------------- void loop() { unsigned long now = millis(); - handleButton(); - readSensor(now); - updateLCD(now); + upButton.update(now); + downButton.update(now); + okButton.update(now); + backButton.update(now); + + sensor.update(now); + + if (upButton.pressed()) { + menu.prev(); + } + + if (downButton.pressed()) { + menu.next(); + } + + if (okButton.pressed()) { + menu.enter(); + } + + if(backButton.pressed()) { + menu.back(); + } + + if (display.ready(now)) { + display.showText( + String("> ") + menu.getCurrent(), + String(" ") + menu.getNext() + ); + } } \ No newline at end of file