انتقل إلى المحتوى الرئيسي

إدارة WiFi

يملك main/wifi_manager.c كل ما يتعلق بالراديو: التزويد، الارتباط، إعادة المحاولة، والتشخيصات. وهو أيضاً موطن أغرب خطأ عتادي صادف هذا المشروع، والذي أصبح إصلاحه الآن ميزة.

الارتباط من الصفر

الانضمام إلى شبكة WiFi محادثة ثابتة الخطوات: تسمع المحطة حزم منارة الشبكة (أو ترسل استطلاعاً عنها)، ثم ترسل إطار مصادقة، ثم طلب ارتباط، ثم تنفذ المصافحة رباعية الاتجاهات التي تثبت أن الطرفين يعرفان كلمة المرور وتشتق مفاتيح الحركة. بعد اكتمال الخطوات الأربع فقط يوزع DHCP عنوان IP.

يفشل كل خطوة بشكل مميز، ويبلغ عن فشلها استدعاء انقطاع الاتصال في ESP-IDF برقم سبب. الأرقام التي تستحق الحفظ، لأن المدير يسجلها عند كل إعادة محاولة:

السببالخطوة التي فشلتالحقيقة المعتادة
201 NO_AP_FOUNDلم يسمع الشبكة إطلاقاًSSID خاطئ، أو خارج المدى، أو شبكة 5 غيغاهرتز فقط
2 AUTH_EXPIREإطار المصادقة لم يتلق جواباًتجاهلنا الموجّه: تصفية MAC، أو أن إطارنا لم يصل فيزيائياً أصلاً
15 / 204المصافحة رباعية الاتجاهاتكلمة مرور خاطئة
205الارتباطفشل اتصال عام، وغالباً ما يتبع أحد الأسباب أعلاه

كما يشغل المدير مسحاً تشخيصياً بعد الفشل النهائي ويسجل كل شبكة مرئية مع القناة والإشارة ووضع المصادقة. سطر السجل الوحيد، Target SSID not visible on 2.4 GHz (5 GHz-only network?)، موجود لأن هذا الخطأ في الضبط وحده ربما يحرق ساعات الهواة أكثر من أي خطأ آخر.

التزويد: المسارات الثلاثة

بالترتيب، عند كل إقلاع: بيانات اعتماد محفوظة في NVS (مهلة 8 ثوانٍ)، ثم بيانات اعتماد Kconfig مضمّنة في البناء (18 ثانية، بمقاس يتيح اكتمال سلم قدرة الإرسال أدناه)، ثم التزويد عبر SoftAP من خلال مكوّن espressif/network_provisioning (أزال ESP-IDF v6 تقنية SmartConfig، فحل هذا محلها). يعلن الجهاز عن نقطة وصول مفتوحة باسم Safi-XXXXXX (الجزء اللاحق من آخر ثلاث بايتات من عنوان MAC الخاص بمحطة WiFi STA)، ويدفع تطبيق الهاتف "ESP SoftAP Provisioning" من Espressif بيانات الاعتماد عبر جلسة protocomm بالمستوى الأمني 2: مصادقة SRP6a إضافة إلى تشفير AES-GCM، ترسو على رمز إثبات حيازة من 16 محرفاً. تشتق بنيات الإنتاج PoP عند الإقلاع كـ HMAC-SHA256(السر المصنعي، عنوان MAC الأساسي) في main/pop_derive.c بدلاً من تخزينه؛ وينفذ tools/nvs_mass_provisioning.py الاشتقاق نفسه في المصنع، لذا يطابق الملصق البرنامج الثابت دائماً. أما بنيات التطوير فتعود إلى NVS (نطاق الأسماء provisioning، المفتاح pop) وتولّد PoP عشوائياً عند أول إقلاع، يُطبع مرة واحدة على المنفذ التسلسلي. تُحفظ بيانات الاعتماد المستلمة في NVS وتُستخدم فوراً؛ التدفق الكامل المواجه للمستخدم في دليل المستخدم. يضيف الكود تعقيداً واحداً جديراً بالمعرفة: علم suppress_retry متعمد يحيط بالمسح التشخيصي، لأن قطع الاتصال الذي يسبق المسح كان ليسابق منطق إعادة المحاولة التلقائية ليدخل في المسح نفسه.

لماذا نقطة الوصول مفتوحة بدلاً من كونها محمية بعبارة مرور، ولماذا أُجّل wpa3_compatible_mode: فصل الأمان.

سلم قدرة الإرسال

القصة من الميدان. أثناء التشغيل الأول، كانت اللوحة ترى كل شبكة (كان المسح يسردها بإشارة قوية) لكنها لا تنضم إلى أي منها: كل محاولة كانت تموت بالسبب 2، إطار المصادقة بلا إجابة. ثلاث نقاط وصول مختلفة، من بينها واحدة تعمل على حاسوب محمول على بعد نصف متر ولها سجلاتها التي تثبت أن أي إطار مصادقة لم يصل إطلاقاً. استقبال مثالي، وإرسال ميت.

