QT UI: Wifi chooser (#2062)

* qt wifi

Squashed commit of the following:

commit bec029c7b906c1df5324a8dbb0a58b8980c313ab
Author: grekiki <gregor1234567890@gmail.com>
Date:   Mon Nov 2 19:31:30 2020 +0100

    try to collect security type

commit e1e4d97f48a293392d33fe607936bbe94415c846
Author: grekiki <gregor1234567890@gmail.com>
Date:   Mon Nov 2 16:06:55 2020 +0100

    add a function for refresh

commit 52bd7d0937040bd1d5c582f324fdb60f33677014
Author: grekiki <gregor1234567890@gmail.com>
Date:   Fri Oct 30 11:14:23 2020 +0100

    allow compilation

commit 1b91e1057cca564d6b021a579d97940a8f2b9328
Author: Gregor Kikelj <gregor1234567890@gmail.com>
Date:   Wed Oct 21 14:12:05 2020 +0200

    dont build keyboard

commit cc8bad2ddd668d1397a9003a518699c3f706cca8
Author: Gregor Kikelj <gregor1234567890@gmail.com>
Date:   Tue Oct 20 18:22:07 2020 +0200

    kind of works

commit ce3a9b6d96a1985ba5b9a2f17c15530cb8f93ca8
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Oct 19 11:22:55 2020 +0200

    remove button and text field

commit 2db3d11bdb8e69098c34c04a1341ea707ce1ed6a
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 15:31:26 2020 +0200

    try lineedit

commit d045c302dcec612c8d2ff14ba256af06c7df9ebb
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 15:01:18 2020 +0200

    add dialog test button

commit 21fa63e33b12b0bcdad441e778b2cf6c42b113e4
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 12:36:10 2020 +0200

    Only show one if both 2.4 and 5 Ghz found

commit dfb9ca4173adc05264663a3658298899eea2c619
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 12:24:16 2020 +0200

    Sort networks by strength

commit e57fe68f7972f955fc4da7054af676df8581b003
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:59:39 2020 +0200

    Handle currently connected AP

commit a5e80e122176f39a9bccfb8056b0886d210fdf24
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:38:18 2020 +0200

    Add todo

commit 98a1bc6e7a1f38b0ff7cb810b7d63a133552dfcc
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:37:35 2020 +0200

    Implement scan method

commit 9a774a509b1665371d9fd51b40550ad2388d58bc
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:29:03 2020 +0200

    show list of wifi networks

* add to settings

* no wifi on pc

* refactor get_property

* refactor WiFi, split between UI and network manager stuff

* renaming

* refresh works

* refactor

* forgot to git add

* connecting works again

* print connection error on weird networks

* extract adapter path

* found networks

* Deleting existing connections to SSID we are trying to connect to

* have paths of active connections

* mvp

* fix review

* qt wifi

Squashed commit of the following:

commit bec029c7b906c1df5324a8dbb0a58b8980c313ab
Author: grekiki <gregor1234567890@gmail.com>
Date:   Mon Nov 2 19:31:30 2020 +0100

    try to collect security type

commit e1e4d97f48a293392d33fe607936bbe94415c846
Author: grekiki <gregor1234567890@gmail.com>
Date:   Mon Nov 2 16:06:55 2020 +0100

    add a function for refresh

commit 52bd7d0937040bd1d5c582f324fdb60f33677014
Author: grekiki <gregor1234567890@gmail.com>
Date:   Fri Oct 30 11:14:23 2020 +0100

    allow compilation

commit 1b91e1057cca564d6b021a579d97940a8f2b9328
Author: Gregor Kikelj <gregor1234567890@gmail.com>
Date:   Wed Oct 21 14:12:05 2020 +0200

    dont build keyboard

commit cc8bad2ddd668d1397a9003a518699c3f706cca8
Author: Gregor Kikelj <gregor1234567890@gmail.com>
Date:   Tue Oct 20 18:22:07 2020 +0200

    kind of works

commit ce3a9b6d96a1985ba5b9a2f17c15530cb8f93ca8
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Oct 19 11:22:55 2020 +0200

    remove button and text field

commit 2db3d11bdb8e69098c34c04a1341ea707ce1ed6a
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 15:31:26 2020 +0200

    try lineedit

commit d045c302dcec612c8d2ff14ba256af06c7df9ebb
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 15:01:18 2020 +0200

    add dialog test button

commit 21fa63e33b12b0bcdad441e778b2cf6c42b113e4
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 12:36:10 2020 +0200

    Only show one if both 2.4 and 5 Ghz found

commit dfb9ca4173adc05264663a3658298899eea2c619
Author: Willem Melching <willem.melching@gmail.com>
Date:   Mon Aug 24 12:24:16 2020 +0200

    Sort networks by strength

commit e57fe68f7972f955fc4da7054af676df8581b003
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:59:39 2020 +0200

    Handle currently connected AP

commit a5e80e122176f39a9bccfb8056b0886d210fdf24
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:38:18 2020 +0200

    Add todo

commit 98a1bc6e7a1f38b0ff7cb810b7d63a133552dfcc
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:37:35 2020 +0200

    Implement scan method

commit 9a774a509b1665371d9fd51b40550ad2388d58bc
Author: Willem Melching <willem.melching@gmail.com>
Date:   Sun Aug 23 13:29:03 2020 +0200

    show list of wifi networks

* add to settings

* no wifi on pc

* refactor get_property

* refactor WiFi, split between UI and network manager stuff

* renaming

* refresh works

* refactor

* forgot to git add

* connecting works again

* print connection error on weird networks

* extract adapter path

* found networks

* Deleting existing connections to SSID we are trying to connect to

* have paths of active connections

* mvp

* fix review

* fix bugs

* fix text color

* colors

* wider button

* show connected network first

* fix sorting

* remove hack

* sorting

* auto refresh

* only refresh when widget is visible

* scan once on startup

* dont open dialog on qcom2

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Comma Device <device@comma.ai>
Co-authored-by: grekiki <gregor1234567890@gmail.com>
albatross
Willem Melching 2020-11-19 16:51:48 +01:00 committed by GitHub
parent 5ebc0dd85b
commit f93bca98ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 471 additions and 73 deletions

View File

@ -71,7 +71,7 @@ else:
else:
qt_libs += [f"Qt5{m}" for m in qt_modules]
qt_src = ["qt/ui.cc", "qt/window.cc", "qt/qt_sound.cc", "qt/offroad/settings.cc", "qt/offroad/onboarding.cc"] + src
qt_src = ["qt/ui.cc", "qt/window.cc", "qt/qt_sound.cc", "qt/offroad/settings.cc", "qt/offroad/onboarding.cc", "qt/offroad/wifi.cc", "qt/offroad/wifiManager.cc"] + src
qt_env.Program("_ui", qt_src, LIBS=qt_libs + libs)
# spinner and text window

View File

@ -3,8 +3,6 @@
#include <sstream>
#include <cassert>
#include "settings.hpp"
#include <QString>
#include <QVBoxLayout>
#include <QHBoxLayout>
@ -12,6 +10,9 @@
#include <QLabel>
#include <QPixmap>
#include "wifi.hpp"
#include "settings.hpp"
#include "common/params.h"
ParamsToggle::ParamsToggle(QString param, QString title, QString description, QString icon_path, QWidget *parent): QFrame(parent) , param(param) {
@ -189,6 +190,17 @@ QWidget * developer_panel() {
return widget;
}
QWidget * network_panel() {
QVBoxLayout *main_layout = new QVBoxLayout;
main_layout->addWidget(new WifiUI());
QWidget *widget = new QWidget;
widget->setLayout(main_layout);
return widget;
}
void SettingsWindow::setActivePanel() {
QPushButton *btn = qobject_cast<QPushButton*>(sender());
panel_layout->setCurrentWidget(panels[btn->text()]);
@ -217,6 +229,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QWidget(parent) {
{"device", device_panel()},
{"toggles", toggles_panel()},
{"developer", developer_panel()},
{"network", network_panel()},
};
for (auto &panel : panels) {

View File

@ -21,7 +21,6 @@ public slots:
void checkboxClicked(int state);
};
class SettingsWindow : public QWidget {
Q_OBJECT

View File

@ -0,0 +1,124 @@
#include <QDebug>
#include <QListWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QPushButton>
#include <QInputDialog>
#include <QLineEdit>
#include <QCoreApplication>
#include <QButtonGroup>
#include <QStackedLayout>
#include "wifi.hpp"
#include "wifiManager.hpp"
CustomConnectButton::CustomConnectButton(QString text, int iid){
setText(text);
id=iid;
}
void clearLayout(QLayout* layout){
while (QLayoutItem* item = layout->takeAt(0)){
if (QWidget* widget = item->widget()){
widget->deleteLater();
}
if (QLayout* childLayout = item->layout()){
clearLayout(childLayout);
}
delete item;
}
}
WifiUI::WifiUI(QWidget *parent) : QWidget(parent) {
vlayout = new QVBoxLayout;
wifi = new WifiManager;
refresh();
setLayout(vlayout);
setStyleSheet(R"(
QLabel { font-size: 40px }
QPushButton:enabled {
background-color: #114265;
}
QPushButton:disabled {
background-color: #323C43;
}
* {
background-color: #114265;
}
)");
// TODO: implement (not) connecting with wrong password
// Update network list every second
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh()));
timer->start(1000);
// Scan on startup
wifi->request_scan();
}
void WifiUI::refresh(){
if (!this->isVisible()){
return;
}
wifi->request_scan();
wifi->refreshNetworks();
clearLayout(vlayout);
int i=0;
QButtonGroup* connectButtons=new QButtonGroup(this);
QObject::connect(connectButtons, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(handleButton(QAbstractButton*)));
for (Network &network : wifi->seen_networks){
QHBoxLayout *hlayout = new QHBoxLayout;
hlayout->addWidget(new QLabel(QString::fromUtf8(network.ssid)));
unsigned int strength_scale = std::round(network.strength / 25.0) * 25;
QPixmap pix("../assets/offroad/indicator_wifi_" + QString::number(strength_scale) + ".png");
QLabel *icon = new QLabel();
icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation));
icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
hlayout->addWidget(icon);
hlayout->addSpacing(20);
CustomConnectButton* m_button = new CustomConnectButton(network.connected ? "Connected" : "Connect",i);
m_button->setFixedWidth(300);
m_button->setDisabled(network.connected || network.security_type == SecurityType::UNSUPPORTED);
connectButtons->addButton(m_button,i);
hlayout->addWidget(m_button);
hlayout->addSpacing(20);
vlayout->addLayout(hlayout);
i+=1;
}
}
void WifiUI::handleButton(QAbstractButton* button){
CustomConnectButton* m_button = static_cast<CustomConnectButton*>(button);
int id = m_button->id;
Network n = wifi->seen_networks[id];
// qDebug() << "Clicked a button:" << id;
// qDebug() << n.ssid;
if(n.security_type==SecurityType::OPEN){
wifi->connect(n);
} else if (n.security_type==SecurityType::WPA){
bool ok = false;
QString password;
#ifdef QCOM2
// TODO: implement touch keyboard
#else
password = QInputDialog::getText(this, "Password for "+n.ssid, "Password", QLineEdit::Normal, "", &ok);
#endif
if (ok){
wifi->connect(n, password);
}
} else {
qDebug() << "Cannot determine a network's security type";
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "wifiManager.hpp"
#include <QWidget>
#include <QtDBus>
#include <QPushButton>
#include <QButtonGroup>
#include <QVBoxLayout>
#include <QStackedLayout>
#include <QTimer>
class CustomConnectButton : public QPushButton{
public:
explicit CustomConnectButton(QString text, int iid);
int id;
};
class WifiUI : public QWidget {
Q_OBJECT
private:
WifiManager* wifi;
QVBoxLayout* vlayout;
QTimer * timer;
public:
explicit WifiUI(QWidget *parent = 0);
private slots:
void handleButton(QAbstractButton* m_button);
void refresh();
};

View File

@ -0,0 +1,255 @@
#include <algorithm>
#include <set>
#include "wifiManager.hpp"
#include "wifi.hpp"
typedef QMap<QString, QMap<QString, QVariant> > Connection;
QString nm_path = "/org/freedesktop/NetworkManager";
QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings";
QString nm_iface = "org.freedesktop.NetworkManager";
QString props_iface = "org.freedesktop.DBus.Properties";
QString nm_settings_iface = "org.freedesktop.NetworkManager.Settings";
QString nm_settings_conn_iface = "org.freedesktop.NetworkManager.Settings.Connection";
QString device_iface = "org.freedesktop.NetworkManager.Device";
QString wireless_device_iface = "org.freedesktop.NetworkManager.Device.Wireless";
QString ap_iface = "org.freedesktop.NetworkManager.AccessPoint";
QString connection_iface = "org.freedesktop.NetworkManager.Connection.Active";
QString nm_service = "org.freedesktop.NetworkManager";
template <typename T>
T get_response(QDBusMessage response){
QVariant first = response.arguments().at(0);
QDBusVariant dbvFirst = first.value<QDBusVariant>();
QVariant vFirst = dbvFirst.variant();
return vFirst.value<T>();
}
bool compare_by_strength(const Network &a, const Network &b){
if (a.connected) return true;
if (b.connected) return false;
return a.strength > b.strength;
}
WifiManager::WifiManager(){
qDBusRegisterMetaType<Connection>();
adapter = get_adapter();
has_adapter = adapter != "";
}
void WifiManager::refreshNetworks(){
if (!has_adapter) return;
bus = QDBusConnection::systemBus();
seen_networks.clear();
seen_ssids.clear();
for (Network &network : get_networks()){
if(seen_ssids.count(network.ssid)){
continue;
}
seen_ssids.push_back(network.ssid);
seen_networks.push_back(network);
}
}
QList<Network> WifiManager::get_networks(){
QList<Network> r;
QDBusInterface nm(nm_service, adapter, wireless_device_iface, bus);
QDBusMessage response = nm.call("GetAllAccessPoints");
QVariant first = response.arguments().at(0);
QString active_ap = get_active_ap();
const QDBusArgument &args = first.value<QDBusArgument>();
args.beginArray();
while (!args.atEnd()) {
QDBusObjectPath path;
args >> path;
QByteArray ssid = get_property(path.path(), "Ssid");
unsigned int strength = get_ap_strength(path.path());
SecurityType security = getSecurityType(path.path());
Network network = {path.path(), ssid, strength, path.path()==active_ap, security};
if (ssid.length()){
r.push_back(network);
}
}
args.endArray();
std::sort(r.begin(), r.end(), compare_by_strength);
return r;
}
SecurityType WifiManager::getSecurityType(QString path){
int sflag = get_property(path, "Flags").toInt();
int wpaflag = get_property(path, "WpaFlags").toInt();
int rsnflag = get_property(path, "RsnFlags").toInt();
int wpa_props = wpaflag | rsnflag;
if(sflag == 0){
return SecurityType::OPEN;
}else if((sflag & 0x1) && (wpa_props & (0x333) && !(wpa_props & 0x200)) ){
return SecurityType::WPA;
}else{
// qDebug() << "Cannot determine security type for " << get_property(path, "Ssid") << " with flags";
// qDebug() << "flag " << sflag;
// qDebug() << "WpaFlag " << wpaflag;
// qDebug() << "RsnFlag " << rsnflag;
return SecurityType::UNSUPPORTED;
}
}
void WifiManager::connect(Network n){
return connect(n,"","");
}
void WifiManager::connect(Network n, QString password){
return connect(n, "", password);
}
void WifiManager::connect(Network n, QString username, QString password){
QString active_ap = get_active_ap();
if(active_ap!=""){
clear_connections(get_property(active_ap,"Ssid"));
}
clear_connections(n.ssid);
qDebug() << "Connecting to"<< n.ssid << "with username, password =" << username << "," <<password;
connect(n.ssid, username, password, n.security_type);
}
void WifiManager::connect(QByteArray ssid, QString username, QString password, SecurityType security_type){
Connection connection;
connection["connection"]["type"] = "802-11-wireless";
connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}');
connection["connection"]["id"] = "OpenPilot connection "+QString::fromStdString(ssid.toStdString()); //TODO Add security type
connection["802-11-wireless"]["ssid"] = ssid;
connection["802-11-wireless"]["mode"] = "infrastructure";
if(security_type == SecurityType::WPA){
connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk";
connection["802-11-wireless-security"]["auth-alg"] = "open";
connection["802-11-wireless-security"]["psk"] = password;
}
connection["ipv4"]["method"] = "auto";
connection["ipv6"]["method"] = "ignore";
QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus);
QDBusReply<QDBusObjectPath> result = nm_settings.call("AddConnection", QVariant::fromValue(connection));
if (!result.isValid()) {
qDebug() << result.error().name() << result.error().message();
} else {
qDebug() << result.value().path();
}
}
void WifiManager::print_active_connections(){
//TO-DO clean up, the code is not currently in use.
QDBusInterface nm(nm_service, nm_path, props_iface, bus);
QDBusMessage response = nm.call("Get", nm_iface, "ActiveConnections");
QVariant first = response.arguments().at(0);
QDBusVariant dbvFirst = first.value<QDBusVariant>();
QVariant vFirst = dbvFirst.variant();
QDBusArgument step4 = vFirst.value<QDBusArgument>();
QDBusObjectPath path;
step4.beginArray();
while (!step4.atEnd()){
step4 >> path;
qDebug()<<path.path();
}
step4.endArray();
}
void WifiManager::clear_connections(QString ssid){
QDBusInterface nm(nm_service, nm_settings_path, nm_settings_iface, bus);
QDBusMessage response = nm.call("ListConnections");
QVariant first = response.arguments().at(0);
const QDBusArgument &args = first.value<QDBusArgument>();
args.beginArray();
while (!args.atEnd()) {
QDBusObjectPath path;
args >> path;
QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus);
QDBusMessage response = nm2.call("GetSettings");
const QDBusArgument &dbusArg = response.arguments().at(0).value<QDBusArgument>();
QMap<QString,QMap<QString,QVariant> > map;
dbusArg >> map;
for( QString outer_key : map.keys() ){
QMap<QString,QVariant> innerMap = map.value(outer_key);
for( QString inner_key : innerMap.keys() ){
if(inner_key=="ssid"){
QString value = innerMap.value(inner_key).value<QString>();
if(value == ssid){
// qDebug()<<"Deleting "<<value;
nm2.call("Delete");
}
}
}
}
}
}
void WifiManager::request_scan(){
if (!has_adapter) return;
QDBusInterface nm(nm_service, adapter, wireless_device_iface, bus);
QDBusMessage response = nm.call("RequestScan", QVariantMap());
}
uint WifiManager::get_wifi_device_state(){
QDBusInterface device_props(nm_service, adapter, props_iface, bus);
QDBusMessage response = device_props.call("Get", device_iface, "State");
uint resp = get_response<uint>(response);
return resp;
}
QString WifiManager::get_active_ap(){
QDBusInterface device_props(nm_service, adapter, props_iface, bus);
QDBusMessage response = device_props.call("Get", wireless_device_iface, "ActiveAccessPoint");
QDBusObjectPath r = get_response<QDBusObjectPath>(response);
return r.path();
}
QByteArray WifiManager::get_property(QString network_path ,QString property){
QDBusInterface device_props(nm_service, network_path, props_iface, bus);
QDBusMessage response = device_props.call("Get", ap_iface, property);
return get_response<QByteArray>(response);
}
unsigned int WifiManager::get_ap_strength(QString network_path){
QDBusInterface device_props(nm_service, network_path, props_iface, bus);
QDBusMessage response = device_props.call("Get", ap_iface, "Strength");
return get_response<unsigned int>(response);
}
QString WifiManager::get_adapter(){
QDBusInterface nm(nm_service, nm_path, nm_iface, bus);
QDBusMessage response = nm.call("GetDevices");
QVariant first = response.arguments().at(0);
QString adapter_path = "";
const QDBusArgument &args = first.value<QDBusArgument>();
args.beginArray();
while (!args.atEnd()) {
QDBusObjectPath path;
args >> path;
// Get device type
QDBusInterface device_props(nm_service, path.path(), props_iface, bus);
QDBusMessage response = device_props.call("Get", device_iface, "DeviceType");
uint device_type = get_response<uint>(response);
if (device_type == 2){ // Wireless
adapter_path = path.path();
break;
}
}
args.endArray();
return adapter_path;
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <QWidget>
#include <QtDBus>
enum class SecurityType{OPEN, WPA, UNSUPPORTED};
struct Network {
QString path;
QByteArray ssid;
unsigned int strength;
bool connected;
SecurityType security_type;
};
class WifiManager{
private:
QVector<QByteArray> seen_ssids;
QString adapter;//Path to network manager wifi-device
QDBusConnection bus = QDBusConnection::systemBus();
QString get_adapter();
QList<Network> get_networks();
void connect(QByteArray ssid, QString username, QString password, SecurityType security_type);
QString get_active_ap();
void clear_connections(QString ssid);
void print_active_connections();
uint get_wifi_device_state();
QByteArray get_ap_ssid(QString network_path);
QByteArray get_property(QString network_path, QString property);
unsigned int get_ap_strength(QString network_path);
SecurityType getSecurityType(QString ssid);
public:
bool has_adapter;
void request_scan();
QVector<Network> seen_networks;
explicit WifiManager();
void refreshNetworks();
void connect(Network ssid);
void connect(Network ssid, QString password);
void connect(Network ssid, QString username, QString password);
};

View File

@ -1,69 +0,0 @@
#include <QtDBus>
#include <QDebug>
typedef QMap<QString, QMap<QString, QVariant> > Connection;
Q_DECLARE_METATYPE(Connection)
void wifi_stuff(){
qDBusRegisterMetaType<Connection>();
QString nm_path = "/org/freedesktop/NetworkManager";
QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings";
QString nm_iface = "org.freedesktop.NetworkManager";
QString props_iface = "org.freedesktop.DBus.Properties";
QString nm_settings_iface = "org.freedesktop.NetworkManager.Settings";
QString nm_service = "org.freedesktop.NetworkManager";
QString device_service = "org.freedesktop.NetworkManager.Device";
QDBusConnection bus = QDBusConnection::systemBus();
// Get devices
QDBusInterface nm(nm_service, nm_path, nm_iface, bus);
QDBusMessage response = nm.call("GetDevices");
QVariant first = response.arguments().at(0);
const QDBusArgument &args = first.value<QDBusArgument>();
args.beginArray();
while (!args.atEnd()) {
QDBusObjectPath path;
args >> path;
// Get device type
QDBusInterface device_props(nm_service, path.path(), props_iface, bus);
QDBusMessage response = device_props.call("Get", device_service, "DeviceType");
QVariant first = response.arguments().at(0);
QDBusVariant dbvFirst = first.value<QDBusVariant>();
QVariant vFirst = dbvFirst.variant();
uint device_type = vFirst.value<uint>();
qDebug() << path.path() << device_type;
}
args.endArray();
// Add connection
Connection connection;
connection["connection"]["type"] = "802-11-wireless";
connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}');
connection["connection"]["id"] = "Connection 1";
connection["802-11-wireless"]["ssid"] = QByteArray("<ssid>");
connection["802-11-wireless"]["mode"] = "infrastructure";
connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk";
connection["802-11-wireless-security"]["auth-alg"] = "open";
connection["802-11-wireless-security"]["psk"] = "<password>";
connection["ipv4"]["method"] = "auto";
connection["ipv6"]["method"] = "ignore";
QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus);
QDBusReply<QDBusObjectPath> result = nm_settings.call("AddConnection", QVariant::fromValue(connection));
if (!result.isValid()) {
qDebug() << result.error().name() << result.error().message();
} else {
qDebug() << result.value().path();
}
}