#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include "loadingAnimation.h"
#define DHTPIN 4 // DHT sensor pin
#define DHTTYPE DHT11
#define ENCODER_CLK 3 // Rotary encoder CLK pin
#define ENCODER_DT 5 // Rotary encoder DT pin
#define BUTTON_PIN 2 // Rotary encoder button pin
#define DEBOUNCE_DELAY 50 // Short delay for debounce
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht(DHTPIN, DHTTYPE);
enum MenuState { MENU, SUBMENU };
MenuState currentState = MENU;
const char* menuItems[] = {"Temperature", "Humidity", "Option 1", "Message"};
const int totalMenuItems = sizeof(menuItems) / sizeof(menuItems[0]);
int selectedItem = 0;
int topItem = 0; // Tracks the top visible item
int lastEncoderCLK = HIGH; // To track the previous state of the CLK pin
void setup() {
lcd.begin(16, 2);
lcd.backlight();
Serial.begin(9600);
dht.begin();
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT_PULLUP);
loadingAnimation(lcd);
lcd.clear();
displayMenu();
}
void loop() {
handleRotaryEncoder();
handleButton();
delay(DEBOUNCE_DELAY); // Short delay for debounce
}
void handleRotaryEncoder() {
int currentEncoderCLK = digitalRead(ENCODER_CLK);
if (currentEncoderCLK != lastEncoderCLK && currentEncoderCLK == LOW) { // Detect falling edge
if (currentState == MENU) {
// Only allow scrolling in the main menu
if (digitalRead(ENCODER_DT) != currentEncoderCLK) {
// Clockwise rotation
selectedItem = (selectedItem + 1) % totalMenuItems;
} else {
// Counterclockwise rotation
selectedItem = (selectedItem - 1 + totalMenuItems) % totalMenuItems;
}
// Adjust the top item for scrolling if needed
if (selectedItem < topItem) {
topItem = selectedItem;
} else if (selectedItem >= topItem + 2) {
topItem = selectedItem - 1;
}
displayMenu();
}
}
lastEncoderCLK = currentEncoderCLK;
}
void handleButton() {
static int lastButtonState = HIGH;
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == LOW && lastButtonState == HIGH) {
// Button pressed
if (currentState == MENU) {
// Enter submenu
currentState = SUBMENU;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("< Main Menu");
showSubmenu();
} else if (currentState == SUBMENU) {
// Return to the main menu
currentState = MENU;
displayMenu();
}
}
lastButtonState = buttonState;
}
void displayMenu() {
lcd.clear();
for (int i = 0; i < 2; i++) { // Display up to 2 items at a time
int index = topItem + i;
if (index < totalMenuItems) {
lcd.setCursor(0, i);
lcd.print((index == selectedItem) ? "> " : " ");
lcd.print(menuItems[index]);
}
}
}
void showSubmenu() {
switch (selectedItem) {
case 0:
displayTemperature();
break;
case 1:
displayHumidity();
break;
case 2:
lcd.print("Option 1");
break;
case 3:
readMessage();
break;
}
}
void displayTemperature() {
lcd.setCursor(0, 1);
float temperature = dht.readTemperature();
if (isnan(temperature)) {
lcd.print("Sensor error!");
} else {
lcd.print("Temp: ");
lcd.print(temperature);
lcd.print("\xDF""C");
}
}
void displayHumidity() {
lcd.setCursor(0, 1);
float humidity = dht.readHumidity();
if (isnan(humidity)) {
lcd.print("Sensor error!");
} else {
lcd.print("Hum: ");
lcd.print(humidity);
lcd.print("%");
}
}
void readMessage() {
lcd.setCursor(0, 1);
lcd.print("Awaiting input...");
if (Serial.available() > 0) {
lcd.setCursor(0, 1);
lcd.print(" "); // Clear the previous message
String input = Serial.readStringUntil('\n'); // Read input from serial
lcd.setCursor(0, 1);
lcd.print(input);
}
}