#define BLYNK_TEMPLATE_ID "TMPL6T3N5bRd5"
#define BLYNK_TEMPLATE_NAME "snser"
#define BLYNK_AUTH_TOKEN "wD9tkKPZHF-RmPX5ON1BbjxHwzjsVSro"
// #define BLYNK_PRINT Serial // فعّلها لو تريد لوج على السيريال
// ==================== المكتبات ====================
#include <Wire.h>
#include <Blynk.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <ESP32Servo.h>
// ==================== التوصيلات (Hardware) ====================
#define DHTPIN 15
#define DHTTYPE DHT22
#define PIR_PIN 13
#define LED_PIN 27
#define BUZZER_PIN 12
#define SERVO_PIN 14
// ==================== العتبات (منطق التشغيل) ====================
const float TEMP_HIGH = 30.0; // °C
const float HUMI_HIGH = 70.0; // %
// ==================== Wi-Fi (Wokwi) ====================
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
// ==================== كائنات عامة ====================
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo vent;
BlynkTimer timer;
// ==================== فلترة (متوسط متحرك) ====================
static const int N = 5;
float tBuf[N] = {0}, hBuf[N] = {0};
int idx = 0; bool bufFilled = false;
// ==================== متغيرات ====================
float T = NAN, H = NAN; // القيم المفلترة
int m = 0; // PIR 0/1
int servoPos = 0; // زاوية السيرفو (للإرسال)
// ==================== توابع مساعدة ====================
float avg(float* a, int n) {
if (n <= 0) return NAN;
float s = 0; for (int i=0;i<n;i++) s += a[i];
return s / n;
}
void ensureWiFi() {
if (WiFi.status() == WL_CONNECTED) return;
WiFi.disconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASS);
unsigned long t0 = millis();
while (WiFi.status() != WL_CONNECTED && (millis() - t0) < 8000) delay(100);
}
void ensureBlynk() {
if (!Blynk.connected()) Blynk.connect(1000);
}
// ==================== مهام دورية ====================
void readSensors() {
m = digitalRead(PIR_PIN); // PIR
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
// لو القراءة فاشلة، لا نحدّث T/H هذه الدورة
return;
}
tBuf[idx] = t; hBuf[idx] = h;
idx = (idx + 1) % N; if (idx == 0) bufFilled = true;
T = avg(tBuf, bufFilled ? N : idx);
H = avg(hBuf, bufFilled ? N : idx);
// LCD
lcd.clear();
lcd.setCursor(0,0);
lcd.print("T:"); lcd.print(T,1); lcd.print((char)223); lcd.print("C ");
lcd.print("H:"); lcd.print(H,0); lcd.print("%");
lcd.setCursor(0,1);
lcd.print("m:"); lcd.print(m ? "1":"0");
if (T >= TEMP_HIGH) lcd.print(" HOT");
else if (H >= HUMI_HIGH) lcd.print(" HUM");
else lcd.print(" OK ");
}
void outputsLogic() {
// LED: ثابت لو حرارة عالية، وميض لو رطوبة عالية، وإلا مطفأ
static bool blinkState = false;
if (!isnan(T) && T >= TEMP_HIGH) {
digitalWrite(LED_PIN, HIGH);
} else if (!isnan(H) && H >= HUMI_HIGH) {
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState ? HIGH : LOW);
} else {
digitalWrite(LED_PIN, LOW);
}
// Buzzer: يعمل فقط عند حرارة عالية ومع وجود حركة
if (!isnan(T) && T >= TEMP_HIGH && m) digitalWrite(BUZZER_PIN, HIGH);
else digitalWrite(BUZZER_PIN, LOW);
// Servo: 90° عند حرارة عالية، 0° غير ذلك
servoPos = (!isnan(T) && T >= TEMP_HIGH) ? 90 : 0;
vent.write(servoPos);
}
void sendToBlynk() {
if (!Blynk.connected()) return;
// إرسال القيم كلٌ على حدة
if (!isnan(T)) Blynk.virtualWrite(V0, T); // Temperature
if (!isnan(H)) Blynk.virtualWrite(V1, H); // Humidity
Blynk.virtualWrite(V2, servoPos); // Servo Angle (0..180)
Blynk.virtualWrite(V3, m); // Motion (0/1)
Blynk.virtualWrite(V4, digitalRead(LED_PIN)); // LED State (0/1)
Blynk.virtualWrite(V5, digitalRead(BUZZER_PIN)); // Buzzer State (0/1)
}
// يمكن إضافة مزامنة لاحقًا إن احتجت استقبال قيم من التطبيق
BLYNK_CONNECTED() {}
// ==================== setup / loop ====================
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
dht.begin();
lcd.init(); lcd.backlight();
vent.attach(SERVO_PIN);
vent.write(0); servoPos = 0;
ensureWiFi();
Blynk.config(BLYNK_AUTH_TOKEN); // إدارة الواي فاي يدويًا
ensureBlynk();
// جدولة المهام
timer.setInterval(2000L, readSensors);
timer.setInterval(1000L, outputsLogic);
timer.setInterval(2000L, sendToBlynk);
timer.setInterval(5000L, ensureWiFi);
timer.setInterval(5000L, ensureBlynk);
// إرسال مبدئي
sendToBlynk();
}
void loop() {
Blynk.run();
timer.run();
}