#include <SD.h>
#include <RTClib.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
RTC_DS1307 rtc;
// Define buttons analog input pin and button values
#define BUTTON_RIGHT 0
#define BUTTON_UP 131
#define BUTTON_DOWN 306
#define BUTTON_LEFT 477
#define BUTTON_SELECT 720
#define BUTTON_PIN A0
// Relay pin
#define RELAY_PIN 2
// SD card pin
#define SD_CS_PIN 3
// Menu variables
int menuIndex = 0;
int menuItemCount = 3;
String menuItems[] = {"Measure", "SD Card", "Language"};
String menuItemsDutch[] = {"Start Maatregel", "SD Kaart", "Taal"};
String languageOptions[] = {"English", "Dutch"};
int languageIndex = 0;
// Timing variables
unsigned long previousMillis = 0;
const long interval = 1000;
unsigned long measurementStartMillis = 0;
bool isMeasuring = false;
bool isHeating = false;
int measurementPhase = 0; // 0: Not started, 1: Heating, 2: Cooling
int measurementCounter = 0;
int heatingTime = 5;
String fileName = "";
// File list variables
const int maxFiles = 20;
String fileList[maxFiles];
int fileCount = 0;
int fileIndex = 0;
File roots;
int selectB = A1;
int upB = A2;
int dnB = A3;
int lftB = 2;
bool UseExtButtons = true;
void setup() {
// Initialize serial communication
Serial.begin(9600);
// Initialize LCD
lcd.begin(16, 2);
lcd.print(languageIndex == 0 ? "Initializing..." : "Initialiseren...");
// Initialize RTC
if (!rtc.begin()) {
lcd.setCursor(0, 1);
lcd.print(languageIndex == 0 ? "RTC Init Failed!" : "RTC Init Mislukt!");
while (1);
}
//if (!rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
//}
DateTime now = rtc.now();
Serial.println(now.timestamp(DateTime::TIMESTAMP_FULL));
// Initialize SD card
if (!SD.begin(SD_CS_PIN)) {
lcd.setCursor(0, 1);
lcd.print(languageIndex == 0 ? "SD Init Failed!" : "SD Init Mislukt!");
while (1);
}
// Initialize relay pin
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
// Clear LCD
lcd.clear();
showMenu();
if(UseExtButtons){
pinMode(selectB, INPUT_PULLUP);
pinMode(upB, INPUT_PULLUP);
pinMode(dnB, INPUT_PULLUP);
pinMode(lftB, INPUT_PULLUP);
}
}
void loop() {
unsigned long currentMillis = millis();
if (isMeasuring) {
handleMeasurement(currentMillis);
} else {
int button = readButton();
//Serial.println(button);
handleMenu(button);
}
}
int readButton() {
if(!UseExtButtons){
int adcKeyIn = analogRead(BUTTON_PIN);
if (adcKeyIn <= BUTTON_RIGHT + 2 && adcKeyIn > BUTTON_RIGHT -2) return 0;
if (adcKeyIn <= BUTTON_UP + 2 && adcKeyIn > BUTTON_UP -2) return 1;
if (adcKeyIn <= BUTTON_DOWN + 2 && adcKeyIn > BUTTON_DOWN -2) return 2;
if (adcKeyIn <= BUTTON_LEFT + 2 && adcKeyIn > BUTTON_LEFT -2) return 3;
if (adcKeyIn <= BUTTON_SELECT + 2 && adcKeyIn > BUTTON_SELECT -2) return 4;
return -1;
}
else{
if(!digitalRead(selectB))
return 4;
if(!digitalRead(upB))
return 1;
if(!digitalRead(dnB))
return 2;
if(!digitalRead(lftB))
return 3;
return -1;
}
}
void handleMenu(int button) {
if (button == 1) { // Up
delay(250);
menuIndex = (menuIndex - 1 + 3) % 3;
showMenu();
} else if (button == 2) { // Down
delay(250);
menuIndex = (menuIndex + 1) % 3;
showMenu();
} else if (button == 4) { // Select
delay(250);
executeMenu();
}
}
void showMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("> ");
lcd.print(languageIndex == 0 ? menuItems[menuIndex] : menuItemsDutch[menuIndex]);
lcd.setCursor(2, 1);
int n = (menuIndex + 1) % menuItemCount;
lcd.print(languageIndex == 0 ? menuItems[n] : menuItemsDutch[n]);
}
void executeMenu() {
switch (menuIndex) {
case 0:
startMeasurement();
break;
case 1:
sdCardMenu();
break;
case 2:
languageMenu();
break;
}
}
void startMeasurement() {
lcd.clear();
lcd.print(languageIndex == 0 ? "Starting..." : "Beginnen...");
delay(1000);
isMeasuring = true;
measurementPhase = 1; // Start with heating
measurementCounter = 0;
measurementStartMillis = millis();
fileName = createFileName();
Serial.println(fileName);
lcd.clear();
lcd.print(languageIndex == 0 ? "Heating..." : "Verwarmen...");
digitalWrite(RELAY_PIN, HIGH);
}
void handleMeasurement(unsigned long currentMillis) {
if (currentMillis - previousMillis >= interval) {
lcd.setCursor(0,1);
lcd.print(String(heatingTime - measurementCounter) + "s");
Serial.println("HandleMeasurement");
previousMillis = currentMillis;
File dataFile = SD.open(fileName, FILE_WRITE);
delay(1000);
if (!dataFile) {
lcd.clear();
lcd.print(languageIndex == 0 ? "File Error!" : "Bestandsfout!");
delay(2000);
isMeasuring = false;
showMenu();
return;
}
logTemperature(dataFile);
dataFile.close();
measurementCounter++;
if (measurementPhase == 1 && measurementCounter >= heatingTime) {
measurementPhase = 2; // Switch to cooling
measurementCounter = 0;
digitalWrite(RELAY_PIN, LOW);
lcd.clear();
lcd.print(languageIndex == 0 ? "Cooling..." : "Koeling...");
} else if (measurementPhase == 2 && measurementCounter >= heatingTime) {
isMeasuring = false;
lcd.clear();
lcd.print(languageIndex == 0 ? "Complete!" : "Compleet!");
delay(2000);
showMenu();
}
}
}
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
String createFileName() {
// int n = countFilesInSD() + 1;
// n++;
// String s = "File" + String(n) + ".txt";
return "File" + String(countFilesInSD() + 1) + ".txt";
//return "log1.txt";
}
int countFilesInSD() {
Serial.println("Counting");
File root = SD.open("/");
int count = 0;
while (true) {
File entry = root.openNextFile();
if (!entry) {
Serial.println("Failed");
break;
}
if (!entry.isDirectory() && count < maxFiles) {
fileList[count] = entry.name();
Serial.println(entry.name());
count++;
}
entry.close();
}
Serial.println(count);
return count;
}
void logTemperature(File& dataFile) {
DateTime now = rtc.now();
float temperature = 0;//dht.readTemperature();
dataFile.print(now.timestamp(DateTime::TIMESTAMP_FULL));
dataFile.print(", ");
dataFile.println(temperature);
}
void showFileList(int n){
lcd.clear();
lcd.print("> ");
lcd.print(fileList[n]);
if(n < fileCount - 1){
lcd.setCursor(2, 1);
lcd.print(fileList[n + 1]);
}
}
void sdCardMenu() {
fileCount = countFilesInSD();
lcd.clear();
lcd.print(languageIndex == 0 ? "Files: " : "Bestanden: ");
lcd.print(fileCount);
delay(2000);
int showIndex = 0;
bool showingItems = true;
showFileList(showIndex);
while(showingItems){
int button = readButton();
if(button == 2){ // Down
delay(250);
showIndex++;
if(showIndex > fileCount - 1){
showIndex = fileCount - 1;
}
showFileList(showIndex);
}
if(button == 1){ // Up
delay(250);
showIndex--;
if(showIndex < 0){
showIndex = 0;
}
showFileList(showIndex);
}
if(button == 3){ // Left
delay(250);
showingItems = false;
}
if (button == 4) { // Select
delay(250);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(languageIndex == 0 ? "Delete file?" : "Verwijder bestand?");
lcd.setCursor(0, 1);
lcd.print(languageIndex == 0 ? "Yes / No" : "Ja / Nee");
bool DoDeleteFile = true;
while (DoDeleteFile) {
button = readButton();
if (button == 4) { // Select (Yes)
SD.remove(fileList[showIndex].c_str());
lcd.clear();
lcd.print(languageIndex == 0 ? "Deleted!" : "Verwijderd!");
for(int i = 0; i < maxFiles; i++){
fileList[i] = "";
}
delay(1000);
DoDeleteFile = false;
} else if (button == 3) { // Left (No)
lcd.clear();
lcd.print(languageIndex == 0 ? "Cancelled!" : "Geannuleerd!");
delay(1000);
DoDeleteFile = false;
}
}
}
}
showMenu();
}
void languageMenu() {
lcd.clear();
lcd.print(languageIndex == 0 ? "Select Language:" : "Selecteer Taal:");
delay(1000);
lcd.clear();
lcd.print(languageOptions[languageIndex]);
int button;
while (true) {
button = readButton();
if (button == 1) { // Up
languageIndex = (languageIndex - 1 + 2) % 2;
lcd.clear();
lcd.print(languageOptions[languageIndex]);
} else if (button == 2) { // Down
languageIndex = (languageIndex + 1) % 2;
lcd.clear();
lcd.print(languageOptions[languageIndex]);
} else if (button == 4) { // Select
break;
}
delay(500);
}
lcd.clear();
lcd.print(languageIndex == 0 ? "Selected: " : "Geselecteerd: ");
lcd.setCursor(0, 1);
lcd.print(languageOptions[languageIndex]);
delay(1000);
showMenu();
}