diff --git a/.gitignore b/.gitignore
index a892d263..d5b58a47 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,5 +10,7 @@ Thumbs.db
*.pro.user*
+CMakeLists.txt.user
+
packaging/android/nymeaapp.properties
build
diff --git a/.gitmodules b/.gitmodules
index 051dbf83..540bdea7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,11 +1,13 @@
[submodule "QtZeroConf"]
path = QtZeroConf
- url = https://github.com/mzanetti/QtZeroConf.git
+ url = https://github.com/nymea/QtZeroConf.git
+ branch = main
[submodule "nymea-remoteproxy"]
path = nymea-remoteproxy
- url = https://github.com/guh/nymea-remoteproxy.git
+ url = https://github.com/nymea/nymea-remoteproxy.git
+ branch = master
[submodule "android_openssl"]
path = 3rdParty/android/android_openssl
url = https://github.com/KDAB/android_openssl.git
- branch = 1.0.x
+ branch = master
shallow = true
diff --git a/3rdParty/android/android_openssl b/3rdParty/android/android_openssl
index ef412c6e..32ebe304 160000
--- a/3rdParty/android/android_openssl
+++ b/3rdParty/android/android_openssl
@@ -1 +1 @@
-Subproject commit ef412c6ebf131fae29a873d0c5db6c6b9dd494fd
+Subproject commit 32ebe304ff064a9affb699b2185af78e3494f49a
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000..95247236
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,19 @@
+# Repository Guidelines
+
+## Project Structure & Module Organization
+`nymea-app/` holds the QtQuick entry point plus top-level QML, and `libnymea-app/` supplies shared C++ helpers, models, and logging categories. Feature bundles reside in `experiences/`, which should stay self-contained with QML, assets, and translations. Vendored code lives in `3rdParty/` and `QtZeroConf/`. Tests sit inside `tests/testrunner/` (unit) and `tests/integration/` (scenario). Packaging and store metadata are in `packaging/`, `snap/`, `debian/`, and `fastlane/`; edit them only when coordinating a release.
+
+## Build, Test, and Development Commands
+After cloning, run `git submodule update --init --recursive`. Configure with `cmake -S . -B build -DNYMEA_ENABLE_ZEROCONF=ON` and build via `cmake --build build --target nymea-app -j$(nproc)`. Execute the suite with `cmake --build build --target test` or `ctest --test-dir build --output-on-failure`. Qt Creator users can rely on `qmake nymea-app.pro CONFIG+=withtests && make`. Re-run `messages.sh` whenever you touch translations.
+
+## Coding Style & Naming Conventions
+Use Qt’s 4-space indentation, braces on new lines, and PascalCase for types (`DashboardModel`) with lowerCamelCase members (`defaultStyle`). Order includes as Qt, nymea, then local headers, and prefer `NYMEA_LOGGING_CATEGORY` over raw `qDebug`. In QML, match filenames to the exported component, avoid wildcard imports, and keep property names lowerCamelCase.
+
+## Testing Guidelines
+Add Qt Test cases under `tests/testrunner/` following the module path (e.g., `tests/testrunner/dashboard/tst_dashboard.cpp`) and use descriptive names such as `shouldConnectOnValidCredentials`. Integration flows belong to `tests/integration/` and may drive nymead or device simulators. Every functional PR needs at least one automated test plus a screenshot for UI changes. Run `ctest --test-dir build -V` before requesting review and document any skipped cases.
+
+## Commit & Pull Request Guidelines
+Commits should have concise, imperative subjects like “Fix Android packaging target configuration” plus a short body covering motivation, toggles, and tests. Pull requests must describe the issue solved, summarize design choices, link related issues, and attach test evidence (command snippets, screenshots, or APK links). Tag reviewers responsible for touched areas and keep changes scoped to a single feature or bugfix.
+
+## Security & Configuration Tips
+Store secrets in local environment files, never in git. Update `config.h.in` or `config.pri` when adding switches and document the defaults in the PR. Android builds download OpenSSL during configuration, so ensure CI nodes have first-run network access or cache the package internally. Call out any new runtime permissions so reviewers can test them explicitly.
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..0d88e833
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,98 @@
+cmake_minimum_required(VERSION 3.16)
+
+file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" NYMEA_VERSION_LINES)
+list(LENGTH NYMEA_VERSION_LINES NYMEA_VERSION_COUNT)
+if(NOT NYMEA_VERSION_COUNT GREATER_EQUAL 1)
+ message(FATAL_ERROR "version.txt must contain at least the application version")
+endif()
+list(GET NYMEA_VERSION_LINES 0 NYMEA_APP_VERSION)
+if(NOT NYMEA_VERSION_COUNT GREATER_EQUAL 2)
+ set(NYMEA_APP_REVISION "0")
+else()
+ list(GET NYMEA_VERSION_LINES 1 NYMEA_APP_REVISION)
+endif()
+
+project(nymea-app VERSION ${NYMEA_APP_VERSION} LANGUAGES CXX)
+
+if(IOS)
+ enable_language(OBJCXX)
+endif()
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+set(APPLICATION_NAME "nymea-app" CACHE STRING "Application name")
+set(ORGANISATION_NAME "nymea" CACHE STRING "Organisation name")
+
+option(NYMEA_ENABLE_ZEROCONF "Enable ZeroConf support" OFF)
+option(NYMEA_USE_MATERIAL_ICONS "Use the Material icon set instead of Suru" OFF)
+option(NYMEA_ENABLE_FIREBASE "Enable Firebase Cloud Messaging integration" ON)
+set(NYMEA_OVERLAY_PATH "" CACHE PATH "Optional overlay directory for branding")
+
+find_package(Qt6 REQUIRED COMPONENTS
+ Core
+ Gui
+ Network
+ Qml
+ Quick
+ QuickControls2
+ Svg
+ WebSockets
+ Bluetooth
+ Charts
+ Nfc
+)
+
+find_package(OpenSSL QUIET)
+
+if(ANDROID)
+ include(FetchContent)
+ FetchContent_Declare(
+ android_openssl
+ DOWNLOAD_EXTRACT_TIMESTAMP true
+ URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip
+ )
+ FetchContent_MakeAvailable(android_openssl)
+ include(${android_openssl_SOURCE_DIR}/android_openssl.cmake)
+
+ set(NYMEA_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_SOURCE_DIR}/packaging/android" CACHE PATH "Android packaging directory")
+
+ set(_nymea_app_root_property "nymeaAppRoot=${CMAKE_SOURCE_DIR}")
+ if(NYMEA_ENABLE_FIREBASE)
+ set(_nymea_firebase_property "useFirebase=true")
+ else()
+ set(_nymea_firebase_property "useFirebase=false")
+ endif()
+
+ file(WRITE "${NYMEA_ANDROID_PACKAGE_SOURCE_DIR}/nymeaapp.properties" "${_nymea_app_root_property}\n${_nymea_firebase_property}\n")
+ configure_file(
+ "${CMAKE_SOURCE_DIR}/version.txt"
+ "${NYMEA_ANDROID_PACKAGE_SOURCE_DIR}/version.txt"
+ COPYONLY
+ )
+
+ add_link_options("-Wl,-z,max-page-size=16384")
+endif()
+
+# Make config.h available to all targets
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_BINARY_DIR}/config.h @ONLY)
+
+# Common warning flags
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ add_compile_options(-Wall)
+ if(UNIX AND NOT APPLE)
+ add_compile_options(-Wno-deprecated-declarations -Wno-deprecated-copy)
+ endif()
+endif()
+
+set(APP_VERSION ${NYMEA_APP_VERSION})
+set(APP_REVISION ${NYMEA_APP_REVISION})
+
+add_subdirectory(libnymea-app)
+add_subdirectory(experiences)
+add_subdirectory(nymea-app)
diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user
new file mode 100644
index 00000000..a7dea20a
--- /dev/null
+++ b/CMakeLists.txt.user
@@ -0,0 +1,701 @@
+
+
+
+
+
+ EnvironmentId
+ {3a02a921-eea1-43cd-a37d-2b4e59d6151d}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ true
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 0
+ 80
+ true
+ true
+ 1
+ 0
+ false
+ true
+ false
+ 2
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+ false
+
+
+ 0
+ true
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 10
+ true
+
+
+
+ true
+
+ 0
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Android.Device.Type
+ true
+ Android Qt 6.8.4 Clang armeabi-v7a
+ Android Qt 6.8.4 Clang armeabi-v7a
+ {4ea481fa-d782-4c19-8a79-381a58bbab97}
+ 0
+ 0
+ 0
+
+ Debug
+ 2
+ false
+
+ -DQT_HOST_PATH:PATH=%{Qt:QT_HOST_PREFIX}
+-DANDROID_PLATFORM:STRING=android-23
+-DANDROID_SDK_ROOT:PATH=/usr/local/android
+-DQT_USE_TARGET_ANDROID_BUILD_DIR:BOOL=ON
+-DANDROID_USE_LEGACY_TOOLCHAIN_FILE:BOOL=OFF
+-DCMAKE_BUILD_TYPE:STRING=Debug
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_NO_GLOBAL_APK_TARGET_PART_OF_ALL:BOOL=ON
+-DANDROID_ABI:STRING=armeabi-v7a
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DQT_MAINTENANCE_TOOL:FILEPATH=/home/timon/Qt/MaintenanceTool
+-DANDROID_NDK:PATH=/usr/local/android/ndk/26.1.10909125
+-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_FIND_ROOT_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DANDROID_STL:STRING=c++_shared
+-DCMAKE_TOOLCHAIN_FILE:FILEPATH=/usr/local/android/ndk/26.1.10909125/build/cmake/android.toolchain.cmake
+ 0
+ /home/timon/nymea/development/qt6-cmake/nymea-app/build/Android_Qt_6_8_4_Clang_armeabi_v7a-Debug
+
+
+
+
+ all
+
+ false
+
+ true
+ Build
+ CMakeProjectManager.MakeStep
+
+
+ android-36
+
+
+ true
+ Build Android APK
+ QmakeProjectManager.AndroidBuildApkStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ Build
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ CMakeProjectManager.CMakeBuildConfiguration
+ 0
+ 0
+
+
+
+ true
+ Qt4ProjectManager.AndroidDeployQtStep
+
+ 1
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ Qt4ProjectManager.AndroidDeployConfiguration2
+
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 2
+
+ true
+
+ arm64-v8a
+ armeabi-v7a
+ armeabi
+
+ 0A301JEC211655
+ 33
+
+ true
+
+
+ true
+ true
+ 0
+ true
+
+
+
+
+
+
+
+ 0
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+ nymea-app
+ Qt4ProjectManager.AndroidRunConfiguration:
+ nymea-app
+ true
+
+ true
+ true
+
+ 1
+
+ 1
+
+
+
+ true
+ Qt4ProjectManager.AndroidDeployQtStep
+
+ 1
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ Qt4ProjectManager.AndroidDeployConfiguration2
+
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 2
+
+ true
+ true
+ 0
+ true
+
+
+
+
+
+
+
+ 0
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+ nymea-app
+ Qt4ProjectManager.AndroidRunConfiguration:
+ nymea-app
+ true
+
+ true
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.Target.1
+
+ Desktop
+ true
+ Desktop Qt 6.8.4
+ Desktop Qt 6.8.4
+ qt.qt6.684.linux_gcc_64_kit
+ 0
+ 0
+ 0
+
+ Debug
+ 2
+ false
+
+ -DCMAKE_BUILD_TYPE:STRING=Debug
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DQT_MAINTENANCE_TOOL:FILEPATH=/home/timon/Qt/MaintenanceTool
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+ 0
+ /home/timon/nymea/development/qt6-cmake/nymea-app/build/Desktop_Qt_6_8_4-Debug
+
+
+
+
+ all
+
+ false
+
+ true
+ Build
+ CMakeProjectManager.MakeStep
+
+ 1
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ Build
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ CMakeProjectManager.CMakeBuildConfiguration
+ 0
+ 0
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+
+
+
+
+
+
+
+ false
+
+ true
+ ApplicationManagerPlugin.Deploy.CMakePackageStep
+
+
+ install-package --acknowledge
+ true
+ Install Application Manager package
+ ApplicationManagerPlugin.Deploy.InstallPackageStep
+
+
+
+
+
+
+
+ 2
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ApplicationManagerPlugin.Deploy.Configuration
+
+ 2
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+ nymea-app
+ CMakeProjectManager.CMakeRunConfiguration.
+ nymea-app
+ true
+
+ true
+ true
+ true
+ false
+
+ 1
+
+ 1
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+
+
+
+
+
+
+
+ false
+
+ true
+ ApplicationManagerPlugin.Deploy.CMakePackageStep
+
+
+ install-package --acknowledge
+ true
+ Install Application Manager package
+ ApplicationManagerPlugin.Deploy.InstallPackageStep
+
+
+
+
+
+
+
+ 2
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ApplicationManagerPlugin.Deploy.Configuration
+
+ 2
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+ nymea-app
+ CMakeProjectManager.CMakeRunConfiguration.
+ nymea-app
+ true
+
+ true
+ true
+ true
+ false
+
+ 1
+
+
+
+ ProjectExplorer.Project.Target.2
+
+ Android.Device.Type
+ true
+ Android Qt 6.8.4 Clang armeabi-v7a
+ Android Qt 6.8.4 Clang armeabi-v7a
+ {d6a68c9e-38a8-48ba-9f70-7050ff8c051f}
+ 0
+ 0
+ 0
+
+ Debug
+ 2
+ false
+
+ -DANDROID_STL:STRING=c++_shared
+-DQT_NO_GLOBAL_APK_TARGET_PART_OF_ALL:BOOL=ON
+-DQT_HOST_PATH:PATH=%{Qt:QT_HOST_PREFIX}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DANDROID_ABI:STRING=armeabi-v7a
+-DCMAKE_BUILD_TYPE:STRING=Debug
+-DANDROID_NDK:PATH=/usr/local/android/ndk/29.0.14033849
+-DQT_USE_TARGET_ANDROID_BUILD_DIR:BOOL=ON
+-DANDROID_USE_LEGACY_TOOLCHAIN_FILE:BOOL=OFF
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_FIND_ROOT_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DANDROID_SDK_ROOT:PATH=/usr/local/android
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DANDROID_PLATFORM:STRING=android-23
+-DQT_MAINTENANCE_TOOL:FILEPATH=/home/timon/Qt/MaintenanceTool
+-DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_TOOLCHAIN_FILE:FILEPATH=/usr/local/android/ndk/29.0.14033849/build/cmake/android.toolchain.cmake
+-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+ 0
+ /home/timon/nymea/development/qt6-cmake/nymea-app/build/Android_Qt_6_8_4_Clang_armeabi_v7a-Debug
+
+
+
+
+ all
+
+ false
+
+ true
+ Build
+ CMakeProjectManager.MakeStep
+
+
+ android-36
+
+
+ true
+ Build Android APK
+ QmakeProjectManager.AndroidBuildApkStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ Build
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ CMakeProjectManager.CMakeBuildConfiguration
+ 0
+ 0
+
+
+
+ true
+ Qt4ProjectManager.AndroidDeployQtStep
+
+ 1
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ Qt4ProjectManager.AndroidDeployConfiguration2
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+
+
+
+
+
+
+ 0
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+ nymea-app
+ Qt4ProjectManager.AndroidRunConfiguration:
+ nymea-app
+ false
+ true
+ true
+
+ 1
+
+ 1
+
+
+
+ true
+ Qt4ProjectManager.AndroidDeployQtStep
+
+ 1
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ Qt4ProjectManager.AndroidDeployConfiguration2
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+
+
+
+
+
+
+ 0
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+ nymea-app
+ Qt4ProjectManager.AndroidRunConfiguration:
+ nymea-app
+ false
+ true
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 3
+
+
+ Version
+ 22
+
+
diff --git a/QtZeroConf b/QtZeroConf
index 2b9b3c7c..a6c8302b 160000
--- a/QtZeroConf
+++ b/QtZeroConf
@@ -1 +1 @@
-Subproject commit 2b9b3c7c74f05e83c4052fbb1629b22568f36b64
+Subproject commit a6c8302b3accf6be2ecb7c40ec69d1707a2c5765
diff --git a/README.md b/README.md
index b09f8880..48c05123 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ QtQuick nymea client application
# building
Required packages:
-It is recommended to install a complete Qt installation. Minimum required Qt Version *5.7.0*.
+It is recommended to install a complete Qt installation. Minimum required Qt version is Qt 6.
No extra modules are required for a basic desktop build.
@@ -14,14 +14,19 @@ After cloning the repository, run
$ git submodule init
$ git submodule update
-To build a binary run
+To build a binary with CMake run
- $ mkdir builddir
- $ cd builddir
- $ qmake path/to/source/dir
- $ make
+ $ cmake -S . -B build
+ $ cmake --build build
-Or open `nymea-app.pro` in QtCreator and click the **"Play"** button.
+The build can be customised with the following cache variables:
+
+- `-DNYMEA_ENABLE_ZEROCONF=ON` enables ZeroConf support when the QtZeroConf and
+ Avahi dependencies are available.
+- `-DNYMEA_USE_MATERIAL_ICONS=ON` switches the icon theme to the Material icon set.
+
+Legacy qmake builds are still available by opening `nymea-app.pro` in QtCreator
+and building the project there.
Optional configuration flags to be passed to qmake:
@@ -30,8 +35,13 @@ Optional configuration flags to be passed to qmake:
> Enables building the testrunner target
## Android
-As Qt can't bundle a build of openssl for android, you need to place a copy to
-`/opt/android-ssl/`
+When targeting Android, the build will download the KDAB
+[`android_openssl`](https://github.com/KDAB/android_openssl) package at
+configure time and automatically bundle the provided `libssl` and `libcrypto`
+shared libraries inside the APK. An active internet connection is therefore
+required the first time you configure an Android build directory. Other
+platforms will build without explicitly linking to OpenSSL if the development
+package is not installed.
## Windows
diff --git a/androidservice/androidservice.pro b/androidservice/androidservice.pro
deleted file mode 100644
index 7503e717..00000000
--- a/androidservice/androidservice.pro
+++ /dev/null
@@ -1,56 +0,0 @@
-TEMPLATE = lib
-TARGET = service
-CONFIG += dll
-QT += core androidextras
-QT += network qml quick quickcontrols2 svg websockets bluetooth charts nfc
-
-include(../shared.pri)
-include(../3rdParty/android/android_openssl/openssl.pri)
-
-
-INCLUDEPATH += $$top_srcdir/libnymea-app/
-
-# https://bugreports.qt.io/browse/QTBUG-83165
-LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
-
-LIBS += -L$$top_builddir/libnymea-app/ -lnymea-app
-PRE_TARGETDEPS += ../libnymea-app
-
-RESOURCES += controlviews/controlviews.qrc \
- ../nymea-app/resources.qrc \
- ../nymea-app/images.qrc \
- ../nymea-app/styles.qrc
-
-INCLUDEPATH += ../nymea-app/
-
-SOURCES += \
- controlviews/devicecontrolapplication.cpp \
- nymeaappservice/nymeaappservice.cpp \
- nymeaappservice/androidbinder.cpp \
- ../nymea-app/stylecontroller.cpp \
- ../nymea-app/platformhelper.cpp \
- ../nymea-app/nfchelper.cpp \
- ../nymea-app/nfcthingactionwriter.cpp \
- ../nymea-app/platformintegration/android/platformhelperandroid.cpp \
- service_main.cpp
-
-HEADERS += \
- controlviews/devicecontrolapplication.h \
- nymeaappservice/nymeaappservice.h \
- nymeaappservice/androidbinder.h \
- ../nymea-app/stylecontroller.h \
- ../nymea-app/platformhelper.h \
- ../nymea-app/nfchelper.h \
- ../nymea-app/nfcthingactionwriter.h \
- ../nymea-app/platformintegration/android/platformhelperandroid.h \
-
-DISTFILES += \
- java/io/guh/nymeaapp/Action.java \
- java/io/guh/nymeaapp/NymeaAppControlService.java \
- java/io/guh/nymeaapp/NymeaAppService.java \
- java/io/guh/nymeaapp/NymeaAppControlsActivity.java \
- java/io/guh/nymeaapp/NymeaAppServiceConnection.java \
- java/io/guh/nymeaapp/Thing.java \
- java/io/guh/nymeaapp/State.java \
- java/io/guh/nymeaapp/NymeaHost.java \
- controlviews/Main.qml
diff --git a/androidservice/controlviews/Main.qml b/androidservice/controlviews/Main.qml
deleted file mode 100644
index 68a355c2..00000000
--- a/androidservice/controlviews/Main.qml
+++ /dev/null
@@ -1,66 +0,0 @@
-import QtQuick 2.8
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.1
-import QtQuick.Layouts 1.2
-import Qt.labs.settings 1.0
-import Nymea 1.0
-import "qrc:/ui/devicepages/"
-
-ApplicationWindow {
- id: app
- visible: true
- visibility: ApplicationWindow.FullScreen
- color: Material.background
- title: Configuration.appName
-
- Material.theme: NymeaUtils.isDark(Style.backgroundColor) ? Material.Dark : Material.Light
- Material.background: Style.backgroundColor
- Material.accent: Style.accentColor
- Material.foreground: Style.foregroundColor
-
- font.pixelSize: mediumFont
- font.weight: Font.Normal
- font.capitalization: Font.MixedCase
- font.family: Style.fontFamily
-
- property int margins: 16
- property int bigMargins: 20
-
- property int extraSmallFont: 10
- property int smallFont: 13
- property int mediumFont: 16
- property int largeFont: 20
-
- property int smallIconSize: 16
- property int iconSize: 24
- property int bigIconSize: 40
- property int hugeIconSize: 64
-
- property int delegateHeight: 60
-
- readonly property bool landscape: app.width > app.height
-
- ThingsProxy {
- id: thingProxy
- engine: _engine
- filterThingId: controlledThingId
- }
-
- property Thing controlledThing: engine.thingManager.fetchingData ? null : engine.thingManager.things.getThing(controlledThingId)
-
- onControlledThingChanged: {
- loader.setSource("qrc:/ui/devicepages/" + NymeaUtils.interfaceListToDevicePage(controlledThing.thingClass.interfaces), {thing: controlledThing, header: null})
- PlatformHelper.hideSplashScreen();
- }
-
- Loader {
- id: loader
- anchors.fill: parent
- anchors.bottomMargin: app.margins // For some reason the bottom edge seems a bit off in the overlay
- }
-
- onClosing: {
- print("************* Control View closing")
- }
-
-}
diff --git a/androidservice/controlviews/controlviews.qrc b/androidservice/controlviews/controlviews.qrc
deleted file mode 100644
index f907b18e..00000000
--- a/androidservice/controlviews/controlviews.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- Main.qml
-
-
diff --git a/androidservice/controlviews/devicecontrolapplication.cpp b/androidservice/controlviews/devicecontrolapplication.cpp
deleted file mode 100644
index 67d16dfd..00000000
--- a/androidservice/controlviews/devicecontrolapplication.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-#include "devicecontrolapplication.h"
-
-#include "engine.h"
-#include "connection/discovery/nymeadiscovery.h"
-#include "connection/nymeahosts.h"
-#include "libnymea-app-core.h"
-#include "../nymea-app/stylecontroller.h"
-#include "../nymea-app/platformhelper.h"
-#include "../nymea-app/nfchelper.h"
-#include "../nymea-app/nfcthingactionwriter.h"
-#include "../nymea-app/platformintegration/android/platformhelperandroid.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
-{
- Q_UNUSED(engine)
- Q_UNUSED(scriptEngine)
- return new PlatformHelperAndroid();
-}
-
-DeviceControlApplication::DeviceControlApplication(int argc, char *argv[]) : QApplication(argc, argv)
-{
- setApplicationName("nymea-app");
- setOrganizationName("nymea");
-
- QSettings settings;
-
- m_discovery = new NymeaDiscovery(this);
-
- m_engine = new Engine(this);
-
- m_qmlEngine = new QQmlApplicationEngine(this);
-
- Nymea::Core::registerQmlTypes();
-
- qmlRegisterSingletonType("Nymea", 1, 0, "PlatformHelper", platformHelperProvider);
- qmlRegisterSingletonType(QUrl("qrc:///ui/utils/NymeaUtils.qml"), "Nymea", 1, 0, "NymeaUtils" );
- qmlRegisterType("Nymea", 1, 0, "NfcThingActionWriter");
- qmlRegisterSingletonType("Nymea", 1, 0, "NfcHelper", NfcHelper::nfcHelperProvider);
-
- StyleController *styleController = new StyleController("light", this);
-
- QQmlFileSelector *styleSelector = new QQmlFileSelector(m_qmlEngine);
- styleSelector->setExtraSelectors({styleController->currentStyle()});
-
- foreach (const QFileInfo &fi, QDir(":/ui/fonts/").entryInfoList()) {
- QFontDatabase::addApplicationFont(fi.absoluteFilePath());
- }
- foreach (const QFileInfo &fi, QDir(":/styles/" + styleController->currentStyle() + "/fonts/").entryInfoList()) {
- qDebug() << "Adding style font:" << fi.absoluteFilePath();
- QFontDatabase::addApplicationFont(fi.absoluteFilePath());
- }
-
- qmlRegisterSingletonType(QUrl("qrc:///styles/" + styleController->currentStyle() + "/Style.qml"), "Nymea", 1, 0, "Style" );
-
- m_qmlEngine->rootContext()->setContextProperty("styleController", styleController);
- m_qmlEngine->rootContext()->setContextProperty("engine", m_engine);
- m_qmlEngine->rootContext()->setContextProperty("_engine", m_engine);
- m_qmlEngine->rootContext()->setContextProperty("controlledThingId", ""); // Unknown at this point
-
- m_qmlEngine->load(QUrl(QLatin1String("qrc:/Main.qml")));
-
- jboolean startedByNfc = QtAndroid::androidActivity().callMethod("startedByNfc", "()Z");
- if (startedByNfc) {
- qDebug() << "**** Started by NFC";
- qDebug() << "Registering NFC handler and waiting for message.";
-
- QNearFieldManager *manager = new QNearFieldManager(this);
- manager->registerNdefMessageHandler(this, SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget*)));
-
- } else {
- qDebug() << "*** Started by other intent";
- qDebug() << "Expecing nymeaId and thingId in intent extras.";
- QString nymeaId = QtAndroid::androidActivity().callObjectMethod("nymeaId").toString();
- QString thingId = QtAndroid::androidActivity().callObjectMethod("thingId").toString();
-
- connectToNymea(nymeaId);
- m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
- }
-}
-
-void DeviceControlApplication::handleNdefMessage(QNdefMessage message, QNearFieldTarget *target)
-{
- Q_UNUSED(target)
- qDebug() << "************* NFC message!" << message.toByteArray();
- if (message.count() < 1) {
- qWarning() << "NFC message doesn't contain any records...";
- return;
- }
- // NOTE: At this point we're only supporting one NDEF record per message
- QNdefRecord record = message.first();
- QNdefNfcUriRecord uriRecord(record);
-
- QUrl url = uriRecord.uri();
- if (url.scheme() != "nymea") {
- qWarning() << "NDEF URI record scheme is not \"nymea://\"";
- return;
- }
-
- QUuid nymeaId = QUuid(url.host());
- if (nymeaId.isNull()) {
- qWarning() << "Invalid nymea UUID in NDEF record.";
- return;
- }
-
- QUuid thingId = QUuid(QUrlQuery(url).queryItemValue("t"));
- if (thingId.isNull()) {
- qWarning() << "Invalid thing in NDEF record";
- return;
- }
-
- m_pendingNfcAction = url;
-
- connectToNymea(nymeaId);
- m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
-
- connect(m_engine->thingManager(), &ThingManager::fetchingDataChanged, [this](){
- if (m_engine->jsonRpcClient()->connected() && !m_engine->thingManager()->fetchingData()) {
- qDebug() << "Ready to process commands";
- runNfcAction();
- }
- });
-}
-
-void DeviceControlApplication::connectToNymea(const QUuid &nymeaId)
-{
- NymeaHost *host = m_discovery->nymeaHosts()->find(nymeaId);
- if (!host) {
- qWarning() << "No such nymea host:" << nymeaId;
- // TODO: We could wait here until the discovery finds it... But it really should be cached already...
- exit(1);
- }
- qDebug() << "Connecting to:" << host->name();
- m_engine->jsonRpcClient()->connectToHost(host);
-}
-
-void DeviceControlApplication::runNfcAction()
-{
- if (!m_pendingNfcAction.isEmpty()) {
- qDebug() << "NFC action:" << m_pendingNfcAction;
- }
- QUrl url = m_pendingNfcAction;
- m_pendingNfcAction.clear();
-
- if (url.scheme() != "nymea") {
- qWarning() << "NDEF URI record scheme is not \"nymea://\" in" << url.toString();
- return;
- }
-
- QUuid nymeaId = QUuid(url.host());
- if (nymeaId.isNull()) {
- qWarning() << "Invalid nymea UUID" << url.host() << "in NDEF record" << url.toString();
- return;
- }
-
- QUuid thingId = QUuid(QUrlQuery(url).queryItemValue("t"));
- Thing *thing = m_engine->thingManager()->things()->getThing(thingId);
- if (!thing) {
- qDebug() << "Thing" << thingId.toString() << "from" << url.toString() << "doesn't exist on nymea host" << nymeaId.toString();
- return;
- }
-
- QList> queryItems = QUrlQuery(url.query()).queryItems();
- for (int i = 0; i < queryItems.count(); i++) {
- QString entryName = queryItems.at(i).first;
- if (entryName == "t") {
- continue;
- }
- if (!entryName.startsWith("a")) {
- qDebug() << "Only actions are supported. Skipping query item" << entryName;
- continue;
- }
-
- QString actionString = queryItems.at(i).second;
- QStringList parts = actionString.split("#");
- if (parts.count() == 0) {
- qDebug() << "Invalid action definition:" << actionString;
- continue;
- }
-
- if (parts.count() > 2) {
- // The parameters might contain a #, let's merge them again
- parts[1] = parts.mid(1).join('#');
- }
-
- QString actionTypeName = parts.at(0);
- ActionType *actionType = thing->thingClass()->actionTypes()->findByName(actionTypeName);
- if (!actionType) {
- qWarning() << "Invalid action name" << actionType << "in url:" << url.toString();
- continue;
- }
-
- QHash paramsInUri;
- if (parts.count() > 1) {
- QString paramsString = parts.at(1);
- foreach (const QString ¶mString, paramsString.split("+")) {
- QStringList parts = paramString.split(":");
- if (parts.count() != 2) {
- qWarning() << "Invalid param format" << paramString << "in url:" << url.toString();
- continue;
- }
- paramsInUri.insert(parts.at(0), parts.at(1));
- }
- }
-
- qDebug() << "Parameters in NFC uri:" << paramsInUri;
-
- QVariantList params;
- for (int j = 0; j < actionType->paramTypes()->rowCount(); j++) {
- ParamType *paramType = actionType->paramTypes()->get(j);
- QVariantMap param;
- param.insert("paramTypeId", paramType->id());
- if (paramsInUri.contains(paramType->name())) {
- param.insert("value", paramsInUri.value(paramType->name()));
- } else {
- param.insert("value", paramType->defaultValue());
- }
- params.append(param);
- }
-
- qDebug() << "Action parameters:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
-
- m_engine->thingManager()->executeAction(thingId, actionType->id(), params);
- }
-}
-
-
diff --git a/androidservice/controlviews/devicecontrolapplication.h b/androidservice/controlviews/devicecontrolapplication.h
deleted file mode 100644
index edd6985c..00000000
--- a/androidservice/controlviews/devicecontrolapplication.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef DEVICECONTROLAPPLICATION_H
-#define DEVICECONTROLAPPLICATION_H
-
-#include
-#include
-#include
-#include
-#include
-
-#include "types/ruleactions.h"
-#include "connection/discovery/nymeadiscovery.h"
-#include "engine.h"
-
-class DeviceControlApplication : public QApplication
-{
- Q_OBJECT
-public:
- explicit DeviceControlApplication(int argc, char *argv[]);
-
-private slots:
- void handleNdefMessage(QNdefMessage message,QNearFieldTarget* target);
-
- void connectToNymea(const QUuid &nymeaId);
-
- void runNfcAction();
-
-private:
- NymeaDiscovery *m_discovery = nullptr;
- Engine *m_engine = nullptr;
- QQmlApplicationEngine *m_qmlEngine = nullptr;
-
- QUrl m_pendingNfcAction;
-
-
-};
-
-#endif // DEVICECONTROLAPPLICATION_H
diff --git a/androidservice/java/io/guh/nymeaapp/Action.java b/androidservice/java/io/guh/nymeaapp/Action.java
deleted file mode 100644
index 04923f02..00000000
--- a/androidservice/java/io/guh/nymeaapp/Action.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.guh.nymeaapp;
-
-import java.util.UUID;
-
-public class Action {
- public UUID typeId;
- public String name;
- public String displayName;
-}
diff --git a/androidservice/java/io/guh/nymeaapp/NymeaAppControlService.java b/androidservice/java/io/guh/nymeaapp/NymeaAppControlService.java
deleted file mode 100644
index 8d3a7e0d..00000000
--- a/androidservice/java/io/guh/nymeaapp/NymeaAppControlService.java
+++ /dev/null
@@ -1,289 +0,0 @@
-package io.guh.nymeaapp;
-
-import android.util.Log;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.ComponentName;
-import android.app.PendingIntent;
-import android.net.Uri;
-import android.content.Context;
-import android.service.controls.ControlsProviderService;
-import android.service.controls.actions.*;
-import android.service.controls.Control;
-import android.service.controls.DeviceTypes;
-import android.service.controls.templates.*;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-
-import java.util.concurrent.Flow.Publisher;
-import java.util.function.Consumer;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.UUID;
-import java.util.HashMap;
-import io.reactivex.Flowable;
-import io.reactivex.processors.ReplayProcessor;
-import org.reactivestreams.FlowAdapters;
-import org.json.*;
-
-// Android device controls service
-
-// This service is instantiated by the android device controls on demand. It will
-// connect to the NymeaAppService and interact with nymea through that.
-
-public class NymeaAppControlService extends ControlsProviderService {
- private String TAG = "nymea-app: NymeaAppControlService";
- private NymeaAppServiceConnection m_serviceConnection;
-
- // For publishing all available
- private ReplayProcessor m_publisherForAll;
- private ArrayList m_pendingForAll = new ArrayList(); // pending nymea ids to query
-
- private ReplayProcessor m_updatePublisher;
- private List m_activeControlIds;
-
-
- private void ensureServiceConnection() {
- if (m_serviceConnection == null) {
- m_serviceConnection = new NymeaAppServiceConnection(getBaseContext()) {
- @Override public void onConnectedChanged(boolean connected) {
- Log.d(TAG, "Connected to NymeaAppService. Known hosts: " + m_serviceConnection.getHosts().size());
- if (connected && m_publisherForAll != null) {
- Log.d(TAG, "Processing all");
- processAll();
- }
- }
- @Override public void onReadyChanged(UUID nymeaId, boolean ready) {
- Log.d(TAG, "Nymea instance " + nymeaId.toString() + " ready state changed: " + Boolean.toString(ready));
- if (ready) {
- process(nymeaId);
- }
- }
- @Override public void onUpdate(UUID nymeaId, UUID thingId) {
- if (m_updatePublisher != null && m_activeControlIds.contains(thingId.toString())) {
-// Log.d(TAG, "Updating publisher for thing: " + thingId);
- m_updatePublisher.onNext(thingToControl(nymeaId, thingId));
-// m_updatePublisher.onComplete();
- }
- }
- };
- }
- Intent serviceIntent = new Intent(this, NymeaAppService.class);
- bindService(serviceIntent, m_serviceConnection, Context.BIND_AUTO_CREATE);
- }
-
- private void processAll() {
- ensureServiceConnection();
- if (m_serviceConnection.connected()) {
- // Need to add all the pending before processing
- if (m_publisherForAll != null) {
- for (UUID nymeaId: m_serviceConnection.getHosts().keySet()) {
- m_pendingForAll.add(nymeaId);
- }
- }
- for (UUID nymeaId: m_serviceConnection.getHosts().keySet()) {
- if (m_serviceConnection.getHosts().get(nymeaId).isReady) {
- process(nymeaId);
- }
- }
- } else {
- Log.d(TAG, "Not connected to NymeaAppService yet...");
- }
- }
-
- private void process(UUID nymeaId) {
- Log.d(TAG, "Processing...");
- ensureServiceConnection();
- if (!m_serviceConnection.connected()) {
- Log.d(TAG, "NymeaAppService not connected to nymea instance " + nymeaId + " yet.");
- return;
- }
- if (!m_serviceConnection.getHosts().keySet().contains(nymeaId)) {
- Log.d(TAG, "Service connection is not ready yet...");
- return;
- }
-
- for (Thing thing : m_serviceConnection.getHosts().get(nymeaId).things.values()) {
- Log.d(TAG, "Processing thing: " + thing.name);
-
- if (m_publisherForAll != null) {
- Log.d(TAG, "Adding stateless");
- m_publisherForAll.onNext(thingToControl(nymeaId, thing.id));
- }
-
- if (m_updatePublisher != null) {
- if (m_activeControlIds.contains(thing.id.toString())) {
- Log.d(TAG, "Adding stateful");
- m_updatePublisher.onNext(thingToControl(nymeaId, thing.id));
- }
- }
- }
-
- if (m_pendingForAll.contains(nymeaId)) {
- m_pendingForAll.remove(nymeaId);
- }
-
- // The publisher for all needs to be completed when done
- if (m_publisherForAll != null && m_pendingForAll.isEmpty()) {
- Log.d(TAG, "Completing all publisher");
- m_publisherForAll.onComplete();
- }
-
- Log.d(TAG, "Done processing");
- // We never close the update publisher as we need that one to send updates
- }
-
-
- @Override
- public Publisher createPublisherForAllAvailable() {
- Log.d(TAG, "Creating publishers for all");
- m_publisherForAll = ReplayProcessor.create();
- processAll();
- return FlowAdapters.toFlowPublisher(m_publisherForAll);
- }
-
- @Override
- public Publisher createPublisherFor(List controlIds) {
- Log.d(TAG, "Creating publishers for " + Integer.toString(controlIds.size()));
- m_updatePublisher = ReplayProcessor.create();
- m_activeControlIds = controlIds;
- processAll();
- return FlowAdapters.toFlowPublisher(m_updatePublisher);
- }
-
- @Override
- public void performControlAction(String controlId, ControlAction action, Consumer consumer) {
- Log.d(TAG, "Performing control action: " + controlId);
-
- UUID nymeaId = m_serviceConnection.hostForThing(UUID.fromString(controlId));
- if (nymeaId == null) {
- Log.d(TAG, "Nymea host not found for thing id: " + controlId);
- consumer.accept(ControlAction.RESPONSE_FAIL);
- return;
- }
- Thing thing = m_serviceConnection.getThing(UUID.fromString(controlId));
- if (thing == null) {
- Log.d(TAG, "Thing not found for id: " + controlId);
- consumer.accept(ControlAction.RESPONSE_FAIL);
- return;
- }
-
- UUID actionTypeId;
- String param;
- if (thing.interfaces.contains("dimmablelight") && action instanceof FloatAction) {
- actionTypeId = thing.stateByName("brightness").typeId;
- FloatAction fAction = (FloatAction) action;
- param = String.valueOf(Math.round(fAction.getNewValue()));
- } else if (thing.interfaces.contains("power") && action instanceof BooleanAction) {
- actionTypeId = thing.stateByName("power").typeId;
- BooleanAction bAction = (BooleanAction) action;
- param = bAction.getNewState() == true ? "true" : "false";
- } else if (thing.interfaces.contains("closable") && action instanceof BooleanAction) {
- BooleanAction bAction = (BooleanAction) action;
- if (bAction.getNewState()) {
- Log.d(TAG, "executing open");
- actionTypeId = thing.actionByName("open").typeId;
- } else {
- Log.d(TAG, "executing close");
- actionTypeId = thing.actionByName("close").typeId;
- }
- param = "";
- } else if (thing.interfaces.contains("volumecontroller") && thing.stateByName("volume") != null) {
- actionTypeId = thing.stateByName("volume").typeId;
- FloatAction fAction = (FloatAction) action;
- param = String.valueOf(Math.round(fAction.getNewValue()));
- } else {
- Log.d(TAG, "Unhandled action for: " + thing.name);
- consumer.accept(ControlAction.RESPONSE_FAIL);
- return;
- }
-
- m_serviceConnection.executeAction(nymeaId, thing.id, actionTypeId, param);
- consumer.accept(ControlAction.RESPONSE_OK);
-
- }
-
- private HashMap m_intents = new HashMap();
-
- private Control thingToControl(UUID nymeaId, UUID thingId) {
-// Log.d(TAG, "Creating control for thing: " + thing.name + " id: " + thing.id);
-
- NymeaHost nymeaHost = m_serviceConnection.getHosts().get(nymeaId);
- Thing thing = nymeaHost.things.get(thingId);
-
- // NOTE: intentId 1 doesn't work for some reason I don't understand yet...
- // so let's make sure we never add "1" to it by always added 100
- int intentId = m_intents.size() + 100;
- PendingIntent pi;
- if (m_intents.containsKey(thing.id)) {
- intentId = m_intents.get(thing.id);
- } else {
- m_intents.put(thing.id, intentId);
- }
-
- Context context = getBaseContext();
- Intent intent = new Intent(context, NymeaAppControlsActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- intent.putExtra("nymeaId", nymeaId.toString());
- intent.putExtra("thingId", thing.id.toString());
- pi = PendingIntent.getActivity(context, intentId, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- Log.d(TAG, "Created pendingintent for " + thing.name + " with id " + intentId + " and extra " + thing.id);
-
- Control.StatefulBuilder builder = new Control.StatefulBuilder(thing.id.toString(), pi)
- .setTitle(thing.name)
- .setSubtitle(thing.className)
- .setStructure(nymeaHost.name);
-
- if (thing.interfaces.contains("impulsebasedgaragedoor")) {
- builder.setDeviceType(DeviceTypes.TYPE_GARAGE);
- builder.setControlTemplate(new StatelessTemplate(thing.id.toString()));
- } else if (thing.interfaces.contains("statefulgaragedoor")) {
- builder.setDeviceType(DeviceTypes.TYPE_GARAGE);
- State stateState = thing.stateByName("state");
- ControlButton controlButton = new ControlButton(stateState.value.equals("open"), stateState.displayName);
- builder.setControlTemplate(new ToggleTemplate(thing.id.toString(), controlButton));
-
-// } else if (thing.interfaces.contains("extendedstatefulgaragedoor")) {
-// builder.setDeviceTyoe(DeviceTypes.TYPE_GARAGE);
-
- } else if (thing.interfaces.contains("light")) {
- builder.setDeviceType(DeviceTypes.TYPE_LIGHT);
- State powerState = thing.stateByName("power");
- ControlButton controlButton = new ControlButton(powerState.value.equals("true"), powerState.displayName);
-
- if (thing.interfaces.contains("dimmablelight")) {
- State brightnessState = thing.stateByName("brightness");
- RangeTemplate rangeTemplate = new RangeTemplate(thing.id.toString(), 0, 100, Float.parseFloat(brightnessState.value), 1, brightnessState.displayName);
- builder.setControlTemplate(new ToggleRangeTemplate(thing.id.toString(), controlButton, rangeTemplate));
- } else {
- builder.setControlTemplate(new ToggleTemplate(thing.id.toString(), controlButton));
- }
- } else if (thing.interfaces.contains("powersocket")) {
- builder.setDeviceType(DeviceTypes.TYPE_OUTLET);
- State powerState = thing.stateByName("power");
- ControlButton controlButton = new ControlButton(powerState.value.equals("true"), powerState.displayName);
- builder.setControlTemplate(new ToggleTemplate(thing.id.toString(), controlButton));
- } else if (thing.interfaces.contains("mediaplayer")) {
- if (thing.stateByName("playerType").value == "video") {
- builder.setDeviceType(DeviceTypes.TYPE_TV);
- } else {
- // FIXME: There doesn't seem to be a speaker DeviceType!?!
- builder.setDeviceType(DeviceTypes.TYPE_TV);
- }
- if (thing.interfaces.contains("volumecontroller")) {
- State volumeState = thing.stateByName("volume");
- if (volumeState != null) {
- RangeTemplate rangeTemplate = new RangeTemplate(thing.id.toString(), 0, 100, Float.parseFloat(volumeState.value), 1, volumeState.displayName);
- builder.setControlTemplate(rangeTemplate);
- }
- }
- } else {
- builder.setDeviceType(DeviceTypes.TYPE_GENERIC_ON_OFF);
- }
- builder.setStatus(Control.STATUS_OK);
-
-// Log.d(TAG, "Created control for thing: " + thing.name + " id: " + thing.id);
- return builder.build();
- }
-}
diff --git a/androidservice/java/io/guh/nymeaapp/NymeaAppControlsActivity.java b/androidservice/java/io/guh/nymeaapp/NymeaAppControlsActivity.java
deleted file mode 100644
index 3b94d25e..00000000
--- a/androidservice/java/io/guh/nymeaapp/NymeaAppControlsActivity.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package io.guh.nymeaapp;
-import android.util.Log;
-import android.content.Intent;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Build;
-import android.telephony.TelephonyManager;
-import android.provider.Settings.Secure;
-import android.os.Vibrator;
-import android.os.Process;
-import android.nfc.NfcAdapter;
-import android.nfc.NdefMessage;
-import android.os.Parcelable;
-
-// An activity spawned by android device controls on demand.
-
-public class NymeaAppControlsActivity extends org.qtproject.qt5.android.bindings.QtActivity
-{
- private static final String TAG = "nymea-app: NymeaAppControlActivity";
-
-
- @Override public void onPause() {
- Log.d(TAG, "Pausing...");
- System.exit(0);
- }
-
- @Override public void onResume() {
- super.onResume();
- Log.d(TAG, "Resuming...");
- }
-
- @Override public void onDestroy() {
- Log.d(TAG, "Destroying...");
- }
-
- public boolean startedByNfc() {
- return NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction());
- }
-
- public String nymeaId()
- {
- return getIntent().getStringExtra("nymeaId");
- }
-
- public String thingId()
- {
- return getIntent().getStringExtra("thingId");
- }
-
- public void vibrate(int duration)
- {
- Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
- v.vibrate(duration);
- }
-}
diff --git a/androidservice/java/io/guh/nymeaapp/NymeaAppService.java b/androidservice/java/io/guh/nymeaapp/NymeaAppService.java
deleted file mode 100644
index 5bc6acf7..00000000
--- a/androidservice/java/io/guh/nymeaapp/NymeaAppService.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package io.guh.nymeaapp;
-
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import org.qtproject.qt5.android.bindings.QtService;
-
-// Background service establishing a connection to nymea and providing data on android specific interfaces
-// such as IBinder and BroadcastListener
-
-// This service loads the service_main Qt entry point and does most of its work in C++/Qt
-
-public class NymeaAppService extends QtService
-{
- public static final String NYMEA_APP_BROADCAST = "io.guh.nymeaapp.NymeaAppService.broadcast";
-
- private static final String TAG = "nymea-app: NymeaAppService";
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.i(TAG, "Creating Service");
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.i(TAG, "Destroying Service");
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- int ret = super.onStartCommand(intent, flags, startId);
-
- // Do some work
-
- Log.d(TAG, "*************** Service started");
-
- return ret;
- }
-
- public void sendBroadcast(String payload) {
- Intent sendToUiIntent = new Intent();
- sendToUiIntent.setAction(NYMEA_APP_BROADCAST);
- sendToUiIntent.putExtra("data", payload);
-// Log.d(TAG, "Service sending broadcast");
- sendBroadcast(sendToUiIntent);
- }
-}
diff --git a/androidservice/java/io/guh/nymeaapp/NymeaAppServiceConnection.java b/androidservice/java/io/guh/nymeaapp/NymeaAppServiceConnection.java
deleted file mode 100644
index fd3c3b1b..00000000
--- a/androidservice/java/io/guh/nymeaapp/NymeaAppServiceConnection.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package io.guh.nymeaapp;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.UUID;
-import java.util.HashMap;
-
-import android.util.Log;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
-import android.content.ServiceConnection;
-import android.content.ComponentName;
-import android.content.Context;
-
-import android.service.controls.Control;
-import android.service.controls.DeviceTypes;
-
-import io.reactivex.processors.ReplayProcessor;
-
-import org.json.*;
-
-// Helper class to establish a connection to the NymeaAppService and interact
-// with that using IBinder and ServiceBroadcastListener
-
-public class NymeaAppServiceConnection implements ServiceConnection {
- private static final String TAG = "nymea-app: NymeaAppServiceConnection";
- private IBinder m_service;
- private Context m_context;
-
- private boolean m_connected = false;
- private HashMap m_nymeaHosts = new HashMap();
-
- public NymeaAppServiceConnection(Context context) {
- super();
- m_context = context;
- }
-
- final public boolean connected() {
- return m_connected;
- }
- public void onConnectedChanged(boolean connected) {};
-
- final public boolean isReady(UUID nymeaId) {
- return m_nymeaHosts.get(nymeaId).isReady;
- }
- public void onReadyChanged(UUID nymeaId, boolean ready) {}
-
- public final HashMap getHosts() {
- return m_nymeaHosts;
- }
-
- final public Thing getThing(UUID thingId) {
- for (HashMap.Entry entry : m_nymeaHosts.entrySet()) {
- Thing thing = entry.getValue().things.get(thingId);
- if (thing != null) {
- return thing;
- }
- }
- return null;
- }
- final public UUID hostForThing(UUID thingId) {
- for (HashMap.Entry entry : m_nymeaHosts.entrySet()) {
- Thing thing = entry.getValue().things.get(thingId);
- if (thing != null) {
- return entry.getKey();
- }
- }
- return null;
- }
-
- public void onError() {}
- public void onUpdate(UUID nymeaId, UUID thingId) {}
-
- final public void executeAction(UUID nymeaId, UUID thingId, UUID actionTypeId, String paramValue) {
- try {
- JSONObject params = new JSONObject();
- params.put("nymeaId", nymeaId.toString());
- params.put("thingId", thingId.toString());
- params.put("actionTypeId", actionTypeId.toString());
- JSONArray actionParams = new JSONArray();
- JSONObject param = new JSONObject();
- param.put("paramTypeId", actionTypeId.toString());
- param.put("value", paramValue);
- actionParams.put(param);
- params.put("params", actionParams);
- Parcel parcel = createRequest("ExecuteAction", params);
- Parcel retParcel = Parcel.obtain();
- m_service.transact(1, parcel, retParcel, 0);
- } catch (Exception e) {
- Log.d(TAG, "Error calling executeAction on NymeaAppService");
- }
- }
-
- @Override public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "Connected to NymeaAppService");
- m_service = service;
-
- registerServiceBroadcastReceiver();
-
- try {
- Parcel parcel = createRequest("GetInstances");
- Parcel retParcel = Parcel.obtain();
-
- m_service.transact(1, parcel, retParcel, 0);
-
- JSONObject reply = new JSONObject(retParcel.readString());
- Log.d(TAG, "Instaces received: " + reply.toString());
- JSONArray instances = reply.getJSONArray("instances");
- for (int i = 0; i < instances.length(); i++) {
- JSONObject instanceMap = instances.getJSONObject(i);
- NymeaHost nymeaHost = new NymeaHost();
- nymeaHost.id = UUID.fromString(instanceMap.getString("id"));
- nymeaHost.name = instanceMap.getString("name");
- nymeaHost.isReady = instanceMap.getBoolean("isReady");
- m_nymeaHosts.put(nymeaHost.id, nymeaHost);
- if (nymeaHost.isReady) {
- fetchThings(nymeaHost.id);
- }
- }
- } catch (JSONException e) {
- Log.d(TAG, "Error while processing JSON in communication with NymeaAppService: " + e.toString());
- onError();
- return;
- } catch (RemoteException e) {
- Log.d(TAG, "Error communicating with NymeaAppService: " + e.toString());
- onError();
- return;
- }
-
- m_connected = true;
- onConnectedChanged(m_connected);
- }
-
- @Override public void onServiceDisconnected(ComponentName arg0) {
- m_service = null;
- for (int i = 0; i < m_nymeaHosts.size(); i++) {
- m_nymeaHosts.get(i).isReady = false;
- }
- m_connected = false;
- onConnectedChanged(m_connected);
- }
-
- public void registerServiceBroadcastReceiver() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(NymeaAppService.NYMEA_APP_BROADCAST);
- m_context.registerReceiver(serviceMessageReceiver, intentFilter);
- Log.d(TAG, "Registered broadcast receiver");
- }
-
- private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (NymeaAppService.NYMEA_APP_BROADCAST.equals(intent.getAction())) {
- String payload = intent.getStringExtra("data");
- try {
- processBroadcast(payload);
- } catch(JSONException e) {
- Log.d(TAG, "Error parsing broadcast JSON: " + e.toString());
- }
- }
- }
- };
-
- private void processBroadcast(String payload) throws JSONException
- {
- JSONObject data = new JSONObject(payload);
- JSONObject params = data.getJSONObject("params");
-// Log.d(TAG, "Broadcast received from NymeaAppService: " + data.getString("notification"));
- Log.d(TAG, params.toString());
-
- if (data.getString("notification").equals("ThingStateChanged")) {
- UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
- UUID thingId = UUID.fromString(params.getString("thingId"));
- UUID stateTypeId = UUID.fromString(params.getString("stateTypeId"));
- String value = params.getString("value");
-// Log.d(TAG, "Thing state changed: " + thingId + " stateTypeId: " + stateTypeId + " value: " + value);
-
- Thing thing = getThing(thingId);
- if (thing != null) {
- thing.stateById(stateTypeId).value = value;
- onUpdate(nymeaId, thingId);
- } else {
- Log.d(TAG, "Got a state change notification for a thing we don't know!");
- }
- }
-
- if (data.getString("notification").equals("ReadyStateChanged")) {
- UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
- NymeaHost host = m_nymeaHosts.get(nymeaId);
- host.isReady = params.getBoolean("isReady");
- if (host.isReady) {
- Log.d(TAG, "Host is ready. Fetching things...");
- fetchThings(nymeaId);
- } else {
- Log.d(TAG, "Host is not ready yet...");
- }
- }
- }
-
- private void fetchThings(UUID nymeaId) {
- Log.d(TAG, "Fetching things");
- String thingsList;
- try {
- JSONObject params = new JSONObject();
- params.put("nymeaId", nymeaId.toString());
- Parcel parcel = createRequest("GetThings", params);
- Parcel retParcel = Parcel.obtain();
- m_service.transact(1, parcel, retParcel, 0);
- thingsList = retParcel.readString();
- } catch (Exception e) {
- Log.d(TAG, "Error fetching things from NymeaAppService: " + e.toString());
- onError();
- return;
- }
-
- try {
- JSONObject result = new JSONObject(thingsList);
- for (int i = 0; i < result.getJSONArray("things").length(); i++) {
- JSONObject entry = result.getJSONArray("things").getJSONObject(i);
- Thing thing = new Thing();
- thing.id = UUID.fromString(entry.getString("id"));
- thing.name = entry.getString("name");
- thing.className = entry.getString("className");
- JSONArray ifaces = entry.getJSONArray("interfaces");
- for (int j = 0; j < ifaces.length(); j++) {
- thing.interfaces.add(ifaces.get(j));
- }
- JSONArray states = entry.getJSONArray("states");
- for (int j = 0; j < states.length(); j++) {
- JSONObject stateMap = states.getJSONObject(j);
- State s = new State();
- s.typeId = UUID.fromString(stateMap.getString("stateTypeId"));
- s.name = stateMap.getString("name");
- s.displayName = stateMap.getString("displayName");
- s.value = stateMap.getString("value");
- thing.states.add(s);
- }
- JSONArray actions = entry.getJSONArray("actions");
- for (int j = 0; j < actions.length(); j++) {
- JSONObject actionMap = actions.getJSONObject(j);
- Action a = new Action();
- a.typeId = UUID.fromString(actionMap.getString("actionTypeId"));
- a.name = actionMap.getString("name");
- a.displayName = actionMap.getString("displayName");
- thing.actions.add(a);
- }
- m_nymeaHosts.get(nymeaId).things.put(thing.id, thing);
- }
-
- } catch (Exception e) {
- Log.d(TAG, "Error parsing JSON from NymeaAppService: " + e.toString());
- Log.d(TAG, thingsList);
- m_service = null;
- onError();
- return;
- }
-
- Log.d(TAG, "Things fetched: " + m_nymeaHosts.get(nymeaId).things.size());
- m_nymeaHosts.get(nymeaId).isReady = true;
- onReadyChanged(nymeaId, true);
- }
-
- private Parcel createRequest(String method) throws JSONException {
- return createRequest(method, null);
- }
- private Parcel createRequest(String method, JSONObject params) throws JSONException {
- Parcel ret = Parcel.obtain();
- JSONObject payload = new JSONObject();
- payload.put("method", method);
- if (params != null) {
- payload.put("params", params);
- }
- Log.d(TAG, "Parcel payload: " + payload.toString());
- ret.writeString(payload.toString());
- return ret;
- }
-}
diff --git a/androidservice/java/io/guh/nymeaapp/NymeaHost.java b/androidservice/java/io/guh/nymeaapp/NymeaHost.java
deleted file mode 100644
index a568563c..00000000
--- a/androidservice/java/io/guh/nymeaapp/NymeaHost.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.guh.nymeaapp;
-
-import java.util.HashMap;
-import java.util.ArrayList;
-import java.util.UUID;
-
-public class NymeaHost {
-
- UUID id;
- boolean isReady = false;
- String name = "";
- HashMap things = new HashMap();
-}
diff --git a/androidservice/java/io/guh/nymeaapp/State.java b/androidservice/java/io/guh/nymeaapp/State.java
deleted file mode 100644
index 5b7053ea..00000000
--- a/androidservice/java/io/guh/nymeaapp/State.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.guh.nymeaapp;
-
-import java.util.UUID;
-
-public class State {
- public UUID typeId;
- public String name;
- public String displayName;
- public String value;
-}
diff --git a/androidservice/java/io/guh/nymeaapp/Thing.java b/androidservice/java/io/guh/nymeaapp/Thing.java
deleted file mode 100644
index e5667831..00000000
--- a/androidservice/java/io/guh/nymeaapp/Thing.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package io.guh.nymeaapp;
-
-import android.util.Log;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.UUID;
-
-
-public class Thing {
- static final public String TAG = "nymea-app: Thing";
- public UUID id;
- public String name;
- public String className;
- public List interfaces = new ArrayList();
-
- public ArrayList states = new ArrayList();
- public ArrayList actions = new ArrayList();
-
- public State stateByName(String name) {
- for (int i = 0; i < states.size(); i++) {
- if (states.get(i).name.equals(name)) {
- return states.get(i);
- }
- }
- return null;
- }
-
- public State stateById(UUID stateTypeId) {
- for (int i = 0; i < states.size(); i++) {
- if (states.get(i).typeId.equals(stateTypeId)) {
- return states.get(i);
- }
- }
- return null;
- }
-
- public Action actionByName(String name) {
- for (int i = 0; i < actions.size(); i++) {
- Log.d(TAG, "Thing has action: " + actions.get(i).name);
- if (actions.get(i).name.equals(name)) {
- return actions.get(i);
- }
- }
- return null;
- }
-
- public Action actionById(UUID actionTypeId) {
- for (int i = 0; i < actions.size(); i++) {
- if (actions.get(i).typeId.equals(actionTypeId)) {
- return actions.get(i);
- }
- }
- return null;
- }
-}
diff --git a/androidservice/nymeaappservice/androidbinder.cpp b/androidservice/nymeaappservice/androidbinder.cpp
deleted file mode 100644
index 41696887..00000000
--- a/androidservice/nymeaappservice/androidbinder.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-#include "androidbinder.h"
-#include "engine.h"
-#include "types/thing.h"
-
-#include
-#include
-#include
-#include
-#include
-
-AndroidBinder::AndroidBinder(NymeaAppService *service):
- m_service(service)
-{
-}
-
-bool AndroidBinder::onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags)
-{
- qDebug() << "onTransact: code " << code << ", flags " << int(flags);
-
-// QString payload = data.readData();
- QString payload = data.handle().callObjectMethod("readString").toString();
-
- QJsonParseError error;
- QJsonDocument jsonDoc = QJsonDocument::fromJson(payload.toUtf8(), &error);
- if (error.error != QJsonParseError::NoError) {
- qWarning() << "Error parsing JSON from parcel:" << error.errorString();
- qWarning() << payload;
- return false;
- }
- QVariantMap request = jsonDoc.toVariant().toMap();
-
- if (request.value("method").toString() == "GetInstances") {
- QVariantMap params;
- QVariantList instances;
- foreach (const QUuid &nymeaId, m_service->engines().keys()) {
- Engine *engine = m_service->engines().value(nymeaId);
- QVariantMap instance;
- instance.insert("id", nymeaId);
- instance.insert("isReady", engine->jsonRpcClient()->connected() && !engine->thingManager()->fetchingData());
- instance.insert("name", engine->jsonRpcClient()->currentHost()->name());
- instances.append(instance);
- }
- params.insert("instances", instances);
- sendReply(reply, params);
- return true;
- }
-
- if (request.value("method").toString() == "GetThings") {
- QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
- Engine *engine = m_service->engines().value(nymeaId);
- if (!engine) {
- qWarning() << "Android client requested things for an invalid nymea instance:" << nymeaId;
- return false;
- }
- QVariantList thingsList;
- for (int i = 0; i < engine->thingManager()->things()->rowCount(); i++) {
- Thing *thing = engine->thingManager()->things()->get(i);
- QVariantMap thingMap;
- thingMap.insert("id", thing->id());
- thingMap.insert("name", thing->name());
- thingMap.insert("className", thing->thingClass()->displayName());
- thingMap.insert("interfaces", thing->thingClass()->interfaces());
- QVariantList states;
- for (int j = 0; j < thing->states()->rowCount(); j++) {
- State *state = thing->states()->get(j);
- QVariantMap stateMap;
- stateMap.insert("stateTypeId", state->stateTypeId());
- stateMap.insert("name", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->name());
- stateMap.insert("displayName", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->displayName());
- stateMap.insert("value", state->value());
- states.append(stateMap);
- }
- thingMap.insert("states", states);
- QVariantList actions;
- for (int j = 0; j < thing->thingClass()->actionTypes()->rowCount(); j++) {
- ActionType *actionType = thing->thingClass()->actionTypes()->get(j);
- QVariantMap actionMap;
- actionMap.insert("actionTypeId", actionType->id());
- actionMap.insert("name", actionType->name());
- actionMap.insert("displayName", actionType->displayName());
- actions.append(actionMap);
- }
- thingMap.insert("actions", actions);
- thingsList.append(thingMap);
- }
- QVariantMap params;
- params.insert("things", thingsList);
- sendReply(reply, params);
- return true;
- }
-
- if (request.value("method").toString() == "ExecuteAction") {
- qDebug() << "ExecuteAction";
- QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
- Engine *engine = m_service->engines().value(nymeaId);
- if (!engine) {
- qWarning() << "Android client requested executeAction for an invalid nymea instance:" << nymeaId;
- return false;
- }
- QUuid thingId = request.value("params").toMap().value("thingId").toUuid();
- QUuid actionTypeId = request.value("params").toMap().value("actionTypeId").toUuid();
- QVariantList params = request.value("params").toMap().value("params").toList();
-
- qDebug() << "**** executeAction:" << thingId << actionTypeId << params;
- engine->thingManager()->executeAction(thingId, actionTypeId, params);
- }
-
- return false;
-}
-
-void AndroidBinder::sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms)
-{
- QString payload = QJsonDocument::fromVariant(params).toJson();
- reply.handle().callMethod("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(payload).object());
-}
diff --git a/androidservice/nymeaappservice/androidbinder.h b/androidservice/nymeaappservice/androidbinder.h
deleted file mode 100644
index 36a9b795..00000000
--- a/androidservice/nymeaappservice/androidbinder.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef ANDROIDBINDER_H
-#define ANDROIDBINDER_H
-
-#include
-
-#include "nymeaappservice.h"
-#include "engine.h"
-
-class AndroidBinder : public QAndroidBinder
-{
-public:
- explicit AndroidBinder(NymeaAppService *service);
-
- bool onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags) override;
-
-private:
- void sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms);
-
-private:
- NymeaAppService *m_service = nullptr;
-};
-
-#endif // ANDROIDBINDER_H
diff --git a/androidservice/nymeaappservice/nymeaappservice.cpp b/androidservice/nymeaappservice/nymeaappservice.cpp
deleted file mode 100644
index 76a2d4a8..00000000
--- a/androidservice/nymeaappservice/nymeaappservice.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-#include "nymeaappservice.h"
-#include "androidbinder.h"
-
-#include
-#include
-#include
-#include
-
-#include "connection/discovery/nymeadiscovery.h"
-#include "connection/nymeahosts.h"
-
-NymeaAppService::NymeaAppService(int argc, char **argv):
- QAndroidService(argc, argv, [=](const QAndroidIntent &) {
- return new AndroidBinder{this};
- })
-{
- setApplicationName("nymea-app");
- setOrganizationName("nymea");
-
- QSettings settings;
-
- NymeaDiscovery *discovery = new NymeaDiscovery(this);
-
- settings.beginGroup("ConfiguredHosts");
- foreach (const QString &childGroup, settings.childGroups()) {
- settings.beginGroup(childGroup);
- QUuid lastConnected = settings.value("uuid").toUuid();
- QString cachedName = settings.value("cachedName").toString();
- settings.endGroup();
-
- if (lastConnected.isNull()) {
- continue;
- }
- NymeaHost *host = discovery->nymeaHosts()->find(lastConnected);
- if (!host) {
- continue;
- }
-
- Engine *engine = new Engine(this);
- engine->jsonRpcClient()->connectToHost(host);
- m_engines.insert(host->uuid(), engine);
-
-
- QObject::connect(engine->thingManager(), &ThingManager::thingStateChanged, [=](const QUuid &thingId, const QUuid &stateTypeId, const QVariant &value){
- QVariantMap params;
- params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
- params.insert("thingId", thingId);
- params.insert("stateTypeId", stateTypeId);
- params.insert("value", value);
- sendNotification("ThingStateChanged", params);
- });
-
- connect(engine->thingManager(), &ThingManager::fetchingDataChanged, [=]() {
- qDebug() << "Fetching data changed";
- QVariantMap params;
- params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
- params.insert("isReady", !engine->thingManager()->fetchingData());
- qDebug() << "Nymea host is ready" << engine->jsonRpcClient()->currentHost()->uuid();
- sendNotification("ReadyStateChanged", params);
- });
- }
- settings.endGroup();
-
- qDebug() << "NymeaAppService started.";
-
-}
-
-QHash NymeaAppService::engines() const
-{
- return m_engines;
-}
-
-void NymeaAppService::sendNotification(const QString ¬ification, const QVariantMap ¶ms)
-{
- QVariantMap data;
- data.insert("notification", notification);
- data.insert("params", params);
- QString payload = QJsonDocument::fromVariant(data).toJson();
- QtAndroid::androidService().callMethod("sendBroadcast",
- "(Ljava/lang/String;)V",
- QAndroidJniObject::fromString(payload).object());
-
-}
diff --git a/androidservice/nymeaappservice/nymeaappservice.h b/androidservice/nymeaappservice/nymeaappservice.h
deleted file mode 100644
index 5e823efa..00000000
--- a/androidservice/nymeaappservice/nymeaappservice.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef NYMEAAPPSERVICE_H
-#define NYMEAAPPSERVICE_H
-
-#include
-#include
-#include
-
-#include "engine.h"
-
-class NymeaAppService : public QAndroidService
-{
- Q_OBJECT
-public:
- explicit NymeaAppService(int argc, char** argv);
-
- QHash engines() const;
-
-private:
- void sendNotification(const QString ¬ification, const QVariantMap ¶ms);
-
-
-private:
- QHash m_engines;
-
-};
-
-#endif // NYMEAAPPSERVICE_H
diff --git a/androidservice/service_main.cpp b/androidservice/service_main.cpp
deleted file mode 100644
index 46efab22..00000000
--- a/androidservice/service_main.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include
-#include
-
-#include "nymeaappservice/nymeaappservice.h"
-#include "controlviews/devicecontrolapplication.h"
-
-#include
-#include
-
-int main(int argc, char *argv[])
-{
- qWarning() << "Service starting from a separate .so file";
-
- QLoggingCategory::setFilterRules("qt.remoteobjects.debug=true\n");
-
- QStringList args;
- for (int i = 0; i < argc; i++) {
- args.append(QByteArray(argv[i]));
- qDebug() << "nymea-app: Added command line arg" << args.last();
- }
- QCommandLineParser parser;
- QCommandLineOption controlActivityOption("controlActivity");
- parser.addOption(controlActivityOption);
- parser.parse(args);
-
- QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-
- QCoreApplication *app;
- if (parser.isSet(controlActivityOption)) {
- qDebug() << "nymea-app: Starting Device Control Activity";
- app = new DeviceControlApplication(argc, argv);
- } else {
- qDebug() << "nymea-app: Starting NymeaAppService background service";
- app = new NymeaAppService(argc, argv);
- }
- return app->exec();
-}
diff --git a/config.h.in.qmake b/config.h.in.qmake
new file mode 100644
index 00000000..ed2ba667
--- /dev/null
+++ b/config.h.in.qmake
@@ -0,0 +1,71 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* 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 .
+*
+* 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
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef VERSION_H
+#define VERSION_H
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* 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 .
+*
+* 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
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef VERSION_H
+#define VERSION_H
+
+#define APP_VERSION '"$$APP_VERSION"'
+#define APPLICATION_NAME '"$$APPLICATION_NAME"'
+#define ORGANISATION_NAME '"$$ORGANISATION_NAME"'
+
+#endif
diff --git a/debian b/debian
index 3f3d1dfa..cf793782 120000
--- a/debian
+++ b/debian
@@ -1 +1 @@
-packaging/ubuntu/debian/
\ No newline at end of file
+packaging/ubuntu/debian-qt6/
\ No newline at end of file
diff --git a/experiences/CMakeLists.txt b/experiences/CMakeLists.txt
new file mode 100644
index 00000000..cb6c01f9
--- /dev/null
+++ b/experiences/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(airconditioning)
diff --git a/experiences/airconditioning/CMakeLists.txt b/experiences/airconditioning/CMakeLists.txt
new file mode 100644
index 00000000..58d56a13
--- /dev/null
+++ b/experiences/airconditioning/CMakeLists.txt
@@ -0,0 +1,31 @@
+file(GLOB AIRCONDITIONING_SOURCES CONFIGURE_DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+)
+file(GLOB AIRCONDITIONING_HEADERS CONFIGURE_DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.h
+)
+
+add_library(nymea-app-airconditioning STATIC
+ ${AIRCONDITIONING_SOURCES}
+ ${AIRCONDITIONING_HEADERS}
+)
+set_target_properties(nymea-app-airconditioning PROPERTIES OUTPUT_NAME "nymea-app-airconditioning")
+
+target_include_directories(nymea-app-airconditioning
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/libnymea-app
+ ${CMAKE_BINARY_DIR}
+)
+
+target_link_libraries(nymea-app-airconditioning
+ PUBLIC
+ nymea-app-core
+ Qt6::Core
+ Qt6::Network
+ Qt6::WebSockets
+ Qt6::Bluetooth
+ Qt6::Charts
+ Qt6::Quick
+ Qt6::Qml
+)
diff --git a/experiences/airconditioning/airconditioning.pro b/experiences/airconditioning/airconditioning.pro
index 9ca7c8ab..67657a29 100644
--- a/experiences/airconditioning/airconditioning.pro
+++ b/experiences/airconditioning/airconditioning.pro
@@ -10,8 +10,8 @@ include(../../shared.pri)
LIBS += -L$${top_builddir}/libnymea-app/ -lnymea-app
android: {
-LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
-PRE_TARGETDEPS += $$top_builddir/libnymea-app/$${ANDROID_TARGET_ARCH}/libnymea-app.a
+ LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
+ PRE_TARGETDEPS += $$top_builddir/libnymea-app/$${ANDROID_TARGET_ARCH}/libnymea-app_$${ANDROID_TARGET_ARCH}.a
}
INCLUDEPATH += $${top_srcdir}/libnymea-app/
diff --git a/experiences/airconditioning/airconditioningmanager.cpp b/experiences/airconditioning/airconditioningmanager.cpp
index 32d0dde8..23fc2822 100644
--- a/experiences/airconditioning/airconditioningmanager.cpp
+++ b/experiences/airconditioning/airconditioningmanager.cpp
@@ -25,8 +25,6 @@
#include "airconditioningmanager.h"
#include "zoneinfo.h"
-#include "engine.h"
-
#include
#include
diff --git a/experiences/airconditioning/airconditioningmanager.h b/experiences/airconditioning/airconditioningmanager.h
index 071090d9..3d3a051a 100644
--- a/experiences/airconditioning/airconditioningmanager.h
+++ b/experiences/airconditioning/airconditioningmanager.h
@@ -28,8 +28,7 @@
#include
#include "zoneinfo.h"
-
-class Engine;
+#include "engine.h"
class AirConditioningManager : public QObject
{
diff --git a/experiences/airconditioning/temperatureschedule.cpp b/experiences/airconditioning/temperatureschedule.cpp
index 7c2a57f5..6808598e 100644
--- a/experiences/airconditioning/temperatureschedule.cpp
+++ b/experiences/airconditioning/temperatureschedule.cpp
@@ -123,7 +123,9 @@ QHash TemperatureDaySchedule::roleNames() const
void TemperatureDaySchedule::clear()
{
beginResetModel();
- qDeleteAll(m_list);
+ foreach (TemperatureSchedule *schedule, m_list)
+ schedule->deleteLater();
+
m_list.clear();
endResetModel();
}
@@ -131,7 +133,7 @@ void TemperatureDaySchedule::clear()
void TemperatureDaySchedule::addSchedule(TemperatureSchedule *schedule)
{
schedule->setParent(this);
- beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
+ beginInsertRows(QModelIndex(), static_cast(m_list.count()), static_cast(m_list.count()));
m_list.append(schedule);
endInsertRows();
emit countChanged();
diff --git a/experiences/airconditioning/temperatureschedule.h b/experiences/airconditioning/temperatureschedule.h
index 3df4e804..673d80fa 100644
--- a/experiences/airconditioning/temperatureschedule.h
+++ b/experiences/airconditioning/temperatureschedule.h
@@ -75,7 +75,7 @@ public:
TemperatureDaySchedule(QObject *parent = nullptr);
~TemperatureDaySchedule();
- int rowCount(const QModelIndex & = QModelIndex()) const override { return m_list.count(); }
+ int rowCount(const QModelIndex & = QModelIndex()) const override { return static_cast(m_list.count()); }
QVariant data(const QModelIndex &index, int role) const override;
QHash roleNames() const override;
@@ -90,7 +90,7 @@ signals:
void countChanged();
private:
- QList m_list;
+ QList m_list;
};
class TemperatureWeekSchedule: public QAbstractListModel
@@ -101,7 +101,7 @@ public:
TemperatureWeekSchedule(QObject *parent = nullptr);
~TemperatureWeekSchedule();
- int rowCount(const QModelIndex & = QModelIndex()) const override { return m_list.count(); }
+ int rowCount(const QModelIndex & = QModelIndex()) const override { return static_cast(m_list.count()); }
QVariant data(const QModelIndex &, int) const override { return QVariant(); }
QHash roleNames() const override { return QHash(); }
diff --git a/experiences/airconditioning/zoneinfo.cpp b/experiences/airconditioning/zoneinfo.cpp
index 1bcd09ef..309d2a66 100644
--- a/experiences/airconditioning/zoneinfo.cpp
+++ b/experiences/airconditioning/zoneinfo.cpp
@@ -258,10 +258,10 @@ void ZoneInfos::addZoneInfo(ZoneInfo *zoneInfo)
{
zoneInfo->setParent(this);
connect(zoneInfo, &ZoneInfo::nameChanged, this, [=](){
- QModelIndex idx = index(m_list.indexOf(zoneInfo));
+ QModelIndex idx = index(static_cast(m_list.indexOf(zoneInfo)));
emit dataChanged(idx, idx, {RoleName});
});
- beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
+ beginInsertRows(QModelIndex(), static_cast(m_list.count()), static_cast(m_list.count()));
m_list.append(zoneInfo);
endInsertRows();
emit countChanged();
diff --git a/experiences/airconditioning/zoneinfo.h b/experiences/airconditioning/zoneinfo.h
index 4bc46390..9b8e86ea 100644
--- a/experiences/airconditioning/zoneinfo.h
+++ b/experiences/airconditioning/zoneinfo.h
@@ -173,7 +173,7 @@ public:
};
ZoneInfos(QObject *parent = nullptr): QAbstractListModel(parent) {}
- int rowCount(const QModelIndex & = QModelIndex()) const override { return m_list.count(); }
+ int rowCount(const QModelIndex & = QModelIndex()) const override { return static_cast(m_list.count()); }
QVariant data(const QModelIndex &index, int role) const override;
QHash roleNames() const override;
diff --git a/experiences/evdash/evdash.pro b/experiences/evdash/evdash.pro
new file mode 100644
index 00000000..05d898d5
--- /dev/null
+++ b/experiences/evdash/evdash.pro
@@ -0,0 +1,29 @@
+TEMPLATE = lib
+CONFIG += staticlib
+TARGET = nymea-app-evdash
+
+QT -= gui
+QT += network websockets quick
+
+include(../../shared.pri)
+
+LIBS += -L$${top_builddir}/libnymea-app/ -lnymea-app
+INCLUDEPATH += $${top_srcdir}/libnymea-app/
+
+android: {
+ LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
+ PRE_TARGETDEPS += $$top_builddir/libnymea-app/$${ANDROID_TARGET_ARCH}/libnymea-app_$${ANDROID_TARGET_ARCH}.a
+}
+
+HEADERS += \
+ evdashmanager.h \
+ evdashusers.h \
+ libnymea-app-evdash.h
+
+SOURCES += \
+ evdashmanager.cpp \
+ evdashusers.cpp
+
+android: {
+ DESTDIR = $${ANDROID_TARGET_ARCH}
+}
diff --git a/experiences/evdash/evdashmanager.cpp b/experiences/evdash/evdashmanager.cpp
new file mode 100644
index 00000000..cb960f2b
--- /dev/null
+++ b/experiences/evdash/evdashmanager.cpp
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright (C) 2013 - 2024, nymea GmbH
+* Copyright (C) 2024 - 2025, chargebyte austria GmbH
+*
+* This file is part of nymea-app.
+*
+* 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.
+*
+* 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.
+*
+* You should have received a copy of the GNU General Public License
+* along with nymea-app. If not, see .
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "evdashmanager.h"
+
+#include
+
+#include
+
+NYMEA_LOGGING_CATEGORY(dcEvDashExperience, "EvDashExperience")
+
+EvDashManager::EvDashManager(QObject *parent)
+ :QObject{parent},
+ m_users{new EvDashUsers(this)}
+{
+
+}
+
+EvDashManager::~EvDashManager()
+{
+ if (m_engine) {
+ m_engine->jsonRpcClient()->unregisterNotificationHandler(this);
+ }
+}
+
+EvDashUsers *EvDashManager::users() const
+{
+ return m_users;
+}
+
+Engine *EvDashManager::engine() const
+{
+ return m_engine;
+}
+
+void EvDashManager::setEngine(Engine *engine)
+{
+ if (m_engine == engine)
+ return;
+
+ if (m_engine)
+ m_engine->jsonRpcClient()->unregisterNotificationHandler(this);
+
+ m_engine = engine;
+ emit engineChanged();
+
+ if (m_engine) {
+ connect(engine, &Engine::destroyed, this, [engine, this]{ if (m_engine == engine) m_engine = nullptr; });
+
+ m_engine->jsonRpcClient()->registerNotificationHandler(this, "EvDash", "notificationReceived");
+ m_engine->jsonRpcClient()->sendCommand("EvDash.GetEnabled", QVariantMap(), this, "getEnabledResponse");
+ m_engine->jsonRpcClient()->sendCommand("EvDash.GetUsers", QVariantMap(), this, "getUsersResponse");
+ }
+}
+
+bool EvDashManager::enabled() const
+{
+ return m_enabled;
+}
+
+int EvDashManager::setEnabled(bool enabled)
+{
+ QVariantMap params;
+ params.insert("enabled", enabled);
+ return m_engine->jsonRpcClient()->sendCommand("EvDash.SetEnabled", params, this, "setEnabledResponse");
+}
+
+int EvDashManager::addUser(const QString &username, const QString &password)
+{
+ QVariantMap params;
+ params.insert("username", username);
+ params.insert("password", password);
+ return m_engine->jsonRpcClient()->sendCommand("EvDash.AddUser", params, this, "addUserResponse");
+}
+
+int EvDashManager::removeUser(const QString &username)
+{
+ QVariantMap params;
+ params.insert("username", username);
+ return m_engine->jsonRpcClient()->sendCommand("EvDash.RemoveUser", params, this, "removeUserResponse");
+}
+
+void EvDashManager::notificationReceived(const QVariantMap &data)
+{
+ QString notification = data.value("notification").toString();
+ QVariantMap params = data.value("params").toMap();
+
+ if (notification == "EvDash.EnabledChanged") {
+ bool enabled = params.value("enabled").toBool();
+ if (m_enabled != enabled) {
+ m_enabled = enabled;
+ emit enabledChanged();
+ }
+ } else if (notification == "EvDash.UserAdded") {
+ m_users->addUser(params.value("username").toString());
+ } else if (notification == "EvDash.UserRemoved") {
+ m_users->removeUser(params.value("username").toString());
+ } else {
+ qCDebug(dcEvDashExperience()) << "Unhandled notification received" << data;
+ }
+}
+
+void EvDashManager::getEnabledResponse(int commandId, const QVariantMap ¶ms)
+{
+ Q_UNUSED(commandId)
+ qCDebug(dcEvDashExperience()) << "Response for GetEnabled request" << commandId << params;
+
+ bool enabled = params.value("enabled").toBool();
+ if (m_enabled != enabled) {
+ m_enabled = enabled;
+ emit enabledChanged();
+ }
+}
+
+void EvDashManager::setEnabledResponse(int commandId, const QVariantMap ¶ms)
+{
+ qCDebug(dcEvDashExperience()) << "Response for SetEnabled request" << commandId << params;
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ EvDashError error = static_cast(metaEnum.keyToValue(params.value("evDashError").toByteArray().data()));
+ emit setEnabledReply(commandId, error);
+}
+
+void EvDashManager::getUsersResponse(int commandId, const QVariantMap ¶ms)
+{
+ Q_UNUSED(commandId)
+ qCDebug(dcEvDashExperience()) << "Response for GetEnabled request" << commandId << params;
+ m_users->setUsers(params.value("usernames").toStringList());
+}
+
+void EvDashManager::addUserResponse(int commandId, const QVariantMap ¶ms)
+{
+ qCDebug(dcEvDashExperience()) << "Response for AddUser request" << commandId << params;
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ EvDashError error = static_cast(metaEnum.keyToValue(params.value("evDashError").toByteArray().data()));
+ emit addUserReply(commandId, error);
+}
+
+void EvDashManager::removeUserResponse(int commandId, const QVariantMap ¶ms)
+{
+ qCDebug(dcEvDashExperience()) << "Response for RemoveUser request" << commandId << params;
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ EvDashError error = static_cast(metaEnum.keyToValue(params.value("evDashError").toByteArray().data()));
+ emit removeUserReply(commandId, error);
+}
+
+
diff --git a/experiences/evdash/evdashmanager.h b/experiences/evdash/evdashmanager.h
new file mode 100644
index 00000000..01ba0332
--- /dev/null
+++ b/experiences/evdash/evdashmanager.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright (C) 2013 - 2024, nymea GmbH
+* Copyright (C) 2024 - 2025, chargebyte austria GmbH
+*
+* This file is part of nymea-app.
+*
+* 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.
+*
+* 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.
+*
+* You should have received a copy of the GNU General Public License
+* along with nymea-app. If not, see .
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef EVDASHMANAGER_H
+#define EVDASHMANAGER_H
+
+#include
+#include
+
+#include "evdashusers.h"
+
+class EvDashManager : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(EvDashUsers *users READ users CONSTANT FINAL)
+
+public:
+ enum EvDashError {
+ EvDashErrorNoError = 0,
+ EvDashErrorBackendError,
+ EvDashErrorDuplicateUser,
+ EvDashErrorUserNotFound,
+ EvDashErrorBadPassword
+ };
+ Q_ENUM(EvDashError)
+
+ explicit EvDashManager(QObject *parent = nullptr);
+ ~EvDashManager();
+
+ EvDashUsers *users() const;
+
+ Engine* engine() const;
+ void setEngine(Engine *engine);
+
+ bool enabled() const;
+ int setEnabled(bool enabled);
+
+ Q_INVOKABLE int addUser(const QString &username, const QString &password);
+ Q_INVOKABLE int removeUser(const QString &username);
+
+signals:
+ void engineChanged();
+ void enabledChanged();
+
+ void setEnabledReply(int commandId, EvDashManager::EvDashError error);
+ void addUserReply(int commandId, EvDashManager::EvDashError error);
+ void removeUserReply(int commandId, EvDashManager::EvDashError error);
+
+private slots:
+ void notificationReceived(const QVariantMap &data);
+
+ void getEnabledResponse(int commandId, const QVariantMap ¶ms);
+ void setEnabledResponse(int commandId, const QVariantMap ¶ms);
+
+ void getUsersResponse(int commandId, const QVariantMap ¶ms);
+ void addUserResponse(int commandId, const QVariantMap ¶ms);
+ void removeUserResponse(int commandId, const QVariantMap ¶ms);
+
+private:
+ Engine *m_engine = nullptr;
+ bool m_enabled = false;
+ EvDashUsers *m_users = nullptr;
+
+};
+
+#endif // EVDASHMANAGER_H
diff --git a/experiences/evdash/evdashusers.cpp b/experiences/evdash/evdashusers.cpp
new file mode 100644
index 00000000..e3492804
--- /dev/null
+++ b/experiences/evdash/evdashusers.cpp
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright (C) 2013 - 2024, nymea GmbH
+* Copyright (C) 2024 - 2025, chargebyte austria GmbH
+*
+* This file is part of nymea-app.
+*
+* 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.
+*
+* 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.
+*
+* You should have received a copy of the GNU General Public License
+* along with nymea-app. If not, see .
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "evdashusers.h"
+
+#include
+
+namespace {
+inline bool localeLess(const QString &lhs, const QString &rhs)
+{
+ return QString::localeAwareCompare(lhs, rhs) < 0;
+}
+}
+
+EvDashUsers::EvDashUsers(QObject *parent)
+ : QAbstractListModel(parent)
+{
+
+}
+
+EvDashUsers::EvDashUsers(const QStringList &data, QObject *parent)
+ : QAbstractListModel(parent), m_data(data)
+{
+
+}
+
+int EvDashUsers::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return m_data.size();
+}
+
+QVariant EvDashUsers::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= m_data.size())
+ return QVariant();
+
+ if (role == Qt::DisplayRole || role == NameRole)
+ return m_data.at(index.row());
+
+ return QVariant();
+}
+
+QHash EvDashUsers::roleNames() const
+{
+ QHash roles;
+ roles[NameRole] = "name";
+ return roles;
+}
+
+void EvDashUsers::setUsers(const QStringList &users)
+{
+ QStringList sortedUsers = users;
+ sortedUsers.removeDuplicates();
+ std::sort(sortedUsers.begin(), sortedUsers.end(), localeLess);
+
+ if (sortedUsers == m_data)
+ return;
+
+ beginResetModel();
+ m_data = sortedUsers;
+ endResetModel();
+}
+
+void EvDashUsers::addUser(const QString &user)
+{
+ if (user.isEmpty() || m_data.contains(user))
+ return;
+
+ const auto insertIt = std::lower_bound(m_data.begin(), m_data.end(), user, localeLess);
+ const int insertIndex = std::distance(m_data.begin(), insertIt);
+
+ beginInsertRows(QModelIndex(), insertIndex, insertIndex);
+ m_data.insert(insertIndex, user);
+ endInsertRows();
+}
+
+void EvDashUsers::removeUser(const QString &user)
+{
+ int index = m_data.indexOf(user);
+ if (index < 0)
+ return;
+
+ beginRemoveRows(QModelIndex(), index, index);
+ m_data.removeAt(index);
+ endRemoveRows();
+}
diff --git a/experiences/evdash/evdashusers.h b/experiences/evdash/evdashusers.h
new file mode 100644
index 00000000..991294fe
--- /dev/null
+++ b/experiences/evdash/evdashusers.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright (C) 2013 - 2024, nymea GmbH
+* Copyright (C) 2024 - 2025, chargebyte austria GmbH
+*
+* This file is part of nymea-app.
+*
+* 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.
+*
+* 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.
+*
+* You should have received a copy of the GNU General Public License
+* along with nymea-app. If not, see .
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef EVDASHUSERS_H
+#define EVDASHUSERS_H
+
+#include
+#include
+#include
+
+class EvDashUsers : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ enum Roles { DisplayRole = Qt::UserRole + 1, NameRole };
+
+ explicit EvDashUsers(QObject *parent = nullptr);
+ explicit EvDashUsers(const QStringList &data, QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash roleNames() const override;
+
+ void setUsers(const QStringList &users);
+ void addUser(const QString &username);
+ void removeUser(const QString &username);
+
+private:
+ QStringList m_data;
+
+};
+
+
+#endif // EVDASHUSERS_H
diff --git a/experiences/evdash/libnymea-app-evdash.h b/experiences/evdash/libnymea-app-evdash.h
new file mode 100644
index 00000000..040cf3e0
--- /dev/null
+++ b/experiences/evdash/libnymea-app-evdash.h
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright (C) 2013 - 2024, nymea GmbH
+* Copyright (C) 2024 - 2025, chargebyte austria GmbH
+*
+* This file is part of nymea-app.
+*
+* 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.
+*
+* 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.
+*
+* You should have received a copy of the GNU General Public License
+* along with nymea-app. If not, see .
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef LIBNYMEA_APP_EVDASH_H
+#define LIBNYMEA_APP_EVDASH_H
+
+#include "evdashmanager.h"
+#include "evdashusers.h"
+
+#include
+
+namespace Nymea {
+
+namespace EvDash {
+
+void registerQmlTypes() {
+ qmlRegisterType("Nymea.EvDash", 1, 0, "EvDashManager");
+ qmlRegisterUncreatableType("Nymea.EvDash", 1, 0, "EvDashUsers", "Get if from the EvDash Manager");
+}
+
+}
+
+}
+
+#endif // LIBNYMEA_APP_EVDASH_H
diff --git a/experiences/experiences.pro b/experiences/experiences.pro
index 298fcbc4..794d26d4 100644
--- a/experiences/experiences.pro
+++ b/experiences/experiences.pro
@@ -1,3 +1,3 @@
TEMPLATE = subdirs
-SUBDIRS += airconditioning
+SUBDIRS += airconditioning evdash
diff --git a/libnymea-app/CMakeLists.txt b/libnymea-app/CMakeLists.txt
new file mode 100644
index 00000000..0dd7288e
--- /dev/null
+++ b/libnymea-app/CMakeLists.txt
@@ -0,0 +1,116 @@
+set(LIBNYMEA_APP_SOURCES)
+file(GLOB_RECURSE LIBNYMEA_APP_SOURCES CONFIGURE_DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+)
+file(GLOB_RECURSE LIBNYMEA_APP_HEADERS CONFIGURE_DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.h
+)
+
+set(NYMEA_REMOTEPROXYCLIENT_MODULE
+ ${CMAKE_SOURCE_DIR}/nymea-remoteproxy/cmake/nymea-remoteproxyclient-sources.cmake
+)
+
+set(REMOTE_PROXYCLIENT_SOURCES)
+set(REMOTE_PROXYCLIENT_HEADERS)
+set(REMOTE_PROXYCLIENT_INCLUDE_DIRS)
+
+if(EXISTS ${NYMEA_REMOTEPROXYCLIENT_MODULE})
+ include(${NYMEA_REMOTEPROXYCLIENT_MODULE})
+
+ if(COMMAND nymea_remoteproxyclient_sources)
+ nymea_remoteproxyclient_sources(
+ REMOTE_PROXYCLIENT_SOURCES
+ REMOTE_PROXYCLIENT_HEADERS
+ REMOTE_PROXYCLIENT_INCLUDE_DIRS
+ )
+ endif()
+
+ if(DEFINED NYMEA_REMOTEPROXYCLIENT_SOURCES)
+ list(APPEND REMOTE_PROXYCLIENT_SOURCES ${NYMEA_REMOTEPROXYCLIENT_SOURCES})
+ endif()
+ if(DEFINED NYMEA_REMOTEPROXYCLIENT_HEADERS)
+ list(APPEND REMOTE_PROXYCLIENT_HEADERS ${NYMEA_REMOTEPROXYCLIENT_HEADERS})
+ endif()
+ if(DEFINED NYMEA_REMOTEPROXYCLIENT_INCLUDE_DIRS)
+ list(APPEND REMOTE_PROXYCLIENT_INCLUDE_DIRS ${NYMEA_REMOTEPROXYCLIENT_INCLUDE_DIRS})
+ endif()
+
+ if(NOT REMOTE_PROXYCLIENT_SOURCES AND NOT REMOTE_PROXYCLIENT_HEADERS)
+ message(FATAL_ERROR
+ "nymea-remoteproxyclient module did not populate its source lists. "
+ "Please ensure nymea-remoteproxy is checked out at the required revision."
+ )
+ endif()
+else()
+ message(FATAL_ERROR
+ "nymea-remoteproxyclient CMake module not found. Did you initialize the nymea-remoteproxy submodule?"
+ )
+endif()
+
+if(NOT REMOTE_PROXYCLIENT_INCLUDE_DIRS)
+ set(_nymea_remoteproxyclient_root
+ ${CMAKE_SOURCE_DIR}/nymea-remoteproxy/libnymea-remoteproxyclient
+ )
+ if(EXISTS ${_nymea_remoteproxyclient_root})
+ list(APPEND REMOTE_PROXYCLIENT_INCLUDE_DIRS ${_nymea_remoteproxyclient_root})
+ endif()
+ unset(_nymea_remoteproxyclient_root)
+endif()
+
+if(NOT REMOTE_PROXYCLIENT_INCLUDE_DIRS)
+ message(FATAL_ERROR
+ "nymea-remoteproxyclient include directories were not provided by the module. "
+ "Please ensure the nymea-remoteproxy submodule is checked out at the required revision."
+ )
+endif()
+
+set(NYMEA_APP_CORE_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}
+)
+
+list(APPEND NYMEA_APP_CORE_INCLUDE_DIRS ${REMOTE_PROXYCLIENT_INCLUDE_DIRS})
+
+if(EXISTS ${CMAKE_SOURCE_DIR}/QtZeroConf)
+ list(APPEND NYMEA_APP_CORE_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/QtZeroConf)
+endif()
+
+add_library(nymea-app-core STATIC
+ ${LIBNYMEA_APP_SOURCES}
+ ${LIBNYMEA_APP_HEADERS}
+ ${REMOTE_PROXYCLIENT_SOURCES}
+ ${REMOTE_PROXYCLIENT_HEADERS}
+)
+set_target_properties(nymea-app-core PROPERTIES OUTPUT_NAME "nymea-app")
+
+list(REMOVE_DUPLICATES NYMEA_APP_CORE_INCLUDE_DIRS)
+target_include_directories(nymea-app-core PUBLIC ${NYMEA_APP_CORE_INCLUDE_DIRS})
+
+target_link_libraries(nymea-app-core
+ PUBLIC
+ Qt6::Core
+ Qt6::Network
+ Qt6::WebSockets
+ Qt6::Bluetooth
+ Qt6::Charts
+ Qt6::Quick
+ Qt6::Qml
+)
+
+if(TARGET OpenSSL::SSL AND TARGET OpenSSL::Crypto)
+ target_link_libraries(nymea-app-core PUBLIC OpenSSL::SSL OpenSSL::Crypto)
+else()
+ message(WARNING "OpenSSL development libraries not found; continuing without explicit OpenSSL linkage.")
+endif()
+
+if(NYMEA_ENABLE_ZEROCONF)
+ target_compile_definitions(nymea-app-core PUBLIC WITH_ZEROCONF QZEROCONF_STATIC)
+ find_library(QTZEROCONF_LIBRARY NAMES QtZeroConf HINTS ${CMAKE_SOURCE_DIR}/QtZeroConf)
+ if(NOT QTZEROCONF_LIBRARY AND TARGET Qt6::QtZeroConf)
+ target_link_libraries(nymea-app-core PUBLIC Qt6::QtZeroConf)
+ elseif(QTZEROCONF_LIBRARY)
+ target_link_libraries(nymea-app-core PUBLIC ${QTZEROCONF_LIBRARY})
+ else()
+ message(FATAL_ERROR "ZeroConf support requested but QtZeroConf library was not found")
+ endif()
+endif()
diff --git a/libnymea-app/appdata.cpp b/libnymea-app/appdata.cpp
index f8d66063..182afb4e 100644
--- a/libnymea-app/appdata.cpp
+++ b/libnymea-app/appdata.cpp
@@ -115,7 +115,7 @@ void AppData::load()
for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); i++) {
QMetaProperty prop = metaObject()->property(i);
- qCDebug(dcAppData) << "ComponentComplete property:" << prop.name() << prop.isUser() << prop.type() << prop.isScriptable(this) << prop.isScriptable();
+ qCDebug(dcAppData) << "ComponentComplete property:" << prop.name() << prop.isUser() << prop.type() << prop.isScriptable();
QVariantMap params;
params.insert("appId", APPLICATION_NAME);
if (!m_group.isEmpty()) {
diff --git a/libnymea-app/appdata.h b/libnymea-app/appdata.h
index 671e8eb5..6630eb5a 100644
--- a/libnymea-app/appdata.h
+++ b/libnymea-app/appdata.h
@@ -29,7 +29,7 @@
#include
#include
-class Engine;
+#include "engine.h"
class AppData : public QObject, public QQmlParserStatus
{
diff --git a/libnymea-app/applogcontroller.cpp b/libnymea-app/applogcontroller.cpp
index 0a6ab76c..a1692025 100644
--- a/libnymea-app/applogcontroller.cpp
+++ b/libnymea-app/applogcontroller.cpp
@@ -308,7 +308,7 @@ LogMessages::LogMessages(QObject *parent):
int LogMessages::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_messages.count();
+ return static_cast(m_messages.count());
}
QVariant LogMessages::data(const QModelIndex &index, int role) const
@@ -342,7 +342,7 @@ QHash LogMessages::roleNames() const
void LogMessages::append(const QDateTime ×tamp, const QString &category, const QString &message, AppLogController::LogLevel level)
{
- beginInsertRows(QModelIndex(), m_messages.count(), m_messages.count());
+ beginInsertRows(QModelIndex(), static_cast(m_messages.count()), static_cast(m_messages.count()));
LogMessage msg;
msg.timestamp = timestamp;
msg.category = category;
@@ -372,7 +372,7 @@ LoggingCategories::LoggingCategories(AppLogController *parent):
int LoggingCategories::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return nymeaLoggingCategories().count();
+ return static_cast(nymeaLoggingCategories().count());
}
QVariant LoggingCategories::data(const QModelIndex &index, int role) const
diff --git a/libnymea-app/configuration/mqttpolicies.cpp b/libnymea-app/configuration/mqttpolicies.cpp
index 9b44117c..fe8a9d65 100644
--- a/libnymea-app/configuration/mqttpolicies.cpp
+++ b/libnymea-app/configuration/mqttpolicies.cpp
@@ -33,7 +33,7 @@ MqttPolicies::MqttPolicies(QObject *parent) : QAbstractListModel(parent)
int MqttPolicies::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index)
- return m_list.count();
+ return static_cast(m_list.count());
}
QVariant MqttPolicies::data(const QModelIndex &index, int role) const
@@ -67,27 +67,27 @@ QHash MqttPolicies::roleNames() const
void MqttPolicies::addPolicy(MqttPolicy *policy)
{
policy->setParent(this);
- beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
+ beginInsertRows(QModelIndex(), static_cast(m_list.count()), static_cast(m_list.count()));
m_list.append(policy);
connect(policy, &MqttPolicy::clientIdChanged, this, [this, policy]() {
- QModelIndex index = this->index(m_list.indexOf(policy));
+ QModelIndex index = this->index(static_cast(m_list.indexOf(policy)));
emit dataChanged(index, index, {RoleClientId});
});
connect(policy, &MqttPolicy::usernameChanged, this, [this, policy]() {
- QModelIndex index = this->index(m_list.indexOf(policy));
+ QModelIndex index = this->index(static_cast(m_list.indexOf(policy)));
emit dataChanged(index, index, {RoleUsername});
});
connect(policy, &MqttPolicy::passwordChanged, this, [this, policy]() {
- QModelIndex index = this->index(m_list.indexOf(policy));
+ QModelIndex index = this->index(static_cast(m_list.indexOf(policy)));
emit dataChanged(index, index, {RolePassword});
});
connect(policy, &MqttPolicy::allowedPublishTopicFiltersChanged, this, [this, policy]() {
- QModelIndex index = this->index(m_list.indexOf(policy));
+ QModelIndex index = this->index(static_cast(m_list.indexOf(policy)));
emit dataChanged(index, index, {RoleAllowedPublishTopicFilters});
});
connect(policy, &MqttPolicy::allowedSubscribeTopicFiltersChanged, this, [this, policy]() {
- QModelIndex index = this->index(m_list.indexOf(policy));
+ QModelIndex index = this->index(static_cast(m_list.indexOf(policy)));
emit dataChanged(index, index, {RoleAllowedSubscribeTopicFilters});
});
@@ -97,7 +97,7 @@ void MqttPolicies::addPolicy(MqttPolicy *policy)
void MqttPolicies::removePolicy(MqttPolicy *policy)
{
- int idx = m_list.indexOf(policy);
+ int idx = static_cast(m_list.indexOf(policy));
if (idx < 0) {
return;
}
@@ -127,7 +127,9 @@ MqttPolicy *MqttPolicies::get(int index) const
void MqttPolicies::clear()
{
beginResetModel();
- qDeleteAll(m_list);
+ foreach (MqttPolicy* policy, m_list)
+ policy->deleteLater();
+
m_list.clear();
endResetModel();
}
diff --git a/libnymea-app/configuration/mqttpolicies.h b/libnymea-app/configuration/mqttpolicies.h
index 4639d025..b26ec916 100644
--- a/libnymea-app/configuration/mqttpolicies.h
+++ b/libnymea-app/configuration/mqttpolicies.h
@@ -52,15 +52,17 @@ public:
void addPolicy(MqttPolicy *policy);
void removePolicy(MqttPolicy *policy);
- Q_INVOKABLE MqttPolicy* getPolicy(const QString &clientId) const;
- Q_INVOKABLE MqttPolicy* get(int index) const;
+ Q_INVOKABLE MqttPolicy *getPolicy(const QString &clientId) const;
+ Q_INVOKABLE MqttPolicy *get(int index) const;
void clear();
+
signals:
void countChanged();
private:
- QList m_list;
+ QList m_list;
+
};
#endif // MQTTPOLICIES_H
diff --git a/libnymea-app/configuration/networkmanager.h b/libnymea-app/configuration/networkmanager.h
index 1bb5019a..30a63aaa 100644
--- a/libnymea-app/configuration/networkmanager.h
+++ b/libnymea-app/configuration/networkmanager.h
@@ -28,8 +28,10 @@
#include
#include
-class Engine;
-class NetworkDevices;
+#include "engine.h"
+#include "types/networkdevices.h"
+
+
class WiredNetworkDevices;
class WirelessNetworkDevices;
diff --git a/libnymea-app/configuration/nymeaconfiguration.h b/libnymea-app/configuration/nymeaconfiguration.h
index c6cba934..d1201b04 100644
--- a/libnymea-app/configuration/nymeaconfiguration.h
+++ b/libnymea-app/configuration/nymeaconfiguration.h
@@ -27,6 +27,9 @@
#include
+#include "serverconfigurations.h"
+#include "mqttpolicies.h"
+
class JsonRpcClient;
class ServerConfiguration;
class ServerConfigurations;
@@ -35,7 +38,6 @@ class WebServerConfigurations;
class TunnelProxyServerConfiguration;
class TunnelProxyServerConfigurations;
class MqttPolicy;
-class MqttPolicies;
class NymeaConfiguration : public QObject
{
@@ -131,7 +133,7 @@ signals:
void serverNameChanged();
private:
- JsonRpcClient* m_client = nullptr;
+ JsonRpcClient *m_client = nullptr;
bool m_fetchingData = false;
bool m_debugServerEnabled = false;
diff --git a/libnymea-app/configuration/serverconfiguration.h b/libnymea-app/configuration/serverconfiguration.h
index c5105789..0cef2662 100644
--- a/libnymea-app/configuration/serverconfiguration.h
+++ b/libnymea-app/configuration/serverconfiguration.h
@@ -56,7 +56,7 @@ public:
bool sslEnabled() const;
void setSslEnabled(bool sslEnabled);
- Q_INVOKABLE virtual ServerConfiguration* clone() const;
+ Q_INVOKABLE virtual ServerConfiguration *clone() const;
signals:
void addressChanged();
diff --git a/libnymea-app/configuration/serverconfigurations.cpp b/libnymea-app/configuration/serverconfigurations.cpp
index 4901b666..a084ed19 100644
--- a/libnymea-app/configuration/serverconfigurations.cpp
+++ b/libnymea-app/configuration/serverconfigurations.cpp
@@ -33,7 +33,7 @@ ServerConfigurations::ServerConfigurations(QObject *parent) : QAbstractListModel
int ServerConfigurations::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_list.count();
+ return static_cast(m_list.count());
}
QVariant ServerConfigurations::data(const QModelIndex &index, int role) const
@@ -67,23 +67,23 @@ QHash ServerConfigurations::roleNames() const
void ServerConfigurations::addConfiguration(ServerConfiguration *configuration)
{
configuration->setParent(this);
- beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
+ beginInsertRows(QModelIndex(), static_cast(m_list.count()), static_cast(m_list.count()));
m_list.append(configuration);
connect(configuration, &ServerConfiguration::addressChanged, this, [this, configuration]() {
- QModelIndex idx = index(m_list.indexOf(configuration), 0);
+ QModelIndex idx = index(static_cast(m_list.indexOf(configuration)), 0);
emit dataChanged(idx, idx, {RoleAddress});
});
connect(configuration, &ServerConfiguration::portChanged, this, [this, configuration]() {
- QModelIndex idx = index(m_list.indexOf(configuration), 0);
+ QModelIndex idx = index(static_cast(m_list.indexOf(configuration)), 0);
emit dataChanged(idx, idx, {RolePort});
});
connect(configuration, &ServerConfiguration::authenticationEnabledChanged, this, [this, configuration]() {
- QModelIndex idx = index(m_list.indexOf(configuration), 0);
+ QModelIndex idx = index(static_cast(m_list.indexOf(configuration)), 0);
emit dataChanged(idx, idx, {RoleAuthenticationEnabled});
});
connect(configuration, &ServerConfiguration::sslEnabledChanged, this, [this, configuration]() {
- QModelIndex idx = index(m_list.indexOf(configuration), 0);
+ QModelIndex idx = index(static_cast(m_list.indexOf(configuration)), 0);
emit dataChanged(idx, idx, {RoleSslEnabled});
});
@@ -107,7 +107,9 @@ void ServerConfigurations::removeConfiguration(const QString &id)
void ServerConfigurations::clear()
{
beginResetModel();
- qDeleteAll(m_list);
+ foreach (ServerConfiguration *config, m_list)
+ config->deleteLater();
+
m_list.clear();
endResetModel();
emit countChanged();
diff --git a/libnymea-app/configuration/serverconfigurations.h b/libnymea-app/configuration/serverconfigurations.h
index 90d4ff26..0477f13c 100644
--- a/libnymea-app/configuration/serverconfigurations.h
+++ b/libnymea-app/configuration/serverconfigurations.h
@@ -57,8 +57,8 @@ public:
void clear();
- Q_INVOKABLE ServerConfiguration* get(int index) const;
- Q_INVOKABLE ServerConfiguration* getConfiguration(const QString &id) const;
+ Q_INVOKABLE ServerConfiguration *get(int index) const;
+ Q_INVOKABLE ServerConfiguration *getConfiguration(const QString &id) const;
signals:
void countChanged();
diff --git a/libnymea-app/connection/bluetoothtransport.cpp b/libnymea-app/connection/bluetoothtransport.cpp
index dbb370c9..04706667 100644
--- a/libnymea-app/connection/bluetoothtransport.cpp
+++ b/libnymea-app/connection/bluetoothtransport.cpp
@@ -70,10 +70,10 @@ void BluetoothTransport::disconnect()
NymeaTransportInterface::ConnectionState BluetoothTransport::connectionState() const
{
switch (m_socket->state()) {
- case QBluetoothSocket::ConnectedState:
+ case QBluetoothSocket::SocketState::ConnectedState:
return NymeaTransportInterface::ConnectionStateConnected;
- case QBluetoothSocket::ConnectingState:
- case QBluetoothSocket::ServiceLookupState:
+ case QBluetoothSocket::SocketState::ConnectingState:
+ case QBluetoothSocket::SocketState::ServiceLookupState:
return NymeaTransportInterface::ConnectionStateConnecting;
default:
return NymeaTransportInterface::ConnectionStateDisconnected;
diff --git a/libnymea-app/connection/discovery/bluetoothservicediscovery.cpp b/libnymea-app/connection/discovery/bluetoothservicediscovery.cpp
index da51c15a..de64c392 100644
--- a/libnymea-app/connection/discovery/bluetoothservicediscovery.cpp
+++ b/libnymea-app/connection/discovery/bluetoothservicediscovery.cpp
@@ -24,9 +24,6 @@
#include "bluetoothservicediscovery.h"
-#include "../nymeahosts.h"
-#include "../nymeahost.h"
-
#include
#include "logging.h"
@@ -127,17 +124,6 @@ void BluetoothServiceDiscovery::onServiceDiscovered(const QBluetoothServiceInfo
if (serviceInfo.serviceClassUuids().first() == QBluetoothUuid(QUuid("997936b5-d2cd-4c57-b41b-c6048320cd2b"))) {
qCDebug(dcBluetoothDiscovery()) << "BluetoothServiceDiscovery: Found nymea rfcom service!";
-
-// NymeaHost* host = m_nymeaHosts->find(serviceInfo.device().address());
-// if (!host) {
-// host = new DiscoveryDevice(DiscoveryDevice::DeviceTypeBluetooth, this);
-// qDebug() << "BluetoothServiceDiscovery: Adding new bluetooth host to model";
-// host->setName(QString("%1 (%2)").arg(serviceInfo.serviceName()).arg(serviceInfo.device().name()));
-//// device->setBluetoothAddress(serviceInfo.device().address());
-// PortConfig pc;
-
-// m_nymeaHosts->addHost(device);
-// }
}
}
@@ -157,7 +143,6 @@ void BluetoothServiceDiscovery::onServiceDiscoveryFinished()
return;
}
-// qDebug() << "BluetoothServiceDiscovery: Restart service discovery";
discover();
}
}
diff --git a/libnymea-app/connection/discovery/nymeadiscovery.cpp b/libnymea-app/connection/discovery/nymeadiscovery.cpp
index 45943f79..d7838a82 100644
--- a/libnymea-app/connection/discovery/nymeadiscovery.cpp
+++ b/libnymea-app/connection/discovery/nymeadiscovery.cpp
@@ -32,8 +32,8 @@
#include
#include
#include
-#include
-#include
+//#include
+//#include
#include "logging.h"
NYMEA_LOGGING_CATEGORY(dcDiscovery, "Discovery")
@@ -192,7 +192,6 @@ void NymeaDiscovery::setUpnpDiscoveryEnabled(bool upnpDiscoveryEnabled)
}
}
-
void NymeaDiscovery::loadFromDisk()
{
QSettings settings;
diff --git a/libnymea-app/connection/discovery/nymeadiscovery.h b/libnymea-app/connection/discovery/nymeadiscovery.h
index a710c5c0..b062682c 100644
--- a/libnymea-app/connection/discovery/nymeadiscovery.h
+++ b/libnymea-app/connection/discovery/nymeadiscovery.h
@@ -30,13 +30,12 @@
#include
#include "connection/nymeahost.h"
+#include "connection/nymeahosts.h"
-class NymeaHosts;
class UpnpDiscovery;
class ZeroconfDiscovery;
class BluetoothServiceDiscovery;
-
class NymeaDiscovery : public QObject
{
Q_OBJECT
diff --git a/libnymea-app/connection/discovery/upnpdiscovery.cpp b/libnymea-app/connection/discovery/upnpdiscovery.cpp
index 41d4376c..5a709bbf 100644
--- a/libnymea-app/connection/discovery/upnpdiscovery.cpp
+++ b/libnymea-app/connection/discovery/upnpdiscovery.cpp
@@ -28,7 +28,7 @@
#include
#include
#include
-#include
+//#include
#include "logging.h"
@@ -38,16 +38,16 @@ UpnpDiscovery::UpnpDiscovery(NymeaHosts *nymeaHosts, QObject *parent) :
QObject(parent),
m_nymeaHosts(nymeaHosts)
{
- m_networkConfigurationManager = new QNetworkConfigurationManager(this);
+// m_networkConfigurationManager = new QNetworkConfigurationManager(this);
m_networkAccessManager = new QNetworkAccessManager(this);
connect(m_networkAccessManager, &QNetworkAccessManager::finished, this, &UpnpDiscovery::networkReplyFinished);
m_repeatTimer.setInterval(500);
connect(&m_repeatTimer, &QTimer::timeout, this, &UpnpDiscovery::writeDiscoveryPacket);
- connect(m_networkConfigurationManager, &QNetworkConfigurationManager::configurationAdded, this, &UpnpDiscovery::updateInterfaces);
- connect(m_networkConfigurationManager, &QNetworkConfigurationManager::configurationChanged, this, &UpnpDiscovery::updateInterfaces);
- connect(m_networkConfigurationManager, &QNetworkConfigurationManager::configurationRemoved, this, &UpnpDiscovery::updateInterfaces);
+// connect(m_networkConfigurationManager, &QNetworkConfigurationManager::configurationAdded, this, &UpnpDiscovery::updateInterfaces);
+// connect(m_networkConfigurationManager, &QNetworkConfigurationManager::configurationChanged, this, &UpnpDiscovery::updateInterfaces);
+// connect(m_networkConfigurationManager, &QNetworkConfigurationManager::configurationRemoved, this, &UpnpDiscovery::updateInterfaces);
updateInterfaces();
}
@@ -116,8 +116,13 @@ void UpnpDiscovery::updateInterfaces()
}
qCInfo(dcUPnP()) << "Discovering on" << netAddressEntry.ip() << port;
m_sockets.insert(netAddressEntry.ip(), socket);
- connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
+
connect(socket, &QUdpSocket::readyRead, this, &UpnpDiscovery::readData);
+#if QT_VERSION >= QT_VERSION_CHECK(5 , 15, 0)
+ connect(socket, &QUdpSocket::errorOccurred, this, &UpnpDiscovery::error);
+#else
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
+#endif
}
}
@@ -176,7 +181,7 @@ void UpnpDiscovery::readData()
const QStringList lines = QString(data).split("\r\n");
foreach (const QString& line, lines) {
- int separatorIndex = line.indexOf(':');
+ int separatorIndex = static_cast(line.indexOf(':'));
QString key = line.left(separatorIndex).toUpper();
QString value = line.mid(separatorIndex+1).trimmed();
@@ -259,14 +264,14 @@ void UpnpDiscovery::networkReplyFinished(QNetworkReply *reply)
}
}
- if (xml.name() == "friendlyName") {
+ if (xml.name() == QStringLiteral("friendlyName")) {
name = xml.readElementText();
}
- if (xml.name() == "modelNumber") {
+ if (xml.name() == QStringLiteral("modelNumber")) {
version = xml.readElementText();
}
- if (xml.name() == "UDN") {
- uuid = xml.readElementText().split(':').last();
+ if (xml.name() == QStringLiteral("UDN")) {
+ uuid = QUuid(xml.readElementText().split(':').last());
}
}
}
diff --git a/libnymea-app/connection/discovery/upnpdiscovery.h b/libnymea-app/connection/discovery/upnpdiscovery.h
index b05bd9aa..3e3dbf34 100644
--- a/libnymea-app/connection/discovery/upnpdiscovery.h
+++ b/libnymea-app/connection/discovery/upnpdiscovery.h
@@ -29,7 +29,7 @@
#include
#include
#include
-#include
+//#include
#include
#include "../nymeahost.h"
@@ -63,7 +63,7 @@ private slots:
private:
QHash m_sockets;
QNetworkAccessManager *m_networkAccessManager;
- QNetworkConfigurationManager *m_networkConfigurationManager;
+// QNetworkConfigurationManager *m_networkConfigurationManager;
QTimer m_repeatTimer;
diff --git a/libnymea-app/connection/discovery/zeroconfdiscovery.cpp b/libnymea-app/connection/discovery/zeroconfdiscovery.cpp
index 202ffbd0..e0f24bd2 100644
--- a/libnymea-app/connection/discovery/zeroconfdiscovery.cpp
+++ b/libnymea-app/connection/discovery/zeroconfdiscovery.cpp
@@ -45,23 +45,23 @@ ZeroconfDiscovery::ZeroconfDiscovery(NymeaHosts *nymeaHosts, QObject *parent) :
connect(m_zeroconfJsonRPC, &QZeroConf::serviceUpdated, this, &ZeroconfDiscovery::serviceEntryAdded);
connect(m_zeroconfJsonRPC, &QZeroConf::serviceRemoved, this, &ZeroconfDiscovery::serviceEntryRemoved);
- if (m_zeroconfJsonRPC->isValid()) {
+ // if (m_zeroconfJsonRPC->isValid()) {
m_zeroconfJsonRPC->startBrowser("_jsonrpc._tcp", QAbstractSocket::IPv4Protocol);
qCInfo(dcZeroConf()) << "Created service browser for _jsonrpc._tcp:" << m_zeroconfJsonRPC->browserExists();
- } else {
- qCWarning(dcZeroConf()) << "Failed to initialize service broeser for _jsonprc._tcp";
- }
+ // } else {
+ // qCWarning(dcZeroConf()) << "Failed to initialize service broeser for _jsonprc._tcp";
+ // }
m_zeroconfWebSocket = new QZeroConf(this);
connect(m_zeroconfWebSocket, &QZeroConf::serviceAdded, this, &ZeroconfDiscovery::serviceEntryAdded);
connect(m_zeroconfWebSocket, &QZeroConf::serviceUpdated, this, &ZeroconfDiscovery::serviceEntryAdded);
connect(m_zeroconfWebSocket, &QZeroConf::serviceRemoved, this, &ZeroconfDiscovery::serviceEntryRemoved);
- if (m_zeroconfWebSocket->isValid()) {
+ // if (m_zeroconfWebSocket->isValid()) {
m_zeroconfWebSocket->startBrowser("_ws._tcp", QAbstractSocket::IPv4Protocol);
qCInfo(dcZeroConf()) << "Created service browser for _ws._tcp:" << m_zeroconfWebSocket->browserExists();
- } else {
- qCWarning(dcZeroConf()) << "Failed to initialize service browserr for _ws._tcp";
- }
+ // } else {
+ // qCWarning(dcZeroConf()) << "Failed to initialize service browserr for _ws._tcp";
+ // }
#else
qCInfo(dcZeroConf()) << "Zeroconf support not compiled in. Zeroconf will not be available.";
@@ -108,7 +108,7 @@ void ZeroconfDiscovery::serviceEntryAdded(const QZeroConfService &entry)
qCDebug(dcZeroConf()) << "Service discovered" << entry->type() << entry->name() << " IP:" << entry->ip().toString() << entry->txt();
- QString uuid;
+ QUuid uuid;
bool sslEnabled = false;
QString serverName;
QString version;
@@ -118,7 +118,7 @@ void ZeroconfDiscovery::serviceEntryAdded(const QZeroConfService &entry)
sslEnabled = (txtRecord.second == "true");
}
if (txtRecord.first == "uuid") {
- uuid = txtRecord.second;
+ uuid = QUuid(txtRecord.second);
}
if (txtRecord.first == "name") {
serverName = txtRecord.second;
@@ -167,7 +167,7 @@ void ZeroconfDiscovery::serviceEntryRemoved(const QZeroConfService &entry)
return;
}
- QString uuid;
+ QUuid uuid;
bool sslEnabled = false;
QString serverName;
QString version;
@@ -177,7 +177,7 @@ void ZeroconfDiscovery::serviceEntryRemoved(const QZeroConfService &entry)
sslEnabled = (txtRecord.second == "true");
}
if (txtRecord.first == "uuid") {
- uuid = txtRecord.second;
+ uuid = QUuid(txtRecord.second);
}
if (txtRecord.first == "name") {
serverName = txtRecord.second;
diff --git a/libnymea-app/connection/networkreachabilitymonitor.cpp b/libnymea-app/connection/networkreachabilitymonitor.cpp
index 60a8bc19..da9e9c0a 100644
--- a/libnymea-app/connection/networkreachabilitymonitor.cpp
+++ b/libnymea-app/connection/networkreachabilitymonitor.cpp
@@ -38,6 +38,25 @@ NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
setupIOS();
#endif
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+
+ m_networkInformation = QNetworkInformation::instance();
+
+ qCDebug(dcNymeaConnection()) << "Network infromation supported features:" << m_networkInformation->supportedFeatures();
+ qCDebug(dcNymeaConnection()) << "Network reachability:" << m_networkInformation->reachability();
+ qCDebug(dcNymeaConnection()) << "Network trasport medium changed:" << m_networkInformation->transportMedium();
+
+ QObject::connect(m_networkInformation, &QNetworkInformation::reachabilityChanged, this, [this](QNetworkInformation::Reachability reachability){
+ qCDebug(dcNymeaConnection()) << "Network reachability changed:" << reachability;
+ updateActiveBearers();
+ });
+
+ QObject::connect(m_networkInformation, &QNetworkInformation::transportMediumChanged, this, [this](QNetworkInformation::TransportMedium type){
+ qCDebug(dcNymeaConnection()) << "Network trasport medium changed:" << type;
+ updateActiveBearers();
+ });
+
+#else
m_networkConfigManager = new QNetworkConfigurationManager(this);
QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationAdded, this, [this](const QNetworkConfiguration &config){
@@ -50,6 +69,7 @@ NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
qCDebug(dcNymeaConnection()) << "Network configuration removed:" << config.name() << config.bearerTypeName() << config.purpose();
updateActiveBearers();
});
+#endif
QGuiApplication *app = static_cast(QGuiApplication::instance());
QObject::connect(app, &QGuiApplication::applicationStateChanged, this, [this](Qt::ApplicationState state) {
@@ -58,7 +78,6 @@ NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
});
updateActiveBearers();
-
}
NetworkReachabilityMonitor::~NetworkReachabilityMonitor()
@@ -80,6 +99,16 @@ void NetworkReachabilityMonitor::updateActiveBearers()
#endif
NymeaConnection::BearerTypes availableBearerTypes;
+
+// Note: some features are availabe since Qt 6.3.0, but the minimal Qt6 version is 6.6.0,
+// so we don't want so have an unhanlded gap and let the compiler warn about incompatibility
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ if (m_networkInformation->reachability() == QNetworkInformation::Reachability::Disconnected) {
+ qCDebug(dcNymeaConnection()) << "No reachable network transport medium available.";
+ } else {
+ availableBearerTypes.setFlag(qBearerTypeToNymeaBearerType(m_networkInformation->transportMedium()));
+ }
+#else
QList configs = m_networkConfigManager->allConfigurations(QNetworkConfiguration::Active);
qCDebug(dcNymeaConnection()) << "Network configuations:" << configs.count();
foreach (const QNetworkConfiguration &config, configs) {
@@ -97,6 +126,7 @@ void NetworkReachabilityMonitor::updateActiveBearers()
qCDebug(dcNymeaConnection()) << "Updating network manager";
m_networkConfigManager->updateConfigurations();
}
+#endif
if (m_availableBearerTypes != availableBearerTypes) {
qCInfo(dcNymeaConnection()) << "Available Bearer Types changed to:" << availableBearerTypes;
@@ -109,6 +139,27 @@ void NetworkReachabilityMonitor::updateActiveBearers()
emit availableBearerTypesUpdated();
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkInformation::TransportMedium type)
+{
+ switch (type) {
+ case QNetworkInformation::TransportMedium::Unknown:
+ // Unable to determine the connection type. Assume it's something we can establish any connection type on
+ return NymeaConnection::BearerTypeAll;
+ case QNetworkInformation::TransportMedium::Ethernet:
+ return NymeaConnection::BearerTypeEthernet;
+ case QNetworkInformation::TransportMedium::Cellular:
+ return NymeaConnection::BearerTypeMobileData;
+ case QNetworkInformation::TransportMedium::WiFi:
+ return NymeaConnection::BearerTypeWiFi;
+ case QNetworkInformation::TransportMedium::Bluetooth:
+ // Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it.
+ return NymeaConnection::BearerTypeBluetooth;
+ }
+
+ return NymeaConnection::BearerTypeAll;
+}
+#else
NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type)
{
switch (type) {
@@ -130,9 +181,11 @@ NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearer
case QNetworkConfiguration::Bearer4G:
return NymeaConnection::BearerTypeMobileData;
case QNetworkConfiguration::BearerBluetooth:
- // Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it.
+ // Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it.
return NymeaConnection::BearerTypeNone;
}
- return NymeaConnection::BearerTypeAll;
+ return NymeaConnection::BearerTypeAll;
}
+
+#endif
diff --git a/libnymea-app/connection/networkreachabilitymonitor.h b/libnymea-app/connection/networkreachabilitymonitor.h
index fd227655..e5c0b802 100644
--- a/libnymea-app/connection/networkreachabilitymonitor.h
+++ b/libnymea-app/connection/networkreachabilitymonitor.h
@@ -26,14 +26,19 @@
#define NETWORKREACHABILITYMONITOR_H
#include
-#include
-#include "nymeaconnection.h"
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#include
+#else
+#include
+#endif
#ifdef Q_OS_IOS
#import
#endif
+#include "nymeaconnection.h"
+
class NetworkReachabilityMonitor : public QObject
{
Q_OBJECT
@@ -52,10 +57,16 @@ private slots:
void updateActiveBearers();
private:
- QNetworkConfigurationManager *m_networkConfigManager = nullptr;
NymeaConnection::BearerTypes m_availableBearerTypes = NymeaConnection::BearerTypeNone;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
+ QNetworkInformation *m_networkInformation = nullptr;
+ static NymeaConnection::BearerType qBearerTypeToNymeaBearerType(QNetworkInformation::TransportMedium type);
+#else
+ QNetworkConfigurationManager *m_networkConfigManager = nullptr;
static NymeaConnection::BearerType qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type);
+#endif
+
#ifdef Q_OS_IOS
void setupIOS();
diff --git a/libnymea-app/connection/nymeaconnection.cpp b/libnymea-app/connection/nymeaconnection.cpp
index c0a58997..969ed0f5 100644
--- a/libnymea-app/connection/nymeaconnection.cpp
+++ b/libnymea-app/connection/nymeaconnection.cpp
@@ -316,18 +316,18 @@ void NymeaConnection::onConnected()
newTransport->deleteLater();
-// Connection *existingConnection = m_transportCandidates.value(m_currentTransport);
-// Connection *alternativeConnection = m_transportCandidates.value(newTransport);
-// if (alternativeConnection->priority() > existingConnection->priority()) {
-// qDebug() << "New connection has higher priority! Roaming from" << existingConnection->url() << existingConnection->priority() << "to" << alternativeConnection->url() << alternativeConnection->priority();
-// m_transportCandidates.remove(m_currentTransport);
-// m_currentTransport->deleteLater();
-// m_currentTransport = newTransport;
-// } else {
-// qDebug() << "Connection" << alternativeConnection->url() << alternativeConnection->priority() << "has lower priority than existing" << existingConnection->url() << existingConnection->priority();
-// m_transportCandidates.remove(newTransport);
-// newTransport->deleteLater();
-// }
+ // Connection *existingConnection = m_transportCandidates.value(m_currentTransport);
+ // Connection *alternativeConnection = m_transportCandidates.value(newTransport);
+ // if (alternativeConnection->priority() > existingConnection->priority()) {
+ // qDebug() << "New connection has higher priority! Roaming from" << existingConnection->url() << existingConnection->priority() << "to" << alternativeConnection->url() << alternativeConnection->priority();
+ // m_transportCandidates.remove(m_currentTransport);
+ // m_currentTransport->deleteLater();
+ // m_currentTransport = newTransport;
+ // } else {
+ // qDebug() << "Connection" << alternativeConnection->url() << alternativeConnection->priority() << "has lower priority than existing" << existingConnection->url() << existingConnection->priority();
+ // m_transportCandidates.remove(newTransport);
+ // newTransport->deleteLater();
+ // }
return;
}
}
@@ -389,7 +389,7 @@ void NymeaConnection::onDataAvailable(const QByteArray &data)
{
NymeaTransportInterface *t = static_cast(sender());
if (t == m_currentTransport) {
-// qCDebug(dcNymeaConnection()) << "Data available";
+ // qCDebug(dcNymeaConnection()) << "Data available";
emit dataAvailable(data);
} else {
qCDebug(dcNymeaConnection()) << "Received data from a transport that is not the current one:" << t->url();
@@ -416,7 +416,7 @@ void NymeaConnection::onAvailableBearerTypesUpdated()
if (!m_currentTransport) {
// There's a host but no connection. Try connecting now...
qCInfo(dcNymeaConnection()) << "There's a host but no connection. Trying to connect now...";
- connectInternal(m_currentHost);
+ //connectInternal(m_currentHost);
}
}
@@ -463,7 +463,7 @@ void NymeaConnection::connectInternal(NymeaHost *host)
connectInternal(loopbackConnection);
} else if (m_networkReachabilityMonitor->availableBearerTypes().testFlag(NymeaConnection::BearerTypeWiFi)
- || m_networkReachabilityMonitor->availableBearerTypes().testFlag(NymeaConnection::BearerTypeEthernet)) {
+ || m_networkReachabilityMonitor->availableBearerTypes().testFlag(NymeaConnection::BearerTypeEthernet)) {
Connection* lanConnection = host->connections()->bestMatch(Connection::BearerTypeLan | Connection::BearerTypeWan);
if (lanConnection) {
qCDebug(dcNymeaConnection()) << "Best candidate LAN/WAN connection:" << lanConnection->url();
@@ -529,12 +529,12 @@ bool NymeaConnection::isConnectionBearerAvailable(Connection::BearerType connect
switch (connectionBearerType) {
case Connection::BearerTypeLan:
return availableBearerTypes().testFlag(BearerTypeEthernet)
- || availableBearerTypes().testFlag(BearerTypeWiFi);
+ || availableBearerTypes().testFlag(BearerTypeWiFi);
case Connection::BearerTypeWan:
case Connection::BearerTypeCloud:
return availableBearerTypes().testFlag(BearerTypeEthernet)
- || availableBearerTypes().testFlag(BearerTypeWiFi)
- || availableBearerTypes().testFlag(BearerTypeMobileData);
+ || availableBearerTypes().testFlag(BearerTypeWiFi)
+ || availableBearerTypes().testFlag(BearerTypeMobileData);
case Connection::BearerTypeBluetooth:
return availableBearerTypes().testFlag(BearerTypeBluetooth);
case Connection::BearerTypeUnknown:
diff --git a/libnymea-app/connection/nymeaconnection.h b/libnymea-app/connection/nymeaconnection.h
index f805c25f..43c6d323 100644
--- a/libnymea-app/connection/nymeaconnection.h
+++ b/libnymea-app/connection/nymeaconnection.h
@@ -30,9 +30,14 @@
#include
#include
#include
-#include
#include
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#include
+#else
+#include
+#endif
+
#include "nymeahost.h"
class NymeaTransportInterface;
diff --git a/libnymea-app/connection/nymeahost.cpp b/libnymea-app/connection/nymeahost.cpp
index 341baa9a..2f9626a8 100644
--- a/libnymea-app/connection/nymeahost.cpp
+++ b/libnymea-app/connection/nymeahost.cpp
@@ -126,7 +126,7 @@ Connections::~Connections()
int Connections::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_connections.count();
+ return static_cast(m_connections.count());
}
QVariant Connections::data(const QModelIndex &index, int role) const
@@ -159,10 +159,10 @@ Connection* Connections::find(const QUrl &url) const
void Connections::addConnection(Connection *connection)
{
connection->setParent(this);
- beginInsertRows(QModelIndex(), m_connections.count(), m_connections.count());
+ beginInsertRows(QModelIndex(), static_cast(m_connections.count()), static_cast(m_connections.count()));
m_connections.append(connection);
connect(connection, &Connection::onlineChanged, this, [this, connection]() {
- int idx = m_connections.indexOf(connection);
+ int idx = static_cast(m_connections.indexOf(connection));
if (idx < 0) {
return;
}
@@ -175,7 +175,7 @@ void Connections::addConnection(Connection *connection)
void Connections::removeConnection(Connection *connection)
{
- int idx = m_connections.indexOf(connection);
+ int idx = static_cast(m_connections.indexOf(connection));
if (idx == -1) {
qWarning() << "Cannot remove connections as it's not in this model";
return;
diff --git a/libnymea-app/connection/nymeahosts.cpp b/libnymea-app/connection/nymeahosts.cpp
index 45e11a17..8c821a40 100644
--- a/libnymea-app/connection/nymeahosts.cpp
+++ b/libnymea-app/connection/nymeahosts.cpp
@@ -23,9 +23,8 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "nymeahosts.h"
-#include "connection/discovery/nymeadiscovery.h"
#include "nymeahost.h"
-#include "jsonrpc/jsonrpcclient.h"
+
#include
NymeaHosts::NymeaHosts(QObject *parent) :
@@ -36,7 +35,7 @@ NymeaHosts::NymeaHosts(QObject *parent) :
int NymeaHosts::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_hosts.count();
+ return static_cast(m_hosts.count());
}
QVariant NymeaHosts::data(const QModelIndex &index, int role) const
@@ -66,16 +65,16 @@ void NymeaHosts::addHost(NymeaHost *host)
}
host->setParent(this);
connect(host, &NymeaHost::nameChanged, this, [=](){
- int idx = m_hosts.indexOf(host);
+ int idx = static_cast(m_hosts.indexOf(host));
emit dataChanged(index(idx), index(idx), {NameRole});
});
connect(host, &NymeaHost::versionChanged, this, [=](){
- int idx = m_hosts.indexOf(host);
+ int idx = static_cast(m_hosts.indexOf(host));
emit dataChanged(index(idx), index(idx), {VersionRole});
});
connect(host, &NymeaHost::connectionChanged, this, &NymeaHosts::hostChanged);
- beginInsertRows(QModelIndex(), m_hosts.count(), m_hosts.count());
+ beginInsertRows(QModelIndex(), static_cast(m_hosts.count()), static_cast(m_hosts.count()));
m_hosts.append(host);
endInsertRows();
emit hostAdded(host);
@@ -84,7 +83,7 @@ void NymeaHosts::addHost(NymeaHost *host)
void NymeaHosts::removeHost(NymeaHost *host)
{
- int idx = m_hosts.indexOf(host);
+ int idx = static_cast(m_hosts.indexOf(host));
if (idx == -1) {
qWarning() << "Cannot remove NymeaHost" << host << "as its not in the model";
return;
@@ -162,138 +161,3 @@ QHash NymeaHosts::roleNames() const
roles[VersionRole] = "version";
return roles;
}
-
-NymeaHostsFilterModel::NymeaHostsFilterModel(QObject *parent):
- QSortFilterProxyModel(parent)
-{
-
-}
-
-NymeaDiscovery *NymeaHostsFilterModel::discovery() const
-{
- return m_nymeaDiscovery;
-}
-
-void NymeaHostsFilterModel::setDiscovery(NymeaDiscovery *discovery)
-{
- if (m_nymeaDiscovery != discovery) {
- m_nymeaDiscovery = discovery;
- setSourceModel(discovery->nymeaHosts());
- emit discoveryChanged();
-
- connect(discovery->nymeaHosts(), &NymeaHosts::hostChanged, this, [this](){
-// qDebug() << "Host Changed!";
- invalidateFilter();
- emit countChanged();
- });
-
- emit countChanged();
- }
-}
-
-JsonRpcClient *NymeaHostsFilterModel::jsonRpcClient() const
-{
- return m_jsonRpcClient;
-}
-
-void NymeaHostsFilterModel::setJsonRpcClient(JsonRpcClient *jsonRpcClient)
-{
- if (m_jsonRpcClient != jsonRpcClient) {
- m_jsonRpcClient = jsonRpcClient;
- emit jsonRpcClientChanged();
-
- connect(m_jsonRpcClient, &JsonRpcClient::availableBearerTypesChanged, this, [this](){
-// qDebug() << "Bearer Types Changed!";
- invalidateFilter();
- emit countChanged();
- });
-
- invalidateFilter();
- emit countChanged();
- }
-}
-
-bool NymeaHostsFilterModel::showUnreachableBearers() const
-{
- return m_showUneachableBearers;
-}
-
-void NymeaHostsFilterModel::setShowUnreachableBearers(bool showUnreachableBearers)
-{
- if (m_showUneachableBearers != showUnreachableBearers) {
- m_showUneachableBearers = showUnreachableBearers;
- emit showUnreachableBearersChanged();
- invalidateFilter();
- emit countChanged();
- }
-}
-
-bool NymeaHostsFilterModel::showUnreachableHosts() const
-{
- return m_showUneachableHosts;
-}
-
-void NymeaHostsFilterModel::setShowUnreachableHosts(bool showUnreachableHosts)
-{
- if (m_showUneachableHosts != showUnreachableHosts) {
- m_showUneachableHosts = showUnreachableHosts;
- emit showUnreachableHostsChanged();
- invalidateFilter();
- emit countChanged();
- }
-}
-
-NymeaHost *NymeaHostsFilterModel::get(int index) const
-{
- return m_nymeaDiscovery->nymeaHosts()->get(mapToSource(this->index(index, 0)).row());
-}
-
-bool NymeaHostsFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
-{
- Q_UNUSED(sourceParent)
- NymeaHost *host = m_nymeaDiscovery->nymeaHosts()->get(sourceRow);
- if (m_jsonRpcClient && !m_showUneachableBearers) {
- bool hasReachableConnection = false;
- for (int i = 0; i < host->connections()->rowCount(); i++) {
-// qCritical() << "checking host for available bearer" << host->name() << host->connections()->get(i)->url() << "available bearer types:" << m_jsonRpcClient->availableBearerTypes() << "hosts bearer types" << host->connections()->get(i)->bearerType();
- // Either enable a connection when the Bearer type is directly available
- switch (host->connections()->get(i)->bearerType()) {
- case Connection::BearerTypeLan:
- hasReachableConnection |= m_jsonRpcClient->availableBearerTypes().testFlag(NymeaConnection::BearerTypeEthernet);
- hasReachableConnection |= m_jsonRpcClient->availableBearerTypes().testFlag(NymeaConnection::BearerTypeWiFi);
- break;
- case Connection::BearerTypeWan:
- case Connection::BearerTypeCloud:
- hasReachableConnection |= m_jsonRpcClient->availableBearerTypes().testFlag(NymeaConnection::BearerTypeEthernet);
- hasReachableConnection |= m_jsonRpcClient->availableBearerTypes().testFlag(NymeaConnection::BearerTypeWiFi);
- hasReachableConnection |= m_jsonRpcClient->availableBearerTypes().testFlag(NymeaConnection::BearerTypeMobileData);
- break;
- case Connection::BearerTypeBluetooth:
- hasReachableConnection |= m_jsonRpcClient->availableBearerTypes().testFlag(NymeaConnection::BearerTypeBluetooth);
- break;
- case Connection::BearerTypeUnknown:
- case Connection::BearerTypeLoopback:
- hasReachableConnection = true;
- break;
- case Connection::BearerTypeNone:
- break;
- }
- }
- if (!hasReachableConnection) {
- return false;
- }
- }
- if (!m_showUneachableHosts) {
- bool isOnline = false;
- for (int i = 0; i < host->connections()->rowCount(); i++) {
- if (host->connections()->get(i)->online()) {
- isOnline = true;
- break;
- }
- }
- if (!isOnline) {
- return false;
- }
- }
- return true;
-}
diff --git a/libnymea-app/connection/nymeahosts.h b/libnymea-app/connection/nymeahosts.h
index 725048bb..6ad61ad6 100644
--- a/libnymea-app/connection/nymeahosts.h
+++ b/libnymea-app/connection/nymeahosts.h
@@ -29,10 +29,11 @@
#include
#include
#include
+
#include "nymeahost.h"
-class NymeaDiscovery;
class JsonRpcClient;
+class NymeaDiscovery;
class NymeaHosts : public QAbstractListModel
{
@@ -76,49 +77,49 @@ private:
QList m_hosts;
};
-class NymeaHostsFilterModel: public QSortFilterProxyModel
-{
- Q_OBJECT
- Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
- Q_PROPERTY(NymeaDiscovery* discovery READ discovery WRITE setDiscovery NOTIFY discoveryChanged)
- Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient WRITE setJsonRpcClient NOTIFY jsonRpcClientChanged)
- Q_PROPERTY(bool showUnreachableBearers READ showUnreachableBearers WRITE setShowUnreachableBearers NOTIFY showUnreachableBearersChanged)
- Q_PROPERTY(bool showUnreachableHosts READ showUnreachableHosts WRITE setShowUnreachableHosts NOTIFY showUnreachableHostsChanged)
+// class NymeaHostsFilterModel: public QSortFilterProxyModel
+// {
+// Q_OBJECT
+// Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
+// Q_PROPERTY(NymeaDiscovery* discovery READ discovery WRITE setDiscovery NOTIFY discoveryChanged)
+// Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient WRITE setJsonRpcClient NOTIFY jsonRpcClientChanged)
+// Q_PROPERTY(bool showUnreachableBearers READ showUnreachableBearers WRITE setShowUnreachableBearers NOTIFY showUnreachableBearersChanged)
+// Q_PROPERTY(bool showUnreachableHosts READ showUnreachableHosts WRITE setShowUnreachableHosts NOTIFY showUnreachableHostsChanged)
-public:
- NymeaHostsFilterModel(QObject *parent = nullptr);
+// public:
+// NymeaHostsFilterModel(QObject *parent = nullptr);
- NymeaDiscovery *discovery() const;
- void setDiscovery(NymeaDiscovery *discovery);
+// NymeaDiscovery *discovery() const;
+// void setDiscovery(NymeaDiscovery *discovery);
- JsonRpcClient *jsonRpcClient() const;
- void setJsonRpcClient(JsonRpcClient* jsonRpcClient);
+// JsonRpcClient *jsonRpcClient() const;
+// void setJsonRpcClient(JsonRpcClient* jsonRpcClient);
- bool showUnreachableBearers() const;
- void setShowUnreachableBearers(bool showUnreachableBearers);
+// bool showUnreachableBearers() const;
+// void setShowUnreachableBearers(bool showUnreachableBearers);
- bool showUnreachableHosts() const;
- void setShowUnreachableHosts(bool showUnreachableHosts);
+// bool showUnreachableHosts() const;
+// void setShowUnreachableHosts(bool showUnreachableHosts);
- Q_INVOKABLE NymeaHost* get(int index) const;
+// Q_INVOKABLE NymeaHost *get(int index) const;
-signals:
- void countChanged();
- void discoveryChanged();
- void jsonRpcClientChanged();
- void showUnreachableBearersChanged();
- void showUnreachableHostsChanged();
+// signals:
+// void countChanged();
+// void discoveryChanged();
+// void jsonRpcClientChanged();
+// void showUnreachableBearersChanged();
+// void showUnreachableHostsChanged();
-protected:
- bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
+// protected:
+// bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
-private:
- NymeaDiscovery *m_nymeaDiscovery = nullptr;
- JsonRpcClient *m_jsonRpcClient = nullptr;
+// private:
+// NymeaDiscovery *m_nymeaDiscovery = nullptr;
+// JsonRpcClient *m_jsonRpcClient = nullptr;
- bool m_showUneachableBearers = false;
- bool m_showUneachableHosts = false;
+// bool m_showUneachableBearers = false;
+// bool m_showUneachableHosts = false;
-};
+// };
#endif // NYMEAHOSTS_H
diff --git a/libnymea-app/connection/nymeatransportinterface.h b/libnymea-app/connection/nymeatransportinterface.h
index 801bced5..980fd1b6 100644
--- a/libnymea-app/connection/nymeatransportinterface.h
+++ b/libnymea-app/connection/nymeatransportinterface.h
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
class NymeaTransportInterface;
diff --git a/libnymea-app/connection/tcpsockettransport.cpp b/libnymea-app/connection/tcpsockettransport.cpp
index b7e8b13d..92346ec3 100644
--- a/libnymea-app/connection/tcpsockettransport.cpp
+++ b/libnymea-app/connection/tcpsockettransport.cpp
@@ -38,8 +38,7 @@ TcpSocketTransport::TcpSocketTransport(QObject *parent) : NymeaTransportInterfac
typedef void (QSslSocket:: *sslErrorsSignal)(const QList &);
QObject::connect(&m_socket, static_cast(&QSslSocket::sslErrors), this, &TcpSocketTransport::sslErrors);
QObject::connect(&m_socket, &QSslSocket::readyRead, this, &TcpSocketTransport::socketReadyRead);
- typedef void (QSslSocket:: *errorSignal)(QAbstractSocket::SocketError);
- QObject::connect(&m_socket, static_cast(&QSslSocket::error), this, &TcpSocketTransport::error);
+ QObject::connect(&m_socket, &QSslSocket::errorOccurred, this, &TcpSocketTransport::error);
QObject::connect(&m_socket, &QSslSocket::stateChanged, this, &TcpSocketTransport::onSocketStateChanged);
}
diff --git a/libnymea-app/connection/tunnelproxytransport.cpp b/libnymea-app/connection/tunnelproxytransport.cpp
index cde06016..3ff9ffa1 100644
--- a/libnymea-app/connection/tunnelproxytransport.cpp
+++ b/libnymea-app/connection/tunnelproxytransport.cpp
@@ -59,7 +59,7 @@ bool TunnelProxyTransport::connect(const QUrl &url)
serverUrl.setScheme(url.scheme() == "tunnels" ? "ssl" : "tcp");
serverUrl.setHost(url.host());
serverUrl.setPort(url.port());
- QUuid serverUuid = QUrlQuery(url).queryItemValue("uuid");
+ QUuid serverUuid(QUrlQuery(url).queryItemValue("uuid"));
return m_remoteConnection->connectServer(serverUrl, serverUuid);
}
diff --git a/libnymea-app/energy/energylogs.cpp b/libnymea-app/energy/energylogs.cpp
index 2ae67be8..745ae0a7 100644
--- a/libnymea-app/energy/energylogs.cpp
+++ b/libnymea-app/energy/energylogs.cpp
@@ -183,7 +183,7 @@ void EnergyLogs::componentComplete()
int EnergyLogs::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_list.count();
+ return static_cast(m_list.count());
}
QVariant EnergyLogs::data(const QModelIndex &index, int role) const
@@ -267,7 +267,7 @@ QList EnergyLogs::entries() const
void EnergyLogs::appendEntry(EnergyLogEntry *entry, double minValue, double maxValue)
{
entry->setParent(this);
- int index = m_list.count();
+ int index = static_cast(m_list.count());
beginInsertRows(QModelIndex(), index, index);
m_list.append(entry);
endInsertRows();
@@ -286,8 +286,8 @@ void EnergyLogs::appendEntry(EnergyLogEntry *entry, double minValue, double maxV
void EnergyLogs::appendEntries(const QList &entries)
{
- int index = m_list.count();
- beginInsertRows(QModelIndex(), index, index + entries.count());
+ int index = static_cast(m_list.count());
+ beginInsertRows(QModelIndex(), index, index + static_cast(entries.count()));
for (int i = 0; i < entries.count(); i++) {
EnergyLogEntry* entry = entries.at(i);
entry->setParent(this);
@@ -316,7 +316,7 @@ void EnergyLogs::getLogsResponse(int commandId, const QVariantMap ¶ms)
if (!entries.isEmpty()) {
if (m_list.isEmpty()) {
// qCDebug(dcEnergyLogs()) << "Energy logs received" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
- beginInsertRows(QModelIndex(), 0, entries.count());
+ beginInsertRows(QModelIndex(), 0, static_cast(entries.count()));
m_list.append(entries);
endInsertRows();
emit entriesAdded(0, entries);
@@ -328,7 +328,7 @@ void EnergyLogs::getLogsResponse(int commandId, const QVariantMap ¶ms)
} else if (entries.first()->timestamp() < m_list.first()->timestamp()) {
if (entries.last()->timestamp().addSecs(m_sampleRate * 60) == m_list.first()->timestamp()) {
- beginInsertRows(QModelIndex(), 0, entries.count());
+ beginInsertRows(QModelIndex(), 0, static_cast(entries.count()));
m_list = entries + m_list;
endInsertRows();
emit entriesAdded(0, entries);
@@ -348,7 +348,7 @@ void EnergyLogs::getLogsResponse(int commandId, const QVariantMap ¶ms)
// If the mismatch is in the visible area, we'll discard everything and fetch again
// Else if the mismatch is outside the visible area, we'll just discard the old data and work with what we received
if (entries.first()->timestamp() <= m_startTime && entries.last()->timestamp() >= m_endTime) {
- beginInsertRows(QModelIndex(), 0, entries.count());
+ beginInsertRows(QModelIndex(), 0, static_cast(entries.count()));
m_list.append(entries);
endInsertRows();
emit entriesAdded(0, entries);
@@ -363,8 +363,8 @@ void EnergyLogs::getLogsResponse(int commandId, const QVariantMap ¶ms)
}
} else if (entries.first()->timestamp().addSecs(-m_sampleRate * 60) == m_list.last()->timestamp()) {
- int index = m_list.count();
- beginInsertRows(QModelIndex(), m_list.count(), m_list.count() + entries.count());
+ int index = static_cast(m_list.count());
+ beginInsertRows(QModelIndex(), index, index + static_cast(entries.count()));
m_list.append(entries);
endInsertRows();
emit entriesAdded(index, entries);
@@ -379,7 +379,7 @@ void EnergyLogs::getLogsResponse(int commandId, const QVariantMap ¶ms)
} else {
// Start of fetched entries does not line up with end of existing entries. Discarding existing entries
clear();
- beginInsertRows(QModelIndex(), 0, entries.count());
+ beginInsertRows(QModelIndex(), 0, static_cast(entries.count()));
m_list.append(entries);
endInsertRows();
emit entriesAdded(0, entries);
@@ -420,9 +420,11 @@ void EnergyLogs::notificationReceivedInternal(const QVariantMap &data)
void EnergyLogs::clear()
{
- int count = m_list.count();
+ int count = static_cast(m_list.count());
beginResetModel();
- qDeleteAll(m_list);
+ foreach (EnergyLogEntry *entry, m_list)
+ entry->deleteLater();
+
m_list.clear();
endResetModel();
emit countChanged();
@@ -486,4 +488,3 @@ void EnergyLogs::fetchLogs()
qCDebug(dcEnergyLogs()) << "Fetching energy logs:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
m_engine->jsonRpcClient()->sendCommand("Energy.Get" + logsName(), params, this, "getLogsResponse");
}
-
diff --git a/libnymea-app/energy/energymanager.h b/libnymea-app/energy/energymanager.h
index cbeda3ad..3366a85f 100644
--- a/libnymea-app/energy/energymanager.h
+++ b/libnymea-app/energy/energymanager.h
@@ -28,7 +28,7 @@
#include
#include
-class Engine;
+#include "engine.h"
class EnergyManager : public QObject
{
diff --git a/libnymea-app/engine.cpp b/libnymea-app/engine.cpp
index 1d42b9aa..9e39d24c 100644
--- a/libnymea-app/engine.cpp
+++ b/libnymea-app/engine.cpp
@@ -48,9 +48,6 @@ Engine::Engine(QObject *parent) :
connect(m_thingManager, &ThingManager::fetchingDataChanged, this, &Engine::onThingManagerFetchingChanged);
- connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, [this]() {
- qDebug() << "JSONRpc connected changed:" << m_jsonRpcClient->connected();
- });
}
ThingManager *Engine::thingManager() const
diff --git a/libnymea-app/engine.h b/libnymea-app/engine.h
index ce0a4b22..6f551c46 100644
--- a/libnymea-app/engine.h
+++ b/libnymea-app/engine.h
@@ -31,13 +31,12 @@
#include "connection/nymeatransportinterface.h"
#include "jsonrpc/jsonrpcclient.h"
-class RuleManager;
-class ScriptManager;
-class LogManager;
-class TagsManager;
-class NymeaConfiguration;
-class SystemController;
-class NetworkManager;
+#include "rulemanager.h"
+#include "scriptmanager.h"
+#include "logmanager.h"
+#include "tagsmanager.h"
+#include "configuration/nymeaconfiguration.h"
+#include "system/systemcontroller.h"
class Engine : public QObject
{
@@ -78,4 +77,6 @@ private slots:
};
+Q_DECLARE_METATYPE(Engine*)
+
#endif // ENGINE_H
diff --git a/libnymea-app/interfacesmodel.cpp b/libnymea-app/interfacesmodel.cpp
index 8e1e9880..c0293659 100644
--- a/libnymea-app/interfacesmodel.cpp
+++ b/libnymea-app/interfacesmodel.cpp
@@ -36,7 +36,7 @@ InterfacesModel::InterfacesModel(QObject *parent):
int InterfacesModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_interfaces.count();
+ return static_cast(m_interfaces.count());
}
QVariant InterfacesModel::data(const QModelIndex &index, int role) const
@@ -154,10 +154,10 @@ void InterfacesModel::syncInterfaces()
}
}
- qWarning() << "syncing for interfaces:" << m_shownInterfaces;
+ // qWarning() << "syncing for interfaces:" << m_shownInterfaces;
QStringList interfacesInSource;
foreach (ThingClass *dc, thingClasses) {
-// qWarning() << "thing" <name() << "has interfaces" << dc->interfaces();
+ // qWarning() << "thing" <name() << "has interfaces" << dc->interfaces();
bool isInShownIfaces = false;
foreach (const QString &interface, dc->interfaces()) {
@@ -168,7 +168,7 @@ void InterfacesModel::syncInterfaces()
if (!interfacesInSource.contains(interface)) {
interfacesInSource.append(interface);
}
-// qWarning() << "yes" << interface;
+ // qWarning() << "yes" << interface;
isInShownIfaces = true;
}
if (m_showUncategorized && !isInShownIfaces && !interfacesInSource.contains("uncategorized")) {
@@ -185,13 +185,13 @@ void InterfacesModel::syncInterfaces()
interfacesToAdd.removeAll(interface);
}
foreach (const QString &interface, interfacesToRemove) {
- int idx = m_interfaces.indexOf(interface);
+ int idx = static_cast(m_interfaces.indexOf(interface));
beginRemoveRows(QModelIndex(), idx, idx);
m_interfaces.takeAt(idx);
endRemoveRows();
}
if (!interfacesToAdd.isEmpty()) {
- beginInsertRows(QModelIndex(), m_interfaces.count(), m_interfaces.count() + interfacesToAdd.count() - 1);
+ beginInsertRows(QModelIndex(), static_cast(m_interfaces.count()), static_cast(m_interfaces.count()) + static_cast(interfacesToAdd.count()) - 1);
m_interfaces.append(interfacesToAdd);
endInsertRows();
}
diff --git a/libnymea-app/interfacesmodel.h b/libnymea-app/interfacesmodel.h
index fe2a6f8e..cd7d20e3 100644
--- a/libnymea-app/interfacesmodel.h
+++ b/libnymea-app/interfacesmodel.h
@@ -29,9 +29,8 @@
#include
#include "things.h"
-
-class Engine;
-class ThingsProxy;
+#include "engine.h"
+#include "thingsproxy.h"
class InterfacesModel : public QAbstractListModel
{
diff --git a/libnymea-app/jsonrpc/jsonrpcclient.cpp b/libnymea-app/jsonrpc/jsonrpcclient.cpp
index b50efae8..4f637bfd 100644
--- a/libnymea-app/jsonrpc/jsonrpcclient.cpp
+++ b/libnymea-app/jsonrpc/jsonrpcclient.cpp
@@ -76,6 +76,7 @@ void JsonRpcClient::registerNotificationHandler(QObject *handler, const QString
}
m_notificationHandlers.insert(nameSpace, handler);
m_notificationHandlerMethods.insert(handler, method);
+
setNotificationsEnabled();
}
@@ -153,7 +154,7 @@ void JsonRpcClient::disconnectFromHost()
m_connection->disconnectFromHost();
}
-void JsonRpcClient::acceptCertificate(const QString &serverUuid, const QByteArray &pem)
+void JsonRpcClient::acceptCertificate(const QUuid &serverUuid, const QByteArray &pem)
{
qDebug() << "Pinning new certificate for" << serverUuid << pem;
storePem(serverUuid, pem);
@@ -199,7 +200,7 @@ void JsonRpcClient::notificationReceived(const QVariantMap &data)
m_token = data.value("params").toMap().value("token").toByteArray();
QSettings settings;
settings.beginGroup("jsonTokens");
- settings.setValue(m_connection->currentHost()->uuid().toString(), m_token);
+ settings.setValue(m_serverUuid.toString(), m_token);
settings.endGroup();
m_initialSetupRequired = false;
@@ -305,9 +306,9 @@ QString JsonRpcClient::jsonRpcVersion() const
return m_jsonRpcVersion.toString();
}
-QString JsonRpcClient::serverUuid() const
+QUuid JsonRpcClient::serverUuid() const
{
- return m_connection && m_connection->currentHost() ? m_connection->currentHost()->uuid().toString() : "";
+ return m_connection && m_connection->currentHost() ? m_connection->currentHost()->uuid() : QUuid();
}
QString JsonRpcClient::serverName() const
@@ -394,7 +395,7 @@ void JsonRpcClient::processAuthenticate(int /*commandId*/, const QVariantMap &da
emit permissionsChanged();
QSettings settings;
settings.beginGroup("jsonTokens");
- settings.setValue(m_connection->currentHost()->uuid().toString(), m_token);
+ settings.setValue(m_serverUuid.toString(), m_token);
settings.endGroup();
emit authenticationRequiredChanged();
@@ -481,8 +482,8 @@ void JsonRpcClient::sendRequest(const QVariantMap &request)
bool JsonRpcClient::loadPem(const QUuid &serverUud, QByteArray &pem)
{
- QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/sslcerts/");
- QFile certFile(dir.absoluteFilePath(serverUud.toString().remove(QRegExp("[{}]")) + ".pem"));
+ QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/sslcerts/");
+ QFile certFile(dir.absoluteFilePath(serverUud.toString().remove(QRegularExpression("[{}]")) + ".pem"));
if (!certFile.open(QFile::ReadOnly)) {
return false;
}
@@ -493,11 +494,11 @@ bool JsonRpcClient::loadPem(const QUuid &serverUud, QByteArray &pem)
bool JsonRpcClient::storePem(const QUuid &serverUuid, const QByteArray &pem)
{
- QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/sslcerts/");
+ QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/sslcerts/");
if (!dir.exists()) {
- dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/sslcerts/");
+ dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/sslcerts/");
}
- QFile certFile(dir.absoluteFilePath(serverUuid.toString().remove(QRegExp("[{}]")) + ".pem"));
+ QFile certFile(dir.absoluteFilePath(serverUuid.toString().remove(QRegularExpression("[{}]")) + ".pem"));
if (!certFile.open(QFile::WriteOnly | QFile::Truncate)) {
return false;
}
@@ -549,7 +550,7 @@ void JsonRpcClient::dataReceived(const QByteArray &data)
// qDebug() << "JsonRpcClient: received data:" << qUtf8Printable(data);
m_receiveBuffer.append(data);
- int splitIndex = m_receiveBuffer.indexOf("}\n{") + 1;
+ int splitIndex = static_cast(m_receiveBuffer.indexOf("}\n{")) + 1;
if (splitIndex <= 0) {
splitIndex = m_receiveBuffer.length();
}
@@ -600,7 +601,7 @@ void JsonRpcClient::dataReceived(const QByteArray &data)
m_token.clear();
QSettings settings;
settings.beginGroup("jsonTokens");
- settings.setValue(serverUuid(), m_token);
+ settings.setValue(m_serverUuid.toString(), m_token);
settings.endGroup();
emit authenticationRequiredChanged();
m_authenticated = false;
@@ -651,12 +652,16 @@ void JsonRpcClient::helloReply(int /*commandId*/, const QVariantMap ¶ms)
m_pushButtonAuthAvailable = params.value("pushButtonAuthAvailable").toBool();
emit pushButtonAuthAvailableChanged();
+ m_serverUuid = params.value("uuid").toUuid();
m_serverVersion = params.value("version").toString();
QUuid serverUuid = params.value("uuid").toUuid();
QString name = params.value("name").toString();
m_experiences.clear();
foreach (const QVariant &experience, params.value("experiences").toList()) {
- m_experiences.insert(experience.toMap().value("name").toString(), experience.toMap().value("version").toString());
+ QString experienceName = experience.toMap().value("name").toString();
+ QString experienceVersion = experience.toMap().value("version").toString();
+ m_experiences.insert(experienceName, experienceVersion);
+ qCInfo(dcJsonRpc()) << "Experience available:" << experienceName << experienceVersion;
}
QString protoVersionString = params.value("protocol version").toString();
@@ -721,7 +726,7 @@ void JsonRpcClient::helloReply(int /*commandId*/, const QVariantMap ¶ms)
// Reject the connection until the UI explicitly accepts this...
m_connection->disconnectFromHost();
- emit verifyConnectionCertificate(serverUuid.toString(), issuerInfo, certificate.toPem());
+ emit verifyConnectionCertificate(m_serverUuid.toString(), issuerInfo, certificate.toPem());
return;
}
qCInfo(dcJsonRpc()) << "This connections certificate is trusted.";
@@ -769,7 +774,7 @@ void JsonRpcClient::helloReply(int /*commandId*/, const QVariantMap ¶ms)
// Reload the token, now that we're certain about the server uuid.
QSettings settings;
settings.beginGroup("jsonTokens");
- m_token = settings.value(serverUuid.toString()).toByteArray();
+ m_token = settings.value(m_serverUuid.toString()).toByteArray();
settings.endGroup();
emit authenticationRequiredChanged();
diff --git a/libnymea-app/jsonrpc/jsonrpcclient.h b/libnymea-app/jsonrpc/jsonrpcclient.h
index 4b9fbf9e..9cd4cabd 100644
--- a/libnymea-app/jsonrpc/jsonrpcclient.h
+++ b/libnymea-app/jsonrpc/jsonrpcclient.h
@@ -51,7 +51,7 @@ class JsonRpcClient : public QObject
Q_PROPERTY(bool authenticated READ authenticated NOTIFY authenticatedChanged)
Q_PROPERTY(QString serverVersion READ serverVersion NOTIFY handshakeReceived)
Q_PROPERTY(QString jsonRpcVersion READ jsonRpcVersion NOTIFY handshakeReceived)
- Q_PROPERTY(QString serverUuid READ serverUuid NOTIFY handshakeReceived)
+ Q_PROPERTY(QUuid serverUuid READ serverUuid NOTIFY handshakeReceived)
Q_PROPERTY(QString serverName READ serverName NOTIFY serverNameChanged)
Q_PROPERTY(QString serverQtVersion READ serverQtVersion NOTIFY serverQtVersionChanged)
Q_PROPERTY(QString serverQtBuildVersion READ serverQtBuildVersion NOTIFY serverQtVersionChanged)
@@ -85,7 +85,7 @@ public:
QString serverVersion() const;
QString jsonRpcVersion() const;
- QString serverUuid() const;
+ QUuid serverUuid() const;
QString serverName() const;
QString serverQtVersion();
QString serverQtBuildVersion();
@@ -94,7 +94,7 @@ public:
// ui methods
Q_INVOKABLE void connectToHost(NymeaHost *host, Connection *connection = nullptr);
Q_INVOKABLE void disconnectFromHost();
- Q_INVOKABLE void acceptCertificate(const QString &serverUuid, const QByteArray &pem);
+ Q_INVOKABLE void acceptCertificate(const QUuid &serverUuid, const QByteArray &pem);
Q_INVOKABLE bool tokenExists(const QString &serverUuid) const;
Q_INVOKABLE void addToken(const QString &serverUuid, const QByteArray &token);
@@ -154,6 +154,7 @@ private:
bool m_pushButtonAuthAvailable = false;
bool m_authenticated = false;
int m_pendingPushButtonTransaction = -1;
+ QUuid m_serverUuid;
QVersionNumber m_jsonRpcVersion;
QString m_serverVersion;
QString m_serverQtVersion;
diff --git a/libnymea-app/libnymea-app-core.h b/libnymea-app/libnymea-app-core.h
index 64761ecc..89498a89 100644
--- a/libnymea-app/libnymea-app-core.h
+++ b/libnymea-app/libnymea-app-core.h
@@ -28,6 +28,7 @@
#include "engine.h"
#include "connection/nymeahosts.h"
#include "connection/nymeahost.h"
+#include "models/nymeahostsfiltermodel.h"
#include "connection/discovery/nymeadiscovery.h"
#include "vendorsproxy.h"
#include "thingclassesproxy.h"
@@ -371,7 +372,7 @@ void registerQmlTypes() {
qmlRegisterType(uri, 1, 0, "ScriptAutoSaver");
qmlRegisterType(uri, 1, 0, "UserManager");
- qmlRegisterUncreatableType(uri, 1, 0, "UserInfo", "Get it from UserManager");
+ qmlRegisterType(uri, 1, 0, "UserInfo");
qmlRegisterUncreatableType(uri, 1, 0, "TokenInfo", "Get it from TokenInfos");
qmlRegisterUncreatableType(uri, 1, 0, "TokenInfos", "Get it from UserManager");
qmlRegisterUncreatableType(uri, 1, 0, "Users", "Get it from UserManager");
diff --git a/libnymea-app/libnymea-app.pri b/libnymea-app/libnymea-app.pri
index f293f761..693acf2c 100644
--- a/libnymea-app/libnymea-app.pri
+++ b/libnymea-app/libnymea-app.pri
@@ -11,7 +11,6 @@
include(../nymea-remoteproxy/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri)
-
QT -= gui
QT += network websockets bluetooth charts quick
@@ -30,6 +29,7 @@ SOURCES += \
$$PWD/models/boolseriesadapter.cpp \
$$PWD/models/newlogentry.cpp \
$$PWD/models/newlogsmodel.cpp \
+ $$PWD/models/nymeahostsfiltermodel.cpp \
$$PWD/models/scriptsproxymodel.cpp \
$$PWD/pluginconfigmanager.cpp \
$$PWD/serverdebug/serverdebugmanager.cpp \
@@ -199,6 +199,7 @@ HEADERS += \
$$PWD/models/boolseriesadapter.h \
$$PWD/models/newlogentry.h \
$$PWD/models/newlogsmodel.h \
+ $$PWD/models/nymeahostsfiltermodel.h \
$$PWD/models/scriptsproxymodel.h \
$$PWD/pluginconfigmanager.h \
$$PWD/serverdebug/serverdebugmanager.h \
diff --git a/libnymea-app/modbus/modbusrtumanager.cpp b/libnymea-app/modbus/modbusrtumanager.cpp
index 0ba1246b..aed595ac 100644
--- a/libnymea-app/modbus/modbusrtumanager.cpp
+++ b/libnymea-app/modbus/modbusrtumanager.cpp
@@ -148,7 +148,7 @@ ModbusRtuMaster *ModbusRtuManager::unpackModbusRtuMaster(const QVariantMap &modb
void ModbusRtuManager::notificationReceived(const QVariantMap ¬ification)
{
QString notificationString = notification.value("notification").toString();
- qDebug() << "Received notification" << notificationString << endl << notification;
+ qDebug() << "Received notification" << notificationString << Qt::endl << notification;
if (notificationString == "ModbusRtu.SerialPortAdded") {
QVariantMap serialPortMap = notification.value("params").toMap().value("serialPort").toMap();
m_serialPorts->addSerialPort(SerialPort::unpackSerialPort(serialPortMap, m_serialPorts));
diff --git a/libnymea-app/modbus/modbusrtumanager.h b/libnymea-app/modbus/modbusrtumanager.h
index 637a98df..4e64e8d9 100644
--- a/libnymea-app/modbus/modbusrtumanager.h
+++ b/libnymea-app/modbus/modbusrtumanager.h
@@ -29,10 +29,10 @@
#include "types/serialports.h"
-class Engine;
-class JsonRpcClient;
+#include "engine.h"
+#include "modbusrtumasters.h"
+
class ModbusRtuMaster;
-class ModbusRtuMasters;
class ModbusRtuManager : public QObject
{
diff --git a/libnymea-app/modbus/modbusrtumasters.cpp b/libnymea-app/modbus/modbusrtumasters.cpp
index ec297d33..a1755836 100644
--- a/libnymea-app/modbus/modbusrtumasters.cpp
+++ b/libnymea-app/modbus/modbusrtumasters.cpp
@@ -37,7 +37,7 @@ QList ModbusRtuMasters::modbusRtuMasters() const
int ModbusRtuMasters::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_modbusRtuMasters.count();
+ return static_cast(m_modbusRtuMasters.count());
}
QVariant ModbusRtuMasters::data(const QModelIndex &index, int role) const
@@ -86,54 +86,54 @@ void ModbusRtuMasters::addModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster)
connect(modbusRtuMaster, &ModbusRtuMaster::serialPortChanged, this, [=](const QString &serialPort) {
Q_UNUSED(serialPort)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleSerialPort});
});
connect(modbusRtuMaster, &ModbusRtuMaster::baudrateChanged, this, [=](qint32 baudrate) {
Q_UNUSED(baudrate)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleBaudrate});
});
connect(modbusRtuMaster, &ModbusRtuMaster::parityChanged, this, [=](SerialPort::SerialPortParity parity) {
Q_UNUSED(parity)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleParity});
});
connect(modbusRtuMaster, &ModbusRtuMaster::dataBitsChanged, this, [=](SerialPort::SerialPortDataBits dataBits) {
Q_UNUSED(dataBits)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleDataBits});
});
connect(modbusRtuMaster, &ModbusRtuMaster::stopBitsChanged, this, [=](SerialPort::SerialPortStopBits stopBites) {
Q_UNUSED(stopBites)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleStopBits});
});
connect(modbusRtuMaster, &ModbusRtuMaster::numberOfRetriesChanged, this, [=](uint numberOfRetries) {
Q_UNUSED(numberOfRetries)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleNumberOfRetries});
});
connect(modbusRtuMaster, &ModbusRtuMaster::timeoutChanged, this, [=](uint timeout) {
Q_UNUSED(timeout)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleTimeout});
});
connect(modbusRtuMaster, &ModbusRtuMaster::connectedChanged, this, [=](bool connected) {
Q_UNUSED(connected)
- QModelIndex idx = index(m_modbusRtuMasters.indexOf(modbusRtuMaster), 0);
+ QModelIndex idx = index(static_cast(m_modbusRtuMasters.indexOf(modbusRtuMaster)), 0);
emit dataChanged(idx, idx, {RoleConnected});
});
- beginInsertRows(QModelIndex(), m_modbusRtuMasters.count(), m_modbusRtuMasters.count());
+ beginInsertRows(QModelIndex(), static_cast(m_modbusRtuMasters.count()), static_cast(m_modbusRtuMasters.count()));
m_modbusRtuMasters.append(modbusRtuMaster);
endInsertRows();
@@ -156,7 +156,9 @@ void ModbusRtuMasters::removeModbusRtuMaster(const QUuid &modbusUuid)
void ModbusRtuMasters::clear()
{
beginResetModel();
- qDeleteAll(m_modbusRtuMasters);
+ foreach (ModbusRtuMaster *master, m_modbusRtuMasters)
+ master->deleteLater();
+
m_modbusRtuMasters.clear();
endResetModel();
emit countChanged();
diff --git a/libnymea-app/models/barseriesadapter.cpp b/libnymea-app/models/barseriesadapter.cpp
index d7a6e17d..801e7b78 100644
--- a/libnymea-app/models/barseriesadapter.cpp
+++ b/libnymea-app/models/barseriesadapter.cpp
@@ -46,12 +46,12 @@ void BarSeriesAdapter::setLogsModel(LogsModel *logsModel)
}
}
-QtCharts::QAbstractBarSeries *BarSeriesAdapter::barSeries() const
+QAbstractBarSeries *BarSeriesAdapter::barSeries() const
{
return m_barSeries;
}
-void BarSeriesAdapter::setBarSeries(QtCharts::QAbstractBarSeries *barSeries)
+void BarSeriesAdapter::setBarSeries(QAbstractBarSeries *barSeries)
{
if (m_barSeries != barSeries) {
m_barSeries = barSeries;
@@ -78,7 +78,7 @@ void BarSeriesAdapter::update()
if (!m_barSeries || !m_logsModel) {
return;
}
- m_set = new QtCharts::QBarSet(m_barSeries->name());
+ m_set = new QBarSet(m_barSeries->name());
m_barSeries->append(m_set);
for (int i = 0; i < m_logsModel->rowCount(); i++) {
diff --git a/libnymea-app/models/barseriesadapter.h b/libnymea-app/models/barseriesadapter.h
index 18ee35bf..dd9027eb 100644
--- a/libnymea-app/models/barseriesadapter.h
+++ b/libnymea-app/models/barseriesadapter.h
@@ -31,11 +31,15 @@
#include
#include
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+using namespace QtCharts;
+#endif
+
class BarSeriesAdapter : public QObject
{
Q_OBJECT
Q_PROPERTY(LogsModel* logsModel READ logsModel WRITE setLogsModel NOTIFY logsModelChanged)
- Q_PROPERTY(QtCharts::QAbstractBarSeries* barSeries READ barSeries WRITE setBarSeries NOTIFY barSeriesChanged)
+ Q_PROPERTY(QAbstractBarSeries* barSeries READ barSeries WRITE setBarSeries NOTIFY barSeriesChanged)
Q_PROPERTY(Interval interval READ interval WRITE setInterval NOTIFY intervalChanged)
@@ -52,8 +56,8 @@ public:
LogsModel *logsModel() const;
void setLogsModel(LogsModel *logsModel);
- QtCharts::QAbstractBarSeries *barSeries() const;
- void setBarSeries(QtCharts::QAbstractBarSeries *barSeries);
+ QAbstractBarSeries *barSeries() const;
+ void setBarSeries(QAbstractBarSeries *barSeries);
Interval interval() const;
void setInterval(Interval interval);
@@ -80,8 +84,8 @@ private:
};
LogsModel *m_logsModel = nullptr;
- QtCharts::QAbstractBarSeries *m_barSeries = nullptr;
- QtCharts::QBarSet *m_set = nullptr;
+ QAbstractBarSeries *m_barSeries = nullptr;
+ QBarSet *m_set = nullptr;
Interval m_interval = IntervalMinutes;
QList m_timeslots;
diff --git a/libnymea-app/models/boolseriesadapter.cpp b/libnymea-app/models/boolseriesadapter.cpp
index d12f9164..47f31679 100644
--- a/libnymea-app/models/boolseriesadapter.cpp
+++ b/libnymea-app/models/boolseriesadapter.cpp
@@ -46,12 +46,12 @@ void BoolSeriesAdapter::setLogsModel(LogsModel *logsModel)
}
-QtCharts::QXYSeries *BoolSeriesAdapter::xySeries() const
+QXYSeries *BoolSeriesAdapter::xySeries() const
{
return m_series;
}
-void BoolSeriesAdapter::setXySeries(QtCharts::QXYSeries *series)
+void BoolSeriesAdapter::setXySeries(QXYSeries *series)
{
if (m_series != series) {
m_series = series;
@@ -133,14 +133,14 @@ quint64 BoolSeriesAdapter::findIndex(qulonglong timestamp)
// In 99.9% of the cases we'll be prepending (adding live entries) or appending (fetching history)
if (timestamp < m_series->at(m_series->count() - 2).x()) {
- return m_series->count() - 1;
+ return static_cast(m_series->count() - 1);
}
if (timestamp > m_series->at(1).x()) {
return 1;
}
// If for any reason a entry in the middle is added (can't think of one but hey), a binary search will probably do.
- int idx = m_series->count() / 2;
+ int idx = static_cast(m_series->count() / 2);
int range = idx;
int i = 0;
while (true) {
diff --git a/libnymea-app/models/boolseriesadapter.h b/libnymea-app/models/boolseriesadapter.h
index 1ee5720d..a76e9708 100644
--- a/libnymea-app/models/boolseriesadapter.h
+++ b/libnymea-app/models/boolseriesadapter.h
@@ -34,7 +34,7 @@ class BoolSeriesAdapter : public QObject
{
Q_OBJECT
Q_PROPERTY(LogsModel* logsModel READ logsModel WRITE setLogsModel NOTIFY logsModelChanged)
- Q_PROPERTY(QtCharts::QXYSeries* xySeries READ xySeries WRITE setXySeries NOTIFY xySeriesChanged)
+ Q_PROPERTY(QXYSeries* xySeries READ xySeries WRITE setXySeries NOTIFY xySeriesChanged)
Q_PROPERTY(bool inverted READ inverted WRITE setInverted NOTIFY invertedChanged)
@@ -44,8 +44,8 @@ public:
LogsModel* logsModel() const;
void setLogsModel(LogsModel *logsModel);
- QtCharts::QXYSeries* xySeries() const;
- void setXySeries(QtCharts::QXYSeries *series);
+ QXYSeries* xySeries() const;
+ void setXySeries(QXYSeries *series);
bool inverted() const;
void setInverted(bool inverted);
@@ -65,7 +65,7 @@ private:
private:
LogsModel* m_model = nullptr;
- QtCharts::QXYSeries* m_series = nullptr;
+ QXYSeries* m_series = nullptr;
bool m_inverted = false;
};
diff --git a/libnymea-app/models/interfacesproxy.h b/libnymea-app/models/interfacesproxy.h
index 1ee4f3af..559d6474 100644
--- a/libnymea-app/models/interfacesproxy.h
+++ b/libnymea-app/models/interfacesproxy.h
@@ -27,8 +27,8 @@
#include
-class Things;
-class ThingsProxy;
+#include "things.h"
+#include "thingsproxy.h"
class Interface;
class Interfaces;
diff --git a/libnymea-app/models/logsmodel.cpp b/libnymea-app/models/logsmodel.cpp
index 26232259..f02b037f 100644
--- a/libnymea-app/models/logsmodel.cpp
+++ b/libnymea-app/models/logsmodel.cpp
@@ -62,7 +62,7 @@ void LogsModel::setEngine(Engine *engine)
int LogsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_list.count();
+ return static_cast(m_list.count());
}
QVariant LogsModel::data(const QModelIndex &index, int role) const
@@ -150,7 +150,9 @@ void LogsModel::setTypeIds(const QStringList &typeIds)
emit typeIdsChanged();
qCDebug(dcLogEngine()) << "Resetting model because type ids changed";
beginResetModel();
- qDeleteAll(m_list);
+ foreach (LogEntry *entry, m_list)
+ entry->deleteLater();
+
m_list.clear();
m_generatedEntries = 0;
endResetModel();
@@ -247,7 +249,7 @@ LogEntry *LogsModel::findClosest(const QDateTime &dateTime)
return nullptr;
}
int newest = 0;
- int oldest = m_list.count() - 1;
+ int oldest = static_cast(m_list.count()) - 1;
LogEntry *entry = nullptr;
int step = 0;
@@ -312,8 +314,8 @@ void LogsModel::logsReply(int /*commandId*/, const QVariantMap &data)
foreach (const QVariant &logEntryVariant, logEntries) {
QVariantMap entryMap = logEntryVariant.toMap();
QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(entryMap.value("timestamp").toLongLong());
- QString thingId = entryMap.value("thingId").toString();
- QString typeId = entryMap.value("typeId").toString();
+ QUuid thingId = entryMap.value("thingId").toUuid();
+ QUuid typeId = entryMap.value("typeId").toUuid();
QMetaEnum sourceEnum = QMetaEnum::fromType();
LogEntry::LoggingSource loggingSource = static_cast(sourceEnum.keyToValue(entryMap.value("source").toByteArray()));
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType();
@@ -348,7 +350,7 @@ void LogsModel::logsReply(int /*commandId*/, const QVariantMap &data)
return;
}
- beginInsertRows(QModelIndex(), offset, offset + newBlock.count() - 1);
+ beginInsertRows(QModelIndex(), offset, offset + static_cast(newBlock.count()) - 1);
for (int i = 0; i < newBlock.count(); i++) {
// qCDebug(dcLogEngine()) << objectName() << "Inserting: list count" << m_list.count() << "blockSize" << newBlock.count() << "insterting at:" << offset + i;
LogEntry *entry = newBlock.at(i);
diff --git a/libnymea-app/models/logsmodel.h b/libnymea-app/models/logsmodel.h
index 2f9495fa..d3180820 100644
--- a/libnymea-app/models/logsmodel.h
+++ b/libnymea-app/models/logsmodel.h
@@ -29,12 +29,11 @@
#include
#include "types/logentry.h"
+#include "engine.h"
#include
Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
-class Engine;
-
class LogsModel : public QAbstractListModel, public QQmlParserStatus
{
Q_OBJECT
diff --git a/libnymea-app/models/logsmodelng.cpp b/libnymea-app/models/logsmodelng.cpp
index 6723bdec..42ef3f04 100644
--- a/libnymea-app/models/logsmodelng.cpp
+++ b/libnymea-app/models/logsmodelng.cpp
@@ -66,7 +66,7 @@ void LogsModelNg::setEngine(Engine *engine)
int LogsModelNg::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- return m_list.count();
+ return static_cast(m_list.count());
}
QVariant LogsModelNg::data(const QModelIndex &index, int role) const
@@ -161,7 +161,9 @@ void LogsModelNg::setTypeIds(const QStringList &typeIds)
m_typeIds = fixedTypeIds;
emit typeIdsChanged();
beginResetModel();
- qDeleteAll(m_list);
+ foreach (LogEntry *entry, m_list)
+ entry->deleteLater();
+
m_list.clear();
endResetModel();
fetchMore();
@@ -194,12 +196,12 @@ void LogsModelNg::setEndTime(const QDateTime &endTime)
}
}
-QtCharts::QXYSeries *LogsModelNg::graphSeries() const
+QXYSeries *LogsModelNg::graphSeries() const
{
return m_graphSeries;
}
-void LogsModelNg::setGraphSeries(QtCharts::QXYSeries *graphSeries)
+void LogsModelNg::setGraphSeries(QXYSeries *graphSeries)
{
m_graphSeries = graphSeries;
}
@@ -252,7 +254,7 @@ LogEntry *LogsModelNg::findClosest(const QDateTime &dateTime) const
return nullptr;
}
int newest = 0;
- int oldest = m_list.count() - 1;
+ int oldest = static_cast(m_list.count()) - 1;
LogEntry *entry = nullptr;
int step = 0;
@@ -315,8 +317,8 @@ void LogsModelNg::logsReply(int commandId, const QVariantMap &data)
foreach (const QVariant &logEntryVariant, logEntries) {
QVariantMap entryMap = logEntryVariant.toMap();
QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(entryMap.value("timestamp").toLongLong());
- QString thingId = entryMap.value("thingId").toString();
- QString typeId = entryMap.value("typeId").toString();
+ QUuid thingId = entryMap.value("thingId").toUuid();
+ QUuid typeId = entryMap.value("typeId").toUuid();
QMetaEnum sourceEnum = QMetaEnum::fromType();
LogEntry::LoggingSource loggingSource = static_cast(sourceEnum.keyToValue(entryMap.value("source").toByteArray()));
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType();
@@ -338,7 +340,7 @@ void LogsModelNg::logsReply(int commandId, const QVariantMap &data)
return;
}
- beginInsertRows(QModelIndex(), offset, offset + newBlock.count() - 1);
+ beginInsertRows(QModelIndex(), offset, offset + static_cast(newBlock.count()) - 1);
QVariant newMin = m_minValue;
QVariant newMax = m_maxValue;
for (int i = 0; i < newBlock.count(); i++) {
@@ -382,10 +384,10 @@ void LogsModelNg::logsReply(int commandId, const QVariantMap &data)
}
// Adjust min/max
- if (!newMin.isValid() || newMin > entry->value()) {
+ if (!newMin.isValid() || newMin.toDouble() > entry->value().toDouble()) {
newMin = 0;
}
- if (!newMax.isValid() || newMax < entry->value()) {
+ if (!newMax.isValid() || newMax .toDouble() < entry->value().toDouble()) {
newMax = 1;
}
@@ -401,10 +403,10 @@ void LogsModelNg::logsReply(int commandId, const QVariantMap &data)
m_graphSeries->append(QPointF(entry->timestamp().toMSecsSinceEpoch(), value.toReal()));
// Adjust min/max
- if (!newMin.isValid() || newMin > value) {
+ if (!newMin.isValid() || newMin.toDouble() > value.toDouble()) {
newMin = value.toReal();
}
- if (!newMax.isValid() || newMax < value) {
+ if (!newMax.isValid() || newMax.toDouble() < value.toDouble()) {
newMax = value.toReal();
}
}
@@ -566,11 +568,11 @@ void LogsModelNg::newLogEntryReceived(const QVariantMap &data)
}
- if (m_minValue > entry->value().toReal()) {
+ if (m_minValue.toReal() > entry->value().toReal()) {
m_minValue = entry->value().toReal();
emit minValueChanged();
}
- if (m_maxValue < entry->value().toReal()) {
+ if (m_maxValue.toReal() < entry->value().toReal()) {
m_maxValue = entry->value().toReal();
emit maxValueChanged();
}
@@ -580,4 +582,3 @@ void LogsModelNg::newLogEntryReceived(const QVariantMap &data)
}
-
diff --git a/libnymea-app/models/logsmodelng.h b/libnymea-app/models/logsmodelng.h
index 453b63e3..45dcccf5 100644
--- a/libnymea-app/models/logsmodelng.h
+++ b/libnymea-app/models/logsmodelng.h
@@ -32,8 +32,13 @@
#include
#include