Add support for connecting to hidden wifi networks during bt wifi setup

This commit is contained in:
Michael Zanetti 2022-08-31 22:08:22 +02:00
parent d2edaefdc7
commit fafe6a2f4d
12 changed files with 179 additions and 950 deletions

View File

@ -164,7 +164,6 @@ void TagsManager::getTagsResponse(int /*commandId*/, const QVariantMap &params)
m_tags->addTags(tags);
m_busy = false;
qWarning() << "Tags busy changed to false";
emit busyChanged();
}

View File

@ -36,7 +36,7 @@
#include <QBluetoothUuid>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(dcBtWiFiSetup);
Q_DECLARE_LOGGING_CATEGORY(dcBluetoothDiscovery);
BluetoothDiscovery::BluetoothDiscovery(QObject *parent) :
QObject(parent),
@ -47,13 +47,13 @@ BluetoothDiscovery::BluetoothDiscovery(QObject *parent) :
// Check if bluetooth is available
QBluetoothLocalDevice localDevice;
if (!localDevice.isValid()) {
qCWarning(dcBtWiFiSetup) << "BluetoothDiscovery: there is no bluetooth device available.";
qCWarning(dcBluetoothDiscovery) << "No bluetooth device available.";
m_bluetoothAvailable = false;
return;
}
if (localDevice.allDevices().isEmpty()) {
qCWarning(dcBtWiFiSetup) << "BluetoothDiscovery: there is no bluetooth device available currently.";
qCWarning(dcBluetoothDiscovery) << "No bluetooth device available currently.";
m_bluetoothAvailable = false;
return;
}
@ -77,7 +77,7 @@ BluetoothDiscovery::BluetoothDiscovery(QObject *parent) :
// Always start with assuming BT is enabled
m_bluetoothEnabled = true;
qCDebug(dcBtWiFiSetup) << "Initializing Bluetooth";
qCDebug(dcBluetoothDiscovery) << "Initializing Bluetooth";
onBluetoothHostModeChanged(QBluetoothLocalDevice::HostConnectable);
#endif
@ -94,7 +94,7 @@ bool BluetoothDiscovery::bluetoothEnabled() const
#ifdef Q_OS_IOS
return m_bluetoothAvailable && m_bluetoothEnabled;
#endif
qCDebug(dcBtWiFiSetup) << "bluetoothEnabled(): m_bluetoothAvailable:" << m_bluetoothAvailable;
qCDebug(dcBluetoothDiscovery) << "bluetoothEnabled(): m_bluetoothAvailable:" << m_bluetoothAvailable;
return m_bluetoothAvailable && m_localDevice->hostMode() != QBluetoothLocalDevice::HostPoweredOff;
}
void BluetoothDiscovery::setBluetoothEnabled(bool bluetoothEnabled) {
@ -143,7 +143,7 @@ BluetoothDeviceInfos *BluetoothDiscovery::deviceInfos()
void BluetoothDiscovery::onBluetoothHostModeChanged(const QBluetoothLocalDevice::HostMode &hostMode)
{
qCDebug(dcBtWiFiSetup) << "BluetoothDiscovery: host mode changed" << hostMode;
qCDebug(dcBluetoothDiscovery) << "Host mode changed" << hostMode;
switch (hostMode) {
case QBluetoothLocalDevice::HostPoweredOff:
if (m_discoveryAgent) {
@ -186,20 +186,20 @@ void BluetoothDiscovery::onBluetoothHostModeChanged(const QBluetoothLocalDevice:
void BluetoothDiscovery::deviceDiscovered(const QBluetoothDeviceInfo &deviceInfo)
{
qCDebug(dcBtWiFiSetup()) << "BluetoothDiscovery: Device discovered:" << deviceInfo.name() << deviceInfo.address().toString() << deviceInfo.deviceUuid() << deviceInfo.serviceUuids();
qCDebug(dcBluetoothDiscovery()) << "Device discovered:" << deviceInfo.name() << deviceInfo.address().toString() << deviceInfo.deviceUuid() << deviceInfo.serviceUuids();
foreach (BluetoothDeviceInfo *di, m_deviceInfos->deviceInfos()) {
// Some platforms only provide device UUID (e.g. Apple) and MAC address is 00:00:00:00:00
// Others provide only a MAC address and the UUID is null.
// If we have a UUID, use that, otherwise use the MAC for comparison
if (!deviceInfo.deviceUuid().isNull()) {
if (di->bluetoothDeviceInfo().deviceUuid() == deviceInfo.deviceUuid()) {
qCDebug(dcBtWiFiSetup()) << "Updating discovery result (UUID)";
qCDebug(dcBluetoothDiscovery()) << "Updating discovery result (UUID)";
di->setBluetoothDeviceInfo(deviceInfo);
return;
}
} else {
if (di->bluetoothDeviceInfo().address() == deviceInfo.address()) {
qCDebug(dcBtWiFiSetup()) << "Updating discovery result (MAC)";
qCDebug(dcBluetoothDiscovery()) << "Updating discovery result (MAC)";
di->setBluetoothDeviceInfo(deviceInfo);
return;
}
@ -207,27 +207,27 @@ void BluetoothDiscovery::deviceDiscovered(const QBluetoothDeviceInfo &deviceInfo
}
BluetoothDeviceInfo *deviceInformation = new BluetoothDeviceInfo(deviceInfo);
qCDebug(dcBtWiFiSetup) << "BluetoothDiscovery: [+]" << deviceInformation->name() << "(" << deviceInformation->address() << ")" << (deviceInformation->isLowEnergy() ? "LE" : "") << deviceInfo.serviceUuids();
qCDebug(dcBluetoothDiscovery) << "[+]" << deviceInformation->name() << "(" << deviceInformation->address() << ")" << (deviceInformation->isLowEnergy() ? "LE" : "") << deviceInfo.serviceUuids();
m_deviceInfos->addBluetoothDeviceInfo(deviceInformation);
}
void BluetoothDiscovery::discoveryFinished()
{
qCDebug(dcBtWiFiSetup) << "BluetoothDiscovery: Discovery finished" << m_discoveryEnabled << this;
qCDebug(dcBluetoothDiscovery) << "Discovery finished" << m_discoveryEnabled << this;
if (m_discoveryEnabled) {
qCDebug(dcBtWiFiSetup) << "BluetoothDiscovery: Restarting discovery";
qCDebug(dcBluetoothDiscovery) << "Restarting discovery";
m_discoveryAgent->start();
}
}
void BluetoothDiscovery::discoveryCancelled()
{
qCDebug(dcBtWiFiSetup) << "BluetoothDiscovery: Discovery cancelled";
qCDebug(dcBluetoothDiscovery) << "Discovery cancelled";
}
void BluetoothDiscovery::onError(const QBluetoothDeviceDiscoveryAgent::Error &error)
{
qCWarning(dcBtWiFiSetup) << "BluetoothDiscovery: Discovery error:" << error << m_discoveryAgent->errorString();
qCWarning(dcBluetoothDiscovery) << "Discovery error:" << error << m_discoveryAgent->errorString();
#ifdef Q_OS_IOS
if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError) {
m_bluetoothEnabled = false;
@ -253,11 +253,11 @@ void BluetoothDiscovery::start()
}
foreach (const QBluetoothDeviceInfo &info, m_discoveryAgent->discoveredDevices()) {
qCDebug(dcBtWiFiSetup()) << "Already discovered device:" << info.name();
qCDebug(dcBluetoothDiscovery()) << "Already discovered device:" << info.name();
deviceDiscovered(info);
}
qCDebug(dcBtWiFiSetup) << "BluetoothDiscovery: Starting discovery.";
qCDebug(dcBluetoothDiscovery) << "Starting discovery.";
m_discoveryAgent->start();
emit discoveringChanged();
}
@ -268,7 +268,7 @@ void BluetoothDiscovery::stop()
return;
}
qCDebug(dcBtWiFiSetup) << "BluetoothDiscovery: Stop discovering.";
qCDebug(dcBluetoothDiscovery) << "Stopping discovering.";
m_discoveryAgent->stop();
emit discoveringChanged();
}

View File

@ -13,6 +13,7 @@ static QBluetoothUuid wifiCommanderCharacteristicUuid = QBluetoothUuid(QUuid("e0
static QBluetoothUuid wifiResponseCharacteristicUuid = QBluetoothUuid(QUuid("e081fec2-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid wifiStatusCharacteristicUuid = QBluetoothUuid(QUuid("e081fec3-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid wifiModeCharacteristicUuid = QBluetoothUuid(QUuid("e081fec4-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid wifiServiceVersionCharacteristicUuid = QBluetoothUuid(QUuid("e081fec5-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid networkServiceUuid = QBluetoothUuid(QUuid("ef6d6610-b8af-49e0-9eca-ab343513641c"));
static QBluetoothUuid networkStatusCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6611-b8af-49e0-9eca-ab343513641c"));
@ -36,6 +37,11 @@ BtWiFiSetup::~BtWiFiSetup()
qCDebug(dcBtWiFiSetup()) << "Destroying BtWifiSetup";
}
int BtWiFiSetup::wirelessServiceVersion() const
{
return m_wirelessServiceVersion;
}
void BtWiFiSetup::connectToDevice(const BluetoothDeviceInfo *device)
{
qCDebug(dcBtWiFiSetup()) << "Connecting to device" << device->address() << device->name();
@ -46,6 +52,8 @@ void BtWiFiSetup::connectToDevice(const BluetoothDeviceInfo *device)
m_accessPoints->clearModel();
m_bluetoothStatus = BluetoothStatusDisconnected;
emit bluetoothStatusChanged(m_bluetoothStatus);
m_wirelessServiceVersion = 1;
emit wirelessServiceVersionChanged();
}
m_btController = QLowEnergyController::createCentral(device->bluetoothDeviceInfo(), this);
@ -90,7 +98,7 @@ void BtWiFiSetup::disconnectFromDevice()
}
}
void BtWiFiSetup::connectDeviceToWiFi(const QString &ssid, const QString &password)
void BtWiFiSetup::connectDeviceToWiFi(const QString &ssid, const QString &password, bool hidden)
{
if (m_bluetoothStatus < BluetoothStatusConnectedToBluetooth) {
qCWarning(dcBtWiFiSetup()) << "Cannot connect to wifi in state" << m_bluetoothStatus;
@ -102,6 +110,9 @@ void BtWiFiSetup::connectDeviceToWiFi(const QString &ssid, const QString &passwo
QVariantMap parameters;
parameters.insert("e", ssid);
parameters.insert("p", password);
if (hidden) {
parameters.insert("h", true);
}
request.insert("p", parameters);
streamData(m_wifiService, wifiCommanderCharacteristicUuid, request);
}
@ -290,7 +301,9 @@ void BtWiFiSetup::setupServices()
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcBtWiFiSetup()) << "Wifi service discovered";
qCDebug(dcBtWiFiSetup()) << "Wifi service discovered" << m_wifiService->characteristic(wifiServiceVersionCharacteristicUuid).value();
m_wifiService->readCharacteristic(m_wifiService->characteristic(wifiServiceVersionCharacteristicUuid));
// Enable notifations
m_wifiService->writeDescriptor(m_wifiService->characteristic(wifiResponseCharacteristicUuid).descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), QByteArray::fromHex("0100"));
@ -299,6 +312,7 @@ void BtWiFiSetup::setupServices()
qCDebug(dcBtWiFiSetup()) << "Fetching networks after init";
loadNetworks();
});
connect(m_wifiService, &QLowEnergyService::characteristicRead, this, &BtWiFiSetup::characteristicChanged);
connect(m_wifiService, &QLowEnergyService::characteristicChanged, this, &BtWiFiSetup::characteristicChanged);
m_wifiService->discoverDetails();
@ -370,9 +384,10 @@ void BtWiFiSetup::processWiFiPacket(const QVariantMap &data)
case WirelessServiceCommandConnect:
qCDebug(dcBtWiFiSetup()) << "Connect call succeeded";
break;
case WirelessServiceCommandGetCurrentConnection:
case WirelessServiceCommandGetCurrentConnection: {
// Find current network
if (!data.value("p").toMap().value("m").toString().isEmpty() && data.value("p").toMap().value("i").toString().isEmpty()) {
QVariantMap currentConnection = data.value("p").toMap();
if (!currentConnection.value("m").toString().isEmpty() && currentConnection.value("i").toString().isEmpty()) {
// There's a bug in libnymea-networkmanager that sometimes it emits current connection before it actually obtained the IP address
qCDebug(dcBtWiFiSetup()) << "Retring to fetch the current connection because IP is not set yet.";
loadCurrentConnection();
@ -380,7 +395,6 @@ void BtWiFiSetup::processWiFiPacket(const QVariantMap &data)
}
m_currentConnection = nullptr;
foreach (WirelessAccessPoint *accessPoint, m_accessPoints->wirelessAccessPoints()) {
QVariantMap currentConnection = data.value("p").toMap();
QString macAddress = currentConnection.value("m").toString();
if (accessPoint->macAddress() == macAddress) {
// Set the current network
@ -389,6 +403,18 @@ void BtWiFiSetup::processWiFiPacket(const QVariantMap &data)
accessPoint->setHostAddress(currentConnection.value("i").toString());
}
}
if (!m_currentConnection && !currentConnection.value("m").toString().isEmpty()) {
// There's a currentConnection, but we don't know it in our AP list yet. Creating it.
// (This happens for example when connecting to a hidden wifi)
WirelessAccessPoint *newAP = new WirelessAccessPoint(this);
newAP->setSsid(currentConnection.value("e").toString());
newAP->setMacAddress(currentConnection.value("m").toString());
newAP->setSignalStrength(currentConnection.value("s").toInt());
newAP->setProtected(currentConnection.value("p").toBool());
newAP->setHostAddress(currentConnection.value("i").toString());
m_accessPoints->addWirelessAccessPoint(newAP);
m_currentConnection = newAP;
}
qCDebug(dcBtWiFiSetup()) << "current connection is:" << m_currentConnection;
emit currentConnectionChanged();
@ -398,6 +424,7 @@ void BtWiFiSetup::processWiFiPacket(const QVariantMap &data)
}
break;
}
case WirelessServiceCommandScan:
if (responseCode == WirelessServiceResponseSuccess) {
qCDebug(dcBtWiFiSetup()) << "Fetching networks after wifi scan";
@ -425,7 +452,12 @@ void BtWiFiSetup::loadCurrentConnection()
void BtWiFiSetup::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic.uuid() == wifiResponseCharacteristicUuid) {
if (characteristic.uuid() == wifiServiceVersionCharacteristicUuid) {
qCDebug(dcBtWiFiSetup()) << "Wireless service version received:" << value;
m_wirelessServiceVersion = value.toInt();
emit wirelessServiceVersionChanged();
} else if (characteristic.uuid() == wifiResponseCharacteristicUuid) {
m_inputBuffers[characteristic.uuid()].append(value);
if (!m_inputBuffers[characteristic.uuid()].endsWith("\n")) {

View File

@ -12,6 +12,8 @@ class WirelessAccessPoint;
class BtWiFiSetup : public QObject
{
Q_OBJECT
Q_PROPERTY(int wirelessServiceVersion READ wirelessServiceVersion NOTIFY wirelessServiceVersionChanged)
Q_PROPERTY(BluetoothStatus bluetoothStatus READ bluetoothStatus NOTIFY bluetoothStatusChanged)
Q_PROPERTY(QString modelNumber READ modelNumber NOTIFY modelNumberChanged)
@ -122,13 +124,25 @@ public:
};
Q_ENUM(SystemServiceResponse)
enum AuthAlgorithm {
AuthAlgorithmOpen
};
Q_ENUM(AuthAlgorithm)
enum KeyManagement {
KeyManagementWpaPsk
};
Q_ENUM(KeyManagement)
explicit BtWiFiSetup(QObject *parent = nullptr);
~BtWiFiSetup() override;
int wirelessServiceVersion() const;
Q_INVOKABLE void connectToDevice(const BluetoothDeviceInfo *device);
Q_INVOKABLE void disconnectFromDevice();
Q_INVOKABLE void connectDeviceToWiFi(const QString &ssid, const QString &password);
Q_INVOKABLE void connectDeviceToWiFi(const QString &ssid, const QString &password, bool hidden = false);
Q_INVOKABLE void disconnectDeviceFromWiFi();
Q_INVOKABLE void scanWiFi();
Q_INVOKABLE bool pressPushButton();
@ -153,6 +167,7 @@ public:
WirelessAccessPoint *currentConnection() const;
signals:
void wirelessServiceVersionChanged();
void bluetoothStatusChanged(BluetoothStatus status);
void bluetoothConnectionError();
void wifiSetupError();
@ -192,6 +207,8 @@ private:
QHash<QUuid, QByteArray> m_inputBuffers;
int m_wirelessServiceVersion = 1;
QString m_modelNumber;
QString m_manufacturer;
QString m_softwareRevision;

View File

@ -12,11 +12,6 @@
<file>ui/mainviews/FavoritesView.qml</file>
<file>ui/mainviews/ThingsView.qml</file>
<file>ui/connection/ConnectingPage.qml</file>
<file>ui/connection/wifisetup/BluetoothDiscoveryPage.qml</file>
<file>ui/connection/wifisetup/WirelessSetupPage.qml</file>
<file>ui/connection/wifisetup/ConnectWiFiPage.qml</file>
<file>ui/connection/wifisetup/NetworkSettingsPage.qml</file>
<file>ui/connection/wifisetup/BoxInfoPage.qml</file>
<file>ui/components/NymeaHeader.qml</file>
<file>ui/components/HeaderButton.qml</file>
<file>ui/components/ColorPickerPre510.qml</file>
@ -247,7 +242,7 @@
<file>ui/system/ModbusRtuSettingsPage.qml</file>
<file>ui/system/ModbusRtuAddMasterPage.qml</file>
<file>ui/system/ModbusRtuReconfigureMasterPage.qml</file>
<file>ui/connection/NewConnectionWizard.qml</file>
<file>ui/connection/ConnectionWizard.qml</file>
<file>ui/components/WizardPageBase.qml</file>
<file>ui/system/ZigbeeNetworkPage.qml</file>
<file>ui/components/ConnectionInfoDialog.qml</file>

View File

@ -6,7 +6,7 @@ ConfigurationBase {
appName: "nymea:app"
appId: "io.guh.nymeaapp"
connectionWizard: "/ui/connection/NewConnectionWizard.qml"
connectionWizard: "/ui/connection/ConnectionWizard.qml"
magicEnabled: true
networkSettingsEnabled: true

View File

@ -570,66 +570,137 @@ WizardPageBase {
property var wifiSetup: null
content: ListView {
Component.onCompleted: {
wifiSetup.scanWiFi()
}
content: ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: visibleContentHeight
model: wifiSetup.accessPoints
clip: true
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
delegate: NymeaItemDelegate {
width: parent.width
model: wifiSetup.accessPoints
clip: true
text: model.ssid !== "" ? model.ssid : qsTr("Hidden Network")
subText: model.hostAddress
delegate: NymeaItemDelegate {
width: parent.width
iconColor: model.selectedNetwork ? Style.accentColor : "#808080"
iconName: {
if (model.protected) {
if (model.signalStrength <= 25)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-25-secure.svg")
text: model.ssid !== "" ? model.ssid : qsTr("Hidden Network")
subText: model.hostAddress
if (model.signalStrength <= 50)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-50-secure.svg")
iconColor: model.selectedNetwork ? Style.accentColor : "#808080"
iconName: {
if (model.protected) {
if (model.signalStrength <= 25)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-25-secure.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-75-secure.svg")
if (model.signalStrength <= 50)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-50-secure.svg")
if (model.signalStrength <= 100)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-100-secure.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-75-secure.svg")
} else {
if (model.signalStrength <= 100)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-100-secure.svg")
if (model.signalStrength <= 25)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-25.svg")
} else {
if (model.signalStrength <= 50)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-50.svg")
if (model.signalStrength <= 25)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-25.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-75.svg")
if (model.signalStrength <= 50)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-50.svg")
if (model.signalStrength <= 100)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-100.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-75.svg")
if (model.signalStrength <= 100)
return Qt.resolvedUrl("/ui/images/connections/nm-signal-100.svg")
}
}
onClicked: {
print("Connect to ", model.ssid, " --> ", model.macAddress)
if (model.selectedNetwork) {
pageStack.push(networkInformationPage, { ssid: model.ssid})
} else {
pageStack.push(wirelessAuthenticationComponent, { wifiSetup: wifiSetup, ssid: model.ssid })
}
}
}
}
NymeaItemDelegate {
Layout.fillWidth: true
text: qsTr("Hidden WiFi")
visible: wifiSetup.wirelessServiceVersion >= 2
onClicked: {
print("Connect to ", model.ssid, " --> ", model.macAddress)
if (model.selectedNetwork) {
pageStack.push(networkInformationPage, { ssid: model.ssid})
} else {
pageStack.push(wirelessAuthenticationComponent, { wifiSetup: wifiSetup, ssid: model.ssid })
}
pageStack.push(hiddenWifiComponent, {wifiSetup: wifiSetup})
}
}
}
}
}
Component {
id: hiddenWifiComponent
WizardPageBase {
title: qsTr("Hidden WiFi")
text: qsTr("Enter the information for the hidden WiFi")
property var wifiSetup: null
onBack: pageStack.pop();
onNext: {
print("connecting to", ssidTextField.text, passwordTextField.password)
wifiSetup.connectDeviceToWiFi(ssidTextField.text, passwordTextField.password, true)
pageStack.push(wirelessConnectingWiFiComponent)
}
content: ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.alignment: Qt.AlignHCenter
Layout.margins: Style.margins
Label {
Layout.fillWidth: true
text: qsTr("SSID")
}
NymeaTextField {
id: ssidTextField
Layout.fillWidth: true
}
Label {
Layout.fillWidth: true
text: qsTr("Password")
}
PasswordTextField {
id: passwordTextField
Layout.fillWidth: true
signup: false
requireLowerCaseLetter: false
requireUpperCaseLetter: false
requireNumber: false
requireSpecialChar: false
minPasswordLength: 8
}
}
}
}
Component {
id: wirelessAuthenticationComponent
WizardPageBase {

View File

@ -1,305 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.4
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "../../components"
import Nymea 1.0
Page {
id: root
header: NymeaHeader {
text: qsTr("Wireless Box setup")
onBackPressed: pageStack.pop()
}
BluetoothDiscovery {
id: bluetoothDiscovery
discoveryEnabled: pageStack.currentItem === root
}
BluetoothDeviceInfosProxy {
id: deviceInfosProxy
model: bluetoothDiscovery.deviceInfos
filterForLowEnergy: true
filterForServiceUUID: "e081fec0-f757-4449-b9c9-bfa83133f7fc"
nameWhitelist: ["BT WLAN setup"]
}
BtWiFiSetup {
id: wifiSetup
onBluetoothStatusChanged: {
print("status changed", status)
switch (status) {
case BtWiFiSetup.BluetoothStatusDisconnected:
pageStack.pop(root)
break;
case BtWiFiSetup.BluetoothStatusConnectingToBluetooth:
break;
case BtWiFiSetup.BluetoothStatusConnectedToBluetooth:
break;
case BtWiFiSetup.BluetoothStatusLoaded:
if (!wifiSetup.networkingEnabled) {
wifiSetup.networkingEnabled = true;
}
if (!wifiSetup.wirelessEnabled) {
wifiSetup.wirelessEnabled = true;
}
setupDevice()
break;
}
}
onWirelessStatusChanged: {
}
onBluetoothConnectionError: {
print("Error")
pageStack.pop(root)
}
onWirelessEnabledChanged: {
if (wirelessEnabled) {
scanWiFi();
}
}
}
function connectDevice(btDeviceInfo) {
wifiSetup.connectToDevice(btDeviceInfo)
print("**** connecting")
pageStack.push(connectingPageComponent, {deviceName: btDeviceInfo.name})
}
function setupDevice() {
pageStack.pop(root, StackView.Immediate)
if (wifiSetup.currentConnection) {
var page = pageStack.push(Qt.resolvedUrl("WirelessSetupPage.qml"), { wifiSetup: wifiSetup } )
page.done.connect(function() {
pageStack.pop(root, StackView.Immediate);
pageStack.pop();
})
} else {
var page = pageStack.push(Qt.resolvedUrl("ConnectWiFiPage.qml"), { wifiSetup: wifiSetup } )
page.connected.connect(function() {
setupDevice();
})
}
}
ColumnLayout {
anchors.fill: parent
visible: bluetoothDiscovery.bluetoothAvailable && bluetoothDiscovery.bluetoothEnabled
RowLayout {
Layout.margins: app.margins
Label {
Layout.fillWidth: true
text: qsTr("Searching for %1 systems.").arg(Configuration.systemName)
wrapMode: Text.WordWrap
}
BusyIndicator {
running: bluetoothDiscovery.discovering
}
}
ThinDivider {}
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: deviceInfosProxy
clip: true
delegate: NymeaSwipeDelegate {
width: parent.width
iconName: Qt.resolvedUrl("../../images/connections/bluetooth.svg")
text: model.name
subText: model.address
onClicked: {
root.connectDevice(deviceInfosProxy.get(index))
}
}
}
ThinDivider {}
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Layout.bottomMargin: app.margins
spacing: app.margins
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
maximumLineCount: 2
elide: Text.ElideRight
text: qsTr("Troubles finding your %1 system?").arg(Configuration.systemName)
}
Button {
text: qsTr("Help")
onClicked: pageStack.push(helpPageComponent)
}
}
}
ColumnLayout {
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter; margins: app.margins }
visible: !bluetoothDiscovery.bluetoothAvailable || !bluetoothDiscovery.bluetoothEnabled
spacing: app.margins * 2
Label {
Layout.fillWidth: true
text: qsTr("Uh oh")
color: Style.accentColor
font.pixelSize: app.largeFont
}
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: !bluetoothDiscovery.bluetoothAvailable
? qsTr("Bluetooth doesn't seem to be available on this device. The wireless network setup requires a working Bluetooth connection.")
: qsTr("Bluetooth seems to be disabled. Please enable Bluetooth on your device in order to use the wireless network setup.")
}
}
Component {
id: helpPageComponent
Page {
id: helpPage
header: NymeaHeader {
text: qsTr("Wireless setup help")
onBackPressed: pageStack.pop()
}
Flickable {
anchors.fill: parent
contentHeight: helpColumn.implicitHeight
ColumnLayout {
id: helpColumn
width: parent.width
spacing: app.margins
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Layout.topMargin: app.margins
wrapMode: Text.WordWrap
font.bold: true
text: "Raspberry Pi™"
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
wrapMode: Text.WordWrap
text: qsTr("After having installed the nymea community image to your Raspberry Pi, all you need to do is to plug it into a power socket. Note that the Wireless setup will only be available if the Raspberry Pi is not connected to a wired network.")
}
Image {
Layout.preferredWidth: Style.iconSize * 8
Layout.preferredHeight: width * 540 / 800
sourceSize.width: 800
sourceSize.height: 540
fillMode: Image.PreserveAspectFit
Layout.alignment: Qt.AlignHCenter
source: "../../images/rpi-setup.svg"
}
ThinDivider {}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
wrapMode: Text.WordWrap
font.bold: true
text: qsTr("%1 box").arg(systemName)
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
wrapMode: Text.WordWrap
text: qsTr("If you have a %1 box, plug it into a power socket and wait for it to be booted. Once the LED pulses slowly, press the button for 3 seconds until the LED changes.").arg(Configuration.systemName)
}
Image {
Layout.preferredWidth: Style.iconSize * 5
Layout.preferredHeight: width
Layout.bottomMargin: app.margins
sourceSize.width: width
sourceSize.height: width
fillMode: Image.PreserveAspectFit
Layout.alignment: Qt.AlignHCenter
source: "../../images/nymea-box-setup.svg"
}
}
}
}
}
Component {
id: connectingPageComponent
Page {
id: connectingPage
header: NymeaHeader {
text: qsTr("Connecting...")
onBackPressed: pageStack.pop()
}
property string deviceName
ColumnLayout {
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter; margins: app.margins }
spacing: app.margins
BusyIndicator {
Layout.alignment: Qt.AlignHCenter
running: true
}
Label {
id: initializingMessage
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
text: qsTr("Connecting to %1").arg(connectingPage.deviceName)
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
}
}
}
}

View File

@ -1,80 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.4
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "../../components"
import Nymea 1.0
Page {
id: root
header: NymeaHeader {
text: qsTr("Box information")
onBackPressed: pageStack.pop()
}
property BtWiFiSetup wifiSetup: null
ColumnLayout {
anchors { left: parent.left; top: parent.top; right: parent.right }
NymeaSwipeDelegate {
Layout.fillWidth: true
progressive: false
text: qsTr("System UUID")
subText: wifiSetup.modelNumber
}
NymeaSwipeDelegate {
Layout.fillWidth: true
progressive: false
text: qsTr("Manufacturer")
subText: wifiSetup.manufacturer
}
NymeaSwipeDelegate {
Layout.fillWidth: true
progressive: false
text: qsTr("Software revision")
subText: wifiSetup.softwareRevision
}
NymeaSwipeDelegate {
Layout.fillWidth: true
progressive: false
text: qsTr("Firmware revision")
subText: wifiSetup.firmwareRevision
}
NymeaSwipeDelegate {
Layout.fillWidth: true
progressive: false
text: qsTr("Hardware revision")
subText: wifiSetup.hardwareRevision
}
}
}

View File

@ -1,246 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.4
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "../../components"
import Nymea 1.0
Page {
id: root
property BtWiFiSetup wifiSetup: null
signal connected();
header: NymeaHeader {
text: qsTr("Select wireless network")
onBackPressed: {
pageStack.pop();
}
HeaderButton {
imageSource: "../images/info.svg"
onClicked: {
pageStack.push(Qt.resolvedUrl("BoxInfoPage.qml"), {wifiSetup: root.wifiSetup})
}
}
HeaderButton {
imageSource: "../images/settings.svg"
onClicked: {
pageStack.push(Qt.resolvedUrl("NetworkSettingsPage.qml"), {wifiSetup: root.wifiSetup})
}
}
}
ColumnLayout {
anchors.fill: parent
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: WirelessAccessPointsProxy {
accessPoints: wifiSetup.accessPoints
}
clip: true
Timer {
interval: 5000
repeat: true
onTriggered: wifiSetup.scanWiFi()
running: wifiSetup.accessPoints.count === 0
}
BusyIndicator {
anchors.centerIn: parent
visible: wifiSetup.accessPoints.count === 0
running: visible
}
delegate: NymeaSwipeDelegate {
width: parent.width
text: model.ssid !== "" ? model.ssid : qsTr("Hidden Network")
subText: model.hostAddress
iconColor: model.selectedNetwork ? Style.accentColor : "#808080"
iconName: {
if (model.protected) {
if (model.signalStrength <= 25)
return Qt.resolvedUrl("../../images/connections/nm-signal-25-secure.svg")
if (model.signalStrength <= 50)
return Qt.resolvedUrl("../../images/connections/nm-signal-50-secure.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("../../images/connections/nm-signal-75-secure.svg")
if (model.signalStrength <= 100)
return Qt.resolvedUrl("../../images/connections/nm-signal-100-secure.svg")
} else {
if (model.signalStrength <= 25)
return Qt.resolvedUrl("../../images/connections/nm-signal-25.svg")
if (model.signalStrength <= 50)
return Qt.resolvedUrl("../../images/connections/nm-signal-50.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("../../images/connections/nm-signal-75.svg")
if (model.signalStrength <= 100)
return Qt.resolvedUrl("../../images/connections/nm-signal-100.svg")
}
}
onClicked: {
print("Connect to ", model.ssid, " --> ", model.macAddress)
if (model.selectedNetwork) {
pageStack.push(networkInformationPage, { ssid: model.ssid, macAddress: model.macAddress })
} else {
pageStack.push(authenticationPageComponent, { ssid: model.ssid, macAddress: model.macAddress })
}
}
}
}
}
Component {
id: authenticationPageComponent
Page {
id: authenticationPage
header: NymeaHeader {
text: qsTr("Authenticate")
onBackPressed: pageStack.pop()
}
property string ssid
property string macAddress
Connections {
target: root.wifiSetup
onCurrentConnectionChanged: {
if (root.wifiSetup.currentConnection && root.wifiSetup.currentConnection.ssid === authenticationPage.ssid) {
print("**** connected!")
root.connected();
}
}
onWirelessStatusChanged: {
print("Wireless status changed:", wifiSetup.networkStatus)
if (wifiSetup.wirelessStatus === BtWiFiSetup.WirelessStatusFailed) {
wrongPasswordText.visible = true
pageStack.pop(authenticationPage)
}
}
}
ColumnLayout {
anchors { left: parent.left; top: parent.top; right: parent.right; }
Label {
Layout.fillWidth: true
Layout.margins: app.margins
text: qsTr("Enter the password for %1").arg(authenticationPage.ssid)
wrapMode: Text.WordWrap
}
RowLayout {
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
TextField {
id: passwordTextField
Layout.fillWidth: true
property bool showPassword: false
echoMode: showPassword ? TextInput.Normal : TextInput.Password
}
ColorIcon {
Layout.preferredHeight: Style.iconSize
Layout.preferredWidth: Style.iconSize
name: "../images/eye.svg"
color: passwordTextField.showPassword ? Style.accentColor : Style.iconColor
MouseArea {
anchors.fill: parent
onClicked: passwordTextField.showPassword = !passwordTextField.showPassword
}
}
}
Label {
id: wrongPasswordText
text: qsTr("Sorry, the password is wrong. Please try again.")
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
color: "red"
visible: false
}
Button {
Layout.fillWidth: true
Layout.margins: app.margins
text: qsTr("OK")
enabled: passwordTextField.displayText.length >= 8
onClicked: {
root.wifiSetup.connectDeviceToWiFi(authenticationPage.ssid, passwordTextField.text)
pageStack.push(connectingWifiWaitPageComponent, {ssid: authenticationPage.ssid })
}
}
}
}
}
Component {
id: connectingWifiWaitPageComponent
Page {
id: connectingWifiWaitPage
property string ssid
ColumnLayout {
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter; margins: app.margins }
spacing: app.margins * 2
BusyIndicator {
Layout.alignment: Qt.AlignHCenter
}
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Connecting %1 to %2").arg(Configuration.systemName).arg(connectingWifiWaitPage.ssid)
}
}
}
}
}

View File

@ -1,74 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.4
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "../../components"
import Nymea 1.0
Page {
id: root
header: NymeaHeader {
text: qsTr("Network settings")
onBackPressed: pageStack.pop()
}
property BtWiFiSetup wifiSetup: null
ColumnLayout {
anchors { left: parent.left; top: parent.top; right: parent.right }
SwitchDelegate {
Layout.fillWidth: true
text: qsTr("Networking")
checked: wifiSetup.networkingEnabled
onClicked: wifiSetup.networkingEnabled = checked
}
SwitchDelegate {
Layout.fillWidth: true
enabled: wifiSetup.networkingEnabled
text: qsTr("Wireless network")
checked: wifiSetup.wirelessEnabled
onClicked: {
wifiSetup.wirelessEnabled = checked
}
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Trigger a wireless scan on the device.")
onClicked: wifiSetup.scanWiFi()
}
}
}

View File

@ -1,180 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.4
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "../../components"
import Nymea 1.0
Page {
id: root
property BtWiFiSetup wifiSetup: null
signal done()
header: NymeaHeader {
text: qsTr("Wireless network setup")
onBackPressed: {
pageStack.pop();
}
HeaderButton {
imageSource: "../images/info.svg"
onClicked: {
pageStack.push(Qt.resolvedUrl("BoxInfoPage.qml"), {wifiSetup: root.wifiSetup})
}
}
HeaderButton {
imageSource: "../images/settings.svg"
onClicked: {
pageStack.push(Qt.resolvedUrl("NetworkSettingsPage.qml"), {wifiSetup: root.wifiSetup})
}
}
}
Component.onCompleted: {
updateConnectButton();
}
Connections {
target: root.wifiSetup
onWifiSetupError: {
print("Error occurred", errorMessage)
var errorDialog = Qt.createComponent(Qt.resolvedUrl("../components/ErrorDialog.qml"));
var popup = errorDialog.createObject(app, {text: errorMessage})
popup.open()
}
onCurrentConnectionChanged: {
updateConnectButton();
}
}
Connections {
target: nymeaDiscovery.nymeaHosts
onCountChanged: updateConnectButton();
}
function updateConnectButton() {
if (!root.wifiSetup.currentConnection) {
connectButton.host = null;
return;
}
// FIXME: We should rather look for the UUID here, but nymea-networkmanager doesn't support getting us the nymea uuid (yet)
for (var i = 0; i < nymeaDiscovery.nymeaHosts.count; i++) {
for (var j = 0; j < nymeaDiscovery.nymeaHosts.get(i).connections.count; j++) {
if (nymeaDiscovery.nymeaHosts.get(i).connections.get(j).url.toString().indexOf(root.wifiSetup.currentConnection.hostAddress) >= 0) {
connectButton.host = nymeaDiscovery.nymeaHosts.get(i)
return;
}
}
nymeaDiscovery.nymeaHosts.get(i).connections.countChanged.connect(function() {
updateConnectButton();
})
}
connectButton.host = null;
}
ColumnLayout {
anchors { left: parent.left; top: parent.top; right: parent.right }
spacing: app.margins
ColorIcon {
Layout.preferredHeight: Style.iconSize * 2
Layout.preferredWidth: height
Layout.alignment: Qt.AlignCenter
name: "../images/tick.svg"
color: Style.accentColor
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
wrapMode: Text.WordWrap
text: root.wifiSetup.currentConnection
? qsTr("Your %1 system is connected to %2").arg(Configuration.systemName).arg(root.wifiSetup.currentConnection.ssid)
: ""
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
text: qsTr("IP address: %1").arg(root.wifiSetup.currentConnection.hostAddress)
elide: Text.ElideRight
}
RowLayout {
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
visible: !connectButton.visible
spacing: app.margins
Label {
Layout.fillWidth: true
text: qsTr("Waiting for the %1 to appear in your network.").arg(Configuration.systemName)
wrapMode: Text.WordWrap
}
BusyIndicator { }
}
Button {
id: connectButton
visible: host !== null
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
text: qsTr("Connect to %1").arg(Configuration.systemName)
property NymeaHost host: null
onClicked: {
print("connecting to", host)
engine.jsonRpcClient.connectToHost(host)
}
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
text: qsTr("Change network")
onClicked: {
var page = pageStack.push(Qt.resolvedUrl("ConnectWiFiPage.qml"), {wifiSetup: root.wifiSetup})
page.connected.connect(function() {
pageStack.pop(root)
})
}
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
text: qsTr("Close wireless setup")
onClicked: {
root.done()
}
}
}
}