diff --git a/nymea-app/ui/system/EvDashSettingsPage.qml b/nymea-app/ui/system/EvDashSettingsPage.qml
index 4a417dfc..40d53875 100644
--- a/nymea-app/ui/system/EvDashSettingsPage.qml
+++ b/nymea-app/ui/system/EvDashSettingsPage.qml
@@ -1,30 +1,24 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
-* Copyright 2013 - 2025, nymea GmbH
-* Contact: contact@nymea.io
+* Copyright (C) 2013 - 2024, nymea GmbH
+* Copyright (C) 2024 - 2025, chargebyte austria GmbH
*
-* 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
+* This file is part of nymea-app.
*
-* 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.
+* nymea-app is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
*
-* You should have received a copy of the GNU General Public License along with
-* this project. If not, see .
+* nymea-app 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.
*
-* 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
+* You should have received a copy of the GNU General Public License
+* along with nymea-app. If not, see .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -37,11 +31,107 @@ import NymeaApp.Utils
import Nymea.EvDash
-import "../components"
+import "qrc:/ui/components"
SettingsPageBase {
id: root
+ readonly property string serverIpAddress: resolveServerIpAddress()
+ readonly property var webServerConfiguration: resolveWebServerConfiguration()
+ readonly property string dashboardUrl: {
+ if (root.serverIpAddress === "" || root.webServerConfiguration === null) {
+ return ""
+ }
+
+ var protocol = root.webServerConfiguration.sslEnabled ? "https" : "http"
+ return protocol + "://" + root.serverIpAddress + ":" + root.webServerConfiguration.port + "/evdash"
+ }
+
+ function normalizeAddress(address) {
+ if (!address)
+ return ""
+
+ var normalizedAddress = address.toString().trim()
+ var slashIndex = normalizedAddress.indexOf("/")
+ if (slashIndex >= 0)
+ normalizedAddress = normalizedAddress.slice(0, slashIndex)
+
+ return normalizedAddress
+ }
+
+ function getActiveIpv4Address(networkDevices) {
+ if (!networkDevices) {
+ return ""
+ }
+
+ for (var i = 0; i < networkDevices.count; i++) {
+ var networkDevice = networkDevices.get(i)
+ if (!networkDevice || networkDevice.state !== NetworkDevice.NetworkDeviceStateActivated)
+ continue
+
+ for (var j = 0; j < networkDevice.ipv4Addresses.length; j++) {
+ var address = root.normalizeAddress(networkDevice.ipv4Addresses[j])
+ if (address !== "") {
+ return address
+ }
+ }
+ }
+
+ return ""
+ }
+
+ function resolveServerIpAddress() {
+ var address = root.getActiveIpv4Address(networkManager.wiredNetworkDevices)
+ if (address !== "") {
+ console.log("--> server IP (LAN):", address)
+ return address
+ }
+
+ address = root.getActiveIpv4Address(networkManager.wirelessNetworkDevices)
+ if (address !== "")
+ console.log("--> server IP (WLAN):", address)
+
+ return address
+ }
+
+ function preferredConfiguration(currentConfiguration, candidateConfiguration) {
+ if (currentConfiguration === null)
+ return candidateConfiguration
+
+ // Prefer non-SSL to avoid local self-signed certificate issues.
+ if (currentConfiguration.sslEnabled && !candidateConfiguration.sslEnabled)
+ return candidateConfiguration
+
+ return currentConfiguration
+ }
+
+ function resolveWebServerConfiguration() {
+ if (!evDashManager.engine || !evDashManager.engine.nymeaConfiguration)
+ return null
+
+ var exactMatchConfiguration = null
+ var wildcardConfiguration = null
+
+ for (var i = 0; i < evDashManager.engine.nymeaConfiguration.webServerConfigurations.count; i++) {
+ var configuration = evDashManager.engine.nymeaConfiguration.webServerConfigurations.get(i)
+ console.log("--->", (configuration.sslEnabled ? "https" : "http"), configuration.address, configuration.port)
+
+ if (!configuration || configuration.address === "127.0.0.1")
+ continue
+
+ if (configuration.address === root.serverIpAddress) {
+ exactMatchConfiguration = root.preferredConfiguration(exactMatchConfiguration, configuration)
+ continue
+ }
+
+ if (configuration.address === "0.0.0.0") {
+ wildcardConfiguration = root.preferredConfiguration(wildcardConfiguration, configuration)
+ }
+ }
+
+ return exactMatchConfiguration !== null ? exactMatchConfiguration : wildcardConfiguration
+ }
+
header: NymeaHeader {
text: qsTr("EV Dash")
onBackPressed: pageStack.pop()
@@ -60,11 +150,15 @@ SettingsPageBase {
engine: _engine
}
- Component {
- id: errorDialog
- ErrorDialog {}
+ NetworkManager {
+ id: networkManager
+ engine: _engine
}
+ Component {
+ id: errorDialog
+ ErrorDialog { }
+ }
Component {
id: removeUserPopup
@@ -131,6 +225,77 @@ SettingsPageBase {
}
}
+ SwitchDelegate {
+ text: qsTr("Dashboard enabled")
+ checked: evDashManager.enabled
+ onCheckedChanged: evDashManager.enabled = checked
+ Layout.fillWidth: true
+ }
+
+ Label {
+ Layout.fillWidth: true
+ Layout.margins: Style.margins
+ wrapMode: Text.WordWrap
+ visible: evDashManager.enabled
+ text: qsTr("The dashboard can only be reached from the LAN. If you are using the remote connection, the following link might not work.")
+ }
+
+ Label {
+ Layout.fillWidth: true
+ Layout.margins: Style.margins
+ wrapMode: Text.WordWrap
+ visible: evDashManager.enabled && root.serverIpAddress === ""
+ color: "red"
+ text: qsTr("No active LAN IPv4 address was found in the network settings.")
+ }
+
+ Label {
+ Layout.fillWidth: true
+ Layout.margins: Style.margins
+ wrapMode: Text.WordWrap
+ visible: evDashManager.enabled && root.serverIpAddress !== "" && root.webServerConfiguration === null
+ color: "red"
+ text: qsTr("No reachable web server configuration was found for %1. Please enable the web server on this address or on 0.0.0.0.").arg(root.serverIpAddress)
+ }
+
+ NymeaSwipeDelegate {
+ Layout.fillWidth: true
+ iconName: "qrc:/icons/stock_website.svg"
+ text: qsTr("Open EVDash")
+ subText: root.dashboardUrl
+ prominentSubText: true
+ wrapTexts: false
+ visible: evDashManager.enabled && root.dashboardUrl !== ""
+ progressive: true
+ onClicked: { Qt.openUrlExternally(root.dashboardUrl) }
+ }
+
+ SettingsPageSectionHeader {
+ text: qsTr("Manage users")
+ }
+
+ Repeater {
+ id: usersList
+
+ model: evDashManager.users
+ delegate: NymeaItemDelegate {
+ Layout.fillWidth: true
+ text: model.name
+ iconName: "account"
+ progressive: false
+ additionalItem: ColorIcon {
+ name: "delete"
+ color: Style.foregroundColor
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ onClicked: {
+ var popup = removeUserPopup.createObject(app, {username: model.name});
+ popup.open()
+ }
+ }
+ }
+
Component {
id: addUserPopup
@@ -180,38 +345,4 @@ SettingsPageBase {
}
}
}
-
-
- SwitchDelegate {
- text: qsTr("Dashboard enabled")
- checked: evDashManager.enabled
- onCheckedChanged: evDashManager.enabled = checked
- Layout.fillWidth: true
- }
-
- SettingsPageSectionHeader {
- text: qsTr("Manage users")
- }
-
- Repeater {
- id: usersList
- model: evDashManager.users
-
- delegate: NymeaItemDelegate {
- Layout.fillWidth: true
- text: model.name
- iconName: "account"
- progressive: false
- additionalItem: ColorIcon {
- name: "delete"
- color: Style.foregroundColor
- anchors.verticalCenter: parent.verticalCenter
- }
-
- onClicked: {
- var popup = removeUserPopup.createObject(app, {username: model.name});
- popup.open()
- }
- }
- }
}