#include <EEPROM.h>
#include <TimerOne.h>
#include <avr/wdt.h>
// --- تنظیمات ---
#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;
// --- EEPROM ---
#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 ---
int pirHitCount[NUM_SENSORS] = {0};
unsigned long pirLastWindow[NUM_SENSORS] = {0};
const unsigned long PIR_WINDOW = 600;
const int PIR_REQUIRED_HITS = 2;
// --- بوق ---
volatile bool beepRequested = false;
volatile int beepCount = 0;
// --- EEPROM: وضعیت سیستم ---
void safeEEPROMWrite(int addr, byte value) {
if (EEPROM.read(addr) != value) EEPROM.write(addr, value);
}
void saveSystemState() {
safeEEPROMWrite(EEPROM_ADDR_ARMED, systemArmed);
safeEEPROMWrite(EEPROM_ADDR_SILENT, silentMode);
safeEEPROMWrite(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("⚠️ تنظیمات پیشفرض بهدلیل خرابی دادههای EEPROM بارگذاری شد");
}
}
void saveSensorLatchState() {
for (int i = 0; i < NUM_SENSORS; i++) {
safeEEPROMWrite(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);
}
}
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) {
noInterrupts();
if (!beepRequested) {
beepCount = times * 2;
beepRequested = true;
}
interrupts();
}
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) {
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();
}
int readBatteryAverage() {
long sum = 0;
for (int i = 0; i < 10; i++) sum += analogRead(batteryAnalogPin);
return sum / 10;
}
void checkBattery() {
static bool lastChargingState = false;
static int lastBatteryPercent = -1;
int rawBattery = readBatteryAverage();
float voltageBattery = (rawBattery * 5.0 / 1023.0) * batteryDividerRatio;
if (!isCharging && voltageBattery < batteryStartCharge) {
digitalWrite(batteryRelayPin, HIGH);
isCharging = true;
} else if (isCharging && voltageBattery >= batteryStopCharge) {
digitalWrite(batteryRelayPin, LOW);
isCharging = false;
}
if (isCharging != lastChargingState) {
if (isCharging) {
Serial.println("🔋 شارژ باتری فعال شد");
} else {
Serial.println("✅ شارژ باتری قطع شد");
}
lastChargingState = isCharging;
}
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(" %");
}
}
void setup() {
wdt_enable(WDTO_8S);
Serial.begin(9600);
Serial.println("🛡️ دزدگیر راهاندازی شد");
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);
Timer1.initialize(10000); // 10 میلیثانیه
Timer1.attachInterrupt(timerISR);
loadSystemState();
loadSensorLatchState();
// اگر سیستم غیر فعال است، سنسورها خاموش شوند
if (!systemArmed) resetSensorLEDs();
updateStatusLEDs();
}
void loop() {
wdt_reset();
// --- دبیانسر نرمافزاری برای کلیدهای ریموت ---
for (int i = 0; i < NUM_REMOTE_KEYS; i++) {
if (digitalRead(remotePins[i]) == HIGH && !remoteLock[i]) {
delay(30);
if (digitalRead(remotePins[i]) == HIGH) {
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();
activateAlarm();
if (!sensorLatched[i]) {
sensorLatched[i] = true;
saveSensorLatchState();
Serial.print("🚨 تحریک از سنسور ");
Serial.println(i + 1);
updateStatusLEDs();
}
}
}
}
if (buzzerActive && millis() - lastMotionTime > alarmDuration) {
buzzerActive = false;
digitalWrite(buzzerPin, LOW);
Serial.println("🔕 آژیر خودکار قطع شد");
}
checkBattery();
}