From aabebcfac9f44be0ee598dff25d3618e4e8c1e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 3 Apr 2019 14:14:18 +0200 Subject: [PATCH 1/7] Change devicemanager finished info from warning to default debug --- libnymea/devicemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnymea/devicemanager.cpp b/libnymea/devicemanager.cpp index be059f81..78a3500a 100644 --- a/libnymea/devicemanager.cpp +++ b/libnymea/devicemanager.cpp @@ -1452,7 +1452,7 @@ void DeviceManager::onAutoDeviceDisappeared(const DeviceId &deviceId) void DeviceManager::onLoaded() { - qCWarning(dcDeviceManager()) << "Done loading plugins and devices."; + qCDebug(dcDeviceManager()) << "Done loading plugins and devices."; emit loaded(); // schedule some housekeeping... From 13b0f38693c635495a247da0d5c8501d5c61e529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 3 Apr 2019 15:11:43 +0200 Subject: [PATCH 2/7] Add reconfigure auto device mechanism --- libnymea/devicemanager.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/libnymea/devicemanager.cpp b/libnymea/devicemanager.cpp index 78a3500a..70290368 100644 --- a/libnymea/devicemanager.cpp +++ b/libnymea/devicemanager.cpp @@ -1398,7 +1398,22 @@ void DeviceManager::onAutoDevicesAppeared(const DeviceClassId &deviceClassId, co qCWarning(dcDeviceManager()) << "Invalid parent device id. Not adding device to the system."; continue; } - Device *device = new Device(plugin->pluginId(), deviceClassId, this); + + Device *device = nullptr; + + // If the appreaed auto device holds a valid device id, do a reconfiguration for this device + if (!deviceDescriptor.deviceId().isNull()) { + device = findConfiguredDevice(deviceDescriptor.deviceId()); + if (!device) { + qCWarning(dcDeviceManager()) << "Could not find device for auto device descriptor" << deviceDescriptor.deviceId(); + continue; + } + qCDebug(dcDeviceManager()) << "Start reconfiguring auto device" << device; + reconfigureDevice(deviceDescriptor.deviceId(), deviceDescriptor.params()); + continue; + } + + device = new Device(plugin->pluginId(), deviceClassId, this); device->m_autoCreated = true; device->setName(deviceDescriptor.title()); device->setParams(deviceDescriptor.params()); From beb00aa0f1e38f5fe67d9df28d88c7c2acc59594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 3 Apr 2019 19:56:25 +0200 Subject: [PATCH 3/7] Implement autodevice reconfigure in mock plugin and prepare tests --- libnymea/plugin/device.cpp | 8 ++++++++ libnymea/plugin/device.h | 2 ++ plugins/mock/devicepluginmock.cpp | 18 ++++++++++++++++++ plugins/mock/devicepluginmock.h | 1 + plugins/mock/httpdaemon.cpp | 3 +++ plugins/mock/httpdaemon.h | 1 + tests/auto/devices/testdevices.cpp | 17 +++++++++++++++++ 7 files changed, 50 insertions(+) diff --git a/libnymea/plugin/device.cpp b/libnymea/plugin/device.cpp index 70a4f55d..301a2f18 100644 --- a/libnymea/plugin/device.cpp +++ b/libnymea/plugin/device.cpp @@ -260,3 +260,11 @@ Device *Devices::findById(const DeviceId &id) } return nullptr; } + +QDebug operator<<(QDebug dbg, Device *device) +{ + dbg.nospace() << "Device(" << device->name(); + dbg.nospace() << ", id" << device->id(); + dbg.nospace() << ", deviceClassId" << device->deviceClassId() << ")"; + return dbg.space(); +} diff --git a/libnymea/plugin/device.h b/libnymea/plugin/device.h index 0bac6471..1e17f3e9 100644 --- a/libnymea/plugin/device.h +++ b/libnymea/plugin/device.h @@ -94,6 +94,8 @@ private: bool m_autoCreated = false; }; +QDebug operator<<(QDebug dbg, Device *device); + class Devices: public QList { public: diff --git a/plugins/mock/devicepluginmock.cpp b/plugins/mock/devicepluginmock.cpp index 7671bb4a..c321bab4 100644 --- a/plugins/mock/devicepluginmock.cpp +++ b/plugins/mock/devicepluginmock.cpp @@ -383,6 +383,24 @@ void DevicePluginMock::onDisappear() emit autoDeviceDisappeared(device->id()); } +void DevicePluginMock::onReconfigureAutoDevice() +{ + HttpDaemon *daemon = qobject_cast(sender()); + if (!daemon) { + return; + } + Device *device = m_daemons.key(daemon); + qCDebug(dcMockDevice) << "Reconfigure auto device for" << device; + + DeviceDescriptor deviceDescriptor; + deviceDescriptor.setTitle(device->name() + " (reconfigured)"); + deviceDescriptor.setDescription("This auto device was reconfigured"); + deviceDescriptor.setDeviceId(device->id()); + deviceDescriptor.setParams(device->params()); + + emit autoDevicesAppeared(mockDeviceAutoDeviceClassId, { deviceDescriptor }); +} + void DevicePluginMock::emitDevicesDiscovered() { QList deviceDescriptors; diff --git a/plugins/mock/devicepluginmock.h b/plugins/mock/devicepluginmock.h index 72e782dd..8efe6d25 100644 --- a/plugins/mock/devicepluginmock.h +++ b/plugins/mock/devicepluginmock.h @@ -59,6 +59,7 @@ private slots: void setState(const StateTypeId &stateTypeId, const QVariant &value); void triggerEvent(const EventTypeId &id); void onDisappear(); + void onReconfigureAutoDevice(); void emitDevicesDiscovered(); void emitPushButtonDevicesDiscovered(); void emitDisplayPinDevicesDiscovered(); diff --git a/plugins/mock/httpdaemon.cpp b/plugins/mock/httpdaemon.cpp index 1aa3f727..c0799b7b 100644 --- a/plugins/mock/httpdaemon.cpp +++ b/plugins/mock/httpdaemon.cpp @@ -114,6 +114,9 @@ void HttpDaemon::readClient() } else if (url.path() == "/disappear") { qCDebug(dcMockDevice) << "Should disappear"; emit disappear(); + } else if (url.path() == "/reconfigureautodevice") { + qCDebug(dcMockDevice) << "Reconfigure auto device"; + emit reconfigureAutodevice(); } if (tokens[0] == "GET") { diff --git a/plugins/mock/httpdaemon.h b/plugins/mock/httpdaemon.h index ea86ae46..277bb04a 100644 --- a/plugins/mock/httpdaemon.h +++ b/plugins/mock/httpdaemon.h @@ -47,6 +47,7 @@ signals: void setState(const StateTypeId &stateTypeId, const QVariant &value); void triggerEvent(const EventTypeId &eventTypeId); void disappear(); + void reconfigureAutodevice(); private slots: void readClient(); diff --git a/tests/auto/devices/testdevices.cpp b/tests/auto/devices/testdevices.cpp index 39087bff..0661eac0 100644 --- a/tests/auto/devices/testdevices.cpp +++ b/tests/auto/devices/testdevices.cpp @@ -91,6 +91,7 @@ private slots: void reconfigureByDiscovery(); void reconfigureByDiscoveryAndPair(); + void reconfigureAutodevice(); void removeDevice_data(); void removeDevice(); @@ -1275,6 +1276,22 @@ void TestDevices::reconfigureByDiscoveryAndPair() } +void TestDevices::reconfigureAutodevice() +{ + // Get the current autodevice + + QVariant response = injectAndWait("Devices.GetConfiguredDevices"); + QVariantList devices = response.toMap().value("params").toMap().value("devices").toList(); + + QVariantMap autoDevice; + foreach (const QVariant &deviceVariant, devices) { + QVariantMap deviceMap = deviceVariant.toMap(); + qDebug() << deviceMap; + + } + +} + void TestDevices::removeDevice_data() { From 36778e8eda3264d99a40cb75ec07445c13f2aade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 3 Apr 2019 21:55:16 +0200 Subject: [PATCH 4/7] Add test trigger for auto device reconfiguration --- plugins/mock/devicepluginmock.cpp | 1 + tests/auto/devices/testdevices.cpp | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/plugins/mock/devicepluginmock.cpp b/plugins/mock/devicepluginmock.cpp index c321bab4..3407a308 100644 --- a/plugins/mock/devicepluginmock.cpp +++ b/plugins/mock/devicepluginmock.cpp @@ -110,6 +110,7 @@ DeviceManager::DeviceSetupStatus DevicePluginMock::setupDevice(Device *device) connect(daemon, &HttpDaemon::setState, this, &DevicePluginMock::setState); // Keep this queued or it might happen that the HttpDaemon is deleted before it is able to reply to the caller connect(daemon, &HttpDaemon::disappear, this, &DevicePluginMock::onDisappear, Qt::QueuedConnection); + connect(daemon, &HttpDaemon::reconfigureAutodevice, this, &DevicePluginMock::onReconfigureAutoDevice, Qt::QueuedConnection); if (async) { m_asyncSetupDevices.append(device); diff --git a/tests/auto/devices/testdevices.cpp b/tests/auto/devices/testdevices.cpp index 0661eac0..8e5dc938 100644 --- a/tests/auto/devices/testdevices.cpp +++ b/tests/auto/devices/testdevices.cpp @@ -52,6 +52,8 @@ private slots: void storedDevices(); + void reconfigureAutodevice(); + void discoverDevices_data(); void discoverDevices(); @@ -91,7 +93,6 @@ private slots: void reconfigureByDiscovery(); void reconfigureByDiscoveryAndPair(); - void reconfigureAutodevice(); void removeDevice_data(); void removeDevice(); @@ -1278,17 +1279,23 @@ void TestDevices::reconfigureByDiscoveryAndPair() void TestDevices::reconfigureAutodevice() { - // Get the current autodevice + qCDebug(dcTests()) << "Reconfigure auto device"; - QVariant response = injectAndWait("Devices.GetConfiguredDevices"); - QVariantList devices = response.toMap().value("params").toMap().value("devices").toList(); + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceAutoClassId); + QVERIFY2(devices.count() > 0, "There needs to be at least one auto-created Mock Device for this test"); + Device *device = devices.first(); + + // Setup connection to mock client + QNetworkAccessManager *nam = new QNetworkAccessManager(this); + QSignalSpy spy(nam, SIGNAL(finished(QNetworkReply*))); + + // trigger reconfigure signal in mock device + QNetworkReply *reply = nam->get(QNetworkRequest(QUrl(QString("http://localhost:%1/reconfigureautodevice").arg(device->paramValue(httpportParamTypeId).toInt())))); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); - QVariantMap autoDevice; - foreach (const QVariant &deviceVariant, devices) { - QVariantMap deviceMap = deviceVariant.toMap(); - qDebug() << deviceMap; - } } From 695914f4978bcddee08ced828d42f684a4e1a535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 4 Apr 2019 09:53:43 +0200 Subject: [PATCH 5/7] Finish test implementation and verify auto device reconfiguration does work. --- plugins/mock/devicepluginmock.cpp | 16 +++++++++++----- tests/auto/devices/testdevices.cpp | 23 ++++++++++++++--------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/plugins/mock/devicepluginmock.cpp b/plugins/mock/devicepluginmock.cpp index 3407a308..667a9058 100644 --- a/plugins/mock/devicepluginmock.cpp +++ b/plugins/mock/devicepluginmock.cpp @@ -386,18 +386,24 @@ void DevicePluginMock::onDisappear() void DevicePluginMock::onReconfigureAutoDevice() { - HttpDaemon *daemon = qobject_cast(sender()); - if (!daemon) { + HttpDaemon *daemon = qobject_cast(sender()); + if (!daemon) return; - } + Device *device = m_daemons.key(daemon); - qCDebug(dcMockDevice) << "Reconfigure auto device for" << device; + qCDebug(dcMockDevice()) << "Reconfigure auto device for" << device << device->params(); + + int currentPort = device->params().paramValue(mockDeviceAutoDeviceHttpportParamTypeId).toInt(); + + // Note: the reconfigure makes the http server listen on port + 1 + ParamList params; + params.append(Param(mockDeviceAutoDeviceHttpportParamTypeId, currentPort + 1)); DeviceDescriptor deviceDescriptor; deviceDescriptor.setTitle(device->name() + " (reconfigured)"); deviceDescriptor.setDescription("This auto device was reconfigured"); deviceDescriptor.setDeviceId(device->id()); - deviceDescriptor.setParams(device->params()); + deviceDescriptor.setParams(params); emit autoDevicesAppeared(mockDeviceAutoDeviceClassId, { deviceDescriptor }); } diff --git a/tests/auto/devices/testdevices.cpp b/tests/auto/devices/testdevices.cpp index 8e5dc938..3c1abbd7 100644 --- a/tests/auto/devices/testdevices.cpp +++ b/tests/auto/devices/testdevices.cpp @@ -52,8 +52,6 @@ private slots: void storedDevices(); - void reconfigureAutodevice(); - void discoverDevices_data(); void discoverDevices(); @@ -93,6 +91,7 @@ private slots: void reconfigureByDiscovery(); void reconfigureByDiscoveryAndPair(); + void reconfigureAutodevice(); void removeDevice_data(); void removeDevice(); @@ -1281,22 +1280,28 @@ void TestDevices::reconfigureAutodevice() { qCDebug(dcTests()) << "Reconfigure auto device"; + // Get the autodevice QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceAutoClassId); QVERIFY2(devices.count() > 0, "There needs to be at least one auto-created Mock Device for this test"); - Device *device = devices.first(); - // Setup connection to mock client + // Get current auto device infos + Device *currentDevice = devices.first(); + DeviceId deviceId = currentDevice->id(); + int currentPort = currentDevice->paramValue(httpportParamTypeId).toInt(); + + // Trigger reconfigure signal in mock device QNetworkAccessManager *nam = new QNetworkAccessManager(this); QSignalSpy spy(nam, SIGNAL(finished(QNetworkReply*))); - - // trigger reconfigure signal in mock device - QNetworkReply *reply = nam->get(QNetworkRequest(QUrl(QString("http://localhost:%1/reconfigureautodevice").arg(device->paramValue(httpportParamTypeId).toInt())))); + QNetworkReply *reply = nam->get(QNetworkRequest(QUrl(QString("http://localhost:%1/reconfigureautodevice").arg(currentPort)))); spy.wait(); QCOMPARE(spy.count(), 1); reply->deleteLater(); - - + Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(deviceId); + QVERIFY(device); + int newPort = device->paramValue(httpportParamTypeId).toInt(); + // Note: reconfigure autodevice increases the http port by 1 + QVERIFY(newPort == currentPort + 1); } From 7bd863b13131124122b9991cc7acc40c66870598 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 9 Apr 2019 13:05:21 +0200 Subject: [PATCH 6/7] Add some more debug prints to see where it is going wrong. --- libnymea/devicemanager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libnymea/devicemanager.cpp b/libnymea/devicemanager.cpp index 70290368..1959e60f 100644 --- a/libnymea/devicemanager.cpp +++ b/libnymea/devicemanager.cpp @@ -469,17 +469,20 @@ DeviceManager::DeviceError DeviceManager::reconfigureDevice(const DeviceId &devi { Device *device = findConfiguredDevice(deviceId); if (!device) { + qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Device with id" << deviceId.toString() << "not found."; return DeviceErrorDeviceNotFound; } ParamList effectiveParams = params; DeviceClass deviceClass = findDeviceClass(device->deviceClassId()); if (deviceClass.id().isNull()) { + qCWarning(dcDeviceManager()) << "Cannot reconfigure device. DeviceClass for device" << device->name() << deviceId.toString() << "not found."; return DeviceErrorDeviceClassNotFound; } DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId()); if (!plugin) { + qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Plugin for DeviceClass" << deviceClass.displayName() << deviceClass.id().toString() << "not found."; return DeviceErrorPluginNotFound; } @@ -489,8 +492,10 @@ DeviceManager::DeviceError DeviceManager::reconfigureDevice(const DeviceId &devi foreach (const ParamType ¶mType, deviceClass.paramTypes()) { foreach (const Param ¶m, params) { if (paramType.id() == param.paramTypeId()) { - if (paramType.readOnly()) + if (paramType.readOnly()) { + qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Read-only parameters set by user."; return DeviceErrorParameterNotWritable; + } } } } @@ -498,6 +503,7 @@ DeviceManager::DeviceError DeviceManager::reconfigureDevice(const DeviceId &devi DeviceError result = verifyParams(deviceClass.paramTypes(), effectiveParams, false); if (result != DeviceErrorNoError) { + qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Params failed validation."; return result; } From b2228bcf25a57ee11c4334f7fa1c43e786a5862d Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 3 Apr 2019 18:16:13 +0200 Subject: [PATCH 7/7] Add a method to filter Devices --- libnymea/plugin/device.cpp | 19 +++++++++++++++++++ libnymea/plugin/device.h | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libnymea/plugin/device.cpp b/libnymea/plugin/device.cpp index 301a2f18..d47e8b63 100644 --- a/libnymea/plugin/device.cpp +++ b/libnymea/plugin/device.cpp @@ -268,3 +268,22 @@ QDebug operator<<(QDebug dbg, Device *device) dbg.nospace() << ", deviceClassId" << device->deviceClassId() << ")"; return dbg.space(); } + +/*! Filter a Devices list by a parameter. Only Devices having a parameter of the given + \a paramTypeId will be returned. If \a value is given and it is not null, only Devices + with the given \a paramTypeId and the same \a value will be returned. + */ +Devices Devices::filterByParam(const ParamTypeId ¶mTypeId, const QVariant &value) +{ + Devices ret; + foreach (Device* device, *this) { + if (paramTypeId != paramTypeId) { + continue; + } + if (!value.isNull() && device->paramValue(paramTypeId) != value) { + continue; + } + ret << device; + } + return ret; +} diff --git a/libnymea/plugin/device.h b/libnymea/plugin/device.h index 1e17f3e9..12f8803f 100644 --- a/libnymea/plugin/device.h +++ b/libnymea/plugin/device.h @@ -96,12 +96,13 @@ private: QDebug operator<<(QDebug dbg, Device *device); -class Devices: public QList +class LIBNYMEA_EXPORT Devices: public QList { public: Devices() = default; Devices(const QList &other); Device* findById(const DeviceId &id); + Devices filterByParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant()); }; #endif