السبب: على هذه اللوحة، كانت قدرة الإرسال الكاملة الافتراضية للراديو (19.5 dBm) تسحب ذروات تيار لا يستطيع خط تغذية 3.3 فولت توفيرها بشكل نظيف، فكان كل إطار يُرسل يغادر الهوائي مشوهاً. استمر الاستقبال في العمل لأن تكلفة الاستقبال جزء من تكلفة الإرسال. كانت التجربة الحاسمة سطراً واحداً يخفض قدرة الإرسال إلى 2 dBm، فنجح الارتباط فوراً؛ أما الاكتشاف الأدق فكان أن برمجة القدرة صراحةً بعد esp_wifi_start() مباشرة أصلحت حتى القدرة الكاملة (جدول القدرة الافتراضي عند الإقلاع يسلك سلوكاً معطوباً على هذا العتاد حيث لا يسلك الضبط الصريح كذلك).

شُحن الإصلاح كسلم ذاتي الإصلاح بدلاً من رقم مبرمج ثابتاً:

static const int8_t tx_power_ladder[] = {78, 60, 44, 34, 20, 8}; // 0.25 dBm units

تبدأ كل دورة اتصال جديدة بالقدرة الكاملة؛ وكل إعادة محاولة فاشلة تنزل درجة؛ وأي درجة تتصل هي الفائزة (تُسجل القدرة المتصلة). اللوحة السليمة لا تدفع شيئاً، ومصدر التغذية الضعيف ينقذ نفسه في ثوانٍ، ويخبرك سجل المنفذ التسلسلي أي لوحة تملك. الدرس العام: عندما يستطيع الراديو السماع دون الكلام، اشتبه بسلامة التغذية قبل البرمجيات، واجعل التخفيف قابلاً للملاحظة.

توفير الطاقة: الكمون مقابل المللي أمبيرات

يوفر توفير طاقة مودم WiFi (راديو يغفو بين فترات المنارة) عشرات المللي أمبيرات ويكلف 100 إلى 300 مللي ثانية من الكمون في كل رحلة ذهاب وإياب، لأن نقطة الوصول يجب أن تخزن الإطارات مؤقتاً حتى يستيقظ الراديو. تحت توفير الطاقة الافتراضي، استغرقت مصافحات TLS إلى الجهاز (عدة رحلات إضافة إلى التشفير) أكثر من 10 ثوانٍ أثناء تشغيل الصوت: كانت لوحة التحكم تبدو ميتة.

يشغل صافي WIFI_PS_NONE. لجهاز صوتي يعمل بالكهرباء أو ببطارية كبيرة، وتشكل لوحة التحكم الحية جزءاً من جوهر قيمته، لا تشتري المللي أمبيرات شيئاً يستحق. الإعداد سطر واحد في المدير، متعمد الجوار مع استدعاء قدرة الإرسال، مع المنطق في تعليق؛ أي ملف بطارية أكثر عدوانية في المستقبل سيعيد النظر في الاثنين معاً.

إعادة الاتصال

  • ينشر انقطاع الاتصال الحدث EVENT_WIFI_DISCONNECTED (تتفاعل الشاشة ولوحة التحكم)، ويعيد مؤقت مدته 30 ثانية المحاولة من أعلى السلم.
  • ينشر الاتصال الحدث EVENT_WIFI_CONNECTED مع نص عنوان IP؛ يبدأ SNTP عند ذلك الحدث، وأي شيء آخر كان منتظراً (استئناف بث محفوظ مثلاً) يتصل بالحدث نفسه.
  • الفجوة المعروفة القديمة هنا (مسار التزويد الاحتياطي لم يعاود تجربة بيانات الاعتماد المخزنة حتى إعادة التشغيل) أُصلحت بدورة تزويد: مهمة مخصصة تتناوب بين نافذة تزويد SoftAP محدودة (SAFI_PROVISIONING_WINDOW_MIN، 10 دقائق افتراضياً) ودفقة إعادة محاولة لبيانات الاعتماد المخزنة، إلى الأبد، حتى يتصل أحد المسارين. لا يمكن تداخل الطورين لأن واجهتي SoftAP والمحطة تتشاركان راديو واحداً؛ والتناوب هو الجواب القياسي للأجهزة دون شاشة تحكم.
  • يشغل المدير أيضاً مستجيب mDNS، لذا ترد لوحة التحكم على https://safi.local (اسم المضيف قابل للضبط عبر SAFI_MDNS_HOSTNAME). يتتبع مكوّن espressif/mdns أحداث الواجهة بنفسه، لذا لا تحتاج انتقالات التزويد وإعادة الاتصال إلى أسلاك إضافية.