Created
June 11, 2025 08:53
-
-
Save ajangrahmat/66c0245f0dbe6a67518e1845bfe10f29 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* SISTEM MONITORING LINGKUNGAN CANGGIH | |
* Arduino Uno R3 - Proyek Kompleks dengan 10+ Library | |
* | |
* Fitur: | |
* - Monitoring suhu dan kelembaban DHT22 | |
* - Sensor cahaya LDR | |
* - Sensor gerak PIR | |
* - Buzzer alarm | |
* - LED status | |
* - LCD display 16x2 | |
* - Servo motor untuk ventilasi otomatis | |
* - SD Card logging | |
* - RTC untuk timestamp | |
* - Komunikasi serial dengan komputer | |
* | |
* Pin Configuration: | |
* - DHT22: Pin 2 | |
* - LDR: A0 | |
* - PIR: Pin 3 | |
* - Buzzer: Pin 4 | |
* - LED Red: Pin 5 | |
* - LED Green: Pin 6 | |
* - LED Blue: Pin 7 | |
* - Servo: Pin 9 | |
* - LCD: I2C (A4-SDA, A5-SCL) | |
* - SD Card: Pin 10-13 (SPI) | |
* - RTC: I2C (A4-SDA, A5-SCL) | |
*/ | |
// Library imports - Menggunakan 10+ library bawaan Arduino | |
#include <DHT.h> // Library untuk sensor DHT22 | |
#include <LiquidCrystal_I2C.h> // Library untuk LCD I2C | |
#include <Servo.h> // Library untuk servo motor | |
#include <SD.h> // Library untuk SD card | |
#include <SPI.h> // Library untuk komunikasi SPI | |
#include <Wire.h> // Library untuk komunikasi I2C | |
#include <RTClib.h> // Library untuk Real Time Clock | |
#include <EEPROM.h> // Library untuk penyimpanan EEPROM | |
#include <SoftwareSerial.h> // Library untuk serial tambahan | |
#include <avr/wdt.h> // Library untuk watchdog timer | |
#include <avr/sleep.h> // Library untuk mode sleep | |
// Definisi konstanta dan pin | |
#define DHT_PIN 2 | |
#define DHT_TYPE DHT22 | |
#define LDR_PIN A0 | |
#define PIR_PIN 3 | |
#define BUZZER_PIN 4 | |
#define LED_RED 5 | |
#define LED_GREEN 6 | |
#define LED_BLUE 7 | |
#define SERVO_PIN 9 | |
#define SD_CS_PIN 10 | |
#define BUTTON_PIN 8 | |
// Threshold values | |
#define TEMP_HIGH 30.0 | |
#define TEMP_LOW 15.0 | |
#define HUMIDITY_HIGH 80.0 | |
#define HUMIDITY_LOW 30.0 | |
#define LIGHT_THRESHOLD 512 | |
#define MOTION_TIMEOUT 30000 | |
#define ALARM_DURATION 5000 | |
#define SERVO_OPEN_ANGLE 90 | |
#define SERVO_CLOSE_ANGLE 0 | |
// Struktur data untuk sensor readings | |
struct SensorData { | |
float temperature; | |
float humidity; | |
int lightLevel; | |
bool motionDetected; | |
unsigned long timestamp; | |
String status; | |
}; | |
struct AlarmConfig { | |
bool tempAlarmEnabled; | |
bool humidityAlarmEnabled; | |
bool motionAlarmEnabled; | |
bool lightAlarmEnabled; | |
float tempThresholdHigh; | |
float tempThresholdLow; | |
float humidityThresholdHigh; | |
float humidityThresholdLow; | |
}; | |
// Inisialisasi objek library | |
DHT dht(DHT_PIN, DHT_TYPE); | |
LiquidCrystal_I2C lcd(0x27, 16, 2); | |
Servo ventilationServo; | |
RTC_DS3231 rtc; | |
SoftwareSerial bluetoothSerial(12, 13); | |
// Variabel global | |
SensorData currentReading; | |
AlarmConfig alarmSettings; | |
unsigned long lastMotionTime = 0; | |
unsigned long lastReadingTime = 0; | |
unsigned long lastDisplayUpdate = 0; | |
unsigned long lastServoMove = 0; | |
unsigned long lastAlarmTime = 0; | |
unsigned long lastLogTime = 0; | |
unsigned long buttonPressTime = 0; | |
bool systemActive = true; | |
bool alarmActive = false; | |
bool servoOpen = false; | |
bool autoVentilation = true; | |
bool nightMode = false; | |
bool sdCardAvailable = false; | |
bool rtcAvailable = false; | |
int displayMode = 0; | |
int menuIndex = 0; | |
int buttonState = HIGH; | |
int lastButtonState = HIGH; | |
String dataBuffer = ""; | |
String commandBuffer = ""; | |
char logFileName[] = "LOG_0000.TXT"; | |
// Arrays untuk statistik | |
float tempHistory[24]; | |
float humidityHistory[24]; | |
int historyIndex = 0; | |
bool historyFull = false; | |
// Enum untuk status sistem | |
enum SystemStatus { | |
STATUS_NORMAL, | |
STATUS_WARNING, | |
STATUS_ALARM, | |
STATUS_ERROR, | |
STATUS_MAINTENANCE | |
}; | |
SystemStatus currentStatus = STATUS_NORMAL; | |
void setup() { | |
// Inisialisasi komunikasi serial | |
Serial.begin(9600); | |
bluetoothSerial.begin(9600); | |
Serial.println(F("========================================")); | |
Serial.println(F("SISTEM MONITORING LINGKUNGAN v2.1")); | |
Serial.println(F("Arduino Uno R3 - Booting...")); | |
Serial.println(F("========================================")); | |
// Inisialisasi pin digital | |
pinMode(LED_RED, OUTPUT); | |
pinMode(LED_GREEN, OUTPUT); | |
pinMode(LED_BLUE, OUTPUT); | |
pinMode(BUZZER_PIN, OUTPUT); | |
pinMode(PIR_PIN, INPUT); | |
pinMode(BUTTON_PIN, INPUT_PULLUP); | |
// Test LED sequence | |
testLEDSequence(); | |
// Inisialisasi DHT sensor | |
dht.begin(); | |
Serial.println(F("DHT22 sensor initialized")); | |
delay(2000); | |
// Inisialisasi LCD | |
lcd.init(); | |
lcd.backlight(); | |
lcd.setCursor(0, 0); | |
lcd.print("System Booting.."); | |
lcd.setCursor(0, 1); | |
lcd.print("Please wait..."); | |
Serial.println(F("LCD I2C initialized")); | |
// Inisialisasi servo | |
ventilationServo.attach(SERVO_PIN); | |
ventilationServo.write(SERVO_CLOSE_ANGLE); | |
Serial.println(F("Servo motor initialized")); | |
// Inisialisasi RTC | |
if (rtc.begin()) { | |
rtcAvailable = true; | |
if (rtc.lostPower()) { | |
Serial.println(F("RTC lost power, setting time")); | |
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); | |
} | |
Serial.println(F("RTC DS3231 initialized")); | |
} else { | |
Serial.println(F("RTC DS3231 not found")); | |
} | |
// Inisialisasi SD Card | |
if (SD.begin(SD_CS_PIN)) { | |
sdCardAvailable = true; | |
createLogFile(); | |
Serial.println(F("SD Card initialized")); | |
} else { | |
Serial.println(F("SD Card initialization failed")); | |
} | |
// Load konfigurasi dari EEPROM | |
loadConfigFromEEPROM(); | |
// Inisialisasi watchdog timer | |
wdt_enable(WDTO_8S); | |
// Inisialisasi array history | |
initializeHistory(); | |
// Setup interrupts | |
attachInterrupt(digitalPinToInterrupt(PIR_PIN), motionDetected, RISING); | |
// Boot completed | |
lcd.clear(); | |
lcd.setCursor(0, 0); | |
lcd.print("System Ready!"); | |
digitalWrite(LED_GREEN, HIGH); | |
playBootSound(); | |
Serial.println(F("System initialization completed")); | |
Serial.println(F("========================================")); | |
delay(2000); | |
} | |
void loop() { | |
// Reset watchdog timer | |
wdt_reset(); | |
// Handle serial commands | |
handleSerialCommands(); | |
handleBluetoothCommands(); | |
// Check button press | |
handleButtonPress(); | |
// Read sensors setiap 2 detik | |
if (millis() - lastReadingTime >= 2000) { | |
readAllSensors(); | |
processData(); | |
lastReadingTime = millis(); | |
} | |
// Update display setiap 1 detik | |
if (millis() - lastDisplayUpdate >= 1000) { | |
updateDisplay(); | |
lastDisplayUpdate = millis(); | |
} | |
// Auto ventilation control | |
if (autoVentilation) { | |
controlVentilation(); | |
} | |
// Check alarms | |
checkAlarmConditions(); | |
// Log data setiap 5 menit | |
if (millis() - lastLogTime >= 300000) { | |
logDataToSD(); | |
lastLogTime = millis(); | |
} | |
// Update status LED | |
updateStatusLED(); | |
// Send data via bluetooth setiap 10 detik | |
if (millis() % 10000 < 100) { | |
sendBluetoothData(); | |
} | |
// Night mode detection | |
detectNightMode(); | |
// System health check | |
performHealthCheck(); | |
delay(100); | |
} | |
void readAllSensors() { | |
// Baca DHT22 | |
float temp = dht.readTemperature(); | |
float hum = dht.readHumidity(); | |
if (!isnan(temp) && !isnan(hum)) { | |
currentReading.temperature = temp; | |
currentReading.humidity = hum; | |
// Update history | |
updateHistory(temp, hum); | |
} | |
// Baca LDR | |
int ldrValue = analogRead(LDR_PIN); | |
currentReading.lightLevel = map(ldrValue, 0, 1023, 0, 100); | |
// Set timestamp | |
if (rtcAvailable) { | |
DateTime now = rtc.now(); | |
currentReading.timestamp = now.unixtime(); | |
} else { | |
currentReading.timestamp = millis(); | |
} | |
} | |
void processData() { | |
// Tentukan status sistem berdasarkan sensor readings | |
if (currentReading.temperature > TEMP_HIGH || | |
currentReading.temperature < TEMP_LOW || | |
currentReading.humidity > HUMIDITY_HIGH || | |
currentReading.humidity < HUMIDITY_LOW) { | |
if (currentStatus == STATUS_NORMAL) { | |
currentStatus = STATUS_WARNING; | |
currentReading.status = "WARNING"; | |
} | |
} else { | |
if (currentStatus == STATUS_WARNING) { | |
currentStatus = STATUS_NORMAL; | |
currentReading.status = "NORMAL"; | |
} | |
} | |
// Print ke serial untuk debugging | |
if (Serial.available() == 0) { | |
printSensorData(); | |
} | |
} | |
void updateDisplay() { | |
lcd.clear(); | |
switch (displayMode) { | |
case 0: // Temperature & Humidity | |
lcd.setCursor(0, 0); | |
lcd.print("T:"); | |
lcd.print(currentReading.temperature, 1); | |
lcd.print("C H:"); | |
lcd.print(currentReading.humidity, 1); | |
lcd.print("%"); | |
lcd.setCursor(0, 1); | |
lcd.print("Light:"); | |
lcd.print(currentReading.lightLevel); | |
lcd.print("% "); | |
lcd.print(currentReading.status); | |
break; | |
case 1: // Time and Status | |
if (rtcAvailable) { | |
DateTime now = rtc.now(); | |
lcd.setCursor(0, 0); | |
if (now.hour() < 10) lcd.print("0"); | |
lcd.print(now.hour()); | |
lcd.print(":"); | |
if (now.minute() < 10) lcd.print("0"); | |
lcd.print(now.minute()); | |
lcd.print(":"); | |
if (now.second() < 10) lcd.print("0"); | |
lcd.print(now.second()); | |
lcd.print(" "); | |
lcd.print(nightMode ? "NIGHT" : "DAY"); | |
} | |
lcd.setCursor(0, 1); | |
lcd.print("Status: "); | |
switch (currentStatus) { | |
case STATUS_NORMAL: lcd.print("OK"); break; | |
case STATUS_WARNING: lcd.print("WARN"); break; | |
case STATUS_ALARM: lcd.print("ALARM"); break; | |
case STATUS_ERROR: lcd.print("ERROR"); break; | |
default: lcd.print("UNKN"); break; | |
} | |
break; | |
case 2: // Statistics | |
lcd.setCursor(0, 0); | |
lcd.print("Avg T:"); | |
lcd.print(calculateAverageTemp(), 1); | |
lcd.print("C"); | |
lcd.setCursor(0, 1); | |
lcd.print("Avg H:"); | |
lcd.print(calculateAverageHumidity(), 1); | |
lcd.print("%"); | |
break; | |
} | |
} | |
void controlVentilation() { | |
bool shouldOpen = false; | |
// Logic untuk membuka/tutup ventilasi | |
if (currentReading.temperature > TEMP_HIGH || | |
currentReading.humidity > HUMIDITY_HIGH) { | |
shouldOpen = true; | |
} | |
if (shouldOpen && !servoOpen) { | |
ventilationServo.write(SERVO_OPEN_ANGLE); | |
servoOpen = true; | |
lastServoMove = millis(); | |
Serial.println(F("Ventilation opened")); | |
} else if (!shouldOpen && servoOpen && | |
(millis() - lastServoMove > 60000)) { | |
ventilationServo.write(SERVO_CLOSE_ANGLE); | |
servoOpen = false; | |
lastServoMove = millis(); | |
Serial.println(F("Ventilation closed")); | |
} | |
} | |
void checkAlarmConditions() { | |
bool alarmTriggered = false; | |
String alarmReason = ""; | |
// Check temperature alarm | |
if (alarmSettings.tempAlarmEnabled) { | |
if (currentReading.temperature > alarmSettings.tempThresholdHigh) { | |
alarmTriggered = true; | |
alarmReason = "HIGH TEMP"; | |
} else if (currentReading.temperature < alarmSettings.tempThresholdLow) { | |
alarmTriggered = true; | |
alarmReason = "LOW TEMP"; | |
} | |
} | |
// Check humidity alarm | |
if (alarmSettings.humidityAlarmEnabled) { | |
if (currentReading.humidity > alarmSettings.humidityThresholdHigh) { | |
alarmTriggered = true; | |
alarmReason = "HIGH HUMID"; | |
} else if (currentReading.humidity < alarmSettings.humidityThresholdLow) { | |
alarmTriggered = true; | |
alarmReason = "LOW HUMID"; | |
} | |
} | |
// Check motion alarm (jika aktif di malam hari) | |
if (alarmSettings.motionAlarmEnabled && nightMode && currentReading.motionDetected) { | |
alarmTriggered = true; | |
alarmReason = "MOTION"; | |
} | |
// Trigger alarm | |
if (alarmTriggered && !alarmActive) { | |
triggerAlarm(alarmReason); | |
} else if (!alarmTriggered && alarmActive) { | |
stopAlarm(); | |
} | |
// Auto stop alarm setelah durasi tertentu | |
if (alarmActive && (millis() - lastAlarmTime > ALARM_DURATION)) { | |
stopAlarm(); | |
} | |
} | |
void triggerAlarm(String reason) { | |
alarmActive = true; | |
lastAlarmTime = millis(); | |
currentStatus = STATUS_ALARM; | |
Serial.print(F("ALARM TRIGGERED: ")); | |
Serial.println(reason); | |
// Sound buzzer pattern | |
for (int i = 0; i < 3; i++) { | |
digitalWrite(BUZZER_PIN, HIGH); | |
delay(200); | |
digitalWrite(BUZZER_PIN, LOW); | |
delay(200); | |
} | |
// Flash red LED | |
digitalWrite(LED_RED, HIGH); | |
} | |
void stopAlarm() { | |
alarmActive = false; | |
currentStatus = STATUS_NORMAL; | |
digitalWrite(BUZZER_PIN, LOW); | |
digitalWrite(LED_RED, LOW); | |
Serial.println(F("Alarm stopped")); | |
} | |
void motionDetected() { | |
currentReading.motionDetected = true; | |
lastMotionTime = millis(); | |
} | |
void handleButtonPress() { | |
int reading = digitalRead(BUTTON_PIN); | |
if (reading != lastButtonState) { | |
buttonPressTime = millis(); | |
} | |
if ((millis() - buttonPressTime) > 50) { | |
if (reading != buttonState) { | |
buttonState = reading; | |
if (buttonState == LOW) { | |
// Button pressed | |
displayMode = (displayMode + 1) % 3; | |
playButtonSound(); | |
} | |
} | |
} | |
lastButtonState = reading; | |
} | |
void handleSerialCommands() { | |
while (Serial.available()) { | |
char c = Serial.read(); | |
if (c == '\n') { | |
processCommand(commandBuffer); | |
commandBuffer = ""; | |
} else { | |
commandBuffer += c; | |
} | |
} | |
} | |
void handleBluetoothCommands() { | |
while (bluetoothSerial.available()) { | |
char c = bluetoothSerial.read(); | |
if (c == '\n') { | |
processBluetoothCommand(commandBuffer); | |
commandBuffer = ""; | |
} else { | |
commandBuffer += c; | |
} | |
} | |
} | |
void processCommand(String cmd) { | |
cmd.trim(); | |
cmd.toUpperCase(); | |
if (cmd == "STATUS") { | |
printSystemStatus(); | |
} else if (cmd == "RESET") { | |
resetSystem(); | |
} else if (cmd == "ALARM_ON") { | |
alarmSettings.tempAlarmEnabled = true; | |
Serial.println(F("Temperature alarm enabled")); | |
} else if (cmd == "ALARM_OFF") { | |
alarmSettings.tempAlarmEnabled = false; | |
Serial.println(F("Temperature alarm disabled")); | |
} else if (cmd == "VENT_AUTO") { | |
autoVentilation = true; | |
Serial.println(F("Auto ventilation enabled")); | |
} else if (cmd == "VENT_MANUAL") { | |
autoVentilation = false; | |
Serial.println(F("Auto ventilation disabled")); | |
} else if (cmd == "VENT_OPEN") { | |
ventilationServo.write(SERVO_OPEN_ANGLE); | |
servoOpen = true; | |
Serial.println(F("Ventilation opened manually")); | |
} else if (cmd == "VENT_CLOSE") { | |
ventilationServo.write(SERVO_CLOSE_ANGLE); | |
servoOpen = false; | |
Serial.println(F("Ventilation closed manually")); | |
} else if (cmd == "SAVE_CONFIG") { | |
saveConfigToEEPROM(); | |
Serial.println(F("Configuration saved")); | |
} else if (cmd == "HELP") { | |
printHelp(); | |
} else { | |
Serial.println(F("Unknown command. Type HELP for commands")); | |
} | |
} | |
void processBluetoothCommand(String cmd) { | |
// Process bluetooth commands | |
processCommand(cmd); | |
bluetoothSerial.println("Command processed: " + cmd); | |
} | |
void logDataToSD() { | |
if (!sdCardAvailable) return; | |
File dataFile = SD.open(logFileName, FILE_WRITE); | |
if (dataFile) { | |
// Create CSV format log entry | |
if (rtcAvailable) { | |
DateTime now = rtc.now(); | |
dataFile.print(now.year()); | |
dataFile.print("-"); | |
dataFile.print(now.month()); | |
dataFile.print("-"); | |
dataFile.print(now.day()); | |
dataFile.print(" "); | |
dataFile.print(now.hour()); | |
dataFile.print(":"); | |
dataFile.print(now.minute()); | |
dataFile.print(":"); | |
dataFile.print(now.second()); | |
} else { | |
dataFile.print(millis()); | |
} | |
dataFile.print(","); | |
dataFile.print(currentReading.temperature); | |
dataFile.print(","); | |
dataFile.print(currentReading.humidity); | |
dataFile.print(","); | |
dataFile.print(currentReading.lightLevel); | |
dataFile.print(","); | |
dataFile.print(currentReading.motionDetected ? "1" : "0"); | |
dataFile.print(","); | |
dataFile.print(currentReading.status); | |
dataFile.println(); | |
dataFile.close(); | |
Serial.println(F("Data logged to SD card")); | |
} | |
} | |
void updateStatusLED() { | |
// Turn off all LEDs | |
digitalWrite(LED_RED, LOW); | |
digitalWrite(LED_GREEN, LOW); | |
digitalWrite(LED_BLUE, LOW); | |
// Set LED based on status | |
switch (currentStatus) { | |
case STATUS_NORMAL: | |
digitalWrite(LED_GREEN, HIGH); | |
break; | |
case STATUS_WARNING: | |
digitalWrite(LED_BLUE, HIGH); | |
break; | |
case STATUS_ALARM: | |
// Red LED blinks dalam alarm state | |
digitalWrite(LED_RED, (millis() % 1000) < 500); | |
break; | |
case STATUS_ERROR: | |
digitalWrite(LED_RED, HIGH); | |
break; | |
} | |
} | |
void sendBluetoothData() { | |
bluetoothSerial.print("TEMP:"); | |
bluetoothSerial.print(currentReading.temperature); | |
bluetoothSerial.print(",HUMID:"); | |
bluetoothSerial.print(currentReading.humidity); | |
bluetoothSerial.print(",LIGHT:"); | |
bluetoothSerial.print(currentReading.lightLevel); | |
bluetoothSerial.print(",STATUS:"); | |
bluetoothSerial.println(currentReading.status); | |
} | |
void detectNightMode() { | |
nightMode = (currentReading.lightLevel < 20); | |
if (nightMode) { | |
lcd.noBacklight(); | |
} else { | |
lcd.backlight(); | |
} | |
} | |
void performHealthCheck() { | |
// Check sensor validity | |
if (isnan(currentReading.temperature) || isnan(currentReading.humidity)) { | |
currentStatus = STATUS_ERROR; | |
Serial.println(F("ERROR: DHT sensor malfunction")); | |
} | |
// Check SD card status | |
if (sdCardAvailable && !SD.begin(SD_CS_PIN)) { | |
sdCardAvailable = false; | |
Serial.println(F("WARNING: SD card disconnected")); | |
} | |
// Reset motion detection flag | |
if (millis() - lastMotionTime > MOTION_TIMEOUT) { | |
currentReading.motionDetected = false; | |
} | |
} | |
// Utility functions | |
void testLEDSequence() { | |
digitalWrite(LED_RED, HIGH); | |
delay(200); | |
digitalWrite(LED_RED, LOW); | |
digitalWrite(LED_GREEN, HIGH); | |
delay(200); | |
digitalWrite(LED_GREEN, LOW); | |
digitalWrite(LED_BLUE, HIGH); | |
delay(200); | |
digitalWrite(LED_BLUE, LOW); | |
} | |
void playBootSound() { | |
tone(BUZZER_PIN, 1000, 200); | |
delay(250); | |
tone(BUZZER_PIN, 1500, 200); | |
delay(250); | |
tone(BUZZER_PIN, 2000, 200); | |
} | |
void playButtonSound() { | |
tone(BUZZER_PIN, 800, 100); | |
} | |
void printSensorData() { | |
Serial.print(F("Temperature: ")); | |
Serial.print(currentReading.temperature); | |
Serial.print(F("°C, Humidity: ")); | |
Serial.print(currentReading.humidity); | |
Serial.print(F("%, Light: ")); | |
Serial.print(currentReading.lightLevel); | |
Serial.print(F("%, Motion: ")); | |
Serial.print(currentReading.motionDetected ? "YES" : "NO"); | |
Serial.print(F(", Status: ")); | |
Serial.println(currentReading.status); | |
} | |
void printSystemStatus() { | |
Serial.println(F("=== SYSTEM STATUS ===")); | |
Serial.print(F("Temperature: ")); | |
Serial.println(currentReading.temperature); | |
Serial.print(F("Humidity: ")); | |
Serial.println(currentReading.humidity); | |
Serial.print(F("Light Level: ")); | |
Serial.println(currentReading.lightLevel); | |
Serial.print(F("Motion: ")); | |
Serial.println(currentReading.motionDetected ? "Detected" : "None"); | |
Serial.print(F("Ventilation: ")); | |
Serial.println(servoOpen ? "Open" : "Closed"); | |
Serial.print(F("Night Mode: ")); | |
Serial.println(nightMode ? "Yes" : "No"); | |
Serial.print(F("Auto Vent: ")); | |
Serial.println(autoVentilation ? "Enabled" : "Disabled"); | |
Serial.print(F("SD Card: ")); | |
Serial.println(sdCardAvailable ? "Available" : "Not Available"); | |
Serial.print(F("RTC: ")); | |
Serial.println(rtcAvailable ? "Available" : "Not Available"); | |
Serial.println(F("==================")); | |
} | |
void printHelp() { | |
Serial.println(F("=== AVAILABLE COMMANDS ===")); | |
Serial.println(F("STATUS - Show system status")); | |
Serial.println(F("RESET - Reset system")); | |
Serial.println(F("ALARM_ON - Enable temperature alarm")); | |
Serial.println(F("ALARM_OFF - Disable temperature alarm")); | |
Serial.println(F("VENT_AUTO - Enable auto ventilation")); | |
Serial.println(F("VENT_MANUAL - Disable auto ventilation")); | |
Serial.println(F("VENT_OPEN - Open ventilation manually")); | |
Serial.println(F("VENT_CLOSE - Close ventilation manually")); | |
Serial.println(F("SAVE_CONFIG - Save configuration")); | |
Serial.println(F("HELP - Show this help")); | |
Serial.println(F("========================")); | |
} | |
void createLogFile() { | |
// Create unique log file name | |
for (int i = 0; i < 10000; i++) { | |
logFileName[4] = '0' + (i / 1000) % 10; | |
logFileName[5] = '0' + (i / 100) % 10; | |
logFileName[6] = '0' + (i / 10) % 10; | |
logFileName[7] = '0' + i % 10; | |
if (!SD.exists(logFileName)) { | |
File dataFile = SD.open(logFileName, FILE_WRITE); | |
if (dataFile) { | |
dataFile.println("Timestamp,Temperature,Humidity,Light,Motion,Status"); | |
dataFile.close(); | |
Serial.print(F("Created log file: ")); | |
Serial.println(logFileName); | |
return; | |
} | |
} | |
} | |
} | |
void loadConfigFromEEPROM() { | |
// Load alarm configuration from EEPROM | |
alarmSettings.tempAlarmEnabled = EEPROM.read(0); | |
alarmSettings.humidityAlarmEnabled = EEPROM.read(1); | |
alarmSettings.motionAlarmEnabled = EEPROM.read(2); | |
// Load threshold values (stored as integers, divide by 10) | |
int tempHigh = (EEPROM.read(10) << 8) | EEPROM.read(11); | |
int tempLow = (EEPROM.read(12) << 8) | EEPROM.read(13); | |
int humidHigh = (EEPROM.read(14) << 8) | EEPROM.read(15); | |
int humidLow = (EEPROM.read(16) << 8) | EEPROM.read(17); | |
alarmSettings.tempThresholdHigh = tempHigh / 10.0; | |
alarmSettings.tempThresholdLow = tempLow / 10.0; | |
alarmSettings.humidityThresholdHigh = humidHigh / 10.0; | |
alarmSettings.humidityThresholdLow = humidLow / 10.0; | |
// Set default values if EEPROM is empty | |
if (tempHigh == 0 && tempLow == 0) { | |
alarmSettings.tempThresholdHigh = TEMP_HIGH; | |
alarmSettings.tempThresholdLow = TEMP_LOW; | |
alarmSettings.humidityThresholdHigh = HUMIDITY_HIGH; | |
alarmSettings.humidityThresholdLow = HUMIDITY_LOW; | |
alarmSettings.tempAlarmEnabled = true; | |
alarmSettings.humidityAlarmEnabled = true; | |
alarmSettings.motionAlarmEnabled = false; | |
} | |
} | |
void saveConfigToEEPROM() { | |
EEPROM.write(0, alarmSettings.tempAlarmEnabled); | |
EEPROM.write(1, alarmSettings.humidityAlarmEnabled); | |
EEPROM.write(2, alarmSettings.motionAlarmEnabled); | |
// Save threshold values (multiply by 10 and store as integers) | |
int tempHigh = (int)(alarmSettings.tempThresholdHigh * 10); | |
int tempLow = (int)(alarmSettings.tempThresholdLow * 10); | |
int humidHigh = (int)(alarmSettings.humidityThresholdHigh * 10); | |
int humidLow = (int)(alarmSettings.humidityThresholdLow * 10); | |
EEPROM.write(10, tempHigh >> 8); | |
EEPROM.write(11, tempHigh & 0xFF); | |
EEPROM.write(12, tempLow >> 8); | |
EEPROM.write(13, tempLow & 0xFF); | |
EEPROM.write(14, humidHigh >> 8); | |
EEPROM.write(15, humidHigh & 0xFF); | |
EEPROM.write(16, humidLow >> 8); | |
EEPROM.write(17, humidLow & 0xFF); | |
} | |
void initializeHistory() { | |
for (int i = 0; i < 24; i++) { | |
tempHistory[i] = 0.0; | |
humidityHistory[i] = 0.0; | |
} | |
} | |
void updateHistory(float temp, float humidity) { | |
tempHistory[historyIndex] = temp; | |
humidityHistory[historyIndex] = humidity; | |
historyIndex = (historyIndex + 1) % 24; | |
if (historyIndex == 0) { | |
historyFull = true; | |
} | |
} | |
float calculateAverageTemp() { | |
float sum = 0.0; | |
int count = historyFull ? 24 : historyIndex; | |
for (int i = 0; i < count; i++) { | |
sum += tempHistory[i]; | |
} | |
return count > 0 ? sum / count : 0.0; | |
} | |
float calculateAverageHumidity() { | |
float sum = 0.0; | |
int count = historyFull ? 24 : historyIndex; | |
for (int i = 0; i < count; i++) { | |
sum += humidityHistory[i]; | |
} | |
return count > 0 ? sum / count : 0.0; | |
} | |
void resetSystem() { | |
Serial.println(F("Resetting system...")); | |
// Reset all variables to default | |
currentStatus = STATUS_NORMAL; | |
alarmActive = false; | |
servoOpen = false; | |
autoVentilation = true; | |
nightMode = false; | |
displayMode = 0; | |
historyIndex = 0; | |
historyFull = false; | |
// Reset hardware | |
digitalWrite(LED_RED, LOW); | |
digitalWrite(LED_GREEN, LOW); | |
digitalWrite(LED_BLUE, LOW); | |
digitalWrite(BUZZER_PIN, LOW); | |
ventilationServo.write(SERVO_CLOSE_ANGLE); | |
// Clear LCD | |
lcd.clear(); | |
lcd.setCursor(0, 0); | |
lcd.print("System Reset"); | |
lcd.setCursor(0, 1); | |
lcd.print("Please wait..."); | |
// Initialize history | |
initializeHistory(); | |
delay(2000); | |
Serial.println(F("System reset completed")); | |
} | |
// Advanced sensor calibration function | |
void calibrateSensors() { | |
Serial.println(F("Starting sensor calibration...")); | |
float tempSum = 0, humidSum = 0; | |
int validReadings = 0; | |
// Take 10 readings for calibration | |
for (int i = 0; i < 10; i++) { | |
float temp = dht.readTemperature(); | |
float hum = dht.readHumidity(); | |
if (!isnan(temp) && !isnan(hum)) { | |
tempSum += temp; | |
humidSum += hum; | |
validReadings++; | |
} | |
delay(1000); | |
Serial.print("."); | |
} | |
if (validReadings > 0) { | |
float avgTemp = tempSum / validReadings; | |
float avgHumid = humidSum / validReadings; | |
Serial.println(); | |
Serial.print(F("Calibration completed. Avg Temp: ")); | |
Serial.print(avgTemp); | |
Serial.print(F("°C, Avg Humidity: ")); | |
Serial.print(avgHumid); | |
Serial.println(F("%")); | |
} else { | |
Serial.println(F("Calibration failed - no valid readings")); | |
} | |
} | |
// Data export function | |
void exportDataToSerial() { | |
Serial.println(F("=== DATA EXPORT ===")); | |
Serial.println(F("Index,Temperature,Humidity")); | |
int count = historyFull ? 24 : historyIndex; | |
for (int i = 0; i < count; i++) { | |
Serial.print(i); | |
Serial.print(","); | |
Serial.print(tempHistory[i]); | |
Serial.print(","); | |
Serial.println(humidityHistory[i]); | |
} | |
Serial.println(F("=== END EXPORT ===")); | |
} | |
// Advanced alarm patterns | |
void playAlarmPattern(int pattern) { | |
switch (pattern) { | |
case 1: // Temperature alarm | |
for (int i = 0; i < 5; i++) { | |
tone(BUZZER_PIN, 1000, 100); | |
delay(150); | |
tone(BUZZER_PIN, 1500, 100); | |
delay(150); | |
} | |
break; | |
case 2: // Humidity alarm | |
for (int i = 0; i < 3; i++) { | |
tone(BUZZER_PIN, 800, 300); | |
delay(400); | |
} | |
break; | |
case 3: // Motion alarm | |
tone(BUZZER_PIN, 2000, 1000); | |
delay(200); | |
tone(BUZZER_PIN, 2500, 500); | |
break; | |
default: | |
tone(BUZZER_PIN, 1200, 500); | |
break; | |
} | |
} | |
// Power management functions | |
void enterSleepMode() { | |
Serial.println(F("Entering sleep mode...")); | |
// Turn off non-essential components | |
lcd.noBacklight(); | |
digitalWrite(LED_GREEN, LOW); | |
digitalWrite(LED_BLUE, LOW); | |
// Detach servo to save power | |
ventilationServo.detach(); | |
// Set sleep mode | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |
sleep_enable(); | |
// Sleep until interrupt | |
sleep_mode(); | |
// Wake up | |
sleep_disable(); | |
// Re-initialize components | |
lcd.backlight(); | |
ventilationServo.attach(SERVO_PIN); | |
Serial.println(F("Waking up from sleep mode")); | |
} | |
// Network communication simulation | |
void simulateNetworkComm() { | |
// Simulate sending data to cloud service | |
Serial.println(F("Sending data to cloud...")); | |
// Create JSON-like data string | |
String jsonData = "{"; | |
jsonData += "\"temperature\":"; | |
jsonData += String(currentReading.temperature); | |
jsonData += ",\"humidity\":"; | |
jsonData += String(currentReading.humidity); | |
jsonData += ",\"light\":"; | |
jsonData += String(currentReading.lightLevel); | |
jsonData += ",\"motion\":"; | |
jsonData += (currentReading.motionDetected ? "true" : "false"); | |
jsonData += ",\"status\":\""; | |
jsonData += currentReading.status; | |
jsonData += "\"}"; | |
Serial.println(jsonData); | |
bluetoothSerial.println(jsonData); | |
} | |
// Advanced display functions | |
void showAdvancedDisplay() { | |
lcd.clear(); | |
// Show memory usage | |
int freeMemory = getFreeMemory(); | |
lcd.setCursor(0, 0); | |
lcd.print("Free RAM: "); | |
lcd.print(freeMemory); | |
lcd.print("b"); | |
// Show system uptime | |
lcd.setCursor(0, 1); | |
unsigned long uptime = millis() / 1000; | |
lcd.print("Up: "); | |
lcd.print(uptime / 3600); | |
lcd.print("h"); | |
lcd.print((uptime % 3600) / 60); | |
lcd.print("m"); | |
} | |
// Memory management | |
int getFreeMemory() { | |
extern int __heap_start, *__brkval; | |
int v; | |
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); | |
} | |
// Error handling and logging | |
void logError(String errorMessage) { | |
Serial.print(F("ERROR: ")); | |
Serial.println(errorMessage); | |
if (sdCardAvailable) { | |
File errorFile = SD.open("ERROR.LOG", FILE_WRITE); | |
if (errorFile) { | |
if (rtcAvailable) { | |
DateTime now = rtc.now(); | |
errorFile.print(now.year()); | |
errorFile.print("-"); | |
errorFile.print(now.month()); | |
errorFile.print("-"); | |
errorFile.print(now.day()); | |
errorFile.print(" "); | |
errorFile.print(now.hour()); | |
errorFile.print(":"); | |
errorFile.print(now.minute()); | |
errorFile.print(":"); | |
errorFile.print(now.second()); | |
errorFile.print(" - "); | |
} | |
errorFile.println(errorMessage); | |
errorFile.close(); | |
} | |
} | |
} | |
// Configuration menu system | |
void showConfigMenu() { | |
lcd.clear(); | |
lcd.setCursor(0, 0); | |
lcd.print("Config Menu"); | |
switch (menuIndex) { | |
case 0: | |
lcd.setCursor(0, 1); | |
lcd.print("1.Temp Alarm"); | |
break; | |
case 1: | |
lcd.setCursor(0, 1); | |
lcd.print("2.Humid Alarm"); | |
break; | |
case 2: | |
lcd.setCursor(0, 1); | |
lcd.print("3.Motion Alarm"); | |
break; | |
case 3: | |
lcd.setCursor(0, 1); | |
lcd.print("4.Auto Vent"); | |
break; | |
case 4: | |
lcd.setCursor(0, 1); | |
lcd.print("5.Save & Exit"); | |
break; | |
} | |
} | |
// Sensor validation | |
bool validateSensorReadings() { | |
// Check if temperature is within reasonable range | |
if (currentReading.temperature < -40 || currentReading.temperature > 80) { | |
logError("Temperature reading out of range"); | |
return false; | |
} | |
// Check if humidity is within valid range | |
if (currentReading.humidity < 0 || currentReading.humidity > 100) { | |
logError("Humidity reading out of range"); | |
return false; | |
} | |
// Check for sensor communication errors | |
if (isnan(currentReading.temperature) || isnan(currentReading.humidity)) { | |
logError("DHT sensor communication error"); | |
return false; | |
} | |
return true; | |
} | |
// Statistical analysis | |
void performStatisticalAnalysis() { | |
if (!historyFull && historyIndex < 5) return; | |
int count = historyFull ? 24 : historyIndex; | |
// Calculate standard deviation for temperature | |
float tempMean = calculateAverageTemp(); | |
float tempVariance = 0; | |
for (int i = 0; i < count; i++) { | |
float diff = tempHistory[i] - tempMean; | |
tempVariance += diff * diff; | |
} | |
float tempStdDev = sqrt(tempVariance / count); | |
// Calculate humidity statistics | |
float humidMean = calculateAverageHumidity(); | |
float humidVariance = 0; | |
for (int i = 0; i < count; i++) { | |
float diff = humidityHistory[i] - humidMean; | |
humidVariance += diff * diff; | |
} | |
float humidStdDev = sqrt(humidVariance / count); | |
// Log statistical data | |
Serial.println(F("=== STATISTICAL ANALYSIS ===")); | |
Serial.print(F("Temperature - Mean: ")); | |
Serial.print(tempMean); | |
Serial.print(F("°C, StdDev: ")); | |
Serial.println(tempStdDev); | |
Serial.print(F("Humidity - Mean: ")); | |
Serial.print(humidMean); | |
Serial.print(F("%, StdDev: ")); | |
Serial.println(humidStdDev); | |
Serial.println(F("===========================")); | |
} | |
// System diagnostics | |
void runSystemDiagnostics() { | |
Serial.println(F("Running system diagnostics...")); | |
// Test all LEDs | |
Serial.println(F("Testing LEDs...")); | |
testLEDSequence(); | |
// Test buzzer | |
Serial.println(F("Testing buzzer...")); | |
playBootSound(); | |
// Test servo | |
Serial.println(F("Testing servo...")); | |
ventilationServo.write(45); | |
delay(1000); | |
ventilationServo.write(0); | |
// Test sensors | |
Serial.println(F("Testing sensors...")); | |
readAllSensors(); | |
if (validateSensorReadings()) { | |
Serial.println(F("All sensors OK")); | |
} else { | |
Serial.println(F("Sensor issues detected")); | |
} | |
// Test SD card | |
if (sdCardAvailable) { | |
Serial.println(F("SD card: OK")); | |
} else { | |
Serial.println(F("SD card: Not available")); | |
} | |
// Test RTC | |
if (rtcAvailable) { | |
Serial.println(F("RTC: OK")); | |
} else { | |
Serial.println(F("RTC: Not available")); | |
} | |
Serial.println(F("Diagnostics completed")); | |
} | |
// Main system loop helper functions | |
void updateSystemTimers() { | |
static unsigned long lastTimerUpdate = 0; | |
if (millis() - lastTimerUpdate >= 1000) { | |
// Update any time-based calculations here | |
lastTimerUpdate = millis(); | |
} | |
} | |
void handleEmergencyShutdown() { | |
if (currentReading.temperature > 60.0) { | |
Serial.println(F("EMERGENCY: Temperature too high!")); | |
// Open ventilation immediately | |
ventilationServo.write(SERVO_OPEN_ANGLE); | |
// Trigger emergency alarm | |
for (int i = 0; i < 10; i++) { | |
digitalWrite(LED_RED, HIGH); | |
digitalWrite(BUZZER_PIN, HIGH); | |
delay(100); | |
digitalWrite(LED_RED, LOW); | |
digitalWrite(BUZZER_PIN, LOW); | |
delay(100); | |
} | |
currentStatus = STATUS_ERROR; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment