Tavoitteena oli kirjoittaa Raspberry Pi 4:lle Qt-sovellus, jolla voidaan vaihtaa eri WLAN-tukiasemien välillä ja tallentaa niihin liittyvät tunnukset.
Käytin lähtökohtana raspbian-buster-lite-kuvaa ja Qt-asennusta Qt:ssä kuvatulla tavalla Raspberry Pi 4:ssä .
Lisäksi olen asentanut NetworkManagerin, jota voidaan käyttää shell-komennolla (nmcli ...) Luo, määritä ja hallitse verkkoyhteyksiä.
Tietoja tästä löytyy https://wiki.debian.org/de/NetworkManager tai https://developer.gnome.org/NetworkManager/stable/nmcli.html.
NetworkManager tarjoaa komennon, jonka avulla voidaan käynnistää valvontaprosessi, joka sitten kommentoi eri rajapintojen muutoksia (wlan0 tai eth0) (esim. ei käytettävissä, katkaistu, yhdistää, kytketty, ...).
Halusin käyttää tätä valvontaa näyttääkseni verkkopaikkojen eri tilat graafisessa käyttöliittymässä. 2 ongelmaa ilmeni:
- jos useita nmcli-komentoja annettiin nopeasti peräkkäin, palaute eri tiloista saapui viiveellä, eikä sitä voitu näyttää suorana graafisessa käyttöliittymässä.
- NMCLI-komentojen palaute lähetettiin eri paikoissa, joten sitä voitiin koordinoida huonosti.
Seurantatoiminto
Ensinnäkin tarvitsemme valvontatoiminnon (monitorDevices) ja julkisen korttipaikan toiminnon, joka sieppaa ja arvioi valvontalähdön ja lähettää sitten tilaviestit esimerkiksi graafiseen käyttöliittymään.
"monitorDevices" -toiminnossa, joka käynnistyy automaattisesti, kun sovellus käynnistyy, nmcli-komento käynnistetään sudo: sudo nmcli -näytöllä
Lauseessa "setProcessChannelMode(QProcess::MergedChannels)" todetaan, että "Standard Output" ja "Standard Error" näytetään yhdessä kanavassa ja niitä voidaan siten arvioida funktiolla.
Riviä "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput())))" käytetään aina, kun viesti näytetään (readyReadStandardOutput), se lähetetään paikkaan "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:>
Arviointitoiminto
Viestien arviointi suoritetaan sitten "processOutput" -toiminnossa. QProcess senderProcess sieppaa kaikkien nmcli-komentojen kaikki viestit - ei vain valvontakomennon viestit.
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:>
Aloita toinen nmcli-prosessi
Jos käynnistät nyt toisen nmcli-komennon alla olevalla toiminnolla, yllä oleva valvontatoiminto sieppaa lähdön ja sitä voidaan sitten arvioida ja käsitellä edelleen "outputProcess" -ohjelmassa.
Tämä toiminto vaihtaa olemassa olevaan verkkoyhteyteen ja käynnistää sen. On tärkeää, ettet sisällytä "set_wifi_process->waitForReadyRead()" tai "set_wifi_process->waitForFinished ()", koska silloin kaikkien viestien tulostus estetään, kunnes tämä prosessi on valmis.
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()));
}
Rivi "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))))" välittää tämän prosessin lähtöviestit takaisin "processOutput" -laitteeseen ja voidaan arvioida siellä uudelleen keskeisessä paikassa. </:code3:>