Konfigurationsverktyg för Raspberry Pi 4 NetworkManager

Målet var att skriva en Qt-applikation för Raspberry Pi 4 som kan användas för att växla mellan olika WLAN-åtkomstpunkter och lagra tillhörande referenser.
Jag använde en raspbian-buster-lite-bild och en Qt-installation som beskrivs i Qt på Raspberry Pi 4 som utgångspunkt.
Dessutom har jag installerat NetworkManager, som kan användas med skalkommando (nmcli ...) Skapa, konfigurera och hantera nätverksanslutningar.
Information om detta finns under https://wiki.debian.org/de/NetworkManager eller https://developer.gnome.org/NetworkManager/stable/nmcli.html.
NetworkManager erbjuder ett kommando som kan användas för att starta en övervakningsprocess, som sedan kommenterar ändringar i de olika gränssnitten (wlan0 eller eth0) (t.ex. otillgänglig, frånkopplad, ansluten, ansluten, ...).
Jag ville använda den här övervakningen för att visa de olika statuserna för nätverksplatserna i GUI. 2 problem uppstod:

  • Om flera nmcli-kommandon utfärdades i snabb följd, kom feedbacken om de olika statuserna med en tidsfördröjning och kunde inte visas live i GUI.
  • Återkopplingen av NMCLI-kommandona skickades i olika fack och kunde därför vara dåligt samordnad.

Övervakningsfunktion

Först och främst behöver vi övervakningsfunktionen (monitorDevices) och den offentliga slotfunktionen, som fångar upp och utvärderar övervakningsutgången och sedan skickar statusmeddelandena till GUI, till exempel.
I funktionen "monitorDevices", som startar automatiskt när programmet startar, startas nmcli-kommandot med sudo: sudo nmcli monitor
Satsen "setProcessChannelMode(QProcess::MergedChannels)" anger att "Standard Output" och "Standard Error" visas tillsammans i en kanal och kan därför utvärderas med en funktion.
Raden "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" används när ett meddelande visas (readyReadStandardOutput), det skickas till kortplatsen "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:>

Funktion för utvärdering

Utvärderingen av meddelandena utförs sedan i funktionen "processOutput". QProcess senderProcess fångar upp alla meddelanden i alla nmcli-kommandon - inte bara de i övervakningskommandot.

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

Starta en annan nmcli-process

Om du nu startar ett annat nmcli-kommando med funktionen nedan fångas utdata upp av ovanstående övervakningsfunktion och kan sedan utvärderas och bearbetas vidare i "outputProcess".
Den här funktionen växlar till en befintlig nätverksanslutning och startar den. Det är viktigt att inte inkludera en "set_wifi_process->waitForReadyRead ()" eller "set_wifi_process->waitForFinished()", eftersom utdata från alla meddelanden blockeras tills processen är klar.

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

Raden "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" vidarebefordrar utdatameddelandena för den här processen tillbaka till "processOutput" och kan utvärderas där igen på en central plats. </:code3:>