Mục tiêu là viết một ứng dụng Qt cho Raspberry Pi 4 có thể được sử dụng để chuyển đổi giữa các điểm truy cập WLAN khác nhau và lưu trữ các thông tin đăng nhập liên quan.
Tôi đã sử dụng hình ảnh raspbian-buster-lite và cài đặt Qt như được mô tả trong Qt trên Raspberry Pi 4 làm điểm khởi đầu.
Ngoài ra, tôi đã cài đặt NetworkManager, có thể được sử dụng bằng lệnh shell (nmcli ...) Tạo, cấu hình và quản lý kết nối mạng.
Thông tin về điều này có thể được tìm thấy dưới https://wiki.debian.org/de/NetworkManager hoặc https://developer.gnome.org/NetworkManager/stable/nmcli.html.
NetworkManager cung cấp một lệnh có thể được sử dụng để bắt đầu quá trình giám sát, sau đó nhận xét về các thay đổi đối với các giao diện khác nhau (wlan0 hoặc eth0) (ví dụ: không khả dụng, ngắt kết nối, kết nối, kết nối, ...).
Tôi muốn sử dụng giám sát này để hiển thị các trạng thái khác nhau của các vị trí mạng trong GUI. 2 vấn đề nổi lên:
- nếu một số lệnh nmcli được ban hành liên tiếp, thì phản hồi về các trạng thái khác nhau đến với độ trễ thời gian và không thể hiển thị trực tiếp trong GUI.
- Phản hồi của các lệnh nmcli được gửi trong các khe khác nhau và do đó có thể được phối hợp kém.
Chức năng giám sát
Trước hết, chúng ta cần chức năng giám sát (monitorDevices) và chức năng khe cắm công cộng, chức năng này chặn và đánh giá đầu ra giám sát và sau đó gửi thông báo trạng thái đến GUI chẳng hạn.
Trong chức năng "monitorDevices", tự động khởi động khi ứng dụng khởi động, lệnh nmcli được bắt đầu bằng sudo: sudo nmcli monitor
Câu lệnh "setProcessChannelMode (QProcess:: MergedChannels)" nói rằng "Standard Output" và "Standard Error" được hiển thị cùng nhau trong một kênh và do đó có thể được đánh giá bằng một hàm.
Dòng "connect (device_monitoring_process, SIGNAL (readyReadStandardOutput ()), this, SLOT (processOutput ()))" được sử dụng bất cứ khi nào một thông báo được hiển thị (readyReadStandardOutput), nó được gửi đến khe "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:>
Chức năng đánh giá
Việc đánh giá các thông điệp sau đó được thực hiện trong chức năng "processOutput". QProcess senderProcess chặn tất cả các tin nhắn của tất cả các lệnh nmcli - không chỉ các lệnh của lệnh giám sát.
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:>
Bắt đầu một quá trình nmcli khác
Nếu bây giờ bạn bắt đầu một lệnh nmcli khác với chức năng bên dưới, đầu ra sẽ bị chặn bởi chức năng giám sát ở trên và sau đó có thể được đánh giá và xử lý thêm trong "outputProcess".
Chức năng này chuyển sang kết nối mạng hiện có và khởi động nó. Điều quan trọng là không bao gồm "set_wifi_process->waitForReadyRead()" hoặc "set_wifi_process->waitForFinished()", bởi vì sau đó đầu ra của tất cả các thư sẽ bị chặn cho đến khi quá trình này kết thúc.
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()));
}
Dòng "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput())))" chuyển tiếp các thông báo đầu ra của quy trình này trở lại "processOutput" và có thể được đánh giá lại ở đó tại một vị trí trung tâm. </:code3:>