Raspberry Pi 4 NetworkManager Konfiguračný nástroj

Cieľom bolo napísať Qt aplikáciu pre Raspberry Pi 4, ktorá môže byť použitá na prepínanie medzi rôznymi prístupovými bodmi WLAN a ukladanie súvisiacich poverení.
Ako východiskový bod som použil obrázok raspbian-buster-lite a inštaláciu Qt, ako je opísané v Qt na Raspberry Pi 4 .
Okrem toho som nainštaloval NetworkManager, ktorý môže byť použitý shell príkazom (nmcli ...) vytvárajte, konfigurujte a spravujte sieťové pripojenia.
Informácie o tom nájdete v časti https://wiki.debian.org/de/NetworkManager alebo https://developer.gnome.org/NetworkManager/stable/nmcli.html.
NetworkManager ponúka príkaz, ktorý môže byť použitý na spustenie monitorovacieho procesu, ktorý potom komentuje zmeny rôznych rozhraní (wlan0 alebo eth0) (napr. nedostupné, odpojené, pripojené, pripojené, ...).
Chcel som použiť toto monitorovanie na zobrazenie rôznych stavov sieťových umiestnení v grafickom používateľskom rozhraní. Vyskytli sa 2 problémy:

  • ak bolo niekoľko príkazov nmcli vydaných v rýchlom slede, spätná väzba o rôznych stavoch prišla s časovým oneskorením a nemohla byť zobrazená naživo v grafickom používateľskom rozhraní.
  • spätná väzba príkazov NMCLI bola odoslaná v rôznych slotoch, a preto mohla byť zle koordinovaná.

Monitorovacia funkcia

V prvom rade potrebujeme monitorovaciu funkciu (monitorDevices) a funkciu verejného slotu, ktorá zachytí a vyhodnotí monitorovací výstup a potom napríklad odošle stavové správy do grafického používateľského rozhrania.
Vo funkcii "monitorDevices", ktorá sa automaticky spustí pri spustení aplikácie, sa príkaz nmcli spustí pomocou sudo: sudo nmcli monitor
Príkaz "setProcessChannelMode(QProcess::MergedChannels)" uvádza, že "Štandardný výstup" a "Štandardná chyba" sa zobrazujú spolu v kanáli, a preto ich možno vyhodnotiť pomocou funkcie.
Riadok "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), tento, SLOT(processOutput()))" sa používa vždy, keď sa zobrazí správa (readyReadStandardOutput), odošle sa do slotu "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:>

Vyhodnocovacia funkcia

Vyhodnotenie správ sa potom vykoná vo funkcii "processOutput". QProcess senderProcess zachytáva všetky správy všetkých príkazov nmcli - nielen správy monitorovacieho príkazu.

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

Spustenie ďalšieho procesu nmcli

Ak teraz spustíte ďalší príkaz nmcli s nižšie uvedenou funkciou, výstup je zachytený vyššie uvedenou monitorovacou funkciou a potom môže byť vyhodnotený a ďalej spracovaný v "outputProcess".
Táto funkcia prepne na existujúce sieťové pripojenie a spustí ho. Je dôležité nezahrnúť "set_wifi_process->waitForReadyRead()" alebo "set_wifi_process->waitForFinished()", pretože výstup všetkých správ bude zablokovaný, kým sa tento proces nedokončí.

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

Riadok "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" presmeruje výstupné správy tohto procesu späť na "processOutput" a môže byť tam opäť vyhodnotený na centrálnom mieste. </:code3:>