Instrumentul de configurare Raspberry Pi 4 NetworkManager

Scopul a fost de a scrie o aplicație Qt pentru Raspberry Pi 4 care poate fi utilizată pentru a comuta între diferite puncte de acces WLAN și pentru a stoca acreditările asociate.
Am folosit o imagine raspbian-buster-lite și o instalație Qt așa cum este descrisă în Qt pe Raspberry Pi 4 ca punct de plecare.
În plus, am instalat NetworkManager, care poate fi folosit de comanda shell (nmcli ...) Creați, configurați și gestionați conexiuni de rețea.
Informații în acest sens pot fi găsite la https://wiki.debian.org/de/NetworkManager sau https://developer.gnome.org/NetworkManager/stable/nmcli.html.
NetworkManager oferă o comandă care poate fi utilizată pentru a începe un proces de monitorizare, care apoi comentează modificările diferitelor interfețe (wlan0 sau eth0) (de exemplu, indisponibil, deconectat, conectat, ...).
Am vrut să folosesc această monitorizare pentru a afișa diferitele stări ale locațiilor de rețea din GUI. Au apărut 2 probleme:

  • dacă mai multe comenzi nmcli au fost emise în succesiune rapidă, atunci feedback-ul despre diferitele stări a sosit cu o întârziere și nu a putut fi afișat live în GUI.
  • Feedback-ul comenzilor nmcli a fost trimis în diferite sloturi și, prin urmare, ar putea fi slab coordonat.

Funcția de monitorizare

În primul rând, avem nevoie de funcția de monitorizare (monitorDevices) și de funcția de slot public, care interceptează și evaluează ieșirea de monitorizare și apoi trimite mesajele de stare către GUI, de exemplu.
În funcția "monitorDevices", care pornește automat la pornirea aplicației, comanda nmcli este pornită cu monitorul sudo: sudo nmcli
Instrucțiunea "setProcessChannelMode(QProcess::MergedChannels)" afirmă că "Standard Output" și "Standard Error" sunt afișate împreună într-un canal și pot fi astfel evaluate cu o funcție.
Linia "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), aceasta, SLOT(processOutput()))" este utilizată ori de câte ori este afișat un mesaj (readyReadStandardOutput), este trimis la slotul "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:>

Funcția de evaluare

Evaluarea mesajelor este apoi efectuată în funcția "processOutput". QProcess senderProcess interceptează toate mesajele tuturor comenzilor nmcli - nu doar cele ale comenzii de monitorizare.

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:>

Începeți un alt proces nmcli

Dacă acum porniți o altă comandă nmcli cu funcția de mai jos, ieșirea este interceptată de funcția de monitorizare de mai sus și poate fi apoi evaluată și procesată în continuare în "outputProcess".
Această funcție comută la o conexiune de rețea existentă și o pornește. Este important să nu includeți un "set_wifi_process->waitForReadyRead ()" sau "set_wifi_process->waitForFinished()", deoarece atunci ieșirea tuturor mesajelor va fi blocată până la finalizarea acestui proces.

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()));
}

Linia "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" transmite mesajele de ieșire ale acestui proces înapoi la "processOutput" și poate fi evaluată acolo din nou într-o locație centrală. </:code3:>