L’objectif était d’écrire une application Qt pour le Raspberry Pi 4 qui peut être utilisée pour basculer entre différents points d’accès WLAN et stocker les informations d’identification associées.
J’ai utilisé une image raspbian-buster-lite et une installation Qt comme décrit dans Qt sur le Raspberry Pi 4 comme point de départ.
De plus, j’ai installé le NetworkManager, qui peut être utilisé par commande shell (nmcli...) Créez, configurez et gérez les connexions réseau.
Vous trouverez des informations à ce sujet sous https://wiki.debian.org/de/NetworkManager ou https://developer.gnome.org/NetworkManager/stable/nmcli.html.
Le NetworkManager propose une commande qui peut être utilisée pour démarrer un processus de surveillance, qui commente ensuite les modifications apportées aux différentes interfaces (wlan0 ou eth0) (par exemple, indisponible, déconnecté, connecté, ...).
Je voulais utiliser cette surveillance pour afficher les différents états des emplacements réseau dans l’interface graphique. 2 problèmes sont apparus :

  • si plusieurs commandes NMCLI ont été émises en succession rapide, les retours sur les différents statuts sont arrivés avec un décalage et ne pouvaient pas être affichés en direct dans l’interface graphique.
  • Le retour des commandes NMCLI a été envoyé dans différents emplacements et pourrait donc être mal coordonné.

Fonction de surveillance

Tout d’abord, nous avons besoin de la fonction de surveillance (monitorDevices) et de la fonction de fente publique, qui intercepte et évalue la sortie de surveillance, puis envoie les messages d’état à l’interface graphique, par exemple.
Dans la fonction « monitorDevices », qui démarre automatiquement au démarrage de l’application, la commande nmcli est lancée avec sudo: sudo nmcli monitor
L’instruction « setProcessChannelMode(QProcess::MergedChannels) » indique que « Standard Output » et « Standard Error » sont affichés ensemble dans un canal et peuvent donc être évalués avec une fonction.
La ligne « connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput())) » est utilisée chaque fois qu’un message est affiché (readyReadStandardOutput), il est envoyé à l’emplacement « 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:>

Fonction d’évaluation

L’évaluation des messages est ensuite effectuée dans la fonction « processOutput ». QProcess senderProcess intercepte tous les messages de toutes les commandes nmcli - pas seulement ceux de la commande monitoring.

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

Démarrer un autre processus nmcli

Si vous démarrez maintenant une autre commande nmcli avec la fonction ci-dessous, la sortie est interceptée par la fonction de surveillance ci-dessus et peut ensuite être évaluée et traitée dans le « outputProcess ».
Cette fonction bascule vers une connexion réseau existante et la démarre. Il est important de ne pas inclure de « set_wifi_process->waitForReadyRead() » ou « set_wifi_process->waitForFinished() », car la sortie de tous les messages sera bloquée jusqu’à ce que ce processus soit terminé.

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

La ligne « connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput())) » transmet les messages de sortie de ce processus au « processOutput » et peut y être évaluée à nouveau à un emplacement central. </:code3:>

Walter Prechtl

Walter Prechtl

Mise à jour à: 12. March 2024
Temps de lecture: 4 minutes