Skip to content

Instantly share code, notes, and snippets.

@ajangrahmat
Created June 11, 2025 08:53
Show Gist options
  • Save ajangrahmat/66c0245f0dbe6a67518e1845bfe10f29 to your computer and use it in GitHub Desktop.
Save ajangrahmat/66c0245f0dbe6a67518e1845bfe10f29 to your computer and use it in GitHub Desktop.
/*
* 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