Add support for JS device plugins
This commit is contained in:
parent
9322cc79e9
commit
b97e4e5b0c
@ -269,6 +269,10 @@ DeviceDiscoveryInfo* DeviceManagerImplementation::discoverDevices(const DeviceCl
|
|||||||
}
|
}
|
||||||
qCDebug(dcDeviceManager()) << "Discovery finished. Found devices:" << discoveryInfo->deviceDescriptors().count();
|
qCDebug(dcDeviceManager()) << "Discovery finished. Found devices:" << discoveryInfo->deviceDescriptors().count();
|
||||||
foreach (const DeviceDescriptor &descriptor, discoveryInfo->deviceDescriptors()) {
|
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);
|
m_discoveredDevices.insert(descriptor.id(), descriptor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -296,8 +300,10 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDevice(const DeviceCl
|
|||||||
* Returns \l{DeviceError} to inform about the result. */
|
* Returns \l{DeviceError} to inform about the result. */
|
||||||
DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList ¶ms, const QString &name)
|
DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList ¶ms, const QString &name)
|
||||||
{
|
{
|
||||||
|
qWarning() << "Have descriptors" << m_discoveredDevices.keys();
|
||||||
DeviceDescriptor descriptor = m_discoveredDevices.value(deviceDescriptorId);
|
DeviceDescriptor descriptor = m_discoveredDevices.value(deviceDescriptorId);
|
||||||
if (!descriptor.isValid()) {
|
if (!descriptor.isValid()) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Cannot add device. DeviceDescriptor" << deviceDescriptorId << "not found.";
|
||||||
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
||||||
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
|
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
|
||||||
return info;
|
return info;
|
||||||
@ -305,11 +311,13 @@ DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceDe
|
|||||||
|
|
||||||
DeviceClass deviceClass = findDeviceClass(descriptor.deviceClassId());
|
DeviceClass deviceClass = findDeviceClass(descriptor.deviceClassId());
|
||||||
if (!deviceClass.isValid()) {
|
if (!deviceClass.isValid()) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Cannot add device. DeviceClass" << descriptor.deviceClassId() << "not found.";
|
||||||
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
||||||
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
if (!deviceClass.createMethods().testFlag(DeviceClass::CreateMethodDiscovery)) {
|
if (!deviceClass.createMethods().testFlag(DeviceClass::CreateMethodDiscovery)) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Cannot add device. This device cannot be added via discovery.";
|
||||||
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
||||||
info->finish(Device::DeviceErrorCreationMethodNotSupported);
|
info->finish(Device::DeviceErrorCreationMethodNotSupported);
|
||||||
return info;
|
return info;
|
||||||
@ -675,12 +683,14 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const
|
|||||||
{
|
{
|
||||||
DeviceClass deviceClass = findDeviceClass(deviceClassId);
|
DeviceClass deviceClass = findDeviceClass(deviceClassId);
|
||||||
if (deviceClass.id().isNull()) {
|
if (deviceClass.id().isNull()) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Cannot add device. DeviceClass" << deviceClassId << "not found.";
|
||||||
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
||||||
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceClass.setupMethod() != DeviceClass::SetupMethodJustAdd) {
|
if (deviceClass.setupMethod() != DeviceClass::SetupMethodJustAdd) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Cannot add device. This device cannot be added this way. (SetupMethodJustAdd)";
|
||||||
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
||||||
info->finish(Device::DeviceErrorCreationMethodNotSupported);
|
info->finish(Device::DeviceErrorCreationMethodNotSupported);
|
||||||
return info;
|
return info;
|
||||||
@ -694,6 +704,7 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const
|
|||||||
|
|
||||||
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
|
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Cannot add device. Plugin for device class" << deviceClass.name() << "not found.";
|
||||||
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
||||||
info->finish(Device::DeviceErrorPluginNotFound);
|
info->finish(Device::DeviceErrorPluginNotFound);
|
||||||
return info;
|
return info;
|
||||||
@ -703,6 +714,7 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const
|
|||||||
ParamList effectiveParams = buildParams(deviceClass.paramTypes(), params);
|
ParamList effectiveParams = buildParams(deviceClass.paramTypes(), params);
|
||||||
Device::DeviceError paramsResult = DeviceUtils::verifyParams(deviceClass.paramTypes(), effectiveParams);
|
Device::DeviceError paramsResult = DeviceUtils::verifyParams(deviceClass.paramTypes(), effectiveParams);
|
||||||
if (paramsResult != Device::DeviceErrorNoError) {
|
if (paramsResult != Device::DeviceErrorNoError) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Cannot add device. Parameter verification failed.";
|
||||||
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
|
||||||
info->finish(paramsResult);
|
info->finish(paramsResult);
|
||||||
return info;
|
return info;
|
||||||
@ -1107,8 +1119,20 @@ void DeviceManagerImplementation::loadPlugins()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptDevicePlugin *plugin = new ScriptDevicePlugin(this);
|
ScriptDevicePlugin *plugin = new ScriptDevicePlugin(this);
|
||||||
plugin->loadScript("/home/micha/Develop/nymea-plugin-jstest/devicepluginjstest.js");
|
bool ret = plugin->loadScript("/home/micha/Develop/nymea-plugin-jstest/devicepluginjstest.js");
|
||||||
loadPlugin(plugin, plugin->metaData());
|
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)
|
void DeviceManagerImplementation::loadPlugin(DevicePlugin *pluginIface, const PluginMetadata &metaData)
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
#include <plugintimer.h>
|
||||||
|
|
||||||
ScriptDevicePlugin::ScriptDevicePlugin(QObject *parent) : DevicePlugin(parent)
|
ScriptDevicePlugin::ScriptDevicePlugin(QObject *parent) : DevicePlugin(parent)
|
||||||
{
|
{
|
||||||
@ -15,7 +16,7 @@ bool ScriptDevicePlugin::loadScript(const QString &fileName)
|
|||||||
{
|
{
|
||||||
|
|
||||||
QFileInfo fi(fileName);
|
QFileInfo fi(fileName);
|
||||||
QString metaDataFileName = fileName + "on";
|
QString metaDataFileName = fi.absoluteDir().path() + '/' + fi.baseName() + ".json";
|
||||||
|
|
||||||
QFile metaDataFile(metaDataFileName);
|
QFile metaDataFile(metaDataFileName);
|
||||||
if (!metaDataFile.open(QFile::ReadOnly)) {
|
if (!metaDataFile.open(QFile::ReadOnly)) {
|
||||||
@ -58,18 +59,18 @@ bool ScriptDevicePlugin::loadScript(const QString &fileName)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_engine = new QJSEngine(this);
|
m_engine = new QQmlEngine(this);
|
||||||
m_engine->installExtensions(QJSEngine::ConsoleExtension);
|
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);
|
m_pluginImport = m_engine->importModule(fileName);
|
||||||
QString contents = stream.readAll();
|
if (m_pluginImport.isError()) {
|
||||||
scriptFile.close();
|
qCWarning(dcDeviceManager()) << "Error loading plugin module" << m_pluginImport.errorType() << m_pluginImport.toString();
|
||||||
QJSValue result = m_engine->evaluate(contents, fileName);
|
|
||||||
if (result.isError()) {
|
|
||||||
qCWarning(dcDeviceManager()) << "Error evaluating script" << fileName << result.toString();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qCDebug(dcDeviceManager()) << "Loaded JS plugin" << fileName;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,5 +81,162 @@ QJsonObject ScriptDevicePlugin::metaData() const
|
|||||||
|
|
||||||
void ScriptDevicePlugin::init()
|
void ScriptDevicePlugin::init()
|
||||||
{
|
{
|
||||||
|
qmlRegisterType<PluginTimerManager>();
|
||||||
|
qmlRegisterType<PluginTimer>();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,137 @@
|
|||||||
|
|
||||||
#include "devices/deviceplugin.h"
|
#include "devices/deviceplugin.h"
|
||||||
|
|
||||||
#include <QJSEngine>
|
#include <QQmlEngine>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
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
|
class ScriptDevicePlugin : public DevicePlugin
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -16,13 +144,21 @@ public:
|
|||||||
QJsonObject metaData() const;
|
QJsonObject metaData() const;
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
signals:
|
void startMonitoringAutoDevices() override;
|
||||||
|
void discoverDevices(DeviceDiscoveryInfo *info) override;
|
||||||
public slots:
|
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:
|
private:
|
||||||
QJSEngine *m_engine = nullptr;
|
QQmlEngine *m_engine = nullptr;
|
||||||
QJsonObject m_metaData;
|
QJsonObject m_metaData;
|
||||||
|
QJSValue m_pluginImport;
|
||||||
|
QHash<Device*, ScriptDevice*> m_devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SCRIPTDEVICEPLUGIN_H
|
#endif // SCRIPTDEVICEPLUGIN_H
|
||||||
|
|||||||
@ -455,6 +455,8 @@ JsonReply *DeviceHandler::GetDiscoveredDevices(const QVariantMap ¶ms) const
|
|||||||
QVariantList deviceDescriptorList;
|
QVariantList deviceDescriptorList;
|
||||||
foreach (const DeviceDescriptor &deviceDescriptor, info->deviceDescriptors()) {
|
foreach (const DeviceDescriptor &deviceDescriptor, info->deviceDescriptors()) {
|
||||||
deviceDescriptorList.append(pack(deviceDescriptor));
|
deviceDescriptorList.append(pack(deviceDescriptor));
|
||||||
|
qWarning() << "*** Discovery result:" << deviceDescriptor.params();
|
||||||
|
qWarning() << "Packed:" << pack(deviceDescriptor);
|
||||||
}
|
}
|
||||||
returns.insert("deviceDescriptors", deviceDescriptorList);
|
returns.insert("deviceDescriptors", deviceDescriptorList);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ class DeviceManager;
|
|||||||
class LIBNYMEA_EXPORT DeviceSetupInfo : public QObject
|
class LIBNYMEA_EXPORT DeviceSetupInfo : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(Device* device READ device CONSTANT)
|
||||||
public:
|
public:
|
||||||
explicit DeviceSetupInfo(Device *device, DeviceManager *deviceManager, quint32 timeout = 0);
|
explicit DeviceSetupInfo(Device *device, DeviceManager *deviceManager, quint32 timeout = 0);
|
||||||
|
|
||||||
|
|||||||
@ -185,7 +185,7 @@ Interface DeviceUtils::loadInterface(const QString &name)
|
|||||||
ActionTypes actionTypes;
|
ActionTypes actionTypes;
|
||||||
EventTypes eventTypes;
|
EventTypes eventTypes;
|
||||||
foreach (const QVariant &stateVariant, content.value("states").toList()) {
|
foreach (const QVariant &stateVariant, content.value("states").toList()) {
|
||||||
StateType stateType(StateTypeId::fromUuid(QUuid()));
|
StateType stateType;
|
||||||
stateType.setName(stateVariant.toMap().value("name").toString());
|
stateType.setName(stateVariant.toMap().value("name").toString());
|
||||||
stateType.setType(QVariant::nameToType(stateVariant.toMap().value("type").toByteArray()));
|
stateType.setType(QVariant::nameToType(stateVariant.toMap().value("type").toByteArray()));
|
||||||
stateType.setPossibleValues(stateVariant.toMap().value("allowedValues").toList());
|
stateType.setPossibleValues(stateVariant.toMap().value("allowedValues").toList());
|
||||||
@ -193,7 +193,7 @@ Interface DeviceUtils::loadInterface(const QString &name)
|
|||||||
stateType.setMaxValue(stateVariant.toMap().value("maxValue"));
|
stateType.setMaxValue(stateVariant.toMap().value("maxValue"));
|
||||||
stateTypes.append(stateType);
|
stateTypes.append(stateType);
|
||||||
|
|
||||||
EventType stateChangeEventType(EventTypeId::fromUuid(QUuid()));
|
EventType stateChangeEventType;
|
||||||
stateChangeEventType.setName(stateType.name());
|
stateChangeEventType.setName(stateType.name());
|
||||||
ParamType stateChangeEventParamType;
|
ParamType stateChangeEventParamType;
|
||||||
stateChangeEventParamType.setName(stateType.name());
|
stateChangeEventParamType.setName(stateType.name());
|
||||||
@ -205,7 +205,7 @@ Interface DeviceUtils::loadInterface(const QString &name)
|
|||||||
eventTypes.append(stateChangeEventType);
|
eventTypes.append(stateChangeEventType);
|
||||||
|
|
||||||
if (stateVariant.toMap().value("writable", false).toBool()) {
|
if (stateVariant.toMap().value("writable", false).toBool()) {
|
||||||
ActionType stateChangeActionType(ActionTypeId::fromUuid(QUuid()));
|
ActionType stateChangeActionType;
|
||||||
stateChangeActionType.setName(stateType.name());
|
stateChangeActionType.setName(stateType.name());
|
||||||
stateChangeActionType.setParamTypes(ParamTypes() << stateChangeEventParamType);
|
stateChangeActionType.setParamTypes(ParamTypes() << stateChangeEventParamType);
|
||||||
actionTypes.append(stateChangeActionType);
|
actionTypes.append(stateChangeActionType);
|
||||||
@ -213,7 +213,7 @@ Interface DeviceUtils::loadInterface(const QString &name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (const QVariant &actionVariant, content.value("actions").toList()) {
|
foreach (const QVariant &actionVariant, content.value("actions").toList()) {
|
||||||
ActionType actionType(ActionTypeId::fromUuid(QUuid()));
|
ActionType actionType;
|
||||||
actionType.setName(actionVariant.toMap().value("name").toString());
|
actionType.setName(actionVariant.toMap().value("name").toString());
|
||||||
ParamTypes paramTypes;
|
ParamTypes paramTypes;
|
||||||
foreach (const QVariant &actionParamVariant, actionVariant.toMap().value("params").toList()) {
|
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()) {
|
foreach (const QVariant &eventVariant, content.value("events").toList()) {
|
||||||
EventType eventType(EventTypeId::fromUuid(QUuid()));
|
EventType eventType;
|
||||||
eventType.setName(eventVariant.toMap().value("name").toString());
|
eventType.setName(eventVariant.toMap().value("name").toString());
|
||||||
ParamTypes paramTypes;
|
ParamTypes paramTypes;
|
||||||
foreach (const QVariant &eventParamVariant, eventVariant.toMap().value("params").toList()) {
|
foreach (const QVariant &eventParamVariant, eventVariant.toMap().value("params").toList()) {
|
||||||
|
|||||||
@ -69,7 +69,6 @@
|
|||||||
HardwareManager::HardwareManager(QObject *parent) :
|
HardwareManager::HardwareManager(QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Sets the given \a resource to \a enabled. This allows to enable/disable individual \l{HardwareResource}{HardwareResources}. */
|
/*! Sets the given \a resource to \a enabled. This allows to enable/disable individual \l{HardwareResource}{HardwareResources}. */
|
||||||
|
|||||||
@ -38,6 +38,7 @@ class HardwareResource;
|
|||||||
class HardwareManager : public QObject
|
class HardwareManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(PluginTimerManager* pluginTimerManager READ pluginTimerManager CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HardwareManager(QObject *parent = nullptr);
|
HardwareManager(QObject *parent = nullptr);
|
||||||
|
|||||||
@ -66,8 +66,8 @@ public:
|
|||||||
PluginTimerManager(QObject *parent = nullptr);
|
PluginTimerManager(QObject *parent = nullptr);
|
||||||
virtual ~PluginTimerManager() = default;
|
virtual ~PluginTimerManager() = default;
|
||||||
|
|
||||||
virtual PluginTimer *registerTimer(int seconds = 60) = 0;
|
Q_INVOKABLE virtual PluginTimer *registerTimer(int seconds = 60) = 0;
|
||||||
virtual void unregisterTimer(PluginTimer *timer = nullptr) = 0;
|
Q_INVOKABLE virtual void unregisterTimer(PluginTimer *timer = nullptr) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PLUGINTIMER_H
|
#endif // PLUGINTIMER_H
|
||||||
|
|||||||
@ -29,13 +29,20 @@
|
|||||||
|
|
||||||
#include "libnymea.h"
|
#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: \
|
public: \
|
||||||
type##Id(const QUuid &uuid): QUuid(uuid) {} \
|
type##Id(const QUuid &uuid): GadgetUuid(uuid) {} \
|
||||||
type##Id(): QUuid() {} \
|
type##Id(): GadgetUuid() {} \
|
||||||
static type##Id create##type##Id() { return type##Id(QUuid::createUuid().toString()); } \
|
static type##Id create##type##Id() { return type##Id(QUuid::createUuid()); } \
|
||||||
static type##Id fromUuid(const QUuid &uuid) { return type##Id(uuid.toString()); } \
|
|
||||||
bool operator==(const type##Id &other) const { \
|
bool operator==(const type##Id &other) const { \
|
||||||
return toString() == other.toString(); \
|
return toString() == other.toString(); \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@ -599,7 +599,7 @@ void TestLogging::testHouseKeeping()
|
|||||||
deviceParams.append(httpParam);
|
deviceParams.append(httpParam);
|
||||||
params.insert("deviceParams", deviceParams);
|
params.insert("deviceParams", deviceParams);
|
||||||
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
|
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.");
|
QVERIFY2(!deviceId.isNull(), "Something went wrong creating the device for testing.");
|
||||||
|
|
||||||
// Trigger something that creates a logging entry
|
// Trigger something that creates a logging entry
|
||||||
|
|||||||
@ -2766,7 +2766,7 @@ void TestRules::testInitStatesActive()
|
|||||||
params.insert("exitActions", exitActions);
|
params.insert("exitActions", exitActions);
|
||||||
|
|
||||||
QVariant response = injectAndWait("Rules.AddRule", params);
|
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");
|
QVERIFY2(!ruleId.isNull(), "Error adding rule");
|
||||||
|
|
||||||
// Get the current state value, make sure it's false
|
// Get the current state value, make sure it's false
|
||||||
@ -3140,7 +3140,7 @@ void TestRules::testHousekeeping()
|
|||||||
deviceParams.append(httpParam);
|
deviceParams.append(httpParam);
|
||||||
params.insert("deviceParams", deviceParams);
|
params.insert("deviceParams", deviceParams);
|
||||||
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
|
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.");
|
QVERIFY2(!deviceId.isNull(), "Something went wrong creating the device for testing.");
|
||||||
|
|
||||||
// Create a rule with this device
|
// Create a rule with this device
|
||||||
@ -3181,7 +3181,7 @@ void TestRules::testHousekeeping()
|
|||||||
}
|
}
|
||||||
|
|
||||||
response = injectAndWait("Rules.AddRule", params);
|
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.
|
// Verfy that the rule has been created successfully and our device is in there.
|
||||||
|
|||||||
Reference in New Issue
Block a user