Add Qt6 support
Add Qt6 debian packaging
This commit is contained in:
parent
5f4f2a9b78
commit
f5c4bd16ac
@ -66,8 +66,8 @@ Recommends: nymea-cli,
|
|||||||
nymea-zwave-plugin-impl,
|
nymea-zwave-plugin-impl,
|
||||||
influxdb,
|
influxdb,
|
||||||
Description: An open source IoT server - daemon
|
Description: An open source IoT server - daemon
|
||||||
The nymea daemon is a plugin based IoT (Internet of Things) server.
|
The nymea daemon is a plugin based IoT (Internet of Things) server.
|
||||||
The server works like a translator for devices, things and services
|
The server works like a translator for devices, things and services
|
||||||
and allows them to interact.
|
and allows them to interact.
|
||||||
|
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ Depends: ${shlibs:Depends},
|
|||||||
libnymea-tests (= ${binary:Version}),
|
libnymea-tests (= ${binary:Version}),
|
||||||
libnymea-core-dev (= ${binary:Version})
|
libnymea-core-dev (= ${binary:Version})
|
||||||
Description: nymea-tests library - development files
|
Description: nymea-tests library - development files
|
||||||
Provides the nymea-tests development files for building
|
Provides the nymea-tests development files for building
|
||||||
automated tests.
|
automated tests.
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ $(info Building with DEB_BUILD_OPTIONS: [${DEB_BUILD_OPTIONS}])
|
|||||||
MAKE_TARGETS=all lrelease
|
MAKE_TARGETS=all lrelease
|
||||||
ifeq (,$(filter nodoc,$(DEB_BUILD_OPTIONS)))
|
ifeq (,$(filter nodoc,$(DEB_BUILD_OPTIONS)))
|
||||||
MAKE_TARGETS += doc
|
MAKE_TARGETS += doc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
QMAKE_ADDITIONAL_ARGS = CONFIG+=norpath
|
QMAKE_ADDITIONAL_ARGS = CONFIG+=norpath
|
||||||
ifneq (,$(filter coverage,$(DEB_BUILD_OPTIONS)))
|
ifneq (,$(filter coverage,$(DEB_BUILD_OPTIONS)))
|
||||||
1
debian-qt6/changelog
Symbolic link
1
debian-qt6/changelog
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/changelog
|
||||||
1
debian-qt6/compat
Normal file
1
debian-qt6/compat
Normal file
@ -0,0 +1 @@
|
|||||||
|
13
|
||||||
221
debian-qt6/control
Normal file
221
debian-qt6/control
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
Source: nymea
|
||||||
|
Section: utils
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: nymea GmbH <developer@nymea.io>
|
||||||
|
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: <!nodoc>
|
||||||
|
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.
|
||||||
1
debian-qt6/copyright
Symbolic link
1
debian-qt6/copyright
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/copyright
|
||||||
1
debian-qt6/libnymea-core-dev.install.in
Symbolic link
1
debian-qt6/libnymea-core-dev.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea-core-dev.install.in
|
||||||
1
debian-qt6/libnymea-core.install.in
Symbolic link
1
debian-qt6/libnymea-core.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea-core.install.in
|
||||||
1
debian-qt6/libnymea-dev.install.in
Symbolic link
1
debian-qt6/libnymea-dev.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea-dev.install.in
|
||||||
1
debian-qt6/libnymea-tests-dev.install.in
Symbolic link
1
debian-qt6/libnymea-tests-dev.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea-tests-dev.install.in
|
||||||
1
debian-qt6/libnymea-tests.install.in
Symbolic link
1
debian-qt6/libnymea-tests.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea-tests.install.in
|
||||||
1
debian-qt6/libnymea1-dev.dirs.in
Symbolic link
1
debian-qt6/libnymea1-dev.dirs.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea1-dev.dirs.in
|
||||||
1
debian-qt6/libnymea1-dev.manpages
Symbolic link
1
debian-qt6/libnymea1-dev.manpages
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea1-dev.manpages
|
||||||
1
debian-qt6/libnymea1.dirs.in
Symbolic link
1
debian-qt6/libnymea1.dirs.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea1.dirs.in
|
||||||
1
debian-qt6/libnymea1.install.in
Symbolic link
1
debian-qt6/libnymea1.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/libnymea1.install.in
|
||||||
1
debian-qt6/man
Symbolic link
1
debian-qt6/man
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/man/
|
||||||
1
debian-qt6/nymea-data.install
Symbolic link
1
debian-qt6/nymea-data.install
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-data.install
|
||||||
1
debian-qt6/nymea-dev-tools.install.in
Symbolic link
1
debian-qt6/nymea-dev-tools.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-dev-tools.install.in
|
||||||
1
debian-qt6/nymea-doc.dirs
Symbolic link
1
debian-qt6/nymea-doc.dirs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-doc.dirs
|
||||||
1
debian-qt6/nymea-doc.install
Symbolic link
1
debian-qt6/nymea-doc.install
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-doc.install
|
||||||
1
debian-qt6/nymea-tests.dirs.in
Symbolic link
1
debian-qt6/nymea-tests.dirs.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-tests.dirs.in
|
||||||
1
debian-qt6/nymea-tests.install.in
Symbolic link
1
debian-qt6/nymea-tests.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-tests.install.in
|
||||||
1
debian-qt6/nymea-translations.dirs
Symbolic link
1
debian-qt6/nymea-translations.dirs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-translations.dirs
|
||||||
1
debian-qt6/nymea-translations.install
Symbolic link
1
debian-qt6/nymea-translations.install
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymea-translations.install
|
||||||
1
debian-qt6/nymead.dirs
Symbolic link
1
debian-qt6/nymead.dirs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymead.dirs
|
||||||
1
debian-qt6/nymead.install.in
Symbolic link
1
debian-qt6/nymead.install.in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymead.install.in
|
||||||
1
debian-qt6/nymead.manpages
Symbolic link
1
debian-qt6/nymead.manpages
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymead.manpages
|
||||||
1
debian-qt6/nymead.postinst
Symbolic link
1
debian-qt6/nymead.postinst
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymead.postinst
|
||||||
1
debian-qt6/nymead.prerm
Symbolic link
1
debian-qt6/nymead.prerm
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/nymead.prerm
|
||||||
66
debian-qt6/rules
Executable file
66
debian-qt6/rules
Executable file
@ -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
|
||||||
1
debian-qt6/source
Symbolic link
1
debian-qt6/source
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../debian-qt5/source/
|
||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
#include "openssl/ssl.h"
|
#include "openssl/ssl.h"
|
||||||
|
|
||||||
#include <QRegExp>
|
#include <QRegularExpression>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -87,8 +87,8 @@ void CertificateGenerator::generate(const QString &certificateFilename, const QS
|
|||||||
q_check_ptr(x509);
|
q_check_ptr(x509);
|
||||||
// Randomize serial number in case a previous one is stuck in a browser (Chromium
|
// 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)
|
// 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());
|
std::srand(QUuid::createUuid().toString().remove(QRegularExpression("[a-zA-Z{}-]")).left(5).toInt());
|
||||||
ASN1_INTEGER_set(X509_get_serialNumber(x509), qrand());
|
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_notBefore(x509), 0); // not before current time
|
||||||
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L*10); // not after 10 years from this point
|
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L*10); // not after 10 years from this point
|
||||||
X509_set_pubkey(x509, pkey);
|
X509_set_pubkey(x509, pkey);
|
||||||
|
|||||||
@ -167,28 +167,28 @@ void DebugReportGenerator::saveSystemInformation()
|
|||||||
|
|
||||||
qCDebug(dcDebugServer()) << "Write system information file" << outputFile.fileName();
|
qCDebug(dcDebugServer()) << "Write system information file" << outputFile.fileName();
|
||||||
QTextStream stream(&outputFile);
|
QTextStream stream(&outputFile);
|
||||||
stream << "Server name: " << NymeaCore::instance()->configuration()->serverName() << endl;
|
stream << "Server name: " << NymeaCore::instance()->configuration()->serverName() << '\n';
|
||||||
stream << "Server version: " << NYMEA_VERSION_STRING << endl;
|
stream << "Server version: " << NYMEA_VERSION_STRING << '\n';
|
||||||
stream << "JSON-RPC version: " << JSON_PROTOCOL_VERSION << endl;
|
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() << ")" << endl;
|
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()) << endl;
|
stream << "Timezone: " << QString::fromUtf8(NymeaCore::instance()->configuration()->timeZone()) << '\n';
|
||||||
stream << "Server UUID: " << NymeaCore::instance()->configuration()->serverUuid().toString() << endl;
|
stream << "Server UUID: " << NymeaCore::instance()->configuration()->serverUuid().toString() << '\n';
|
||||||
stream << "Settings path: " << NymeaSettings::settingsPath() << endl;
|
stream << "Settings path: " << NymeaSettings::settingsPath() << '\n';
|
||||||
stream << "Translations path: " << NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath() << endl;
|
stream << "Translations path: " << NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath() << '\n';
|
||||||
stream << "User: " << qgetenv("USER") << endl;
|
stream << "User: " << qgetenv("USER") << '\n';
|
||||||
stream << "Command: " << QCoreApplication::arguments().join(' ') << endl;
|
stream << "Command: " << QCoreApplication::arguments().join(' ') << '\n';
|
||||||
stream << "Qt runtime version: " << qVersion() << endl;
|
stream << "Qt runtime version: " << qVersion() << '\n';
|
||||||
stream << "" << endl;
|
stream << "" << '\n';
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 6, 0))
|
#if (QT_VERSION < QT_VERSION_CHECK(5, 6, 0))
|
||||||
stream << "Hostname: " << QHostInfo::localHostName() << endl;
|
stream << "Hostname: " << QHostInfo::localHostName() << '\n';
|
||||||
#else
|
#else
|
||||||
stream << "Hostname: " << QSysInfo::machineHostName() << endl;
|
stream << "Hostname: " << QSysInfo::machineHostName() << '\n';
|
||||||
#endif
|
#endif
|
||||||
stream << "Architecture: " << QSysInfo::currentCpuArchitecture() << endl;
|
stream << "Architecture: " << QSysInfo::currentCpuArchitecture() << '\n';
|
||||||
stream << "Kernel type: " << QSysInfo::kernelType() << endl;
|
stream << "Kernel type: " << QSysInfo::kernelType() << '\n';
|
||||||
stream << "Kernel version: " << QSysInfo::kernelVersion() << endl;
|
stream << "Kernel version: " << QSysInfo::kernelVersion() << '\n';
|
||||||
stream << "Product type: " << QSysInfo::productType() << endl;
|
stream << "Product type: " << QSysInfo::productType() << '\n';
|
||||||
stream << "Product version: " << QSysInfo::productVersion() << endl;
|
stream << "Product version: " << QSysInfo::productVersion() << '\n';
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -673,7 +673,7 @@ void DebugServerHandler::onPingProcessFinished(int exitCode, QProcess::ExitStatu
|
|||||||
{
|
{
|
||||||
qCDebug(dcDebugServer()) << "Ping process finished" << exitCode << exitStatus;
|
qCDebug(dcDebugServer()) << "Ping process finished" << exitCode << exitStatus;
|
||||||
QByteArray processOutput = m_pingProcess->readAll();
|
QByteArray processOutput = m_pingProcess->readAll();
|
||||||
qCDebug(dcDebugServer()) << "Ping output:" << endl << qUtf8Printable(processOutput);
|
qCDebug(dcDebugServer()) << "Ping output:" << '\n' << qUtf8Printable(processOutput);
|
||||||
|
|
||||||
if (m_pingReply) {
|
if (m_pingReply) {
|
||||||
m_pingReply->setPayload(processOutput);
|
m_pingReply->setPayload(processOutput);
|
||||||
@ -690,7 +690,7 @@ void DebugServerHandler::onDigProcessFinished(int exitCode, QProcess::ExitStatus
|
|||||||
{
|
{
|
||||||
qCDebug(dcDebugServer()) << "Dig process finished" << exitCode << exitStatus;
|
qCDebug(dcDebugServer()) << "Dig process finished" << exitCode << exitStatus;
|
||||||
QByteArray processOutput = m_digProcess->readAll();
|
QByteArray processOutput = m_digProcess->readAll();
|
||||||
qCDebug(dcDebugServer()) << "Dig output:" << endl << qUtf8Printable(processOutput);
|
qCDebug(dcDebugServer()) << "Dig output:" << '\n' << qUtf8Printable(processOutput);
|
||||||
|
|
||||||
if (m_digReply) {
|
if (m_digReply) {
|
||||||
m_digReply->setPayload(processOutput);
|
m_digReply->setPayload(processOutput);
|
||||||
@ -707,7 +707,7 @@ void DebugServerHandler::onTracePathProcessFinished(int exitCode, QProcess::Exit
|
|||||||
{
|
{
|
||||||
qCDebug(dcDebugServer()) << "Tracepath process finished" << exitCode << exitStatus;
|
qCDebug(dcDebugServer()) << "Tracepath process finished" << exitCode << exitStatus;
|
||||||
QByteArray processOutput = m_tracePathProcess->readAll();
|
QByteArray processOutput = m_tracePathProcess->readAll();
|
||||||
qCDebug(dcDebugServer()) << "Tracepath output:" << endl << qUtf8Printable(processOutput);
|
qCDebug(dcDebugServer()) << "Tracepath output:" << '\n' << qUtf8Printable(processOutput);
|
||||||
|
|
||||||
if (m_tracePathReply) {
|
if (m_tracePathReply) {
|
||||||
m_tracePathReply->setPayload(processOutput);
|
m_tracePathReply->setPayload(processOutput);
|
||||||
|
|||||||
@ -70,7 +70,7 @@ void BluetoothDiscoveryReplyImplementation::setDiscoveredDevices(const QList<QPa
|
|||||||
|
|
||||||
void BluetoothDiscoveryReplyImplementation::addDiscoveredDevice(const QBluetoothDeviceInfo &info, const QBluetoothHostInfo &hostInfo)
|
void BluetoothDiscoveryReplyImplementation::addDiscoveredDevice(const QBluetoothDeviceInfo &info, const QBluetoothHostInfo &hostInfo)
|
||||||
{
|
{
|
||||||
m_discoveredDevices.append(qMakePair<QBluetoothDeviceInfo, QBluetoothHostInfo>(info, hostInfo));
|
m_discoveredDevices.append(QPair<QBluetoothDeviceInfo, QBluetoothHostInfo>(info, hostInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothDiscoveryReplyImplementation::setFinished()
|
void BluetoothDiscoveryReplyImplementation::setFinished()
|
||||||
|
|||||||
@ -37,7 +37,11 @@ BluetoothLowEnergyDeviceImplementation::BluetoothLowEnergyDeviceImplementation(c
|
|||||||
BluetoothLowEnergyDevice(parent),
|
BluetoothLowEnergyDevice(parent),
|
||||||
m_deviceInfo(deviceInfo)
|
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);
|
m_controller = new QLowEnergyController(address(), this);
|
||||||
|
#endif
|
||||||
m_controller->setRemoteAddressType(addressType);
|
m_controller->setRemoteAddressType(addressType);
|
||||||
|
|
||||||
connect(m_controller, &QLowEnergyController::connected, this, &BluetoothLowEnergyDeviceImplementation::onConnected);
|
connect(m_controller, &QLowEnergyController::connected, this, &BluetoothLowEnergyDeviceImplementation::onConnected);
|
||||||
|
|||||||
@ -138,11 +138,19 @@ BluetoothPairingJob *BluetoothLowEnergyManagerImplementation::pairDevice(const Q
|
|||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
localDevice->requestPairing(device, QBluetoothLocalDevice::AuthorizedPaired);
|
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){
|
connect(localDevice, &QBluetoothLocalDevice::error, job, [=](QBluetoothLocalDevice::Error error){
|
||||||
qCDebug(dcBluetooth()) << "Pairing error" << error;
|
qCDebug(dcBluetooth()) << "Pairing error" << error;
|
||||||
job->finish(false);
|
job->finish(false);
|
||||||
localDevice->deleteLater();
|
localDevice->deleteLater();
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
connect(localDevice, &QBluetoothLocalDevice::pairingFinished, job, [=](const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing){
|
connect(localDevice, &QBluetoothLocalDevice::pairingFinished, job, [=](const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing){
|
||||||
qCDebug(dcBluetooth()) << "Pairing finished" << address.toString() << pairing;
|
qCDebug(dcBluetooth()) << "Pairing finished" << address.toString() << pairing;
|
||||||
job->finish(true);
|
job->finish(true);
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
#ifndef BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
|
#ifndef BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
|
||||||
#define BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
|
#define BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
|
||||||
|
|
||||||
#include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h"
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <hardware/bluetoothlowenergy/bluetoothlowenergymanager.h>
|
||||||
|
|
||||||
namespace nymeaserver
|
namespace nymeaserver {
|
||||||
{
|
|
||||||
|
|
||||||
class NymeaBluetoothAgent;
|
class NymeaBluetoothAgent;
|
||||||
class BluetoothLowEnergyManagerImplementation;
|
class BluetoothLowEnergyManagerImplementation;
|
||||||
@ -35,4 +34,5 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
|
#endif // BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
|
||||||
|
|||||||
@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcBluetooth)
|
Q_DECLARE_LOGGING_CATEGORY(dcBluetooth)
|
||||||
|
|
||||||
namespace nymeaserver
|
namespace nymeaserver {
|
||||||
{
|
|
||||||
|
|
||||||
NymeaBluetoothAgentAdapter::NymeaBluetoothAgentAdapter(NymeaBluetoothAgent *agent, QObject *parent):
|
NymeaBluetoothAgentAdapter::NymeaBluetoothAgentAdapter(NymeaBluetoothAgent *agent, QObject *parent):
|
||||||
QObject{parent},
|
QObject{parent},
|
||||||
|
|||||||
@ -6,8 +6,9 @@
|
|||||||
#include <QDBusMessage>
|
#include <QDBusMessage>
|
||||||
#include <QBluetoothAddress>
|
#include <QBluetoothAddress>
|
||||||
|
|
||||||
namespace nymeaserver
|
#include <hardware/bluetoothlowenergy/nymeabluetoothagent.h>
|
||||||
{
|
|
||||||
|
namespace nymeaserver {
|
||||||
|
|
||||||
class NymeaBluetoothAgent;
|
class NymeaBluetoothAgent;
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ MacAddressDatabase::MacAddressDatabase(QObject *parent) : QObject(parent)
|
|||||||
{
|
{
|
||||||
// Find database in system data locations
|
// Find database in system data locations
|
||||||
QString databaseFileName;
|
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");
|
QFileInfo databaseFileInfo(dataLocation + QDir::separator() + "mac-addresses.db");
|
||||||
if (!databaseFileInfo.exists()) {
|
if (!databaseFileInfo.exists()) {
|
||||||
continue;
|
continue;
|
||||||
@ -58,7 +58,7 @@ MacAddressDatabase::MacAddressDatabase(QObject *parent) : QObject(parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (databaseFileName.isEmpty()) {
|
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.";
|
qCWarning(dcMacAddressDatabase()) << "The mac address database lookup feature will not be available.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -156,7 +156,11 @@ void MacAddressDatabase::runNextLookup()
|
|||||||
|
|
||||||
m_currentReply = m_pendingReplies.dequeue();
|
m_currentReply = m_pendingReplies.dequeue();
|
||||||
m_currentReply->m_startTimestamp = QDateTime::currentMSecsSinceEpoch();
|
m_currentReply->m_startTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
QFuture<QString> future = QtConcurrent::run(&MacAddressDatabase::lookupMacAddressVendorInternal, this, m_currentReply->macAddress());
|
||||||
|
#else
|
||||||
QFuture<QString> future = QtConcurrent::run(this, &MacAddressDatabase::lookupMacAddressVendorInternal, m_currentReply->macAddress());
|
QFuture<QString> future = QtConcurrent::run(this, &MacAddressDatabase::lookupMacAddressVendorInternal, m_currentReply->macAddress());
|
||||||
|
#endif
|
||||||
m_futureWatcher->setFuture(future);
|
m_futureWatcher->setFuture(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +189,12 @@ QString MacAddressDatabase::lookupMacAddressVendorInternal(const QString &macAdd
|
|||||||
QString searchString = fullMacAddressString.left(length);
|
QString searchString = fullMacAddressString.left(length);
|
||||||
QString queryString = QString("SELECT COUNT(oui) FROM oui WHERE oui LIKE \'%1%\';").arg(searchString);
|
QString queryString = QString("SELECT COUNT(oui) FROM oui WHERE oui LIKE \'%1%\';").arg(searchString);
|
||||||
qCDebug(dcMacAddressDatabase()) << "Query:" << queryString;
|
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()) {
|
if (countQuery.lastError().isValid()) {
|
||||||
qCWarning(dcMacAddressDatabase()) << "Query finished with error" << countQuery.lastError().text();
|
qCWarning(dcMacAddressDatabase()) << "Query finished with error" << countQuery.lastError().text();
|
||||||
break;
|
break;
|
||||||
@ -201,11 +210,16 @@ QString MacAddressDatabase::lookupMacAddressVendorInternal(const QString &macAdd
|
|||||||
// Query the name
|
// Query the name
|
||||||
queryString = QString("SELECT companyName from companyNames WHERE rowid IS (SELECT companyNameIndex FROM oui WHERE oui=\'%1\');").arg(searchString);
|
queryString = QString("SELECT companyName from companyNames WHERE rowid IS (SELECT companyNameIndex FROM oui WHERE oui=\'%1\');").arg(searchString);
|
||||||
qCDebug(dcMacAddressDatabase()) << "Query:" << queryString;
|
qCDebug(dcMacAddressDatabase()) << "Query:" << queryString;
|
||||||
countQuery = m_db.exec(queryString);
|
QSqlQuery rowQuery(m_db);
|
||||||
if (!countQuery.next())
|
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;
|
break;
|
||||||
|
|
||||||
manufacturer = countQuery.value(0).toString();
|
manufacturer = rowQuery.value(0).toString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,9 +32,10 @@
|
|||||||
#include "mqttchannelimplementation.h"
|
#include "mqttchannelimplementation.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
#include <QtDebug>
|
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
#include <QtDebug>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ MqttChannel *MqttProviderImplementation::createChannel(const QHostAddress &clien
|
|||||||
QString clientId;
|
QString clientId;
|
||||||
// Generate a clientId that hasn't been used yet.
|
// Generate a clientId that hasn't been used yet.
|
||||||
do {
|
do {
|
||||||
clientId = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16);
|
clientId = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")).left(16);
|
||||||
} while (m_createdChannels.contains(clientId));
|
} while (m_createdChannels.contains(clientId));
|
||||||
|
|
||||||
return createChannel(clientId, clientAddress, topicPrefixList);
|
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)
|
MqttChannel *MqttProviderImplementation::createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList)
|
||||||
{
|
{
|
||||||
QString username = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16);
|
QString username = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")).left(16);
|
||||||
QString password = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16);
|
QString password = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")).left(16);
|
||||||
|
|
||||||
return createChannel(clientId, username, password, clientAddress, topicPrefixList);
|
return createChannel(clientId, username, password, clientAddress, topicPrefixList);
|
||||||
}
|
}
|
||||||
@ -160,8 +161,8 @@ MqttClient *MqttProviderImplementation::createInternalClient(const QString &clie
|
|||||||
|
|
||||||
MqttPolicy policy;
|
MqttPolicy policy;
|
||||||
policy.clientId = clientId;
|
policy.clientId = clientId;
|
||||||
policy.username = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
policy.username = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
|
||||||
policy.password = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
policy.password = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
|
||||||
policy.allowedPublishTopicFilters.append("#");
|
policy.allowedPublishTopicFilters.append("#");
|
||||||
policy.allowedSubscribeTopicFilters.append("#");
|
policy.allowedSubscribeTopicFilters.append("#");
|
||||||
m_broker->updatePolicy(policy);
|
m_broker->updatePolicy(policy);
|
||||||
|
|||||||
@ -137,13 +137,15 @@ void NetworkAccessManagerImpl::setEnabled(bool enabled)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled) {
|
// FIXME Qt6: disabeling the networkmanager should be updated with the new hardware resource methods
|
||||||
m_manager->setNetworkAccessible(QNetworkAccessManager::Accessible);
|
|
||||||
qCDebug(dcNetworkManager()) << "Network Manager enabled";
|
// if (enabled) {
|
||||||
} else {
|
// m_manager->setNetworkAccessible(QNetworkAccessManager::Accessible);
|
||||||
m_manager->setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
// qCDebug(dcNetworkManager()) << "Network Manager enabled";
|
||||||
qCDebug(dcNetworkManager()) << "Network Manager disabled";
|
// } else {
|
||||||
}
|
// m_manager->setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
||||||
|
// qCDebug(dcNetworkManager()) << "Network Manager disabled";
|
||||||
|
// }
|
||||||
m_enabled = enabled;
|
m_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,8 +55,8 @@
|
|||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
#include <QXmlStreamWriter>
|
#include <QXmlStreamWriter>
|
||||||
#include <QNetworkConfiguration>
|
#include <QRegularExpression>
|
||||||
#include <QNetworkConfigurationManager>
|
#include <QStringView>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
@ -70,10 +70,13 @@ UpnpDiscoveryImplementation::UpnpDiscoveryImplementation(QNetworkAccessManager *
|
|||||||
m_notificationTimer->setSingleShot(false);
|
m_notificationTimer->setSingleShot(false);
|
||||||
connect(m_notificationTimer, &QTimer::timeout, this, &UpnpDiscoveryImplementation::notificationTimeout);
|
connect(m_notificationTimer, &QTimer::timeout, this, &UpnpDiscoveryImplementation::notificationTimeout);
|
||||||
|
|
||||||
QNetworkConfigurationManager *configManager = new QNetworkConfigurationManager(this);
|
// FIXME Qt6: maybe we can use udev in order to detect network configuration changes, centralized,
|
||||||
connect(configManager, &QNetworkConfigurationManager::configurationAdded, this, &UpnpDiscoveryImplementation::networkConfigurationChanged);
|
// also available for integration plugins since there are some examples
|
||||||
connect(configManager, &QNetworkConfigurationManager::configurationRemoved, this, &UpnpDiscoveryImplementation::networkConfigurationChanged);
|
|
||||||
connect(configManager, &QNetworkConfigurationManager::configurationChanged, this, &UpnpDiscoveryImplementation::networkConfigurationChanged);
|
// 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;
|
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...
|
// 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);
|
NymeaSettings globalSettings(NymeaSettings::SettingsRoleGlobal);
|
||||||
globalSettings.beginGroup("nymead");
|
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.endGroup();
|
||||||
|
|
||||||
globalSettings.beginGroup("WebServer");
|
globalSettings.beginGroup("WebServer");
|
||||||
@ -184,12 +187,17 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int
|
|||||||
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
||||||
QByteArray rootdeviceResponseMessage = QByteArray("HTTP/1.1 200 OK\r\n"
|
QByteArray rootdeviceResponseMessage = QByteArray("HTTP/1.1 200 OK\r\n"
|
||||||
"CACHE-CONTROL: max-age=1900\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"
|
"EXT:\r\n"
|
||||||
"LOCATION: " + locationString.toUtf8() + "\r\n"
|
"LOCATION: " + locationString.toUtf8() +
|
||||||
"SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n"
|
"\r\n"
|
||||||
|
"SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) +
|
||||||
|
" UPnP/1.1 \r\n"
|
||||||
"ST: upnp:rootdevice\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");
|
"\r\n");
|
||||||
|
|
||||||
qCDebug(dcUpnp()) << QString("Sending response to %1:%2").arg(host.toString()).arg(port);
|
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.isStartElement()) {
|
||||||
if (xml.name().toString() == "device") {
|
if (xml.name().toString() == "device") {
|
||||||
while (!xml.atEnd()) {
|
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());
|
upnpDeviceDescriptor.setDeviceType(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "friendlyName" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("friendlyName") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setFriendlyName(xml.readElementText());
|
upnpDeviceDescriptor.setFriendlyName(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "manufacturer" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("manufacturer") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setManufacturer(xml.readElementText());
|
upnpDeviceDescriptor.setManufacturer(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "manufacturerURL" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("manufacturerURL") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setManufacturerURL(QUrl(xml.readElementText()));
|
upnpDeviceDescriptor.setManufacturerURL(QUrl(xml.readElementText()));
|
||||||
}
|
}
|
||||||
if (xml.name() == "modelDescription" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("modelDescription") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setModelDescription(xml.readElementText());
|
upnpDeviceDescriptor.setModelDescription(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "modelName" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("modelName") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setModelName(xml.readElementText());
|
upnpDeviceDescriptor.setModelName(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "modelNumber" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("modelNumber") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setModelNumber(xml.readElementText());
|
upnpDeviceDescriptor.setModelNumber(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "modelURL" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("modelURL") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setModelURL(QUrl(xml.readElementText()));
|
upnpDeviceDescriptor.setModelURL(QUrl(xml.readElementText()));
|
||||||
}
|
}
|
||||||
if (xml.name() == "serialNumber" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("serialNumber") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setSerialNumber(xml.readElementText());
|
upnpDeviceDescriptor.setSerialNumber(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "UDN" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("UDN") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setUuid(xml.readElementText());
|
upnpDeviceDescriptor.setUuid(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "uuid" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("uuid") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setUuid(xml.readElementText());
|
upnpDeviceDescriptor.setUuid(xml.readElementText());
|
||||||
}
|
}
|
||||||
if (xml.name() == "UPC" && xml.isStartElement()) {
|
if (xml.name() == QLatin1StringView("UPC") && xml.isStartElement()) {
|
||||||
upnpDeviceDescriptor.setUpc(xml.readElementText());
|
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();
|
||||||
}
|
}
|
||||||
xml.readNext();
|
xml.readNext();
|
||||||
@ -403,14 +450,14 @@ void UpnpDiscoveryImplementation::sendByeByeMessage()
|
|||||||
|
|
||||||
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
||||||
QByteArray byebyeMessage = QByteArray("NOTIFY * HTTP/1.1\r\n"
|
QByteArray byebyeMessage = QByteArray("NOTIFY * HTTP/1.1\r\n"
|
||||||
"HOST:239.255.255.250:1900\r\n"
|
"HOST:239.255.255.250:1900\r\n"
|
||||||
"CACHE-CONTROL: max-age=1900\r\n"
|
"CACHE-CONTROL: max-age=1900\r\n"
|
||||||
"LOCATION: " + locationString.toUtf8() + "\r\n"
|
"LOCATION: " + locationString.toUtf8() + "\r\n"
|
||||||
"NT:urn:schemas-upnp-org:device:Basic:1\r\n"
|
"NT:urn:schemas-upnp-org:device:Basic:1\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"
|
||||||
"NTS: ssdp:byebye\r\n"
|
"NTS: ssdp:byebye\r\n"
|
||||||
"SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n"
|
"SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
sendToMulticast(byebyeMessage);
|
sendToMulticast(byebyeMessage);
|
||||||
}
|
}
|
||||||
@ -449,14 +496,14 @@ void UpnpDiscoveryImplementation::sendAliveMessage()
|
|||||||
|
|
||||||
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
||||||
QByteArray aliveMessage = QByteArray("NOTIFY * HTTP/1.1\r\n"
|
QByteArray aliveMessage = QByteArray("NOTIFY * HTTP/1.1\r\n"
|
||||||
"HOST:239.255.255.250:1900\r\n"
|
"HOST:239.255.255.250:1900\r\n"
|
||||||
"CACHE-CONTROL: max-age=1900\r\n"
|
"CACHE-CONTROL: max-age=1900\r\n"
|
||||||
"LOCATION: " + locationString.toUtf8() + "\r\n"
|
"LOCATION: " + locationString.toUtf8() + "\r\n"
|
||||||
"NT:urn:schemas-upnp-org:device:Basic:1\r\n"
|
"NT:urn:schemas-upnp-org:device:Basic:1\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"
|
||||||
"NTS: ssdp:alive\r\n"
|
"NTS: ssdp:alive\r\n"
|
||||||
"SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n"
|
"SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
sendToMulticast(aliveMessage);
|
sendToMulticast(aliveMessage);
|
||||||
}
|
}
|
||||||
@ -485,14 +532,14 @@ void UpnpDiscoveryImplementation::discoverTimeout()
|
|||||||
delete discoveryRequest;
|
delete discoveryRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpnpDiscoveryImplementation::networkConfigurationChanged(const QNetworkConfiguration &config)
|
// void UpnpDiscoveryImplementation::networkConfigurationChanged(const QNetworkConfiguration &config)
|
||||||
{
|
// {
|
||||||
Q_UNUSED(config)
|
// Q_UNUSED(config)
|
||||||
if (m_enabled) {
|
// if (m_enabled) {
|
||||||
disable();
|
// disable();
|
||||||
enable();
|
// enable();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
bool UpnpDiscoveryImplementation::enable()
|
bool UpnpDiscoveryImplementation::enable()
|
||||||
{
|
{
|
||||||
@ -531,7 +578,11 @@ bool UpnpDiscoveryImplementation::enable()
|
|||||||
m_available = true;
|
m_available = true;
|
||||||
emit availableChanged(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)));
|
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
|
||||||
|
#endif
|
||||||
connect(m_socket, &QUdpSocket::readyRead, this, &UpnpDiscoveryImplementation::readData);
|
connect(m_socket, &QUdpSocket::readyRead, this, &UpnpDiscoveryImplementation::readData);
|
||||||
|
|
||||||
m_notificationTimer->start();
|
m_notificationTimer->start();
|
||||||
|
|||||||
@ -94,7 +94,7 @@ private slots:
|
|||||||
void sendAliveMessage();
|
void sendAliveMessage();
|
||||||
void discoverTimeout();
|
void discoverTimeout();
|
||||||
|
|
||||||
void networkConfigurationChanged(const QNetworkConfiguration &config);
|
//void networkConfigurationChanged(const QNetworkConfiguration &config);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool enable();
|
bool enable();
|
||||||
|
|||||||
@ -41,7 +41,11 @@ Radio433BrennenstuhlGateway::Radio433BrennenstuhlGateway(QObject *parent) :
|
|||||||
// UDP socket to sending data to gateway
|
// UDP socket to sending data to gateway
|
||||||
m_gateway = new QUdpSocket(this);
|
m_gateway = new QUdpSocket(this);
|
||||||
connect(m_gateway, &QUdpSocket::readyRead, this, &Radio433BrennenstuhlGateway::readData);
|
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)));
|
connect(m_gateway, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(gatewayError(QAbstractSocket::SocketError)));
|
||||||
|
#endif
|
||||||
|
|
||||||
// Timer for discovery of the Gateway
|
// Timer for discovery of the Gateway
|
||||||
m_discoverTimer = new QTimer(this);
|
m_discoverTimer = new QTimer(this);
|
||||||
@ -62,7 +66,7 @@ bool Radio433BrennenstuhlGateway::sendData(int delay, QList<int> rawData, int re
|
|||||||
|
|
||||||
// bring rawData list to a single ByteArray, values separated by ','
|
// bring rawData list to a single ByteArray, values separated by ','
|
||||||
foreach (int value, rawData) {
|
foreach (int value, rawData) {
|
||||||
data.append(QString::number(value) + ",");
|
data.append(QString("%1,").arg(value).toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Protocol:
|
/* Protocol:
|
||||||
@ -79,7 +83,7 @@ bool Radio433BrennenstuhlGateway::sendData(int delay, QList<int> rawData, int re
|
|||||||
* ; | end of command
|
* ; | 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) {
|
if (m_gateway->writeDatagram(message, m_gatewayAddress, m_port) > 0) {
|
||||||
m_available = true;
|
m_available = true;
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "libnymea.h"
|
#include <libnymea.h>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "nymeasettings.h"
|
#include "nymeasettings.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
@ -46,7 +47,7 @@ PluginInfoCache::PluginInfoCache()
|
|||||||
|
|
||||||
void PluginInfoCache::cachePluginInfo(const QJsonObject &metaData)
|
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/";
|
QDir path = NymeaSettings::cachePath() + "/plugininfo/";
|
||||||
if (!path.exists()) {
|
if (!path.exists()) {
|
||||||
if (!path.mkpath(path.absolutePath())) {
|
if (!path.mkpath(path.absolutePath())) {
|
||||||
@ -65,7 +66,7 @@ void PluginInfoCache::cachePluginInfo(const QJsonObject &metaData)
|
|||||||
|
|
||||||
QJsonObject PluginInfoCache::loadPluginInfo(const PluginId &pluginId)
|
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/";
|
QDir path = NymeaSettings::cachePath() + "/plugininfo/";
|
||||||
QFile file(path.absoluteFilePath(fileName));
|
QFile file(path.absoluteFilePath(fileName));
|
||||||
if (!file.open(QFile::ReadOnly)) {
|
if (!file.open(QFile::ReadOnly)) {
|
||||||
|
|||||||
@ -15,28 +15,28 @@ PyObject *QVariantToPyObject(const QVariant &value)
|
|||||||
{
|
{
|
||||||
PyObject *pyValue = nullptr;
|
PyObject *pyValue = nullptr;
|
||||||
|
|
||||||
switch (value.type()) {
|
switch (static_cast<int>(value.type())) {
|
||||||
case QVariant::Bool:
|
case QMetaType::Bool:
|
||||||
pyValue = PyBool_FromLong(value.toBool());
|
pyValue = PyBool_FromLong(value.toBool());
|
||||||
break;
|
break;
|
||||||
case QVariant::Int:
|
case QMetaType::Int:
|
||||||
case QVariant::UInt:
|
case QMetaType::UInt:
|
||||||
case QVariant::LongLong:
|
case QMetaType::LongLong:
|
||||||
case QVariant::ULongLong:
|
case QMetaType::ULongLong:
|
||||||
pyValue = PyLong_FromLongLong(value.toLongLong());
|
pyValue = PyLong_FromLongLong(value.toLongLong());
|
||||||
break;
|
break;
|
||||||
case QVariant::String:
|
case QMetaType::QString:
|
||||||
case QVariant::ByteArray:
|
case QMetaType::QByteArray:
|
||||||
pyValue = PyUnicode_FromString(value.toString().toUtf8());
|
pyValue = PyUnicode_FromString(value.toString().toUtf8());
|
||||||
break;
|
break;
|
||||||
case QVariant::Double:
|
case QMetaType::Double:
|
||||||
pyValue = PyFloat_FromDouble(value.toDouble());
|
pyValue = PyFloat_FromDouble(value.toDouble());
|
||||||
break;
|
break;
|
||||||
case QVariant::Invalid:
|
case QMetaType::UnknownType:
|
||||||
pyValue = Py_None;
|
pyValue = Py_None;
|
||||||
Py_INCREF(pyValue);
|
Py_INCREF(pyValue);
|
||||||
break;
|
break;
|
||||||
case QVariant::DateTime: {
|
case QMetaType::QDateTime: {
|
||||||
PyObject *longObj = PyLong_FromLongLong(value.toDateTime().toMSecsSinceEpoch() / 1000);
|
PyObject *longObj = PyLong_FromLongLong(value.toDateTime().toMSecsSinceEpoch() / 1000);
|
||||||
PyObject *timeTuple = Py_BuildValue("(O)", longObj);
|
PyObject *timeTuple = Py_BuildValue("(O)", longObj);
|
||||||
pyValue = PyDateTime_FromTimestamp(timeTuple);
|
pyValue = PyDateTime_FromTimestamp(timeTuple);
|
||||||
@ -44,7 +44,7 @@ PyObject *QVariantToPyObject(const QVariant &value)
|
|||||||
Py_DECREF(timeTuple);
|
Py_DECREF(timeTuple);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QVariant::StringList: {
|
case QMetaType::QStringList: {
|
||||||
QStringList stringList = value.toStringList();
|
QStringList stringList = value.toStringList();
|
||||||
pyValue = PyTuple_New(stringList.length());
|
pyValue = PyTuple_New(stringList.length());
|
||||||
for (int i = 0; i < stringList.count(); i++) {
|
for (int i = 0; i < stringList.count(); i++) {
|
||||||
|
|||||||
@ -76,8 +76,8 @@ bool ScriptIntegrationPlugin::loadScript(const QString &fileName)
|
|||||||
spacer += ' ';
|
spacer += ' ';
|
||||||
}
|
}
|
||||||
QDebug dbg = qWarning(dcThingManager()).nospace().noquote();
|
QDebug dbg = qWarning(dcThingManager()).nospace().noquote();
|
||||||
dbg << metaDataFileName << ":" << lineIndex << ":" << errorOffset + 2 << ": error: JSON parsing failed: " << error.errorString() << ": " << data.trimmed() << endl;
|
dbg << metaDataFileName << ":" << lineIndex << ":" << errorOffset + 2 << ": error: JSON parsing failed: " << error.errorString() << ": " << data.trimmed() << '\n';
|
||||||
dbg << data << endl;
|
dbg << data << '\n';
|
||||||
dbg << spacer << "^";
|
dbg << spacer << "^";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,6 +71,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QMetaEnum>
|
#include <QMetaEnum>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
ThingManagerImplementation::ThingManagerImplementation(HardwareManager *hardwareManager, LogEngine *logEngine, const QLocale &locale, QObject *parent) :
|
ThingManagerImplementation::ThingManagerImplementation(HardwareManager *hardwareManager, LogEngine *logEngine, const QLocale &locale, QObject *parent) :
|
||||||
ThingManager(parent),
|
ThingManager(parent),
|
||||||
@ -1962,7 +1963,8 @@ void ThingManagerImplementation::onLoaded()
|
|||||||
void ThingManagerImplementation::cleanupThingStateCache()
|
void ThingManagerImplementation::cleanupThingStateCache()
|
||||||
{
|
{
|
||||||
QDir dir(NymeaSettings::cachePath() + "/thingstates/");
|
QDir dir(NymeaSettings::cachePath() + "/thingstates/");
|
||||||
foreach (const QFileInfo &entry, dir.entryList()) {
|
foreach (const QString &entryString, dir.entryList()) {
|
||||||
|
QFileInfo entry(entryString);
|
||||||
ThingId thingId(entry.baseName());
|
ThingId thingId(entry.baseName());
|
||||||
if (!m_configuredThings.contains(thingId)) {
|
if (!m_configuredThings.contains(thingId)) {
|
||||||
qCDebug(dcThingManager()) << "Thing ID" << thingId.toString() << "not found in configured things. Cleaning up stale thing state cache.";
|
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)
|
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)
|
void ThingManagerImplementation::loadThingStates(Thing *thing)
|
||||||
@ -2331,8 +2333,17 @@ void ThingManagerImplementation::loadThingStates(Thing *thing)
|
|||||||
value = settings->value(stateType.id().toString());
|
value = settings->value(stateType.id().toString());
|
||||||
}
|
}
|
||||||
value.convert(stateType.type());
|
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;
|
QVariantList convertedPossibleValues;
|
||||||
foreach (QVariant possibleValue, possibleValues) {
|
foreach (QVariant possibleValue, possibleValues) {
|
||||||
possibleValue.convert(stateType.type());
|
possibleValue.convert(stateType.type());
|
||||||
@ -2409,12 +2420,12 @@ void ThingManagerImplementation::registerStateLogger(Thing *thing, const StateTy
|
|||||||
{
|
{
|
||||||
StateType stateType = thing->thingClass().getStateType(stateTypeId);
|
StateType stateType = thing->thingClass().getStateType(stateTypeId);
|
||||||
QString name = thing->id().toString() + "-" + stateType.name();
|
QString name = thing->id().toString() + "-" + stateType.name();
|
||||||
QList<QVariant::Type> sampledTypes {
|
QList<QMetaType::Type> sampledTypes {
|
||||||
QVariant::Int,
|
QMetaType::Int,
|
||||||
QVariant::UInt,
|
QMetaType::UInt,
|
||||||
QVariant::LongLong,
|
QMetaType::LongLong,
|
||||||
QVariant::ULongLong,
|
QMetaType::ULongLong,
|
||||||
QVariant::Double
|
QMetaType::Double
|
||||||
};
|
};
|
||||||
Types::LoggingType loggingType = sampledTypes.contains(stateType.type()) ? Types::LoggingTypeSampled : Types::LoggingTypeDiscrete;
|
Types::LoggingType loggingType = sampledTypes.contains(stateType.type()) ? Types::LoggingTypeSampled : Types::LoggingTypeDiscrete;
|
||||||
Logger *logger = m_logEngine->registerLogSource("state-" + name, {}, loggingType, stateType.name());
|
Logger *logger = m_logEngine->registerLogSource("state-" + name, {}, loggingType, stateType.name());
|
||||||
|
|||||||
@ -29,13 +29,15 @@
|
|||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#include "translator.h"
|
#include "translator.h"
|
||||||
#include "nymeasettings.h"
|
|
||||||
#include "thingmanagerimplementation.h"
|
#include "thingmanagerimplementation.h"
|
||||||
|
|
||||||
#include "loggingcategories.h"
|
#include <nymeasettings.h>
|
||||||
#include "integrations/integrationplugin.h"
|
#include <loggingcategories.h>
|
||||||
#include <QCoreApplication>
|
#include <integrations/integrationplugin.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
Translator::Translator(ThingManagerImplementation *thingManager):
|
Translator::Translator(ThingManagerImplementation *thingManager):
|
||||||
m_thingManager(thingManager)
|
m_thingManager(thingManager)
|
||||||
@ -99,7 +101,7 @@ void Translator::loadTranslator(IntegrationPlugin *plugin, const QLocale &locale
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QString pluginId = plugin->pluginId().toString().remove(QRegExp("[{}]"));
|
QString pluginId = plugin->pluginId().toString().remove(QRegularExpression("[{}]"));
|
||||||
|
|
||||||
foreach (const QString &pluginPath, m_thingManager->pluginSearchDirs()) {
|
foreach (const QString &pluginPath, m_thingManager->pluginSearchDirs()) {
|
||||||
if (translator->load(locale, pluginId, "-", QDir(pluginPath + "/translations/").absolutePath(), ".qm")) {
|
if (translator->load(locale, pluginId, "-", QDir(pluginPath + "/translations/").absolutePath(), ".qm")) {
|
||||||
|
|||||||
@ -753,7 +753,7 @@ QVariantMap ConfigurationHandler::packBasicConfiguration()
|
|||||||
QVariantMap basicConfiguration;
|
QVariantMap basicConfiguration;
|
||||||
basicConfiguration.insert("serverName", NymeaCore::instance()->configuration()->serverName());
|
basicConfiguration.insert("serverName", NymeaCore::instance()->configuration()->serverName());
|
||||||
basicConfiguration.insert("serverUuid", NymeaCore::instance()->configuration()->serverUuid().toString());
|
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("timeZone", QTimeZone::systemTimeZoneId());
|
||||||
basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name());
|
basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name());
|
||||||
basicConfiguration.insert("location", QVariantMap{
|
basicConfiguration.insert("location", QVariantMap{
|
||||||
|
|||||||
@ -76,6 +76,7 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QSslConfiguration>
|
#include <QSslConfiguration>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
@ -698,7 +699,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
|||||||
|
|
||||||
qCDebug(dcJsonRpc()) << "Invoking method" << targetNamespace + '.' + method << "from client" << clientId;
|
qCDebug(dcJsonRpc()) << "Invoking method" << targetNamespace + '.' + method << "from client" << clientId;
|
||||||
|
|
||||||
JsonReply *reply;
|
JsonReply *reply = nullptr;
|
||||||
if (handler->metaObject()->indexOfMethod(method.toUtf8() + "(QVariantMap,JsonContext)") >= 0) {
|
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));
|
QMetaObject::invokeMethod(handler, method.toUtf8().data(), Q_RETURN_ARG(JsonReply*, reply), Q_ARG(QVariantMap, params), Q_ARG(JsonContext, callContext));
|
||||||
} else {
|
} else {
|
||||||
@ -861,12 +862,18 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler)
|
|||||||
// Sanity checks on API:
|
// Sanity checks on API:
|
||||||
// * Make sure all $ref: entries are valid.
|
// * 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.
|
// * 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 methods = m_api.value("methods").toMap();
|
||||||
QVariantMap notifications = m_api.value("notifications").toMap();
|
QVariantMap notifications = m_api.value("notifications").toMap();
|
||||||
|
|
||||||
QVariantMap apiIncludingThis = m_api;
|
QVariantMap apiIncludingThis = m_api;
|
||||||
|
|
||||||
// Verify enums name clash
|
// Verify enums name clash
|
||||||
QVariantMap enums = m_api.value("enums").toMap();
|
|
||||||
foreach (const QString &enumName, handler->jsonEnums().keys()) {
|
foreach (const QString &enumName, handler->jsonEnums().keys()) {
|
||||||
QVariantList list = handler->jsonEnums().value(enumName).toList();
|
QVariantList list = handler->jsonEnums().value(enumName).toList();
|
||||||
if (enums.contains(enumName) && enums.value(enumName) != list) {
|
if (enums.contains(enumName) && enums.value(enumName) != list) {
|
||||||
@ -877,7 +884,6 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler)
|
|||||||
}
|
}
|
||||||
apiIncludingThis["enums"] = enums;
|
apiIncludingThis["enums"] = enums;
|
||||||
|
|
||||||
QVariantMap flags = m_api.value("flags").toMap();
|
|
||||||
foreach (const QString &flagName, handler->jsonFlags().keys()) {
|
foreach (const QString &flagName, handler->jsonFlags().keys()) {
|
||||||
QVariant flagDescription = handler->jsonFlags().value(flagName);
|
QVariant flagDescription = handler->jsonFlags().value(flagName);
|
||||||
if (enums.contains(flagName)) {
|
if (enums.contains(flagName)) {
|
||||||
@ -893,17 +899,21 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler)
|
|||||||
apiIncludingThis["flags"] = flags;
|
apiIncludingThis["flags"] = flags;
|
||||||
|
|
||||||
// Verify objects
|
// Verify objects
|
||||||
QVariantMap existingTypes = m_api.value("types").toMap();
|
QVariantMap typesIncludingThis = types;
|
||||||
QVariantMap typesIncludingThis = existingTypes;
|
foreach (const QString &objectName, handler->jsonObjects().keys()) {
|
||||||
typesIncludingThis.unite(handler->jsonObjects());
|
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;
|
apiIncludingThis["types"] = typesIncludingThis;
|
||||||
foreach (const QString &objectName, handler->jsonObjects().keys()) {
|
foreach (const QString &objectName, handler->jsonObjects().keys()) {
|
||||||
QVariantMap object = handler->jsonObjects().value(objectName).toMap();
|
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
|
// Check for invalid $ref: entries
|
||||||
if (!JsonValidator::checkRefs(object, apiIncludingThis)) {
|
if (!JsonValidator::checkRefs(object, apiIncludingThis)) {
|
||||||
qCWarning(dcJsonRpc()).nospace() << "Invalid reference in object type " << objectName << ". Not registering handler " << handler->name();
|
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();
|
QVariantMap method = handler->jsonMethods().value(methodName).toMap();
|
||||||
|
|
||||||
if (handler->metaObject()->indexOfMethod(methodName.toUtf8() + "(QVariantMap)") < 0
|
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();
|
qCWarning(dcJsonRpc()).nospace().noquote() << "Invalid method \"" << methodName << "\". Method \"JsonReply* " + methodName + "(QVariantMap,JsonContext)\" does not exist. Not registering handler " << handler->name();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -931,7 +941,16 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler)
|
|||||||
}
|
}
|
||||||
newMethods.insert(handler->name() + '.' + methodName, method);
|
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;
|
apiIncludingThis["methods"] = methods;
|
||||||
|
|
||||||
// Verify notifications
|
// Verify notifications
|
||||||
@ -944,7 +963,17 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler)
|
|||||||
}
|
}
|
||||||
newNotifications.insert(handler->name() + '.' + notificationName, notification);
|
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;
|
apiIncludingThis["notifications"] = notifications;
|
||||||
|
|
||||||
// Checks completed. Store new API
|
// Checks completed. Store new API
|
||||||
@ -954,10 +983,10 @@ bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler)
|
|||||||
m_handlers.insert(handler->name(), handler);
|
m_handlers.insert(handler->name(), handler);
|
||||||
for (int i = 0; i < handler->metaObject()->methodCount(); ++i) {
|
for (int i = 0; i < handler->metaObject()->methodCount(); ++i) {
|
||||||
QMetaMethod method = handler->metaObject()->method(i);
|
QMetaMethod method = handler->metaObject()->method(i);
|
||||||
if (method.methodType() == QMetaMethod::Signal && QString(method.name()).contains(QRegExp("^[A-Z]"))) {
|
if (method.methodType() == QMetaMethod::Signal && QString(method.name()).contains(QRegularExpression("^[A-Z]"))) {
|
||||||
if (method.parameterCount() == 1 && method.parameterType(0) == QVariant::Map) {
|
if (method.parameterCount() == 1 && method.parameterType(0) == QMetaType::QVariantMap) {
|
||||||
QObject::connect(handler, method, this, metaObject()->method(metaObject()->indexOfSlot("sendNotification(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)")));
|
QObject::connect(handler, method, this, metaObject()->method(metaObject()->indexOfSlot("sendClientNotification(QUuid,QVariantMap)")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,19 +104,19 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QVariantMap m_api;
|
QVariantMap m_api;
|
||||||
QHash<JsonHandler*, QString> m_experiences;
|
QHash<JsonHandler *, QString> m_experiences;
|
||||||
QHash<QString, JsonHandler *> m_handlers;
|
QHash<QString, JsonHandler *> m_handlers;
|
||||||
QHash<JsonReply *, TransportInterface *> m_asyncReplies;
|
QHash<JsonReply *, TransportInterface *> m_asyncReplies;
|
||||||
|
|
||||||
QHash<QUuid, TransportInterface*> m_clientTransports;
|
QHash<QUuid, TransportInterface *> m_clientTransports;
|
||||||
QHash<QUuid, QByteArray> m_clientBuffers;
|
QHash<QUuid, QByteArray> m_clientBuffers;
|
||||||
QHash<QUuid, QStringList> m_clientNotifications;
|
QHash<QUuid, QStringList> m_clientNotifications;
|
||||||
QHash<QUuid, QLocale> m_clientLocales;
|
QHash<QUuid, QLocale> m_clientLocales;
|
||||||
QHash<QUuid, QByteArray> m_clientTokens;
|
QHash<QUuid, QByteArray> m_clientTokens;
|
||||||
QHash<int, QUuid> m_pushButtonTransactions;
|
QHash<int, QUuid> m_pushButtonTransactions;
|
||||||
QHash<QUuid, QTimer*> m_newConnectionWaitTimers;
|
QHash<QUuid, QTimer *> m_newConnectionWaitTimers;
|
||||||
|
|
||||||
QHash<QString, JsonReply*> m_pairingRequests;
|
QHash<QString, JsonReply *> m_pairingRequests;
|
||||||
|
|
||||||
int m_notificationId;
|
int m_notificationId;
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
@ -48,26 +49,26 @@ bool JsonValidator::checkRefs(const QVariantMap &map, const QVariantMap &api)
|
|||||||
if (map.value(key).toString().startsWith("$ref:")) {
|
if (map.value(key).toString().startsWith("$ref:")) {
|
||||||
QString refName = map.value(key).toString().remove("$ref:");
|
QString refName = map.value(key).toString().remove("$ref:");
|
||||||
if (!enums.contains(refName) && !flags.contains(refName) && !types.contains(refName)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (map.value(key).type() == QVariant::Map) {
|
if (map.value(key).userType() == QMetaType::QVariantMap) {
|
||||||
bool ret = checkRefs(map.value(key).toMap(), api);
|
bool ret = checkRefs(map.value(key).toMap(), api);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (map.value(key).type() == QVariant::List) {
|
if (map.value(key).userType() == QMetaType::QVariantList) {
|
||||||
foreach (const QVariant &entry, map.value(key).toList()) {
|
foreach (const QVariant &entry, map.value(key).toList()) {
|
||||||
if (entry.toString().startsWith("$ref:")) {
|
if (entry.toString().startsWith("$ref:")) {
|
||||||
QString refName = entry.toString().remove("$ref:");
|
QString refName = entry.toString().remove("$ref:");
|
||||||
if (!enums.contains(refName) && !flags.contains(refName) && !types.contains(refName)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry.type() == QVariant::Map) {
|
if (entry.userType() == QMetaType::QVariantMap) {
|
||||||
bool ret = checkRefs(map.value(key).toMap(), api);
|
bool ret = checkRefs(map.value(key).toMap(), api);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return false;
|
return false;
|
||||||
@ -113,16 +114,16 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q
|
|||||||
{
|
{
|
||||||
// Make sure all required values are available
|
// Make sure all required values are available
|
||||||
foreach (const QString &key, definition.keys()) {
|
foreach (const QString &key, definition.keys()) {
|
||||||
QRegExp isOptional = QRegExp("^([a-z]:)*o:.*");
|
QRegularExpression isOptional = QRegularExpression("^([a-z]:)*o:.*");
|
||||||
if (isOptional.exactMatch(key)) {
|
if (isOptional.match(key).hasMatch()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QRegExp isReadOnly = QRegExp("^([a-z]:)*r:.*");
|
QRegularExpression isReadOnly = QRegularExpression("^([a-z]:)*r:.*");
|
||||||
if (isReadOnly.exactMatch(key) && openMode.testFlag(QIODevice::WriteOnly)) {
|
if (isReadOnly.match(key).hasMatch() && openMode.testFlag(QIODevice::WriteOnly)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QString trimmedKey = key;
|
QString trimmedKey = key;
|
||||||
trimmedKey.remove(QRegExp("^(o:|r:|d:)*"));
|
trimmedKey.remove(QRegularExpression("^(o:|r:|d:)*"));
|
||||||
if (!map.contains(trimmedKey)) {
|
if (!map.contains(trimmedKey)) {
|
||||||
return Result(false, "Missing required key: " + key, key);
|
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?
|
// Is the key allowed in here?
|
||||||
QVariant expectedValue = definition.value(key);
|
QVariant expectedValue = definition.value(key);
|
||||||
foreach (const QString &definitionKey, definition.keys()) {
|
foreach (const QString &definitionKey, definition.keys()) {
|
||||||
QRegExp regExp = QRegExp("(o:|r:|d:)*" + key);
|
QRegularExpression regExp = QRegularExpression("(o:|r:|d:)" + key);
|
||||||
if (regExp.exactMatch(definitionKey)) {
|
if (regExp.match(definitionKey).hasMatch()) {
|
||||||
expectedValue = definition.value(definitionKey);
|
expectedValue = definition.value(definitionKey);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!expectedValue.isValid()) {
|
if (!expectedValue.isValid()) {
|
||||||
@ -158,14 +160,14 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result(true);
|
return Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const QVariant &definition, const QVariantMap &api, QIODevice::OpenMode openMode)
|
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();
|
QString expectedTypeName = definition.toString();
|
||||||
|
|
||||||
if (expectedTypeName.startsWith("$ref:")) {
|
if (expectedTypeName.startsWith("$ref:")) {
|
||||||
@ -178,16 +180,31 @@ JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const
|
|||||||
QVariant refDefinition = enums.value(refName);
|
QVariant refDefinition = enums.value(refName);
|
||||||
|
|
||||||
QVariantList enumList = refDefinition.toList();
|
QVariantList enumList = refDefinition.toList();
|
||||||
if (!enumList.contains(value.toString())) {
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
return Result(false, "Expected enum value for" + refName + " but got " + value.toString());
|
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);
|
return Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Or flags
|
// Or flags
|
||||||
QVariantMap flags = api.value("flags").toMap();
|
QVariantMap flags = api.value("flags").toMap();
|
||||||
if (flags.contains(refName)) {
|
if (flags.contains(refName)) {
|
||||||
QVariant refDefinition = flags.value(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());
|
return Result(false, "Expected flags " + refName + " but got " + value.toString());
|
||||||
}
|
}
|
||||||
QString flagEnum = refDefinition.toList().first().toString();
|
QString flagEnum = refDefinition.toList().first().toString();
|
||||||
@ -206,7 +223,23 @@ JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonHandler::BasicType expectedBasicType = JsonHandler::enumNameToValue<JsonHandler::BasicType>(expectedTypeName);
|
JsonHandler::BasicType expectedBasicType = JsonHandler::enumNameToValue<JsonHandler::BasicType>(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
|
// Verify basic compatiblity
|
||||||
if (expectedBasicType != JsonHandler::Variant && !value.canConvert(expectedVariantType)) {
|
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()) {
|
if (expectedBasicType == JsonHandler::Uuid && value.toUuid().isNull()) {
|
||||||
return Result(false, "Invalid Uuid: " + value.toString());
|
return Result(false, "Invalid Uuid: " + value.toString());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Make sure ints are valid
|
// Make sure ints are valid
|
||||||
if (expectedBasicType == JsonHandler::Int) {
|
if (expectedBasicType == JsonHandler::Int) {
|
||||||
bool ok;
|
bool ok;
|
||||||
@ -260,18 +295,27 @@ JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const
|
|||||||
return Result(true);
|
return Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (definition.type() == QVariant::Map) {
|
if (definition.userType() == QMetaType::QVariantMap) {
|
||||||
if (value.type() != QVariant::Map) {
|
if (value.userType() != QMetaType::QVariantMap) {
|
||||||
return Result(false, "Invalid value. Expected a map but received: " + value.toString());
|
return Result(false, "Invalid value. Expected a map but received: " + value.toString());
|
||||||
}
|
}
|
||||||
return validateMap(value.toMap(), definition.toMap(), api, openMode);
|
return validateMap(value.toMap(), definition.toMap(), api, openMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (definition.type() == QVariant::List) {
|
if (definition.userType() == QMetaType::QVariantList) {
|
||||||
QVariantList list = definition.toList();
|
QVariantList list = definition.toList();
|
||||||
QVariant entryDefinition = list.first();
|
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()) {
|
foreach (const QVariant &entry, value.toList()) {
|
||||||
Result result = validateEntry(entry, entryDefinition, api, openMode);
|
Result result = validateEntry(entry, entryDefinition, api, openMode);
|
||||||
|
|||||||
@ -672,9 +672,11 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network)
|
|||||||
case Zigbee::ZigbeeBackendTypeNxp:
|
case Zigbee::ZigbeeBackendTypeNxp:
|
||||||
networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeNxp));
|
networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeNxp));
|
||||||
break;
|
break;
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
case Zigbee::ZigbeeBackendTypeTi:
|
case Zigbee::ZigbeeBackendTypeTi:
|
||||||
networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeTi));
|
networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeTi));
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (network->state()) {
|
switch (network->state()) {
|
||||||
|
|||||||
@ -3,38 +3,13 @@ TARGET = nymea-core
|
|||||||
|
|
||||||
include(../nymea.pri)
|
include(../nymea.pri)
|
||||||
|
|
||||||
QT += bluetooth dbus qml sql websockets serialport
|
QT += core bluetooth dbus qml sql websockets serialport
|
||||||
INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir
|
INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir
|
||||||
LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto
|
LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto
|
||||||
|
|
||||||
CONFIG += link_pkgconfig
|
CONFIG += link_pkgconfig
|
||||||
PKGCONFIG += nymea-mqtt nymea-networkmanager nymea-zigbee nymea-remoteproxyclient nymea-gpio
|
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) {
|
packagesExist(systemd) {
|
||||||
message(Building with systemd support)
|
message(Building with systemd support)
|
||||||
PKGCONFIG += systemd
|
PKGCONFIG += systemd
|
||||||
@ -43,12 +18,25 @@ packagesExist(systemd) {
|
|||||||
message(Building without systemd support)
|
message(Building without systemd support)
|
||||||
}
|
}
|
||||||
|
|
||||||
packagesExist(Qt5SerialBus) {
|
greaterThan(QT_MAJOR_VERSION, 5) {
|
||||||
message("Building with QtSerialBus support.")
|
qtHaveModule(serialbus) {
|
||||||
PKGCONFIG += Qt5SerialBus
|
message("Building with QtSerialBus support.")
|
||||||
DEFINES += WITH_QTSERIALBUS
|
QT *= serialbus
|
||||||
|
DEFINES += WITH_QTSERIALBUS
|
||||||
|
} else {
|
||||||
|
message("QtSerialBus package not found. Building without QtSerialBus support.")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Separate module in Qt6
|
||||||
|
QT *= concurrent
|
||||||
} else {
|
} 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
|
# Note: udev is not available on all platforms
|
||||||
|
|||||||
@ -34,6 +34,7 @@
|
|||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
LogEngineInfluxDB::LogEngineInfluxDB(const QString &host, const QString &dbName, const QString &username, const QString &password, QObject *parent)
|
LogEngineInfluxDB::LogEngineInfluxDB(const QString &host, const QString &dbName, const QString &username, const QString &password, QObject *parent)
|
||||||
: LogEngine{parent},
|
: LogEngine{parent},
|
||||||
@ -185,18 +186,18 @@ void LogEngineInfluxDB::logEvent(Logger *logger, const QStringList &tags, const
|
|||||||
|
|
||||||
foreach (const QString &name, values.keys()) {
|
foreach (const QString &name, values.keys()) {
|
||||||
QVariant value = values.value(name);
|
QVariant value = values.value(name);
|
||||||
switch (value.type()) {
|
switch (value.userType()) {
|
||||||
case QVariant::String:
|
case QMetaType::QString:
|
||||||
case QVariant::ByteArray:
|
case QMetaType::QByteArray:
|
||||||
fieldsList.append(QString("%1=\"%2\"").arg(name).arg(QString(value.toByteArray().toPercentEncoding())));
|
fieldsList.append(QString("%1=\"%2\"").arg(name).arg(QString(value.toByteArray().toPercentEncoding())));
|
||||||
break;
|
break;
|
||||||
case QVariant::Uuid:
|
case QMetaType::QUuid:
|
||||||
fieldsList.append(QString("%1=\"%2\"").arg(name).arg(value.toString()));
|
fieldsList.append(QString("%1=\"%2\"").arg(name).arg(value.toString()));
|
||||||
break;
|
break;
|
||||||
case QVariant::Int:
|
case QMetaType::Int:
|
||||||
case QVariant::UInt:
|
case QMetaType::UInt:
|
||||||
case QVariant::LongLong:
|
case QMetaType::LongLong:
|
||||||
case QVariant::ULongLong:
|
case QMetaType::ULongLong:
|
||||||
fieldsList.append(QString("%1=%2i").arg(name).arg(value.toString()));
|
fieldsList.append(QString("%1=%2i").arg(name).arg(value.toString()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -490,10 +491,10 @@ LogFetchJob *LogEngineInfluxDB::fetchLogEntries(const QStringList &sources, cons
|
|||||||
for (int i = 1; i < columns.count(); i++) {
|
for (int i = 1; i < columns.count(); i++) {
|
||||||
QString column = columns.at(i);
|
QString column = columns.at(i);
|
||||||
if (sampleRate != Types::SampleRateAny) {
|
if (sampleRate != Types::SampleRateAny) {
|
||||||
column.remove(QRegExp("^mean_"));
|
column.remove(QRegularExpression("^mean_"));
|
||||||
}
|
}
|
||||||
QVariant value = values.at(i);
|
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()));
|
valuesMap.insert(column, QByteArray::fromPercentEncoding(value.toByteArray()));
|
||||||
} else {
|
} else {
|
||||||
valuesMap.insert(column, values.at(i));
|
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, "finished", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, status), Q_ARG(QVariantList, results));
|
||||||
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,6 @@
|
|||||||
#ifndef LOGENGINEINFLUXDB_H
|
#ifndef LOGENGINEINFLUXDB_H
|
||||||
#define LOGENGINEINFLUXDB_H
|
#define LOGENGINEINFLUXDB_H
|
||||||
|
|
||||||
#include "logging/logengine.h"
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
@ -40,9 +39,15 @@
|
|||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
|
|
||||||
class QueryJob: public QObject {
|
#include "logging/logentry.h"
|
||||||
|
#include "logging/logengine.h"
|
||||||
|
|
||||||
|
class QueryJob: public QObject
|
||||||
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
public:
|
||||||
explicit QueryJob(const QNetworkRequest &request, bool post, bool isInit, QObject *parent = nullptr);
|
explicit QueryJob(const QNetworkRequest &request, bool post, bool isInit, QObject *parent = nullptr);
|
||||||
|
~QueryJob() = default;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished(QNetworkReply::NetworkError status, const QVariantList &response);
|
void finished(QNetworkReply::NetworkError status, const QVariantList &response);
|
||||||
@ -118,12 +123,13 @@ private:
|
|||||||
|
|
||||||
QHash<QString, Logger*> m_loggers;
|
QHash<QString, Logger*> m_loggers;
|
||||||
|
|
||||||
QQueue<QueryJob*> m_initQueryQueue;
|
QQueue<QueryJob *> m_initQueryQueue;
|
||||||
QueryJob *m_currentInitQuery = nullptr;
|
QueryJob *m_currentInitQuery = nullptr;
|
||||||
QQueue<QueryJob*> m_queryQueue;
|
QQueue<QueryJob *> m_queryQueue;
|
||||||
QueryJob *m_currentQuery = nullptr;
|
QueryJob *m_currentQuery = nullptr;
|
||||||
QQueue<QueueEntry> m_writeQueue;
|
QQueue<QueueEntry> m_writeQueue;
|
||||||
QNetworkReply* m_currentWriteReply = nullptr;
|
QNetworkReply *m_currentWriteReply = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // LOGENGINEINFLUXDB_H
|
#endif // LOGENGINEINFLUXDB_H
|
||||||
|
|||||||
@ -320,7 +320,7 @@ QLocale NymeaConfiguration::locale() const
|
|||||||
{
|
{
|
||||||
NymeaSettings settings(NymeaSettings::SettingsRoleGlobal);
|
NymeaSettings settings(NymeaSettings::SettingsRoleGlobal);
|
||||||
settings.beginGroup("nymead");
|
settings.beginGroup("nymead");
|
||||||
return settings.value("language", "en_US").toString();
|
return QLocale(settings.value("language", "en_US").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NymeaConfiguration::setLocale(const QLocale &locale)
|
void NymeaConfiguration::setLocale(const QLocale &locale)
|
||||||
|
|||||||
@ -243,11 +243,11 @@ void Rule::setActive(const bool &active)
|
|||||||
QDebug operator<<(QDebug dbg, const Rule &rule)
|
QDebug operator<<(QDebug dbg, const Rule &rule)
|
||||||
{
|
{
|
||||||
QDebugStateSaver saver(dbg);
|
QDebugStateSaver saver(dbg);
|
||||||
dbg.nospace() << endl << "=== Rule begin ===" << endl;
|
dbg.nospace() << '\n' << "=== Rule begin ===" << '\n';
|
||||||
dbg.nospace() << "ID:" << rule.id().toString() << endl;
|
dbg.nospace() << "ID:" << rule.id().toString() << '\n';
|
||||||
dbg.nospace() << "Name:" << rule.name() << endl;
|
dbg.nospace() << "Name:" << rule.name() << '\n';
|
||||||
dbg.nospace() << "Enabled:" << rule.enabled() << endl;
|
dbg.nospace() << "Enabled:" << rule.enabled() << '\n';
|
||||||
dbg.nospace() << "Active:" << rule.active() << endl;
|
dbg.nospace() << "Active:" << rule.active() << '\n';
|
||||||
dbg.nospace() << rule.eventDescriptors();
|
dbg.nospace() << rule.eventDescriptors();
|
||||||
dbg.nospace() << rule.timeDescriptor();
|
dbg.nospace() << rule.timeDescriptor();
|
||||||
dbg.nospace() << rule.stateEvaluator();
|
dbg.nospace() << rule.stateEvaluator();
|
||||||
|
|||||||
@ -211,9 +211,9 @@ void RuleAction::operator=(const RuleAction &other)
|
|||||||
QDebug operator<<(QDebug dbg, const RuleAction &ruleAction)
|
QDebug operator<<(QDebug dbg, const RuleAction &ruleAction)
|
||||||
{
|
{
|
||||||
QDebugStateSaver saver(dbg);
|
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++) {
|
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;
|
return dbg;
|
||||||
}
|
}
|
||||||
@ -221,7 +221,7 @@ QDebug operator<<(QDebug dbg, const RuleAction &ruleAction)
|
|||||||
QDebug operator<<(QDebug dbg, const QList<RuleAction> &ruleActionList)
|
QDebug operator<<(QDebug dbg, const QList<RuleAction> &ruleActionList)
|
||||||
{
|
{
|
||||||
QDebugStateSaver saver(dbg);
|
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++ ) {
|
for (int i = 0; i < ruleActionList.count(); i++ ) {
|
||||||
dbg.nospace() << " " << i << ": " << ruleActionList.at(i);
|
dbg.nospace() << " " << i << ": " << ruleActionList.at(i);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -235,9 +235,9 @@ RuleActionParams RuleActionParams::operator<<(const RuleActionParam &ruleActionP
|
|||||||
QDebug operator<<(QDebug dbg, const RuleActionParams &ruleActionParams)
|
QDebug operator<<(QDebug dbg, const RuleActionParams &ruleActionParams)
|
||||||
{
|
{
|
||||||
QDebugStateSaver saver(dbg);
|
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++ ) {
|
for (int i = 0; i < ruleActionParams.count(); i++ ) {
|
||||||
dbg.nospace() << " " << i << ": " << ruleActionParams.at(i) << endl;
|
dbg.nospace() << " " << i << ": " << ruleActionParams.at(i) << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
return dbg;
|
return dbg;
|
||||||
|
|||||||
@ -128,6 +128,8 @@
|
|||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QMetaEnum>
|
#include <QMetaEnum>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
NYMEA_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine")
|
NYMEA_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine")
|
||||||
NYMEA_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug")
|
NYMEA_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug")
|
||||||
@ -185,12 +187,20 @@ QList<Rule> RuleEngine::evaluateEvent(const Event &event)
|
|||||||
}
|
}
|
||||||
ThingClass thingClass = thing->thingClass();
|
ThingClass thingClass = thing->thingClass();
|
||||||
EventType eventType = thingClass.eventTypes().findById(event.eventTypeId());
|
EventType eventType = thingClass.eventTypes().findById(event.eventTypeId());
|
||||||
|
StateType stateType = thingClass.stateTypes().findById(event.eventTypeId());
|
||||||
|
|
||||||
|
if (eventType.isValid()) {
|
||||||
if (event.params().count() == 0) {
|
if (event.params().count() == 0) {
|
||||||
qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event: " << thing->name() << " - " << eventType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << eventType.id().toString() << ")";
|
qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event: " << thing->name() << " - " << eventType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << eventType.id().toString() << ")";
|
||||||
} else {
|
} else {
|
||||||
qCDebug(dcRuleEngineDebug).nospace().noquote() << "Evaluate event: " << thing->name() << " - " << eventType.name() << " (ThingId:" << thing->id().toString() << ", EventTypeId:" << eventType.id().toString() << ")" << endl << " " << event.params();
|
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<Rule> rules;
|
QList<Rule> rules;
|
||||||
@ -342,7 +352,7 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
|||||||
// Check IDs in each EventDescriptor
|
// Check IDs in each EventDescriptor
|
||||||
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
|
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
|
||||||
if (!eventDescriptor.isValid()) {
|
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;
|
return RuleErrorEventTypeNotFound;
|
||||||
}
|
}
|
||||||
if (eventDescriptor.type() == EventDescriptor::TypeThing) {
|
if (eventDescriptor.type() == EventDescriptor::TypeThing) {
|
||||||
@ -375,11 +385,11 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
|||||||
// Interface based event
|
// Interface based event
|
||||||
Interface iface = m_thingManager->supportedInterfaces().findByName(eventDescriptor.interface());
|
Interface iface = m_thingManager->supportedInterfaces().findByName(eventDescriptor.interface());
|
||||||
if (!iface.isValid()) {
|
if (!iface.isValid()) {
|
||||||
qWarning(dcRuleEngine()) << "No such interface:" << eventDescriptor.interface();
|
qCWarning(dcRuleEngine()) << "No such interface:" << eventDescriptor.interface();
|
||||||
return RuleErrorInterfaceNotFound;
|
return RuleErrorInterfaceNotFound;
|
||||||
}
|
}
|
||||||
if (iface.eventTypes().findByName(eventDescriptor.interfaceEvent()).name().isEmpty() && iface.stateTypes().findByName(eventDescriptor.interfaceEvent()).name().isEmpty()) {
|
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;
|
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();
|
qCDebug(dcRuleEngine) << "Executing rule exit actions of rule" << rule.name() << rule.id().toString();
|
||||||
m_logger->log({rule.id().toString(), "executed"}, {{"name", rule.name()}});
|
m_logger->log({rule.id().toString(), "executed"}, {{"name", rule.name()}});
|
||||||
// m_logEngine->logRuleExitActionsExecuted(rule);
|
// m_logEngine->logRuleExitActionsExecuted(rule);
|
||||||
executeRuleActions(rule.id(), rule.exitActions());
|
executeRuleActions(rule.id(), rule.exitActions());
|
||||||
return RuleErrorNoError;
|
return RuleErrorNoError;
|
||||||
}
|
}
|
||||||
@ -892,7 +902,7 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const Thing
|
|||||||
paramValue = event.param(paramDescriptor.paramTypeId()).value();
|
paramValue = event.param(paramDescriptor.paramTypeId()).value();
|
||||||
} else {
|
} else {
|
||||||
if (paramDescriptor.paramName().isEmpty()) {
|
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;
|
allOK = false;
|
||||||
continue;
|
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()) {
|
switch (paramDescriptor.operatorType()) {
|
||||||
case Types::ValueOperatorEquals:
|
case Types::ValueOperatorEquals:
|
||||||
if (paramValue != paramDescriptor.value()) {
|
if (paramValue != paramDescriptor.value()) {
|
||||||
@ -939,6 +990,7 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const Thing
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
// All matching!
|
// All matching!
|
||||||
if (allOK) {
|
if (allOK) {
|
||||||
@ -981,7 +1033,7 @@ bool RuleEngine::containsState(const StateEvaluator &stateEvaluator, const Event
|
|||||||
RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction, const Rule &rule)
|
RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction, const Rule &rule)
|
||||||
{
|
{
|
||||||
if (!ruleAction.isValid()) {
|
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;
|
return RuleErrorActionTypeNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1041,7 +1093,7 @@ RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction,
|
|||||||
bool found = !paramType.defaultValue().isNull();
|
bool found = !paramType.defaultValue().isNull();
|
||||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||||
if (ruleActionParam.paramTypeId() == paramType.id()
|
if (ruleActionParam.paramTypeId() == paramType.id()
|
||||||
|| ruleActionParam.paramName() == paramType.name()) {
|
|| ruleActionParam.paramName() == paramType.name()) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1081,8 +1133,13 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if the param type of the event and the action match
|
// check if the param type of the event and the action match
|
||||||
QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId());
|
QMetaType::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId());
|
||||||
QVariant v(eventParamType);
|
QVariant v;
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
||||||
|
v = QVariant::fromMetaType(QMetaType(eventParamType));
|
||||||
|
#else
|
||||||
|
v = QVariant(static_cast<QVariant::Type>(eventParamType));
|
||||||
|
#endif
|
||||||
if (eventParamType != paramType.type() && !v.canConvert(static_cast<int>(paramType.type()))) {
|
if (eventParamType != paramType.type() && !v.canConvert(static_cast<int>(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) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:";
|
||||||
qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type();
|
qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type();
|
||||||
@ -1097,8 +1154,13 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru
|
|||||||
}
|
}
|
||||||
ThingClass stateThingClass = m_thingManager->findThingClass(d->thingClassId());
|
ThingClass stateThingClass = m_thingManager->findThingClass(d->thingClassId());
|
||||||
StateType stateType = stateThingClass.stateTypes().findById(ruleActionParam.stateTypeId());
|
StateType stateType = stateThingClass.stateTypes().findById(ruleActionParam.stateTypeId());
|
||||||
QVariant::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId());
|
QMetaType::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId());
|
||||||
QVariant v(stateType.type());
|
QVariant v;
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
||||||
|
v = QVariant::fromMetaType(QMetaType(stateType.type()));
|
||||||
|
#else
|
||||||
|
v = QVariant(static_cast<QVariant::Type>(stateType.type()));
|
||||||
|
#endif
|
||||||
if (actionParamType != stateType.type() && !v.canConvert(static_cast<int>(actionParamType))) {
|
if (actionParamType != stateType.type() && !v.canConvert(static_cast<int>(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) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:";
|
||||||
qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType;
|
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();
|
qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString();
|
||||||
return RuleErrorInvalidRuleActionParameter;
|
return RuleErrorInvalidRuleActionParameter;
|
||||||
}
|
}
|
||||||
if (paramType.type() != ruleActionParam.value().type() && !ruleActionParam.value().canConvert(static_cast<int>(paramType.type()))) {
|
if (paramType.type() != ruleActionParam.value().userType() && !ruleActionParam.value().canConvert(static_cast<int>(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) << "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) << " -> actionParamType:" << paramType.type();
|
||||||
qCWarning(dcRuleEngine) << " -> stateType:" << ruleActionParam.value().type();
|
qCWarning(dcRuleEngine) << " -> stateType:" << ruleActionParam.value().type();
|
||||||
@ -1121,7 +1183,7 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru
|
|||||||
return RuleErrorNoError;
|
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 ThingClass &thingClass, m_thingManager->supportedThings()) {
|
||||||
foreach (const ActionType &actionType, thingClass.actionTypes()) {
|
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 ThingClass &thingClass, m_thingManager->supportedThings()) {
|
||||||
foreach (const EventType &eventType, thingClass.eventTypes()) {
|
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)
|
void RuleEngine::appendRule(const Rule &rule)
|
||||||
@ -1187,7 +1249,7 @@ void RuleEngine::saveRule(const Rule &rule)
|
|||||||
|
|
||||||
CalendarItem calendarItem = rule.timeDescriptor().calendarItems().at(i);
|
CalendarItem calendarItem = rule.timeDescriptor().calendarItems().at(i);
|
||||||
if (calendarItem.dateTime().isValid())
|
if (calendarItem.dateTime().isValid())
|
||||||
settings.setValue("dateTime", calendarItem.dateTime().toTime_t());
|
settings.setValue("dateTime", calendarItem.dateTime().toSecsSinceEpoch());
|
||||||
|
|
||||||
if (calendarItem.startTime().isValid())
|
if (calendarItem.startTime().isValid())
|
||||||
settings.setValue("startTime", calendarItem.startTime().toString("hh:mm"));
|
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);
|
TimeEventItem timeEventItem = rule.timeDescriptor().timeEventItems().at(i);
|
||||||
|
|
||||||
if (timeEventItem.dateTime().isValid())
|
if (timeEventItem.dateTime().isValid())
|
||||||
settings.setValue("dateTime", timeEventItem.dateTime().toTime_t());
|
settings.setValue("dateTime", timeEventItem.dateTime().toSecsSinceEpoch());
|
||||||
|
|
||||||
if (timeEventItem.time().isValid())
|
if (timeEventItem.time().isValid())
|
||||||
settings.setValue("time", timeEventItem.time().toString("hh:mm"));
|
settings.setValue("time", timeEventItem.time().toString("hh:mm"));
|
||||||
@ -1339,7 +1401,7 @@ QList<RuleAction> RuleEngine::loadRuleActions(NymeaSettings *settings)
|
|||||||
foreach (QString paramTypeIdString, settings->childGroups()) {
|
foreach (QString paramTypeIdString, settings->childGroups()) {
|
||||||
if (paramTypeIdString.startsWith("RuleActionParam-")) {
|
if (paramTypeIdString.startsWith("RuleActionParam-")) {
|
||||||
settings->beginGroup(paramTypeIdString);
|
settings->beginGroup(paramTypeIdString);
|
||||||
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
|
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegularExpression("^RuleActionParam-"));
|
||||||
EventTypeId eventTypeId = EventTypeId(settings->value("eventTypeId", EventTypeId()).toString());
|
EventTypeId eventTypeId = EventTypeId(settings->value("eventTypeId", EventTypeId()).toString());
|
||||||
ParamTypeId eventParamTypeId = ParamTypeId(settings->value("eventParamTypeId", ParamTypeId()).toString());
|
ParamTypeId eventParamTypeId = ParamTypeId(settings->value("eventParamTypeId", ParamTypeId()).toString());
|
||||||
ThingId stateThingId = ThingId(settings->value("stateThingId", ThingId()).toString());
|
ThingId stateThingId = ThingId(settings->value("stateThingId", ThingId()).toString());
|
||||||
@ -1349,9 +1411,9 @@ QList<RuleAction> RuleEngine::loadRuleActions(NymeaSettings *settings)
|
|||||||
StateTypeId stateTypeId = StateTypeId(settings->value("stateTypeId", StateTypeId()).toString());
|
StateTypeId stateTypeId = StateTypeId(settings->value("stateTypeId", StateTypeId()).toString());
|
||||||
QVariant value = settings->value("value");
|
QVariant value = settings->value("value");
|
||||||
if (settings->contains("valueType")) {
|
if (settings->contains("valueType")) {
|
||||||
QVariant::Type valueType = static_cast<QVariant::Type>(settings->value("valueType").toInt());
|
QMetaType::Type valueType = static_cast<QMetaType::Type>(settings->value("valueType").toInt());
|
||||||
// Note: only warn, and continue with the QVariant guessed type
|
// 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.";
|
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<int>(valueType))) {
|
} else if (!value.canConvert(static_cast<int>(valueType))) {
|
||||||
qCWarning(dcRuleEngine()) << "Error loading rule action. Could not convert the rule action param value" << value << "to the stored type" << 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 QList<RuleAction
|
|||||||
}
|
}
|
||||||
ActionType actionType = m_thingManager->findConfiguredThing(action.thingId())->thingClass().actionTypes().findById(action.actionTypeId());
|
ActionType actionType = m_thingManager->findConfiguredThing(action.thingId())->thingClass().actionTypes().findById(action.actionTypeId());
|
||||||
m_logger->log({ruleId.toString(), "executed"}, {
|
m_logger->log({ruleId.toString(), "executed"}, {
|
||||||
{"name", m_rules.value(ruleId).name()},
|
{"name", m_rules.value(ruleId).name()},
|
||||||
{"status", QMetaEnum::fromType<Thing::ThingError>().valueToKey(info->status())},
|
{"status", QMetaEnum::fromType<Thing::ThingError>().valueToKey(info->status())},
|
||||||
{"thingId", info->action().thingId()},
|
{"thingId", info->action().thingId()},
|
||||||
{"action", actionType.name()}
|
{"action", actionType.name()}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,11 +1586,11 @@ void RuleEngine::executeRuleActions(const RuleId &ruleId, const QList<RuleAction
|
|||||||
if (info->status() != Thing::ThingErrorNoError) {
|
if (info->status() != Thing::ThingErrorNoError) {
|
||||||
qCWarning(dcRuleEngine) << "Error executing browser action:" << info->status();
|
qCWarning(dcRuleEngine) << "Error executing browser action:" << info->status();
|
||||||
m_logger->log({ruleId.toString(), "executed"}, {
|
m_logger->log({ruleId.toString(), "executed"}, {
|
||||||
{"name", m_rules.value(ruleId).name()},
|
{"name", m_rules.value(ruleId).name()},
|
||||||
{"status", QMetaEnum::fromType<Thing::ThingError>().valueToKey(info->status())},
|
{"status", QMetaEnum::fromType<Thing::ThingError>().valueToKey(info->status())},
|
||||||
{"thingId", info->browserAction().thingId()},
|
{"thingId", info->browserAction().thingId()},
|
||||||
{"browserItem", info->browserAction().itemId()}
|
{"browserItem", info->browserAction().itemId()}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1546,9 +1608,9 @@ void RuleEngine::onEventTriggered(const Event &event)
|
|||||||
// Event based
|
// Event based
|
||||||
if (!rule.eventDescriptors().isEmpty()) {
|
if (!rule.eventDescriptors().isEmpty()) {
|
||||||
m_logger->log({rule.id().toString()}, {
|
m_logger->log({rule.id().toString()}, {
|
||||||
{"name", rule.name()},
|
{"name", rule.name()},
|
||||||
{"state", "triggered"}
|
{"state", "triggered"}
|
||||||
});
|
});
|
||||||
|
|
||||||
QList<RuleAction> tmp;
|
QList<RuleAction> tmp;
|
||||||
if (rule.statesActive() && rule.timeActive()) {
|
if (rule.statesActive() && rule.timeActive()) {
|
||||||
@ -1587,9 +1649,9 @@ void RuleEngine::onEventTriggered(const Event &event)
|
|||||||
} else {
|
} else {
|
||||||
// State based rule
|
// State based rule
|
||||||
m_logger->log({rule.id().toString()}, {
|
m_logger->log({rule.id().toString()}, {
|
||||||
{"name", rule.name()},
|
{"name", rule.name()},
|
||||||
{"state", rule.active() ? "active" : "inactive"}
|
{"state", rule.active() ? "active" : "inactive"}
|
||||||
});
|
});
|
||||||
emit ruleActiveChanged(rule);
|
emit ruleActiveChanged(rule);
|
||||||
if (rule.active()) {
|
if (rule.active()) {
|
||||||
executeRuleActions(rule.id(), rule.actions());
|
executeRuleActions(rule.id(), rule.actions());
|
||||||
@ -1668,7 +1730,7 @@ void RuleEngine::init()
|
|||||||
settings.beginGroup(childGroup);
|
settings.beginGroup(childGroup);
|
||||||
|
|
||||||
CalendarItem calendarItem;
|
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.setStartTime(QTime::fromString(settings.value("startTime").toString()));
|
||||||
calendarItem.setDuration(settings.value("duration", 0).toUInt());
|
calendarItem.setDuration(settings.value("duration", 0).toUInt());
|
||||||
|
|
||||||
@ -1706,7 +1768,7 @@ void RuleEngine::init()
|
|||||||
settings.beginGroup(childGroup);
|
settings.beginGroup(childGroup);
|
||||||
|
|
||||||
TimeEventItem timeEventItem;
|
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()));
|
timeEventItem.setTime(QTime::fromString(settings.value("time").toString()));
|
||||||
|
|
||||||
QList<int> weekDays;
|
QList<int> weekDays;
|
||||||
@ -1758,13 +1820,13 @@ void RuleEngine::init()
|
|||||||
foreach (QString groupName, settings.childGroups()) {
|
foreach (QString groupName, settings.childGroups()) {
|
||||||
if (groupName.startsWith("ParamDescriptor-")) {
|
if (groupName.startsWith("ParamDescriptor-")) {
|
||||||
settings.beginGroup(groupName);
|
settings.beginGroup(groupName);
|
||||||
QString strippedGroupName = groupName.remove(QRegExp("^ParamDescriptor-"));
|
QString strippedGroupName = groupName.remove(QRegularExpression("^ParamDescriptor-"));
|
||||||
|
|
||||||
QVariant value = settings.value("value");
|
QVariant value = settings.value("value");
|
||||||
if (settings.contains("valueType")) {
|
if (settings.contains("valueType")) {
|
||||||
QVariant::Type valueType = static_cast<QVariant::Type>(settings.value("valueType").toInt());
|
QMetaType::Type valueType = static_cast<QMetaType::Type>(settings.value("valueType").toInt());
|
||||||
// Note: only warn, and continue with the QVariant guessed type
|
// 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.";
|
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<int>(valueType))) {
|
} else if (!value.canConvert(static_cast<int>(valueType))) {
|
||||||
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the param descriptor value" << value << "to the stored type" << valueType;
|
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the param descriptor value" << value << "to the stored type" << valueType;
|
||||||
|
|||||||
@ -127,8 +127,8 @@ private:
|
|||||||
RuleError checkRuleAction(const RuleAction &ruleAction, const Rule &rule);
|
RuleError checkRuleAction(const RuleAction &ruleAction, const Rule &rule);
|
||||||
RuleError checkRuleActionParam(const RuleActionParam &ruleActionParam, const ActionType &actionType, const Rule &rule);
|
RuleError checkRuleActionParam(const RuleActionParam &ruleActionParam, const ActionType &actionType, const Rule &rule);
|
||||||
|
|
||||||
QVariant::Type getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId);
|
QMetaType::Type getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId);
|
||||||
QVariant::Type getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId);
|
QMetaType::Type getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId);
|
||||||
|
|
||||||
void appendRule(const Rule &rule);
|
void appendRule(const Rule &rule);
|
||||||
void saveRule(const Rule &rule);
|
void saveRule(const Rule &rule);
|
||||||
|
|||||||
@ -35,6 +35,8 @@
|
|||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
#include "nymeasettings.h"
|
#include "nymeasettings.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
StateEvaluator::StateEvaluator(const StateDescriptor &stateDescriptor):
|
StateEvaluator::StateEvaluator(const StateDescriptor &stateDescriptor):
|
||||||
@ -199,9 +201,9 @@ StateEvaluator StateEvaluator::loadFromSettings(NymeaSettings &settings, const Q
|
|||||||
}
|
}
|
||||||
QVariant stateValue = settings.value("value");
|
QVariant stateValue = settings.value("value");
|
||||||
if (settings.contains("valueType")) {
|
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
|
// 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;
|
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)) {
|
} 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.";
|
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();
|
qCWarning(dcRuleEngine) << "Could not convert value of state descriptor" << m_stateDescriptor.stateTypeId() << " to:" << QVariant::typeToName(stateType.type()) << " Got:" << m_stateDescriptor.stateValue();
|
||||||
return false;
|
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()) {
|
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();
|
qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Max:" << stateType.maxValue();
|
||||||
return false;
|
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();
|
qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Min:" << stateType.minValue();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (!stateType.possibleValues().isEmpty() && !stateType.possibleValues().contains(stateValue)) {
|
if (!stateType.possibleValues().isEmpty() && !stateType.possibleValues().contains(stateValue)) {
|
||||||
QStringList possibleValues;
|
QStringList possibleValues;
|
||||||
foreach (const QVariant &value, stateType.possibleValues()) {
|
foreach (const QVariant &value, stateType.possibleValues()) {
|
||||||
@ -286,7 +301,7 @@ bool StateEvaluator::isValid() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if comparing to another state
|
// if comparing to another state
|
||||||
} else if (!m_stateDescriptor.valueThingId().isNull() && !m_stateDescriptor.valueStateTypeId().isNull()) {
|
} else if (!m_stateDescriptor.valueThingId().isNull() && !m_stateDescriptor.valueStateTypeId().isNull()) {
|
||||||
Thing *valueThing = NymeaCore::instance()->thingManager()->findConfiguredThing(m_stateDescriptor.valueThingId());
|
Thing *valueThing = NymeaCore::instance()->thingManager()->findConfiguredThing(m_stateDescriptor.valueThingId());
|
||||||
if (!valueThing) {
|
if (!valueThing) {
|
||||||
@ -307,11 +322,11 @@ bool StateEvaluator::isValid() const
|
|||||||
} else { // TypeInterface
|
} else { // TypeInterface
|
||||||
Interface iface = NymeaCore::instance()->thingManager()->supportedInterfaces().findByName(m_stateDescriptor.interface());
|
Interface iface = NymeaCore::instance()->thingManager()->supportedInterfaces().findByName(m_stateDescriptor.interface());
|
||||||
if (!iface.isValid()) {
|
if (!iface.isValid()) {
|
||||||
qWarning(dcRuleEngine()) << "No such interface:" << m_stateDescriptor.interface();
|
qCWarning(dcRuleEngine()) << "No such interface:" << m_stateDescriptor.interface();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (iface.stateTypes().findByName(m_stateDescriptor.interfaceState()).name().isEmpty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,11 +371,64 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!descriptor.stateValue().isNull()) {
|
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>();
|
||||||
|
QColor desciptorColor = descriptorValue.value<QColor>();
|
||||||
|
|
||||||
|
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());
|
bool res = convertedValue.convert(state.value().type());
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (descriptor.operatorType()) {
|
switch (descriptor.operatorType()) {
|
||||||
case Types::ValueOperatorEquals:
|
case Types::ValueOperatorEquals:
|
||||||
return state.value() == convertedValue;
|
return state.value() == convertedValue;
|
||||||
@ -375,7 +443,7 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const
|
|||||||
case Types::ValueOperatorNotEquals:
|
case Types::ValueOperatorNotEquals:
|
||||||
return state.value() != convertedValue;
|
return state.value() != convertedValue;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else if (!descriptor.valueThingId().isNull() && !descriptor.valueStateTypeId().isNull()) {
|
} else if (!descriptor.valueThingId().isNull() && !descriptor.valueStateTypeId().isNull()) {
|
||||||
Thing *valueThing = NymeaCore::instance()->thingManager()->findConfiguredThing(descriptor.valueThingId());
|
Thing *valueThing = NymeaCore::instance()->thingManager()->findConfiguredThing(descriptor.valueThingId());
|
||||||
if (!valueThing) {
|
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();
|
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()) {
|
switch (descriptor.operatorType()) {
|
||||||
case Types::ValueOperatorEquals:
|
case Types::ValueOperatorEquals:
|
||||||
return state.value() == valueState.value();
|
return state.value() == valueState.value();
|
||||||
@ -403,6 +488,7 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const
|
|||||||
case Types::ValueOperatorNotEquals:
|
case Types::ValueOperatorNotEquals:
|
||||||
return state.value() != valueState.value();
|
return state.value() != valueState.value();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // Interface based
|
} else { // Interface based
|
||||||
@ -430,7 +516,7 @@ bool StateEvaluator::evaluateDescriptor(const StateDescriptor &descriptor) const
|
|||||||
QDebug operator<<(QDebug dbg, const StateEvaluator &stateEvaluator)
|
QDebug operator<<(QDebug dbg, const StateEvaluator &stateEvaluator)
|
||||||
{
|
{
|
||||||
QDebugStateSaver saver(dbg);
|
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++) {
|
for (int i = 0; i < stateEvaluator.childEvaluators().count(); i++) {
|
||||||
dbg.nospace() << " " << i << ": " << stateEvaluator.childEvaluators().at(i);
|
dbg.nospace() << " " << i << ": " << stateEvaluator.childEvaluators().at(i);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,8 @@
|
|||||||
|
|
||||||
#include <QMessageLogger>
|
#include <QMessageLogger>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcScriptEngine)
|
Q_DECLARE_LOGGING_CATEGORY(dcScriptEngine)
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
@ -79,7 +81,7 @@ void ScriptAction::classBegin()
|
|||||||
|
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
foreach (const Param ¶m, action.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();
|
QString paramName = thing->thingClass().actionTypes().findById(action.actionTypeId()).paramTypes().findById(param.paramTypeId()).name();
|
||||||
params.insert(paramName, param.value().toByteArray());
|
params.insert(paramName, param.value().toByteArray());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,16 +45,16 @@
|
|||||||
#include "nymeasettings.h"
|
#include "nymeasettings.h"
|
||||||
#include "logging/logengine.h"
|
#include "logging/logengine.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QQmlComponent>
|
#include <QQmlComponent>
|
||||||
#include <QJsonParseError>
|
#include <QJsonParseError>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
NYMEA_LOGGING_CATEGORY(dcScriptEngine, "ScriptEngine")
|
NYMEA_LOGGING_CATEGORY(dcScriptEngine, "ScriptEngine")
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
@ -367,7 +367,7 @@ void ScriptEngine::loadScripts()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Script *script = new Script();
|
Script *script = new Script();
|
||||||
script->setId(jsonFileInfo.baseName());
|
script->setId(QUuid(jsonFileInfo.baseName()));
|
||||||
script->setName(jsonDoc.toVariant().toMap().value("name").toString());
|
script->setName(jsonDoc.toVariant().toMap().value("name").toString());
|
||||||
|
|
||||||
bool loaded = loadScript(script);
|
bool loaded = loadScript(script);
|
||||||
@ -449,14 +449,14 @@ void ScriptEngine::unloadScript(Script *script)
|
|||||||
QString ScriptEngine::baseName(const QUuid &id)
|
QString ScriptEngine::baseName(const QUuid &id)
|
||||||
{
|
{
|
||||||
QString path = NymeaSettings::storagePath() + "/scripts/";
|
QString path = NymeaSettings::storagePath() + "/scripts/";
|
||||||
QString basename = id.toString().remove(QRegExp("[{}]"));
|
QString basename = id.toString().remove(QRegularExpression("[{}]"));
|
||||||
return path + basename;
|
return path + basename;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::onScriptMessage(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
void ScriptEngine::onScriptMessage(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||||
{
|
{
|
||||||
QFileInfo fi(context.file);
|
QFileInfo fi(context.file);
|
||||||
QUuid scriptId = fi.baseName();
|
QUuid scriptId(fi.baseName());
|
||||||
if (!m_scripts.contains(scriptId)) {
|
if (!m_scripts.contains(scriptId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
#include <qqml.h>
|
#include <qqml.h>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
namespace scriptengine {
|
namespace scriptengine {
|
||||||
@ -97,7 +98,7 @@ void ScriptEvent::onEventTriggered(const Event &event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_eventTypeId.isEmpty() && event.eventTypeId() != m_eventTypeId) {
|
if (!m_eventTypeId.isEmpty() && event.eventTypeId() != EventTypeId(m_eventTypeId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ void ScriptEvent::onEventTriggered(const Event &event)
|
|||||||
|
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
foreach (const Param ¶m, event.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();
|
QString paramName = thing->thingClass().eventTypes().findById(event.eventTypeId()).paramTypes().findById(param.paramTypeId()).name();
|
||||||
params.insert(paramName, param.value().toByteArray());
|
params.insert(paramName, param.value().toByteArray());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
#include <qqml.h>
|
#include <qqml.h>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
namespace scriptengine {
|
namespace scriptengine {
|
||||||
@ -91,13 +92,13 @@ void ScriptInterfaceEvent::onEventTriggered(const Event &event)
|
|||||||
|
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
foreach (const Param ¶m, event.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();
|
QString paramName = thing->thingClass().eventTypes().findById(event.eventTypeId()).paramTypes().findById(param.paramTypeId()).name();
|
||||||
params.insert(paramName, param.value().toByteArray());
|
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.
|
// 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user