El objetivo era escribir una aplicación Qt para la Raspberry Pi 4 que se pueda utilizar para cambiar entre diferentes puntos de acceso WLAN y almacenar las credenciales asociadas.
Utilicé una imagen raspbian-buster-lite y una instalación Qt como se describe en Qt en la Raspberry Pi 4 como punto de partida.
Además, he instalado el NetworkManager, que se puede utilizar mediante el comando shell (nmcli ...) Cree, configure y administre conexiones de red.
La información al respecto se puede encontrar en https://wiki.debian.org/de/NetworkManager o https://developer.gnome.org/NetworkManager/stable/nmcli.html.
El NetworkManager ofrece un comando que se puede utilizar para iniciar un proceso de monitorización, que luego comenta los cambios en las diversas interfaces (wlan0 o eth0) (por ejemplo, no disponible, desconectado, conectando, conectado, ...).
Quería usar este monitoreo para mostrar los diferentes estados de las ubicaciones de red en la GUI. Surgieron 2 problemas:

  • si se emitieron varios comandos nmcli en rápida sucesión, entonces los comentarios sobre los diferentes estados llegaron con un retraso de tiempo y no se pudieron mostrar en vivo en la GUI.
  • La retroalimentación de los comandos NMCLI se envió en diferentes ranuras y, por lo tanto, podría estar mal coordinada.

Función de monitoreo

En primer lugar, necesitamos la función de monitoreo (monitorDevices) y la función de ranura pública, que intercepta y evalúa la salida de monitoreo y luego envía los mensajes de estado a la GUI, por ejemplo.
En la función "monitorDevices", que se inicia automáticamente cuando se inicia la aplicación, el comando nmcli se inicia con sudo: sudo nmcli monitor
La instrucción "setProcessChannelMode(QProcess::MergedChannels)" indica que "Standard Output" y "Standard Error" se muestran juntos en un canal y, por lo tanto, se pueden evaluar con una función.
La línea "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" se utiliza siempre que se muestra un mensaje (readyReadStandardOutput), se envía a la ranura "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:>

Función de evaluación

La evaluación de los mensajes se lleva a cabo en la función "processOutput". El senderProcess de QProcess intercepta todos los mensajes de todos los comandos nmcli, no solo los del comando de supervisión.

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

Iniciar otro proceso nmcli

Si ahora inicia otro comando nmcli con la función siguiente, la salida es interceptada por la función de monitoreo anterior y luego puede ser evaluada y procesada en el "outputProcess".
Esta función cambia a una conexión de red existente y la inicia. Es importante no incluir un "set_wifi_process->waitForReadyRead()" o "set_wifi_process->waitForFinished()", porque entonces la salida de todos los mensajes se bloqueará hasta que finalice este proceso.

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 línea "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" reenvía los mensajes de salida de este proceso a "processOutput" y se puede evaluar allí de nuevo en una ubicación central. </:code3:>

Walter Prechtl

Walter Prechtl

Actualizado en: 12. March 2024
Tiempo de lectura: 4 minutos