Инструмент настройки Raspberry Pi 4 NetworkManager

Цель состояла в том, чтобы написать приложение Qt для Raspberry Pi 4, которое можно использовать для переключения между различными точками доступа WLAN и хранения связанных учетных данных.
В качестве отправной точки я использовал образ raspbian-buster-lite и установку Qt, как описано в Qt на Raspberry Pi 4 .
Кроме того, я установил NetworkManager, который можно использовать с помощью команды оболочки (nmcli ...) Создание, настройка и управление сетевыми подключениями.
Информацию об этом можно найти в разделе https://wiki.debian.org/de/NetworkManager или https://developer.gnome.org/NetworkManager/stable/nmcli.html.
NetworkManager предлагает команду, которую можно использовать для запуска процесса мониторинга, который затем комментирует изменения в различных интерфейсах (wlan0 или eth0) (например, недоступен, отключен, подключен, подключен, ...).
Я хотел использовать этот мониторинг для отображения различных статусов сетевых расположений в графическом интерфейсе. Возникли 2 проблемы:

  • если несколько команд nmcli были выданы в быстрой последовательности, то обратная связь о разных статусах поступала с задержкой по времени и не могла отображаться в реальном времени в графическом интерфейсе.
  • Обратная связь команд NMCLI отправлялась в разные слоты и, таким образом, могла быть плохо скоординирована.

Функция мониторинга

Прежде всего, нам нужна функция мониторинга (monitorDevices) и функция публичного слота, которая перехватывает и оценивает выходные данные мониторинга, а затем отправляет, например, сообщения о состоянии в графический интерфейс.
В функции "monitorDevices", которая запускается автоматически при запуске приложения, команда nmcli запускается с помощью sudo: sudo nmcli monitor
Оператор "setProcessChannelMode(QProcess::MergedChannels)" утверждает, что "Стандартный вывод" и "Стандартная ошибка" отображаются вместе в канале и, таким образом, могут быть вычислены с помощью функции.
Строка "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" используется всякий раз, когда отображается сообщение (readyReadStandardOutput), оно отправляется в слот "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:>

Оценочная функция

Затем оценка сообщений выполняется в функции «processOutput». QProcess senderProcess перехватывает все сообщения всех команд nmcli, а не только сообщения команды мониторинга.

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

Запуск другого процесса nmcli

Если теперь вы запустите другую команду nmcli с приведенной ниже функцией, выходные данные будут перехвачены приведенной выше функцией мониторинга, а затем могут быть оценены и дополнительно обработаны в «outputProcess».
Эта функция переключается на существующее сетевое соединение и запускает его. Важно не включать «set_wifi_process->waitForReadyRead()» или «set_wifi_process->waitForFinished()», потому что тогда вывод всех сообщений будет заблокирован до завершения этого процесса.

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

Строка "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" пересылает выходные сообщения этого процесса обратно в "processOutput" и может быть вычислена там снова в центральном расположении. </:code3:>