From b97e4e5b0cd75940c3c3fb9fb48d437e66bfac7c Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 12 Nov 2019 15:43:39 +0100 Subject: [PATCH] Add support for JS device plugins --- .../devices/devicemanagerimplementation.cpp | 28 ++- libnymea-core/devices/scriptdeviceplugin.cpp | 176 +++++++++++++++++- libnymea-core/devices/scriptdeviceplugin.h | 146 ++++++++++++++- libnymea-core/jsonrpc/devicehandler.cpp | 2 + libnymea/devices/devicesetupinfo.h | 1 + libnymea/devices/deviceutils.cpp | 10 +- libnymea/hardwaremanager.cpp | 1 - libnymea/hardwaremanager.h | 1 + libnymea/plugintimer.h | 4 +- libnymea/typeutils.h | 17 +- tests/auto/logging/testlogging.cpp | 2 +- tests/auto/rules/testrules.cpp | 6 +- 12 files changed, 361 insertions(+), 33 deletions(-) diff --git a/libnymea-core/devices/devicemanagerimplementation.cpp b/libnymea-core/devices/devicemanagerimplementation.cpp index 39bbae23..5a3ba256 100644 --- a/libnymea-core/devices/devicemanagerimplementation.cpp +++ b/libnymea-core/devices/devicemanagerimplementation.cpp @@ -269,6 +269,10 @@ DeviceDiscoveryInfo* DeviceManagerImplementation::discoverDevices(const DeviceCl } qCDebug(dcDeviceManager()) << "Discovery finished. Found devices:" << discoveryInfo->deviceDescriptors().count(); foreach (const DeviceDescriptor &descriptor, discoveryInfo->deviceDescriptors()) { + if (!descriptor.isValid()) { + qCWarning(dcDeviceManager()) << "Descriptor is invalid. Not adding to results"; + continue; + } m_discoveredDevices.insert(descriptor.id(), descriptor); } }); @@ -296,8 +300,10 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDevice(const DeviceCl * Returns \l{DeviceError} to inform about the result. */ DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList ¶ms, const QString &name) { + qWarning() << "Have descriptors" << m_discoveredDevices.keys(); DeviceDescriptor descriptor = m_discoveredDevices.value(deviceDescriptorId); if (!descriptor.isValid()) { + qCWarning(dcDeviceManager()) << "Cannot add device. DeviceDescriptor" << deviceDescriptorId << "not found."; DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this); info->finish(Device::DeviceErrorDeviceDescriptorNotFound); return info; @@ -305,11 +311,13 @@ DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceDe DeviceClass deviceClass = findDeviceClass(descriptor.deviceClassId()); if (!deviceClass.isValid()) { + qCWarning(dcDeviceManager()) << "Cannot add device. DeviceClass" << descriptor.deviceClassId() << "not found."; DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this); info->finish(Device::DeviceErrorDeviceClassNotFound); return info; } if (!deviceClass.createMethods().testFlag(DeviceClass::CreateMethodDiscovery)) { + qCWarning(dcDeviceManager()) << "Cannot add device. This device cannot be added via discovery."; DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this); info->finish(Device::DeviceErrorCreationMethodNotSupported); return info; @@ -675,12 +683,14 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const { DeviceClass deviceClass = findDeviceClass(deviceClassId); if (deviceClass.id().isNull()) { + qCWarning(dcDeviceManager()) << "Cannot add device. DeviceClass" << deviceClassId << "not found."; DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this); info->finish(Device::DeviceErrorDeviceClassNotFound); return info; } if (deviceClass.setupMethod() != DeviceClass::SetupMethodJustAdd) { + qCWarning(dcDeviceManager()) << "Cannot add device. This device cannot be added this way. (SetupMethodJustAdd)"; DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this); info->finish(Device::DeviceErrorCreationMethodNotSupported); return info; @@ -694,6 +704,7 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId()); if (!plugin) { + qCWarning(dcDeviceManager()) << "Cannot add device. Plugin for device class" << deviceClass.name() << "not found."; DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this); info->finish(Device::DeviceErrorPluginNotFound); return info; @@ -703,6 +714,7 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const ParamList effectiveParams = buildParams(deviceClass.paramTypes(), params); Device::DeviceError paramsResult = DeviceUtils::verifyParams(deviceClass.paramTypes(), effectiveParams); if (paramsResult != Device::DeviceErrorNoError) { + qCWarning(dcDeviceManager()) << "Cannot add device. Parameter verification failed."; DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this); info->finish(paramsResult); return info; @@ -1107,8 +1119,20 @@ void DeviceManagerImplementation::loadPlugins() } ScriptDevicePlugin *plugin = new ScriptDevicePlugin(this); - plugin->loadScript("/home/micha/Develop/nymea-plugin-jstest/devicepluginjstest.js"); - loadPlugin(plugin, plugin->metaData()); + bool ret = plugin->loadScript("/home/micha/Develop/nymea-plugin-jstest/devicepluginjstest.js"); + if (!ret) { + delete plugin; + qCWarning(dcDeviceManager()) << "JS plugin failed to load"; + return; + } + PluginMetadata metaData(plugin->metaData()); + if (!metaData.isValid()) { + qCWarning(dcDeviceManager()) << "Not loading JS plugin. Invalid metadata."; + foreach (const QString &error, metaData.validationErrors()) { + qCWarning(dcDeviceManager()) << error; + } + } + loadPlugin(plugin, metaData); } void DeviceManagerImplementation::loadPlugin(DevicePlugin *pluginIface, const PluginMetadata &metaData) diff --git a/libnymea-core/devices/scriptdeviceplugin.cpp b/libnymea-core/devices/scriptdeviceplugin.cpp index 89fa90c2..a0654e3c 100644 --- a/libnymea-core/devices/scriptdeviceplugin.cpp +++ b/libnymea-core/devices/scriptdeviceplugin.cpp @@ -5,6 +5,7 @@ #include #include "loggingcategories.h" +#include ScriptDevicePlugin::ScriptDevicePlugin(QObject *parent) : DevicePlugin(parent) { @@ -15,7 +16,7 @@ bool ScriptDevicePlugin::loadScript(const QString &fileName) { QFileInfo fi(fileName); - QString metaDataFileName = fileName + "on"; + QString metaDataFileName = fi.absoluteDir().path() + '/' + fi.baseName() + ".json"; QFile metaDataFile(metaDataFileName); if (!metaDataFile.open(QFile::ReadOnly)) { @@ -58,18 +59,18 @@ bool ScriptDevicePlugin::loadScript(const QString &fileName) return false; } - m_engine = new QJSEngine(this); - m_engine->installExtensions(QJSEngine::ConsoleExtension); + m_engine = new QQmlEngine(this); + m_engine->installExtensions(QJSEngine::AllExtensions); + m_engine->addImportPath(fi.absoluteDir().path() + "/node_modules/"); + qCWarning(dcDeviceManager()) << "Engine import path list" << m_engine->importPathList(); - QTextStream stream(&scriptFile); - QString contents = stream.readAll(); - scriptFile.close(); - QJSValue result = m_engine->evaluate(contents, fileName); - if (result.isError()) { - qCWarning(dcDeviceManager()) << "Error evaluating script" << fileName << result.toString(); + m_pluginImport = m_engine->importModule(fileName); + if (m_pluginImport.isError()) { + qCWarning(dcDeviceManager()) << "Error loading plugin module" << m_pluginImport.errorType() << m_pluginImport.toString(); return false; } + qCDebug(dcDeviceManager()) << "Loaded JS plugin" << fileName; return true; } @@ -80,5 +81,162 @@ QJsonObject ScriptDevicePlugin::metaData() const void ScriptDevicePlugin::init() { + qmlRegisterType(); + qmlRegisterType(); + QJSValue hardwareManagerObject = m_engine->newQObject(hardwareManager()); + m_engine->globalObject().setProperty("hardwareManager", hardwareManagerObject); + + if (!m_pluginImport.hasOwnProperty("init")) { + DevicePlugin::init(); + return; + } + QJSValue initFunction = m_pluginImport.property("init"); + QJSValue result = initFunction.call(); + if (result.isError()) { + qCWarning(dcDeviceManager()) << "Error calling init in JS plugin:" << result.toString(); + return; + } +} + +void ScriptDevicePlugin::discoverDevices(DeviceDiscoveryInfo *info) +{ + if (!m_pluginImport.hasOwnProperty("discoverDevices")) { + DevicePlugin::discoverDevices(info); + return; + } + + ScriptDeviceDiscoveryInfo *scriptInfo = new ScriptDeviceDiscoveryInfo(info); + QJSValue jsInfo = m_engine->newQObject(scriptInfo); + + QJSValue discoverFunction = m_pluginImport.property("discoverDevices"); + QJSValue ret = discoverFunction.call({jsInfo}); + if (ret.isError()) { + qCWarning(dcDeviceManager()) << "discoverDevices script failed to execute:\n" << ret.toString(); + } +} + +void ScriptDevicePlugin::startPairing(DevicePairingInfo *info) +{ + if (!m_pluginImport.hasOwnProperty("startPairing")) { + DevicePlugin::startPairing(info); + return; + } + + ScriptDevicePairingInfo *scriptInfo = new ScriptDevicePairingInfo(info); + QJSValue jsInfo = m_engine->newQObject(scriptInfo); + + QJSValue startPairingFunction = m_pluginImport.property("startPairing"); + QJSValue ret = startPairingFunction.call({jsInfo}); + if (ret.isError()) { + qCWarning(dcDeviceManager()) << "startPairing script failed to execute:\n" << ret.toString(); + } +} + +void ScriptDevicePlugin::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) +{ + if (!m_pluginImport.hasOwnProperty("confirmPairing")) { + DevicePlugin::confirmPairing(info, username, secret); + return; + } + + ScriptDevicePairingInfo *scriptInfo = new ScriptDevicePairingInfo(info); + QJSValue jsInfo = m_engine->newQObject(scriptInfo); + + QJSValue confirmPairingFunction = m_pluginImport.property("confirmPairing"); + QJSValue ret = confirmPairingFunction.call({jsInfo, username, secret}); + if (ret.isError()) { + qCWarning(dcDeviceManager()) << "confirmPairing script failed to execute:\n" << ret.toString(); + } +} + +void ScriptDevicePlugin::startMonitoringAutoDevices() +{ + if (!m_pluginImport.hasOwnProperty("startMonitoringAutoDevices")) { + DevicePlugin::startMonitoringAutoDevices(); + return; + } + + QJSValue monitorFunction = m_pluginImport.property("startMonitoringAutoDevices"); + QJSValue ret = monitorFunction.call(); + if (ret.isError()) { + qCWarning(dcDeviceManager()) << "startMonitoringAutoDevices failed to execute:\n" << ret.toString(); + } +} + +void ScriptDevicePlugin::setupDevice(DeviceSetupInfo *info) +{ + if (!m_pluginImport.hasOwnProperty("setupDevice")) { + DevicePlugin::setupDevice(info); + return; + } + QJSValue setupFunction = m_pluginImport.property("setupDevice"); + + Device *device = info->device(); + ScriptDevice *scriptDevice = new ScriptDevice(device); + m_devices.insert(device, scriptDevice); + connect(device, &Device::destroyed, this, [this, device](){ + m_devices.remove(device); + }); + + ScriptDeviceSetupInfo *scriptInfo = new ScriptDeviceSetupInfo(info, scriptDevice); + + qWarning() << "Setup params" << info->device()->params(); + QJSValue jsInfo = m_engine->newQObject(scriptInfo); + QJSValue ret = setupFunction.call({jsInfo}); + + if (ret.errorType() != QJSValue::NoError) { + qCWarning(dcDeviceManager()) << "setupDevice script failed to execute:\n" << ret.toString(); + } +} + +void ScriptDevicePlugin::postSetupDevice(Device *device) +{ + if (!m_pluginImport.hasOwnProperty("postSetupDevice")) { + DevicePlugin::postSetupDevice(device); + return; + } + QJSValue postSetupFunction = m_pluginImport.property("postSetupDevice"); + + QJSValue jsDevice = m_engine->newQObject(m_devices.value(device)); + QJSValue ret = postSetupFunction.call({jsDevice}); + if (ret.errorType() != QJSValue::NoError) { + qCWarning(dcDeviceManager()) << "setupDevice script failed to execute:\n" << ret.toString(); + } +} + +void ScriptDevicePlugin::deviceRemoved(Device *device) +{ + if (!m_pluginImport.hasOwnProperty("deviceRemoved")) { + DevicePlugin::deviceRemoved(device); + return; + } + + QJSValue jsDevice = m_engine->newQObject(m_devices.value(device)); + + QJSValue deviceRemovedFunction = m_pluginImport.property("deviceRemoved"); + QJSValue ret = deviceRemovedFunction.call({jsDevice}); + if (ret.isError()) { + qCWarning(dcDeviceManager()) << "deviceRemoved script failed to execute:\n" << ret.toString(); + } +} + +void ScriptDevicePlugin::executeAction(DeviceActionInfo *info) +{ + if (!m_pluginImport.hasOwnProperty("executeAction")) { + DevicePlugin::executeAction(info); + return; + } + + ScriptDevice *scriptDevice = m_devices.value(info->device()); + QJSValue jsDevice = m_engine->newQObject(scriptDevice); + + ScriptDeviceActionInfo *scriptInfo = new ScriptDeviceActionInfo(info, scriptDevice); + QJSValue jsInfo = m_engine->newQObject(scriptInfo); + + QJSValue executeActionFunction = m_pluginImport.property("executeAction"); + QJSValue ret = executeActionFunction.call({jsInfo}); + if (ret.isError()) { + qCWarning(dcDeviceManager()) << "executeAction script failed to execute:\n" << ret.toString(); + } } diff --git a/libnymea-core/devices/scriptdeviceplugin.h b/libnymea-core/devices/scriptdeviceplugin.h index c28c07a5..9f5194dd 100644 --- a/libnymea-core/devices/scriptdeviceplugin.h +++ b/libnymea-core/devices/scriptdeviceplugin.h @@ -3,9 +3,137 @@ #include "devices/deviceplugin.h" -#include +#include #include +class ScriptDeviceDiscoveryInfo: public QObject +{ + Q_OBJECT +public: + ScriptDeviceDiscoveryInfo(DeviceDiscoveryInfo *info): QObject(info), m_info(info) { + connect(info, &DeviceDiscoveryInfo::aborted, this, &ScriptDeviceDiscoveryInfo::aborted); + connect(info, &DeviceDiscoveryInfo::finished, this, &ScriptDeviceDiscoveryInfo::finished); + } + Q_INVOKABLE void addDeviceDescriptor(const QUuid &deviceClassId, const QString &title, const QString &description = QString(), const QVariantList ¶ms = QVariantList(), const QUuid &parentDeviceId = QUuid()) { + ParamList paramList; + for (int i = 0; i < params.count(); i++) { + paramList << Param(params.at(i).toMap().value("paramTypeId").toUuid(), params.at(i).toMap().value("value")); + } + DeviceDescriptor d(deviceClassId, title, description, parentDeviceId); + d.setParams(paramList); + m_info->addDeviceDescriptor(d); + } + Q_INVOKABLE void finish(Device::DeviceError status = Device::DeviceErrorNoError, const QString &displayMessage = QString()) { + m_info->finish(status, displayMessage); + } +signals: + void aborted(); + void finished(); +private: + DeviceDiscoveryInfo *m_info = nullptr; +}; + +class ScriptDevice: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) +public: + ScriptDevice(Device *device): QObject(device), m_device(device) { + connect(device, &Device::nameChanged, this, &ScriptDevice::nameChanged); + } + + QString name() const { return m_device->name(); } + void setName(const QString &name) { m_device->setName(name); } + + Q_INVOKABLE QVariant paramValue(const QUuid ¶mTypeId) { return m_device->paramValue(paramTypeId); } + Q_INVOKABLE void setParamValue(const QUuid ¶mTypeId, const QVariant &value) { m_device->setParamValue(paramTypeId, value); } + + Q_INVOKABLE QVariant stateValue(const QUuid &stateTypeId) { return m_device->stateValue(stateTypeId); } + Q_INVOKABLE void setStateValue(const QUuid &stateTypeId, const QVariant &value) { m_device->setStateValue(stateTypeId, value); } + +signals: + void nameChanged(); + +private: + Device *m_device = nullptr; +}; + +class ScriptDeviceSetupInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(ScriptDevice* device READ device CONSTANT) +public: + ScriptDeviceSetupInfo(DeviceSetupInfo *info, ScriptDevice *scriptDevice): QObject(info), m_info(info), m_device(scriptDevice) { + connect(info, &DeviceSetupInfo::aborted, this, &ScriptDeviceSetupInfo::aborted); + connect(info, &DeviceSetupInfo::finished, this, &ScriptDeviceSetupInfo::finished); + } + Q_INVOKABLE void finish(Device::DeviceError status = Device::DeviceErrorNoError, const QString &displayMessage = QString()) { + m_info->finish(status, displayMessage); + } + ScriptDevice* device() const { return m_device; } +signals: + void aborted(); + void finished(); +private: + DeviceSetupInfo *m_info = nullptr; + ScriptDevice* m_device = nullptr; +}; + +class ScriptDevicePairingInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(QUuid deviceClassId READ deviceClassId CONSTANT) + Q_PROPERTY(QUuid deviceId READ deviceId CONSTANT) + Q_PROPERTY(QString deviceName READ deviceName CONSTANT) + Q_PROPERTY(QUuid parentDeviceId READ parentDeviceId CONSTANT) + Q_PROPERTY(QUrl oAuthUrl READ oAuthUrl WRITE setOAuthUrl) +public: + ScriptDevicePairingInfo(DevicePairingInfo* info): QObject(info), m_info(info) { + connect(info, &DevicePairingInfo::aborted, this, &ScriptDevicePairingInfo::aborted); + connect(info, &DevicePairingInfo::finished, this, &ScriptDevicePairingInfo::finished); + } + Q_INVOKABLE QVariant paramValue(const QUuid ¶mTypeId) { return m_info->params().paramValue(paramTypeId); } + Q_INVOKABLE void finish(Device::DeviceError status = Device::DeviceErrorNoError, const QString &displayMessage = QString()) { + m_info->finish(status, displayMessage); + } + QUuid deviceClassId() const { return m_info->deviceClassId(); } + QUuid deviceId() const { return m_info->deviceId(); } + QString deviceName() const { return m_info->deviceName(); } + QUuid parentDeviceId() const { return m_info->parentDeviceId(); } + QUrl oAuthUrl() const { return m_info->oAuthUrl(); } + void setOAuthUrl(const QUrl &oAuthUrl) { m_info->setOAuthUrl(oAuthUrl); } +signals: + void aborted(); + void finished(); +private: + DevicePairingInfo *m_info = nullptr; +}; + +class ScriptDeviceActionInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(ScriptDevice* device READ device CONSTANT) + Q_PROPERTY(QUuid actionTypeId READ actionTypeId CONSTANT) +public: + ScriptDeviceActionInfo(DeviceActionInfo* info, ScriptDevice* scriptDevice): QObject(info), m_info(info), m_device(scriptDevice) { + connect(info, &DeviceActionInfo::finished, this, &ScriptDeviceActionInfo::finished); + connect(info, &DeviceActionInfo::aborted, this, &ScriptDeviceActionInfo::aborted); + } + ScriptDevice* device() const { return m_device; } + QUuid actionTypeId() const { return m_info->action().actionTypeId(); } + Q_INVOKABLE QVariant paramValue(const QUuid ¶mTypeId) { return m_info->action().params().paramValue(paramTypeId); } + Q_INVOKABLE void finish(Device::DeviceError status = Device::DeviceErrorNoError, const QString &displayMessage = QString()) { + m_info->finish(status, displayMessage); + } + +signals: + void aborted(); + void finished(); +private: + DeviceActionInfo* m_info = nullptr; + ScriptDevice* m_device = nullptr; +}; + class ScriptDevicePlugin : public DevicePlugin { Q_OBJECT @@ -16,13 +144,21 @@ public: QJsonObject metaData() const; void init() override; -signals: - -public slots: + void startMonitoringAutoDevices() override; + void discoverDevices(DeviceDiscoveryInfo *info) override; + void startPairing(DevicePairingInfo *info) override; + void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override; + void setupDevice(DeviceSetupInfo *info) override; + void postSetupDevice(Device *device) override; + void deviceRemoved(Device *device) override; + void executeAction(DeviceActionInfo *info) override; + void browseDevice(BrowseResult *result) override; private: - QJSEngine *m_engine = nullptr; + QQmlEngine *m_engine = nullptr; QJsonObject m_metaData; + QJSValue m_pluginImport; + QHash m_devices; }; #endif // SCRIPTDEVICEPLUGIN_H diff --git a/libnymea-core/jsonrpc/devicehandler.cpp b/libnymea-core/jsonrpc/devicehandler.cpp index 367b0c88..1de7c8dc 100644 --- a/libnymea-core/jsonrpc/devicehandler.cpp +++ b/libnymea-core/jsonrpc/devicehandler.cpp @@ -455,6 +455,8 @@ JsonReply *DeviceHandler::GetDiscoveredDevices(const QVariantMap ¶ms) const QVariantList deviceDescriptorList; foreach (const DeviceDescriptor &deviceDescriptor, info->deviceDescriptors()) { deviceDescriptorList.append(pack(deviceDescriptor)); + qWarning() << "*** Discovery result:" << deviceDescriptor.params(); + qWarning() << "Packed:" << pack(deviceDescriptor); } returns.insert("deviceDescriptors", deviceDescriptorList); } diff --git a/libnymea/devices/devicesetupinfo.h b/libnymea/devices/devicesetupinfo.h index 614b291b..8bdbb445 100644 --- a/libnymea/devices/devicesetupinfo.h +++ b/libnymea/devices/devicesetupinfo.h @@ -32,6 +32,7 @@ class DeviceManager; class LIBNYMEA_EXPORT DeviceSetupInfo : public QObject { Q_OBJECT + Q_PROPERTY(Device* device READ device CONSTANT) public: explicit DeviceSetupInfo(Device *device, DeviceManager *deviceManager, quint32 timeout = 0); diff --git a/libnymea/devices/deviceutils.cpp b/libnymea/devices/deviceutils.cpp index 07126c91..b2d81572 100644 --- a/libnymea/devices/deviceutils.cpp +++ b/libnymea/devices/deviceutils.cpp @@ -185,7 +185,7 @@ Interface DeviceUtils::loadInterface(const QString &name) ActionTypes actionTypes; EventTypes eventTypes; foreach (const QVariant &stateVariant, content.value("states").toList()) { - StateType stateType(StateTypeId::fromUuid(QUuid())); + StateType stateType; stateType.setName(stateVariant.toMap().value("name").toString()); stateType.setType(QVariant::nameToType(stateVariant.toMap().value("type").toByteArray())); stateType.setPossibleValues(stateVariant.toMap().value("allowedValues").toList()); @@ -193,7 +193,7 @@ Interface DeviceUtils::loadInterface(const QString &name) stateType.setMaxValue(stateVariant.toMap().value("maxValue")); stateTypes.append(stateType); - EventType stateChangeEventType(EventTypeId::fromUuid(QUuid())); + EventType stateChangeEventType; stateChangeEventType.setName(stateType.name()); ParamType stateChangeEventParamType; stateChangeEventParamType.setName(stateType.name()); @@ -205,7 +205,7 @@ Interface DeviceUtils::loadInterface(const QString &name) eventTypes.append(stateChangeEventType); if (stateVariant.toMap().value("writable", false).toBool()) { - ActionType stateChangeActionType(ActionTypeId::fromUuid(QUuid())); + ActionType stateChangeActionType; stateChangeActionType.setName(stateType.name()); stateChangeActionType.setParamTypes(ParamTypes() << stateChangeEventParamType); actionTypes.append(stateChangeActionType); @@ -213,7 +213,7 @@ Interface DeviceUtils::loadInterface(const QString &name) } foreach (const QVariant &actionVariant, content.value("actions").toList()) { - ActionType actionType(ActionTypeId::fromUuid(QUuid())); + ActionType actionType; actionType.setName(actionVariant.toMap().value("name").toString()); ParamTypes paramTypes; foreach (const QVariant &actionParamVariant, actionVariant.toMap().value("params").toList()) { @@ -229,7 +229,7 @@ Interface DeviceUtils::loadInterface(const QString &name) } foreach (const QVariant &eventVariant, content.value("events").toList()) { - EventType eventType(EventTypeId::fromUuid(QUuid())); + EventType eventType; eventType.setName(eventVariant.toMap().value("name").toString()); ParamTypes paramTypes; foreach (const QVariant &eventParamVariant, eventVariant.toMap().value("params").toList()) { diff --git a/libnymea/hardwaremanager.cpp b/libnymea/hardwaremanager.cpp index 21f9e3dd..9cb8d553 100644 --- a/libnymea/hardwaremanager.cpp +++ b/libnymea/hardwaremanager.cpp @@ -69,7 +69,6 @@ HardwareManager::HardwareManager(QObject *parent) : QObject(parent) { - } /*! Sets the given \a resource to \a enabled. This allows to enable/disable individual \l{HardwareResource}{HardwareResources}. */ diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h index a88ab580..9f30580c 100644 --- a/libnymea/hardwaremanager.h +++ b/libnymea/hardwaremanager.h @@ -38,6 +38,7 @@ class HardwareResource; class HardwareManager : public QObject { Q_OBJECT + Q_PROPERTY(PluginTimerManager* pluginTimerManager READ pluginTimerManager CONSTANT) public: HardwareManager(QObject *parent = nullptr); diff --git a/libnymea/plugintimer.h b/libnymea/plugintimer.h index ffda5446..a08c85b7 100644 --- a/libnymea/plugintimer.h +++ b/libnymea/plugintimer.h @@ -66,8 +66,8 @@ public: PluginTimerManager(QObject *parent = nullptr); virtual ~PluginTimerManager() = default; - virtual PluginTimer *registerTimer(int seconds = 60) = 0; - virtual void unregisterTimer(PluginTimer *timer = nullptr) = 0; + Q_INVOKABLE virtual PluginTimer *registerTimer(int seconds = 60) = 0; + Q_INVOKABLE virtual void unregisterTimer(PluginTimer *timer = nullptr) = 0; }; #endif // PLUGINTIMER_H diff --git a/libnymea/typeutils.h b/libnymea/typeutils.h index a8439a69..37690efe 100644 --- a/libnymea/typeutils.h +++ b/libnymea/typeutils.h @@ -29,13 +29,20 @@ #include "libnymea.h" -#define DECLARE_TYPE_ID(type) class type##Id: public QUuid \ +class GadgetUuid: public QUuid +{ + Q_GADGET +public: + GadgetUuid() {} + GadgetUuid(const QUuid &uuid): QUuid(uuid) {} +}; + +#define DECLARE_TYPE_ID(type) class type##Id: public GadgetUuid \ { \ public: \ - type##Id(const QUuid &uuid): QUuid(uuid) {} \ - type##Id(): QUuid() {} \ - static type##Id create##type##Id() { return type##Id(QUuid::createUuid().toString()); } \ - static type##Id fromUuid(const QUuid &uuid) { return type##Id(uuid.toString()); } \ + type##Id(const QUuid &uuid): GadgetUuid(uuid) {} \ + type##Id(): GadgetUuid() {} \ + static type##Id create##type##Id() { return type##Id(QUuid::createUuid()); } \ bool operator==(const type##Id &other) const { \ return toString() == other.toString(); \ } \ diff --git a/tests/auto/logging/testlogging.cpp b/tests/auto/logging/testlogging.cpp index 98e40a75..ba6fda7f 100644 --- a/tests/auto/logging/testlogging.cpp +++ b/tests/auto/logging/testlogging.cpp @@ -599,7 +599,7 @@ void TestLogging::testHouseKeeping() deviceParams.append(httpParam); params.insert("deviceParams", deviceParams); QVariant response = injectAndWait("Devices.AddConfiguredDevice", params); - DeviceId deviceId = DeviceId::fromUuid(response.toMap().value("params").toMap().value("deviceId").toUuid()); + DeviceId deviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toUuid()); QVERIFY2(!deviceId.isNull(), "Something went wrong creating the device for testing."); // Trigger something that creates a logging entry diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index e390457e..a7d7407c 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -2766,7 +2766,7 @@ void TestRules::testInitStatesActive() params.insert("exitActions", exitActions); QVariant response = injectAndWait("Rules.AddRule", params); - RuleId ruleId = RuleId::fromUuid(response.toMap().value("params").toMap().value("ruleId").toUuid()); + RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toUuid()); QVERIFY2(!ruleId.isNull(), "Error adding rule"); // Get the current state value, make sure it's false @@ -3140,7 +3140,7 @@ void TestRules::testHousekeeping() deviceParams.append(httpParam); params.insert("deviceParams", deviceParams); QVariant response = injectAndWait("Devices.AddConfiguredDevice", params); - DeviceId deviceId = DeviceId::fromUuid(response.toMap().value("params").toMap().value("deviceId").toUuid()); + DeviceId deviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toUuid()); QVERIFY2(!deviceId.isNull(), "Something went wrong creating the device for testing."); // Create a rule with this device @@ -3181,7 +3181,7 @@ void TestRules::testHousekeeping() } response = injectAndWait("Rules.AddRule", params); - RuleId ruleId = RuleId::fromUuid(response.toMap().value("params").toMap().value("ruleId").toUuid()); + RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toUuid()); // Verfy that the rule has been created successfully and our device is in there.