Målet var at skrive en Qt-applikation til Raspberry Pi 4, der kan bruges til at skifte mellem forskellige WLAN-adgangspunkter og gemme de tilhørende legitimationsoplysninger.
Jeg brugte et raspbian-buster-lite billede og en Qt installation som beskrevet i Qt på Raspberry Pi 4 som udgangspunkt.
Derudover har jeg installeret NetworkManager, som kan bruges af shell-kommandoen (nmcli ...) Opret, konfigurer og administrer netværksforbindelser.
Oplysninger om dette kan findes under https://wiki.debian.org/de/NetworkManager eller https://developer.gnome.org/NetworkManager/stable/nmcli.html.
NetworkManager tilbyder en kommando, der kan bruges til at starte en overvågningsproces, som derefter kommenterer ændringer i de forskellige grænseflader (wlan0 eller eth0) (f.eks. Utilgængelig, afbrudt, forbinder, tilsluttet, ...).
Jeg ønskede at bruge denne overvågning til at vise de forskellige statusser for netværksplaceringerne i GUI'en. Der opstod 2 problemer:

  • Hvis flere NMCLI-kommandoer blev udstedt hurtigt efter hinanden, ankom feedbacken om de forskellige statusser med en tidsforsinkelse og kunne ikke vises live i GUI'en.
  • Feedbacken fra NMCLI-kommandoerne blev sendt i forskellige slots og kunne derfor være dårligt koordineret.

Overvågningsfunktion

Først og fremmest har vi brug for overvågningsfunktionen (monitorDevices) og public slot-funktionen, som opfanger og evaluerer overvågningsoutputtet og derefter sender statusmeddelelserne til f.eks. GUI.
I funktionen "monitorDevices", som starter automatisk, når applikationen starter, startes nmcli-kommandoen med sudo: sudo nmcli monitor
Udsagnet "setProcessChannelMode(QProcess::MergedChannels)" angiver, at "Standard Output" og "Standard Error" vises sammen i en kanal og dermed kan evalueres med en funktion.
Linjen "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" bruges, når en meddelelse vises (readyReadStandardOutput), den sendes til slot "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:>

Evalueringsfunktion

Evalueringen af meddelelserne udføres derefter i funktionen "processOutput". QProcess senderProcess opfanger alle meddelelser fra alle nmcli kommandoer - ikke kun dem fra overvågningskommandoen.

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

Start en anden nmcli proces

Hvis du nu starter en anden nmcli-kommando med funktionen nedenfor, opfanges outputtet af ovenstående overvågningsfunktion og kan derefter evalueres og behandles yderligere i "outputProcess".
Denne funktion skifter til en eksisterende netværksforbindelse og starter den. Det er vigtigt ikke at inkludere en "set_wifi_process->waitForReadyRead ()" eller "set_wifi_process->waitForFinished()", for så blokeres outputtet af alle meddelelser, indtil denne proces er afsluttet.

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

Linjen "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" videresender outputmeddelelserne fra denne proces tilbage til "processOutput" og kan evalueres der igen på et centralt sted. </:code3:>

Walter Prechtl

Walter Prechtl

Opdateret på: 12. March 2024
Læsetid: 4 minutter