Amaç, Raspberry Pi 4 için farklı WLAN erişim noktaları arasında geçiş yapmak ve ilişkili kimlik bilgilerini depolamak için kullanılabilecek bir Qt uygulaması yazmaktı.
Başlangıç noktası olarak Raspberry Pi 4'teki Qt'de açıklandığı gibi bir raspbian-buster-lite görüntüsü ve bir Qt kurulumu kullandım.
Ek olarak, kabuk komutu (nmcli ...) tarafından kullanılabilen NetworkManager'ı yükledim Ağ bağlantıları oluşturun, yapılandırın ve yönetin.
Bununla ilgili bilgiler https://wiki.debian.org/de/NetworkManager veya https://developer.gnome.org/NetworkManager/stable/nmcli.html altında bulunabilir.
NetworkManager, bir izleme işlemini başlatmak için kullanılabilecek bir komut sunar ve daha sonra çeşitli arayüzlerdeki (wlan0 veya eth0) değişiklikler hakkında yorum yapar (örneğin, kullanılamıyor, bağlantısı kesildi, bağlanıyor, bağlı, ...).
Bu izlemeyi, GUI'deki ağ konumlarının farklı durumlarını görüntülemek için kullanmak istedim. 2 sorun ortaya çıktı:
- Birkaç nmcli komutu hızlı bir şekilde art arda verildiyse, farklı durumlarla ilgili geri bildirimler bir zaman gecikmesiyle geldi ve GUI'de canlı olarak görüntülenemedi.
- NMCLI komutlarının geri bildirimi farklı yuvalarda gönderildi ve bu nedenle zayıf bir şekilde koordine edilebildi.
İzleme fonksiyonu
Her şeyden önce, izleme çıktısını kesen ve değerlendiren ve ardından durum mesajlarını GUI'ye gönderen izleme işlevine (monitorDevices) ve genel slot işlevine ihtiyacımız var.
Uygulama başladığında otomatik olarak başlayan "monitorDevices" işlevinde, nmcli komutu sudo ile başlatılır: sudo nmcli monitor
"setProcessChannelMode(QProcess::MergedChannels)" ifadesi, "Standart Çıktı" ve "Standart Hata" nın bir kanalda birlikte görüntülendiğini ve böylece bir işlevle değerlendirilebileceğini belirtir.
Bir mesaj görüntülendiğinde (readyReadStandardOutput())) "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput())" satırı kullanılır, "processOutput" yuvasına gönderilir.
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:>
Değerlendirme fonksiyonu
Mesajların değerlendirilmesi daha sonra "processOutput" işlevinde gerçekleştirilir. QProcess senderProcess, yalnızca izleme komutunun değil, tüm nmcli komutlarının tüm iletilerini yakalar.
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:>
Başka bir nmcli işlemi başlatma
Şimdi aşağıdaki işlevle başka bir nmcli komutu başlatırsanız, çıktı yukarıdaki izleme işlevi tarafından yakalanır ve daha sonra "outputProcess" içinde değerlendirilebilir ve daha fazla işlenebilir.
Bu işlev varolan bir ağ bağlantısına geçer ve onu başlatır. "set_wifi_process->waitForReadyRead()" veya "set_wifi_process->waitForFinished()" eklememek önemlidir, çünkü bu işlem tamamlanana kadar tüm iletilerin çıktısı engellenir.
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()))" satırı, bu işlemin çıkış mesajlarını "processOutput"a geri iletir ve orada tekrar merkezi bir konumda değerlendirilebilir. </:code3:>