#include <EEPROM.h>
#include <TimerOne.h>
#include <avr/wdt.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define NUM_SENSORS 3
#define NUM_REMOTE_KEYS 4
const int sensorPins[NUM_SENSORS] = {2, 3, 4};
const int remotePins[NUM_REMOTE_KEYS] = {6, 7, 8, 9};
const int buzzerPin = 5;
const int ledArmedPin = 10;
const int ledDisarmedPin = 11;
const int ledSilentPin = 12;
const int ledSensorPins[NUM_SENSORS] = {A0, A1, A2};
const int batteryRelayPin = A5;
const int batteryAnalogPin = A3;
const float batteryStartCharge = 12.4;
const float batteryStopCharge = 12.6;
const float batteryDividerRatio = 2.6;
#define EEPROM_ADDR_ARMED 0
#define EEPROM_ADDR_SILENT 1
#define EEPROM_MAGIC_ADDR 10
#define EEPROM_MAGIC_VALUE 0xAB
#define EEPROM_ADDR_SENSOR_LATCHED 20
bool systemArmed = false;
bool silentMode = false;
bool buzzerActive = false;
bool sensorTriggered = false;
bool sensorLatched[NUM_SENSORS] = {false};
bool remoteLock[NUM_REMOTE_KEYS] = {false};
bool isCharging = false;
unsigned long lastMotionTime = 0;
const unsigned long alarmDuration = 20000;
// PIR Filtering
int pirHitCount[NUM_SENSORS] = {0};
unsigned long pirLastWindow[NUM_SENSORS] = {0};
const unsigned long PIR_WINDOW = 600;
const int PIR_REQUIRED_HITS = 2;
// LCD Control
unsigned long lcdBacklightTimer = 0;
bool lcdBacklightState = true;
const unsigned long LCD_BACKLIGHT_TIMEOUT = 10000;
// LCD Sensor Trigger Display
bool lcdSensorMsgActive = false;
unsigned long lcdSensorMsgTimer = 0;
const unsigned long LCD_SENSOR_MSG_DURATION = 20000;
// Buzzer
volatile bool beepRequested = false;
volatile int beepCount = 0;
// Battery Monitoring
int lastBatteryPercent = -1;
bool lastChargingState = false;
String lastModeLabel = "";
void saveSystemState() {
EEPROM.write(EEPROM_ADDR_ARMED, systemArmed);
EEPROM.write(EEPROM_ADDR_SILENT, silentMode);
EEPROM.write(EEPROM_MAGIC_ADDR, EEPROM_MAGIC_VALUE);
}
void loadSystemState() {
byte magic = EEPROM.read(EEPROM_MAGIC_ADDR);
if (magic == EEPROM_MAGIC_VALUE) {
systemArmed = EEPROM.read(EEPROM_ADDR_ARMED);
silentMode = EEPROM.read(EEPROM_ADDR_SILENT);
Serial.println(systemArmed ? (silentMode ? "✅ دزدگیر فعال (سایلنت)" : "✅ دزدگیر فعال") : "❌ دزدگیر غیرفعال");
} else {
systemArmed = false;
silentMode = false;
saveSystemState();
Serial.println("⚠️ تنظیمات پیشفرض بارگذاری شد");
}
}
void saveSensorLatchState() {
for (int i = 0; i < NUM_SENSORS; i++) {
EEPROM.write(EEPROM_ADDR_SENSOR_LATCHED + i, sensorLatched[i]);
}
}
void loadSensorLatchState() {
for (int i = 0; i < NUM_SENSORS; i++) {
sensorLatched[i] = EEPROM.read(EEPROM_ADDR_SENSOR_LATCHED + i);
digitalWrite(ledSensorPins[i], sensorLatched[i]);
}
}
bool isReliablePIR(int index) {
if (digitalRead(sensorPins[index]) == HIGH) {
unsigned long now = millis();
if (now - pirLastWindow[index] > PIR_WINDOW) {
pirHitCount[index] = 1;
pirLastWindow[index] = now;
} else {
pirHitCount[index]++;
pirLastWindow[index] = now;
if (pirHitCount[index] >= PIR_REQUIRED_HITS) {
pirHitCount[index] = 0;
return true;
}
}
}
return false;
}
void requestBeep(int times) {
if (!beepRequested) {
beepCount = times * 2;
beepRequested = true;
}
}
void timerISR() {
static bool buzzerState = false;
static int intervalCounter = 0;
if (beepRequested && beepCount > 0) {
if (intervalCounter == 0) {
buzzerState = !buzzerState;
digitalWrite(buzzerPin, buzzerState);
if (!buzzerState && --beepCount == 0)
beepRequested = false;
intervalCounter = 2;
} else intervalCounter--;
}
}
void activateAlarm() {
if (!silentMode) {
buzzerActive = true;
digitalWrite(buzzerPin, HIGH);
}
}
void updateStatusLEDs() {
digitalWrite(ledArmedPin, systemArmed && !silentMode);
digitalWrite(ledSilentPin, systemArmed && silentMode);
digitalWrite(ledDisarmedPin, !systemArmed);
for (int i = 0; i < NUM_SENSORS; i++) {
digitalWrite(ledSensorPins[i], sensorLatched[i]);
}
}
void resetSensorLEDs() {
for (int i = 0; i < NUM_SENSORS; i++) {
sensorLatched[i] = false;
digitalWrite(ledSensorPins[i], LOW);
}
saveSensorLatchState();
}
void handleRemoteCommand(int key) {
lcdBacklightState = true;
lcdBacklightTimer = millis();
lcd.backlight();
switch (key) {
case 0:
if (!systemArmed || silentMode) {
systemArmed = true;
silentMode = false;
sensorTriggered = false;
resetSensorLEDs();
saveSystemState();
requestBeep(1);
Serial.println("✅ دزدگیر فعال شد");
}
break;
case 1:
if (systemArmed) {
systemArmed = false;
silentMode = false;
buzzerActive = false;
sensorTriggered = false;
digitalWrite(buzzerPin, LOW);
saveSystemState();
requestBeep(1);
Serial.println("❌ دزدگیر غیرفعال شد");
}
break;
case 2:
if (!systemArmed || !silentMode) {
systemArmed = true;
silentMode = true;
sensorTriggered = false;
resetSensorLEDs();
saveSystemState();
requestBeep(1);
Serial.println("🔇 دزدگیر فعال شد (سایلنت)");
}
break;
case 3:
if (buzzerActive) {
buzzerActive = false;
digitalWrite(buzzerPin, LOW);
requestBeep(1);
Serial.println("🛑 آژیر دستی خاموش شد");
}
break;
}
updateStatusLEDs();
}
void checkBattery() {
int rawBattery = analogRead(batteryAnalogPin);
float voltageBattery = (rawBattery * 5.0 / 1023.0) * batteryDividerRatio;
if (!isCharging && voltageBattery < batteryStartCharge) {
digitalWrite(batteryRelayPin, HIGH);
isCharging = true;
Serial.println("🔋 شارژ باتری شروع شد");
} else if (isCharging && voltageBattery >= batteryStopCharge) {
digitalWrite(batteryRelayPin, LOW);
isCharging = false;
Serial.println("✅ شارژ باتری متوقف شد");
}
float percentage = ((voltageBattery - 11.0) / (12.6 - 11.0)) * 100.0;
percentage = constrain(percentage, 0, 100);
int percentInt = round(percentage);
if (percentInt != lastBatteryPercent) {
lastBatteryPercent = percentInt;
Serial.print("🔋 درصد شارژ باتری: ");
Serial.print(percentInt);
Serial.println(" %");
}
if (isCharging != lastChargingState) {
lastChargingState = isCharging;
}
}
void updateLCDStatus() {
if (lcdSensorMsgActive) return;
lcd.setCursor(0, 0);
lcd.print("Mode: ");
lcd.print(systemArmed ? (silentMode ? "Silent " : "Active ") : "Disarmed ");
lcd.print(" ");
lcd.setCursor(0, 1);
if (isCharging)
lcd.print("Charging ");
else {
lcd.print("Battery ");
lcd.print(lastBatteryPercent);
lcd.print("% ");
}
}
void setup() {
wdt_enable(WDTO_8S);
Serial.begin(9600);
for (int i = 0; i < NUM_SENSORS; i++) {
pinMode(sensorPins[i], INPUT);
pinMode(ledSensorPins[i], OUTPUT);
}
for (int i = 0; i < NUM_REMOTE_KEYS; i++) pinMode(remotePins[i], INPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(ledArmedPin, OUTPUT);
pinMode(ledDisarmedPin, OUTPUT);
pinMode(ledSilentPin, OUTPUT);
pinMode(batteryRelayPin, OUTPUT);
digitalWrite(batteryRelayPin, LOW);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Alarm System ");
lcd.setCursor(0, 1);
lcd.print("Initializing... ");
delay(1000);
lcd.clear();
Timer1.initialize(10000);
Timer1.attachInterrupt(timerISR);
loadSystemState();
loadSensorLatchState();
updateStatusLEDs();
updateLCDStatus();
}
void loop() {
wdt_reset();
for (int i = 0; i < NUM_REMOTE_KEYS; i++) {
if (digitalRead(remotePins[i]) == HIGH && !remoteLock[i]) {
handleRemoteCommand(i);
remoteLock[i] = true;
} else if (digitalRead(remotePins[i]) == LOW) {
remoteLock[i] = false;
}
}
if (systemArmed) {
for (int i = 0; i < NUM_SENSORS; i++) {
if (isReliablePIR(i)) {
sensorTriggered = true;
lastMotionTime = millis();
if (!silentMode) activateAlarm();
if (!sensorLatched[i]) {
sensorLatched[i] = true;
saveSensorLatchState();
}
Serial.print("🚨 تحریک سنسور ");
Serial.print(i + 1);
Serial.println();
updateStatusLEDs();
lcd.clear();
lcd.setCursor(0, 0);
char line1[17];
snprintf(line1, 17, "Sensor %d Triggered", i + 1);
lcd.print(line1);
lcd.setCursor(0, 1);
lcd.print("Mode: ");
lcd.print(silentMode ? "Silent " : "Active ");
lcdSensorMsgTimer = millis();
lcdSensorMsgActive = true;
}
}
}
if (buzzerActive && millis() - lastMotionTime > alarmDuration) {
buzzerActive = false;
digitalWrite(buzzerPin, LOW);
Serial.println("🔕 آژیر خودکار قطع شد");
}
if (lcdSensorMsgActive && millis() - lcdSensorMsgTimer > LCD_SENSOR_MSG_DURATION) {
lcdSensorMsgActive = false;
lcd.clear();
updateLCDStatus();
}
if (lcdBacklightState && millis() - lcdBacklightTimer > LCD_BACKLIGHT_TIMEOUT) {
lcdBacklightState = false;
lcd.noBacklight();
}
checkBattery();
updateLCDStatus();
}