From f5c4bd16ac74dc9364148d8057dc251a60c4c864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sun, 21 Jan 2024 21:18:02 +0100 Subject: [PATCH] Add Qt6 support Add Qt6 debian packaging --- debian | 1 + {debian => debian-qt5}/changelog | 0 {debian => debian-qt5}/compat | 0 {debian => debian-qt5}/control | 6 +- {debian => debian-qt5}/copyright | 0 .../libnymea-core-dev.install.in | 0 .../libnymea-core.install.in | 0 .../libnymea-dev.install.in | 0 .../libnymea-tests-dev.install.in | 0 .../libnymea-tests.install.in | 0 {debian => debian-qt5}/libnymea1-dev.dirs.in | 0 {debian => debian-qt5}/libnymea1-dev.manpages | 0 {debian => debian-qt5}/libnymea1.dirs.in | 0 {debian => debian-qt5}/libnymea1.install.in | 0 .../man/nymea-plugininfocompiler.1 | 0 {debian => debian-qt5}/man/nymead.1 | 0 {debian => debian-qt5}/nymea-data.install | 0 .../nymea-dev-tools.install.in | 0 {debian => debian-qt5}/nymea-doc.dirs | 0 {debian => debian-qt5}/nymea-doc.install | 0 {debian => debian-qt5}/nymea-tests.dirs.in | 0 {debian => debian-qt5}/nymea-tests.install.in | 0 .../nymea-translations.dirs | 0 .../nymea-translations.install | 0 {debian => debian-qt5}/nymead.dirs | 0 {debian => debian-qt5}/nymead.install.in | 0 {debian => debian-qt5}/nymead.manpages | 0 {debian => debian-qt5}/nymead.postinst | 0 {debian => debian-qt5}/nymead.prerm | 0 {debian => debian-qt5}/rules | 2 +- {debian => debian-qt5}/source/format | 0 debian-qt6/changelog | 1 + debian-qt6/compat | 1 + debian-qt6/control | 221 ++++++ debian-qt6/copyright | 1 + debian-qt6/libnymea-core-dev.install.in | 1 + debian-qt6/libnymea-core.install.in | 1 + debian-qt6/libnymea-dev.install.in | 1 + debian-qt6/libnymea-tests-dev.install.in | 1 + debian-qt6/libnymea-tests.install.in | 1 + debian-qt6/libnymea1-dev.dirs.in | 1 + debian-qt6/libnymea1-dev.manpages | 1 + debian-qt6/libnymea1.dirs.in | 1 + debian-qt6/libnymea1.install.in | 1 + debian-qt6/man | 1 + debian-qt6/nymea-data.install | 1 + debian-qt6/nymea-dev-tools.install.in | 1 + debian-qt6/nymea-doc.dirs | 1 + debian-qt6/nymea-doc.install | 1 + debian-qt6/nymea-tests.dirs.in | 1 + debian-qt6/nymea-tests.install.in | 1 + debian-qt6/nymea-translations.dirs | 1 + debian-qt6/nymea-translations.install | 1 + debian-qt6/nymead.dirs | 1 + debian-qt6/nymead.install.in | 1 + debian-qt6/nymead.manpages | 1 + debian-qt6/nymead.postinst | 1 + debian-qt6/nymead.prerm | 1 + debian-qt6/rules | 66 ++ debian-qt6/source | 1 + libnymea-core/certificategenerator.cpp | 6 +- libnymea-core/debugreportgenerator.cpp | 38 +- libnymea-core/debugserverhandler.cpp | 6 +- .../bluetoothdiscoveryreplyimplementation.cpp | 2 +- ...bluetoothlowenergydeviceimplementation.cpp | 4 + ...luetoothlowenergymanagerimplementation.cpp | 8 + .../bluetoothpairingjobimplementation.h | 6 +- .../nymeabluetoothagent.cpp | 3 +- .../bluetoothlowenergy/nymeabluetoothagent.h | 5 +- .../hardware/network/macaddressdatabase.cpp | 26 +- .../mqtt/mqttproviderimplementation.cpp | 13 +- .../network/networkaccessmanagerimpl.cpp | 16 +- .../upnp/upnpdiscoveryimplementation.cpp | 145 ++-- .../upnp/upnpdiscoveryimplementation.h | 2 +- .../radio433/radio433brennenstuhlgateway.cpp | 8 +- .../radio433/radio433brennenstuhlgateway.h | 2 +- .../integrations/plugininfocache.cpp | 5 +- libnymea-core/integrations/python/pyutils.h | 24 +- .../integrations/scriptintegrationplugin.cpp | 4 +- .../thingmanagerimplementation.cpp | 31 +- libnymea-core/integrations/translator.cpp | 12 +- .../jsonrpc/configurationhandler.cpp | 2 +- .../jsonrpc/jsonrpcserverimplementation.cpp | 63 +- .../jsonrpc/jsonrpcserverimplementation.h | 8 +- libnymea-core/jsonrpc/jsonvalidator.cpp | 90 ++- libnymea-core/jsonrpc/zigbeehandler.cpp | 2 + libnymea-core/libnymea-core.pro | 50 +- libnymea-core/logging/logengineinfluxdb.cpp | 22 +- libnymea-core/logging/logengineinfluxdb.h | 16 +- libnymea-core/nymeaconfiguration.cpp | 2 +- libnymea-core/ruleengine/rule.cpp | 10 +- libnymea-core/ruleengine/ruleaction.cpp | 6 +- libnymea-core/ruleengine/ruleactionparam.cpp | 4 +- libnymea-core/ruleengine/ruleengine.cpp | 156 ++-- libnymea-core/ruleengine/ruleengine.h | 4 +- libnymea-core/ruleengine/stateevaluator.cpp | 104 ++- libnymea-core/scriptengine/scriptaction.cpp | 4 +- libnymea-core/scriptengine/scriptengine.cpp | 10 +- libnymea-core/scriptengine/scriptevent.cpp | 5 +- .../scriptengine/scriptinterfaceevent.cpp | 5 +- .../scriptengine/scriptinterfacestate.cpp | 3 +- libnymea-core/scriptengine/scriptthing.cpp | 5 +- libnymea-core/servers/bluetoothserver.cpp | 20 +- libnymea-core/servers/httpreply.cpp | 2 +- libnymea-core/servers/httprequest.cpp | 7 +- libnymea-core/servers/tcpserver.cpp | 4 +- libnymea-core/servers/webserver.cpp | 24 +- libnymea-core/tagging/tag.cpp | 2 +- libnymea-core/usermanager/usermanager.cpp | 250 ++++--- libnymea-core/zigbee/zigbeeadapter.cpp | 2 + libnymea-core/zigbee/zigbeeadapter.h | 2 + libnymea-core/zigbee/zigbeemanager.cpp | 6 + libnymea-core/zwave/zwavedevicedatabase.cpp | 89 +-- libnymea-core/zwave/zwavedevicedatabase.h | 3 +- libnymea-core/zwave/zwavemanager.cpp | 9 +- libnymea/coap/coap.cpp | 12 +- libnymea/coap/coapoption.cpp | 20 +- libnymea/coap/coappdu.cpp | 24 +- libnymea/coap/coapreply.cpp | 10 +- libnymea/coap/corelink.cpp | 14 +- libnymea/hardwaremanager.h | 4 +- libnymea/integrations/browseresult.h | 1 + libnymea/integrations/browseritemresult.h | 1 + libnymea/integrations/integrationplugin.cpp | 3 +- libnymea/integrations/pluginmetadata.cpp | 18 +- libnymea/integrations/thing.cpp | 19 +- libnymea/integrations/thingactioninfo.cpp | 2 +- libnymea/integrations/thingutils.cpp | 38 +- libnymea/integrations/thingutils.h | 2 + libnymea/jsonrpc/jsonhandler.cpp | 240 ++++-- libnymea/jsonrpc/jsonhandler.h | 32 +- libnymea/logging/logengine.cpp | 31 +- libnymea/logging/logengine.h | 31 + libnymea/logging/logentry.cpp | 30 + libnymea/logging/logentry.h | 36 +- libnymea/logging/logger.cpp | 30 + libnymea/logging/logger.h | 30 + libnymea/loggingcategories.cpp | 2 +- .../network/zeroconf/zeroconfserviceentry.cpp | 14 +- libnymea/time/timedescriptor.cpp | 2 +- libnymea/time/timeeventitem.cpp | 2 +- libnymea/types/eventdescriptor.cpp | 4 +- libnymea/types/eventtype.cpp | 4 +- libnymea/types/param.cpp | 4 +- libnymea/types/paramdescriptor.cpp | 2 +- libnymea/types/paramtype.cpp | 23 +- libnymea/types/paramtype.h | 10 +- libnymea/types/statetype.cpp | 10 +- libnymea/types/statetype.h | 8 +- libnymea/types/thingclass.h | 7 +- libnymea/typeutils.h | 23 +- nymea.pri | 45 +- plugins/mock/httpdaemon.cpp | 14 +- plugins/mock/integrationpluginmock.cpp | 4 +- server/main.cpp | 17 +- server/qtservice/qtservice.cpp | 2 +- server/server.pro | 8 +- tests/auto/autotests.pri | 27 +- tests/auto/integrations/testintegrations.cpp | 21 +- tests/auto/jsonrpc/testjsonrpc.cpp | 18 +- tests/auto/mqttbroker/mqttbroker.pro | 7 +- .../auto/pythonplugins/testpythonplugins.cpp | 9 +- tests/auto/rules/testrules.cpp | 65 +- tests/auto/scripts/testscripts.cpp | 694 ++++++++++++------ tests/auto/tags/testtags.cpp | 14 +- tests/auto/timemanager/testtimemanager.cpp | 24 +- tests/auto/versioning/testversioning.cpp | 18 +- tests/auto/webserver/testwebserver.cpp | 19 +- tests/auto/webserver/webserver.pro | 7 +- tests/scripts/getplugins.sh | 4 +- tests/scripts/getsupporteddevices.sh | 21 - tests/scripts/getsupportedvendors.sh | 7 - .../{getconfigureddevices.sh => getthings.sh} | 8 +- tests/scripts/getvendors.sh | 21 + tests/scripts/getversion.sh | 2 +- tests/scripts/hello.sh | 2 +- tests/scripts/introspect.sh | 2 +- tests/scripts/snoopnotifications.sh | 2 +- tests/scripts/version.sh | 4 +- tests/testlib/nymeatestbase.cpp | 13 +- tests/testlib/nymeatestbase.h | 17 +- tests/testlib/testlib.pro | 25 +- tests/tests.pro | 1 - .../plugininfocompiler.cpp | 7 +- 184 files changed, 2527 insertions(+), 1045 deletions(-) create mode 120000 debian rename {debian => debian-qt5}/changelog (100%) rename {debian => debian-qt5}/compat (100%) rename {debian => debian-qt5}/control (98%) rename {debian => debian-qt5}/copyright (100%) rename {debian => debian-qt5}/libnymea-core-dev.install.in (100%) rename {debian => debian-qt5}/libnymea-core.install.in (100%) rename {debian => debian-qt5}/libnymea-dev.install.in (100%) rename {debian => debian-qt5}/libnymea-tests-dev.install.in (100%) rename {debian => debian-qt5}/libnymea-tests.install.in (100%) rename {debian => debian-qt5}/libnymea1-dev.dirs.in (100%) rename {debian => debian-qt5}/libnymea1-dev.manpages (100%) rename {debian => debian-qt5}/libnymea1.dirs.in (100%) rename {debian => debian-qt5}/libnymea1.install.in (100%) rename {debian => debian-qt5}/man/nymea-plugininfocompiler.1 (100%) rename {debian => debian-qt5}/man/nymead.1 (100%) rename {debian => debian-qt5}/nymea-data.install (100%) rename {debian => debian-qt5}/nymea-dev-tools.install.in (100%) rename {debian => debian-qt5}/nymea-doc.dirs (100%) rename {debian => debian-qt5}/nymea-doc.install (100%) rename {debian => debian-qt5}/nymea-tests.dirs.in (100%) rename {debian => debian-qt5}/nymea-tests.install.in (100%) rename {debian => debian-qt5}/nymea-translations.dirs (100%) rename {debian => debian-qt5}/nymea-translations.install (100%) rename {debian => debian-qt5}/nymead.dirs (100%) rename {debian => debian-qt5}/nymead.install.in (100%) rename {debian => debian-qt5}/nymead.manpages (100%) rename {debian => debian-qt5}/nymead.postinst (100%) rename {debian => debian-qt5}/nymead.prerm (100%) rename {debian => debian-qt5}/rules (99%) rename {debian => debian-qt5}/source/format (100%) create mode 120000 debian-qt6/changelog create mode 100644 debian-qt6/compat create mode 100644 debian-qt6/control create mode 120000 debian-qt6/copyright create mode 120000 debian-qt6/libnymea-core-dev.install.in create mode 120000 debian-qt6/libnymea-core.install.in create mode 120000 debian-qt6/libnymea-dev.install.in create mode 120000 debian-qt6/libnymea-tests-dev.install.in create mode 120000 debian-qt6/libnymea-tests.install.in create mode 120000 debian-qt6/libnymea1-dev.dirs.in create mode 120000 debian-qt6/libnymea1-dev.manpages create mode 120000 debian-qt6/libnymea1.dirs.in create mode 120000 debian-qt6/libnymea1.install.in create mode 120000 debian-qt6/man create mode 120000 debian-qt6/nymea-data.install create mode 120000 debian-qt6/nymea-dev-tools.install.in create mode 120000 debian-qt6/nymea-doc.dirs create mode 120000 debian-qt6/nymea-doc.install create mode 120000 debian-qt6/nymea-tests.dirs.in create mode 120000 debian-qt6/nymea-tests.install.in create mode 120000 debian-qt6/nymea-translations.dirs create mode 120000 debian-qt6/nymea-translations.install create mode 120000 debian-qt6/nymead.dirs create mode 120000 debian-qt6/nymead.install.in create mode 120000 debian-qt6/nymead.manpages create mode 120000 debian-qt6/nymead.postinst create mode 120000 debian-qt6/nymead.prerm create mode 100755 debian-qt6/rules create mode 120000 debian-qt6/source delete mode 100755 tests/scripts/getsupporteddevices.sh delete mode 100755 tests/scripts/getsupportedvendors.sh rename tests/scripts/{getconfigureddevices.sh => getthings.sh} (53%) create mode 100755 tests/scripts/getvendors.sh diff --git a/debian b/debian new file mode 120000 index 00000000..cd83f55c --- /dev/null +++ b/debian @@ -0,0 +1 @@ +debian-qt5 \ No newline at end of file diff --git a/debian/changelog b/debian-qt5/changelog similarity index 100% rename from debian/changelog rename to debian-qt5/changelog diff --git a/debian/compat b/debian-qt5/compat similarity index 100% rename from debian/compat rename to debian-qt5/compat diff --git a/debian/control b/debian-qt5/control similarity index 98% rename from debian/control rename to debian-qt5/control index 842d5fc9..4c305b67 100644 --- a/debian/control +++ b/debian-qt5/control @@ -66,8 +66,8 @@ Recommends: nymea-cli, nymea-zwave-plugin-impl, influxdb, Description: An open source IoT server - daemon - The nymea daemon is a plugin based IoT (Internet of Things) server. - The server works like a translator for devices, things and services + The nymea daemon is a plugin based IoT (Internet of Things) server. + The server works like a translator for devices, things and services and allows them to interact. @@ -120,7 +120,7 @@ Depends: ${shlibs:Depends}, libnymea-tests (= ${binary:Version}), libnymea-core-dev (= ${binary:Version}) Description: nymea-tests library - development files - Provides the nymea-tests development files for building + Provides the nymea-tests development files for building automated tests. diff --git a/debian/copyright b/debian-qt5/copyright similarity index 100% rename from debian/copyright rename to debian-qt5/copyright diff --git a/debian/libnymea-core-dev.install.in b/debian-qt5/libnymea-core-dev.install.in similarity index 100% rename from debian/libnymea-core-dev.install.in rename to debian-qt5/libnymea-core-dev.install.in diff --git a/debian/libnymea-core.install.in b/debian-qt5/libnymea-core.install.in similarity index 100% rename from debian/libnymea-core.install.in rename to debian-qt5/libnymea-core.install.in diff --git a/debian/libnymea-dev.install.in b/debian-qt5/libnymea-dev.install.in similarity index 100% rename from debian/libnymea-dev.install.in rename to debian-qt5/libnymea-dev.install.in diff --git a/debian/libnymea-tests-dev.install.in b/debian-qt5/libnymea-tests-dev.install.in similarity index 100% rename from debian/libnymea-tests-dev.install.in rename to debian-qt5/libnymea-tests-dev.install.in diff --git a/debian/libnymea-tests.install.in b/debian-qt5/libnymea-tests.install.in similarity index 100% rename from debian/libnymea-tests.install.in rename to debian-qt5/libnymea-tests.install.in diff --git a/debian/libnymea1-dev.dirs.in b/debian-qt5/libnymea1-dev.dirs.in similarity index 100% rename from debian/libnymea1-dev.dirs.in rename to debian-qt5/libnymea1-dev.dirs.in diff --git a/debian/libnymea1-dev.manpages b/debian-qt5/libnymea1-dev.manpages similarity index 100% rename from debian/libnymea1-dev.manpages rename to debian-qt5/libnymea1-dev.manpages diff --git a/debian/libnymea1.dirs.in b/debian-qt5/libnymea1.dirs.in similarity index 100% rename from debian/libnymea1.dirs.in rename to debian-qt5/libnymea1.dirs.in diff --git a/debian/libnymea1.install.in b/debian-qt5/libnymea1.install.in similarity index 100% rename from debian/libnymea1.install.in rename to debian-qt5/libnymea1.install.in diff --git a/debian/man/nymea-plugininfocompiler.1 b/debian-qt5/man/nymea-plugininfocompiler.1 similarity index 100% rename from debian/man/nymea-plugininfocompiler.1 rename to debian-qt5/man/nymea-plugininfocompiler.1 diff --git a/debian/man/nymead.1 b/debian-qt5/man/nymead.1 similarity index 100% rename from debian/man/nymead.1 rename to debian-qt5/man/nymead.1 diff --git a/debian/nymea-data.install b/debian-qt5/nymea-data.install similarity index 100% rename from debian/nymea-data.install rename to debian-qt5/nymea-data.install diff --git a/debian/nymea-dev-tools.install.in b/debian-qt5/nymea-dev-tools.install.in similarity index 100% rename from debian/nymea-dev-tools.install.in rename to debian-qt5/nymea-dev-tools.install.in diff --git a/debian/nymea-doc.dirs b/debian-qt5/nymea-doc.dirs similarity index 100% rename from debian/nymea-doc.dirs rename to debian-qt5/nymea-doc.dirs diff --git a/debian/nymea-doc.install b/debian-qt5/nymea-doc.install similarity index 100% rename from debian/nymea-doc.install rename to debian-qt5/nymea-doc.install diff --git a/debian/nymea-tests.dirs.in b/debian-qt5/nymea-tests.dirs.in similarity index 100% rename from debian/nymea-tests.dirs.in rename to debian-qt5/nymea-tests.dirs.in diff --git a/debian/nymea-tests.install.in b/debian-qt5/nymea-tests.install.in similarity index 100% rename from debian/nymea-tests.install.in rename to debian-qt5/nymea-tests.install.in diff --git a/debian/nymea-translations.dirs b/debian-qt5/nymea-translations.dirs similarity index 100% rename from debian/nymea-translations.dirs rename to debian-qt5/nymea-translations.dirs diff --git a/debian/nymea-translations.install b/debian-qt5/nymea-translations.install similarity index 100% rename from debian/nymea-translations.install rename to debian-qt5/nymea-translations.install diff --git a/debian/nymead.dirs b/debian-qt5/nymead.dirs similarity index 100% rename from debian/nymead.dirs rename to debian-qt5/nymead.dirs diff --git a/debian/nymead.install.in b/debian-qt5/nymead.install.in similarity index 100% rename from debian/nymead.install.in rename to debian-qt5/nymead.install.in diff --git a/debian/nymead.manpages b/debian-qt5/nymead.manpages similarity index 100% rename from debian/nymead.manpages rename to debian-qt5/nymead.manpages diff --git a/debian/nymead.postinst b/debian-qt5/nymead.postinst similarity index 100% rename from debian/nymead.postinst rename to debian-qt5/nymead.postinst diff --git a/debian/nymead.prerm b/debian-qt5/nymead.prerm similarity index 100% rename from debian/nymead.prerm rename to debian-qt5/nymead.prerm diff --git a/debian/rules b/debian-qt5/rules similarity index 99% rename from debian/rules rename to debian-qt5/rules index 706a5915..4138ffef 100755 --- a/debian/rules +++ b/debian-qt5/rules @@ -14,7 +14,7 @@ $(info Building with DEB_BUILD_OPTIONS: [${DEB_BUILD_OPTIONS}]) MAKE_TARGETS=all lrelease ifeq (,$(filter nodoc,$(DEB_BUILD_OPTIONS))) MAKE_TARGETS += doc -endif +endif QMAKE_ADDITIONAL_ARGS = CONFIG+=norpath ifneq (,$(filter coverage,$(DEB_BUILD_OPTIONS))) diff --git a/debian/source/format b/debian-qt5/source/format similarity index 100% rename from debian/source/format rename to debian-qt5/source/format diff --git a/debian-qt6/changelog b/debian-qt6/changelog new file mode 120000 index 00000000..98cdf8f2 --- /dev/null +++ b/debian-qt6/changelog @@ -0,0 +1 @@ +../debian-qt5/changelog \ No newline at end of file diff --git a/debian-qt6/compat b/debian-qt6/compat new file mode 100644 index 00000000..b1bd38b6 --- /dev/null +++ b/debian-qt6/compat @@ -0,0 +1 @@ +13 diff --git a/debian-qt6/control b/debian-qt6/control new file mode 100644 index 00000000..7f918d9e --- /dev/null +++ b/debian-qt6/control @@ -0,0 +1,221 @@ +Source: nymea +Section: utils +Priority: optional +Maintainer: nymea GmbH +Standards-Version: 4.7.2 +Homepage: https://nymea.io +Vcs-Git: https://github.com/nymea/nymea.git +Build-Depends: debhelper, + dbus-test-runner, + dpkg-dev, + libnymea-mqtt-dev (>= 0.1.2), + libnymea-networkmanager-dev (>= 1.5.0~), + libnymea-remoteproxyclient-dev (>= 0.1.13), + libnymea-zigbee-dev (>= 0.1.0), + libnymea-gpio-dev, + libpython3-dev, + qt6-base-dev, + qt6-base-dev-tools, + qt6-websockets-dev, + qt6-connectivity-dev, + qt6-declarative-dev, + qt6-serialport-dev, + qt6-serialbus-dev, + qml6-module-qtquick, + qtchooser, + libqt6bluetooth6, + libqt6sql6-sqlite, + libqt6dbus6 | libqt6dbus6t64, + libssl-dev, + rsync, + influxdb:native, + libsystemd-dev, + + +Package: nymea +Architecture: any +Section: metapackages +Multi-Arch: same +Depends: nymead (= ${binary:Version}), + ${misc:Depends} +Recommends: qml-module-qtquick2 +Suggests: nymea-doc +Description: An open source IoT server - meta package + The nymea daemon is a plugin based IoT (Internet of Things) server. + The server works like a translator for devices, things and services + and allows them to interact. + + +Package: nymead +Architecture: any +Section: net +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-translations, + libnymea-core (= ${binary:Version}), + libnymea1 (= ${binary:Version}), +Recommends: nymea-cli, + nymea-data, + network-manager, + nymea-update-plugin-impl, + nymea-system-plugin-impl, + nymea-zeroconf-plugin-impl, + nymea-apikeysprovider-plugin-impl, + nymea-zwave-plugin-impl, + influxdb, +Description: An open source IoT server - daemon + The nymea daemon is a plugin based IoT (Internet of Things) server. + The server works like a translator for devices, things and services + and allows them to interact. + + +Package: nymea-data +Section: misc +Architecture: all +Depends: ${misc:Depends} +Recommends: nymead +Description: Optional data for extending functionality in nymea daemon - data + Provides application data used by nymea:core + + +Package: nymea-doc +Section: doc +Architecture: all +Depends: ${misc:Depends} +Recommends: nymea +Build-Profiles: +Description: Documentation for the nymea library - documentation + This package contains documentation for developing nymea plugins. + + +Package: nymea-translations +Section: misc +Architecture: all +Depends: ${misc:Depends} +Recommends: nymea +Description: Translation files for nymead - translations + Translation files for the nymea daemon. + + +Package: libnymea-tests +Section: libs +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libnymea-core (= ${binary:Version}) +Description: nymea-tests library - library + Shared resources for nymea-tests. + This package provides also the mock plugin for the tests. + + +Package: libnymea-tests-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libnymea-tests (= ${binary:Version}), + libnymea-core-dev (= ${binary:Version}) +Description: nymea-tests library - development files + Provides the nymea-tests development files for building + automated tests. + + +Package: nymea-tests +Section: devel +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea (= ${binary:Version}), + libnymea-tests (= ${binary:Version}), + influxdb, +Description: nymea automated tests - tests + Automated tests for the nymea daemon. + + +Package: libnymea1 +Section: libs +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, +Provides: nymea-update-plugin-api-1, + nymea-zeroconf-plugin-api-1, + nymea-system-plugin-api-3 +Description: nymea shared resources - library + Shared resources for nymea plugins. + + +Package: libnymea-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libnymea1 (= ${binary:Version}), + pkg-config, + qt6-base-dev, +Replaces: libnymea1-dev +Breaks: libnymea1-dev +Provides: libnymea1-dev +Description: nymea plugin development API library - development files + Shared resources for developing nymea plugins. + + +Package: libnymea-core +Section: libs +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + logrotate, + bluez, + tar, + iputils-tracepath, + iputils-ping, + qml6-module-qtquick, + libqt6sql6-sqlite, + libcap2-bin, + dnsutils, +Description: nymea:core internal - library + Internal library for nymea:core. + + +Package: libnymea-core-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libnymea-core (= ${binary:Version}), + libnymea-dev (= ${binary:Version}) +Description: nymea:core internal library - development files + Development files for the internal nymea:core library. + + +Package: nymea-dev-tools +Section: libdevel +Architecture: any +Multi-Arch: no +Depends: ${shlibs:Depends}, + ${misc:Depends}, + qt6-base-dev-tools, + rsync, +Description: Tools for developing nymea plugins. + This package will install the nymea-plugininfocompiler. + + +Package: nymea-sdk +Section: devel +Architecture: all +Multi-Arch: no +Depends: nymea-dev-tools (= ${binary:Version}), + libnymea-dev (= ${binary:Version}), +Recommends: nymea-qtcreator-wizards, + crossbuilder, +Suggests: libnymea-core-dev (= ${binary:Version}) +Description: The nymea SDK. + Meta-Package for everything required to develop nymea integration plugins. diff --git a/debian-qt6/copyright b/debian-qt6/copyright new file mode 120000 index 00000000..cc658776 --- /dev/null +++ b/debian-qt6/copyright @@ -0,0 +1 @@ +../debian-qt5/copyright \ No newline at end of file diff --git a/debian-qt6/libnymea-core-dev.install.in b/debian-qt6/libnymea-core-dev.install.in new file mode 120000 index 00000000..419f28d0 --- /dev/null +++ b/debian-qt6/libnymea-core-dev.install.in @@ -0,0 +1 @@ +../debian-qt5/libnymea-core-dev.install.in \ No newline at end of file diff --git a/debian-qt6/libnymea-core.install.in b/debian-qt6/libnymea-core.install.in new file mode 120000 index 00000000..0a8dbc4d --- /dev/null +++ b/debian-qt6/libnymea-core.install.in @@ -0,0 +1 @@ +../debian-qt5/libnymea-core.install.in \ No newline at end of file diff --git a/debian-qt6/libnymea-dev.install.in b/debian-qt6/libnymea-dev.install.in new file mode 120000 index 00000000..6d366d0b --- /dev/null +++ b/debian-qt6/libnymea-dev.install.in @@ -0,0 +1 @@ +../debian-qt5/libnymea-dev.install.in \ No newline at end of file diff --git a/debian-qt6/libnymea-tests-dev.install.in b/debian-qt6/libnymea-tests-dev.install.in new file mode 120000 index 00000000..fa2fac89 --- /dev/null +++ b/debian-qt6/libnymea-tests-dev.install.in @@ -0,0 +1 @@ +../debian-qt5/libnymea-tests-dev.install.in \ No newline at end of file diff --git a/debian-qt6/libnymea-tests.install.in b/debian-qt6/libnymea-tests.install.in new file mode 120000 index 00000000..e7680d5d --- /dev/null +++ b/debian-qt6/libnymea-tests.install.in @@ -0,0 +1 @@ +../debian-qt5/libnymea-tests.install.in \ No newline at end of file diff --git a/debian-qt6/libnymea1-dev.dirs.in b/debian-qt6/libnymea1-dev.dirs.in new file mode 120000 index 00000000..96170755 --- /dev/null +++ b/debian-qt6/libnymea1-dev.dirs.in @@ -0,0 +1 @@ +../debian-qt5/libnymea1-dev.dirs.in \ No newline at end of file diff --git a/debian-qt6/libnymea1-dev.manpages b/debian-qt6/libnymea1-dev.manpages new file mode 120000 index 00000000..16159fd9 --- /dev/null +++ b/debian-qt6/libnymea1-dev.manpages @@ -0,0 +1 @@ +../debian-qt5/libnymea1-dev.manpages \ No newline at end of file diff --git a/debian-qt6/libnymea1.dirs.in b/debian-qt6/libnymea1.dirs.in new file mode 120000 index 00000000..719687c2 --- /dev/null +++ b/debian-qt6/libnymea1.dirs.in @@ -0,0 +1 @@ +../debian-qt5/libnymea1.dirs.in \ No newline at end of file diff --git a/debian-qt6/libnymea1.install.in b/debian-qt6/libnymea1.install.in new file mode 120000 index 00000000..54732df6 --- /dev/null +++ b/debian-qt6/libnymea1.install.in @@ -0,0 +1 @@ +../debian-qt5/libnymea1.install.in \ No newline at end of file diff --git a/debian-qt6/man b/debian-qt6/man new file mode 120000 index 00000000..2373149a --- /dev/null +++ b/debian-qt6/man @@ -0,0 +1 @@ +../debian-qt5/man/ \ No newline at end of file diff --git a/debian-qt6/nymea-data.install b/debian-qt6/nymea-data.install new file mode 120000 index 00000000..1256b47f --- /dev/null +++ b/debian-qt6/nymea-data.install @@ -0,0 +1 @@ +../debian-qt5/nymea-data.install \ No newline at end of file diff --git a/debian-qt6/nymea-dev-tools.install.in b/debian-qt6/nymea-dev-tools.install.in new file mode 120000 index 00000000..076d67f7 --- /dev/null +++ b/debian-qt6/nymea-dev-tools.install.in @@ -0,0 +1 @@ +../debian-qt5/nymea-dev-tools.install.in \ No newline at end of file diff --git a/debian-qt6/nymea-doc.dirs b/debian-qt6/nymea-doc.dirs new file mode 120000 index 00000000..dfa8b306 --- /dev/null +++ b/debian-qt6/nymea-doc.dirs @@ -0,0 +1 @@ +../debian-qt5/nymea-doc.dirs \ No newline at end of file diff --git a/debian-qt6/nymea-doc.install b/debian-qt6/nymea-doc.install new file mode 120000 index 00000000..0a41a69f --- /dev/null +++ b/debian-qt6/nymea-doc.install @@ -0,0 +1 @@ +../debian-qt5/nymea-doc.install \ No newline at end of file diff --git a/debian-qt6/nymea-tests.dirs.in b/debian-qt6/nymea-tests.dirs.in new file mode 120000 index 00000000..bca5c74c --- /dev/null +++ b/debian-qt6/nymea-tests.dirs.in @@ -0,0 +1 @@ +../debian-qt5/nymea-tests.dirs.in \ No newline at end of file diff --git a/debian-qt6/nymea-tests.install.in b/debian-qt6/nymea-tests.install.in new file mode 120000 index 00000000..95050555 --- /dev/null +++ b/debian-qt6/nymea-tests.install.in @@ -0,0 +1 @@ +../debian-qt5/nymea-tests.install.in \ No newline at end of file diff --git a/debian-qt6/nymea-translations.dirs b/debian-qt6/nymea-translations.dirs new file mode 120000 index 00000000..a18dc553 --- /dev/null +++ b/debian-qt6/nymea-translations.dirs @@ -0,0 +1 @@ +../debian-qt5/nymea-translations.dirs \ No newline at end of file diff --git a/debian-qt6/nymea-translations.install b/debian-qt6/nymea-translations.install new file mode 120000 index 00000000..2e64a68d --- /dev/null +++ b/debian-qt6/nymea-translations.install @@ -0,0 +1 @@ +../debian-qt5/nymea-translations.install \ No newline at end of file diff --git a/debian-qt6/nymead.dirs b/debian-qt6/nymead.dirs new file mode 120000 index 00000000..562cbf48 --- /dev/null +++ b/debian-qt6/nymead.dirs @@ -0,0 +1 @@ +../debian-qt5/nymead.dirs \ No newline at end of file diff --git a/debian-qt6/nymead.install.in b/debian-qt6/nymead.install.in new file mode 120000 index 00000000..0b4a176b --- /dev/null +++ b/debian-qt6/nymead.install.in @@ -0,0 +1 @@ +../debian-qt5/nymead.install.in \ No newline at end of file diff --git a/debian-qt6/nymead.manpages b/debian-qt6/nymead.manpages new file mode 120000 index 00000000..1f43aa8e --- /dev/null +++ b/debian-qt6/nymead.manpages @@ -0,0 +1 @@ +../debian-qt5/nymead.manpages \ No newline at end of file diff --git a/debian-qt6/nymead.postinst b/debian-qt6/nymead.postinst new file mode 120000 index 00000000..ea3fcc8d --- /dev/null +++ b/debian-qt6/nymead.postinst @@ -0,0 +1 @@ +../debian-qt5/nymead.postinst \ No newline at end of file diff --git a/debian-qt6/nymead.prerm b/debian-qt6/nymead.prerm new file mode 120000 index 00000000..5d822868 --- /dev/null +++ b/debian-qt6/nymead.prerm @@ -0,0 +1 @@ +../debian-qt5/nymead.prerm \ No newline at end of file diff --git a/debian-qt6/rules b/debian-qt6/rules new file mode 100755 index 00000000..b7c08612 --- /dev/null +++ b/debian-qt6/rules @@ -0,0 +1,66 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +export DH_VERBOSE=1 +export QT_QPA_PLATFORM=minimal + +ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) + DEB_PARALLEL_JOBS ?= $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) +else + DEB_PARALLEL_JOBS += $(shell getconf _NPROCESSORS_ONLN) +endif + +$(info Building with DEB_BUILD_OPTIONS: [${DEB_BUILD_OPTIONS}]) +MAKE_TARGETS=all lrelease +ifeq (,$(filter nodoc,$(DEB_BUILD_OPTIONS))) + MAKE_TARGETS += doc +endif + +QMAKE_ADDITIONAL_ARGS = CONFIG+=norpath +ifneq (,$(filter coverage,$(DEB_BUILD_OPTIONS))) + QMAKE_ADDITIONAL_ARGS += CONFIG+=coverage CONFIG+=debug +else + QMAKE_ADDITIONAL_ARGS += CONFIG+=release +endif + +DPKG_EXPORT_BUILDFLAGS = 1 +DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) + +NYMEA_DPKG_VERSION := $(shell dpkg-parsechangelog -SVersion) +QMAKE_ADDITIONAL_ARGS += NYMEA_VERSION=$(NYMEA_DPKG_VERSION) + +include /usr/share/dpkg/buildflags.mk + +PREPROCESS_FILES := $(wildcard debian/*.in) + +$(PREPROCESS_FILES:.in=): %: %.in + sed 's,/@DEB_HOST_MULTIARCH@,$(DEB_HOST_MULTIARCH:%=/%),g' $< > $@ + +override_dh_auto_configure: + dh_auto_configure -- $(QMAKE_ADDITIONAL_ARGS) + +override_dh_auto_build: + make -j$(DEB_PARALLEL_JOBS) $(MAKE_TARGETS) + +override_dh_install: $(PREPROCESS_FILES:.in=) + # Make sure the docs directory exists, even if we didn't build them + mkdir -p $(CURDIR)/doc/html + dh_install + +# Note that this is the default with compat level 12. +override_dh_missing: + dh_missing --list-missing + +override_dh_auto_test: + dh_auto_test -- -k TESTARGS="-m 600 -p -o -p -,txt -p -o -p test-results.xml,xunitxml" TESTRUNNER="dbus-test-runner --bus-type=both --task" + +override_dh_installsystemd: + dh_installsystemd --restart-after-upgrade + +override_dh_auto_clean: + dh_auto_clean + find . -name *.qm -exec rm {} \; + rm -rf $(PREPROCESS_FILES:.in=) + +%: + dh $@ --buildsystem=qmake6 --parallel diff --git a/debian-qt6/source b/debian-qt6/source new file mode 120000 index 00000000..bfdc36ec --- /dev/null +++ b/debian-qt6/source @@ -0,0 +1 @@ +../debian-qt5/source/ \ No newline at end of file diff --git a/libnymea-core/certificategenerator.cpp b/libnymea-core/certificategenerator.cpp index 34679f5a..890d1dc0 100644 --- a/libnymea-core/certificategenerator.cpp +++ b/libnymea-core/certificategenerator.cpp @@ -32,7 +32,7 @@ #include "openssl/ssl.h" -#include +#include #include #include #include @@ -87,8 +87,8 @@ void CertificateGenerator::generate(const QString &certificateFilename, const QS q_check_ptr(x509); // Randomize serial number in case a previous one is stuck in a browser (Chromium // completely rejects reused serial numbers and doesn't even allow to bypass it by an exception) - qsrand(QUuid::createUuid().toString().remove(QRegExp("[a-zA-Z{}-]")).left(5).toInt()); - ASN1_INTEGER_set(X509_get_serialNumber(x509), qrand()); + std::srand(QUuid::createUuid().toString().remove(QRegularExpression("[a-zA-Z{}-]")).left(5).toInt()); + ASN1_INTEGER_set(X509_get_serialNumber(x509), std::rand()); X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time X509_gmtime_adj(X509_get_notAfter(x509), 31536000L*10); // not after 10 years from this point X509_set_pubkey(x509, pkey); diff --git a/libnymea-core/debugreportgenerator.cpp b/libnymea-core/debugreportgenerator.cpp index 9a784716..11d61a6e 100644 --- a/libnymea-core/debugreportgenerator.cpp +++ b/libnymea-core/debugreportgenerator.cpp @@ -167,28 +167,28 @@ void DebugReportGenerator::saveSystemInformation() qCDebug(dcDebugServer()) << "Write system information file" << outputFile.fileName(); QTextStream stream(&outputFile); - stream << "Server name: " << NymeaCore::instance()->configuration()->serverName() << endl; - stream << "Server version: " << NYMEA_VERSION_STRING << endl; - stream << "JSON-RPC version: " << JSON_PROTOCOL_VERSION << endl; - stream << "Language: " << NymeaCore::instance()->configuration()->locale().name() << " (" << NymeaCore::instance()->configuration()->locale().nativeCountryName() << " - " << NymeaCore::instance()->configuration()->locale().nativeLanguageName() << ")" << endl; - stream << "Timezone: " << QString::fromUtf8(NymeaCore::instance()->configuration()->timeZone()) << endl; - stream << "Server UUID: " << NymeaCore::instance()->configuration()->serverUuid().toString() << endl; - stream << "Settings path: " << NymeaSettings::settingsPath() << endl; - stream << "Translations path: " << NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath() << endl; - stream << "User: " << qgetenv("USER") << endl; - stream << "Command: " << QCoreApplication::arguments().join(' ') << endl; - stream << "Qt runtime version: " << qVersion() << endl; - stream << "" << endl; + stream << "Server name: " << NymeaCore::instance()->configuration()->serverName() << '\n'; + stream << "Server version: " << NYMEA_VERSION_STRING << '\n'; + stream << "JSON-RPC version: " << JSON_PROTOCOL_VERSION << '\n'; + stream << "Language: " << NymeaCore::instance()->configuration()->locale().name() << " (" << NymeaCore::instance()->configuration()->locale().nativeCountryName() << " - " << NymeaCore::instance()->configuration()->locale().nativeLanguageName() << ")" << '\n'; + stream << "Timezone: " << QString::fromUtf8(NymeaCore::instance()->configuration()->timeZone()) << '\n'; + stream << "Server UUID: " << NymeaCore::instance()->configuration()->serverUuid().toString() << '\n'; + stream << "Settings path: " << NymeaSettings::settingsPath() << '\n'; + stream << "Translations path: " << NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath() << '\n'; + stream << "User: " << qgetenv("USER") << '\n'; + stream << "Command: " << QCoreApplication::arguments().join(' ') << '\n'; + stream << "Qt runtime version: " << qVersion() << '\n'; + stream << "" << '\n'; #if (QT_VERSION < QT_VERSION_CHECK(5, 6, 0)) - stream << "Hostname: " << QHostInfo::localHostName() << endl; + stream << "Hostname: " << QHostInfo::localHostName() << '\n'; #else - stream << "Hostname: " << QSysInfo::machineHostName() << endl; + stream << "Hostname: " << QSysInfo::machineHostName() << '\n'; #endif - stream << "Architecture: " << QSysInfo::currentCpuArchitecture() << endl; - stream << "Kernel type: " << QSysInfo::kernelType() << endl; - stream << "Kernel version: " << QSysInfo::kernelVersion() << endl; - stream << "Product type: " << QSysInfo::productType() << endl; - stream << "Product version: " << QSysInfo::productVersion() << endl; + stream << "Architecture: " << QSysInfo::currentCpuArchitecture() << '\n'; + stream << "Kernel type: " << QSysInfo::kernelType() << '\n'; + stream << "Kernel version: " << QSysInfo::kernelVersion() << '\n'; + stream << "Product type: " << QSysInfo::productType() << '\n'; + stream << "Product version: " << QSysInfo::productVersion() << '\n'; outputFile.close(); } diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index 30f49e8e..dde8f391 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -673,7 +673,7 @@ void DebugServerHandler::onPingProcessFinished(int exitCode, QProcess::ExitStatu { qCDebug(dcDebugServer()) << "Ping process finished" << exitCode << exitStatus; QByteArray processOutput = m_pingProcess->readAll(); - qCDebug(dcDebugServer()) << "Ping output:" << endl << qUtf8Printable(processOutput); + qCDebug(dcDebugServer()) << "Ping output:" << '\n' << qUtf8Printable(processOutput); if (m_pingReply) { m_pingReply->setPayload(processOutput); @@ -690,7 +690,7 @@ void DebugServerHandler::onDigProcessFinished(int exitCode, QProcess::ExitStatus { qCDebug(dcDebugServer()) << "Dig process finished" << exitCode << exitStatus; QByteArray processOutput = m_digProcess->readAll(); - qCDebug(dcDebugServer()) << "Dig output:" << endl << qUtf8Printable(processOutput); + qCDebug(dcDebugServer()) << "Dig output:" << '\n' << qUtf8Printable(processOutput); if (m_digReply) { m_digReply->setPayload(processOutput); @@ -707,7 +707,7 @@ void DebugServerHandler::onTracePathProcessFinished(int exitCode, QProcess::Exit { qCDebug(dcDebugServer()) << "Tracepath process finished" << exitCode << exitStatus; QByteArray processOutput = m_tracePathProcess->readAll(); - qCDebug(dcDebugServer()) << "Tracepath output:" << endl << qUtf8Printable(processOutput); + qCDebug(dcDebugServer()) << "Tracepath output:" << '\n' << qUtf8Printable(processOutput); if (m_tracePathReply) { m_tracePathReply->setPayload(processOutput); diff --git a/libnymea-core/hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.cpp b/libnymea-core/hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.cpp index 9b02a8de..6fe586bb 100644 --- a/libnymea-core/hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.cpp +++ b/libnymea-core/hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.cpp @@ -70,7 +70,7 @@ void BluetoothDiscoveryReplyImplementation::setDiscoveredDevices(const QList(info, hostInfo)); + m_discoveredDevices.append(QPair(info, hostInfo)); } void BluetoothDiscoveryReplyImplementation::setFinished() diff --git a/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.cpp b/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.cpp index adde47b4..be79d1e6 100644 --- a/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.cpp +++ b/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.cpp @@ -37,7 +37,11 @@ BluetoothLowEnergyDeviceImplementation::BluetoothLowEnergyDeviceImplementation(c BluetoothLowEnergyDevice(parent), m_deviceInfo(deviceInfo) { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + m_controller = QLowEnergyController::createCentral(deviceInfo, this); +#else m_controller = new QLowEnergyController(address(), this); +#endif m_controller->setRemoteAddressType(addressType); connect(m_controller, &QLowEnergyController::connected, this, &BluetoothLowEnergyDeviceImplementation::onConnected); diff --git a/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.cpp b/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.cpp index b66ac8e7..3a02b4b0 100644 --- a/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.cpp +++ b/libnymea-core/hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.cpp @@ -138,11 +138,19 @@ BluetoothPairingJob *BluetoothLowEnergyManagerImplementation::pairDevice(const Q return job; } localDevice->requestPairing(device, QBluetoothLocalDevice::AuthorizedPaired); +#if QT_VERSION >= QT_VERSION_CHECK(6,2,0) + connect(localDevice, &QBluetoothLocalDevice::errorOccurred, job, [=](QBluetoothLocalDevice::Error error){ + qCDebug(dcBluetooth()) << "Pairing error" << error; + job->finish(false); + localDevice->deleteLater(); + }); +#else connect(localDevice, &QBluetoothLocalDevice::error, job, [=](QBluetoothLocalDevice::Error error){ qCDebug(dcBluetooth()) << "Pairing error" << error; job->finish(false); localDevice->deleteLater(); }); +#endif connect(localDevice, &QBluetoothLocalDevice::pairingFinished, job, [=](const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing){ qCDebug(dcBluetooth()) << "Pairing finished" << address.toString() << pairing; job->finish(true); diff --git a/libnymea-core/hardware/bluetoothlowenergy/bluetoothpairingjobimplementation.h b/libnymea-core/hardware/bluetoothlowenergy/bluetoothpairingjobimplementation.h index 16304fba..ee2cacf1 100644 --- a/libnymea-core/hardware/bluetoothlowenergy/bluetoothpairingjobimplementation.h +++ b/libnymea-core/hardware/bluetoothlowenergy/bluetoothpairingjobimplementation.h @@ -1,11 +1,10 @@ #ifndef BLUETOOTHPAIRINGJOBIMPLEMENTATION_H #define BLUETOOTHPAIRINGJOBIMPLEMENTATION_H -#include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h" #include +#include -namespace nymeaserver -{ +namespace nymeaserver { class NymeaBluetoothAgent; class BluetoothLowEnergyManagerImplementation; @@ -35,4 +34,5 @@ private: }; } + #endif // BLUETOOTHPAIRINGJOBIMPLEMENTATION_H diff --git a/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.cpp b/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.cpp index 2aa8adba..4a2ab006 100644 --- a/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.cpp +++ b/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.cpp @@ -5,8 +5,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcBluetooth) -namespace nymeaserver -{ +namespace nymeaserver { NymeaBluetoothAgentAdapter::NymeaBluetoothAgentAdapter(NymeaBluetoothAgent *agent, QObject *parent): QObject{parent}, diff --git a/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.h b/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.h index 2990548c..846c4d60 100644 --- a/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.h +++ b/libnymea-core/hardware/bluetoothlowenergy/nymeabluetoothagent.h @@ -6,8 +6,9 @@ #include #include -namespace nymeaserver -{ +#include + +namespace nymeaserver { class NymeaBluetoothAgent; diff --git a/libnymea-core/hardware/network/macaddressdatabase.cpp b/libnymea-core/hardware/network/macaddressdatabase.cpp index 3e57aecd..188459eb 100644 --- a/libnymea-core/hardware/network/macaddressdatabase.cpp +++ b/libnymea-core/hardware/network/macaddressdatabase.cpp @@ -47,7 +47,7 @@ MacAddressDatabase::MacAddressDatabase(QObject *parent) : QObject(parent) { // Find database in system data locations QString databaseFileName; - foreach (const QString &dataLocation, QStandardPaths::standardLocations(QStandardPaths::DataLocation)) { + foreach (const QString &dataLocation, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) { QFileInfo databaseFileInfo(dataLocation + QDir::separator() + "mac-addresses.db"); if (!databaseFileInfo.exists()) { continue; @@ -58,7 +58,7 @@ MacAddressDatabase::MacAddressDatabase(QObject *parent) : QObject(parent) } if (databaseFileName.isEmpty()) { - qCWarning(dcMacAddressDatabase()) << "Could not find the mac address database in any system data location paths" << QStandardPaths::standardLocations(QStandardPaths::DataLocation); + qCWarning(dcMacAddressDatabase()) << "Could not find the mac address database in any system data location paths" << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); qCWarning(dcMacAddressDatabase()) << "The mac address database lookup feature will not be available."; return; } @@ -156,7 +156,11 @@ void MacAddressDatabase::runNextLookup() m_currentReply = m_pendingReplies.dequeue(); m_currentReply->m_startTimestamp = QDateTime::currentMSecsSinceEpoch(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QFuture future = QtConcurrent::run(&MacAddressDatabase::lookupMacAddressVendorInternal, this, m_currentReply->macAddress()); +#else QFuture future = QtConcurrent::run(this, &MacAddressDatabase::lookupMacAddressVendorInternal, m_currentReply->macAddress()); +#endif m_futureWatcher->setFuture(future); } @@ -185,7 +189,12 @@ QString MacAddressDatabase::lookupMacAddressVendorInternal(const QString &macAdd QString searchString = fullMacAddressString.left(length); QString queryString = QString("SELECT COUNT(oui) FROM oui WHERE oui LIKE \'%1%\';").arg(searchString); qCDebug(dcMacAddressDatabase()) << "Query:" << queryString; - QSqlQuery countQuery = m_db.exec(queryString); + QSqlQuery countQuery(m_db); + if (!countQuery.exec(queryString)) { + qCWarning(dcMacAddressDatabase()) << "Unable to execute SQL query" << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + break; + } + if (countQuery.lastError().isValid()) { qCWarning(dcMacAddressDatabase()) << "Query finished with error" << countQuery.lastError().text(); break; @@ -201,11 +210,16 @@ QString MacAddressDatabase::lookupMacAddressVendorInternal(const QString &macAdd // Query the name queryString = QString("SELECT companyName from companyNames WHERE rowid IS (SELECT companyNameIndex FROM oui WHERE oui=\'%1\');").arg(searchString); qCDebug(dcMacAddressDatabase()) << "Query:" << queryString; - countQuery = m_db.exec(queryString); - if (!countQuery.next()) + QSqlQuery rowQuery(m_db); + if (!rowQuery.exec(queryString)) { + qCWarning(dcMacAddressDatabase()) << "Unable to execute SQL query" << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + break; + } + + if (!rowQuery.next()) break; - manufacturer = countQuery.value(0).toString(); + manufacturer = rowQuery.value(0).toString(); break; } diff --git a/libnymea-core/hardware/network/mqtt/mqttproviderimplementation.cpp b/libnymea-core/hardware/network/mqtt/mqttproviderimplementation.cpp index e9266cbd..0003ab31 100644 --- a/libnymea-core/hardware/network/mqtt/mqttproviderimplementation.cpp +++ b/libnymea-core/hardware/network/mqtt/mqttproviderimplementation.cpp @@ -32,9 +32,10 @@ #include "mqttchannelimplementation.h" #include "loggingcategories.h" -#include #include +#include #include +#include namespace nymeaserver { @@ -52,7 +53,7 @@ MqttChannel *MqttProviderImplementation::createChannel(const QHostAddress &clien QString clientId; // Generate a clientId that hasn't been used yet. do { - clientId = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16); + clientId = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")).left(16); } while (m_createdChannels.contains(clientId)); return createChannel(clientId, clientAddress, topicPrefixList); @@ -60,8 +61,8 @@ MqttChannel *MqttProviderImplementation::createChannel(const QHostAddress &clien MqttChannel *MqttProviderImplementation::createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList) { - QString username = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16); - QString password = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16); + QString username = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")).left(16); + QString password = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")).left(16); return createChannel(clientId, username, password, clientAddress, topicPrefixList); } @@ -160,8 +161,8 @@ MqttClient *MqttProviderImplementation::createInternalClient(const QString &clie MqttPolicy policy; policy.clientId = clientId; - policy.username = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); - policy.password = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); + policy.username = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); + policy.password = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); policy.allowedPublishTopicFilters.append("#"); policy.allowedSubscribeTopicFilters.append("#"); m_broker->updatePolicy(policy); diff --git a/libnymea-core/hardware/network/networkaccessmanagerimpl.cpp b/libnymea-core/hardware/network/networkaccessmanagerimpl.cpp index b774afea..94028ba8 100644 --- a/libnymea-core/hardware/network/networkaccessmanagerimpl.cpp +++ b/libnymea-core/hardware/network/networkaccessmanagerimpl.cpp @@ -137,13 +137,15 @@ void NetworkAccessManagerImpl::setEnabled(bool enabled) return; } - if (enabled) { - m_manager->setNetworkAccessible(QNetworkAccessManager::Accessible); - qCDebug(dcNetworkManager()) << "Network Manager enabled"; - } else { - m_manager->setNetworkAccessible(QNetworkAccessManager::NotAccessible); - qCDebug(dcNetworkManager()) << "Network Manager disabled"; - } + // FIXME Qt6: disabeling the networkmanager should be updated with the new hardware resource methods + + // if (enabled) { + // m_manager->setNetworkAccessible(QNetworkAccessManager::Accessible); + // qCDebug(dcNetworkManager()) << "Network Manager enabled"; + // } else { + // m_manager->setNetworkAccessible(QNetworkAccessManager::NotAccessible); + // qCDebug(dcNetworkManager()) << "Network Manager disabled"; + // } m_enabled = enabled; } diff --git a/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp b/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp index 9b4424a0..92a1cac8 100644 --- a/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp +++ b/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp @@ -55,8 +55,8 @@ #include #include #include -#include -#include +#include +#include namespace nymeaserver { @@ -70,10 +70,13 @@ UpnpDiscoveryImplementation::UpnpDiscoveryImplementation(QNetworkAccessManager * m_notificationTimer->setSingleShot(false); connect(m_notificationTimer, &QTimer::timeout, this, &UpnpDiscoveryImplementation::notificationTimeout); - QNetworkConfigurationManager *configManager = new QNetworkConfigurationManager(this); - connect(configManager, &QNetworkConfigurationManager::configurationAdded, this, &UpnpDiscoveryImplementation::networkConfigurationChanged); - connect(configManager, &QNetworkConfigurationManager::configurationRemoved, this, &UpnpDiscoveryImplementation::networkConfigurationChanged); - connect(configManager, &QNetworkConfigurationManager::configurationChanged, this, &UpnpDiscoveryImplementation::networkConfigurationChanged); + // FIXME Qt6: maybe we can use udev in order to detect network configuration changes, centralized, + // also available for integration plugins since there are some examples + + // QNetworkConfigurationManager *configManager = new QNetworkConfigurationManager(this); + // connect(configManager, &QNetworkConfigurationManager::configurationAdded, this, &UpnpDiscoveryImplementation::networkConfigurationChanged); + // connect(configManager, &QNetworkConfigurationManager::configurationRemoved, this, &UpnpDiscoveryImplementation::networkConfigurationChanged); + // connect(configManager, &QNetworkConfigurationManager::configurationChanged, this, &UpnpDiscoveryImplementation::networkConfigurationChanged); m_available = true; @@ -132,7 +135,7 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int // TODO: Once DeviceManager (and with that this can be moved into the server, use NymeaCore's configuration manager instead of parsing the config here... NymeaSettings globalSettings(NymeaSettings::SettingsRoleGlobal); globalSettings.beginGroup("nymead"); - QByteArray uuid = globalSettings.value("uuid", QUuid()).toString().remove(QRegExp("[{}]")).toUtf8(); + QByteArray uuid = globalSettings.value("uuid", QUuid()).toString().remove(QRegularExpression("[{}]")).toUtf8(); globalSettings.endGroup(); globalSettings.beginGroup("WebServer"); @@ -184,12 +187,17 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int // http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf QByteArray rootdeviceResponseMessage = QByteArray("HTTP/1.1 200 OK\r\n" "CACHE-CONTROL: max-age=1900\r\n" - "DATE: " + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT\r\n" + "DATE: " + + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + + " GMT\r\n" "EXT:\r\n" - "LOCATION: " + locationString.toUtf8() + "\r\n" - "SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n" + "LOCATION: " + locationString.toUtf8() + + "\r\n" + "SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + + " UPnP/1.1 \r\n" "ST: upnp:rootdevice\r\n" - "USN: uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" + "USN: uuid:" + uuid + + "::urn:schemas-upnp-org:device:Basic:1\r\n" "\r\n"); qCDebug(dcUpnp()) << QString("Sending response to %1:%2").arg(host.toString()).arg(port); @@ -311,42 +319,81 @@ void UpnpDiscoveryImplementation::replyFinished() if (xml.isStartElement()) { if (xml.name().toString() == "device") { while (!xml.atEnd()) { - if (xml.name() == "deviceType" && xml.isStartElement()) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (xml.name() == QLatin1StringView("deviceType") && xml.isStartElement()) { upnpDeviceDescriptor.setDeviceType(xml.readElementText()); } - if (xml.name() == "friendlyName" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("friendlyName") && xml.isStartElement()) { upnpDeviceDescriptor.setFriendlyName(xml.readElementText()); } - if (xml.name() == "manufacturer" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("manufacturer") && xml.isStartElement()) { upnpDeviceDescriptor.setManufacturer(xml.readElementText()); } - if (xml.name() == "manufacturerURL" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("manufacturerURL") && xml.isStartElement()) { upnpDeviceDescriptor.setManufacturerURL(QUrl(xml.readElementText())); } - if (xml.name() == "modelDescription" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("modelDescription") && xml.isStartElement()) { upnpDeviceDescriptor.setModelDescription(xml.readElementText()); } - if (xml.name() == "modelName" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("modelName") && xml.isStartElement()) { upnpDeviceDescriptor.setModelName(xml.readElementText()); } - if (xml.name() == "modelNumber" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("modelNumber") && xml.isStartElement()) { upnpDeviceDescriptor.setModelNumber(xml.readElementText()); } - if (xml.name() == "modelURL" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("modelURL") && xml.isStartElement()) { upnpDeviceDescriptor.setModelURL(QUrl(xml.readElementText())); } - if (xml.name() == "serialNumber" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("serialNumber") && xml.isStartElement()) { upnpDeviceDescriptor.setSerialNumber(xml.readElementText()); } - if (xml.name() == "UDN" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("UDN") && xml.isStartElement()) { upnpDeviceDescriptor.setUuid(xml.readElementText()); } - if (xml.name() == "uuid" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("uuid") && xml.isStartElement()) { upnpDeviceDescriptor.setUuid(xml.readElementText()); } - if (xml.name() == "UPC" && xml.isStartElement()) { + if (xml.name() == QLatin1StringView("UPC") && xml.isStartElement()) { upnpDeviceDescriptor.setUpc(xml.readElementText()); } +#else + if (xml.name() == QLatin1String("deviceType") && xml.isStartElement()) { + upnpDeviceDescriptor.setDeviceType(xml.readElementText()); + } + if (xml.name() == QLatin1String("friendlyName") && xml.isStartElement()) { + upnpDeviceDescriptor.setFriendlyName(xml.readElementText()); + } + if (xml.name() == QLatin1String("manufacturer") && xml.isStartElement()) { + upnpDeviceDescriptor.setManufacturer(xml.readElementText()); + } + if (xml.name() == QLatin1String("manufacturerURL") && xml.isStartElement()) { + upnpDeviceDescriptor.setManufacturerURL(QUrl(xml.readElementText())); + } + if (xml.name() == QLatin1String("modelDescription") && xml.isStartElement()) { + upnpDeviceDescriptor.setModelDescription(xml.readElementText()); + } + if (xml.name() == QLatin1String("modelName") && xml.isStartElement()) { + upnpDeviceDescriptor.setModelName(xml.readElementText()); + } + if (xml.name() == QLatin1String("modelNumber") && xml.isStartElement()) { + upnpDeviceDescriptor.setModelNumber(xml.readElementText()); + } + if (xml.name() == QLatin1String("modelURL") && xml.isStartElement()) { + upnpDeviceDescriptor.setModelURL(QUrl(xml.readElementText())); + } + if (xml.name() == QLatin1String("serialNumber") && xml.isStartElement()) { + upnpDeviceDescriptor.setSerialNumber(xml.readElementText()); + } + if (xml.name() == QLatin1String("UDN") && xml.isStartElement()) { + upnpDeviceDescriptor.setUuid(xml.readElementText()); + } + if (xml.name() == QLatin1String("uuid") && xml.isStartElement()) { + upnpDeviceDescriptor.setUuid(xml.readElementText()); + } + if (xml.name() == QLatin1String("UPC") && xml.isStartElement()) { + upnpDeviceDescriptor.setUpc(xml.readElementText()); + } +#endif xml.readNext(); } xml.readNext(); @@ -403,14 +450,14 @@ void UpnpDiscoveryImplementation::sendByeByeMessage() // http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf QByteArray byebyeMessage = QByteArray("NOTIFY * HTTP/1.1\r\n" - "HOST:239.255.255.250:1900\r\n" - "CACHE-CONTROL: max-age=1900\r\n" - "LOCATION: " + locationString.toUtf8() + "\r\n" - "NT:urn:schemas-upnp-org:device:Basic:1\r\n" - "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" - "NTS: ssdp:byebye\r\n" - "SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n" - "\r\n"); + "HOST:239.255.255.250:1900\r\n" + "CACHE-CONTROL: max-age=1900\r\n" + "LOCATION: " + locationString.toUtf8() + "\r\n" + "NT:urn:schemas-upnp-org:device:Basic:1\r\n" + "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" + "NTS: ssdp:byebye\r\n" + "SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n" + "\r\n"); sendToMulticast(byebyeMessage); } @@ -449,14 +496,14 @@ void UpnpDiscoveryImplementation::sendAliveMessage() // http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf QByteArray aliveMessage = QByteArray("NOTIFY * HTTP/1.1\r\n" - "HOST:239.255.255.250:1900\r\n" - "CACHE-CONTROL: max-age=1900\r\n" - "LOCATION: " + locationString.toUtf8() + "\r\n" - "NT:urn:schemas-upnp-org:device:Basic:1\r\n" - "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" - "NTS: ssdp:alive\r\n" - "SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n" - "\r\n"); + "HOST:239.255.255.250:1900\r\n" + "CACHE-CONTROL: max-age=1900\r\n" + "LOCATION: " + locationString.toUtf8() + "\r\n" + "NT:urn:schemas-upnp-org:device:Basic:1\r\n" + "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" + "NTS: ssdp:alive\r\n" + "SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n" + "\r\n"); sendToMulticast(aliveMessage); } @@ -485,14 +532,14 @@ void UpnpDiscoveryImplementation::discoverTimeout() delete discoveryRequest; } -void UpnpDiscoveryImplementation::networkConfigurationChanged(const QNetworkConfiguration &config) -{ - Q_UNUSED(config) - if (m_enabled) { - disable(); - enable(); - } -} +// void UpnpDiscoveryImplementation::networkConfigurationChanged(const QNetworkConfiguration &config) +// { +// Q_UNUSED(config) +// if (m_enabled) { +// disable(); +// enable(); +// } +// } bool UpnpDiscoveryImplementation::enable() { @@ -531,7 +578,11 @@ bool UpnpDiscoveryImplementation::enable() m_available = true; emit availableChanged(true); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(m_socket, &QUdpSocket::errorOccurred, this, &UpnpDiscoveryImplementation::error); +#else connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); +#endif connect(m_socket, &QUdpSocket::readyRead, this, &UpnpDiscoveryImplementation::readData); m_notificationTimer->start(); diff --git a/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.h b/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.h index bb42d113..ef851619 100644 --- a/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.h +++ b/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.h @@ -94,7 +94,7 @@ private slots: void sendAliveMessage(); void discoverTimeout(); - void networkConfigurationChanged(const QNetworkConfiguration &config); + //void networkConfigurationChanged(const QNetworkConfiguration &config); public slots: bool enable(); diff --git a/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.cpp b/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.cpp index 56463945..18e1c546 100644 --- a/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.cpp +++ b/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.cpp @@ -41,7 +41,11 @@ Radio433BrennenstuhlGateway::Radio433BrennenstuhlGateway(QObject *parent) : // UDP socket to sending data to gateway m_gateway = new QUdpSocket(this); connect(m_gateway, &QUdpSocket::readyRead, this, &Radio433BrennenstuhlGateway::readData); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(m_gateway, &QUdpSocket::errorOccurred, this, &Radio433BrennenstuhlGateway::gatewayError); +#else connect(m_gateway, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(gatewayError(QAbstractSocket::SocketError))); +#endif // Timer for discovery of the Gateway m_discoverTimer = new QTimer(this); @@ -62,7 +66,7 @@ bool Radio433BrennenstuhlGateway::sendData(int delay, QList rawData, int re // bring rawData list to a single ByteArray, values separated by ',' foreach (int value, rawData) { - data.append(QString::number(value) + ","); + data.append(QString("%1,").arg(value).toUtf8()); } /* Protocol: @@ -79,7 +83,7 @@ bool Radio433BrennenstuhlGateway::sendData(int delay, QList rawData, int re * ; | end of command */ - message.append("TXP:0,0," + QString::number(repetitions) + ",0," + QString::number(delay) + "," + QString::number(rawData.count()/2) + "," + data + ";"); + message.append(QString("TXP:0,0,%1,0,%2,%3,").arg(repetitions).arg(delay).arg(rawData.count() / 2).toUtf8() + data + QByteArray(";")); if (m_gateway->writeDatagram(message, m_gatewayAddress, m_port) > 0) { m_available = true; diff --git a/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.h b/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.h index 2f1988f0..84839e9b 100644 --- a/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.h +++ b/libnymea-core/hardware/radio433/radio433brennenstuhlgateway.h @@ -36,7 +36,7 @@ #include #include -#include "libnymea.h" +#include namespace nymeaserver { diff --git a/libnymea-core/integrations/plugininfocache.cpp b/libnymea-core/integrations/plugininfocache.cpp index c003a059..3ec16a86 100644 --- a/libnymea-core/integrations/plugininfocache.cpp +++ b/libnymea-core/integrations/plugininfocache.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "nymeasettings.h" #include "loggingcategories.h" @@ -46,7 +47,7 @@ PluginInfoCache::PluginInfoCache() void PluginInfoCache::cachePluginInfo(const QJsonObject &metaData) { - QString fileName = metaData.value("id").toString().remove(QRegExp("[{}]")) + ".cache"; + QString fileName = metaData.value("id").toString().remove(QRegularExpression("[{}]")) + ".cache"; QDir path = NymeaSettings::cachePath() + "/plugininfo/"; if (!path.exists()) { if (!path.mkpath(path.absolutePath())) { @@ -65,7 +66,7 @@ void PluginInfoCache::cachePluginInfo(const QJsonObject &metaData) QJsonObject PluginInfoCache::loadPluginInfo(const PluginId &pluginId) { - QString fileName = pluginId.toString().remove(QRegExp("[{}]")) + ".cache"; + QString fileName = pluginId.toString().remove(QRegularExpression("[{}]")) + ".cache"; QDir path = NymeaSettings::cachePath() + "/plugininfo/"; QFile file(path.absoluteFilePath(fileName)); if (!file.open(QFile::ReadOnly)) { diff --git a/libnymea-core/integrations/python/pyutils.h b/libnymea-core/integrations/python/pyutils.h index c62d01cd..4fa3b804 100644 --- a/libnymea-core/integrations/python/pyutils.h +++ b/libnymea-core/integrations/python/pyutils.h @@ -15,28 +15,28 @@ PyObject *QVariantToPyObject(const QVariant &value) { PyObject *pyValue = nullptr; - switch (value.type()) { - case QVariant::Bool: + switch (static_cast(value.type())) { + case QMetaType::Bool: pyValue = PyBool_FromLong(value.toBool()); break; - case QVariant::Int: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::LongLong: + case QMetaType::ULongLong: pyValue = PyLong_FromLongLong(value.toLongLong()); break; - case QVariant::String: - case QVariant::ByteArray: + case QMetaType::QString: + case QMetaType::QByteArray: pyValue = PyUnicode_FromString(value.toString().toUtf8()); break; - case QVariant::Double: + case QMetaType::Double: pyValue = PyFloat_FromDouble(value.toDouble()); break; - case QVariant::Invalid: + case QMetaType::UnknownType: pyValue = Py_None; Py_INCREF(pyValue); break; - case QVariant::DateTime: { + case QMetaType::QDateTime: { PyObject *longObj = PyLong_FromLongLong(value.toDateTime().toMSecsSinceEpoch() / 1000); PyObject *timeTuple = Py_BuildValue("(O)", longObj); pyValue = PyDateTime_FromTimestamp(timeTuple); @@ -44,7 +44,7 @@ PyObject *QVariantToPyObject(const QVariant &value) Py_DECREF(timeTuple); break; } - case QVariant::StringList: { + case QMetaType::QStringList: { QStringList stringList = value.toStringList(); pyValue = PyTuple_New(stringList.length()); for (int i = 0; i < stringList.count(); i++) { diff --git a/libnymea-core/integrations/scriptintegrationplugin.cpp b/libnymea-core/integrations/scriptintegrationplugin.cpp index b6dd4025..75476021 100644 --- a/libnymea-core/integrations/scriptintegrationplugin.cpp +++ b/libnymea-core/integrations/scriptintegrationplugin.cpp @@ -76,8 +76,8 @@ bool ScriptIntegrationPlugin::loadScript(const QString &fileName) spacer += ' '; } QDebug dbg = qWarning(dcThingManager()).nospace().noquote(); - dbg << metaDataFileName << ":" << lineIndex << ":" << errorOffset + 2 << ": error: JSON parsing failed: " << error.errorString() << ": " << data.trimmed() << endl; - dbg << data << endl; + dbg << metaDataFileName << ":" << lineIndex << ":" << errorOffset + 2 << ": error: JSON parsing failed: " << error.errorString() << ": " << data.trimmed() << '\n'; + dbg << data << '\n'; dbg << spacer << "^"; return false; } diff --git a/libnymea-core/integrations/thingmanagerimplementation.cpp b/libnymea-core/integrations/thingmanagerimplementation.cpp index c4fcea5d..8fdfee94 100644 --- a/libnymea-core/integrations/thingmanagerimplementation.cpp +++ b/libnymea-core/integrations/thingmanagerimplementation.cpp @@ -71,6 +71,7 @@ #include #include #include +#include ThingManagerImplementation::ThingManagerImplementation(HardwareManager *hardwareManager, LogEngine *logEngine, const QLocale &locale, QObject *parent) : ThingManager(parent), @@ -1962,7 +1963,8 @@ void ThingManagerImplementation::onLoaded() void ThingManagerImplementation::cleanupThingStateCache() { QDir dir(NymeaSettings::cachePath() + "/thingstates/"); - foreach (const QFileInfo &entry, dir.entryList()) { + foreach (const QString &entryString, dir.entryList()) { + QFileInfo entry(entryString); ThingId thingId(entry.baseName()); if (!m_configuredThings.contains(thingId)) { qCDebug(dcThingManager()) << "Thing ID" << thingId.toString() << "not found in configured things. Cleaning up stale thing state cache."; @@ -2298,7 +2300,7 @@ void ThingManagerImplementation::postSetupThing(Thing *thing) QString ThingManagerImplementation::statesCacheFile(const ThingId &thingId) { - return NymeaSettings::cachePath() + "/thingstates/" + thingId.toString().remove(QRegExp("[{}]")) + ".cache"; + return NymeaSettings::cachePath() + "/thingstates/" + thingId.toString().remove(QRegularExpression("[{}]")) + ".cache"; } void ThingManagerImplementation::loadThingStates(Thing *thing) @@ -2331,8 +2333,17 @@ void ThingManagerImplementation::loadThingStates(Thing *thing) value = settings->value(stateType.id().toString()); } value.convert(stateType.type()); - minValue.convert(stateType.type()); - maxValue.convert(stateType.type()); + + // Note: the convert method has changed in Qt6. I will return a valid + // QVariant and therefore set min max values for the state even tough they + // are still invalid on purpose + + if (minValue.isValid()) + minValue.convert(stateType.type()); + + if (maxValue.isValid()) + maxValue.convert(stateType.type()); + QVariantList convertedPossibleValues; foreach (QVariant possibleValue, possibleValues) { possibleValue.convert(stateType.type()); @@ -2409,12 +2420,12 @@ void ThingManagerImplementation::registerStateLogger(Thing *thing, const StateTy { StateType stateType = thing->thingClass().getStateType(stateTypeId); QString name = thing->id().toString() + "-" + stateType.name(); - QList sampledTypes { - QVariant::Int, - QVariant::UInt, - QVariant::LongLong, - QVariant::ULongLong, - QVariant::Double + QList sampledTypes { + QMetaType::Int, + QMetaType::UInt, + QMetaType::LongLong, + QMetaType::ULongLong, + QMetaType::Double }; Types::LoggingType loggingType = sampledTypes.contains(stateType.type()) ? Types::LoggingTypeSampled : Types::LoggingTypeDiscrete; Logger *logger = m_logEngine->registerLogSource("state-" + name, {}, loggingType, stateType.name()); diff --git a/libnymea-core/integrations/translator.cpp b/libnymea-core/integrations/translator.cpp index 552f60c0..c32ef1fb 100644 --- a/libnymea-core/integrations/translator.cpp +++ b/libnymea-core/integrations/translator.cpp @@ -29,13 +29,15 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "translator.h" -#include "nymeasettings.h" #include "thingmanagerimplementation.h" -#include "loggingcategories.h" -#include "integrations/integrationplugin.h" -#include +#include +#include +#include + #include +#include +#include Translator::Translator(ThingManagerImplementation *thingManager): m_thingManager(thingManager) @@ -99,7 +101,7 @@ void Translator::loadTranslator(IntegrationPlugin *plugin, const QLocale &locale loaded = true; } } else { - QString pluginId = plugin->pluginId().toString().remove(QRegExp("[{}]")); + QString pluginId = plugin->pluginId().toString().remove(QRegularExpression("[{}]")); foreach (const QString &pluginPath, m_thingManager->pluginSearchDirs()) { if (translator->load(locale, pluginId, "-", QDir(pluginPath + "/translations/").absolutePath(), ".qm")) { diff --git a/libnymea-core/jsonrpc/configurationhandler.cpp b/libnymea-core/jsonrpc/configurationhandler.cpp index 3c7134eb..366e1366 100644 --- a/libnymea-core/jsonrpc/configurationhandler.cpp +++ b/libnymea-core/jsonrpc/configurationhandler.cpp @@ -753,7 +753,7 @@ QVariantMap ConfigurationHandler::packBasicConfiguration() QVariantMap basicConfiguration; basicConfiguration.insert("serverName", NymeaCore::instance()->configuration()->serverName()); basicConfiguration.insert("serverUuid", NymeaCore::instance()->configuration()->serverUuid().toString()); - basicConfiguration.insert("serverTime", NymeaCore::instance()->timeManager()->currentDateTime().toTime_t()); + basicConfiguration.insert("serverTime", NymeaCore::instance()->timeManager()->currentDateTime().toSecsSinceEpoch()); basicConfiguration.insert("timeZone", QTimeZone::systemTimeZoneId()); basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name()); basicConfiguration.insert("location", QVariantMap{ diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp index 404822b4..2722516e 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp @@ -76,6 +76,7 @@ #include #include #include +#include namespace nymeaserver { @@ -698,7 +699,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac qCDebug(dcJsonRpc()) << "Invoking method" << targetNamespace + '.' + method << "from client" << clientId; - JsonReply *reply; + JsonReply *reply = nullptr; if (handler->metaObject()->indexOfMethod(method.toUtf8() + "(QVariantMap,JsonContext)") >= 0) { QMetaObject::invokeMethod(handler, method.toUtf8().data(), Q_RETURN_ARG(JsonReply*, reply), Q_ARG(QVariantMap, params), Q_ARG(JsonContext, callContext)); } else { @@ -861,12 +862,18 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) // Sanity checks on API: // * Make sure all $ref: entries are valid. // * A handler must not register a type name that is already registered by a previously loaded handler with different content. + + qCDebug(dcJsonRpc()).nospace() << "Registering JSON RPC handler: " << handler->name() << ". Performing sanity check"; + + QVariantMap enums = m_api.value("enums").toMap(); + QVariantMap flags = m_api.value("flags").toMap(); + QVariantMap types = m_api.value("types").toMap(); QVariantMap methods = m_api.value("methods").toMap(); QVariantMap notifications = m_api.value("notifications").toMap(); + QVariantMap apiIncludingThis = m_api; // Verify enums name clash - QVariantMap enums = m_api.value("enums").toMap(); foreach (const QString &enumName, handler->jsonEnums().keys()) { QVariantList list = handler->jsonEnums().value(enumName).toList(); if (enums.contains(enumName) && enums.value(enumName) != list) { @@ -877,7 +884,6 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) } apiIncludingThis["enums"] = enums; - QVariantMap flags = m_api.value("flags").toMap(); foreach (const QString &flagName, handler->jsonFlags().keys()) { QVariant flagDescription = handler->jsonFlags().value(flagName); if (enums.contains(flagName)) { @@ -893,17 +899,21 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) apiIncludingThis["flags"] = flags; // Verify objects - QVariantMap existingTypes = m_api.value("types").toMap(); - QVariantMap typesIncludingThis = existingTypes; - typesIncludingThis.unite(handler->jsonObjects()); + QVariantMap typesIncludingThis = types; + foreach (const QString &objectName, handler->jsonObjects().keys()) { + if (types.contains(objectName) && types.value(objectName) != handler->jsonObjects().value(objectName)) { + qCWarning(dcJsonRpc()) << "Object type" << objectName << "is already registered and not the same. Not registering handler" << handler->name(); + qCWarning(dcJsonRpc()) << types.value(objectName); + qCWarning(dcJsonRpc()) << handler->jsonObjects().value(objectName); + return false; + } else { + typesIncludingThis.insert(objectName, handler->jsonObjects().value(objectName)); + } + } + apiIncludingThis["types"] = typesIncludingThis; foreach (const QString &objectName, handler->jsonObjects().keys()) { QVariantMap object = handler->jsonObjects().value(objectName).toMap(); - // Check for name clashes - if (existingTypes.contains(objectName) && existingTypes.value(objectName) != handler->jsonObjects().value(objectName)) { - qCWarning(dcJsonRpc()) << "Object type" << objectName << "is already registered. Not registering handler" << handler->name(); - return false; - } // Check for invalid $ref: entries if (!JsonValidator::checkRefs(object, apiIncludingThis)) { qCWarning(dcJsonRpc()).nospace() << "Invalid reference in object type " << objectName << ". Not registering handler " << handler->name(); @@ -917,7 +927,7 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) QVariantMap method = handler->jsonMethods().value(methodName).toMap(); if (handler->metaObject()->indexOfMethod(methodName.toUtf8() + "(QVariantMap)") < 0 - && handler->metaObject()->indexOfMethod(methodName.toUtf8() + "(QVariantMap,JsonContext)") < 0) { + && handler->metaObject()->indexOfMethod(methodName.toUtf8() + "(QVariantMap,JsonContext)") < 0) { qCWarning(dcJsonRpc()).nospace().noquote() << "Invalid method \"" << methodName << "\". Method \"JsonReply* " + methodName + "(QVariantMap,JsonContext)\" does not exist. Not registering handler " << handler->name(); return false; } @@ -931,7 +941,16 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) } newMethods.insert(handler->name() + '.' + methodName, method); } - methods.unite(newMethods); + + foreach (const QString &methodName, newMethods.keys()) { + if (methods.contains(methodName)) { + qCWarning(dcJsonRpc()).nospace() << "Method " << methodName << " has already been registered. Not registering handler " << handler->name(); + return false; + } + + methods.insert(methodName, newMethods.value(methodName)); + } + apiIncludingThis["methods"] = methods; // Verify notifications @@ -944,7 +963,17 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) } newNotifications.insert(handler->name() + '.' + notificationName, notification); } - notifications.unite(newNotifications); + + + foreach (const QString ¬ificationName, newNotifications.keys()) { + if (notifications.contains(notificationName)) { + qCWarning(dcJsonRpc()).nospace() << "Notification " << notificationName << " has already been registered. Not registering handler " << handler->name(); + return false; + } + + notifications.insert(notificationName, newNotifications.value(notificationName)); + } + apiIncludingThis["notifications"] = notifications; // Checks completed. Store new API @@ -954,10 +983,10 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) m_handlers.insert(handler->name(), handler); for (int i = 0; i < handler->metaObject()->methodCount(); ++i) { QMetaMethod method = handler->metaObject()->method(i); - if (method.methodType() == QMetaMethod::Signal && QString(method.name()).contains(QRegExp("^[A-Z]"))) { - if (method.parameterCount() == 1 && method.parameterType(0) == QVariant::Map) { + if (method.methodType() == QMetaMethod::Signal && QString(method.name()).contains(QRegularExpression("^[A-Z]"))) { + if (method.parameterCount() == 1 && method.parameterType(0) == QMetaType::QVariantMap) { QObject::connect(handler, method, this, metaObject()->method(metaObject()->indexOfSlot("sendNotification(QVariantMap)"))); - } else if (method.parameterCount() == 2 && method.parameterType(0) == QVariant::Uuid && method.parameterType(1) == QVariant::Map) { + } else if (method.parameterCount() == 2 && method.parameterType(0) == QMetaType::QUuid && method.parameterType(1) == QMetaType::QVariantMap) { QObject::connect(handler, method, this, metaObject()->method(metaObject()->indexOfSlot("sendClientNotification(QUuid,QVariantMap)"))); } } diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.h b/libnymea-core/jsonrpc/jsonrpcserverimplementation.h index 8dacfb1a..9cc87186 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.h +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.h @@ -104,19 +104,19 @@ private slots: private: QVariantMap m_api; - QHash m_experiences; + QHash m_experiences; QHash m_handlers; QHash m_asyncReplies; - QHash m_clientTransports; + QHash m_clientTransports; QHash m_clientBuffers; QHash m_clientNotifications; QHash m_clientLocales; QHash m_clientTokens; QHash m_pushButtonTransactions; - QHash m_newConnectionWaitTimers; + QHash m_newConnectionWaitTimers; - QHash m_pairingRequests; + QHash m_pairingRequests; int m_notificationId; diff --git a/libnymea-core/jsonrpc/jsonvalidator.cpp b/libnymea-core/jsonrpc/jsonvalidator.cpp index 340b8556..68f709a5 100644 --- a/libnymea-core/jsonrpc/jsonvalidator.cpp +++ b/libnymea-core/jsonrpc/jsonvalidator.cpp @@ -36,6 +36,7 @@ #include #include #include +#include namespace nymeaserver { @@ -48,26 +49,26 @@ bool JsonValidator::checkRefs(const QVariantMap &map, const QVariantMap &api) if (map.value(key).toString().startsWith("$ref:")) { QString refName = map.value(key).toString().remove("$ref:"); if (!enums.contains(refName) && !flags.contains(refName) && !types.contains(refName)) { - qCWarning(dcJsonRpc()) << "Invalid reference to" << refName; + qCWarning(dcJsonRpc()) << "Invalid reference to" << refName << "in" << key << map; return false; } } - if (map.value(key).type() == QVariant::Map) { + if (map.value(key).userType() == QMetaType::QVariantMap) { bool ret = checkRefs(map.value(key).toMap(), api); if (!ret) { return false; } } - if (map.value(key).type() == QVariant::List) { + if (map.value(key).userType() == QMetaType::QVariantList) { foreach (const QVariant &entry, map.value(key).toList()) { if (entry.toString().startsWith("$ref:")) { QString refName = entry.toString().remove("$ref:"); if (!enums.contains(refName) && !flags.contains(refName) && !types.contains(refName)) { - qCWarning(dcJsonRpc()) << "Invalid reference to" << refName; + qCWarning(dcJsonRpc()) << "Invalid reference to" << refName << "in" << key << map; return false; } } - if (entry.type() == QVariant::Map) { + if (entry.userType() == QMetaType::QVariantMap) { bool ret = checkRefs(map.value(key).toMap(), api); if (!ret) { return false; @@ -113,16 +114,16 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q { // Make sure all required values are available foreach (const QString &key, definition.keys()) { - QRegExp isOptional = QRegExp("^([a-z]:)*o:.*"); - if (isOptional.exactMatch(key)) { + QRegularExpression isOptional = QRegularExpression("^([a-z]:)*o:.*"); + if (isOptional.match(key).hasMatch()) { continue; } - QRegExp isReadOnly = QRegExp("^([a-z]:)*r:.*"); - if (isReadOnly.exactMatch(key) && openMode.testFlag(QIODevice::WriteOnly)) { + QRegularExpression isReadOnly = QRegularExpression("^([a-z]:)*r:.*"); + if (isReadOnly.match(key).hasMatch() && openMode.testFlag(QIODevice::WriteOnly)) { continue; } QString trimmedKey = key; - trimmedKey.remove(QRegExp("^(o:|r:|d:)*")); + trimmedKey.remove(QRegularExpression("^(o:|r:|d:)*")); if (!map.contains(trimmedKey)) { return Result(false, "Missing required key: " + key, key); } @@ -133,9 +134,10 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q // Is the key allowed in here? QVariant expectedValue = definition.value(key); foreach (const QString &definitionKey, definition.keys()) { - QRegExp regExp = QRegExp("(o:|r:|d:)*" + key); - if (regExp.exactMatch(definitionKey)) { + QRegularExpression regExp = QRegularExpression("(o:|r:|d:)" + key); + if (regExp.match(definitionKey).hasMatch()) { expectedValue = definition.value(definitionKey); + break; } } if (!expectedValue.isValid()) { @@ -158,14 +160,14 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q return result; } - } + } return Result(true); } JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const QVariant &definition, const QVariantMap &api, QIODevice::OpenMode openMode) { - if (definition.type() == QVariant::String) { + if (definition.userType() == QMetaType::QString) { QString expectedTypeName = definition.toString(); if (expectedTypeName.startsWith("$ref:")) { @@ -178,16 +180,31 @@ JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const QVariant refDefinition = enums.value(refName); QVariantList enumList = refDefinition.toList(); - if (!enumList.contains(value.toString())) { - return Result(false, "Expected enum value for" + refName + " but got " + value.toString()); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (value.metaType().id() == QMetaType::QStringList) { + foreach (const QString &valueString, value.toStringList()) { + if (!enumList.contains(valueString)) { + return Result(false, "Expected enum value for " + refName + " but got " + value.toString()); + } + } + } else { + if (!enumList.contains(value.toString())) { + return Result(false, "Expected enum value for " + refName + " but got " + value.toString()); + } } +#else + if (!enumList.contains(value.toString())) { + return Result(false, "Expected enum value for " + refName + " but got " + value.toString()); + } +#endif return Result(true); } + // Or flags QVariantMap flags = api.value("flags").toMap(); if (flags.contains(refName)) { QVariant refDefinition = flags.value(refName); - if (value.type() != QVariant::List && value.type() != QVariant::StringList) { + if (value.userType() != QMetaType::QVariantList && value.userType() != QMetaType::QStringList) { return Result(false, "Expected flags " + refName + " but got " + value.toString()); } QString flagEnum = refDefinition.toList().first().toString(); @@ -206,7 +223,23 @@ JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const } JsonHandler::BasicType expectedBasicType = JsonHandler::enumNameToValue(expectedTypeName); - QVariant::Type expectedVariantType = JsonHandler::basicTypeToVariantType(expectedBasicType); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + // Any string converts fine to Uuid, but the resulting uuid might be null + if (expectedBasicType == JsonHandler::Uuid && value.toUuid().isNull()) { + + QString typeName(value.typeName()); + //qCCritical(dcJsonRpc()) << value << value.userType() << value.typeId() << value.typeName() << value.toString() << value.toUuid() << value.canConvert(QMetaType::QUuid); + + // Verify if this is one of our own uuid types + if (typeName == "ThingId" || typeName == "EventTypeId" || typeName == "StateTypeId" || typeName == "ActionTypeId") { + return Result(true); + }/* else { + return Result(false, "Invalid Uuid: " + value.toString()); + }*/ + } +#else + QMetaType::Type expectedVariantType = JsonHandler::basicTypeToMetaType(expectedBasicType); // Verify basic compatiblity if (expectedBasicType != JsonHandler::Variant && !value.canConvert(expectedVariantType)) { @@ -217,6 +250,8 @@ JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const if (expectedBasicType == JsonHandler::Uuid && value.toUuid().isNull()) { return Result(false, "Invalid Uuid: " + value.toString()); } +#endif + // Make sure ints are valid if (expectedBasicType == JsonHandler::Int) { bool ok; @@ -260,18 +295,27 @@ JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const return Result(true); } - if (definition.type() == QVariant::Map) { - if (value.type() != QVariant::Map) { + if (definition.userType() == QMetaType::QVariantMap) { + if (value.userType() != QMetaType::QVariantMap) { return Result(false, "Invalid value. Expected a map but received: " + value.toString()); } return validateMap(value.toMap(), definition.toMap(), api, openMode); } - if (definition.type() == QVariant::List) { + if (definition.userType() == QMetaType::QVariantList) { QVariantList list = definition.toList(); QVariant entryDefinition = list.first(); - if (value.type() != QVariant::List && value.type() != QVariant::StringList) { - return Result(false, "Expected list of " + entryDefinition.toString() + " but got value of type " + value.typeName() + "\n" + QJsonDocument::fromVariant(value).toJson()); + + if (value.userType() != QMetaType::QVariantList && value.userType() != QMetaType::QStringList) { + + QString elementType = QString(value.typeName()).remove("QList<").remove(">"); + if (elementType == "ThingId" || elementType == "EventTypeId" || elementType == "StateTypeId" || elementType == "ActionTypeId") { + elementType = "Uuid"; + } /*else if (elementType == "ParamList") { + elementType = "Param"; + } else { + return Result(false, "Expected list of " + entryDefinition.toString() + " but got value of type " + value.typeName() + "\n" + QJsonDocument::fromVariant(value).toJson()); + }*/ } foreach (const QVariant &entry, value.toList()) { Result result = validateEntry(entry, entryDefinition, api, openMode); diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 5c462f4b..91364af6 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -672,9 +672,11 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) case Zigbee::ZigbeeBackendTypeNxp: networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeNxp)); break; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) case Zigbee::ZigbeeBackendTypeTi: networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeTi)); break; +#endif } switch (network->state()) { diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 8848a559..e1c9dc9a 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -3,38 +3,13 @@ TARGET = nymea-core include(../nymea.pri) -QT += bluetooth dbus qml sql websockets serialport +QT += core bluetooth dbus qml sql websockets serialport INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto CONFIG += link_pkgconfig PKGCONFIG += nymea-mqtt nymea-networkmanager nymea-zigbee nymea-remoteproxyclient nymea-gpio -CONFIG(withoutpython) { - message("Building without python support.") - CONFIG -= python -} else:packagesExist(python3-embed) { -# As of Ubuntu focal, there's a commonly named python3-embed pointing to the distro version of python -# For everything below python 3.8 we need to manually select one - PKGCONFIG += python3-embed - CONFIG += python -} else:packagesExist(python-3.5) { - # xenial, stretch - PKGCONFIG += python-3.5 - CONFIG += python -} else:packagesExist(python-3.6) { - # bionic - PKGCONFIG += python-3.6 - CONFIG += python -} else:packagesExist(python-3.7) { - # buster, eoan - PKGCONFIG += python-3.7 - CONFIG += python -} else { - message("Python development package not found. Building without python support.") - CONFIG -= python -} - packagesExist(systemd) { message(Building with systemd support) PKGCONFIG += systemd @@ -43,12 +18,25 @@ packagesExist(systemd) { message(Building without systemd support) } -packagesExist(Qt5SerialBus) { - message("Building with QtSerialBus support.") - PKGCONFIG += Qt5SerialBus - DEFINES += WITH_QTSERIALBUS +greaterThan(QT_MAJOR_VERSION, 5) { + qtHaveModule(serialbus) { + message("Building with QtSerialBus support.") + QT *= serialbus + DEFINES += WITH_QTSERIALBUS + } else { + message("QtSerialBus package not found. Building without QtSerialBus support.") + } + + # Separate module in Qt6 + QT *= concurrent } else { - message("Qt5SerialBus package not found. Building without QtSerialBus support.") + packagesExist(Qt5SerialBus) { + message("Building with QtSerialBus support.") + PKGCONFIG += Qt5SerialBus + DEFINES += WITH_QTSERIALBUS + } else { + message("Qt5SerialBus package not found. Building without QtSerialBus support.") + } } # Note: udev is not available on all platforms diff --git a/libnymea-core/logging/logengineinfluxdb.cpp b/libnymea-core/logging/logengineinfluxdb.cpp index bebc3b3f..c3a5f54a 100644 --- a/libnymea-core/logging/logengineinfluxdb.cpp +++ b/libnymea-core/logging/logengineinfluxdb.cpp @@ -34,6 +34,7 @@ #include #include #include +#include LogEngineInfluxDB::LogEngineInfluxDB(const QString &host, const QString &dbName, const QString &username, const QString &password, QObject *parent) : LogEngine{parent}, @@ -185,18 +186,18 @@ void LogEngineInfluxDB::logEvent(Logger *logger, const QStringList &tags, const foreach (const QString &name, values.keys()) { QVariant value = values.value(name); - switch (value.type()) { - case QVariant::String: - case QVariant::ByteArray: + switch (value.userType()) { + case QMetaType::QString: + case QMetaType::QByteArray: fieldsList.append(QString("%1=\"%2\"").arg(name).arg(QString(value.toByteArray().toPercentEncoding()))); break; - case QVariant::Uuid: + case QMetaType::QUuid: fieldsList.append(QString("%1=\"%2\"").arg(name).arg(value.toString())); break; - case QVariant::Int: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::LongLong: + case QMetaType::ULongLong: fieldsList.append(QString("%1=%2i").arg(name).arg(value.toString())); break; default: @@ -490,10 +491,10 @@ LogFetchJob *LogEngineInfluxDB::fetchLogEntries(const QStringList &sources, cons for (int i = 1; i < columns.count(); i++) { QString column = columns.at(i); if (sampleRate != Types::SampleRateAny) { - column.remove(QRegExp("^mean_")); + column.remove(QRegularExpression("^mean_")); } QVariant value = values.at(i); - if (value.type() == QVariant::String || value.type() == QVariant::ByteArray) { + if (value.userType() == QMetaType::QString || value.userType() == QMetaType::QByteArray) { valuesMap.insert(column, QByteArray::fromPercentEncoding(value.toByteArray())); } else { valuesMap.insert(column, values.at(i)); @@ -838,3 +839,4 @@ void QueryJob::finish(QNetworkReply::NetworkError status, const QVariantList &re QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, status), Q_ARG(QVariantList, results)); QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); } + diff --git a/libnymea-core/logging/logengineinfluxdb.h b/libnymea-core/logging/logengineinfluxdb.h index b421db89..f95b0a41 100644 --- a/libnymea-core/logging/logengineinfluxdb.h +++ b/libnymea-core/logging/logengineinfluxdb.h @@ -31,7 +31,6 @@ #ifndef LOGENGINEINFLUXDB_H #define LOGENGINEINFLUXDB_H -#include "logging/logengine.h" #include #include #include @@ -40,9 +39,15 @@ #include #include -class QueryJob: public QObject { +#include "logging/logentry.h" +#include "logging/logengine.h" + +class QueryJob: public QObject +{ Q_OBJECT +public: explicit QueryJob(const QNetworkRequest &request, bool post, bool isInit, QObject *parent = nullptr); + ~QueryJob() = default; signals: void finished(QNetworkReply::NetworkError status, const QVariantList &response); @@ -118,12 +123,13 @@ private: QHash m_loggers; - QQueue m_initQueryQueue; + QQueue m_initQueryQueue; QueryJob *m_currentInitQuery = nullptr; - QQueue m_queryQueue; + QQueue m_queryQueue; QueryJob *m_currentQuery = nullptr; QQueue m_writeQueue; - QNetworkReply* m_currentWriteReply = nullptr; + QNetworkReply *m_currentWriteReply = nullptr; }; + #endif // LOGENGINEINFLUXDB_H diff --git a/libnymea-core/nymeaconfiguration.cpp b/libnymea-core/nymeaconfiguration.cpp index c9d25438..4712e251 100644 --- a/libnymea-core/nymeaconfiguration.cpp +++ b/libnymea-core/nymeaconfiguration.cpp @@ -320,7 +320,7 @@ QLocale NymeaConfiguration::locale() const { NymeaSettings settings(NymeaSettings::SettingsRoleGlobal); settings.beginGroup("nymead"); - return settings.value("language", "en_US").toString(); + return QLocale(settings.value("language", "en_US").toString()); } void NymeaConfiguration::setLocale(const QLocale &locale) diff --git a/libnymea-core/ruleengine/rule.cpp b/libnymea-core/ruleengine/rule.cpp index 9025df2b..f8eee1b4 100644 --- a/libnymea-core/ruleengine/rule.cpp +++ b/libnymea-core/ruleengine/rule.cpp @@ -243,11 +243,11 @@ void Rule::setActive(const bool &active) QDebug operator<<(QDebug dbg, const Rule &rule) { QDebugStateSaver saver(dbg); - dbg.nospace() << endl << "=== Rule begin ===" << endl; - dbg.nospace() << "ID:" << rule.id().toString() << endl; - dbg.nospace() << "Name:" << rule.name() << endl; - dbg.nospace() << "Enabled:" << rule.enabled() << endl; - dbg.nospace() << "Active:" << rule.active() << endl; + dbg.nospace() << '\n' << "=== Rule begin ===" << '\n'; + dbg.nospace() << "ID:" << rule.id().toString() << '\n'; + dbg.nospace() << "Name:" << rule.name() << '\n'; + dbg.nospace() << "Enabled:" << rule.enabled() << '\n'; + dbg.nospace() << "Active:" << rule.active() << '\n'; dbg.nospace() << rule.eventDescriptors(); dbg.nospace() << rule.timeDescriptor(); dbg.nospace() << rule.stateEvaluator(); diff --git a/libnymea-core/ruleengine/ruleaction.cpp b/libnymea-core/ruleengine/ruleaction.cpp index 61c5b313..5d49ab0e 100644 --- a/libnymea-core/ruleengine/ruleaction.cpp +++ b/libnymea-core/ruleengine/ruleaction.cpp @@ -211,9 +211,9 @@ void RuleAction::operator=(const RuleAction &other) QDebug operator<<(QDebug dbg, const RuleAction &ruleAction) { QDebugStateSaver saver(dbg); - dbg.nospace() << "RuleAction(ActionTypeId:" << ruleAction.actionTypeId().toString() << ", ThingId:" << ruleAction.thingId().toString() << ", Interface:" << ruleAction.interface() << ", InterfaceAction:" << ruleAction.interfaceAction() << ", BrowserItemId:" << ruleAction.browserItemId() << ")" << endl; + dbg.nospace() << "RuleAction(ActionTypeId:" << ruleAction.actionTypeId().toString() << ", ThingId:" << ruleAction.thingId().toString() << ", Interface:" << ruleAction.interface() << ", InterfaceAction:" << ruleAction.interfaceAction() << ", BrowserItemId:" << ruleAction.browserItemId() << ")" << '\n'; for (int i = 0; i < ruleAction.ruleActionParams().count(); i++) { - dbg.nospace() << " " << i << ": " << ruleAction.ruleActionParams().at(i) << endl; + dbg.nospace() << " " << i << ": " << ruleAction.ruleActionParams().at(i) << '\n'; } return dbg; } @@ -221,7 +221,7 @@ QDebug operator<<(QDebug dbg, const RuleAction &ruleAction) QDebug operator<<(QDebug dbg, const QList &ruleActionList) { QDebugStateSaver saver(dbg); - dbg.nospace() << "RuleActionList (count:" << ruleActionList.count() << "):" << endl; + dbg.nospace() << "RuleActionList (count:" << ruleActionList.count() << "):" << '\n'; for (int i = 0; i < ruleActionList.count(); i++ ) { dbg.nospace() << " " << i << ": " << ruleActionList.at(i); } diff --git a/libnymea-core/ruleengine/ruleactionparam.cpp b/libnymea-core/ruleengine/ruleactionparam.cpp index fadca87a..cdcb54f7 100644 --- a/libnymea-core/ruleengine/ruleactionparam.cpp +++ b/libnymea-core/ruleengine/ruleactionparam.cpp @@ -235,9 +235,9 @@ RuleActionParams RuleActionParams::operator<<(const RuleActionParam &ruleActionP QDebug operator<<(QDebug dbg, const RuleActionParams &ruleActionParams) { QDebugStateSaver saver(dbg); - dbg.nospace() << "RuleActionParamList (count:" << ruleActionParams.count() << ")" << endl; + dbg.nospace() << "RuleActionParamList (count:" << ruleActionParams.count() << ")" << '\n'; for (int i = 0; i < ruleActionParams.count(); i++ ) { - dbg.nospace() << " " << i << ": " << ruleActionParams.at(i) << endl; + dbg.nospace() << " " << i << ": " << ruleActionParams.at(i) << '\n'; } return dbg; diff --git a/libnymea-core/ruleengine/ruleengine.cpp b/libnymea-core/ruleengine/ruleengine.cpp index b0aa2caf..cfa08ba3 100644 --- a/libnymea-core/ruleengine/ruleengine.cpp +++ b/libnymea-core/ruleengine/ruleengine.cpp @@ -128,6 +128,8 @@ #include #include #include +#include +#include NYMEA_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine") NYMEA_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug") @@ -185,12 +187,20 @@ QList RuleEngine::evaluateEvent(const Event &event) } ThingClass thingClass = thing->thingClass(); EventType eventType = thingClass.eventTypes().findById(event.eventTypeId()); + StateType stateType = thingClass.stateTypes().findById(event.eventTypeId()); - - if (event.params().count() == 0) { - qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event: " << thing->name() << " - " << eventType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << eventType.id().toString() << ")"; - } else { - qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event: " << thing->name() << " - " << eventType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << eventType.id().toString() << ")" << endl << " " << event.params(); + if (eventType.isValid()) { + if (event.params().count() == 0) { + qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event: " << thing->name() << " - " << eventType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << eventType.id().toString() << ")"; + } else { + qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event: " << thing->name() << " - " << eventType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << eventType.id().toString() << ")" << '\n' << " " << event.params(); + } + } else if (stateType.isValid()) { + if (event.params().count() == 0) { + qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event (state changed): " << thing->name() << " - " << stateType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << stateType.id().toString() << ")"; + } else { + qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event (state changed): " << thing->name() << " - " << stateType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << stateType.id().toString() << ")" << '\n' << " " << event.params(); + } } QList rules; @@ -342,7 +352,7 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) // Check IDs in each EventDescriptor foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) { if (!eventDescriptor.isValid()) { - qWarning(dcRuleEngine()) << "EventDescriptor is incomplete. It must have either eventTypeId and thingId, or interface and interfaceEvent"; + qCWarning(dcRuleEngine()) << "EventDescriptor is incomplete. It must have either eventTypeId and thingId, or interface and interfaceEvent"; return RuleErrorEventTypeNotFound; } if (eventDescriptor.type() == EventDescriptor::TypeThing) { @@ -375,11 +385,11 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) // Interface based event Interface iface = m_thingManager->supportedInterfaces().findByName(eventDescriptor.interface()); if (!iface.isValid()) { - qWarning(dcRuleEngine()) << "No such interface:" << eventDescriptor.interface(); + qCWarning(dcRuleEngine()) << "No such interface:" << eventDescriptor.interface(); return RuleErrorInterfaceNotFound; } if (iface.eventTypes().findByName(eventDescriptor.interfaceEvent()).name().isEmpty() && iface.stateTypes().findByName(eventDescriptor.interfaceEvent()).name().isEmpty()) { - qWarning(dcRuleEngine()) << "Interface" << iface.name() << "has no such event:" << eventDescriptor.interfaceEvent(); + qCWarning(dcRuleEngine()) << "Interface" << iface.name() << "has no such event:" << eventDescriptor.interfaceEvent(); return RuleErrorEventTypeNotFound; } } @@ -662,7 +672,7 @@ RuleEngine::RuleError RuleEngine::executeExitActions(const RuleId &ruleId) qCDebug(dcRuleEngine) << "Executing rule exit actions of rule" << rule.name() << rule.id().toString(); m_logger->log({rule.id().toString(), "executed"}, {{"name", rule.name()}}); -// m_logEngine->logRuleExitActionsExecuted(rule); + // m_logEngine->logRuleExitActionsExecuted(rule); executeRuleActions(rule.id(), rule.exitActions()); return RuleErrorNoError; } @@ -892,7 +902,7 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const Thing paramValue = event.param(paramDescriptor.paramTypeId()).value(); } else { if (paramDescriptor.paramName().isEmpty()) { - qWarning(dcRuleEngine()) << "ParamDescriptor invalid. Either paramTypeId or paramName are required"; + qCWarning(dcRuleEngine()) << "ParamDescriptor invalid. Either paramTypeId or paramName are required"; allOK = false; continue; } @@ -907,6 +917,47 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const Thing } } +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + + QVariant descriptorValue = paramDescriptor.value(); + bool res = descriptorValue.convert(paramValue.metaType()); + if (!res) { + qCWarning(dcRuleEngine()) << "Cannot convert the params:" << paramValue << paramDescriptor.value(); + allOK = false; + } else { + // Converted successfully to the same type, now compare the values according to the param descriptor + QPartialOrdering ordering = QVariant::compare(paramValue, descriptorValue); + if (ordering == QPartialOrdering::Unordered) { + qCWarning(dcRuleEngine()) << "Cannot compair the params:" << paramValue << paramDescriptor.value(); + allOK = false; + } else { + bool result = false; + switch (paramDescriptor.operatorType()) { + case Types::ValueOperatorEquals: + result = (ordering == QPartialOrdering::equivalent); + break; + case Types::ValueOperatorGreater: + result = (ordering == QPartialOrdering::greater); + break; + case Types::ValueOperatorGreaterOrEqual: + result = (ordering == QPartialOrdering::greater || ordering == QPartialOrdering::equivalent); + break; + case Types::ValueOperatorLess: + result = (ordering == QPartialOrdering::less); + break; + case Types::ValueOperatorLessOrEqual: + result = (ordering == QPartialOrdering::less || ordering == QPartialOrdering::equivalent); + break; + case Types::ValueOperatorNotEquals: + result = (ordering != QPartialOrdering::equivalent); + break; + } + + qCDebug(dcRuleEngineDebug()) << "Comparing param value" << paramValue << "to descriptor value" << descriptorValue << "with operator" << paramDescriptor.operatorType() << "-->" << result; + allOK = result; + } + } +#else switch (paramDescriptor.operatorType()) { case Types::ValueOperatorEquals: if (paramValue != paramDescriptor.value()) { @@ -939,6 +990,7 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const Thing } break; } +#endif } // All matching! if (allOK) { @@ -981,7 +1033,7 @@ bool RuleEngine::containsState(const StateEvaluator &stateEvaluator, const Event RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction, const Rule &rule) { if (!ruleAction.isValid()) { - qWarning(dcRuleEngine()) << "Action is incomplete. It must have either thingId and actionTypeId/browserItemId, or interface and interfaceAction:" << ruleAction; + qCWarning(dcRuleEngine()) << "Action is incomplete. It must have either thingId and actionTypeId/browserItemId, or interface and interfaceAction:" << ruleAction; return RuleErrorActionTypeNotFound; } @@ -1041,7 +1093,7 @@ RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction, bool found = !paramType.defaultValue().isNull(); foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) { if (ruleActionParam.paramTypeId() == paramType.id() - || ruleActionParam.paramName() == paramType.name()) { + || ruleActionParam.paramName() == paramType.name()) { found = true; break; } @@ -1081,8 +1133,13 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru } // check if the param type of the event and the action match - QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId()); - QVariant v(eventParamType); + QMetaType::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId()); + QVariant v; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + v = QVariant::fromMetaType(QMetaType(eventParamType)); +#else + v = QVariant(static_cast(eventParamType)); +#endif if (eventParamType != paramType.type() && !v.canConvert(static_cast(paramType.type()))) { qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:"; qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type(); @@ -1097,8 +1154,13 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru } ThingClass stateThingClass = m_thingManager->findThingClass(d->thingClassId()); StateType stateType = stateThingClass.stateTypes().findById(ruleActionParam.stateTypeId()); - QVariant::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId()); - QVariant v(stateType.type()); + QMetaType::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId()); + QVariant v; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + v = QVariant::fromMetaType(QMetaType(stateType.type())); +#else + v = QVariant(static_cast(stateType.type())); +#endif if (actionParamType != stateType.type() && !v.canConvert(static_cast(actionParamType))) { qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; @@ -1110,7 +1172,7 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString(); return RuleErrorInvalidRuleActionParameter; } - if (paramType.type() != ruleActionParam.value().type() && !ruleActionParam.value().canConvert(static_cast(paramType.type()))) { + if (paramType.type() != ruleActionParam.value().userType() && !ruleActionParam.value().canConvert(static_cast(paramType.type()))) { qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type(); qCWarning(dcRuleEngine) << " -> stateType:" << ruleActionParam.value().type(); @@ -1121,7 +1183,7 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru return RuleErrorNoError; } -QVariant::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId) +QMetaType::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId) { foreach (const ThingClass &thingClass, m_thingManager->supportedThings()) { foreach (const ActionType &actionType, thingClass.actionTypes()) { @@ -1135,10 +1197,10 @@ QVariant::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId, } } - return QVariant::Invalid; + return QMetaType::UnknownType; } -QVariant::Type RuleEngine::getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId) +QMetaType::Type RuleEngine::getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId) { foreach (const ThingClass &thingClass, m_thingManager->supportedThings()) { foreach (const EventType &eventType, thingClass.eventTypes()) { @@ -1157,7 +1219,7 @@ QVariant::Type RuleEngine::getEventParamType(const EventTypeId &eventTypeId, con } } - return QVariant::Invalid; + return QMetaType::UnknownType; } void RuleEngine::appendRule(const Rule &rule) @@ -1187,7 +1249,7 @@ void RuleEngine::saveRule(const Rule &rule) CalendarItem calendarItem = rule.timeDescriptor().calendarItems().at(i); if (calendarItem.dateTime().isValid()) - settings.setValue("dateTime", calendarItem.dateTime().toTime_t()); + settings.setValue("dateTime", calendarItem.dateTime().toSecsSinceEpoch()); if (calendarItem.startTime().isValid()) settings.setValue("startTime", calendarItem.startTime().toString("hh:mm")); @@ -1221,7 +1283,7 @@ void RuleEngine::saveRule(const Rule &rule) TimeEventItem timeEventItem = rule.timeDescriptor().timeEventItems().at(i); if (timeEventItem.dateTime().isValid()) - settings.setValue("dateTime", timeEventItem.dateTime().toTime_t()); + settings.setValue("dateTime", timeEventItem.dateTime().toSecsSinceEpoch()); if (timeEventItem.time().isValid()) settings.setValue("time", timeEventItem.time().toString("hh:mm")); @@ -1339,7 +1401,7 @@ QList RuleEngine::loadRuleActions(NymeaSettings *settings) foreach (QString paramTypeIdString, settings->childGroups()) { if (paramTypeIdString.startsWith("RuleActionParam-")) { settings->beginGroup(paramTypeIdString); - QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-")); + QString strippedParamTypeIdString = paramTypeIdString.remove(QRegularExpression("^RuleActionParam-")); EventTypeId eventTypeId = EventTypeId(settings->value("eventTypeId", EventTypeId()).toString()); ParamTypeId eventParamTypeId = ParamTypeId(settings->value("eventParamTypeId", ParamTypeId()).toString()); ThingId stateThingId = ThingId(settings->value("stateThingId", ThingId()).toString()); @@ -1349,9 +1411,9 @@ QList RuleEngine::loadRuleActions(NymeaSettings *settings) StateTypeId stateTypeId = StateTypeId(settings->value("stateTypeId", StateTypeId()).toString()); QVariant value = settings->value("value"); if (settings->contains("valueType")) { - QVariant::Type valueType = static_cast(settings->value("valueType").toInt()); + QMetaType::Type valueType = static_cast(settings->value("valueType").toInt()); // Note: only warn, and continue with the QVariant guessed type - if (valueType == QVariant::Invalid) { + if (valueType == QMetaType::UnknownType) { qCWarning(dcRuleEngine()) << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant."; } else if (!value.canConvert(static_cast(valueType))) { qCWarning(dcRuleEngine()) << "Error loading rule action. Could not convert the rule action param value" << value << "to the stored type" << valueType; @@ -1510,11 +1572,11 @@ void RuleEngine::executeRuleActions(const RuleId &ruleId, const QListfindConfiguredThing(action.thingId())->thingClass().actionTypes().findById(action.actionTypeId()); m_logger->log({ruleId.toString(), "executed"}, { - {"name", m_rules.value(ruleId).name()}, - {"status", QMetaEnum::fromType().valueToKey(info->status())}, - {"thingId", info->action().thingId()}, - {"action", actionType.name()} - }); + {"name", m_rules.value(ruleId).name()}, + {"status", QMetaEnum::fromType().valueToKey(info->status())}, + {"thingId", info->action().thingId()}, + {"action", actionType.name()} + }); }); } @@ -1524,11 +1586,11 @@ void RuleEngine::executeRuleActions(const RuleId &ruleId, const QListstatus() != Thing::ThingErrorNoError) { qCWarning(dcRuleEngine) << "Error executing browser action:" << info->status(); m_logger->log({ruleId.toString(), "executed"}, { - {"name", m_rules.value(ruleId).name()}, - {"status", QMetaEnum::fromType().valueToKey(info->status())}, - {"thingId", info->browserAction().thingId()}, - {"browserItem", info->browserAction().itemId()} - }); + {"name", m_rules.value(ruleId).name()}, + {"status", QMetaEnum::fromType().valueToKey(info->status())}, + {"thingId", info->browserAction().thingId()}, + {"browserItem", info->browserAction().itemId()} + }); } }); } @@ -1546,9 +1608,9 @@ void RuleEngine::onEventTriggered(const Event &event) // Event based if (!rule.eventDescriptors().isEmpty()) { m_logger->log({rule.id().toString()}, { - {"name", rule.name()}, - {"state", "triggered"} - }); + {"name", rule.name()}, + {"state", "triggered"} + }); QList tmp; if (rule.statesActive() && rule.timeActive()) { @@ -1587,9 +1649,9 @@ void RuleEngine::onEventTriggered(const Event &event) } else { // State based rule m_logger->log({rule.id().toString()}, { - {"name", rule.name()}, - {"state", rule.active() ? "active" : "inactive"} - }); + {"name", rule.name()}, + {"state", rule.active() ? "active" : "inactive"} + }); emit ruleActiveChanged(rule); if (rule.active()) { executeRuleActions(rule.id(), rule.actions()); @@ -1668,7 +1730,7 @@ void RuleEngine::init() settings.beginGroup(childGroup); CalendarItem calendarItem; - calendarItem.setDateTime(QDateTime::fromTime_t(settings.value("dateTime", 0).toUInt())); + calendarItem.setDateTime(QDateTime::fromSecsSinceEpoch(settings.value("dateTime", 0).toUInt())); calendarItem.setStartTime(QTime::fromString(settings.value("startTime").toString())); calendarItem.setDuration(settings.value("duration", 0).toUInt()); @@ -1706,7 +1768,7 @@ void RuleEngine::init() settings.beginGroup(childGroup); TimeEventItem timeEventItem; - timeEventItem.setDateTime(QDateTime::fromTime_t(settings.value("dateTime", 0).toUInt())); + timeEventItem.setDateTime(QDateTime::fromSecsSinceEpoch(settings.value("dateTime", 0).toUInt())); timeEventItem.setTime(QTime::fromString(settings.value("time").toString())); QList weekDays; @@ -1758,13 +1820,13 @@ void RuleEngine::init() foreach (QString groupName, settings.childGroups()) { if (groupName.startsWith("ParamDescriptor-")) { settings.beginGroup(groupName); - QString strippedGroupName = groupName.remove(QRegExp("^ParamDescriptor-")); + QString strippedGroupName = groupName.remove(QRegularExpression("^ParamDescriptor-")); QVariant value = settings.value("value"); if (settings.contains("valueType")) { - QVariant::Type valueType = static_cast(settings.value("valueType").toInt()); + QMetaType::Type valueType = static_cast(settings.value("valueType").toInt()); // Note: only warn, and continue with the QVariant guessed type - if (valueType == QVariant::Invalid) { + if (valueType == QMetaType::UnknownType) { qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the param descriptor" << strippedGroupName << ". The value type will be guessed by QVariant."; } else if (!value.canConvert(static_cast(valueType))) { qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the param descriptor value" << value << "to the stored type" << valueType; diff --git a/libnymea-core/ruleengine/ruleengine.h b/libnymea-core/ruleengine/ruleengine.h index c2fb6efc..e0dbffbb 100644 --- a/libnymea-core/ruleengine/ruleengine.h +++ b/libnymea-core/ruleengine/ruleengine.h @@ -127,8 +127,8 @@ private: RuleError checkRuleAction(const RuleAction &ruleAction, const Rule &rule); RuleError checkRuleActionParam(const RuleActionParam &ruleActionParam, const ActionType &actionType, const Rule &rule); - QVariant::Type getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId); - QVariant::Type getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId); + QMetaType::Type getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId); + QMetaType::Type getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId); void appendRule(const Rule &rule); void saveRule(const Rule &rule); diff --git a/libnymea-core/ruleengine/stateevaluator.cpp b/libnymea-core/ruleengine/stateevaluator.cpp index 0b14bb30..a94e2427 100644 --- a/libnymea-core/ruleengine/stateevaluator.cpp +++ b/libnymea-core/ruleengine/stateevaluator.cpp @@ -35,6 +35,8 @@ #include "loggingcategories.h" #include "nymeasettings.h" +#include + namespace nymeaserver { StateEvaluator::StateEvaluator(const StateDescriptor &stateDescriptor): @@ -199,9 +201,9 @@ StateEvaluator StateEvaluator::loadFromSettings(NymeaSettings &settings, const Q } QVariant stateValue = settings.value("value"); if (settings.contains("valueType")) { - QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt(); + QMetaType::Type valueType = (QMetaType::Type)settings.value("valueType").toInt(); // Note: only warn, and continue with the QVariant guessed type - if (valueType == QVariant::Invalid) { + if (valueType == QMetaType::UnknownType) { qCWarning(dcRuleEngine()) << "Could not load the value type of the state evaluator. The value type will be guessed by QVariant" << stateValue; } else if (!stateValue.canConvert(valueType)) { qCWarning(dcRuleEngine()) << "Could not convert the state evaluator value" << stateValue << "to the stored type" << valueType << ". The value type will be guessed by QVariant."; @@ -266,6 +268,19 @@ bool StateEvaluator::isValid() const qCWarning(dcRuleEngine) << "Could not convert value of state descriptor" << m_stateDescriptor.stateTypeId() << " to:" << QVariant::typeToName(stateType.type()) << " Got:" << m_stateDescriptor.stateValue(); return false; } +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + QPartialOrdering ordering = QPartialOrdering::Unordered; + ordering = QVariant::compare(stateValue, stateType.maxValue()); + if (stateType.maxValue().isValid() && ordering == QPartialOrdering::Greater) { + qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Max:" << stateType.maxValue(); + return false; + } + ordering = QVariant::compare(stateValue, stateType.minValue()); + if (stateType.minValue().isValid() && ordering == QPartialOrdering::Less) { + qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Min:" << stateType.minValue(); + return false; + } +#else if (stateType.maxValue().isValid() && stateValue > stateType.maxValue()) { qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Max:" << stateType.maxValue(); return false; @@ -275,7 +290,7 @@ bool StateEvaluator::isValid() const qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Min:" << stateType.minValue(); return false; } - +#endif if (!stateType.possibleValues().isEmpty() && !stateType.possibleValues().contains(stateValue)) { QStringList possibleValues; foreach (const QVariant &value, stateType.possibleValues()) { @@ -286,7 +301,7 @@ bool StateEvaluator::isValid() const return false; } - // if comparing to another state + // if comparing to another state } else if (!m_stateDescriptor.valueThingId().isNull() && !m_stateDescriptor.valueStateTypeId().isNull()) { Thing *valueThing = NymeaCore::instance()->thingManager()->findConfiguredThing(m_stateDescriptor.valueThingId()); if (!valueThing) { @@ -307,11 +322,11 @@ bool StateEvaluator::isValid() const } else { // TypeInterface Interface iface = NymeaCore::instance()->thingManager()->supportedInterfaces().findByName(m_stateDescriptor.interface()); if (!iface.isValid()) { - qWarning(dcRuleEngine()) << "No such interface:" << m_stateDescriptor.interface(); + qCWarning(dcRuleEngine()) << "No such interface:" << m_stateDescriptor.interface(); return false; } if (iface.stateTypes().findByName(m_stateDescriptor.interfaceState()).name().isEmpty()) { - qWarning(dcRuleEngine()) << "Interface" << iface.name() << "has no such state:" << m_stateDescriptor.interfaceState(); + qCWarning(dcRuleEngine()) << "Interface" << iface.name() << "has no such state:" << m_stateDescriptor.interfaceState(); return false; } } @@ -356,11 +371,64 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const } if (!descriptor.stateValue().isNull()) { - QVariant convertedValue = descriptor.stateValue(); + QVariant stateValue = state.value(); + QVariant descriptorValue = descriptor.stateValue(); + +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + bool res = descriptorValue.convert(state.value().metaType()); + if (!res) { + return false; + } + + // FIXME: not sure if this is a bug in Qt, but compairing two equivalient QVariant containing QColor + // with QPartialOrdering::equivalent results in false. Until this has been fixed or the error has been found, + // we convert colors to strings and compare them + + // Comparing QVariant(QColor, QColor(ARGB 1, 0, 0, 0)) to QVariant(QColor, QColor(ARGB 1, 0, 1, 0)) with operator Types::ValueOperatorEquals --> false + + if (state.value().typeId() == QMetaType::QColor) { + QColor stateColor = stateValue.value(); + QColor desciptorColor = descriptorValue.value(); + + QString sateColorName = stateColor.name(); + QString desciptorColorName = desciptorColor.name(); + + stateValue = QVariant(sateColorName); + descriptorValue = QVariant(desciptorColorName); + } + + QPartialOrdering ordering = QVariant::compare(stateValue, descriptorValue); + bool result = false; + switch (descriptor.operatorType()) { + case Types::ValueOperatorEquals: + result = (ordering == QPartialOrdering::equivalent); + break; + case Types::ValueOperatorGreater: + result = (ordering == QPartialOrdering::greater); + break; + case Types::ValueOperatorGreaterOrEqual: + result = (ordering == QPartialOrdering::greater || ordering == QPartialOrdering::equivalent); + break; + case Types::ValueOperatorLess: + result = (ordering == QPartialOrdering::less); + break; + case Types::ValueOperatorLessOrEqual: + result = (ordering == QPartialOrdering::less || ordering == QPartialOrdering::equivalent); + break; + case Types::ValueOperatorNotEquals: + result = (ordering != QPartialOrdering::equivalent); + break; + } + + qCDebug(dcRuleEngineDebug()) << "Comparing" << stateValue << "to" << descriptorValue << "with operator" << descriptor.operatorType() << "-->" << result; + + return result; +#else bool res = convertedValue.convert(state.value().type()); if (!res) { return false; } + switch (descriptor.operatorType()) { case Types::ValueOperatorEquals: return state.value() == convertedValue; @@ -375,7 +443,7 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const case Types::ValueOperatorNotEquals: return state.value() != convertedValue; } - +#endif } else if (!descriptor.valueThingId().isNull() && !descriptor.valueStateTypeId().isNull()) { Thing *valueThing = NymeaCore::instance()->thingManager()->findConfiguredThing(descriptor.valueThingId()); if (!valueThing) { @@ -389,6 +457,23 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const } qCDebug(dcRuleEngineDebug()) << "Comparing" << state.value() << "to" << valueState.value() << "with operator" << descriptor.operatorType(); +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + QPartialOrdering ordering = QVariant::compare(state.value(), valueState.value()); + switch (descriptor.operatorType()) { + case Types::ValueOperatorEquals: + return ordering == QPartialOrdering::Equivalent; + case Types::ValueOperatorGreater: + return ordering == QPartialOrdering::Greater; + case Types::ValueOperatorGreaterOrEqual: + return ordering == QPartialOrdering::Greater || ordering == QPartialOrdering::Equivalent; + case Types::ValueOperatorLess: + return ordering == QPartialOrdering::Less; + case Types::ValueOperatorLessOrEqual: + return ordering == QPartialOrdering::Less || ordering == QPartialOrdering::Equivalent; + case Types::ValueOperatorNotEquals: + return ordering != QPartialOrdering::Equivalent; + } +#else switch (descriptor.operatorType()) { case Types::ValueOperatorEquals: return state.value() == valueState.value(); @@ -403,6 +488,7 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const case Types::ValueOperatorNotEquals: return state.value() != valueState.value(); } +#endif } } else { // Interface based @@ -430,7 +516,7 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const QDebug operator<<(QDebug dbg, const StateEvaluator &stateEvaluator) { QDebugStateSaver saver(dbg); - dbg.nospace() << "StateEvaluator: Operator:" << stateEvaluator.operatorType() << endl << " " << stateEvaluator.stateDescriptor() << endl; + dbg.nospace() << "StateEvaluator: Operator:" << stateEvaluator.operatorType() << '\n' << " " << stateEvaluator.stateDescriptor() << '\n'; for (int i = 0; i < stateEvaluator.childEvaluators().count(); i++) { dbg.nospace() << " " << i << ": " << stateEvaluator.childEvaluators().at(i); } diff --git a/libnymea-core/scriptengine/scriptaction.cpp b/libnymea-core/scriptengine/scriptaction.cpp index f2715cbb..bdd78705 100644 --- a/libnymea-core/scriptengine/scriptaction.cpp +++ b/libnymea-core/scriptengine/scriptaction.cpp @@ -41,6 +41,8 @@ #include #include +#include + Q_DECLARE_LOGGING_CATEGORY(dcScriptEngine) namespace nymeaserver { @@ -79,7 +81,7 @@ void ScriptAction::classBegin() QVariantMap params; foreach (const Param ¶m, action.params()) { - params.insert(param.paramTypeId().toString().remove(QRegExp("[{}]")), param.value().toByteArray()); + params.insert(param.paramTypeId().toString().remove(QRegularExpression("[{}]")), param.value().toByteArray()); QString paramName = thing->thingClass().actionTypes().findById(action.actionTypeId()).paramTypes().findById(param.paramTypeId()).name(); params.insert(paramName, param.value().toByteArray()); } diff --git a/libnymea-core/scriptengine/scriptengine.cpp b/libnymea-core/scriptengine/scriptengine.cpp index d4aae667..6178d7ea 100644 --- a/libnymea-core/scriptengine/scriptengine.cpp +++ b/libnymea-core/scriptengine/scriptengine.cpp @@ -45,16 +45,16 @@ #include "nymeasettings.h" #include "logging/logengine.h" +#include #include #include #include #include #include +#include #include "loggingcategories.h" -#include - NYMEA_LOGGING_CATEGORY(dcScriptEngine, "ScriptEngine") namespace nymeaserver { @@ -367,7 +367,7 @@ void ScriptEngine::loadScripts() } Script *script = new Script(); - script->setId(jsonFileInfo.baseName()); + script->setId(QUuid(jsonFileInfo.baseName())); script->setName(jsonDoc.toVariant().toMap().value("name").toString()); bool loaded = loadScript(script); @@ -449,14 +449,14 @@ void ScriptEngine::unloadScript(Script *script) QString ScriptEngine::baseName(const QUuid &id) { QString path = NymeaSettings::storagePath() + "/scripts/"; - QString basename = id.toString().remove(QRegExp("[{}]")); + QString basename = id.toString().remove(QRegularExpression("[{}]")); return path + basename; } void ScriptEngine::onScriptMessage(QtMsgType type, const QMessageLogContext &context, const QString &message) { QFileInfo fi(context.file); - QUuid scriptId = fi.baseName(); + QUuid scriptId(fi.baseName()); if (!m_scripts.contains(scriptId)) { return; } diff --git a/libnymea-core/scriptengine/scriptevent.cpp b/libnymea-core/scriptengine/scriptevent.cpp index 5c4b004c..bb2edef1 100644 --- a/libnymea-core/scriptengine/scriptevent.cpp +++ b/libnymea-core/scriptengine/scriptevent.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace nymeaserver { namespace scriptengine { @@ -97,7 +98,7 @@ void ScriptEvent::onEventTriggered(const Event &event) return; } - if (!m_eventTypeId.isEmpty() && event.eventTypeId() != m_eventTypeId) { + if (!m_eventTypeId.isEmpty() && event.eventTypeId() != EventTypeId(m_eventTypeId)) { return; } @@ -108,7 +109,7 @@ void ScriptEvent::onEventTriggered(const Event &event) QVariantMap params; foreach (const Param ¶m, event.params()) { - params.insert(param.paramTypeId().toString().remove(QRegExp("[{}]")), param.value().toByteArray()); + params.insert(param.paramTypeId().toString().remove(QRegularExpression("[{}]")), param.value().toByteArray()); QString paramName = thing->thingClass().eventTypes().findById(event.eventTypeId()).paramTypes().findById(param.paramTypeId()).name(); params.insert(paramName, param.value().toByteArray()); } diff --git a/libnymea-core/scriptengine/scriptinterfaceevent.cpp b/libnymea-core/scriptengine/scriptinterfaceevent.cpp index c0c85b7c..102f074a 100644 --- a/libnymea-core/scriptengine/scriptinterfaceevent.cpp +++ b/libnymea-core/scriptengine/scriptinterfaceevent.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace nymeaserver { namespace scriptengine { @@ -91,13 +92,13 @@ void ScriptInterfaceEvent::onEventTriggered(const Event &event) QVariantMap params; foreach (const Param ¶m, event.params()) { - params.insert(param.paramTypeId().toString().remove(QRegExp("[{}]")), param.value().toByteArray()); + params.insert(param.paramTypeId().toString().remove(QRegularExpression("[{}]")), param.value().toByteArray()); QString paramName = thing->thingClass().eventTypes().findById(event.eventTypeId()).paramTypes().findById(param.paramTypeId()).name(); params.insert(paramName, param.value().toByteArray()); } // Note: Explicitly convert the params to a Json document because auto-casting from QVariantMap to the JS engine might drop some values. - emit triggered(event.thingId().toString().remove(QRegExp("[{}]")), QJsonDocument::fromVariant(params).toVariant().toMap()); + emit triggered(event.thingId().toString().remove(QRegularExpression("[{}]")), QJsonDocument::fromVariant(params).toVariant().toMap()); } } diff --git a/libnymea-core/scriptengine/scriptinterfacestate.cpp b/libnymea-core/scriptengine/scriptinterfacestate.cpp index 43f8ae27..e3ab0d2d 100644 --- a/libnymea-core/scriptengine/scriptinterfacestate.cpp +++ b/libnymea-core/scriptengine/scriptinterfacestate.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace nymeaserver { namespace scriptengine { @@ -88,7 +89,7 @@ void ScriptInterfaceState::onStateChanged(Thing *thing, const StateTypeId &state return; } - emit stateChanged(thing->id().toString().remove(QRegExp("[{}]")), value); + emit stateChanged(thing->id().toString().remove(QRegularExpression("[{}]")), value); } } diff --git a/libnymea-core/scriptengine/scriptthing.cpp b/libnymea-core/scriptengine/scriptthing.cpp index 86eb329c..3adac38a 100644 --- a/libnymea-core/scriptengine/scriptthing.cpp +++ b/libnymea-core/scriptengine/scriptthing.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include Q_DECLARE_LOGGING_CATEGORY(dcScriptEngine) @@ -163,7 +164,7 @@ void ScriptThing::init(ThingManager *thingManager) Thing *thing = m_thingManager->findConfiguredThing(event.thingId()); QVariantMap params; foreach (const Param ¶m, event.params()) { - params.insert(param.paramTypeId().toString().remove(QRegExp("[{}]")), param.value().toByteArray()); + params.insert(param.paramTypeId().toString().remove(QRegularExpression("[{}]")), param.value().toByteArray()); QString paramName = thing->thingClass().eventTypes().findById(event.eventTypeId()).paramTypes().findById(param.paramTypeId()).name(); params.insert(paramName, param.value().toByteArray()); } @@ -179,7 +180,7 @@ void ScriptThing::init(ThingManager *thingManager) Thing *thing = m_thingManager->findConfiguredThing(action.thingId()); QVariantMap params; foreach (const Param ¶m, action.params()) { - params.insert(param.paramTypeId().toString().remove(QRegExp("[{}]")), param.value().toByteArray()); + params.insert(param.paramTypeId().toString().remove(QRegularExpression("[{}]")), param.value().toByteArray()); QString paramName = thing->thingClass().actionTypes().findById(action.actionTypeId()).paramTypes().findById(param.paramTypeId()).name(); params.insert(paramName, param.value().toByteArray()); } diff --git a/libnymea-core/servers/bluetoothserver.cpp b/libnymea-core/servers/bluetoothserver.cpp index 6c43149a..483d4fbc 100644 --- a/libnymea-core/servers/bluetoothserver.cpp +++ b/libnymea-core/servers/bluetoothserver.cpp @@ -211,12 +211,26 @@ bool BluetoothServer::startServer() // Set service attributes m_serviceInfo = new QBluetoothServiceInfo(); + QBluetoothUuid publicBrowseGroupUuid; + QBluetoothUuid serialPortUuid; + QBluetoothUuid rfCommUuid; + +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + publicBrowseGroupUuid = QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup); + serialPortUuid = QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort); + rfCommUuid = QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm); +#else + publicBrowseGroupUuid = QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup); + serialPortUuid = QBluetoothUuid(QBluetoothUuid::SerialPort); + rfCommUuid = QBluetoothUuid(QBluetoothUuid::Rfcomm); +#endif + QBluetoothServiceInfo::Sequence browseSequence; - browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); + browseSequence << QVariant::fromValue(publicBrowseGroupUuid); m_serviceInfo->setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseSequence); QBluetoothServiceInfo::Sequence classId; - classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)); + classId << QVariant::fromValue(serialPortUuid); m_serviceInfo->setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList, classId); classId.prepend(QVariant::fromValue(nymeaServiceUuid)); @@ -230,7 +244,7 @@ bool BluetoothServer::startServer() // Define protocol QBluetoothServiceInfo::Sequence protocolDescriptorList; QBluetoothServiceInfo::Sequence protocol; - protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm)) + protocol << QVariant::fromValue(rfCommUuid) << QVariant::fromValue(quint8(m_server->serverPort())); protocolDescriptorList.append(QVariant::fromValue(protocol)); m_serviceInfo->setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList); diff --git a/libnymea-core/servers/httpreply.cpp b/libnymea-core/servers/httpreply.cpp index e7988854..f5849297 100644 --- a/libnymea-core/servers/httpreply.cpp +++ b/libnymea-core/servers/httpreply.cpp @@ -491,7 +491,7 @@ void HttpReply::timeout() QDebug operator<<(QDebug debug, HttpReply *httpReply) { QDebugStateSaver saver(debug); - debug.nospace() << "HttpReply(" << httpReply->clientId().toString() << ")" << endl; + debug.nospace() << "HttpReply(" << httpReply->clientId().toString() << ")" << '\n'; debug << qUtf8Printable(httpReply->rawHeader()); debug << qUtf8Printable(httpReply->payload()); return debug; diff --git a/libnymea-core/servers/httprequest.cpp b/libnymea-core/servers/httprequest.cpp index 9958530a..870128a5 100644 --- a/libnymea-core/servers/httprequest.cpp +++ b/libnymea-core/servers/httprequest.cpp @@ -67,6 +67,7 @@ #include "loggingcategories.h" #include +#include namespace nymeaserver { @@ -190,9 +191,9 @@ void HttpRequest::validate() m_payload = m_rawData.right(m_rawData.length() - headerEndIndex).simplified(); // parse status line - QStringList headerLines = QString(m_rawHeader).split(QRegExp("\r\n")); + QStringList headerLines = QString(m_rawHeader).split(QRegularExpression("\r\n")); QString statusLine = headerLines.takeFirst(); - QStringList statusLineTokens = statusLine.split(QRegExp("[ \r\n][ \r\n]*")); + QStringList statusLineTokens = statusLine.split(QRegularExpression("[ \r\n][ \r\n]*")); if (statusLineTokens.count() != 3) { qCWarning(dcWebServer()) << "Could not parse HTTP status line:" << statusLine; return; @@ -278,7 +279,7 @@ HttpRequest::RequestMethod HttpRequest::getRequestMethodType(const QString &meth QDebug operator<<(QDebug debug, const HttpRequest &httpRequest) { QDebugStateSaver saver(debug); - debug << "HttpRequest:" << endl; + debug << "HttpRequest:" << '\n'; debug << qUtf8Printable(httpRequest.rawHeader()); debug << qUtf8Printable(httpRequest.payload()); return debug; diff --git a/libnymea-core/servers/tcpserver.cpp b/libnymea-core/servers/tcpserver.cpp index 1b563844..39fa8958 100644 --- a/libnymea-core/servers/tcpserver.cpp +++ b/libnymea-core/servers/tcpserver.cpp @@ -184,8 +184,8 @@ bool TcpServer::startServer() return false; } - connect(m_server, SIGNAL(clientConnected(QSslSocket *)), SLOT(onClientConnected(QSslSocket *))); - connect(m_server, SIGNAL(clientDisconnected(QSslSocket *)), SLOT(onClientDisconnected(QSslSocket *))); + connect(m_server, &SslServer::clientConnected, this, &TcpServer::onClientConnected); + connect(m_server, &SslServer::clientDisconnected, this, &TcpServer::onClientDisconnected); connect(m_server, &SslServer::dataAvailable, this, &TcpServer::onDataAvailable); qCDebug(dcTcpServer()) << "Started Tcp server" << serverUrl().toString(); diff --git a/libnymea-core/servers/webserver.cpp b/libnymea-core/servers/webserver.cpp index c83d7419..54ce0c53 100644 --- a/libnymea-core/servers/webserver.cpp +++ b/libnymea-core/servers/webserver.cpp @@ -89,10 +89,11 @@ #include "debugserverhandler.h" #include "version.h" -#include +#include #include #include #include +#include #include #include #include @@ -274,9 +275,14 @@ void WebServer::incomingConnection(qintptr socketDescriptor) return; } - connect(socket, SIGNAL(readyRead()), this, SLOT(readClient())); - connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected())); + connect(socket, &QSslSocket::readyRead, this, &WebServer::readClient); + connect(socket, &QSslSocket::disconnected, this, &WebServer::onDisconnected); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(socket, &QSslSocket::errorOccurred, this, &WebServer::onError); +#else connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); +#endif emit clientConnected(clientId); } @@ -508,10 +514,14 @@ void WebServer::onEncrypted() { QSslSocket* socket = static_cast(sender()); qCDebug(dcWebServer()).noquote() << QString("Encrypted connection %1:%2 successfully established.").arg(socket->peerAddress().toString()).arg(socket->peerPort()); - connect(socket, SIGNAL(readyRead()), this, SLOT(readClient())); - connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected())); - connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); + connect(socket, &QSslSocket::readyRead, this, &WebServer::readClient); + connect(socket, &QSslSocket::disconnected, this, &WebServer::onDisconnected); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(socket, &QSslSocket::errorOccurred, this, &WebServer::onError); +#else + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); +#endif emit clientConnected(m_clientList.key(socket)); } @@ -593,7 +603,7 @@ WebServerConfiguration WebServer::configuration() const QByteArray WebServer::createServerXmlDocument(QHostAddress address) { - QByteArray uuid = NymeaCore::instance()->configuration()->serverUuid().toString().remove(QRegExp("[{}]")).toUtf8(); + QByteArray uuid = NymeaCore::instance()->configuration()->serverUuid().toString().remove(QRegularExpression("[{}]")).toUtf8(); QByteArray data; QXmlStreamWriter writer(&data); diff --git a/libnymea-core/tagging/tag.cpp b/libnymea-core/tagging/tag.cpp index 1a89a59a..a2d832cf 100644 --- a/libnymea-core/tagging/tag.cpp +++ b/libnymea-core/tagging/tag.cpp @@ -124,7 +124,7 @@ QDebug operator<<(QDebug dbg, const Tag &tag) } else { dbg.nospace() << "Tag (RuleId:" << tag.ruleId(); } - dbg.nospace() << ", AppId:" << tag.appId() << ", TagId:" << tag.tagId() << ", Value:" << tag.value() << ")" << endl; + dbg.nospace() << ", AppId:" << tag.appId() << ", TagId:" << tag.tagId() << ", Value:" << tag.value() << ")" << '\n'; return dbg; } diff --git a/libnymea-core/usermanager/usermanager.cpp b/libnymea-core/usermanager/usermanager.cpp index 0859a0e5..3018f1ef 100644 --- a/libnymea-core/usermanager/usermanager.cpp +++ b/libnymea-core/usermanager/usermanager.cpp @@ -77,13 +77,12 @@ #include #include #include -#include #include #include -#include #include #include #include +#include namespace nymeaserver { @@ -113,7 +112,7 @@ UserManager::UserManager(const QString &dbName, QObject *parent): m_pushButtonDBusService = new PushButtonDBusService("/io/guh/nymead/UserManager", this); connect(m_pushButtonDBusService, &PushButtonDBusService::pushButtonPressed, this, &UserManager::onPushButtonPressed); - m_pushButtonTransaction = qMakePair(-1, QString()); + m_pushButtonTransaction = QPair(-1, QString()); } /*! Will return true if the database is working fine but doesn't have any information on users whatsoever. @@ -123,27 +122,36 @@ UserManager::UserManager(const QString &dbName, QObject *parent): bool UserManager::initRequired() const { QString getTokensQuery = QString("SELECT id, username, creationdate, deviceName FROM tokens;"); - QSqlQuery result = m_db.exec(getTokensQuery); + QSqlQuery resultQuery(m_db); + if (!resultQuery.exec(getTokensQuery)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << getTokensQuery << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return false; + } + if (m_db.lastError().type() != QSqlError::NoError) { qCWarning(dcUserManager) << "Query for tokens failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getTokensQuery; // Note: do not return true in case the database access fails. return false; } - return users().isEmpty() && !result.first(); + return users().isEmpty() && !resultQuery.first(); } /*! Returns the list of user names for this UserManager. */ UserInfoList UserManager::users() const { - QString userQuery("SELECT * FROM users;"); - QSqlQuery result = m_db.exec(userQuery); UserInfoList users; - while (result.next()) { - UserInfo info = UserInfo(result.value("username").toString()); - info.setEmail(result.value("email").toString()); - info.setDisplayName(result.value("displayName").toString()); - info.setScopes(Types::scopesFromStringList(result.value("scopes").toString().split(','))); + QString userQuery("SELECT * FROM users;"); + QSqlQuery resultQuery(m_db); + if (!resultQuery.exec(userQuery)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << userQuery << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return users; + } + while (resultQuery.next()) { + UserInfo info = UserInfo(resultQuery.value("username").toString()); + info.setEmail(resultQuery.value("email").toString()); + info.setDisplayName(resultQuery.value("displayName").toString()); + info.setScopes(Types::scopesFromStringList(resultQuery.value("scopes").toString().split(','))); users.append(info); } return users; @@ -172,7 +180,7 @@ UserManager::UserError UserManager::createUser(const QString &username, const QS return UserErrorDuplicateUserId; } - QByteArray salt = QUuid::createUuid().toString().remove(QRegExp("[{}]")).toUtf8(); + QByteArray salt = QUuid::createUuid().toString().remove(QRegularExpression("[{}]")).toUtf8(); QByteArray hashedPassword = QCryptographicHash::hash(QString(password + salt).toUtf8(), QCryptographicHash::Sha512).toBase64(); QSqlQuery query(m_db); query.prepare("INSERT INTO users(username, email, displayName, password, salt, scopes) VALUES(?, ?, ?, ?, ?, ?);"); @@ -205,39 +213,59 @@ UserManager::UserError UserManager::changePassword(const QString &username, cons return UserErrorBadPassword; } - QString checkForUserExistingQuery = QString("SELECT * FROM users WHERE lower(username) = \"%1\";").arg(username.toLower()); - QSqlQuery result = m_db.exec(checkForUserExistingQuery); - if (!result.first()) { + QString checkForUserExistingQueryString = QString("SELECT * FROM users WHERE lower(username) = \"%1\";").arg(username.toLower()); + QSqlQuery checkForUserExistingQuery(m_db); + if (!checkForUserExistingQuery.exec(checkForUserExistingQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << checkForUserExistingQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return UserErrorBackendError; + } + + if (!checkForUserExistingQuery.first()) { qCWarning(dcUserManager) << "Username does not exist."; return UserErrorInvalidUserId; } // Update the password - QByteArray salt = QUuid::createUuid().toString().remove(QRegExp("[{}]")).toUtf8(); + QByteArray salt = QUuid::createUuid().toString().remove(QRegularExpression("[{}]")).toUtf8(); QByteArray hashedPassword = QCryptographicHash::hash(QString(newPassword + salt).toUtf8(), QCryptographicHash::Sha512).toBase64(); - QString queryString = QString("UPDATE users SET password = \"%1\", salt = \"%2\" WHERE lower(username) = \"%3\";") + QString updatePasswordQueryString = QString("UPDATE users SET password = \"%1\", salt = \"%2\" WHERE lower(username) = \"%3\";") .arg(QString::fromUtf8(hashedPassword)) .arg(QString::fromUtf8(salt)) .arg(username.toLower()); - m_db.exec(queryString); + + QSqlQuery updatePasswordQuery(m_db); + if (!updatePasswordQuery.exec(updatePasswordQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << updatePasswordQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return UserErrorBackendError; + } + if (m_db.lastError().type() != QSqlError::NoError) { qCWarning(dcUserManager) << "Error updating password for user:" << m_db.lastError().databaseText() << m_db.lastError().driverText(); return UserErrorBackendError; } + qCDebug(dcUserManager()) << "Password updated for user" << username; return UserErrorNoError; } UserManager::UserError UserManager::removeUser(const QString &username) { - QString dropUserQuery = QString("DELETE FROM users WHERE lower(username) =\"%1\";").arg(username.toLower()); - QSqlQuery result = m_db.exec(dropUserQuery); - if (result.numRowsAffected() == 0) { - return UserErrorInvalidUserId; + QString dropUserQueryString = QString("DELETE FROM users WHERE lower(username) =\"%1\";").arg(username.toLower()); + QSqlQuery dropUserQuery(m_db); + if (!dropUserQuery.exec(dropUserQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << dropUserQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return UserErrorBackendError; } - QString dropTokensQuery = QString("DELETE FROM tokens WHERE lower(username) = \"%1\";").arg(username.toLower()); - m_db.exec(dropTokensQuery); + if (dropUserQuery.numRowsAffected() == 0) + return UserErrorInvalidUserId; + + QString dropTokensQueryString = QString("DELETE FROM tokens WHERE lower(username) = \"%1\";").arg(username.toLower()); + QSqlQuery dropTokensQuery(m_db); + if (!dropTokensQuery.exec(dropTokensQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << dropTokensQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return UserErrorBackendError; + } emit userRemoved(username); return UserErrorNoError; @@ -309,18 +337,24 @@ QByteArray UserManager::authenticate(const QString &username, const QString &pas } QByteArray token = QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Sha256).toBase64(); - QString storeTokenQuery = QString("INSERT INTO tokens(id, username, token, creationdate, devicename) VALUES(\"%1\", \"%2\", \"%3\", \"%4\", \"%5\");") + QString storeTokenQueryString = QString("INSERT INTO tokens(id, username, token, creationdate, devicename) VALUES(\"%1\", \"%2\", \"%3\", \"%4\", \"%5\");") .arg(QUuid::createUuid().toString()) .arg(username.toLower()) .arg(QString::fromUtf8(token)) .arg(NymeaCore::instance()->timeManager()->currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(deviceName); - m_db.exec(storeTokenQuery); + QSqlQuery storeTokenQuery(m_db); + if (!storeTokenQuery.exec(storeTokenQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << storeTokenQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return QByteArray(); + } + if (m_db.lastError().type() != QSqlError::NoError) { qCWarning(dcUserManager) << "Error storing token in DB:" << m_db.lastError().databaseText() << m_db.lastError().driverText(); return QByteArray(); } + return token; } @@ -334,7 +368,7 @@ int UserManager::requestPushButtonAuth(const QString &deviceName) qCDebug(dcUserManager()) << "Starting PushButton authentication for device" << deviceName; int transactionId = ++m_pushButtonTransactionIdCounter; - m_pushButtonTransaction = qMakePair(transactionId, deviceName); + m_pushButtonTransaction = QPair(transactionId, deviceName); return transactionId; } @@ -364,22 +398,27 @@ void UserManager::cancelPushButtonAuth(int transactionId) UserInfo UserManager::userInfo(const QString &username) const { - QString getUserQuery = QString("SELECT * FROM users WHERE lower(username) = \"%1\";") + QString getUserQueryString = QString("SELECT * FROM users WHERE lower(username) = \"%1\";") .arg(username); - QSqlQuery result = m_db.exec(getUserQuery); + + QSqlQuery getUserQuery(m_db); + if (!getUserQuery.exec(getUserQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << getUserQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return UserInfo(); + } + if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcUserManager) << "Query for user" << username << "failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getUserQuery; + qCWarning(dcUserManager) << "Query for user" << username << "failed:" << getUserQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return UserInfo(); } - if (!result.first()) { + if (!getUserQuery.first()) return UserInfo(); - } - UserInfo userInfo = UserInfo(result.value("username").toString()); - userInfo.setEmail(result.value("email").toString()); - userInfo.setDisplayName(result.value("displayName").toString()); - userInfo.setScopes(Types::scopesFromStringList(result.value("scopes").toString().split(','))); + UserInfo userInfo = UserInfo(getUserQuery.value("username").toString()); + userInfo.setEmail(getUserQuery.value("email").toString()); + userInfo.setDisplayName(getUserQuery.value("displayName").toString()); + userInfo.setScopes(Types::scopesFromStringList(getUserQuery.value("scopes").toString().split(','))); return userInfo; } @@ -410,48 +449,66 @@ TokenInfo UserManager::tokenInfo(const QByteArray &token) const return TokenInfo(); } - QString getTokenQuery = QString("SELECT id, username, creationdate, deviceName FROM tokens WHERE token = \"%1\";") + QString getTokenQueryString = QString("SELECT id, username, creationdate, deviceName FROM tokens WHERE token = \"%1\";") .arg(QString::fromUtf8(token)); - QSqlQuery result = m_db.exec(getTokenQuery); - if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcUserManager) << "Query for token failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getTokenQuery; + + QSqlQuery getTokenQuery(m_db); + if (!getTokenQuery.exec(getTokenQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << getTokenQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return TokenInfo(); } - if (!result.first()) { + if (m_db.lastError().type() != QSqlError::NoError) { + qCWarning(dcUserManager) << "Query for token failed:" << getTokenQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return TokenInfo(); } - return TokenInfo(result.value("id").toUuid(), result.value("username").toString(), result.value("creationdate").toDateTime(), result.value("devicename").toString()); + + if (!getTokenQuery.first()) + return TokenInfo(); + + return TokenInfo(getTokenQuery.value("id").toUuid(), getTokenQuery.value("username").toString(), getTokenQuery.value("creationdate").toDateTime(), getTokenQuery.value("devicename").toString()); } TokenInfo UserManager::tokenInfo(const QUuid &tokenId) const { - QString getTokenQuery = QString("SELECT id, username, creationdate, deviceName FROM tokens WHERE id = \"%1\";") + QString getTokenQueryString = QString("SELECT id, username, creationdate, deviceName FROM tokens WHERE id = \"%1\";") .arg(tokenId.toString()); - QSqlQuery result = m_db.exec(getTokenQuery); - if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcUserManager) << "Query for token failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getTokenQuery; + + QSqlQuery getTokenQuery(m_db); + if (!getTokenQuery.exec(getTokenQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << getTokenQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return TokenInfo(); } - if (!result.first()) { + if (m_db.lastError().type() != QSqlError::NoError) { + qCWarning(dcUserManager) << "Query for token failed:" << getTokenQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return TokenInfo(); } - return TokenInfo(result.value("id").toUuid(), result.value("username").toString(), result.value("creationdate").toDateTime(), result.value("devicename").toString()); + + if (!getTokenQuery.first()) { + return TokenInfo(); + } + return TokenInfo(getTokenQuery.value("id").toUuid(), getTokenQuery.value("username").toString(), getTokenQuery.value("creationdate").toDateTime(), getTokenQuery.value("devicename").toString()); } /*! Removes the token with the given \a tokenId. Returns \l{UserError} to inform about the result. */ UserManager::UserError UserManager::removeToken(const QUuid &tokenId) { - QString removeTokenQuery = QString("DELETE FROM tokens WHERE id = \"%1\";") + QString removeTokenQueryString = QString("DELETE FROM tokens WHERE id = \"%1\";") .arg(tokenId.toString()); - QSqlQuery result = m_db.exec(removeTokenQuery); - if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcUserManager) << "Removing token failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << removeTokenQuery; + + QSqlQuery removeTokenQuery(m_db); + if (!removeTokenQuery.exec(removeTokenQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << removeTokenQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return UserErrorBackendError; } - if (result.numRowsAffected() != 1) { + + if (m_db.lastError().type() != QSqlError::NoError) { + qCWarning(dcUserManager) << "Removing token failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << removeTokenQueryString; + return UserErrorBackendError; + } + if (removeTokenQuery.numRowsAffected() != 1) { qCWarning(dcUserManager) << "Token not found in DB"; return UserErrorTokenNotFound; } @@ -467,14 +524,20 @@ bool UserManager::verifyToken(const QByteArray &token) qCWarning(dcUserManager) << "Token failed character validation" << token; return false; } - QString getTokenQuery = QString("SELECT * FROM tokens WHERE token = \"%1\";") + QString getTokenQueryString = QString("SELECT * FROM tokens WHERE token = \"%1\";") .arg(QString::fromUtf8(token)); - QSqlQuery result = m_db.exec(getTokenQuery); - if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcUserManager) << "Query for token failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getTokenQuery; + + QSqlQuery getTokenQuery(m_db); + if (!getTokenQuery.exec(getTokenQueryString)) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << getTokenQueryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return false; } - if (!result.first()) { + + if (m_db.lastError().type() != QSqlError::NoError) { + qCWarning(dcUserManager) << "Query for token failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getTokenQueryString; + return false; + } + if (!getTokenQuery.first()) { qCDebug(dcUserManager) << "Authorization failed for token" << token; return false; } @@ -494,56 +557,59 @@ bool UserManager::initDB() int currentVersion = -1; int newVersion = 1; if (m_db.tables().contains("metadata")) { - QSqlQuery query = m_db.exec("SELECT data FROM metadata WHERE `key` = 'version';"); - if (query.next()) { + QSqlQuery query(m_db); + if (!query.exec("SELECT data FROM metadata WHERE `key` = 'version';")) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << query.executedQuery() << m_db.lastError().databaseText() << m_db.lastError().driverText(); + } else if (query.next()) { currentVersion = query.value("data").toInt(); } } if (!m_db.tables().contains("users")) { qCDebug(dcUserManager()) << "Empty user database. Setting up metadata..."; - m_db.exec("CREATE TABLE users (username VARCHAR(40) UNIQUE PRIMARY KEY, email VARCHAR(40), displayName VARCHAR(40), password VARCHAR(100), salt VARCHAR(100), scopes TEXT);"); - if (m_db.lastError().isValid()) { + QSqlQuery query(m_db); + if (!query.exec("CREATE TABLE users (username VARCHAR(40) UNIQUE PRIMARY KEY, email VARCHAR(40), displayName VARCHAR(40), password VARCHAR(100), salt VARCHAR(100), scopes TEXT);") || m_db.lastError().isValid()) { dumpDBError("Error initializing user database (table users)."); m_db.close(); return false; } } else { if (currentVersion < 1) { - m_db.exec("ALTER TABLE users ADD COLUMN scopes TEXT;"); - if (m_db.lastError().isValid()) { + QSqlQuery query = QSqlQuery(m_db); + if (!query.exec("ALTER TABLE users ADD COLUMN scopes TEXT;") || m_db.lastError().isValid()) { dumpDBError("Error migrating user database (table users)."); m_db.close(); return false; } + // Migrated existing users from before multiuser support are admins by default - QSqlQuery query(m_db); + query = QSqlQuery(m_db); query.prepare("UPDATE users SET scopes = ?;"); query.addBindValue(Types::scopesToStringList(Types::PermissionScopeAdmin).join(',')); - query.exec(); - if (query.lastError().isValid()) { + if (!query.exec() || query.lastError().isValid()) { dumpDBError("Error migrating user database (updating existing users)."); m_db.close(); return false; } - m_db.exec("ALTER TABLE users ADD COLUMN email VARCHAR(40);"); - if (m_db.lastError().isValid()) { + query = QSqlQuery(m_db); + if (!query.exec("ALTER TABLE users ADD COLUMN email VARCHAR(40);") || m_db.lastError().isValid()) { dumpDBError("Error migrating user database (table users)."); m_db.close(); return false; } - m_db.exec("ALTER TABLE users ADD COLUMN displayName VARCHAR(40);"); - if (m_db.lastError().isValid()) { + + query = QSqlQuery(m_db); + if (!query.exec("ALTER TABLE users ADD COLUMN displayName VARCHAR(40);") || m_db.lastError().isValid()) { dumpDBError("Error migrating user database (table users)."); m_db.close(); return false; } // Up until schema 1, username was an email. Copy it to initialize the email field. - m_db.exec("UPDATE users SET email = username;"); - if (m_db.lastError().isValid()) { + query = QSqlQuery(m_db); + if (!query.exec("UPDATE users SET email = username;") || m_db.lastError().isValid()) { dumpDBError("Error migrating user database (table users)."); m_db.close(); return false; @@ -554,8 +620,8 @@ bool UserManager::initDB() if (!m_db.tables().contains("tokens")) { qCDebug(dcUserManager()) << "Empty user database. Setting up metadata..."; - m_db.exec("CREATE TABLE tokens (id VARCHAR(40) UNIQUE, username VARCHAR(40), token VARCHAR(100) UNIQUE, creationdate DATETIME, devicename VARCHAR(40));"); - if (m_db.lastError().isValid()) { + QSqlQuery query(m_db); + if (!query.exec("CREATE TABLE tokens (id VARCHAR(40) UNIQUE, username VARCHAR(40), token VARCHAR(100) UNIQUE, creationdate DATETIME, devicename VARCHAR(40));") || m_db.lastError().isValid()) { dumpDBError("Error initializing user database (table tokens)."); m_db.close(); return false; @@ -564,8 +630,8 @@ bool UserManager::initDB() if (m_db.tables().contains("metadata")) { if (currentVersion < newVersion) { - m_db.exec(QString("UPDATE metadata SET data = %1 WHERE `key` = 'version')").arg(newVersion)); - if (m_db.lastError().isValid()) { + QSqlQuery query(m_db); + if (!query.exec(QString("UPDATE metadata SET data = %1 WHERE `key` = 'version')").arg(newVersion)) || m_db.lastError().isValid()) { dumpDBError("Error updating up user database schema version!"); m_db.close(); return false; @@ -573,14 +639,14 @@ bool UserManager::initDB() qCInfo(dcUserManager()) << "Successfully migrated user database."; } } else { - m_db.exec("CREATE TABLE metadata (`key` VARCHAR(10), data VARCHAR(40));"); - if (m_db.lastError().isValid()) { + QSqlQuery query(m_db); + if (!query.exec("CREATE TABLE metadata (`key` VARCHAR(10), data VARCHAR(40));") || m_db.lastError().isValid()) { dumpDBError("Error setting up user database (table metadata)!"); m_db.close(); return false; } - m_db.exec(QString("INSERT INTO metadata (`key`, `data`) VALUES ('version', %1);").arg(newVersion)); - if (m_db.lastError().isValid()) { + query = QSqlQuery(m_db); + if (!query.exec(QString("INSERT INTO metadata (`key`, `data`) VALUES ('version', %1);").arg(newVersion)) || m_db.lastError().isValid()) { dumpDBError("Error setting up user database (setting version metadata)!"); m_db.close(); return false; @@ -639,8 +705,8 @@ void UserManager::rotate(const QString &dbName) bool UserManager::validateUsername(const QString &username) const { - QRegExp validator("[a-zA-Z0-9_\\.+-@]{3,}"); - return validator.exactMatch(username); + QRegularExpression validator("[a-zA-Z0-9_\\.+-@]{3,}"); + return validator.match(username).hasMatch(); } bool UserManager::validatePassword(const QString &password) const @@ -648,13 +714,13 @@ bool UserManager::validatePassword(const QString &password) const if (password.length() < 8) { return false; } - if (!password.contains(QRegExp("[a-z]"))) { + if (!password.contains(QRegularExpression("[a-z]"))) { return false; } - if (!password.contains(QRegExp("[A-Z]"))) { + if (!password.contains(QRegularExpression("[A-Z]"))) { return false; } - if (!password.contains(QRegExp("[0-9]"))) { + if (!password.contains(QRegularExpression("[0-9]"))) { return false; } return true; @@ -662,8 +728,8 @@ bool UserManager::validatePassword(const QString &password) const bool UserManager::validateToken(const QByteArray &token) const { - QRegExp validator(QRegExp("(^[a-zA-Z0-9_\\.+-/=]+$)")); - return validator.exactMatch(token); + QRegularExpression validator(QRegularExpression("(^[a-zA-Z0-9_\\.+-/=]+$)")); + return validator.match(token).hasMatch(); } void UserManager::dumpDBError(const QString &message) @@ -697,15 +763,15 @@ void UserManager::onPushButtonPressed() } QByteArray token = QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Sha256).toBase64(); - QString storeTokenQuery = QString("INSERT INTO tokens(id, username, token, creationdate, devicename) VALUES(\"%1\", \"%2\", \"%3\", \"%4\", \"%5\");") + QString storeTokenQueryString = QString("INSERT INTO tokens(id, username, token, creationdate, devicename) VALUES(\"%1\", \"%2\", \"%3\", \"%4\", \"%5\");") .arg(QUuid::createUuid().toString()) .arg("") .arg(QString::fromUtf8(token)) .arg(NymeaCore::instance()->timeManager()->currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(m_pushButtonTransaction.second); - m_db.exec(storeTokenQuery); - if (m_db.lastError().type() != QSqlError::NoError) { + QSqlQuery storeTokenQuery(m_db); + if (!storeTokenQuery.exec(storeTokenQueryString) || m_db.lastError().type() != QSqlError::NoError) { qCWarning(dcUserManager()) << "Error storing token in DB:" << m_db.lastError().databaseText() << m_db.lastError().driverText(); qCWarning(dcUserManager()) << "PushButton Auth failed."; emit pushButtonAuthFinished(m_pushButtonTransaction.first, false, QByteArray()); diff --git a/libnymea-core/zigbee/zigbeeadapter.cpp b/libnymea-core/zigbee/zigbeeadapter.cpp index 221a1ac3..5faa4631 100644 --- a/libnymea-core/zigbee/zigbeeadapter.cpp +++ b/libnymea-core/zigbee/zigbeeadapter.cpp @@ -127,7 +127,9 @@ QHash ZigbeeAdapter::backendNames() QHash backendNameHash; backendNameHash.insert(ZigbeeBackendTypeDeconz, "deCONZ"); backendNameHash.insert(ZigbeeBackendTypeNxp, "NXP"); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) backendNameHash.insert(ZigbeeBackendTypeTi, "TI"); +#endif return backendNameHash; } diff --git a/libnymea-core/zigbee/zigbeeadapter.h b/libnymea-core/zigbee/zigbeeadapter.h index 10ac176d..c626d749 100644 --- a/libnymea-core/zigbee/zigbeeadapter.h +++ b/libnymea-core/zigbee/zigbeeadapter.h @@ -53,7 +53,9 @@ public: enum ZigbeeBackendType { ZigbeeBackendTypeDeconz, ZigbeeBackendTypeNxp, +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ZigbeeBackendTypeTi +#endif }; Q_ENUM(ZigbeeBackendType) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index a203b2ba..033e9c73 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -272,9 +272,11 @@ void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) case Zigbee::ZigbeeBackendTypeNxp: settings.setValue("backendType", static_cast(ZigbeeAdapter::ZigbeeBackendTypeNxp)); break; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) case Zigbee::ZigbeeBackendTypeTi: settings.setValue("backendType", static_cast(ZigbeeAdapter::ZigbeeBackendTypeTi)); break; +#endif } settings.setValue("panId", network->panId()); settings.setValue("channel", network->channel()); @@ -452,9 +454,11 @@ ZigbeeNetwork *ZigbeeManager::buildNetworkObject(const QUuid &networkId, ZigbeeA case ZigbeeAdapter::ZigbeeBackendTypeNxp: network = ZigbeeNetworkManager::createZigbeeNetwork(networkId, Zigbee::ZigbeeBackendTypeNxp, this); break; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) case ZigbeeAdapter::ZigbeeBackendTypeTi: network = ZigbeeNetworkManager::createZigbeeNetwork(networkId, Zigbee::ZigbeeBackendTypeTi, this); break; +#endif } if (network) { network->setSettingsDirectory(QDir(NymeaSettings::settingsPath())); @@ -638,9 +642,11 @@ ZigbeeAdapter ZigbeeManager::convertUartAdapterToAdapter(const ZigbeeUartAdapter case Zigbee::ZigbeeBackendTypeNxp: adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeNxp); break; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) case Zigbee::ZigbeeBackendTypeTi: adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeTi); break; +#endif } return adapter; } diff --git a/libnymea-core/zwave/zwavedevicedatabase.cpp b/libnymea-core/zwave/zwavedevicedatabase.cpp index adb13994..b9694db5 100644 --- a/libnymea-core/zwave/zwavedevicedatabase.cpp +++ b/libnymea-core/zwave/zwavedevicedatabase.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include "hardware/zwave/zwavenode.h" @@ -42,8 +42,7 @@ #include "loggingcategories.h" Q_DECLARE_LOGGING_CATEGORY(dcZWave) -namespace nymeaserver -{ +namespace nymeaserver { ZWaveDeviceDatabase::ZWaveDeviceDatabase(const QString &path, const QUuid &networkUuid): m_path(path), @@ -63,22 +62,26 @@ bool ZWaveDeviceDatabase::initDB() } } - QString networkUuidString = m_networkUuid.toString().remove(QRegExp("[{}]")); + QString networkUuidString = m_networkUuid.toString().remove(QRegularExpression("[{}]")); m_db = QSqlDatabase::addDatabase("QSQLITE", "ZWaveDevices-" + networkUuidString); m_db.setDatabaseName(path.absoluteFilePath("zwave-network-" + networkUuidString + ".db")); bool opened = m_db.open(); if (!opened) { - qCCritical(dcZWave()) << "Cannot open ZWave device DB at" << m_db.databaseName() << m_db.lastError(); + qCCritical(dcZWave()) << "Cannot open ZWave device DB at" << m_db.databaseName() << m_db.lastError().databaseText(); return false; } if (!m_db.tables().contains("metadata")) { qCDebug(dcZWave()) << "No \"metadata\" table in database. Creating it."; - m_db.exec("CREATE TABLE metadata (version INT);"); - m_db.exec("INSERT INTO metadata (version) VALUES (1);"); + QSqlQuery query(m_db); + if (!query.exec("CREATE TABLE metadata (version INT);")) { + qCWarning(dcUserManager()) << "Unable to execute SQL query" << query.executedQuery() << m_db.lastError().databaseText() << m_db.lastError().driverText(); + return false; + } - if (m_db.lastError().isValid()) { + query = QSqlQuery(m_db); + if (!query.exec("INSERT INTO metadata (version) VALUES (1);") || m_db.lastError().isValid()) { qCCritical(dcZWave()) << "Error creating metadata table in devie database. Driver error:" << m_db.lastError().driverText() << "Database error:" << m_db.lastError().databaseText(); return false; } @@ -86,25 +89,27 @@ bool ZWaveDeviceDatabase::initDB() if (!m_db.tables().contains("nodes")) { qCDebug(dcZWave()) << "No \"nodes\" table in database. Creating it."; - m_db.exec("CREATE TABLE nodes " - "(" - "nodeId INT PRIMARY KEY NOT NULL," - "basicType INT," - "deviceType INT," - "plusDeviceType INT," - "manufacturerId INT," - "manufacturerName TEXT," - "name TEXT," - "productId INT," - "productName TEXT," - "productType INT," - "isZWavePlus INT," - "isSecure INT," - "isBeaming INT," - "version INT" - ");"); - if (m_db.lastError().isValid()) { + QSqlQuery query = QSqlQuery(m_db); + QString queryString = "CREATE TABLE nodes " + "(" + "nodeId INT PRIMARY KEY NOT NULL," + "basicType INT," + "deviceType INT," + "plusDeviceType INT," + "manufacturerId INT," + "manufacturerName TEXT," + "name TEXT," + "productId INT," + "productName TEXT," + "productType INT," + "isZWavePlus INT," + "isSecure INT," + "isBeaming INT," + "version INT" + ");"; + + if (!query.exec(queryString) || m_db.lastError().isValid()) { qCCritical(dcZWave()) << "Error creating nodes table in devices database. Driver error:" << m_db.lastError().driverText() << "Database error:" << m_db.lastError().databaseText(); return false; } @@ -112,21 +117,23 @@ bool ZWaveDeviceDatabase::initDB() if (!m_db.tables().contains("nodevalues")) { qCDebug(dcZWave()) << "No \"nodevalues\" table in database. Creating it."; - m_db.exec("CREATE TABLE nodevalues " - "(" - "valueId INT PRIMARY KEY NOT NULL," - "nodeId INT," - "valueGenre INT," - "commandClass INT," - "instance INT," - "idx INT," - "type INT," - "value TEXT," - "valueSelection INT," - "description TEXT," - "FOREIGN KEY (nodeId) REFERENCES nodes(nodeId)" - ");"); - if (m_db.lastError().isValid()) { + QSqlQuery query(m_db); + QString queryString = "CREATE TABLE nodevalues " + "(" + "valueId INT PRIMARY KEY NOT NULL," + "nodeId INT," + "valueGenre INT," + "commandClass INT," + "instance INT," + "idx INT," + "type INT," + "value TEXT," + "valueSelection INT," + "description TEXT," + "FOREIGN KEY (nodeId) REFERENCES nodes(nodeId)" + ");"; + + if (!query.exec(queryString) || m_db.lastError().isValid()) { qCCritical(dcZWave()) << "Error creating nodevalues table in device database. Driver error:" << m_db.lastError().driverText() << "Database error:" << m_db.lastError().databaseText(); return false; } diff --git a/libnymea-core/zwave/zwavedevicedatabase.h b/libnymea-core/zwave/zwavedevicedatabase.h index b09df9eb..cd88cc09 100644 --- a/libnymea-core/zwave/zwavedevicedatabase.h +++ b/libnymea-core/zwave/zwavedevicedatabase.h @@ -35,8 +35,7 @@ #include "hardware/zwave/zwavenode.h" -namespace nymeaserver -{ +namespace nymeaserver { class ZWaveManager; diff --git a/libnymea-core/zwave/zwavemanager.cpp b/libnymea-core/zwave/zwavemanager.cpp index 1fab7153..1e82d402 100644 --- a/libnymea-core/zwave/zwavemanager.cpp +++ b/libnymea-core/zwave/zwavemanager.cpp @@ -40,6 +40,7 @@ #include #include #include +#include namespace nymeaserver { @@ -523,21 +524,21 @@ QPair ZWaveManager::createNetwork(const QString &seria { if (!available()) { qCWarning(dcZWave()) << "Z-Wave is not available."; - return qMakePair(ZWave::ZWaveErrorBackendError, QUuid()); + return QPair(ZWave::ZWaveErrorBackendError, QUuid()); } - QString networkKey = QUuid::createUuid().toString().remove(QRegExp("[{\\-}]*")); + QString networkKey = QUuid::createUuid().toString().remove(QRegularExpression("[{\\-}]*")); ZWaveNetwork *network = new ZWaveNetwork(QUuid::createUuid(), serialPort, networkKey, this); bool success = loadNetwork(network); if (!success) { delete network; - return qMakePair(ZWave::ZWaveErrorInUse, QUuid()); + return QPair(ZWave::ZWaveErrorInUse, QUuid()); } emit networkAdded(network); storeNetwork(network); - return qMakePair(ZWave::ZWaveErrorNoError, network->networkUuid()); + return QPair(ZWave::ZWaveErrorNoError, network->networkUuid()); } ZWave::ZWaveError ZWaveManager::removeNetwork(const QUuid &networkUuid) diff --git a/libnymea/coap/coap.cpp b/libnymea/coap/coap.cpp index b422d196..e76ab8b6 100644 --- a/libnymea/coap/coap.cpp +++ b/libnymea/coap/coap.cpp @@ -427,7 +427,7 @@ void Coap::processTokenBasedResponse(CoapReply *reply, const CoapPdu &pdu) void Coap::processNotification(const CoapPdu &pdu, const QHostAddress &address, const quint16 &port) { CoapObserveResource resource = m_observeResources.value(pdu.token()); - qCDebug(dcCoap) << "<--- Notification" << endl << pdu; + qCDebug(dcCoap) << "<--- Notification" << '\n' << pdu; // check if it is a blockwise notification if (pdu.hasOption(CoapOption::Block2)) { @@ -443,7 +443,7 @@ void Coap::processNotification(const CoapPdu &pdu, const QHostAddress &address, responsePdu.setMessageId(pdu.messageId()); responsePdu.setToken(pdu.token()); - qCDebug(dcCoap) << "---> Notification" << endl << responsePdu; + qCDebug(dcCoap) << "---> Notification" << '\n' << responsePdu; sendCoapPdu(address, port, responsePdu); // create reply for blockwise transfere @@ -500,7 +500,7 @@ void Coap::processNotification(const CoapPdu &pdu, const QHostAddress &address, m_observerReply->setPort(port); m_observerReply->m_timer->start(); - qCDebug(dcCoap) << "---> Notification" << endl << pdu; + qCDebug(dcCoap) << "---> Notification" << '\n' << pdu; sendData(address, port, pduData); return; @@ -514,7 +514,7 @@ void Coap::processNotification(const CoapPdu &pdu, const QHostAddress &address, responsePdu.setMessageId(pdu.messageId()); responsePdu.setToken(pdu.token()); - qCDebug(dcCoap) << "---> Notification" << endl << responsePdu; + qCDebug(dcCoap) << "---> Notification" << '\n' << responsePdu; sendCoapPdu(address, port, responsePdu); int notificationNumber = 0; @@ -662,7 +662,7 @@ void Coap::processBlock2Notification(CoapReply *reply, const CoapPdu &pdu) responsePdu.setMessageId(pdu.messageId()); responsePdu.setToken(pdu.token()); - qCDebug(dcCoap) << "---> Notification" << endl << responsePdu; + qCDebug(dcCoap) << "---> Notification" << '\n' << responsePdu; sendCoapPdu(reply->hostAddress(), reply->port(), responsePdu); reply->appendPayloadData(pdu.payload()); @@ -712,7 +712,7 @@ void Coap::processBlock2Notification(CoapReply *reply, const CoapPdu &pdu) reply->setMessageId(nextBlockRequest.messageId()); - qCDebug(dcCoap) << "---> Notification" << endl << nextBlockRequest; + qCDebug(dcCoap) << "---> Notification" << '\n' << nextBlockRequest; sendData(reply->hostAddress(), reply->port(), pduData); } diff --git a/libnymea/coap/coapoption.cpp b/libnymea/coap/coapoption.cpp index 83aa26f4..9f05b5f0 100644 --- a/libnymea/coap/coapoption.cpp +++ b/libnymea/coap/coapoption.cpp @@ -119,45 +119,45 @@ QDebug operator<<(QDebug debug, const CoapOption &coapOption) switch (coapOption.option()) { case CoapOption::ETag: - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << "0x" + coapOption.data().toHex() << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << "0x" + coapOption.data().toHex() << '\n'; break; case CoapOption::UriHost: - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data() << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data() << '\n'; break; case CoapOption::UriPath: - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data() << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data() << '\n'; break; case CoapOption::UriQuery: - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data() << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data() << '\n'; break; case CoapOption::ContentFormat: { const QMetaObject &pduMetaObject = CoapPdu::staticMetaObject; QMetaEnum contentEnum = pduMetaObject.enumerator(pduMetaObject.indexOfEnumerator("ContentType")); - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << contentEnum.valueToKey(static_cast(coapOption.data().toHex().toInt(0, 16))) << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << contentEnum.valueToKey(static_cast(coapOption.data().toHex().toInt(0, 16))) << '\n'; break; } case CoapOption::Block1: { // SZX = size exponent CoapPduBlock block(coapOption.data()); - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex() << " Block #" << block.blockNumber() << ", More flag = " << block.moreFlag() << ", SZX:" << block.blockSize() << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex() << " Block #" << block.blockNumber() << ", More flag = " << block.moreFlag() << ", SZX:" << block.blockSize() << '\n'; break; } case CoapOption::Block2: { // SZX = size exponent CoapPduBlock block(coapOption.data()); - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex() << " Block #" << block.blockNumber() << ", More flag = " << block.moreFlag() << ", SZX:" << block.blockSize() << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex() << " Block #" << block.blockNumber() << ", More flag = " << block.moreFlag() << ", SZX:" << block.blockSize() << '\n'; break; } case CoapOption::Observe: { - debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex().toInt(0, 16) << endl; + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex().toInt(0, 16) << '\n'; break; } default: QString optionName = optionEnum.valueToKey(coapOption.option()); if (optionName.isNull()) { - debug.nospace() << "CoapOption(" << "Unknown" << "): " << "value = " << coapOption.option() << " -> " << coapOption.data() << " = " << "0x" + coapOption.data().toHex() << endl; + debug.nospace() << "CoapOption(" << "Unknown" << "): " << "value = " << coapOption.option() << " -> " << coapOption.data() << " = " << "0x" + coapOption.data().toHex() << '\n'; } else { - debug.nospace() << "CoapOption(" << optionName << "): " << coapOption.data() << " = " << "0x" + coapOption.data().toHex() << endl; + debug.nospace() << "CoapOption(" << optionName << "): " << coapOption.data() << " = " << "0x" + coapOption.data().toHex() << '\n'; } break; } diff --git a/libnymea/coap/coappdu.cpp b/libnymea/coap/coappdu.cpp index 01bd4ace..70ccbeea 100644 --- a/libnymea/coap/coappdu.cpp +++ b/libnymea/coap/coappdu.cpp @@ -179,7 +179,7 @@ CoapPdu::CoapPdu(QObject *parent) : m_payload(QByteArray()), m_error(NoError) { - qsrand(QDateTime::currentMSecsSinceEpoch()); + std::srand(QDateTime::currentMSecsSinceEpoch()); } /*! Constructs a CoapPdu from the given \a data with the given \a parent. */ @@ -193,7 +193,7 @@ CoapPdu::CoapPdu(const QByteArray &data, QObject *parent) : m_payload(QByteArray()), m_error(NoError) { - qsrand(QDateTime::currentMSecsSinceEpoch()); + std::srand(QDateTime::currentMSecsSinceEpoch()); unpack(data); } @@ -263,7 +263,7 @@ quint16 CoapPdu::messageId() const */ void CoapPdu::createMessageId() { - setMessageId((quint16)qrand() % 65536); + setMessageId((quint16)std::rand() % 65536); } /*! Sets the messageId of this \l{CoapPdu} to the given \a messageId. */ @@ -301,9 +301,9 @@ void CoapPdu::createToken() { m_token.clear(); // make sure that the toke has a minimum size of 1 - quint8 length = (quint8)(qrand() % 7) + 1; + quint8 length = (quint8)(std::rand() % 7) + 1; for (int i = 0; i < length; i++) { - m_token.append((char)qrand() % 256); + m_token.append((char)std::rand() % 256); } } @@ -621,18 +621,18 @@ QDebug operator<<(QDebug debug, const CoapPdu &coapPdu) QDebugStateSaver saver(debug); const QMetaObject &metaObject = CoapPdu::staticMetaObject; QMetaEnum messageTypeEnum = metaObject.enumerator(metaObject.indexOfEnumerator("MessageType")); - debug.nospace() << "CoapPdu(" << messageTypeEnum.valueToKey(coapPdu.messageType()) << ")" << endl; - debug.nospace() << " Code: " << CoapPdu::getReqRspCodeString(coapPdu.reqRspCode()) << endl; - debug.nospace() << " Ver: " << coapPdu.version() << endl; - debug.nospace() << " Token: " << coapPdu.token().length() << " " << "0x"+ coapPdu.token().toHex() << endl; - debug.nospace() << " Message ID: " << coapPdu.messageId() << endl; - debug.nospace() << " Payload size: " << coapPdu.payload().size() << endl; + debug.nospace() << "CoapPdu(" << messageTypeEnum.valueToKey(coapPdu.messageType()) << ")" << '\n'; + debug.nospace() << " Code: " << CoapPdu::getReqRspCodeString(coapPdu.reqRspCode()) << '\n'; + debug.nospace() << " Ver: " << coapPdu.version() << '\n'; + debug.nospace() << " Token: " << coapPdu.token().length() << " " << "0x"+ coapPdu.token().toHex() << '\n'; + debug.nospace() << " Message ID: " << coapPdu.messageId() << '\n'; + debug.nospace() << " Payload size: " << coapPdu.payload().size() << '\n'; foreach (const CoapOption &option, coapPdu.options()) { debug.nospace() << " " << option; } if (!coapPdu.payload().isEmpty()) - debug.nospace() << endl << coapPdu.payload() << endl; + debug.nospace() << '\n' << coapPdu.payload() << '\n'; return debug; } diff --git a/libnymea/coap/coapreply.cpp b/libnymea/coap/coapreply.cpp index c7698ee0..2085ea5c 100644 --- a/libnymea/coap/coapreply.cpp +++ b/libnymea/coap/coapreply.cpp @@ -352,13 +352,13 @@ QDebug operator<<(QDebug debug, CoapReply *reply) const QMetaObject &metaObject = CoapPdu::staticMetaObject; QMetaEnum messageTypeEnum = metaObject.enumerator(metaObject.indexOfEnumerator("MessageType")); QMetaEnum contentTypeEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ContentType")); - debug.nospace() << "CoapReply(" << messageTypeEnum.valueToKey(reply->messageType()) << ")" << endl; - debug.nospace() << " Status code: " << CoapPdu::getReqRspCodeString(reply->reqRspCode()) << endl; - debug.nospace() << " Content type: " << contentTypeEnum.valueToKey(reply->contentType()) << endl; - debug.nospace() << " Payload size: " << reply->payload().size() << endl; + debug.nospace() << "CoapReply(" << messageTypeEnum.valueToKey(reply->messageType()) << ")" << '\n'; + debug.nospace() << " Status code: " << CoapPdu::getReqRspCodeString(reply->reqRspCode()) << '\n'; + debug.nospace() << " Content type: " << contentTypeEnum.valueToKey(reply->contentType()) << '\n'; + debug.nospace() << " Payload size: " << reply->payload().size() << '\n'; if (!reply->payload().isEmpty()) - debug.nospace() << endl << reply->payload() << endl; + debug.nospace() << '\n' << reply->payload() << '\n'; return debug; } diff --git a/libnymea/coap/corelink.cpp b/libnymea/coap/corelink.cpp index 16d05476..af7e91b6 100644 --- a/libnymea/coap/corelink.cpp +++ b/libnymea/coap/corelink.cpp @@ -146,22 +146,22 @@ QDebug operator<<(QDebug debug, const CoreLink &link) QDebugStateSaver saver(debug); const QMetaObject &metaObject = CoapPdu::staticMetaObject; QMetaEnum contentTypeEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ContentType")); - debug.nospace() << "CoapLink(" << link.path() << ")" << endl; + debug.nospace() << "CoapLink(" << link.path() << ")" << '\n'; if (!link.title().isEmpty()) - debug.nospace() << " Title: " << link.title() << endl; + debug.nospace() << " Title: " << link.title() << '\n'; - debug.nospace() << " Resource type: " << link.resourceType() << endl; - debug.nospace() << " Content type: " << contentTypeEnum.valueToKey(link.contentType()) << endl; + debug.nospace() << " Resource type: " << link.resourceType() << '\n'; + debug.nospace() << " Content type: " << contentTypeEnum.valueToKey(link.contentType()) << '\n'; if (link.observable()) - debug.nospace() << " Observable: " << link.observable() << endl; + debug.nospace() << " Observable: " << link.observable() << '\n'; if (!link.interfaceDescription().isEmpty()) - debug.nospace() << " Interface description: " << link.interfaceDescription() << endl; + debug.nospace() << " Interface description: " << link.interfaceDescription() << '\n'; if (link.maximumSize() >= 0) - debug.nospace() << " Maximum size: " << link.maximumSize() << endl; + debug.nospace() << " Maximum size: " << link.maximumSize() << '\n'; return debug; } diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h index cb34adc0..6ee307d6 100644 --- a/libnymea/hardwaremanager.h +++ b/libnymea/hardwaremanager.h @@ -35,7 +35,6 @@ class Radio433; class UpnpDiscovery; -class PluginTimerManager; class NetworkAccessManager; class UpnpDeviceDescriptor; class PlatformZeroConfController; @@ -48,6 +47,9 @@ class HardwareResource; class ModbusRtuHardwareResource; class NetworkDeviceDiscovery; +// Note: https://www.qt.io/blog/whats-new-in-qmetatype-qvariant +#include "plugintimer.h" + class HardwareManager : public QObject { Q_OBJECT diff --git a/libnymea/integrations/browseresult.h b/libnymea/integrations/browseresult.h index 888f4851..bf835276 100644 --- a/libnymea/integrations/browseresult.h +++ b/libnymea/integrations/browseresult.h @@ -32,6 +32,7 @@ #define BROWSERESULT_H #include +#include #include "thing.h" diff --git a/libnymea/integrations/browseritemresult.h b/libnymea/integrations/browseritemresult.h index 75882a43..7e583b48 100644 --- a/libnymea/integrations/browseritemresult.h +++ b/libnymea/integrations/browseritemresult.h @@ -32,6 +32,7 @@ #define BROWSERITEMRESULT_H #include +#include #include "thing.h" diff --git a/libnymea/integrations/integrationplugin.cpp b/libnymea/integrations/integrationplugin.cpp index 5ab5ee77..02846569 100644 --- a/libnymea/integrations/integrationplugin.cpp +++ b/libnymea/integrations/integrationplugin.cpp @@ -96,6 +96,7 @@ #include #include #include +#include /*! IntegrationPlugin constructor. IntegrationPlugins will be instantiated by the system. This should never be called manually by a plugin implementation. @@ -407,7 +408,7 @@ void IntegrationPlugin::initPlugin(ThingManager *thingManager, HardwareManager * m_thingManager = thingManager; m_hardwareManager = hardwareManager; m_apiKeyStorage = apiKeyStorage; - m_storage = new QSettings(NymeaSettings::settingsPath() + "/pluginconfig-" + pluginId().toString().remove(QRegExp("[{}]")) + ".conf", QSettings::IniFormat, this); + m_storage = new QSettings(NymeaSettings::settingsPath() + "/pluginconfig-" + pluginId().toString().remove(QRegularExpression("[{}]")) + ".conf", QSettings::IniFormat, this); } /*! Returns a map containing the plugin configuration. diff --git a/libnymea/integrations/pluginmetadata.cpp b/libnymea/integrations/pluginmetadata.cpp index 3bf5faca..0cfcabd0 100644 --- a/libnymea/integrations/pluginmetadata.cpp +++ b/libnymea/integrations/pluginmetadata.cpp @@ -371,8 +371,8 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) } } - QVariant::Type t = QVariant::nameToType(st.value("type").toString().toLatin1().data()); - if (t == QVariant::Invalid) { + QMetaType::Type t = static_cast(QVariant::nameToType(st.value("type").toString().toLatin1().data())); + if (t == QMetaType::UnknownType) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" state type \"" + stateTypeName + "\" has invalid type: \"" + st.value("type").toString() + "\""); hasError = true; } @@ -460,14 +460,14 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) QString ioTypeString = st.value("ioType").toString(); Types::IOType ioType = Types::IOTypeNone; if (ioTypeString == "digitalInput") { - if (stateType.type() != QVariant::Bool) { + if (stateType.type() != QMetaType::Bool) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" state type \"" + stateTypeName + "\" is marked as digital input but type is not \"bool\""); hasError = true; break; } ioType = Types::IOTypeDigitalInput; } else if (ioTypeString == "digitalOutput") { - if (stateType.type() != QVariant::Bool) { + if (stateType.type() != QMetaType::Bool) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" state type \"" + stateTypeName + "\" is marked as digital output but type is not \"bool\""); hasError = true; break; @@ -479,7 +479,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) } ioType = Types::IOTypeDigitalOutput; } else if (ioTypeString == "analogInput") { - if (stateType.type() != QVariant::Double && stateType.type() != QVariant::Int && stateType.type() != QVariant::UInt) { + if (stateType.type() != QMetaType::Double && stateType.type() != QMetaType::Int && stateType.type() != QMetaType::UInt) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" state type \"" + stateTypeName + "\" is marked as analog input but type is not \"double\", \"int\" or \"uint\""); hasError = true; break; @@ -491,7 +491,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) } ioType = Types::IOTypeAnalogInput; } else if (ioTypeString == "analogOutput") { - if (stateType.type() != QVariant::Double && stateType.type() != QVariant::Int && stateType.type() != QVariant::UInt) { + if (stateType.type() != QMetaType::Double && stateType.type() != QMetaType::Int && stateType.type() != QMetaType::UInt) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" state type \"" + stateTypeName + "\" is marked as analog output but type is not \"double\", \"int\" or \"uint\""); hasError = true; break; @@ -508,7 +508,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) } ioType = Types::IOTypeAnalogOutput; } else { - m_validationErrors.append("Thing class \"" + thingClass.name() + "\" state type \"" + stateTypeName + "\" has invalid ioType value \"" + ioType + "\" which is not any of \"digitalInput\", \"digitalOutput\", \"analogInput\" or \"analogOutput\""); + m_validationErrors.append("Thing class \"" + thingClass.name() + "\" state type \"" + stateTypeName + "\" has invalid ioType value \"IOTypeNone\" which is not any of \"digitalInput\", \"digitalOutput\", \"analogInput\" or \"analogOutput\""); hasError = true; break; } @@ -1067,8 +1067,8 @@ QPair PluginMetadata::parseParamTypes(const QJsonArray &array) } // Check type - QVariant::Type t = QVariant::nameToType(pt.value("type").toString().toLatin1().data()); - if (t == QVariant::Invalid) { + QMetaType::Type t = static_cast(QVariant::nameToType(pt.value("type").toString().toLatin1().data())); + if (t == QMetaType::UnknownType) { m_validationErrors.append("Param type \"" + paramName + "\" has unknown invalid type \"" + pt.value("type").toString() + "\""); hasErrors = true; } diff --git a/libnymea/integrations/thing.cpp b/libnymea/integrations/thing.cpp index a658004b..ef7c06f0 100644 --- a/libnymea/integrations/thing.cpp +++ b/libnymea/integrations/thing.cpp @@ -134,6 +134,7 @@ #include "types/event.h" #include "loggingcategories.h" #include "statevaluefilters/statevaluefilteradaptive.h" +#include "thingutils.h" #include #include @@ -385,11 +386,11 @@ void Thing::setStateValue(const StateTypeId &stateTypeId, const QVariant &value) return; } State state = m_states.at(i); - if (state.minValue().isValid() && value < state.minValue()) { + if (state.minValue().isValid() && ThingUtils::variantLessThan(value, state.minValue())) { qCWarning(dcThing()).nospace() << this << ": Invalid value " << value << " for state " << stateType.name() << ". Out of range: " << state.minValue() << " - " << state.maxValue() << " (Correcting to closest value within range)"; newValue = state.minValue(); } - if (state.maxValue().isValid() && value > state.maxValue()) { + if (state.maxValue().isValid() && ThingUtils::variantGreaterThan(value, state.maxValue())) { qCWarning(dcThing()).nospace() << this << ": Invalid value " << value << " for state " << stateType.name() << ". Out of range: " << state.minValue() << " - " << state.maxValue() << " (Correcting to closest value within range)"; newValue = state.maxValue(); } @@ -452,11 +453,11 @@ void Thing::setStateMinValue(const StateTypeId &stateTypeId, const QVariant &min m_states[i].setMinValue(newMin); // Sanity check for max >= min - if (m_states.at(i).maxValue() < newMin) { + if (ThingUtils::variantLessThan(m_states.at(i).maxValue(), newMin)) { qCWarning(dcThing()).nospace() << this << ": Adjusting state maximum value for " << stateType.name() << " from " << m_states.at(i).maxValue() << " to new minimum value of " << newMin; m_states[i].setMaxValue(newMin); } - if (m_states.at(i).value() < newMin) { + if (ThingUtils::variantLessThan(m_states.at(i).value(), newMin)) { qCInfo(dcThing()).nospace() << this << ": Adjusting state value for " << stateType.name() << " from " << m_states.at(i).value() << " to new minimum value of " << newMin; m_states[i].setValue(newMin); } @@ -496,12 +497,12 @@ void Thing::setStateMaxValue(const StateTypeId &stateTypeId, const QVariant &max if (newMax.isValid()) { // Sanity check for min <= max - if (m_states.at(i).minValue() > newMax) { + if (ThingUtils::variantGreaterThan(m_states.at(i).minValue(), newMax)) { qCWarning(dcThing()).nospace() << this << ": Adjusting minimum state value for " << stateType.name() << " from " << m_states.at(i).minValue() << " to new maximum value of " << newMax; m_states[i].setMinValue(newMax); } - if (m_states.at(i).value() > newMax) { + if (ThingUtils::variantGreaterThan(m_states.at(i).value(), newMax)) { qCInfo(dcThing()).nospace() << this << ": Adjusting state value for " << stateType.name() << " from " << m_states.at(i).value() << " to new maximum value of " << newMax; m_states[i].setValue(maxValue); } @@ -543,16 +544,16 @@ void Thing::setStateMinMaxValues(const StateTypeId &stateTypeId, const QVariant if (newMax.isValid() || newMax.isValid()) { // Sanity check for min <= max - if (newMin > newMax) { + if (ThingUtils::variantGreaterThan(newMin, newMax)) { qCWarning(dcThing()).nospace() << this << ": Adjusting maximum state value for " << stateType.name() << " from " << m_states.at(i).maxValue() << " to new minimum value of " << newMax; m_states[i].setMaxValue(newMin); } - if (m_states.at(i).value() < m_states.at(i).minValue()) { + if (ThingUtils::variantLessThan(m_states.at(i).value(), m_states.at(i).minValue())) { qCInfo(dcThing()).nospace() << this << ": Adjusting state value for " << stateType.name() << " from " << m_states.at(i).value() << " to new minimum value of " << m_states.at(i).minValue(); m_states[i].setValue(m_states.at(i).minValue()); } - if (m_states.at(i).value() > m_states.at(i).maxValue()) { + if (ThingUtils::variantGreaterThan(m_states.at(i).value(), m_states.at(i).maxValue())) { qCInfo(dcThing()).nospace() << this << ": Adjusting state value for " << stateType.name() << " from " << m_states.at(i).value() << " to new maximum value of " << m_states.at(i).maxValue(); m_states[i].setValue(m_states.at(i).maxValue()); } diff --git a/libnymea/integrations/thingactioninfo.cpp b/libnymea/integrations/thingactioninfo.cpp index be09c39c..056bcefc 100644 --- a/libnymea/integrations/thingactioninfo.cpp +++ b/libnymea/integrations/thingactioninfo.cpp @@ -107,5 +107,5 @@ void ThingActionInfo::finish(Thing::ThingError status, const QString &displayMes m_finished = true; m_status = status; m_displayMessage = displayMessage; - staticQtMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection); + staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection); } diff --git a/libnymea/integrations/thingutils.cpp b/libnymea/integrations/thingutils.cpp index e1a40b02..fc44c4cb 100644 --- a/libnymea/integrations/thingutils.cpp +++ b/libnymea/integrations/thingutils.cpp @@ -98,7 +98,7 @@ Thing::ThingError ThingUtils::verifyParam(const ParamType ¶mType, const Para return Thing::ThingErrorInvalidParameter; } - if (paramType.type() == QVariant::Int) { + if (paramType.type() == QMetaType::Int) { if (paramType.maxValue().isValid() && param.value().toInt() > paramType.maxValue().toInt()) { qCWarning(dcThing) << "Value out of range for param" << param.paramTypeId().toString() << " Got:" << param.value() << " Max:" << paramType.maxValue(); return Thing::ThingErrorInvalidParameter; @@ -108,7 +108,7 @@ Thing::ThingError ThingUtils::verifyParam(const ParamType ¶mType, const Para qCWarning(dcThing) << "Value out of range for param" << param.paramTypeId().toString() << " Got:" << param.value() << " Min:" << paramType.minValue(); return Thing::ThingErrorInvalidParameter; } - } else if (paramType.type() == QVariant::UInt) { + } else if (paramType.type() == QMetaType::UInt) { if (paramType.maxValue().isValid() && param.value().toUInt() > paramType.maxValue().toUInt()) { qCWarning(dcThing) << "Value out of range for param" << param.paramTypeId().toString() << " Got:" << param.value() << " Max:" << paramType.maxValue(); return Thing::ThingErrorInvalidParameter; @@ -118,7 +118,7 @@ Thing::ThingError ThingUtils::verifyParam(const ParamType ¶mType, const Para qCWarning(dcThing) << "Value out of range for param" << param.paramTypeId().toString() << " Got:" << param.value() << " Min:" << paramType.minValue(); return Thing::ThingErrorInvalidParameter; } - } else if (paramType.type() == QVariant::Double) { + } else if (paramType.type() == QMetaType::Double) { if (paramType.maxValue().isValid() && param.value().toDouble() > paramType.maxValue().toDouble()) { qCWarning(dcThing) << "Value out of range for param" << param.paramTypeId().toString() << " Got:" << param.value() << " Max:" << paramType.maxValue(); return Thing::ThingErrorInvalidParameter; @@ -129,12 +129,12 @@ Thing::ThingError ThingUtils::verifyParam(const ParamType ¶mType, const Para return Thing::ThingErrorInvalidParameter; } } else { - if (paramType.maxValue().isValid() && param.value() > paramType.maxValue()) { + if (paramType.maxValue().isValid() && ThingUtils::variantGreaterThan(param.value(), paramType.maxValue())) { qCWarning(dcThing) << "Value out of range for param" << param.paramTypeId().toString() << " Got:" << param.value() << " Max:" << paramType.maxValue(); return Thing::ThingErrorInvalidParameter; } - if (paramType.minValue().isValid() && param.value() < paramType.minValue()) { + if (paramType.minValue().isValid() && ThingUtils::variantLessThan(param.value(), paramType.minValue())) { qCWarning(dcThing) << "Value out of range for param" << param.paramTypeId().toString() << " Got:" << param.value() << " Min:" << paramType.minValue(); return Thing::ThingErrorInvalidParameter; } @@ -199,7 +199,7 @@ Interface ThingUtils::loadInterface(const QString &name) InterfaceParamType paramType; paramType.setName(paramMap.value("name").toString()); - paramType.setType(QVariant::nameToType(paramMap.value("type").toByteArray())); + paramType.setType(static_cast(QVariant::nameToType(paramMap.value("type").toByteArray()))); paramType.setMinValue(paramMap.value("minValue")); paramType.setMaxValue(paramMap.value("maxValue")); paramType.setDefaultValue(paramMap.value("defaultValue")); @@ -226,7 +226,7 @@ Interface ThingUtils::loadInterface(const QString &name) QVariantMap stateMap = stateVariant.toMap(); InterfaceStateType stateType; stateType.setName(stateMap.value("name").toString()); - stateType.setType(QVariant::nameToType(stateMap.value("type").toByteArray())); + stateType.setType(static_cast(QVariant::nameToType(stateMap.value("type").toByteArray()))); stateType.setPossibleValues(stateMap.value("allowedValues").toList()); stateType.setMinValue(stateMap.value("minValue")); stateType.setMaxValue(stateMap.value("maxValue")); @@ -276,7 +276,7 @@ Interface ThingUtils::loadInterface(const QString &name) foreach (const QVariant &actionParamVariant, actionVariant.toMap().value("params").toList()) { ParamType paramType; paramType.setName(actionParamVariant.toMap().value("name").toString()); - paramType.setType(QVariant::nameToType(actionParamVariant.toMap().value("type").toByteArray())); + paramType.setType(static_cast(QVariant::nameToType(actionParamVariant.toMap().value("type").toByteArray()))); paramType.setAllowedValues(actionParamVariant.toMap().value("allowedValues").toList()); paramType.setMinValue(actionParamVariant.toMap().value("min")); paramType.setDefaultValue(actionParamVariant.toMap().value("defaultValue")); @@ -298,7 +298,7 @@ Interface ThingUtils::loadInterface(const QString &name) foreach (const QVariant &eventParamVariant, eventVariant.toMap().value("params").toList()) { ParamType paramType; paramType.setName(eventParamVariant.toMap().value("name").toString()); - paramType.setType(QVariant::nameToType(eventParamVariant.toMap().value("type").toByteArray())); + paramType.setType(static_cast(QVariant::nameToType(eventParamVariant.toMap().value("type").toByteArray()))); paramType.setAllowedValues(eventParamVariant.toMap().value("allowedValues").toList()); paramType.setMinValue(eventParamVariant.toMap().value("minValue")); paramType.setMaxValue(eventParamVariant.toMap().value("maxValue")); @@ -367,3 +367,23 @@ QStringList ThingUtils::generateInterfaceParentList(const QString &interface) } return ret; } + +bool ThingUtils::variantLessThan(const QVariant &leftHandSide, const QVariant &rightHandSide) +{ + // Note: https://www.mail-archive.com/development@qt-project.org/msg39450.html +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + return (QVariant::compare(leftHandSide, rightHandSide) == QPartialOrdering::Less); +#else + return leftHandSide < rightHandSide; +#endif +} + +bool ThingUtils::variantGreaterThan(const QVariant &leftHandSide, const QVariant &rightHandSide) +{ + // Note: https://www.mail-archive.com/development@qt-project.org/msg39450.html +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + return (QVariant::compare(leftHandSide, rightHandSide) == QPartialOrdering::Greater); +#else + return leftHandSide > rightHandSide; +#endif +} diff --git a/libnymea/integrations/thingutils.h b/libnymea/integrations/thingutils.h index c9bf43fb..e108528c 100644 --- a/libnymea/integrations/thingutils.h +++ b/libnymea/integrations/thingutils.h @@ -51,6 +51,8 @@ public: static Interface mergeInterfaces(const Interface &iface1, const Interface &iface2); static QStringList generateInterfaceParentList(const QString &interface); + static bool variantLessThan(const QVariant &leftHandSide, const QVariant &rightHandSide); + static bool variantGreaterThan(const QVariant &leftHandSide, const QVariant &rightHandSide); }; #endif // THINGUTILS_H diff --git a/libnymea/jsonrpc/jsonhandler.cpp b/libnymea/jsonrpc/jsonhandler.cpp index 12a43219..56f411bd 100644 --- a/libnymea/jsonrpc/jsonhandler.cpp +++ b/libnymea/jsonrpc/jsonhandler.cpp @@ -35,9 +35,11 @@ #include #include +#include "types/param.h" + JsonHandler::JsonHandler(QObject *parent) : QObject(parent) { - qRegisterMetaType(); + qRegisterMetaType(); registerEnum(); } @@ -83,63 +85,63 @@ QString JsonHandler::objectRef(const QString &objectName) return "$ref:" + objectName; } -JsonHandler::BasicType JsonHandler::variantTypeToBasicType(QVariant::Type variantType) +JsonHandler::BasicType JsonHandler::variantTypeToBasicType(QMetaType::Type variantType) { switch (variantType) { - case QVariant::Uuid: + case QMetaType::QUuid: return Uuid; - case QVariant::String: + case QMetaType::QString: return String; - case QVariant::StringList: + case QMetaType::QStringList: return StringList; - case QVariant::Int: + case QMetaType::Int: return Int; - case QVariant::UInt: + case QMetaType::UInt: return Uint; - case QVariant::Double: + case QMetaType::Double: return Double; - case QVariant::Bool: + case QMetaType::Bool: return Bool; - case QVariant::Color: + case QMetaType::QColor: return Color; - case QVariant::Time: + case QMetaType::QTime: return Time; - case QVariant::Map: + case QMetaType::QVariantMap: return Object; - case QVariant::DateTime: + case QMetaType::QDateTime: return Uint; // DateTime is represented as time_t default: return Variant; } } -QVariant::Type JsonHandler::basicTypeToVariantType(JsonHandler::BasicType basicType) +QMetaType::Type JsonHandler::basicTypeToMetaType(JsonHandler::BasicType basicType) { switch (basicType) { case Uuid: - return QVariant::Uuid; + return QMetaType::QUuid; case String: - return QVariant::String; + return QMetaType::QString; case StringList: - return QVariant::StringList; + return QMetaType::QStringList; case Int: - return QVariant::Int; + return QMetaType::Int; case Uint: - return QVariant::UInt; + return QMetaType::UInt; case Double: - return QVariant::Double; + return QMetaType::Double; case Bool: - return QVariant::Bool; + return QMetaType::Bool; case Color: - return QVariant::Color; + return QMetaType::QColor; case Time: - return QVariant::Time; + return QMetaType::QTime; case Object: - return QVariant::Map; + return QMetaType::QVariantMap; case Variant: - return QVariant::Invalid; + return QMetaType::UnknownType; } - return QVariant::Invalid; + return QMetaType::UnknownType; } void JsonHandler::registerObject(const QString &name, const QVariantMap &object) @@ -190,6 +192,9 @@ void JsonHandler::registerObject(const QMetaObject &metaObject) for (int i = 0; i < metaObject.propertyCount(); i++) { QMetaProperty metaProperty = metaObject.property(i); QString name = metaProperty.name(); + // if (className == "Thing") + // qCDebug(dcJsonRpc()) << "Thing!" << metaProperty.isUser() << metaProperty.isWritable() << metaProperty.revision(); + if (name == "objectName") { continue; // Skip QObject's objectName property } @@ -199,19 +204,57 @@ void JsonHandler::registerObject(const QMetaObject &metaObject) if (!metaProperty.isWritable()) { name.prepend("r:"); } - if (metaProperty.revision() == 1) { + if (metaProperty.revision() != 0) { name.prepend("d:"); } QVariant typeName; - if (metaProperty.type() == QVariant::UserType) { - if (metaProperty.typeName() == QStringLiteral("QVariant::Type")) { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + int typeId = metaProperty.typeId(); + if (typeId >= QMetaType::User) { + if (metaProperty.typeName() == QStringLiteral("QMetaType::Type")) { typeName = QString("$ref:BasicType"); } else if (QString(metaProperty.typeName()).startsWith("QList")) { QString elementType = QString(metaProperty.typeName()).remove("QList<").remove(">"); if (elementType == "ThingId" || elementType == "EventTypeId" || elementType == "StateTypeId" || elementType == "ActionTypeId") { elementType = "QUuid"; } - QVariant::Type variantType = QVariant::nameToType(elementType.toUtf8()); + QMetaType::Type variantType = static_cast(QVariant::nameToType(elementType.toUtf8())); + typeName = QVariantList() << enumValueName(variantTypeToBasicType(variantType)); + } else { + QString typeNameRaw = QString(metaProperty.typeName()); + QString propertyNameRaw = QString(metaProperty.name()); + QString metaTypeNameRaw = QString(metaProperty.metaType().name()); + if (typeNameRaw.contains("QFlag")) { + QString enumType = QString(typeNameRaw).split("::").last().remove('<').remove('>'); + typeName = QString("$ref:%1").arg(m_flagsEnums.key(enumType)); + } else { + typeName = QString("$ref:%1").arg(QString(typeNameRaw).split("::").last().remove('<').remove('>')); + } + + qCDebug(dcJsonRpc()) << typeNameRaw << propertyNameRaw << metaTypeNameRaw << typeName; + } + } else if (metaProperty.isEnumType()) { + QString typeNameRaw = QString(metaProperty.typeName()); + // Note: since Qt6 flags are also enums, and the type name contains + // QFlags, therefore we need to remove additionally all < > + typeName = QString("$ref:%1").arg(typeNameRaw.split("::").last().remove('<').remove('>')); + } else if (metaProperty.isFlagType()) { + typeName = QVariantList() << "$ref:" + m_flagsEnums.value(metaProperty.name()); + } else if (typeId == QMetaType::QVariantList) { + typeName = QVariantList() << enumValueName(Variant); + } else { + typeName = enumValueName(variantTypeToBasicType(static_cast(typeId))); + } +#else + if (metaProperty.type() == QVariant::UserType) { + if (metaProperty.typeName() == QStringLiteral("QMetaType::Type")) { + typeName = QString("$ref:BasicType"); + } else if (QString(metaProperty.typeName()).startsWith("QList")) { + QString elementType = QString(metaProperty.typeName()).remove("QList<").remove(">"); + if (elementType == "ThingId" || elementType == "EventTypeId" || elementType == "StateTypeId" || elementType == "ActionTypeId") { + elementType = "QUuid"; + } + QMetaType::Type variantType = static_cast(QVariant::nameToType(elementType.toUtf8())); typeName = QVariantList() << enumValueName(variantTypeToBasicType(variantType)); } else { typeName = QString("$ref:%1").arg(QString(metaProperty.typeName()).split("::").last()); @@ -223,8 +266,10 @@ void JsonHandler::registerObject(const QMetaObject &metaObject) } else if (metaProperty.type() == QVariant::List) { typeName = QVariantList() << enumValueName(Variant); } else { - typeName = enumValueName(variantTypeToBasicType(metaProperty.type())); + typeName = enumValueName(variantTypeToBasicType(static_cast(metaProperty.type()))); } + +#endif description.insert(name, typeName); } m_objects.insert(className, description); @@ -278,16 +323,70 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con } QVariant propertyValue = metaProperty.readOnGadget(value); + qCDebug(dcJsonRpc()) << metaProperty.name() << "optional:" << metaProperty.isUser() << "value:" << propertyValue << "valid:" << propertyValue.isValid() << "null:" << propertyValue.isNull(); + // If it's optional and empty, we may skip it +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + if (metaProperty.isUser()) { + + bool isEmpty = false; + + switch (propertyValue.typeId()) { + case QMetaType::QString: + isEmpty = propertyValue.toString().isEmpty(); + break; + case QMetaType::QUuid: + isEmpty = propertyValue.toUuid().isNull(); + break; + default: + isEmpty = (!propertyValue.isValid() || propertyValue.isNull()); + break; + } + + if (isEmpty) { + // Optional and empty...skip this property + continue; + } + } +#else if (metaProperty.isUser() && (!propertyValue.isValid() || propertyValue.isNull())) { continue; } +#endif +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + // Pack flags + if (metaProperty.isFlagType()) { + QString enumName = QString(metaProperty.typeName()).split("::").last().remove('<').remove('>'); + QString flagName = m_flagsEnums.key(enumName); + QMetaEnum metaFlag = m_metaFlags.value(flagName); + Q_ASSERT_X(m_metaFlags.contains(flagName), this->metaObject()->className(), QString("Cannot pack %1. %2 is not registered in this handler.").arg(className).arg(flagName).toUtf8()); + int flagValue = propertyValue.toInt(); + QStringList flags; + for (int i = 0; i < metaFlag.keyCount(); i++) { + int flag = metaFlag.value(i) & flagValue; + if (flag == metaFlag.value(i) && flag > 0) { + flags.append(metaFlag.key(i)); + } + } + ret.insert(metaProperty.name(), flags); + continue; + } + + // Pack enums + if (metaProperty.isEnumType()) { + QString enumName = QString(metaProperty.typeName()).split("::").last().remove('<').remove('>'); + Q_ASSERT_X(m_metaEnums.contains(enumName), this->metaObject()->className(), QString("Cannot pack %1. %2 is not registered in this handler.").arg(className).arg(metaProperty.typeName()).toUtf8()); + QMetaEnum metaEnum = m_metaEnums.value(enumName); + ret.insert(metaProperty.name(), metaEnum.key(propertyValue.toInt())); + continue; + } +#else // Pack flags if (metaProperty.isFlagType()) { QString flagName = QString(metaProperty.typeName()).split("::").last(); - Q_ASSERT_X(m_metaFlags.contains(flagName), this->metaObject()->className(), QString("Cannot pack %1. %2 is not registered in this handler.").arg(className).arg(flagName).toUtf8()); QMetaEnum metaFlag = m_metaFlags.value(flagName); + Q_ASSERT_X(m_metaFlags.contains(flagName), this->metaObject()->className(), QString("Cannot pack %1. %2 is not registered in this handler.").arg(className).arg(flagName).toUtf8()); int flagValue = propertyValue.toInt(); QStringList flags; for (int i = 0; i < metaFlag.keyCount(); i++) { @@ -308,17 +407,23 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con ret.insert(metaProperty.name(), metaEnum.key(propertyValue.toInt())); continue; } - +#endif // Basic type/Variant type - if (metaProperty.typeName() == QStringLiteral("QVariant::Type")) { + if (metaProperty.typeName() == QStringLiteral("QMetaType::Type")) { QMetaEnum metaEnum = QMetaEnum::fromType(); - ret.insert(metaProperty.name(), metaEnum.key(variantTypeToBasicType(propertyValue.template value()))); + ret.insert(metaProperty.name(), metaEnum.valueToKey(propertyValue.template value())); continue; } + // Our own objects - if (metaProperty.type() == QVariant::UserType) { - QString propertyTypeName = QString(metaProperty.typeName()).split("::").last(); + QString propertyTypeName = QString(metaProperty.typeName()).split("::").last(); +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + int typeId = metaProperty.typeId(); +#else + int typeId = metaProperty.type(); +#endif + if (typeId >= QMetaType::User) { if (m_listMetaObjects.contains(propertyTypeName)) { QMetaObject entryMetaObject = m_listMetaObjects.value(propertyTypeName); QVariant packed = pack(entryMetaObject, propertyValue.data()); @@ -343,6 +448,17 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con continue; } + // Manually converting QList... Only QVariantList is known to the meta system + if (propertyTypeName.startsWith("ParamList")) { + QVariantList list; + foreach (const Param &entry, propertyValue.value()) { + list << pack(entry); + } + + ret.insert(metaProperty.name(), list); + continue; + } + // Manually converting QList... Only QVariantList is known to the meta system if (propertyTypeName.startsWith("QList<")) { QVariantList list; @@ -372,7 +488,7 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con } } else if (propertyTypeName == "QList") { foreach (const QDateTime ×tamp, propertyValue.value>()) { - list << timestamp.toMSecsSinceEpoch() / 1000; + list << timestamp.toSecsSinceEpoch(); } } else { Q_ASSERT_X(false, this->metaObject()->className(), QString("Unhandled list type: %1").arg(propertyTypeName).toUtf8()); @@ -392,15 +508,19 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con // Standard properties, QString, int etc... // Special treatment for QDateTime (converting to time_t) - if (metaProperty.type() == QVariant::DateTime) { + if (typeId == QMetaType::QDateTime) { QDateTime dateTime = propertyValue.toDateTime(); - if (metaProperty.isUser() && dateTime.toTime_t() == 0) { + if (metaProperty.isUser() && dateTime.toSecsSinceEpoch() == 0) { continue; } - propertyValue = propertyValue.toDateTime().toTime_t(); - } else if (metaProperty.type() == QVariant::Time) { + propertyValue = propertyValue.toDateTime().toSecsSinceEpoch(); + } else if (typeId == QMetaType::QTime) { propertyValue = propertyValue.toTime().toString("hh:mm"); + if (metaProperty.isUser() && propertyValue.toString().isEmpty()) { + continue; + } } + ret.insert(metaProperty.name(), propertyValue); } return ret; @@ -408,7 +528,7 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con Q_ASSERT_X(false, this->metaObject()->className(), QString("Unregistered object type: %1").arg(className).toUtf8()); qCWarning(dcJsonRpc()) << "Cannot pack object of unregistered type" << className; - return QVariant(); + return QVariant(); } QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &value) const @@ -417,8 +537,12 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu // If it's a list object, loop over count if (m_listMetaObjects.contains(typeName)) { - if (value.type() != QVariant::List) { -// qCWarning(dcJsonRpc()) << "Cannot unpack" << typeName << ". Value is not in list format:" << value; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + if (static_cast(value.typeId()) != QMetaType::QVariantList) { +#else + if (static_cast(value.type()) != QMetaType::QVariantList) { +#endif + qCWarning(dcJsonRpc()) << "Cannot unpack" << typeName << ". Value is not in list format:" << value; return QVariant(); } @@ -435,16 +559,20 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu QVariant value = unpack(entryMetaObject, variant); putMethod.invokeOnGadget(ptr, Q_ARG(QVariant, value)); } - - QVariant ret = QVariant(typeId, ptr); +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + QVariant ret = QVariant(QMetaType(typeId), ptr); +#else + QVariant ret = QVariant(static_cast(typeId), ptr); +#endif QMetaType::destroy(typeId, ptr); return ret; } - // if it's an object, loop over all properties + // If it's an object, loop over all properties if (m_metaObjects.contains(typeName)) { QVariantMap map = value.toMap(); int typeId = QMetaType::type(metaObject.className()); + QMetaType metaType(typeId); Q_ASSERT_X(typeId != 0, this->metaObject()->className(), QString("Cannot handle unregistered meta type %1").arg(typeName).toUtf8()); void* ptr = QMetaType::create(typeId); for (int i = 0; i < metaObject.propertyCount(); i++) { @@ -499,10 +627,16 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu continue; } +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + int typeId = metaProperty.typeId(); +#else + int typeId = metaProperty.type(); +#endif + // Special treatment for QDateTime (convert from time_t) - if (metaProperty.type() == QVariant::DateTime) { - variant = QDateTime::fromTime_t(variant.toUInt()); - } else if (metaProperty.type() == QVariant::Time) { + if (typeId == QMetaType::QDateTime) { + variant = QDateTime::fromSecsSinceEpoch(variant.toUInt()); + } else if (typeId == QMetaType::QTime) { variant = QTime::fromString(variant.toString(), "hh:mm"); } @@ -511,7 +645,11 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu } } +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + QVariant ret = QVariant(QMetaType(typeId), ptr); +#else QVariant ret = QVariant(typeId, ptr); +#endif QMetaType::destroy(typeId, ptr); return ret; } diff --git a/libnymea/jsonrpc/jsonhandler.h b/libnymea/jsonrpc/jsonhandler.h index aa0963c3..75632abf 100644 --- a/libnymea/jsonrpc/jsonhandler.h +++ b/libnymea/jsonrpc/jsonhandler.h @@ -47,17 +47,17 @@ class JsonHandler : public QObject Q_OBJECT public: enum BasicType { - Uuid, - String, - StringList, - Int, - Uint, - Double, - Bool, - Variant, - Color, - Time, - Object + Uuid = QMetaType::QUuid, + String = QMetaType::QString, + StringList = QMetaType::QStringList, + Int = QMetaType::Int, + Uint = QMetaType::UInt, + Double = QMetaType::Double, + Bool = QMetaType::Bool, + Variant = QMetaType::QVariant, + Color = QMetaType::QColor, + Time = QMetaType::QTime, + Object = QMetaType::QVariantMap }; Q_ENUM(BasicType) @@ -87,8 +87,8 @@ public: template static QStringList flagValueNames(T value); template static T flagNamesToValue(const QStringList &names); - static BasicType variantTypeToBasicType(QVariant::Type variantType); - static QVariant::Type basicTypeToVariantType(BasicType basicType); + static BasicType variantTypeToBasicType(QMetaType::Type variantType); + static QMetaType::Type basicTypeToMetaType(BasicType basicType); template QVariant pack(const T &value) const; template QVariant pack(T *value) const; @@ -140,7 +140,7 @@ private: QVariantMap m_methods; QVariantMap m_notifications; }; -Q_DECLARE_METATYPE(QVariant::Type) +Q_DECLARE_METATYPE(QMetaType::Type) template void JsonHandler::registerEnum() @@ -213,7 +213,9 @@ void JsonHandler::registerList(BasicTypeName typeName) QMetaObject listMetaObject = ListType::staticMetaObject; QString listTypeName = QString(listMetaObject.className()).split("::").last(); m_metaObjects.insert(listTypeName, listMetaObject); - m_objects.insert(listTypeName, QVariantList() << QVariant(QString("$ref:%1").arg(enumValueName(typeName)))); + //m_objects.insert(listTypeName, QVariantList() << QVariant(QString("$ref:%1").arg(enumValueName(typeName)))); + m_objects.insert(listTypeName, QVariant(QString("$ref:%1").arg(typeName))); + Q_ASSERT_X(listMetaObject.indexOfProperty("count") >= 0, "JsonHandler", QString("List type %1 does not implement \"count\" property!").arg(listTypeName).toUtf8()); Q_ASSERT_X(listMetaObject.indexOfMethod("get(int)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE QVariant get(int index)\" method!").arg(listTypeName).toUtf8()); Q_ASSERT_X(listMetaObject.indexOfMethod("put(QVariant)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE void put(QVariant variant)\" method!").arg(listTypeName).toUtf8()); diff --git a/libnymea/logging/logengine.cpp b/libnymea/logging/logengine.cpp index 03b131dd..64723af8 100644 --- a/libnymea/logging/logengine.cpp +++ b/libnymea/logging/logengine.cpp @@ -1,3 +1,32 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2024, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "logengine.h" #include "logger.h" @@ -24,7 +53,7 @@ void LogFetchJob::finish(const LogEntries &entries) LogEngine::LogEngine(QObject *parent) : QObject{parent} { - + qRegisterMetaType(); } Logger *LogEngine::createLogger(const QString &name, const QStringList &tags, Types::LoggingType loggingType) diff --git a/libnymea/logging/logengine.h b/libnymea/logging/logengine.h index 62e6c2af..197f42b3 100644 --- a/libnymea/logging/logengine.h +++ b/libnymea/logging/logengine.h @@ -1,3 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2024, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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 LOGENGINE_H #define LOGENGINE_H @@ -5,6 +35,7 @@ #include "types/param.h" #include "typeutils.h" #include "logger.h" +#include "logentry.h" #include #include diff --git a/libnymea/logging/logentry.cpp b/libnymea/logging/logentry.cpp index 0176e225..f767fa12 100644 --- a/libnymea/logging/logentry.cpp +++ b/libnymea/logging/logentry.cpp @@ -1,3 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2024, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "logentry.h" LogEntry::LogEntry() diff --git a/libnymea/logging/logentry.h b/libnymea/logging/logentry.h index ad0a8d6d..3fe27997 100644 --- a/libnymea/logging/logentry.h +++ b/libnymea/logging/logentry.h @@ -1,9 +1,39 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2024, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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 LOGENTRY_H #define LOGENTRY_H -#include -#include #include +#include +#include class LogEntry { @@ -11,6 +41,7 @@ class LogEntry Q_PROPERTY(QDateTime timestamp READ timestamp) Q_PROPERTY(QString source READ source ) Q_PROPERTY(QVariantMap values READ values) + public: LogEntry(); LogEntry(const QDateTime ×tamp, const QString &source, const QVariantMap &values); @@ -26,6 +57,7 @@ private: }; Q_DECLARE_METATYPE(LogEntry) + class LogEntries: public QList { Q_GADGET diff --git a/libnymea/logging/logger.cpp b/libnymea/logging/logger.cpp index dfd961df..7d381f3b 100644 --- a/libnymea/logging/logger.cpp +++ b/libnymea/logging/logger.cpp @@ -1,3 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2024, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "logger.h" #include "logengine.h" #include diff --git a/libnymea/logging/logger.h b/libnymea/logging/logger.h index 131049f0..90ce1d79 100644 --- a/libnymea/logging/logger.h +++ b/libnymea/logging/logger.h @@ -1,3 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2024, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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 LOGGER_H #define LOGGER_H diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index 4f68a550..fd38aab6 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -133,7 +133,7 @@ void nymeaLogMessageHandler(QtMsgType type, const QMessageLogContext &context, c QMutexLocker locker(&s_loggerMutex); if (s_logFile.isOpen()) { QTextStream textStream(&s_logFile); - textStream << messageString << endl; + textStream << messageString << '\n'; } } diff --git a/libnymea/network/zeroconf/zeroconfserviceentry.cpp b/libnymea/network/zeroconf/zeroconfserviceentry.cpp index 8506d17a..e3135cf8 100644 --- a/libnymea/network/zeroconf/zeroconfserviceentry.cpp +++ b/libnymea/network/zeroconf/zeroconfserviceentry.cpp @@ -192,12 +192,12 @@ bool ZeroConfServiceEntry::operator !=(const ZeroConfServiceEntry &other) const QDebug operator <<(QDebug dbg, const ZeroConfServiceEntry &entry) { dbg.nospace() << "ZeroConfServiceEntry("; - dbg << entry.name() << ")" << endl; - dbg << " location: " << entry.hostAddress().toString() << ":" << entry.port() << endl; - dbg << " hostname: " << entry.hostName() << endl; - dbg << " domain: " << entry.domain() << endl; - dbg << "service type: " << entry.serviceType() << endl; - dbg << " protocol: " << entry.protocol() << endl; - dbg << " txt: " << entry.txt() << endl; + dbg << entry.name() << ")" << '\n'; + dbg << " location: " << entry.hostAddress().toString() << ":" << entry.port() << '\n'; + dbg << " hostname: " << entry.hostName() << '\n'; + dbg << " domain: " << entry.domain() << '\n'; + dbg << "service type: " << entry.serviceType() << '\n'; + dbg << " protocol: " << entry.protocol() << '\n'; + dbg << " txt: " << entry.txt() << '\n'; return dbg; } diff --git a/libnymea/time/timedescriptor.cpp b/libnymea/time/timedescriptor.cpp index a25a1df9..dc3a0830 100644 --- a/libnymea/time/timedescriptor.cpp +++ b/libnymea/time/timedescriptor.cpp @@ -119,7 +119,7 @@ bool TimeDescriptor::evaluate(const QDateTime &lastEvaluationTime, const QDateTi QDebug operator<<(QDebug dbg, const TimeDescriptor &timeDescriptor) { QDebugStateSaver saver(dbg); - dbg.nospace() << "TimeDescriptor (TimeEventItems:" << timeDescriptor.timeEventItems().count() << ", CalendarItems:" << timeDescriptor.calendarItems().count() << ")" << endl; + dbg.nospace() << "TimeDescriptor (TimeEventItems:" << timeDescriptor.timeEventItems().count() << ", CalendarItems:" << timeDescriptor.calendarItems().count() << ")" << '\n'; for (int i = 0; i < timeDescriptor.timeEventItems().count(); i++) { dbg.nospace() << " " << i << ": " << timeDescriptor.timeEventItems().at(i); } diff --git a/libnymea/time/timeeventitem.cpp b/libnymea/time/timeeventitem.cpp index 56db1583..c787df74 100644 --- a/libnymea/time/timeeventitem.cpp +++ b/libnymea/time/timeeventitem.cpp @@ -146,7 +146,7 @@ bool TimeEventItem::evaluate(const QDateTime &lastEvaluationTime, const QDateTim QDebug operator<<(QDebug dbg, const TimeEventItem &timeEventItem) { QDebugStateSaver saver(dbg); - dbg.nospace() << "TimeEventItem (Time:" << timeEventItem.time() << ", DateTime:" << timeEventItem.dateTime().toString() << ", " << timeEventItem.repeatingOption() << ")" << endl; + dbg.nospace() << "TimeEventItem (Time:" << timeEventItem.time() << ", DateTime:" << timeEventItem.dateTime().toString() << ", " << timeEventItem.repeatingOption() << ")" << '\n'; return dbg; } diff --git a/libnymea/types/eventdescriptor.cpp b/libnymea/types/eventdescriptor.cpp index 75fae587..c0d915ad 100644 --- a/libnymea/types/eventdescriptor.cpp +++ b/libnymea/types/eventdescriptor.cpp @@ -179,7 +179,7 @@ bool EventDescriptor::operator ==(const EventDescriptor &other) const QDebug operator<<(QDebug dbg, const EventDescriptor &eventDescriptor) { QDebugStateSaver saver(dbg); - dbg.nospace() << "EventDescriptor(EventTypeId: " << eventDescriptor.eventTypeId().toString() << ", ThingId:" << eventDescriptor.thingId().toString() << ", Interface:" << eventDescriptor.interface() << ", InterfaceEvent:" << eventDescriptor.interfaceEvent() << ")" << endl; + dbg.nospace() << "EventDescriptor(EventTypeId: " << eventDescriptor.eventTypeId().toString() << ", ThingId:" << eventDescriptor.thingId().toString() << ", Interface:" << eventDescriptor.interface() << ", InterfaceEvent:" << eventDescriptor.interfaceEvent() << ")" << '\n'; for (int i = 0; i < eventDescriptor.paramDescriptors().count(); i++) { dbg.nospace() << " " << i << ": " << eventDescriptor.paramDescriptors().at(i); } @@ -191,7 +191,7 @@ QDebug operator<<(QDebug dbg, const EventDescriptor &eventDescriptor) QDebug operator<<(QDebug dbg, const QList &eventDescriptors) { QDebugStateSaver saver(dbg); - dbg.nospace() << "EventDescriptorList (count:" << eventDescriptors.count() << "):" << endl; + dbg.nospace() << "EventDescriptorList (count:" << eventDescriptors.count() << "):" << '\n'; for (int i = 0; i < eventDescriptors.count(); i++ ) { dbg.nospace() << " " << i << ": " << eventDescriptors.at(i); } diff --git a/libnymea/types/eventtype.cpp b/libnymea/types/eventtype.cpp index 750c7959..959e14e0 100644 --- a/libnymea/types/eventtype.cpp +++ b/libnymea/types/eventtype.cpp @@ -97,14 +97,14 @@ void EventType::setIndex(const int &index) } /*! Holds a List describing possible parameters for a \l{Event} of this EventType. - * e.g. QList(ParamType("temperature", QVariant::Real)). */ + * e.g. QList(ParamType("temperature", QMetaType::Real)). */ ParamTypes EventType::paramTypes() const { return m_paramTypes; } /*! Set the parameter description for this EventType to \a paramTypes, - * e.g. QList() << ParamType("temperature", QVariant::Real)). */ + * e.g. QList() << ParamType("temperature", QMetaType::Real)). */ void EventType::setParamTypes(const ParamTypes ¶mTypes) { m_paramTypes = paramTypes; diff --git a/libnymea/types/param.cpp b/libnymea/types/param.cpp index 78928601..ed89f0d5 100644 --- a/libnymea/types/param.cpp +++ b/libnymea/types/param.cpp @@ -92,10 +92,10 @@ QDebug operator<<(QDebug dbg, const ParamList ¶ms) QDebugStateSaver saver(dbg); dbg.nospace() << "ParamList (count:" << params.count() << ")"; if (params.count() == 0) { - dbg.nospace() << endl; + dbg.nospace() << '\n'; } for (int i = 0; i < params.count(); i++ ) { - dbg.nospace() << endl << " " << i << ": " << params.at(i); + dbg.nospace() << '\n' << " " << i << ": " << params.at(i); } return dbg; diff --git a/libnymea/types/paramdescriptor.cpp b/libnymea/types/paramdescriptor.cpp index 1169ca30..ab285449 100644 --- a/libnymea/types/paramdescriptor.cpp +++ b/libnymea/types/paramdescriptor.cpp @@ -91,7 +91,7 @@ void ParamDescriptor::setOperatorType(Types::ValueOperator operatorType) QDebug operator<<(QDebug dbg, const ParamDescriptor ¶mDescriptor) { QDebugStateSaver saver(dbg); - dbg.nospace() << "ParamDescriptor(ParamTypeId: " << paramDescriptor.paramTypeId().toString() << ", Name:" << paramDescriptor.paramName() << ", Value:" << paramDescriptor.value() << ")" << endl; + dbg.nospace() << "ParamDescriptor(ParamTypeId: " << paramDescriptor.paramTypeId().toString() << ", Name:" << paramDescriptor.paramName() << ", Value:" << paramDescriptor.value() << ")" << '\n'; return dbg; } diff --git a/libnymea/types/paramtype.cpp b/libnymea/types/paramtype.cpp index e941a851..781bdb08 100644 --- a/libnymea/types/paramtype.cpp +++ b/libnymea/types/paramtype.cpp @@ -48,7 +48,7 @@ #include "paramtype.h" /*! Constructs a ParamType object with the given \a id, \a name, \a type and \a defaultValue. */ -ParamType::ParamType(const ParamTypeId &id, const QString &name, const QVariant::Type type, const QVariant &defaultValue): +ParamType::ParamType(const ParamTypeId &id, const QString &name, const QMetaType::Type type, const QVariant &defaultValue): m_id(id), m_name(name), m_index(0), @@ -104,13 +104,13 @@ void ParamType::setIndex(const int &index) } /*! Returns the type of this ParamType. */ -QVariant::Type ParamType::type() const +QMetaType::Type ParamType::type() const { return m_type; } /*! Sets the type of this ParamType to the given \a type. */ -void ParamType::setType(QVariant::Type type) +void ParamType::setType(QMetaType::Type type) { m_type = type; } @@ -178,7 +178,7 @@ void ParamType::setUnit(const Types::Unit &unit) /*! Returns the limits of this ParamType. limits(minValue, maxValue). */ QPair ParamType::limits() const { - return qMakePair(m_minValue, m_maxValue); + return QPair(m_minValue, m_maxValue); } /*! Sets the limits of this ParamType. limits(\a min, \a max). */ @@ -215,7 +215,7 @@ void ParamType::setReadOnly(const bool &readOnly) /*! Returns true if this ParamType is valid. A ParamType is valid, if the id, the name and the data type is set. */ bool ParamType::isValid() const { - return !m_id.isNull() && !m_name.isEmpty() && m_type != QVariant::Invalid; + return !m_id.isNull() && !m_name.isEmpty() && m_type != QMetaType::UnknownType; } /*! Returns a list of all valid JSON properties a ParamType JSON definition can have. */ @@ -234,10 +234,17 @@ QStringList ParamType::mandatoryTypeProperties() /*! Writes the name, type, defaultValue, min value, max value and readOnly of the given \a paramType to \a dbg. */ QDebug operator<<(QDebug dbg, const ParamType ¶mType) { + QString typeName; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + typeName = QString(QMetaType(paramType.type()).name()); +#else + typeName = QVariant::typeToName(paramType.type()); +#endif + QDebugStateSaver saver(dbg); dbg.nospace() << "ParamType(Id" << paramType.id().toString() << " Name: " << paramType.name() - << ", Type:" << QVariant::typeToName(paramType.type()) + << ", Type:" << typeName << ", Default:" << paramType.defaultValue() << ", Min:" << paramType.minValue() << ", Max:" << paramType.maxValue() @@ -252,9 +259,9 @@ QDebug operator<<(QDebug dbg, const ParamType ¶mType) QDebug operator<<(QDebug dbg, const QList ¶mTypes) { QDebugStateSaver saver(dbg); - dbg.nospace() << "ParamTypeList (count:" << paramTypes.count() << ")" << endl; + dbg.nospace() << "ParamTypeList (count:" << paramTypes.count() << ")" << '\n'; for (int i = 0; i < paramTypes.count(); i++ ) { - dbg.nospace() << " " << i << ": " << paramTypes.at(i) << endl; + dbg.nospace() << " " << i << ": " << paramTypes.at(i) << '\n'; } return dbg; diff --git a/libnymea/types/paramtype.h b/libnymea/types/paramtype.h index c3bcacca..be08cbd4 100644 --- a/libnymea/types/paramtype.h +++ b/libnymea/types/paramtype.h @@ -43,7 +43,7 @@ class LIBNYMEA_EXPORT ParamType Q_PROPERTY(QUuid id READ id) Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) - Q_PROPERTY(QVariant::Type type READ type WRITE setType) + Q_PROPERTY(QMetaType::Type type READ type WRITE setType) Q_PROPERTY(int index READ index WRITE setIndex) Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue USER true) Q_PROPERTY(QVariant minValue READ minValue WRITE setMinValue USER true) @@ -55,7 +55,7 @@ class LIBNYMEA_EXPORT ParamType public: ParamType() = default; - ParamType(const ParamTypeId &id, const QString &name, const QVariant::Type type, const QVariant &defaultValue = QVariant()); + ParamType(const ParamTypeId &id, const QString &name, const QMetaType::Type type, const QVariant &defaultValue = QVariant()); ParamTypeId id() const; @@ -68,8 +68,8 @@ public: int index() const; void setIndex(const int &index); - QVariant::Type type() const; - void setType(QVariant::Type type); + QMetaType::Type type() const; + void setType(QMetaType::Type type); QVariant defaultValue() const; void setDefaultValue(const QVariant &defaultValue); @@ -105,7 +105,7 @@ private: QString m_name; QString m_displayName; int m_index; - QVariant::Type m_type; + QMetaType::Type m_type; QVariant m_defaultValue; QVariant m_minValue; QVariant m_maxValue; diff --git a/libnymea/types/statetype.cpp b/libnymea/types/statetype.cpp index f51752d8..6d738feb 100644 --- a/libnymea/types/statetype.cpp +++ b/libnymea/types/statetype.cpp @@ -98,14 +98,14 @@ void StateType::setIndex(const int &index) m_index = index; } -/*! Returns the Type of the StateType (e.g. QVariant::Real). */ -QVariant::Type StateType::type() const +/*! Returns the Type of the StateType (e.g. QMetaType::Real). */ +QMetaType::Type StateType::type() const { return m_type; } -/*! Set the type fo the StateType to \a type (e.g. QVariant::Real). */ -void StateType::setType(const QVariant::Type &type) +/*! Set the type fo the StateType to \a type (e.g. QMetaType::Real). */ +void StateType::setType(const QMetaType::Type &type) { m_type = type; } @@ -241,7 +241,7 @@ void StateType::setFilter(Types::StateValueFilter filter) /*! Returns true if this state type has an ID, a type and a name set. */ bool StateType::isValid() const { - return !m_id.isNull() && m_type != QVariant::Invalid && !m_name.isEmpty(); + return !m_id.isNull() && m_type != QMetaType::UnknownType && !m_name.isEmpty(); } StateTypes::StateTypes(const QList &other) diff --git a/libnymea/types/statetype.h b/libnymea/types/statetype.h index 69d18b7e..328bf7e1 100644 --- a/libnymea/types/statetype.h +++ b/libnymea/types/statetype.h @@ -42,7 +42,7 @@ class LIBNYMEA_EXPORT StateType Q_PROPERTY(QUuid id READ id) Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) - Q_PROPERTY(QVariant::Type type READ type WRITE setType) + Q_PROPERTY(QMetaType::Type type READ type WRITE setType) Q_PROPERTY(int index READ index WRITE setIndex) Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue) Q_PROPERTY(Types::Unit unit READ unit WRITE setUnit USER true) @@ -67,8 +67,8 @@ public: int index() const; void setIndex(const int &index); - QVariant::Type type() const; - void setType(const QVariant::Type &type); + QMetaType::Type type() const; + void setType(const QMetaType::Type &type); QVariant defaultValue() const; void setDefaultValue(const QVariant &defaultValue); @@ -110,7 +110,7 @@ private: QString m_name; QString m_displayName; int m_index = 0; - QVariant::Type m_type = QVariant::Invalid; + QMetaType::Type m_type = QMetaType::UnknownType; QVariant m_defaultValue; QVariant m_minValue; QVariant m_maxValue; diff --git a/libnymea/types/thingclass.h b/libnymea/types/thingclass.h index d06679cf..31f94703 100644 --- a/libnymea/types/thingclass.h +++ b/libnymea/types/thingclass.h @@ -39,10 +39,12 @@ #include "types/statetype.h" #include "types/paramtype.h" +#include #include #include +#include -class LIBNYMEA_EXPORT ThingClass +class ThingClass { Q_GADGET Q_PROPERTY(QUuid id READ id) @@ -70,7 +72,8 @@ public: CreateMethodAuto = 0x02, CreateMethodDiscovery = 0x04 }; - Q_ENUM(CreateMethod) + Q_ENUM(CreateMethod) // Note: required even if Q_DECLARE_FLAGS should do it + Q_DECLARE_FLAGS(CreateMethods, CreateMethod) Q_FLAG(CreateMethods) diff --git a/libnymea/typeutils.h b/libnymea/typeutils.h index ce613b75..22c5df0b 100644 --- a/libnymea/typeutils.h +++ b/libnymea/typeutils.h @@ -31,14 +31,32 @@ #ifndef TYPEUTILS_H #define TYPEUTILS_H -#include #include +#include #include "libnymea.h" + +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + +#include + #define DECLARE_TYPE_ID(type) class type##Id: public QUuid \ { \ public: \ + type##Id(const QUuid &uuid): QUuid(uuid) {} \ + type##Id(): QUuid() {} \ + type##Id(const QString &uuidString): QUuid(QAnyStringView(uuidString)) {} \ + static type##Id create##type##Id() { return type##Id(QUuid::createUuid()); } \ + bool operator==(const type##Id &other) const { \ + return toString() == other.toString(); \ + } \ +}; \ +Q_DECLARE_METATYPE(type##Id); +#else +#define DECLARE_TYPE_ID(type) class type##Id: public QUuid \ +{ \ + public: \ type##Id(const QUuid &uuid): QUuid(uuid) {} \ type##Id(): QUuid() {} \ static type##Id create##type##Id() { return type##Id(QUuid::createUuid()); } \ @@ -46,7 +64,8 @@ public: \ return toString() == other.toString(); \ } \ }; \ -Q_DECLARE_METATYPE(type##Id); + Q_DECLARE_METATYPE(type##Id); +#endif DECLARE_TYPE_ID(Vendor) DECLARE_TYPE_ID(ThingClass) diff --git a/nymea.pri b/nymea.pri index 35d558fa..eb461809 100644 --- a/nymea.pri +++ b/nymea.pri @@ -3,8 +3,24 @@ COPYRIGHT_YEAR_TO=2025 DEFINES += COPYRIGHT_YEAR_STRING=\\\"$${COPYRIGHT_YEAR_FROM}-$${COPYRIGHT_YEAR_TO}\\\" -QMAKE_CXXFLAGS *= -Werror -std=c++11 -g -Wno-deprecated-declarations -QMAKE_LFLAGS *= -std=c++11 +greaterThan(QT_MAJOR_VERSION, 5) { + message("Building using Qt6 support") + CONFIG *= c++17 + QMAKE_LFLAGS *= -std=c++17 + QMAKE_CXXFLAGS *= -std=c++17 + # Python init is crashing in Qt6, + # disable by default until fixed + CONFIG += withoutpython +} else { + message("Building using Qt5 support") + CONFIG *= c++11 + QMAKE_LFLAGS *= -std=c++11 + QMAKE_CXXFLAGS *= -std=c++11 + DEFINES += QT_DISABLE_DEPRECATED_UP_TO=0x050F00 +} + + +QMAKE_CXXFLAGS *= -Werror -g -Wno-deprecated-declarations top_srcdir=$$PWD top_builddir=$$shadowed($$PWD) @@ -76,3 +92,28 @@ asan: { QMAKE_LFLAGS *= -fsanitize=address } + +CONFIG(withoutpython) { + message("Building without python support.") + CONFIG -= python +} else:packagesExist(python3-embed) { + # As of Ubuntu focal, there's a commonly named python3-embed pointing to the distro version of python + # For everything below python 3.8 we need to manually select one + PKGCONFIG += python3-embed + CONFIG += python +} else:packagesExist(python-3.5) { + # xenial, stretch + PKGCONFIG += python-3.5 + CONFIG += python +} else:packagesExist(python-3.6) { + # bionic + PKGCONFIG += python-3.6 + CONFIG += python +} else:packagesExist(python-3.7) { + # buster, eoan + PKGCONFIG += python-3.7 + CONFIG += python +} else { + message("Python development package not found. Building without python support.") + CONFIG -= python +} diff --git a/plugins/mock/httpdaemon.cpp b/plugins/mock/httpdaemon.cpp index b397388e..e5cea753 100644 --- a/plugins/mock/httpdaemon.cpp +++ b/plugins/mock/httpdaemon.cpp @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include HttpDaemon::HttpDaemon(Thing *thing, IntegrationPlugin *parent): @@ -75,7 +75,7 @@ void HttpDaemon::incomingConnection(qintptr socket) void HttpDaemon::actionExecuted(const ActionTypeId &actionTypeId) { - m_actionList.append(qMakePair(actionTypeId, QDateTime::currentDateTime())); + m_actionList.append(QPair(actionTypeId, QDateTime::currentDateTime())); } void HttpDaemon::readClient() @@ -89,20 +89,20 @@ void HttpDaemon::readClient() QTcpSocket* socket = (QTcpSocket*)sender(); if (socket->canReadLine()) { QByteArray data = socket->readLine(); - QStringList tokens = QString(data).split(QRegExp("[ \r\n][ \r\n]*")); + QStringList tokens = QString(data).split(QRegularExpression("[ \r\n][ \r\n]*")); QUrl url("http://foo.bar" + tokens[1]); QUrlQuery query(url); if (url.path() == "/setstate") { StateTypeId stateTypeId = StateTypeId(query.queryItems().first().first); QVariant stateValue = query.queryItems().first().second; if (stateTypeId == mockBoolStateTypeId || stateTypeId == mockBatteryCriticalStateTypeId) { - stateValue.convert(QVariant::Bool); + stateValue.convert(QMetaType::Bool); } else if (stateTypeId == mockIntStateTypeId) { - stateValue.convert(QVariant::Int); + stateValue.convert(QMetaType::Int); } else if (stateTypeId == mockSignalStrengthStateTypeId) { - stateValue.convert(QVariant::UInt); + stateValue.convert(QMetaType::UInt); } else if (stateTypeId == mockDoubleStateTypeId) { - stateValue.convert(QVariant::Double); + stateValue.convert(QMetaType::Double); } qCDebug(dcMock()) << "Setting state value" << stateValue; emit setState(stateTypeId, stateValue); diff --git a/plugins/mock/integrationpluginmock.cpp b/plugins/mock/integrationpluginmock.cpp index 02424271..aaa56608 100644 --- a/plugins/mock/integrationpluginmock.cpp +++ b/plugins/mock/integrationpluginmock.cpp @@ -336,8 +336,8 @@ void IntegrationPluginMock::startMonitoringAutoThings() ThingDescriptor mockDescriptor(autoMockThingClassId, "Mocked Thing (Auto created)"); ParamList params; - qsrand(QDateTime::currentMSecsSinceEpoch()); - int port = 4242 + (qrand() % 1000); + std::srand(QDateTime::currentMSecsSinceEpoch()); + int port = 4242 + (std::rand() % 1000); Param param(autoMockThingHttpportParamTypeId, port); params.append(param); mockDescriptor.setParams(params); diff --git a/server/main.cpp b/server/main.cpp index cca3f6ec..784f790c 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -76,7 +77,7 @@ int main(int argc, char *argv[]) // check if there are local translations if (!translator.load(QLocale::system(), application.applicationName(), "-", QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath(), ".qm")) if (!translator.load(QLocale::system(), application.applicationName(), "-", NymeaSettings::translationsPath(), ".qm")) - qWarning(dcTranslations()) << "Could not find nymead translations for" << QLocale::system().name() << endl << (QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath()) << endl << NymeaSettings::translationsPath(); + qWarning(dcTranslations()) << "Could not find nymead translations for" << QLocale::system().name() << '\n' << (QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath()) << '\n' << NymeaSettings::translationsPath(); @@ -168,8 +169,8 @@ int main(int argc, char *argv[]) bool enable = nymeaSettings.value(category, false).toBool(); if (enable && category.endsWith("debug")) { loggingRules << QString("%1=%2").arg(category).arg("true"); - loggingRules << QString("%1=%2").arg(QString(category).replace(QRegExp("debug$"), "info")).arg("true"); - loggingRules << QString("%1=%2").arg(QString(category).replace(QRegExp("debug$"), "warning")).arg("true"); + loggingRules << QString("%1=%2").arg(QString(category).replace(QRegularExpression("debug$"), "info")).arg("true"); + loggingRules << QString("%1=%2").arg(QString(category).replace(QRegularExpression("debug$"), "warning")).arg("true"); } else { loggingRules << QString("%1=%2").arg(category).arg(nymeaSettings.value(category, "false").toString()); } @@ -181,11 +182,11 @@ int main(int argc, char *argv[]) bool enable = true; bool isWarning = debugArea.endsWith("Warnings"); bool isInfo = debugArea.endsWith("Info"); - if (QRegExp("^No[A-Z]").exactMatch(debugArea)) { - debugArea.remove(QRegExp("^No")); + if (QRegularExpression("^No[A-Z]").match(debugArea).hasMatch()) { + debugArea.remove(QRegularExpression("^No")); enable = false; } - debugArea.remove(QRegExp("(Warnings|Info)$")); + debugArea.remove(QRegularExpression("(Warnings|Info)$")); if (enable && !isWarning && !isInfo) { loggingRules.append(QString("%1.%2=%3").arg(debugArea).arg("debug").arg("true")); loggingRules.append(QString("%1.%2=%3").arg(debugArea).arg("info").arg("true")); @@ -195,6 +196,7 @@ int main(int argc, char *argv[]) } } + // Finally set the rules for the logging QLoggingCategory::setFilterRules(loggingRules.join('\n')); @@ -228,6 +230,9 @@ int main(int argc, char *argv[]) } qCInfo(dcApplication()) << "Started:" << arguments.takeFirst(); qCInfo(dcApplication()) << "Parameters:" << arguments.join(' '); + qCInfo(dcApplication()) << "Built with Qt:" << QT_VERSION_STR; + qCInfo(dcApplication()) << "Run with Qt:" << qVersion(); + // If running in a snappy environment, print out some details about it. if (!qgetenv("SNAP").isEmpty()) { diff --git a/server/qtservice/qtservice.cpp b/server/qtservice/qtservice.cpp index 9eba70ea..a131e950 100644 --- a/server/qtservice/qtservice.cpp +++ b/server/qtservice/qtservice.cpp @@ -649,7 +649,7 @@ QtServiceBase::QtServiceBase(int argc, char **argv, const QString &name) d_ptr = new QtServiceBasePrivate(nm); d_ptr->q_ptr = this; - d_ptr->serviceFlags = 0; + d_ptr->serviceFlags = ServiceFlag::Default; d_ptr->sysd = 0; for (int i = 0; i < argc; ++i) d_ptr->args.append(QString::fromLocal8Bit(argv[i])); diff --git a/server/server.pro b/server/server.pro index d394638f..08ba9f7a 100644 --- a/server/server.pro +++ b/server/server.pro @@ -8,7 +8,13 @@ INCLUDEPATH += ../libnymea ../libnymea-core $$top_builddir target.path = $$[QT_INSTALL_PREFIX]/bin INSTALLS += target -QT += sql xml websockets bluetooth dbus network +QT += sql websockets bluetooth dbus network + +greaterThan(QT_MAJOR_VERSION, 5) { + QT *= core5compat +} else { + QT *= xml +} CONFIG += link_pkgconfig PKGCONFIG += nymea-zigbee nymea-mqtt diff --git a/tests/auto/autotests.pri b/tests/auto/autotests.pri index 5cd4deac..fed7d80d 100644 --- a/tests/auto/autotests.pri +++ b/tests/auto/autotests.pri @@ -2,9 +2,30 @@ QT += dbus testlib network sql websockets CONFIG += testcase CONFIG += link_pkgconfig -packagesExist(Qt5SerialBus) { - PKGCONFIG += Qt5SerialBus - DEFINES += WITH_QTSERIALBUS +greaterThan(QT_MAJOR_VERSION, 5) { + qtHaveModule(serialbus) { + message("Building with QtSerialBus support.") + QT *= serialbus + DEFINES += WITH_QTSERIALBUS + } else { + message("QtSerialBus package not found. Building without QtSerialBus support.") + } + + # Separate module in Qt6 + QT *= concurrent +} else { + packagesExist(Qt5SerialBus) { + message("Building with QtSerialBus support.") + PKGCONFIG += Qt5SerialBus + DEFINES += WITH_QTSERIALBUS + } else { + message("Qt5SerialBus package not found. Building without QtSerialBus support.") + } +} + +CONFIG(python) { + message("Building tests with Python plugin support") + DEFINES += WITH_PYTHON } PKGCONFIG += nymea-zigbee nymea-networkmanager nymea-mqtt diff --git a/tests/auto/integrations/testintegrations.cpp b/tests/auto/integrations/testintegrations.cpp index 4b1835f0..0284be3c 100644 --- a/tests/auto/integrations/testintegrations.cpp +++ b/tests/auto/integrations/testintegrations.cpp @@ -53,7 +53,6 @@ private: } private slots: - void initTestCase(); void getPlugins(); @@ -297,9 +296,13 @@ void TestIntegrations::getThingClasses_data() QTest::addColumn("vendorId"); QTest::addColumn>("thingClassIds"); QTest::addColumn("resultCount"); - +#ifdef WITH_PYTHON QTest::newRow("vendor nymea") << nymeaVendorId << QList() << 17; QTest::newRow("no filter") << VendorId() << QList() << 17; +#else + QTest::newRow("vendor nymea") << nymeaVendorId << QList() << 14; + QTest::newRow("no filter") << VendorId() << QList() << 14; +#endif QTest::newRow("invalid vendor") << VendorId("93e7d361-8025-4354-b17e-b68406c800bc") << QList() << 0; QTest::newRow("mockThingClassId") << VendorId() << (QList() << mockThingClassId) << 1; QTest::newRow("invalid thingClassId") << VendorId() << (QList() << ThingClassId("6c78ec28-09b6-476d-ac27-1d6966a45c57")) << 0; @@ -585,7 +588,7 @@ void TestIntegrations::getThing() params.insert("thingId", thingId); QVariant response = injectAndWait("Integrations.GetThings", params); -// qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(response).toJson()); + // qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(response).toJson()); if (expectedError == Thing::ThingErrorNoError) { QVariantList things = response.toMap().value("params").toMap().value("things").toList(); @@ -939,9 +942,9 @@ void TestIntegrations::parentChildThings() } } QVERIFY2(!childId.isNull(), QString("Could not find child:\nParent ID:%1\nResponse:%2") - .arg(parentId.toString()) - .arg(qUtf8Printable(QJsonDocument::fromVariant(response).toJson())) - .toUtf8()); + .arg(parentId.toString()) + .arg(qUtf8Printable(QJsonDocument::fromVariant(response).toJson())) + .toUtf8()); // Try to remove the child params.clear(); @@ -992,7 +995,7 @@ void TestIntegrations::getActionTypes_data() QTest::addColumn >("actionTypeTestData"); QTest::newRow("valid thingClass") << mockThingClassId - << (QList() << mockIntWithLimitsActionTypeId << mockAsyncActionTypeId << mockAsyncFailingActionTypeId << mockFailingActionTypeId << mockWithoutParamsActionTypeId << mockPowerActionTypeId << mockWithoutParamsActionTypeId << mockBatteryLevelActionTypeId << mockSignalStrengthActionTypeId << mockUpdateStatusActionTypeId << mockPerformUpdateActionTypeId << mockPressButtonActionTypeId); + << (QList() << mockIntWithLimitsActionTypeId << mockAsyncActionTypeId << mockAsyncFailingActionTypeId << mockFailingActionTypeId << mockWithoutParamsActionTypeId << mockPowerActionTypeId << mockWithoutParamsActionTypeId << mockBatteryLevelActionTypeId << mockSignalStrengthActionTypeId << mockUpdateStatusActionTypeId << mockPerformUpdateActionTypeId << mockPressButtonActionTypeId); QTest::newRow("invalid thingClass") << ThingClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << QList(); } @@ -1726,7 +1729,7 @@ void TestIntegrations::removeThing_data() QTest::newRow("Existing thing") << ThingId(m_mockThingId) << Thing::ThingErrorNoError; QTest::newRow("Not existing thing") << ThingId::createThingId() << Thing::ThingErrorThingNotFound; -// QTest::newRow("Auto device") << m_mockThingAutoId << Thing::ThingErrorCreationMethodNotSupported; + // QTest::newRow("Auto device") << m_mockThingAutoId << Thing::ThingErrorCreationMethodNotSupported; } void TestIntegrations::removeThing() @@ -2076,7 +2079,7 @@ void TestIntegrations::executeAction() if (error == Thing::ThingErrorNoError) { QVERIFY2(actionTypeId == ActionTypeId(data), QString("ActionTypeId mismatch. Got %1, Expected: %2") - .arg(ActionTypeId(data).toString()).arg(actionTypeId.toString()).toLatin1().data()); + .arg(ActionTypeId(data).toString()).arg(actionTypeId.toString()).toLatin1().data()); } else { QVERIFY2(data.length() == 0, QString("Data is %1, should be empty.").arg(QString(data)).toLatin1().data()); } diff --git a/tests/auto/jsonrpc/testjsonrpc.cpp b/tests/auto/jsonrpc/testjsonrpc.cpp index 3a5bad65..88bcb4af 100644 --- a/tests/auto/jsonrpc/testjsonrpc.cpp +++ b/tests/auto/jsonrpc/testjsonrpc.cpp @@ -127,19 +127,19 @@ private: QStringList TestJSONRPC::extractRefs(const QVariant &variant) { - if (variant.canConvert(QVariant::String)) { + if (variant.canConvert(QMetaType::QString)) { if (variant.toString().startsWith("$ref")) { return QStringList() << variant.toString(); } } - if (variant.canConvert(QVariant::List)) { + if (variant.canConvert(QMetaType::QVariantList)) { QStringList refs; foreach (const QVariant tmp, variant.toList()) { refs << extractRefs(tmp); } return refs; } - if (variant.canConvert(QVariant::Map)) { + if (variant.canConvert(QMetaType::QVariantMap)) { QStringList refs; foreach (const QVariant tmp, variant.toMap()) { refs << extractRefs(tmp); @@ -652,18 +652,18 @@ void TestJSONRPC::testBasicCall() void TestJSONRPC::introspect() { QVariant response = injectAndWait("JSONRPC.Introspect"); - QVariantMap methods = response.toMap().value("params").toMap().value("methods").toMap(); - QVariantMap notifications = response.toMap().value("params").toMap().value("notifications").toMap(); - QVariantMap enums = response.toMap().value("params").toMap().value("enums").toMap(); - QVariantMap flags = response.toMap().value("params").toMap().value("flags").toMap(); - QVariantMap types = response.toMap().value("params").toMap().value("types").toMap(); + QMultiMap methods = QMultiMap(response.toMap().value("params").toMap().value("methods").toMap()); + QMultiMap notifications = QMultiMap(response.toMap().value("params").toMap().value("notifications").toMap()); + QMultiMap enums = QMultiMap(response.toMap().value("params").toMap().value("enums").toMap()); + QMultiMap flags = QMultiMap(response.toMap().value("params").toMap().value("flags").toMap()); + QMultiMap types = QMultiMap(response.toMap().value("params").toMap().value("types").toMap()); QVERIFY2(methods.count() > 0, "No methods in Introspect response!"); QVERIFY2(notifications.count() > 0, "No notifications in Introspect response!"); QVERIFY2(types.count() > 0, "No types in Introspect response!"); // Make sure all $ref: pointers have their according type defined - QVariantMap allItems = methods.unite(notifications).unite(types); + QMultiMap allItems = methods.unite(notifications).unite(types); foreach (const QVariant &item, allItems) { foreach (const QString &ref, extractRefs(item)) { QString typeId = ref; diff --git a/tests/auto/mqttbroker/mqttbroker.pro b/tests/auto/mqttbroker/mqttbroker.pro index 8937d736..5e19f1eb 100644 --- a/tests/auto/mqttbroker/mqttbroker.pro +++ b/tests/auto/mqttbroker/mqttbroker.pro @@ -1,7 +1,12 @@ include(../../../nymea.pri) include(../autotests.pri) -QT += xml +greaterThan(QT_MAJOR_VERSION, 5) { + QT *= core5compat +} else { + QT *= xml +} + PKGCONFIG += nymea-mqtt TARGET = nymeatestmqttbroker diff --git a/tests/auto/pythonplugins/testpythonplugins.cpp b/tests/auto/pythonplugins/testpythonplugins.cpp index e2b01471..f0b653fc 100644 --- a/tests/auto/pythonplugins/testpythonplugins.cpp +++ b/tests/auto/pythonplugins/testpythonplugins.cpp @@ -30,7 +30,8 @@ #include "nymeatestbase.h" -#include "integrations/thing.h" +#include +#include ThingClassId pyMockThingClassId = ThingClassId("1761c256-99b1-41bd-988a-a76087f6a4f1"); ThingClassId pyMockDiscoveryPairingThingClassId = ThingClassId("248c5046-847b-44d0-ab7c-684ff79197dc"); @@ -49,16 +50,19 @@ private: private slots: +#ifdef WITH_PYTHON void initTestCase(); void testRestartServer(); void setupAndRemoveThing(); void testDiscoverPairAndRemoveThing(); - +#endif }; +#ifdef WITH_PYTHON + void TestPythonPlugins::testRestartServer() { NymeaTestBase::restartServer(); @@ -141,6 +145,7 @@ void TestPythonPlugins::testDiscoverPairAndRemoveThing() response = injectAndWait("Integrations.RemoveThing", params); verifyThingError(response, Thing::ThingErrorNoError); } +#endif #include "testpythonplugins.moc" QTEST_MAIN(TestPythonPlugins) diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index 72a57a28..2fce4179 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -411,9 +411,9 @@ void TestRules::initTestCase() "Tests.debug=true\n" "RuleEngine.debug=true\n" "RuleEngineDebug.debug=true\n" - "JsonRpc.debug=true\n" + "JsonRpc.debug=false\n" "Mock.*=true\n" - "LogEngine.debug=true\n" + "LogEngine.debug=false\n" ); } @@ -666,14 +666,18 @@ void TestRules::addRemoveRules() } QVariantList replyActions = rule.value("actions").toList(); - QVERIFY2(actions == replyActions, + QVERIFY2(QJsonDocument::fromVariant(actions) == QJsonDocument::fromVariant(replyActions), QString("Actions don't match.\nExpected: %1\nGot: %2") .arg(QString(QJsonDocument::fromVariant(actions).toJson())) .arg(QString(QJsonDocument::fromVariant(replyActions).toJson())) .toUtf8()); QVariantList replyExitActions = rule.value("exitActions").toList(); - QVERIFY2(exitActions == replyExitActions, "ExitActions don't match"); + QVERIFY2(QJsonDocument::fromVariant(exitActions) == QJsonDocument::fromVariant(replyExitActions), + QString("Actions don't match.\nExpected: %1\nGot: %2") + .arg(QString(QJsonDocument::fromVariant(exitActions).toJson())) + .arg(QString(QJsonDocument::fromVariant(replyExitActions).toJson())) + .toUtf8()); params.clear(); params.insert("ruleId", newRuleId); @@ -995,14 +999,14 @@ void TestRules::editRules() } QVariantList replyActions = rule.value("actions").toList(); - QVERIFY2(actions == replyActions, + QVERIFY2(QJsonDocument::fromVariant(actions) == QJsonDocument::fromVariant(replyActions), QString("Actions don't match.\nExpected: %1\nGot: %2") .arg(QString(QJsonDocument::fromVariant(actions).toJson())) .arg(QString(QJsonDocument::fromVariant(replyActions).toJson())) .toUtf8()); QVariantList replyExitActions = rule.value("exitActions").toList(); - QVERIFY2(exitActions == replyExitActions, + QVERIFY2(QJsonDocument::fromVariant(exitActions) == QJsonDocument::fromVariant(replyExitActions), QString("Actions don't match.\nExpected: %1\nGot: %2") .arg(QString(QJsonDocument::fromVariant(exitActions).toJson())) .arg(QString(QJsonDocument::fromVariant(replyExitActions).toJson())) @@ -1330,13 +1334,14 @@ void TestRules::loadStoreConfig() qCDebug(dcTests()) << "Getting rules"; response = injectAndWait("Rules.GetRules"); QVariantList rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList(); - qDebug() << "GetRules before server shutdown:" << response; + qCDebug(dcTests()) << "GetRules before server shutdown:" << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented)); qCDebug(dcTests()) << "Restarting server"; restartServer(); response = injectAndWait("Rules.GetRules"); rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList(); + qCDebug(dcTests()) << "GetRules after server shutdown:" << qUtf8Printable(QJsonDocument::fromVariant(rules).toJson(QJsonDocument::Indented)); QVERIFY2(rules.count() == 4, "There should be exactly four rule."); @@ -1358,13 +1363,15 @@ void TestRules::loadStoreConfig() QVariantMap rule1 = response.toMap().value("params").toMap().value("rule").toMap(); + qCDebug(dcTests()) << "Rule 1 details:" << qUtf8Printable(QJsonDocument::fromVariant(rule1).toJson(QJsonDocument::Indented)); + QVariantList eventDescriptors = rule1.value("eventDescriptors").toList(); QVERIFY2(eventDescriptors.count() == 2, "There should be exactly 2 eventDescriptors"); foreach (const QVariant &expectedEventDescriptorVariant, eventDescriptorList) { bool found = false; foreach (const QVariant &replyEventDescriptorVariant, eventDescriptors) { - if (expectedEventDescriptorVariant.toMap().value("eventTypeId") == replyEventDescriptorVariant.toMap().value("eventTypeId") && - expectedEventDescriptorVariant.toMap().value("thingId") == replyEventDescriptorVariant.toMap().value("thingId")) { + if (expectedEventDescriptorVariant.toMap().value("eventTypeId").toUuid() == replyEventDescriptorVariant.toMap().value("eventTypeId").toUuid() && + expectedEventDescriptorVariant.toMap().value("thingId").toUuid() == replyEventDescriptorVariant.toMap().value("thingId").toUuid()) { found = true; QVariantMap stringifiedExpectedEventDescriptorVariant = QJsonDocument::fromVariant(expectedEventDescriptorVariant).toVariant().toMap(); QVERIFY2(replyEventDescriptorVariant == stringifiedExpectedEventDescriptorVariant, @@ -1401,8 +1408,8 @@ void TestRules::loadStoreConfig() foreach (const QVariant &actionVariant, actions) { bool found = false; foreach (const QVariant &replyActionVariant, replyActions) { - if (actionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") && - actionVariant.toMap().value("thingId") == replyActionVariant.toMap().value("thingId")) { + if (actionVariant.toMap().value("actionTypeId").toUuid() == replyActionVariant.toMap().value("actionTypeId").toUuid() && + actionVariant.toMap().value("thingId").toUuid() == replyActionVariant.toMap().value("thingId").toUuid()) { found = true; // Check rule action params QVariantList actionParams = actionVariant.toMap().value("ruleActionParams").toList(); @@ -1453,8 +1460,8 @@ void TestRules::loadStoreConfig() foreach (const QVariant &actionVariant, actions2) { bool found = false; foreach (const QVariant &replyActionVariant, replyActions2) { - if (actionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") && - actionVariant.toMap().value("thingId") == replyActionVariant.toMap().value("thingId")) { + if (actionVariant.toMap().value("actionTypeId").toUuid() == replyActionVariant.toMap().value("actionTypeId").toUuid() && + actionVariant.toMap().value("thingId").toUuid() == replyActionVariant.toMap().value("thingId").toUuid()) { found = true; // Check rule action params QVariantList actionParams = actionVariant.toMap().value("ruleActionParams").toList(); @@ -1473,8 +1480,8 @@ void TestRules::loadStoreConfig() foreach (const QVariant &exitActionVariant, replyExitActions2) { bool found = false; foreach (const QVariant &replyActionVariant, replyExitActions2) { - if (exitActionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") && - exitActionVariant.toMap().value("thingId") == replyActionVariant.toMap().value("thingId")) { + if (exitActionVariant.toMap().value("actionTypeId").toUuid() == replyActionVariant.toMap().value("actionTypeId").toUuid() && + exitActionVariant.toMap().value("thingId").toUuid() == replyActionVariant.toMap().value("thingId").toUuid()) { found = true; // Check rule action params QVariantList actionParams = exitActionVariant.toMap().value("ruleActionParams").toList(); @@ -1512,8 +1519,8 @@ void TestRules::loadStoreConfig() foreach (const QVariant &actionVariant, actions3) { bool found = false; foreach (const QVariant &replyActionVariant, replyActions3) { - if (actionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") && - actionVariant.toMap().value("thingId") == replyActionVariant.toMap().value("thingId")) { + if (actionVariant.toMap().value("actionTypeId").toUuid() == replyActionVariant.toMap().value("actionTypeId").toUuid() && + actionVariant.toMap().value("thingId").toUuid() == replyActionVariant.toMap().value("thingId").toUuid()) { found = true; // Check rule action params QVariantList actionParams = actionVariant.toMap().value("ruleActionParams").toList(); @@ -2015,7 +2022,7 @@ void TestRules::testChildEvaluator() setWritableStateValue(thingId, StateTypeId(displayPinMockAllowedValuesStateTypeId.toString()), QVariant("String value 1")); setWritableStateValue(thingId, StateTypeId(displayPinMockColorStateTypeId.toString()), QVariant("#000000")); - qCDebug(dcTests()) << "Adding rule"; + qCDebug(dcTests()) << "Adding rule" << qUtf8Printable(QJsonDocument::fromVariant(ruleMap).toJson(QJsonDocument::Indented)); // Add rule QVariant response = injectAndWait("Rules.AddRule", ruleMap); @@ -2736,7 +2743,7 @@ void TestRules::testInterfaceBasedEventRule() addRuleParams.insert("actions", QVariantList() << powerAction); addRuleParams.insert("eventDescriptors", QVariantList() << lowBatteryEvent); - qDebug(dcTests) << "Inserting rule"; + qCDebug(dcTests()) << "Inserting rule"; QVariant response = injectAndWait("Rules.AddRule", addRuleParams); QCOMPARE(response.toMap().value("status").toString(), QString("success")); @@ -2745,7 +2752,7 @@ void TestRules::testInterfaceBasedEventRule() QVariantMap getRuleParams; getRuleParams.insert("ruleId", response.toMap().value("params").toMap().value("ruleId")); - qDebug(dcTests) << "Getting rule details"; + qCDebug(dcTests()) << "Getting rule details"; response = injectAndWait("Rules.GetRuleDetails", getRuleParams); @@ -2759,39 +2766,47 @@ void TestRules::testInterfaceBasedEventRule() QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("ruleActionParams").toList().first().toMap().value("paramName").toString(), QString("power")); QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("ruleActionParams").toList().first().toMap().value("value").toString(), QString("true")); - qDebug(dcTests) << "Clearing action history"; + qCDebug(dcTests()) << "Clearing action history"; // Change the state to true, action should trigger spy.clear(); request = QNetworkRequest(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockThing1Port))); reply = nam.get(request); - qDebug(dcTests) << "Changing battery state -> true"; + qCDebug(dcTests()) << "Changing battery state -> true"; spy.wait(); spy.clear(); + QVERIFY2(reply->isFinished(), "Reply is not finished"); + reply->deleteLater(); + request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockThing1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(true))); reply = nam.get(request); spy.wait(); + QVERIFY2(reply->isFinished(), "Reply is not finished"); QCOMPARE(spy.count(), 1); reply->deleteLater(); verifyRuleExecuted(mockPowerActionTypeId); - qDebug(dcTests) << "Clearing action history"; + qCDebug(dcTests()) << "Clearing action history"; // Change the state to false, action should not trigger spy.clear(); request = QNetworkRequest(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockThing1Port))); reply = nam.get(request); - qDebug(dcTests) << "Changing battery state -> false"; + qCDebug(dcTests()) << "Changing battery state -> false"; spy.wait(); spy.clear(); + QVERIFY2(reply->isFinished(), "Reply is not finished"); + reply->deleteLater(); + request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockThing1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(false))); reply = nam.get(request); spy.wait(); - QCOMPARE(spy.count(), 1); reply->deleteLater(); + QCOMPARE(spy.count(), 1); + verifyRuleNotExecuted(); } diff --git a/tests/auto/scripts/testscripts.cpp b/tests/auto/scripts/testscripts.cpp index f8c240e6..50a35cbb 100644 --- a/tests/auto/scripts/testscripts.cpp +++ b/tests/auto/scripts/testscripts.cpp @@ -31,7 +31,6 @@ #include "nymeatestbase.h" #include "testhelper.h" -#include "nymeasettings.h" #include "nymeacore.h" #include "scriptengine/scriptengine.h" @@ -108,17 +107,31 @@ void TestScripts::init() void TestScripts::testScriptEventById() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingEvent {\n" - " thingId: \"%1\"\n" - " eventTypeId: \"%2\"\n" - " onTriggered: {\n" - " TestHelper.logEvent(thingId, eventTypeId, params);\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg(mockEvent2EventTypeId.toString()); + "import nymea 1.0\n" + "Item {\n" + " ThingEvent {\n" + " thingId: \"%1\"\n" + " eventTypeId: \"%2\"\n" + " onTriggered: (params) => {\n" + " TestHelper.logEvent(thingId, eventTypeId, params);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), mockEvent2EventTypeId.toString()); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingEvent {\n" + " thingId: \"%1\"\n" + " eventTypeId: \"%2\"\n" + " onTriggered: {\n" + " TestHelper.logEvent(thingId, eventTypeId, params);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg(mockEvent2EventTypeId.toString()); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestEvent", script.toUtf8()); @@ -130,10 +143,10 @@ void TestScripts::testScriptEventById() Thing* thing = NymeaCore::instance()->thingManager()->findConfiguredThing(m_mockThingId); int port = thing->paramValue(mockThingHttpportParamTypeId).toInt(); QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2&%3=%4") - .arg(port) - .arg(mockEvent2EventTypeId.toString()) - .arg(mockEvent2EventIntParamParamTypeId.toString()) - .arg(23))); + .arg(port) + .arg(mockEvent2EventTypeId.toString()) + .arg(mockEvent2EventIntParamParamTypeId.toString()) + .arg(23))); QNetworkAccessManager nam; QNetworkReply *r = nam.get(request); connect(r, &QNetworkReply::finished, r, &QNetworkReply::deleteLater); @@ -144,27 +157,40 @@ void TestScripts::testScriptEventById() QCOMPARE(spy.first().at(0).value(), m_mockThingId); QCOMPARE(EventTypeId(spy.first().at(1).toUuid()), mockEvent2EventTypeId); QVariantMap expectedParams; - expectedParams.insert(mockEvent2EventIntParamParamTypeId.toString().remove(QRegExp("[{}]")), 23); + expectedParams.insert(mockEvent2EventIntParamParamTypeId.toString().remove(QRegularExpression("[{}]")), 23); expectedParams.insert("intParam", 23); QVERIFY2(spy.first().at(2).toMap() == expectedParams, QString("Params not matching.\nExpected: %1\nGot: %2") - .arg(QString(QJsonDocument::fromVariant(expectedParams).toJson(QJsonDocument::Indented))) - .arg(QString(QJsonDocument::fromVariant(spy.first().at(2).toMap()).toJson(QJsonDocument::Indented))) - .toUtf8()); + .arg(QString(QJsonDocument::fromVariant(expectedParams).toJson(QJsonDocument::Indented)), + QString(QJsonDocument::fromVariant(spy.first().at(2).toMap()).toJson(QJsonDocument::Indented))).toUtf8()); } void TestScripts::testScriptEventByName() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingEvent {\n" - " thingId: \"%1\"\n" - " eventName: \"%2\"\n" - " onTriggered: {\n" - " TestHelper.logEvent(thingId, eventName, params);\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg("event2"); + "import nymea 1.0\n" + "Item {\n" + " ThingEvent {\n" + " thingId: \"%1\"\n" + " eventName: \"%2\"\n" + " onTriggered: (params) => {\n" + " TestHelper.logEvent(thingId, eventName, params);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), "event2"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingEvent {\n" + " thingId: \"%1\"\n" + " eventName: \"%2\"\n" + " onTriggered: {\n" + " TestHelper.logEvent(thingId, eventName, params);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg("event2"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestEvent", script.toUtf8()); @@ -176,10 +202,10 @@ void TestScripts::testScriptEventByName() Thing* thing = NymeaCore::instance()->thingManager()->findConfiguredThing(m_mockThingId); int port = thing->paramValue(mockThingHttpportParamTypeId).toInt(); QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2&%3=%4") - .arg(port) - .arg(mockEvent2EventTypeId.toString()) - .arg(mockEvent2EventIntParamParamTypeId.toString()) - .arg(10))); + .arg(port) + .arg(mockEvent2EventTypeId.toString()) + .arg(mockEvent2EventIntParamParamTypeId.toString()) + .arg(10))); QNetworkAccessManager nam; QNetworkReply *r = nam.get(request); connect(r, &QNetworkReply::finished, r, &QNetworkReply::deleteLater); @@ -190,25 +216,38 @@ void TestScripts::testScriptEventByName() QCOMPARE(spy.first().at(0).value(), m_mockThingId); QCOMPARE(spy.first().at(1).toString(), QString("event2")); QVariantMap expectedParams; - expectedParams.insert(mockEvent2EventIntParamParamTypeId.toString().remove(QRegExp("[{}]")), 10); + expectedParams.insert(mockEvent2EventIntParamParamTypeId.toString().remove(QRegularExpression("[{}]")), 10); expectedParams.insert("intParam", 10); QCOMPARE(spy.first().at(2).toMap(), expectedParams); } void TestScripts::testReadScriptStateById() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingState {\n" - " thingId: \"%1\"\n" - " stateTypeId: \"%2\"\n" - " onValueChanged: {\n" - " TestHelper.logStateChange(thingId, stateTypeId, value);\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg(mockPowerStateTypeId.toString()); - + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " thingId: \"%1\"\n" + " stateTypeId: \"%2\"\n" + " onValueChanged: () => {\n" + " TestHelper.logStateChange(thingId, stateTypeId, value);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), mockPowerStateTypeId.toString()); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " thingId: \"%1\"\n" + " stateTypeId: \"%2\"\n" + " onValueChanged: {\n" + " TestHelper.logStateChange(thingId, stateTypeId, value);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg(mockPowerStateTypeId.toString()); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestState", script.toUtf8()); QCOMPARE(reply.scriptError, ScriptEngine::ScriptErrorNoError); @@ -230,18 +269,31 @@ void TestScripts::testReadScriptStateById() void TestScripts::testReadScriptStateByNyme() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingState {\n" - " thingId: \"%1\"\n" - " stateName: \"%2\"\n" - " onValueChanged: {\n" - " TestHelper.logStateChange(thingId, stateName, value);\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg("power"); - + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " thingId: \"%1\"\n" + " stateName: \"%2\"\n" + " onValueChanged: () => {\n" + " TestHelper.logStateChange(thingId, stateName, value);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " thingId: \"%1\"\n" + " stateName: \"%2\"\n" + " onValueChanged: {\n" + " TestHelper.logStateChange(thingId, stateName, value);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestState", script.toUtf8()); QCOMPARE(reply.scriptError, ScriptEngine::ScriptErrorNoError); @@ -263,22 +315,39 @@ void TestScripts::testReadScriptStateByNyme() void TestScripts::testWriteScriptStateById() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingState {\n" - " id: thingState\n" - " thingId: \"%1\"\n" - " stateTypeId: \"%2\"\n" - " }\n" - " Connections {\n" - " target: TestHelper\n" - " onSetState: {\n" - " thingState.value = value\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg(mockPowerStateTypeId.toString()); - + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " id: thingState\n" + " thingId: \"%1\"\n" + " stateTypeId: \"%2\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " function onSetState(value) {\n" + " thingState.value = value\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), mockPowerStateTypeId.toString()); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " id: thingState\n" + " thingId: \"%1\"\n" + " stateTypeId: \"%2\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onSetState: {\n" + " thingState.value = value\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg(mockPowerStateTypeId.toString()); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestState", script.toUtf8()); QCOMPARE(reply.scriptError, ScriptEngine::ScriptErrorNoError); @@ -297,21 +366,39 @@ void TestScripts::testWriteScriptStateById() void TestScripts::testWriteScriptStateByName() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingState {\n" - " id: thingState\n" - " thingId: \"%1\"\n" - " stateName: \"%2\"\n" - " }\n" - " Connections {\n" - " target: TestHelper\n" - " onSetState: {\n" - " thingState.value = value\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg("power"); + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " id: thingState\n" + " thingId: \"%1\"\n" + " stateName: \"%2\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " function onSetState(value) {\n" + " thingState.value = value\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingState {\n" + " id: thingState\n" + " thingId: \"%1\"\n" + " stateName: \"%2\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onSetState: {\n" + " thingState.value = value\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestState", script.toUtf8()); @@ -331,24 +418,45 @@ void TestScripts::testWriteScriptStateByName() void TestScripts::testScriptActionById() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingAction {\n" - " id: thingAction\n" - " thingId: \"%1\"\n" - " actionTypeId: \"%2\"\n" - " onExecuted: {\n" - " TestHelper.logActionExecuted(\"%1\", \"%2\", params, status, triggeredBy)\n" - " }\n" - " }\n" - " Connections {\n" - " target: TestHelper\n" - " onExecuteAction: {\n" - " thingAction.execute(params)\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg(mockPowerActionTypeId.toString()); + "import nymea 1.0\n" + "Item {\n" + " ThingAction {\n" + " id: thingAction\n" + " thingId: \"%1\"\n" + " actionTypeId: \"%2\"\n" + " onExecuted: (params, status, triggeredBy) => {\n" + " TestHelper.logActionExecuted(\"%1\", \"%2\", params, status, triggeredBy)\n" + " }\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " function onExecuteAction(params) {\n" + " thingAction.execute(params)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), mockPowerActionTypeId.toString()); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingAction {\n" + " id: thingAction\n" + " thingId: \"%1\"\n" + " actionTypeId: \"%2\"\n" + " onExecuted: {\n" + " TestHelper.logActionExecuted(\"%1\", \"%2\", params, status, triggeredBy)\n" + " }\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onExecuteAction: {\n" + " thingAction.execute(params)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg(mockPowerActionTypeId.toString()); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestAction", script.toUtf8()); @@ -371,31 +479,52 @@ void TestScripts::testScriptActionById() QCOMPARE(actionExecutedSpy.count(), 1); QCOMPARE(actionExecutedSpy.first().at(0).value(), m_mockThingId); QCOMPARE(ActionTypeId(actionExecutedSpy.first().at(1).toString()), mockPowerActionTypeId); - QCOMPARE(actionExecutedSpy.first().at(2).toMap().value(mockPowerActionTypeId.toString().remove(QRegExp("[{}]"))).toBool(), true); + QCOMPARE(actionExecutedSpy.first().at(2).toMap().value(mockPowerActionTypeId.toString().remove(QRegularExpression("[{}]"))).toBool(), true); QCOMPARE(actionExecutedSpy.first().at(3).value(), Thing::ThingErrorNoError); QCOMPARE(actionExecutedSpy.first().at(4).value(), Action::TriggeredByScript); } void TestScripts::testScriptActionByName() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " ThingAction {\n" - " id: thingAction\n" - " thingId: \"%1\"\n" - " actionName: \"%2\"\n" - " onExecuted: {\n" - " TestHelper.logActionExecuted(\"%1\", \"%2\", params, status, triggeredBy)\n" - " }\n" - " }\n" - " Connections {\n" - " target: TestHelper\n" - " onExecuteAction: {\n" - " thingAction.execute(params)\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg("power"); + "import nymea 1.0\n" + "Item {\n" + " ThingAction {\n" + " id: thingAction\n" + " thingId: \"%1\"\n" + " actionName: \"%2\"\n" + " onExecuted: (params, status, triggeredBy) => {\n" + " TestHelper.logActionExecuted(\"%1\", \"%2\", params, status, triggeredBy)\n" + " }\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " function onExecuteAction(params) {\n" + " thingAction.execute(params)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " ThingAction {\n" + " id: thingAction\n" + " thingId: \"%1\"\n" + " actionName: \"%2\"\n" + " onExecuted: {\n" + " TestHelper.logActionExecuted(\"%1\", \"%2\", params, status, triggeredBy)\n" + " }\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onExecuteAction: {\n" + " thingAction.execute(params)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestAction", script.toUtf8()); @@ -439,17 +568,31 @@ void TestScripts::testScriptAlarm() void TestScripts::testInterfaceEvent() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " InterfaceEvent {\n" - " interfaceName: \"%1\"\n" - " eventName: \"%2\"\n" - " onTriggered: {\n" - " TestHelper.logEvent(thingId, eventName, params);\n" - " }\n" - " }\n" - "}\n").arg("button").arg("pressed"); + "import nymea 1.0\n" + "Item {\n" + " InterfaceEvent {\n" + " interfaceName: \"%1\"\n" + " eventName: \"%2\"\n" + " onTriggered: (thingId, params) => {\n" + " TestHelper.logEvent(thingId, eventName, params);\n" + " }\n" + " }\n" + "}\n").arg("button", "pressed"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " InterfaceEvent {\n" + " interfaceName: \"%1\"\n" + " eventName: \"%2\"\n" + " onTriggered: {\n" + " TestHelper.logEvent(thingId, eventName, params);\n" + " }\n" + " }\n" + "}\n").arg("button").arg("pressed"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestEvent", script.toUtf8()); @@ -461,10 +604,10 @@ void TestScripts::testInterfaceEvent() Thing* thing = NymeaCore::instance()->thingManager()->findConfiguredThing(m_mockThingId); int port = thing->paramValue(mockThingHttpportParamTypeId).toInt(); QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2&%3=%4") - .arg(port) - .arg(mockPressedEventTypeId.toString()) - .arg(mockPressedEventButtonNameParamTypeId.toString()) - .arg("xxx"))); + .arg(port) + .arg(mockPressedEventTypeId.toString()) + .arg(mockPressedEventButtonNameParamTypeId.toString()) + .arg("xxx"))); QNetworkAccessManager nam; QNetworkReply *r = nam.get(request); connect(r, &QNetworkReply::finished, r, &QNetworkReply::deleteLater); @@ -475,25 +618,38 @@ void TestScripts::testInterfaceEvent() QCOMPARE(spy.first().at(0).value(), m_mockThingId); QCOMPARE(spy.first().at(1).toString(), QString("pressed")); QVariantMap expectedParams; - expectedParams.insert(mockPressedEventButtonNameParamTypeId.toString().remove(QRegExp("[{}]")), "xxx"); + expectedParams.insert(mockPressedEventButtonNameParamTypeId.toString().remove(QRegularExpression("[{}]")), "xxx"); expectedParams.insert("buttonName", "xxx"); QCOMPARE(spy.first().at(2).toMap(), expectedParams); - } void TestScripts::testInterfaceState() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " InterfaceState {\n" - " interfaceName: \"%1\"\n" - " stateName: \"%2\"\n" - " onStateChanged: {\n" - " TestHelper.logStateChange(thingId, stateName, value);\n" - " }\n" - " }\n" - "}\n").arg("power").arg("power"); + "import nymea 1.0\n" + "Item {\n" + " InterfaceState {\n" + " interfaceName: \"%1\"\n" + " stateName: \"%2\"\n" + " onStateChanged: (thingId, value) => {\n" + " TestHelper.logStateChange(thingId, stateName, value);\n" + " }\n" + " }\n" + "}\n").arg("power", "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " InterfaceState {\n" + " interfaceName: \"%1\"\n" + " stateName: \"%2\"\n" + " onStateChanged: {\n" + " TestHelper.logStateChange(thingId, stateName, value);\n" + " }\n" + " }\n" + "}\n").arg("power").arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestInterfaceState", script.toUtf8()); @@ -516,21 +672,39 @@ void TestScripts::testInterfaceState() void TestScripts::testInterfaceAction() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " InterfaceAction {\n" - " id: interfaceAction\n" - " interfaceName: \"%1\"\n" - " actionName: \"%2\"\n" - " }\n" - " Connections {\n" - " target: TestHelper\n" - " onExecuteAction: {\n" - " interfaceAction.execute(params)\n" - " }\n" - " }\n" - "}\n").arg("power").arg("power"); + "import nymea 1.0\n" + "Item {\n" + " InterfaceAction {\n" + " id: interfaceAction\n" + " interfaceName: \"%1\"\n" + " actionName: \"%2\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " function onExecuteAction(params) {\n" + " interfaceAction.execute(params)\n" + " }\n" + " }\n" + "}\n").arg("power", "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " InterfaceAction {\n" + " id: interfaceAction\n" + " interfaceName: \"%1\"\n" + " actionName: \"%2\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onExecuteAction: {\n" + " interfaceAction.execute(params)\n" + " }\n" + " }\n" + "}\n").arg("power").arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestInterfaceAction", script.toUtf8()); @@ -548,29 +722,47 @@ void TestScripts::testInterfaceAction() QCOMPARE(spy.first().at(0).value()->id(), m_mockThingId); QCOMPARE(spy.first().at(1).value(), mockPowerStateTypeId); QCOMPARE(spy.first().at(2).toBool(), true); - } void TestScripts::testScriptThingAction() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " Thing {\n" - " id: thing\n" - " thingId: \"%1\"\n" - " onActionExecuted: {\n" - " TestHelper.logActionExecuted(\"%1\", actionName, params, status, triggeredBy)\n" - " }\n" - " }\n" - " Connections {\n" - " target: TestHelper\n" - " onExecuteAction: {\n" - " thing.executeAction(\"%2\", params)\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg("power"); - + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " id: thing\n" + " thingId: \"%1\"\n" + " onActionExecuted: (actionName, params, status, triggeredBy) => {\n" + " TestHelper.logActionExecuted(\"%1\", actionName, params, status, triggeredBy)\n" + " }\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " function onExecuteAction(params) {\n" + " thing.executeAction(\"%2\", params)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " id: thing\n" + " thingId: \"%1\"\n" + " onActionExecuted: {\n" + " TestHelper.logActionExecuted(\"%1\", actionName, params, status, triggeredBy)\n" + " }\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onExecuteAction: {\n" + " thing.executeAction(\"%2\", params)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestAction", script.toUtf8()); QCOMPARE(reply.scriptError, ScriptEngine::ScriptErrorNoError); @@ -595,21 +787,33 @@ void TestScripts::testScriptThingAction() QCOMPARE(actionExecutedSpy.first().at(2).toMap().value("power").toBool(), true); QCOMPARE(actionExecutedSpy.first().at(3).value(), Thing::ThingErrorNoError); QCOMPARE(actionExecutedSpy.first().at(4).value(), Action::TriggeredByScript); - } void TestScripts::testScriptThingReadState() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " Thing {\n" - " thingId: \"%1\"\n" - " onStateValueChanged: {\n" - " TestHelper.logStateChange(thingId, stateName, value);\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg("power"); + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " thingId: \"%1\"\n" + " onStateValueChanged: (stateName, value) => {\n" + " TestHelper.logStateChange(thingId, stateName, value);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " thingId: \"%1\"\n" + " onStateValueChanged: {\n" + " TestHelper.logStateChange(thingId, stateName, value);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestState", script.toUtf8()); @@ -628,25 +832,41 @@ void TestScripts::testScriptThingReadState() QCOMPARE(spy.first().at(0).value(), m_mockThingId); QCOMPARE(spy.first().at(1).toString(), QString("power")); QCOMPARE(spy.first().at(2).toBool(), true); - } void TestScripts::testScriptThingWriteState() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " Thing {\n" - " id: thing\n" - " thingId: \"%1\"\n" - " }\n" - " Connections {\n" - " target: TestHelper\n" - " onSetState: {\n" - " thing.setStateValue(\"%2\", value)\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()).arg("power"); + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " id: thing\n" + " thingId: \"%1\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " function onSetState(value) {\n" + " thing.setStateValue(\"%2\", value)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString(), "power"); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " id: thing\n" + " thingId: \"%1\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onSetState: {\n" + " thing.setStateValue(\"%2\", value)\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()).arg("power"); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestState", script.toUtf8()); @@ -662,21 +882,33 @@ void TestScripts::testScriptThingWriteState() QCOMPARE(spy.first().at(0).value()->id(), m_mockThingId); QCOMPARE(spy.first().at(1).value(), mockPowerStateTypeId); QCOMPARE(spy.first().at(2).toBool(), true); - } void TestScripts::testScriptThingEvent() { +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " Thing {\n" - " thingId: \"%1\"\n" - " onEventTriggered: {\n" - " TestHelper.logEvent(thingId, eventName, params);\n" - " }\n" - " }\n" - "}\n").arg(m_mockThingId.toString()); + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " thingId: \"%1\"\n" + " onEventTriggered: (eventName, params) => {\n" + " TestHelper.logEvent(thingId, eventName, params);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()); +#else + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " Thing {\n" + " thingId: \"%1\"\n" + " onEventTriggered: {\n" + " TestHelper.logEvent(thingId, eventName, params);\n" + " }\n" + " }\n" + "}\n").arg(m_mockThingId.toString()); +#endif qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestEvent", script.toUtf8()); @@ -688,10 +920,10 @@ void TestScripts::testScriptThingEvent() Thing* thing = NymeaCore::instance()->thingManager()->findConfiguredThing(m_mockThingId); int port = thing->paramValue(mockThingHttpportParamTypeId).toInt(); QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2&%3=%4") - .arg(port) - .arg(mockEvent2EventTypeId.toString()) - .arg(mockEvent2EventIntParamParamTypeId.toString()) - .arg(10))); + .arg(port) + .arg(mockEvent2EventTypeId.toString()) + .arg(mockEvent2EventIntParamParamTypeId.toString()) + .arg(10))); QNetworkAccessManager nam; QNetworkReply *r = nam.get(request); connect(r, &QNetworkReply::finished, r, &QNetworkReply::deleteLater); @@ -702,10 +934,9 @@ void TestScripts::testScriptThingEvent() QCOMPARE(spy.first().at(0).value(), m_mockThingId); QCOMPARE(spy.first().at(1).toString(), QString("event2")); QVariantMap expectedParams; - expectedParams.insert(mockEvent2EventIntParamParamTypeId.toString().remove(QRegExp("[{}]")), 10); + expectedParams.insert(mockEvent2EventIntParamParamTypeId.toString().remove(QRegularExpression("[{}]")), 10); expectedParams.insert("intParam", 10); QCOMPARE(spy.first().at(2).toMap(), expectedParams); - } void TestScripts::testThingsFindThing() @@ -713,18 +944,18 @@ void TestScripts::testThingsFindThing() QSignalSpy spy(TestHelper::instance(), &TestHelper::testResult); QString script = QString("import QtQuick 2.0\n" - "import nymea 1.0\n" - "Item {\n" - " id: root\n" - " property string thingId: \"%1\"\n" - " Things {\n" - " id: things\n" - " }\n" - " Component.onCompleted: {\n" - " var thing = things.getThing(root.thingId)\n" - " TestHelper.setTestResult(thing.thingId == root.thingId);\n" - " }\n" - "}\n").arg(m_mockThingId.toString()); + "import nymea 1.0\n" + "Item {\n" + " id: root\n" + " property string thingId: \"%1\"\n" + " Things {\n" + " id: things\n" + " }\n" + " Component.onCompleted: {\n" + " var thing = things.getThing(root.thingId)\n" + " TestHelper.setTestResult(thing.thingId == root.thingId);\n" + " }\n" + "}\n").arg(m_mockThingId.toString()); qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestEvent", script.toUtf8()); @@ -732,10 +963,7 @@ void TestScripts::testThingsFindThing() QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().at(0).toBool(), true); - } - - #include "testscripts.moc" QTEST_MAIN(TestScripts) diff --git a/tests/auto/tags/testtags.cpp b/tests/auto/tags/testtags.cpp index bf065c01..97c60dff 100644 --- a/tests/auto/tags/testtags.cpp +++ b/tests/auto/tags/testtags.cpp @@ -160,7 +160,7 @@ void TestTags::updateTagValue() // Check for TagAdded notification QVariantMap notificationTagMap = checkNotification(clientSpy, "Tags.TagAdded").toMap().value("params").toMap().value("tag").toMap(); QJsonDocument jsonDoc = QJsonDocument::fromVariant(notificationTagMap); - QVERIFY2(compareThingTag(notificationTagMap, thingId, appId, tagId, "1"), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); + QVERIFY2(compareThingTag(notificationTagMap, QUuid(thingId), appId, tagId, "1"), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); clientSpy.clear(); // Try getting the changed tag via GetTag @@ -171,7 +171,7 @@ void TestTags::updateTagValue() response = injectAndWait("Tags.GetTags", params); QVariantList tagsList = response.toMap().value("params").toMap().value("tags").toList(); QCOMPARE(tagsList.count(), 1); - QVERIFY2(compareThingTag(tagsList.first().toMap(), thingId, appId, tagId, "1"), "Fetched tag isn't matching the one we added"); + QVERIFY2(compareThingTag(tagsList.first().toMap(), QUuid(thingId), appId, tagId, "1"), "Fetched tag isn't matching the one we added"); // Now update the tag params.clear(); @@ -182,7 +182,7 @@ void TestTags::updateTagValue() // Check for TagAdded notification notificationTagMap = checkNotification(clientSpy, "Tags.TagValueChanged").toMap().value("params").toMap().value("tag").toMap(); jsonDoc = QJsonDocument::fromVariant(notificationTagMap); - QVERIFY2(compareThingTag(notificationTagMap, thingId, appId, tagId, "2"), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); + QVERIFY2(compareThingTag(notificationTagMap, QUuid(thingId), appId, tagId, "2"), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); // Try getting the changed tag via GetTag params.clear(); @@ -192,7 +192,7 @@ void TestTags::updateTagValue() response = injectAndWait("Tags.GetTags", params); tagsList = response.toMap().value("params").toMap().value("tags").toList(); QCOMPARE(tagsList.count(), 1); - QVERIFY2(compareThingTag(tagsList.first().toMap(), thingId, appId, tagId, "2"), "Fetched tag isn't matching the one we added"); + QVERIFY2(compareThingTag(tagsList.first().toMap(), QUuid(thingId), appId, tagId, "2"), "Fetched tag isn't matching the one we added"); } void TestTags::removeTag() @@ -216,7 +216,7 @@ void TestTags::removeTag() // Check for TagAdded notification QVariantMap notificationTagMap = checkNotification(clientSpy, "Tags.TagAdded").toMap().value("params").toMap().value("tag").toMap(); QJsonDocument jsonDoc = QJsonDocument::fromVariant(notificationTagMap); - QVERIFY2(compareThingTag(notificationTagMap, thingId, appId, tagId, value), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); + QVERIFY2(compareThingTag(notificationTagMap, QUuid(thingId), appId, tagId, value), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); clientSpy.clear(); // Try getting the tag via GetTag @@ -227,7 +227,7 @@ void TestTags::removeTag() response = injectAndWait("Tags.GetTags", params); QVariantList tagsList = response.toMap().value("params").toMap().value("tags").toList(); QCOMPARE(tagsList.count(), 1); - QVERIFY2(compareThingTag(tagsList.first().toMap(), thingId, appId, tagId, value), "Fetched tag isn't matching the one we added"); + QVERIFY2(compareThingTag(tagsList.first().toMap(), QUuid(thingId), appId, tagId, value), "Fetched tag isn't matching the one we added"); // Now remove the tag params.clear(); @@ -238,7 +238,7 @@ void TestTags::removeTag() // Check for TagRemoved notification notificationTagMap = checkNotification(clientSpy, "Tags.TagRemoved").toMap().value("params").toMap().value("tag").toMap(); jsonDoc = QJsonDocument::fromVariant(notificationTagMap); - QVERIFY2(compareThingTag(notificationTagMap, thingId, appId, tagId, QString()), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); + QVERIFY2(compareThingTag(notificationTagMap, QUuid(thingId), appId, tagId, QString()), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); // Try getting the tag via GetTag params.clear(); diff --git a/tests/auto/timemanager/testtimemanager.cpp b/tests/auto/timemanager/testtimemanager.cpp index 6246adb0..5923e3d2 100644 --- a/tests/auto/timemanager/testtimemanager.cpp +++ b/tests/auto/timemanager/testtimemanager.cpp @@ -169,10 +169,10 @@ void TestTimeManager::loadSaveTimeDescriptor_data() QVariantList calendarItems; calendarItems.append(createCalendarItem("12:10", 20, repeatingOptionWeekly)); calendarItems.append(createCalendarItem("23:33", 11, repeatingOptionMonthly)); - calendarItems.append(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 50, repeatingOptionYearly)); + calendarItems.append(createCalendarItem(QDateTime::currentDateTime().toSecsSinceEpoch(), 50, repeatingOptionYearly)); QVariantList timeEventItems; - timeEventItems.append(createTimeEventItem(QDateTime::currentDateTime().toTime_t(), repeatingOptionYearly)); + timeEventItems.append(createTimeEventItem(QDateTime::currentDateTime().toSecsSinceEpoch(), repeatingOptionYearly)); timeEventItems.append(createTimeEventItem("13:12", repeatingOptionWeekly)); timeEventItems.append(createTimeEventItem("18:45", repeatingOptionMonthly)); @@ -307,8 +307,8 @@ void TestTimeManager::addTimeDescriptor_data() QTest::addColumn("error"); QTest::newRow("valid: calendarItem") << createTimeDescriptorCalendar(createCalendarItem("08:00", 5)) << RuleEngine::RuleErrorNoError; - QTest::newRow("valid: calendarItem dateTime") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 5)) << RuleEngine::RuleErrorNoError; - QTest::newRow("valid: calendarItem dateTime - yearly") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 5, repeatingOptionYearly)) << RuleEngine::RuleErrorNoError; + QTest::newRow("valid: calendarItem dateTime") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toSecsSinceEpoch(), 5)) << RuleEngine::RuleErrorNoError; + QTest::newRow("valid: calendarItem dateTime - yearly") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toSecsSinceEpoch(), 5, repeatingOptionYearly)) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: calendarItem - daily") << createTimeDescriptorCalendar(createCalendarItem("08:00", 5, repeatingOptionDaily)) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: calendarItem - none") << createTimeDescriptorCalendar(createCalendarItem("09:00", 30, repeatingOptionNone)) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: calendarItem - hourly") << createTimeDescriptorCalendar(createCalendarItem("09:00", 30, repeatingOptionHourly)) << RuleEngine::RuleErrorNoError; @@ -316,8 +316,8 @@ void TestTimeManager::addTimeDescriptor_data() QTest::newRow("valid: calendarItem - monthly - multiple days") << createTimeDescriptorCalendar(createCalendarItem("23:00", 5, repeatingOptionMonthlyMultiple)) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: timeEventItem") << createTimeDescriptorTimeEvent(createTimeEventItem("08:00")) << RuleEngine::RuleErrorNoError; - QTest::newRow("valid: timeEventItem dateTime") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toTime_t())) << RuleEngine::RuleErrorNoError; - QTest::newRow("valid: timeEventItem dateTime - yearly") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toTime_t(), repeatingOptionYearly)) << RuleEngine::RuleErrorNoError; + QTest::newRow("valid: timeEventItem dateTime") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toSecsSinceEpoch())) << RuleEngine::RuleErrorNoError; + QTest::newRow("valid: timeEventItem dateTime - yearly") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toSecsSinceEpoch(), repeatingOptionYearly)) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: timeEventItem - daily") << createTimeDescriptorTimeEvent(createTimeEventItem("08:00", repeatingOptionDaily)) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: timeEventItem - none") << createTimeDescriptorTimeEvent(createTimeEventItem("09:00", repeatingOptionNone)) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: timeEventItem - hourly") << createTimeDescriptorTimeEvent(createTimeEventItem("09:00", repeatingOptionHourly)) << RuleEngine::RuleErrorNoError; @@ -325,7 +325,7 @@ void TestTimeManager::addTimeDescriptor_data() QTest::newRow("valid: timeEventItem - monthly - multiple days") << createTimeDescriptorTimeEvent(createTimeEventItem("23:00", repeatingOptionMonthlyMultiple)) << RuleEngine::RuleErrorNoError; QTest::newRow("invalid: calendarItem none") << createTimeDescriptorCalendar(createCalendarItem("00:12", 12, repeatingOptionInvalidNone)) << RuleEngine::RuleErrorInvalidRepeatingOption; - QTest::newRow("invalid: calendarItem dateTime - daily") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 5, repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidCalendarItem; + QTest::newRow("invalid: calendarItem dateTime - daily") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toSecsSinceEpoch(), 5, repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidCalendarItem; QTest::newRow("invalid: calendarItem invalid duration") << createTimeDescriptorCalendar(createCalendarItem("12:00", 0)) << RuleEngine::RuleErrorInvalidCalendarItem; QTest::newRow("invalid: calendarItem - monthly - weekDays") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthly)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: calendarItem - weekly - monthDays") << createTimeDescriptorCalendar(createCalendarItem("15:30", 20, repeatingOptionInvalidWeekly)) << RuleEngine::RuleErrorInvalidRepeatingOption; @@ -335,7 +335,7 @@ void TestTimeManager::addTimeDescriptor_data() QTest::newRow("invalid: calendarItem - invalid monthdays (to big)") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthDays2)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: timeEventItem none") << createTimeDescriptorTimeEvent(createTimeEventItem("00:12", repeatingOptionInvalidNone)) << RuleEngine::RuleErrorInvalidRepeatingOption; - QTest::newRow("invalid: timeEventItem - dateTime + repeatingOption") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toTime_t(), repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidTimeEventItem; + QTest::newRow("invalid: timeEventItem - dateTime + repeatingOption") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toSecsSinceEpoch(), repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidTimeEventItem; QTest::newRow("invalid: timeEventItem - monthly - weekDays") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidMonthly)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: timeEventItem - weekly - monthDays") << createTimeDescriptorTimeEvent(createTimeEventItem("15:30", repeatingOptionInvalidWeekly)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: timeEventItem - invalid weekdays (negative)") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidWeekDays)) << RuleEngine::RuleErrorInvalidRepeatingOption; @@ -439,7 +439,7 @@ void TestTimeManager::testCalendarDateTime() // CalendarItem QVariantMap calendarItem; - calendarItem.insert("datetime", QVariant(dateTime.toTime_t())); + calendarItem.insert("datetime", QVariant(dateTime.toSecsSinceEpoch())); calendarItem.insert("duration", QVariant(duration)); // Create the rule map @@ -994,7 +994,7 @@ void TestTimeManager::testCalendarYearlyDateTime() // CalendarItem QVariantMap calendarItem; - calendarItem.insert("datetime", QVariant(dateTime.toTime_t())); + calendarItem.insert("datetime", QVariant(dateTime.toSecsSinceEpoch())); calendarItem.insert("duration", QVariant(duration)); calendarItem.insert("repeating", repeatingOption); @@ -1472,7 +1472,7 @@ void TestTimeManager::testEventItemDateTime() // Create the rule map ruleMap.insert("name", "Time based hourly calendar rule"); - ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(dateTime.toTime_t()))); + ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(dateTime.toSecsSinceEpoch()))); ruleMap.insert("actions", QVariantList() << action); // Add the rule @@ -1832,7 +1832,7 @@ void TestTimeManager::testEventItemYearly() // Create the rule map ruleMap.insert("name", "Time based hourly calendar rule"); - ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(dateTime.toTime_t(), repeatingOptionYearly))); + ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(dateTime.toSecsSinceEpoch(), repeatingOptionYearly))); ruleMap.insert("actions", QVariantList() << action); // Add the rule diff --git a/tests/auto/versioning/testversioning.cpp b/tests/auto/versioning/testversioning.cpp index 9551e926..89ff0e4c 100644 --- a/tests/auto/versioning/testversioning.cpp +++ b/tests/auto/versioning/testversioning.cpp @@ -31,6 +31,8 @@ #include "nymeatestbase.h" #include "version.h" +#include + using namespace nymeaserver; class TestVersioning: public NymeaTestBase @@ -38,10 +40,19 @@ class TestVersioning: public NymeaTestBase Q_OBJECT private slots: + void initTestCase(); + void version(); void apiChangeBumpsVersion(); }; +void TestVersioning::initTestCase() +{ + NymeaTestBase::initTestCase("*.debug=false\nJsonRpcTraffic.debug=false\nJsonRpc.debug=true\nTests.debug=true"); + qCDebug(dcTests()) << "TestVersioning starting"; +} + + void TestVersioning::version() { QVariant response = injectAndWait("JSONRPC.Version"); @@ -54,7 +65,7 @@ void TestVersioning::version() QCOMPARE(version, QString(NYMEA_VERSION_STRING)); QVERIFY2(!protocolVersion.toString().isEmpty(), "Protocol version is empty."); - QVERIFY2(protocolVersion.canConvert(QVariant::Int), "Protocol version is not an integer."); + QVERIFY2(protocolVersion.canConvert(QMetaType::Int), "Protocol version is not an integer."); } void TestVersioning::apiChangeBumpsVersion() @@ -72,12 +83,11 @@ void TestVersioning::apiChangeBumpsVersion() QFile oldApiFile(oldFilePath); QVERIFY(oldApiFile.exists() && oldApiFile.open(QIODevice::ReadOnly)); - QByteArray oldVersion = oldApiFile.readLine().trimmed(); QByteArray oldApi = oldApiFile.readAll(); QString newVersionStripped = newVersion; - newVersionStripped = newVersionStripped.remove(QRegExp("\\+[0-9\\.~a-f]*")); + newVersionStripped = newVersionStripped.remove(QRegularExpression("\\+[0-9\\.~a-f]*")); qDebug() << "JSON API version:" << oldVersion; qDebug() << "Binary version:" << newVersion << "(" + newVersionStripped + ")"; @@ -102,7 +112,7 @@ void TestVersioning::apiChangeBumpsVersion() p.waitForFinished(); QByteArray apiDiff = p.readAll(); - qCDebug(dcTests()) << "API Differences:" << endl << qUtf8Printable(apiDiff); + qCDebug(dcTests()) << "API Differences:" << '\n' << qUtf8Printable(apiDiff); if (oldVersion == newVersionStripped && oldApi != newApi) { QVERIFY2(false, "JSONRPC API has changed but version is still the same. You need to bump the API version."); diff --git a/tests/auto/webserver/testwebserver.cpp b/tests/auto/webserver/testwebserver.cpp index 714079ee..a5348084 100644 --- a/tests/auto/webserver/testwebserver.cpp +++ b/tests/auto/webserver/testwebserver.cpp @@ -32,6 +32,7 @@ #include "nymeacore.h" #include +#include using namespace nymeaserver; @@ -129,7 +130,7 @@ void TestWebserver::httpVersion() QVERIFY2(!data.isEmpty(), "got no response"); QStringList lines = QString(data).split("\r\n"); - QStringList firstLineTokens = lines.first().split(QRegExp("[ \r\n][ \r\n]*")); + QStringList firstLineTokens = lines.first().split(QRegularExpression("[ \r\n][ \r\n]*")); QVERIFY2(firstLineTokens.isEmpty() || firstLineTokens.count() > 2, "could not get tokens of first line"); @@ -180,7 +181,7 @@ void TestWebserver::multiPackageMessage() QVERIFY2(!data.isEmpty(), "got no response"); QStringList lines = QString(data).split("\r\n"); - QStringList firstLineTokens = lines.first().split(QRegExp("[ \r\n][ \r\n]*")); + QStringList firstLineTokens = lines.first().split(QRegularExpression("[ \r\n][ \r\n]*")); QVERIFY2(firstLineTokens.isEmpty() || firstLineTokens.count() > 2, "could not get tokens of first line"); @@ -314,7 +315,7 @@ void TestWebserver::badRequests() QVERIFY2(!data.isEmpty(), "got no response"); QStringList lines = QString(data).split("\r\n"); - QStringList firstLineTokens = lines.first().split(QRegExp("[ \r\n][ \r\n]*")); + QStringList firstLineTokens = lines.first().split(QRegularExpression("[ \r\n][ \r\n]*")); QVERIFY2(firstLineTokens.isEmpty() || firstLineTokens.count() > 2, "could not get tokens of first line"); @@ -371,7 +372,7 @@ void TestWebserver::getFiles() void TestWebserver::getServerDescription() { QNetworkAccessManager nam; - connect(&nam, &QNetworkAccessManager::sslErrors, [this, &nam](QNetworkReply* reply, const QList &) { + connect(&nam, &QNetworkAccessManager::sslErrors, this, [](QNetworkReply* reply, const QList &) { reply->ignoreSslErrors(); }); QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*))); @@ -597,14 +598,17 @@ void TestWebserver::getDebugServer() int statusCode = 0; QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*))); - connect(&nam, &QNetworkAccessManager::sslErrors, [this, &nam](QNetworkReply* reply, const QList &) { + connect(&nam, &QNetworkAccessManager::sslErrors, this, [](QNetworkReply* reply, const QList &) { reply->ignoreSslErrors(); }); QNetworkReply *reply = nullptr; QNetworkRequest request; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + // Note: in qt6 the request follows by default the redirect + request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy); +#endif request.setUrl(QUrl("https://localhost:3333" + query)); - clientSpy.clear(); if (method == "get") { @@ -619,7 +623,8 @@ void TestWebserver::getDebugServer() reply = nam.put(request, ""); } - clientSpy.wait(); + clientSpy.wait(1000); + qCCritical(dcTests()) << reply->isFinished() << reply->isRunning() << clientSpy.count(); QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver"); ok = false; diff --git a/tests/auto/webserver/webserver.pro b/tests/auto/webserver/webserver.pro index 12ea234b..85c57a2b 100644 --- a/tests/auto/webserver/webserver.pro +++ b/tests/auto/webserver/webserver.pro @@ -1,7 +1,12 @@ include(../../../nymea.pri) include(../autotests.pri) -QT += xml +greaterThan(QT_MAJOR_VERSION, 5) { + QT *= core5compat +} else { + QT *= xml +} + TARGET = nymeatestwebserver SOURCES += testwebserver.cpp diff --git a/tests/scripts/getplugins.sh b/tests/scripts/getplugins.sh index d480c73a..c7aa3b28 100755 --- a/tests/scripts/getplugins.sh +++ b/tests/scripts/getplugins.sh @@ -5,7 +5,7 @@ if [ -z $1 ]; then exit 1 fi -cat << EOD | nc $1 2222 +cat << EOD | nc $1 2223 {"id":0, "method": "JSONRPC.Hello"} -{"id":1, "method": "Devices.GetPlugins"} +{"id":1, "method": "Integrations.GetPlugins"} EOD diff --git a/tests/scripts/getsupporteddevices.sh b/tests/scripts/getsupporteddevices.sh deleted file mode 100755 index 0d09b5ce..00000000 --- a/tests/scripts/getsupporteddevices.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -if [ -z $1 ]; then - echo "usage $0 host [vendorId]" - exit 1; -fi - -if [ -z $2 ]; then -cat << EOD | nc $1 2222 -{"id":0, "method": "JSONRPC.Hello"} -{"id":1, "method": "Devices.GetSupportedDevices"} -EOD -else -cat << EOD | nc $1 2222 -{"id":0, "method": "JSONRPC.Hello"} -{"id":1, "method": "Devices.GetSupportedDevices", "params":{"vendorId":"$2"}} -EOD -fi - - - diff --git a/tests/scripts/getsupportedvendors.sh b/tests/scripts/getsupportedvendors.sh deleted file mode 100755 index 2188798d..00000000 --- a/tests/scripts/getsupportedvendors.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -if [ -z $1 ]; then - echo "usage $0 host" -else - (echo '{"id":1, "method":"Devices.GetSupportedVendors"}'; sleep 1) | nc $1 2222 -fi diff --git a/tests/scripts/getconfigureddevices.sh b/tests/scripts/getthings.sh similarity index 53% rename from tests/scripts/getconfigureddevices.sh rename to tests/scripts/getthings.sh index cbd8d221..e8225045 100755 --- a/tests/scripts/getconfigureddevices.sh +++ b/tests/scripts/getthings.sh @@ -6,16 +6,16 @@ if [ -z $1 ]; then fi if [ -z $2 ]; then -cat <" + exit 1 +fi + +if [ -z $2 ]; then +cat <(); - qsrand(QDateTime::currentMSecsSinceEpoch()); - m_mockThing1Port = 1337 + (qrand() % 10000); - m_mockThing2Port = 7331 + (qrand() % 10000); + std::srand(QDateTime::currentMSecsSinceEpoch()); + m_mockThing1Port = 1337 + (std::rand() % 10000); + m_mockThing2Port = 7331 + (std::rand() % 10000); // Important for settings QCoreApplication::instance()->setOrganizationName("nymea-test"); @@ -131,6 +131,7 @@ void NymeaTestBase::initTestCase(const QString &loggingRules, bool disableLogEng void NymeaTestBase::cleanupTestCase() { NymeaCore::instance()->destroy(NymeaCore::ShutdownReasonTerm); + } void NymeaTestBase::cleanup() @@ -156,7 +157,7 @@ QVariant NymeaTestBase::injectAndWait(const QString &method, const QVariantMap & int loop = 0; - while (loop < 5) { + while (loop < 10) { if (spy.count() == 0 || loop > 0) { spy.wait(); @@ -396,7 +397,7 @@ void NymeaTestBase::verifyReply(QNetworkReply *reply, const QByteArray &data, co void NymeaTestBase::enableNotifications(const QStringList &namespaces) { - QVariantList variantList; + QStringList variantList; foreach (const QString &ns, namespaces) { variantList << ns; } @@ -404,7 +405,7 @@ void NymeaTestBase::enableNotifications(const QStringList &namespaces) QVariantMap notificationParams; notificationParams.insert("namespaces", variantList); QVariant response = injectAndWait("JSONRPC.SetNotificationStatus", notificationParams); - QVariantList resultList = response.toMap().value("params").toMap().value("namespaces").toList(); + QStringList resultList = response.toMap().value("params").toMap().value("namespaces").toStringList(); std::sort(resultList.begin(), resultList.end()); QCOMPARE(resultList, variantList); } diff --git a/tests/testlib/nymeatestbase.h b/tests/testlib/nymeatestbase.h index 8c528e7d..dbc3f565 100644 --- a/tests/testlib/nymeatestbase.h +++ b/tests/testlib/nymeatestbase.h @@ -75,15 +75,15 @@ protected: QJsonDocument jsonDoc = QJsonDocument::fromVariant(response); QVERIFY2(response.toMap().value("status").toString() == QString("success"), QString("\nExpected status: \"success\"\nGot: %2\nFull message: %3") - .arg(response.toMap().value("status").toString()) - .arg(jsonDoc.toJson().data()) - .toLatin1().data()); + .arg(response.toMap().value("status").toString()) + .arg(jsonDoc.toJson().data()) + .toLatin1().data()); QVERIFY2(response.toMap().value("params").toMap().value(fieldName).toString() == error, QString("\nExpected: %1\nGot: %2\nFull message: %3\n") - .arg(error) - .arg(response.toMap().value("params").toMap().value(fieldName).toString()) - .arg(jsonDoc.toJson().data()) - .toLatin1().data()); + .arg(error) + .arg(response.toMap().value("params").toMap().value(fieldName).toString()) + .arg(jsonDoc.toJson().data()) + .toLatin1().data()); } template QString enumValueName(T value) @@ -102,10 +102,11 @@ protected: { if (allRequired) QVERIFY2(requestList.count() == responseList.count(), "Not the same count of param in response."); + foreach (const QVariant &requestParam, requestList) { bool found = false; foreach (const QVariant &responseParam, responseList) { - if (requestParam.toMap().value("paramTypeId") == responseParam.toMap().value("paramTypeId")){ + if (requestParam.toMap().value("paramTypeId").toUuid() == responseParam.toMap().value("paramTypeId").toUuid()){ QCOMPARE(requestParam.toMap().value("value"), responseParam.toMap().value("value")); found = true; break; diff --git a/tests/testlib/testlib.pro b/tests/testlib/testlib.pro index a9c8f52a..bae6cc8b 100644 --- a/tests/testlib/testlib.pro +++ b/tests/testlib/testlib.pro @@ -8,12 +8,25 @@ QT += testlib dbus network sql websockets CONFIG += link_pkgconfig PKGCONFIG += nymea-zigbee -# Qt serial bus module is officially available since Qt 5.8 -# but not all platforms host the qt serialbus package. -# Let's check if the package exists, not the qt version -packagesExist(Qt5SerialBus) { - Qt += serialbus - DEFINES += WITH_QTSERIALBUS +greaterThan(QT_MAJOR_VERSION, 5) { + qtHaveModule(serialbus) { + message("Building with QtSerialBus support.") + QT *= serialbus + DEFINES += WITH_QTSERIALBUS + } else { + message("QtSerialBus package not found. Building without QtSerialBus support.") + } + + # Separate module in Qt6 + QT *= concurrent +} else { + packagesExist(Qt5SerialBus) { + message("Building with QtSerialBus support.") + PKGCONFIG += Qt5SerialBus + DEFINES += WITH_QTSERIALBUS + } else { + message("Qt5SerialBus package not found. Building without QtSerialBus support.") + } } INCLUDEPATH += $$top_srcdir/libnymea \ diff --git a/tests/tests.pro b/tests/tests.pro index db50a6ec..dbf0b265 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,5 +1,4 @@ TEMPLATE = subdirs SUBDIRS = testlib auto tools/simplepushbuttonhandler - auto.depends += testlib diff --git a/tools/nymea-plugininfocompiler/plugininfocompiler.cpp b/tools/nymea-plugininfocompiler/plugininfocompiler.cpp index e4c96acf..40098117 100644 --- a/tools/nymea-plugininfocompiler/plugininfocompiler.cpp +++ b/tools/nymea-plugininfocompiler/plugininfocompiler.cpp @@ -37,6 +37,7 @@ #include #include #include +#include PluginInfoCompiler::PluginInfoCompiler() { @@ -74,8 +75,8 @@ int PluginInfoCompiler::compile(const QString &inputFile, const QString &outputF spacer += ' '; } QDebug dbg = qWarning().nospace().noquote(); - dbg << inputFile << ":" << lineIndex << ":" << errorOffset + 2 << ": error: JSON parsing failed: " << error.errorString() << ": " << data.trimmed() << endl; - dbg << data << endl; + dbg << inputFile << ":" << lineIndex << ":" << errorOffset + 2 << ": error: JSON parsing failed: " << error.errorString() << ": " << data.trimmed() << '\n'; + dbg << data << '\n'; dbg << spacer << "^"; return 1; } @@ -132,7 +133,7 @@ int PluginInfoCompiler::compile(const QString &inputFile, const QString &outputF qDebug() << "Created translations dir"; } - QFile f(translationsPath + '/' + metadata.pluginId().toString().remove(QRegExp("[{}]")) + "-en_US.ts"); + QFile f(translationsPath + '/' + metadata.pluginId().toString().remove(QRegularExpression("[{}]")) + "-en_US.ts"); QByteArray translationsStub = ""; if (!f.exists()) { if (!f.open(QFile::WriteOnly | QFile::Text)) {