راسبيري باي 4 أداة تكوين مدير الشبكة

كان الهدف هو كتابة تطبيق Qt ل Raspberry Pi 4 والذي يمكن استخدامه للتبديل بين نقاط وصول WLAN المختلفة وتخزين بيانات الاعتماد المرتبطة بها.
لقد استخدمت صورة raspbian-buster-lite وتثبيت Qt كما هو موضح في Qt على Raspberry Pi 4 كنقطة انطلاق.
بالإضافة إلى ذلك ، قمت بتثبيت NetworkManager ، والذي يمكن استخدامه بواسطة أمر shell (nmcli ...) إنشاء اتصالات الشبكة وتكوينها وإدارتها.
يمكن العثور على معلومات حول هذا تحت https://wiki.debian.org/de/NetworkManager أو https://developer.gnome.org/NetworkManager/stable/nmcli.html.
يقدم NetworkManager أمرا يمكن استخدامه لبدء عملية المراقبة ، والتي تعلق بعد ذلك على التغييرات التي تطرأ على الواجهات المختلفة (wlan0 أو eth0) (على سبيل المثال ، غير متوفر ، غير متصل ، متصل ، ...).
كنت أرغب في استخدام هذه المراقبة لعرض الحالات المختلفة لمواقع الشبكة في واجهة المستخدم الرسومية. 2 ظهرت مشاكل:

  • إذا تم إصدار العديد من أوامر nmcli في تتابع سريع ، فإن التعليقات حول الحالات المختلفة وصلت مع تأخير زمني ولا يمكن عرضها مباشرة في واجهة المستخدم الرسومية.
  • تم إرسال ردود الفعل من أوامر NMCLI في فتحات مختلفة وبالتالي يمكن أن تكون سيئة التنسيق.

وظيفة المراقبة

بادئ ذي بدء ، نحتاج إلى وظيفة المراقبة (monitorDevices) ووظيفة الفتحة العامة ، التي تعترض وتقيم مخرجات المراقبة ثم ترسل رسائل الحالة إلى واجهة المستخدم الرسومية ، على سبيل المثال.
في وظيفة "monitorDevices" ، التي تبدأ تلقائيا عند بدء تشغيل التطبيق ، يتم تشغيل الأمر nmcli باستخدام sudo: sudo nmcli monitor
تنص العبارة "setProcessChannelMode(QProcess::MergedChannels)" على أن "الإخراج القياسي" و "الخطأ القياسي" يتم عرضهما معا في قناة وبالتالي يمكن تقييمهما باستخدام دالة.
يتم استخدام السطر "connect (device_monitoring_process ، SIGNAL (readyReadStandardOutput ()) ، this ، SLOT (processOutput ()))" كلما تم عرض رسالة (readyReadStandardOutput) ، يتم إرسالها إلى الفتحة "processOutput".

void CmdLauncher::monitorDevices() {
QStringList device_monitoring_on = {"nmcli", "monitor"};
device_monitoring_process = new QProcess(this);
device_monitoring_process->setProcessChannelMode(QProcess::MergedChannels);
device_monitoring_process->start("sudo", device_monitoring_on);
connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
}

</:code1:>

وظيفة التقييم

ثم يتم تقييم الرسائل في وظيفة "processOutput". تعترض QProcess senderProcess جميع رسائل جميع أوامر nmcli - وليس فقط تلك الخاصة بأمر المراقبة.

void CmdLauncher::processOutput() {
QProcess* senderProcess = qobject_cast<QProcess*>(sender());
senderProcess->setReadChannel(QProcess::StandardOutput);
QString message = QString::fromLocal8Bit(senderProcess->readAllStandardOutput());

qDebug() << "CmdLauncher::processOutput message: " << message << endl;
if (message.contains("Error:")) {
    message.remove(QString("\n"));
    error_messages = message;
    emit getErrorMessagesChanged();
    if (message.contains(QString("Error: unknown connection"))) {
        secrets_required = true;
        emit getSecretsRequiredChanged();
    }
}
// wifi
if (message.contains("wlan0: connected") || message.contains("wlan0:connected")) {
    wifi_device_state = "Wifi-Connected";
    emit getWifiDeviceStateChanged();
    error_messages = "";
    emit getErrorMessagesChanged();
    rescanWifi();
    testInternetConnection();
}

}

</:code2:>

بدء عملية nmcli أخرى

إذا قمت الآن بتشغيل أمر nmcli آخر باستخدام الوظيفة أدناه ، اعتراض الإخراج بواسطة وظيفة المراقبة أعلاه ويمكن بعد ذلك تقييمه ومعالجته في "outputProcess".
تتحول هذه الوظيفة إلى اتصال شبكة موجود وتبدأ تشغيله. من المهم عدم تضمين "set_wifi_process->waitForReadyRead ()" أو "set_wifi_process->waitForFinished()" ، لأنه بعد ذلك سيتم حظر إخراج جميع الرسائل حتى تنتهي هذه العملية.

void CmdLauncher::setWifi(QString ssid) {
    error_messages = "";
    emit getErrorMessagesChanged();

    QString uuid = "";
    for (int i = 0 ; i < networkConnections.length() ; i++) {
        QStringList connections = networkConnections[i].split(":");
        if (connections[1] == ssid)
        {
            uuid = connections[2];
        }
    }

    QStringList args_wifi_exist = {"nmcli", "connection", "up", uuid};
    set_wifi_process = new QProcess(this);
    set_wifi_process->setProcessChannelMode(QProcess::MergedChannels);
    set_wifi_process->start("sudo", args_wifi_exist);
    connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
}

يقوم السطر "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" بإعادة توجيه رسائل إخراج هذه العملية مرة أخرى إلى "processOutput" ويمكن تقييمها هناك مرة أخرى في موقع مركزي. </:code3:>