- KFS × Navera
- IoT & AI for Smart Agriculture
- السيشن 12
التحكم عن بعد + أمان الويب
Remote Control + Web Security
من العرض إلى الفعل: التحكم في مضخة الري ومروحة الصوبة من المتصفح عبر Relay، بتصميم آمن ضد الأعطال (Fail-safe)، ومصادقة المستخدمين، وحماية من الهجمات الشائعة (CSRF، تخمين كلمات السر، أوامر مزيفة) — لأن ثغرة في نظام ري تعني ماءً مهدراً أو محصولاً تالفاً.
نظرة عامة على السيشن
بنهاية السيشن ستكون قادراً على
- توصل Relay أو MOSFET بالمضخة توصيلاً آمناً وتصمم دائرة Fail-safe (OFF عند البدء وعند فقد الاتصال).
- تشرح تدفق الأمر Dashboard → API → Node → Relay → ACK وحالاته (pending / delivered / done / expired).
- تطبق Authentication (جلسة بكلمة سر مشفرة Hash) و Authorization (من يحق له الأمر).
- تحمي النماذج من CSRF وتحد من Brute force وتتحقق من كل مدخل على السيرفر.
- تعرف دور HTTPS و Tokens (API key / JWT) وأين يُستخدم كل منها.
التطبيق في مزرعة الكلية
تشغيل مضخة الري وإيقافها من المتصفح بتأكيد أمني: المشرف يسجل دخوله، يختار الحقل والمدة، يؤكد، فتستلم العقدة الأمر خلال 30 ثانية وتشغل الـ Relay، ثم تطفئ المضخة تلقائياً بعد المدة حتى لو انقطع الاتصال.
المُخرج (Deliverable)
نظام تحكم ثنائي الاتجاه آمن (عرض + أوامر): أمر مضخة من لوحة التحكم ← API بمصادقة و CSRF ← العقدة ← Relay ← ACK، مع حد أقصى لزمن التشغيل وسجل لكل أمر.
خطة السيشن (180 دقيقة)
- 0:00 مراجعة مراجعة: لوحة التحكم ونتائج اختبار المشرف 10 د
- 0:10 شرح المشغلات: Relay و MOSFET والتصميم الآمن ضد الأعطال 25 د
- 0:35 محاكاة Tinkercad: مضخة بـ Relay بأوامر Serial ومهلة أمان 30 د
- 1:05 شرح أمان الويب: هجمات حقيقية على نظام ري وكيف نصده 30 د
- 1:35 استراحة استراحة 10 د
- 1:45 تطبيق Lab: دورة الأمر الكاملة في منصة Smart Farm 35 د
- 2:20 ميداني ميداني: تشغيل المضخة من المتصفح بتأكيد أمني 30 د
- 2:50 تقييم اختبار سريع + الواجب 10 د
الأدوات والمكونات
قاموس المصطلحات (Glossary)
جهاز ينفذ فعلاً: مضخة، مروحة، صمام.
مفتاح كهرومغناطيسي معزول — مناسب للتيار المتردد والمستمر.
مفتاح إلكتروني صامت وسريع لأحمال DC ويدعم PWM.
Relay يعمل عندما يكون الطرف LOW — مهم لحالة البدء.
يمتص الجهد العكسي من ملف المضخة/الريلاي.
أي عطل يقود النظام لحالة آمنة (المضخة OFF).
من أنت؟ (اسم مستخدم وكلمة سر).
ماذا يحق لك أن تفعل؟
تخزين بصمة غير قابلة للعكس بدل كلمة السر نفسها.
موقع خبيث يرسل أمراً باسمك لأنك مسجل الدخول.
تجربة آلاف كلمات السر — نحدها بـ Rate limiting.
رمز يثبت هوية جهاز أو تطبيق بدون كلمة سر.
المشغلات والتصميم الآمن
25 دقيقة| Relay module | MOSFET (IRLZ44N) | |
|---|---|---|
| الأحمال | AC و DC (حتى 10A حسب الموديول) | DC فقط |
| التحكم في السرعة | لا — تشغيل/إيقاف فقط | نعم بـ PWM |
| العزل | عزل كهربي كامل | أرضي مشترك |
| الصوت والعمر | نقرة، عمر ميكانيكي محدود | صامت، عمر طويل |
| في مشروعنا | مضخة المزرعة (يوصلها فني الكهرباء) | مضخة 5V/12V المعمل والمروحة |
قواعد Fail-safe لعقدة تتحكم في الري
- عند تشغيل العقدة: كل المشغلات OFF قبل أي شيء آخر (أول سطرين في setup).
- كل أمر تشغيل له مدة، والعقدة تطفئ وحدها عند انتهائها — لا تعتمد على أمر الإيقاف.
- حد أقصى للتشغيل في الـ firmware (30 دقيقة) حتى لو طلب السيرفر أكثر.
- انقطع الاتصال بالسيرفر؟ أطفئ المضخة.
- الأوامر القديمة (أكثر من 10 دقائق) تنتهي ولا تُنفذ متأخرة.
كهرباء + ماء
الطلاب يعملون فقط بمضخات 5–12V DC من مصدر منفصل. الـ Relay على جانب 220V للمضخة الحقيقية يركبه فني المزرعة داخل لوحة مغلقة بقاطع أرضي (RCD 30mA). لا تلمس أطراف الـ Relay أثناء التشغيل.
Tinkercad: مضخة بـ Relay
30 دقيقةوحدة تحكم مضخة: أوامر Serial + مدة + حماية من الري الزائد
30 دقيقةنحاكي ما تفعله العقدة عند استلام أمر من السيرفر: P5 = شغّل 5 ثوانٍ (= دقائق في الحقيقة)، P0 = أوقف. العقدة ترفض التشغيل إذا كانت التربة مشبعة، وتطفئ وحدها عند انتهاء المدة.
المكونات (Components)
- Arduino Uno R3
- Relay SPDT
- DC Motor (المضخة)
- 9V Battery (مصدر المضخة)
- Diode
- NPN transistor + 1kΩ (لتشغيل ملف الـ Relay)
- Soil Moisture Sensor
- LED أحمر + 220Ω
التوصيل (Wiring)
| من | إلى | ملاحظة |
|---|---|---|
| D7 → 1kΩ | Base الترانزستور | الترانزستور يشغل ملف الـ Relay |
| ملف Relay | 5V ↔ Collector | Diode بالتوازي مع الملف (عكسي) |
| 9V + | Relay COM → NO → Motor + | Motor − إلى 9V − |
| Soil SIG | A1 | |
| D12 | LED أحمر | رفض/إنذار |
ابنِ الدائرة: الـ Arduino لا يغذي المحرك أبداً — بطارية 9V منفصلة عبر تلامس الـ Relay.
شغّل وأرسل
P5في Serial Monitor: المحرك يدور 5 ثوانٍ ثم يتوقف وحده.اجعل حساس التربة مبللاً جداً وأرسل
P5: يرفض ويضيء الأحمر.أرسل
P99: يُقص إلى الحد الأقصى 30.
// Pump controller - simulates a farm node executing server commands
const int RELAY = 7, ALARM = 12, SOIL = A1;
const int MAX_RUN_S = 30; // hard limit in firmware
const int SOIL_WET_LIMIT = 700; // Tinkercad soil sensor: higher = wetter
unsigned long offAt = 0;
void pump(bool on) { digitalWrite(RELAY, on ? HIGH : LOW); }
void setup() {
pinMode(RELAY, OUTPUT); pinMode(ALARM, OUTPUT);
pump(false); // FAIL-SAFE: off before anything else
Serial.begin(9600);
Serial.println("Commands: P<seconds> (e.g. P5) | P0 = stop | S = status");
}
void loop() {
if (Serial.available()) {
String cmd = Serial.readStringUntil('\n'); cmd.trim();
if (cmd.startsWith("P")) {
int secs = constrain(cmd.substring(1).toInt(), 0, MAX_RUN_S);
int soil = analogRead(SOIL);
if (secs > 0 && soil > SOIL_WET_LIMIT) {
digitalWrite(ALARM, HIGH);
Serial.println("REJECTED: soil already wet (" + String(soil) + ")");
} else {
digitalWrite(ALARM, LOW);
pump(secs > 0);
offAt = secs > 0 ? millis() + secs * 1000UL : 0;
Serial.println(secs > 0 ? "ACK pump ON for " + String(secs) + " s" : "ACK pump OFF");
}
} else if (cmd == "S") {
Serial.println(String("pump=") + digitalRead(RELAY) + " soil=" + analogRead(SOIL));
}
}
if (offAt && millis() > offAt) { pump(false); offAt = 0; Serial.println("auto-off (duration reached)"); }
}
أمان الويب لنظام ري
30 دقيقةتخيل أن رابط /api/pump/on بدون حماية. أي طالب على شبكة المزرعة — أو برنامج خبيث على هاتف متصل — يستطيع تشغيل المضخة طوال الليل. الأمان هنا ليس رفاهية: إنه حماية للمياه والمحصول والمعدات.
| الهجوم | السيناريو في المزرعة | الدفاع في الكود |
|---|---|---|
| وصول بدون تسجيل | شخص يفتح لوحة التحكم ويشغل المضخة | @login_required على كل الصفحات والأوامر |
| سرقة كلمة السر من القاعدة | نسخة من farm.db تسربت | تخزين Hash فقط (generate_password_hash) |
| Brute force | سكربت يجرب آلاف كلمات السر | 5 محاولات فاشلة ⇒ إيقاف 10 دقائق |
| CSRF | صفحة خبيثة ترسل POST باسم المشرف المسجل | CSRF token في كل أمر + SameSite=Lax |
| عقدة مزيفة | جهاز يرسل قراءات «جاف» ليشغل الري | X-API-Key للعقد + مقارنة ثابتة الزمن (hmac.compare_digest) |
| مدخلات خبيثة | duration_min = 99999 أو actuator = "rm" | قائمة مسموحات (pump/fan) + حد أقصى 30 دقيقة |
| تنفيذ أمر قديم | أمر من الأمس يُنفذ عند عودة العقدة | انتهاء صلاحية الأوامر بعد 10 دقائق |
| التنصت على الشبكة | قراءة كلمة السر من Wi-Fi | HTTPS (شهادة محلية) + شبكة IoT معزولة بكلمة سر WPA2 |
@app.post("/api/v1/commands")
@login_required # 1) authenticated user only
def create_command():
check_csrf() # 2) token must match the session -> no CSRF
data = request.get_json(silent=True) or {}
actuator, action = data.get("actuator"), data.get("action")
if actuator not in ("pump", "fan") or action not in ("on", "off"): # 3) allow-list
return jsonify(error="invalid command"), 400
if data.get("confirm") is not True: # 4) explicit confirmation from the UI
return jsonify(error="confirmation required"), 400
minutes = max(0, min(int(data.get("duration_min", 5)), config.PUMP_MAX_MIN)) # 5) hard limit
...
db.log_decision(now(), node_id, "manual", "info", f"{session['user']}: {actuator} {action} {minutes} min") # 6) audit log
متى نستخدم JWT؟
لوحتنا تستخدم جلسة (Session cookie) لأنها صفحة ويب على نفس السيرفر — أبسط وأكثر أماناً. JWT مفيد عندما يكون العميل تطبيق هاتف أو خدمة أخرى تستدعي الـ API. والعقد تستخدم API key (يمكن ترقيته لمفتاح لكل عقدة).
Lab: دورة الأمر الكاملة
35 دقيقةحياة أمر تشغيل المضخة
-
pending
المشرف يضغط «تشغيل» ويؤكد ⇒ POST /api/v1/commands ⇒ صف جديد بالحالة pending.
-
delivered
العقدة تسأل كل 30 ث: GET /api/v1/commands/pending?node_id=field_A ⇒ تستلم الأمر وتتحول الحالة delivered.
-
تنفيذ
العقدة تشغل الـ Relay وتضبط مؤقت الإطفاء الذاتي.
-
done
العقدة ترسل POST /api/v1/commands/<id>/ack ⇒ done، ويظهر في سجل القرارات.
-
expired
إن لم تسأل العقدة خلال 10 دقائق ⇒ الأمر ينتهي ولا ينفذ أبداً.
تشغيل مضخة 5V من لوحة التحكم
- التوصيل
Relay IN1 → GPIO 26، VCC → 5V (VIN)، GND مشترك. المضخة على تلامس COM/NO ومن مصدرها المنفصل، والـ Diode عكسياً على أطرافها.
- الـ firmware
ارفع esp32_node_http.ino — لاحظ
relay(PUMP_PIN, false)أول سطر في setup. - الأمر
من اللوحة: العقدة field_A، المضخة، دقيقة واحدة، تشغيل ⇒ أكّد.
- المراقبة
Serial Monitor للعقدة: «CMD #… pump on» ثم بعد دقيقة «pump auto-off».
- اختبار الأمان
شغّل المضخة 5 دقائق ثم افصل الراوتر: تتوقف المضخة عند أول محاولة اتصال فاشلة.
- اختبار CSRF
من Console المتصفح نفذ fetch POST بدون رأس X-CSRF-Token ⇒ يجب أن يرد 403.
النتيجة المتوقعة: المضخة تعمل المدة المطلوبة فقط، والأمر يظهر في السجل بـ done، والطلب بدون CSRF يُرفض.
نتيجة اختبارات الأمان والتحكم (Flask test client)
هذه سيناريوهات اختبرناها فعلياً على الكود قبل نشره:
المخرجات الفعلية عند التشغيل (Real output)
GET / (no login) -> 302 redirect to /login
POST /api/v1/readings (no API key) -> 401
POST /login (wrong password) -> error message
POST /api/v1/commands (no CSRF token) -> 403
POST /api/v1/commands (no confirm) -> 400
POST /api/v1/commands (duration 99) -> 201, stored as 30 min (PUMP_MAX_MIN)
GET /commands/pending (node) -> [{'duration_min': 30, ...}] then empty after ACK
ALL TESTS PASSEDميداني: المضخة من المتصفح
30 دقيقةتشغيل/إيقاف الري من المتصفح بتأكيد أمني
أصيص تجربة في الصوبة (مضخة 5V من دلو) — أو خط تنقيط حقيقي عبر Relay يركبه فني المزرعة
- التحضير
عقدة الصوبة متصلة، وحساس التربة في الأصيص، والمضخة في دلو ماء بخرطوم إلى الأصيص.
- الري عن بعد
المشرف من هاتفه (تسجيل دخول) يأمر بري 2 دقيقة.
- الأثر
راقبوا رطوبة التربة على اللوحة: بعد كم ثانية بدأت ترتفع؟ وكم ارتفعت؟
- اختبار الرفض
حاول تشغيل المضخة من حساب غير مسجل أو بعد انتهاء الجلسة.
- السجل
اعرض سجل القرارات: من أمر؟ متى؟ كم دقيقة؟ هل اكتمل (done)؟
| الأمر # | من | المدة | زمن الوصول للعقدة (ث) | رطوبة قبل | رطوبة بعد 5 د |
|---|---|---|---|---|---|
- الدلو والمضخة على أرضية الصوبة، والإلكترونيات مرفوعة في علبة.
- الفني فقط يتعامل مع جانب 220V.
اختبر فهمك
6 أسئلة · نتيجة فوريةالواجب والتسليم
الواجب الأسبوعي (Weekly Assignment)
ارسم مخطط التوصيل الكامل (Wiring diagram) لعقدة الري في الحقل بما فيه الـ Relay والمصدر المنفصل والـ Diode.
اكتب «نموذج تهديدات» (Threat model) لمنصة فريقك: 5 هجمات محتملة والدفاع ضد كل منها.
غيّر كلمة سر المدير ومفتاح API العقد عبر متغيرات البيئة ووثّق الطريقة (بدون كتابة القيم!).
قائمة التسليم (Submission Checklist)
استعد للسيشن القادمة
انتهت مرحلة الويب! السيشن القادمة نبدأ تحليل البيانات: ثبّت Anaconda أو pip install pandas numpy matplotlib jupyter، وحمّل بيانات المزرعة من صفحة الكورس.