Merge PR #146: Add a method to filter Devices

This commit is contained in:
Jenkins 2019-04-12 13:42:30 +02:00
commit ad9261290d
8 changed files with 114 additions and 4 deletions

View File

@ -469,17 +469,20 @@ DeviceManager::DeviceError DeviceManager::reconfigureDevice(const DeviceId &devi
{ {
Device *device = findConfiguredDevice(deviceId); Device *device = findConfiguredDevice(deviceId);
if (!device) { if (!device) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Device with id" << deviceId.toString() << "not found.";
return DeviceErrorDeviceNotFound; return DeviceErrorDeviceNotFound;
} }
ParamList effectiveParams = params; ParamList effectiveParams = params;
DeviceClass deviceClass = findDeviceClass(device->deviceClassId()); DeviceClass deviceClass = findDeviceClass(device->deviceClassId());
if (deviceClass.id().isNull()) { if (deviceClass.id().isNull()) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. DeviceClass for device" << device->name() << deviceId.toString() << "not found.";
return DeviceErrorDeviceClassNotFound; return DeviceErrorDeviceClassNotFound;
} }
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId()); DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
if (!plugin) { if (!plugin) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Plugin for DeviceClass" << deviceClass.displayName() << deviceClass.id().toString() << "not found.";
return DeviceErrorPluginNotFound; return DeviceErrorPluginNotFound;
} }
@ -489,8 +492,10 @@ DeviceManager::DeviceError DeviceManager::reconfigureDevice(const DeviceId &devi
foreach (const ParamType &paramType, deviceClass.paramTypes()) { foreach (const ParamType &paramType, deviceClass.paramTypes()) {
foreach (const Param &param, params) { foreach (const Param &param, params) {
if (paramType.id() == param.paramTypeId()) { if (paramType.id() == param.paramTypeId()) {
if (paramType.readOnly()) if (paramType.readOnly()) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Read-only parameters set by user.";
return DeviceErrorParameterNotWritable; return DeviceErrorParameterNotWritable;
}
} }
} }
} }
@ -498,6 +503,7 @@ DeviceManager::DeviceError DeviceManager::reconfigureDevice(const DeviceId &devi
DeviceError result = verifyParams(deviceClass.paramTypes(), effectiveParams, false); DeviceError result = verifyParams(deviceClass.paramTypes(), effectiveParams, false);
if (result != DeviceErrorNoError) { if (result != DeviceErrorNoError) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Params failed validation.";
return result; return result;
} }
@ -1398,7 +1404,22 @@ void DeviceManager::onAutoDevicesAppeared(const DeviceClassId &deviceClassId, co
qCWarning(dcDeviceManager()) << "Invalid parent device id. Not adding device to the system."; qCWarning(dcDeviceManager()) << "Invalid parent device id. Not adding device to the system.";
continue; 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->m_autoCreated = true;
device->setName(deviceDescriptor.title()); device->setName(deviceDescriptor.title());
device->setParams(deviceDescriptor.params()); device->setParams(deviceDescriptor.params());
@ -1452,7 +1473,7 @@ void DeviceManager::onAutoDeviceDisappeared(const DeviceId &deviceId)
void DeviceManager::onLoaded() void DeviceManager::onLoaded()
{ {
qCWarning(dcDeviceManager()) << "Done loading plugins and devices."; qCDebug(dcDeviceManager()) << "Done loading plugins and devices.";
emit loaded(); emit loaded();
// schedule some housekeeping... // schedule some housekeeping...

View File

@ -260,3 +260,30 @@ Device *Devices::findById(const DeviceId &id)
} }
return nullptr; 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();
}
/*! 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 &paramTypeId, 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;
}

View File

@ -94,12 +94,15 @@ private:
bool m_autoCreated = false; bool m_autoCreated = false;
}; };
class Devices: public QList<Device*> QDebug operator<<(QDebug dbg, Device *device);
class LIBNYMEA_EXPORT Devices: public QList<Device*>
{ {
public: public:
Devices() = default; Devices() = default;
Devices(const QList<Device *> &other); Devices(const QList<Device *> &other);
Device* findById(const DeviceId &id); Device* findById(const DeviceId &id);
Devices filterByParam(const ParamTypeId &paramTypeId, const QVariant &value = QVariant());
}; };
#endif #endif

View File

@ -110,6 +110,7 @@ DeviceManager::DeviceSetupStatus DevicePluginMock::setupDevice(Device *device)
connect(daemon, &HttpDaemon::setState, this, &DevicePluginMock::setState); 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 // 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::disappear, this, &DevicePluginMock::onDisappear, Qt::QueuedConnection);
connect(daemon, &HttpDaemon::reconfigureAutodevice, this, &DevicePluginMock::onReconfigureAutoDevice, Qt::QueuedConnection);
if (async) { if (async) {
m_asyncSetupDevices.append(device); m_asyncSetupDevices.append(device);
@ -383,6 +384,30 @@ void DevicePluginMock::onDisappear()
emit autoDeviceDisappeared(device->id()); emit autoDeviceDisappeared(device->id());
} }
void DevicePluginMock::onReconfigureAutoDevice()
{
HttpDaemon *daemon = qobject_cast<HttpDaemon *>(sender());
if (!daemon)
return;
Device *device = m_daemons.key(daemon);
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(params);
emit autoDevicesAppeared(mockDeviceAutoDeviceClassId, { deviceDescriptor });
}
void DevicePluginMock::emitDevicesDiscovered() void DevicePluginMock::emitDevicesDiscovered()
{ {
QList<DeviceDescriptor> deviceDescriptors; QList<DeviceDescriptor> deviceDescriptors;

View File

@ -59,6 +59,7 @@ private slots:
void setState(const StateTypeId &stateTypeId, const QVariant &value); void setState(const StateTypeId &stateTypeId, const QVariant &value);
void triggerEvent(const EventTypeId &id); void triggerEvent(const EventTypeId &id);
void onDisappear(); void onDisappear();
void onReconfigureAutoDevice();
void emitDevicesDiscovered(); void emitDevicesDiscovered();
void emitPushButtonDevicesDiscovered(); void emitPushButtonDevicesDiscovered();
void emitDisplayPinDevicesDiscovered(); void emitDisplayPinDevicesDiscovered();

View File

@ -114,6 +114,9 @@ void HttpDaemon::readClient()
} else if (url.path() == "/disappear") { } else if (url.path() == "/disappear") {
qCDebug(dcMockDevice) << "Should disappear"; qCDebug(dcMockDevice) << "Should disappear";
emit disappear(); emit disappear();
} else if (url.path() == "/reconfigureautodevice") {
qCDebug(dcMockDevice) << "Reconfigure auto device";
emit reconfigureAutodevice();
} }
if (tokens[0] == "GET") { if (tokens[0] == "GET") {

View File

@ -47,6 +47,7 @@ signals:
void setState(const StateTypeId &stateTypeId, const QVariant &value); void setState(const StateTypeId &stateTypeId, const QVariant &value);
void triggerEvent(const EventTypeId &eventTypeId); void triggerEvent(const EventTypeId &eventTypeId);
void disappear(); void disappear();
void reconfigureAutodevice();
private slots: private slots:
void readClient(); void readClient();

View File

@ -91,6 +91,7 @@ private slots:
void reconfigureByDiscovery(); void reconfigureByDiscovery();
void reconfigureByDiscoveryAndPair(); void reconfigureByDiscoveryAndPair();
void reconfigureAutodevice();
void removeDevice_data(); void removeDevice_data();
void removeDevice(); void removeDevice();
@ -1275,6 +1276,34 @@ void TestDevices::reconfigureByDiscoveryAndPair()
} }
void TestDevices::reconfigureAutodevice()
{
qCDebug(dcTests()) << "Reconfigure auto device";
// Get the autodevice
QList<Device *> devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceAutoClassId);
QVERIFY2(devices.count() > 0, "There needs to be at least one auto-created Mock Device for this test");
// 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*)));
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);
}
void TestDevices::removeDevice_data() void TestDevices::removeDevice_data()
{ {