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