Merge PR #223: More complete setup

This commit is contained in:
Jenkins nymea 2019-12-01 00:04:59 +01:00
commit 9710aa5927
11 changed files with 325 additions and 246 deletions

View File

@ -169,7 +169,7 @@ Device::DeviceError DeviceManagerImplementation::setPluginConfig(const PluginId
return Device::DeviceErrorPluginNotFound;
}
ParamList params = pluginConfig;
ParamList params = buildParams(plugin->configurationDescription(), pluginConfig);
Device::DeviceError verify = DeviceUtils::verifyParams(plugin->configurationDescription(), params);
if (verify != Device::DeviceErrorNoError)
return verify;
@ -248,8 +248,7 @@ DeviceDiscoveryInfo* DeviceManagerImplementation::discoverDevices(const DeviceCl
return discoveryInfo;
}
// Create a copy of the parameter list because we might modify it (fillig in default values etc)
ParamList effectiveParams = params;
ParamList effectiveParams = buildParams(deviceClass.discoveryParamTypes(), params);
Device::DeviceError result = DeviceUtils::verifyParams(deviceClass.discoveryParamTypes(), effectiveParams);
if (result != Device::DeviceErrorNoError) {
qCWarning(dcDeviceManager) << "Device discovery failed. Parameter verification failed.";
@ -266,7 +265,7 @@ DeviceDiscoveryInfo* DeviceManagerImplementation::discoverDevices(const DeviceCl
}
qCDebug(dcDeviceManager()) << "Discovery finished. Found devices:" << discoveryInfo->deviceDescriptors().count();
foreach (const DeviceDescriptor &descriptor, discoveryInfo->deviceDescriptors()) {
m_discoveredDevices[descriptor.deviceClassId()].insert(descriptor.id(), descriptor);
m_discoveredDevices.insert(descriptor.id(), descriptor);
}
});
@ -280,9 +279,9 @@ DeviceDiscoveryInfo* DeviceManagerImplementation::discoverDevices(const DeviceCl
* Optionally you can supply an id yourself if you must keep track of the added device. If you don't supply it, a new one will
* be generated. Only devices with \l{DeviceClass}{CreateMethodUser} can be created using this method.
* Returns \l{DeviceError} to inform about the result. */
DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id)
DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDevice(const DeviceClassId &deviceClassId, const ParamList &params, const QString &name)
{
return addConfiguredDeviceInternal(deviceClassId, name, params, id);
return addConfiguredDeviceInternal(deviceClassId, name, params);
}
/*! Add a new configured device for the given \l{DeviceClass} the given DeviceDescriptorId and \a deviceId. Only devices with \l{DeviceClass}{CreateMethodDiscovery}
@ -291,9 +290,16 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDevice(const DeviceCl
* are used but can be overridden here.
*
* Returns \l{DeviceError} to inform about the result. */
DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId, const ParamList &params, const DeviceId &deviceId)
DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params, const QString &name)
{
DeviceClass deviceClass = findDeviceClass(deviceClassId);
DeviceDescriptor descriptor = m_discoveredDevices.value(deviceDescriptorId);
if (!descriptor.isValid()) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
return info;
}
DeviceClass deviceClass = findDeviceClass(descriptor.deviceClassId());
if (!deviceClass.isValid()) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceClassNotFound);
@ -305,24 +311,10 @@ DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceCl
return info;
}
DeviceDescriptor descriptor = m_discoveredDevices.value(deviceClassId).value(deviceDescriptorId);
if (!descriptor.isValid()) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
return info;
}
// Merging params from descriptor and user provided ones
ParamList finalParams = buildParams(deviceClass.paramTypes(), params, descriptor.params());
// Merge params from discovered descriptor and additional overrides provided on API call. User provided params have higher priority than discovery params.
ParamList finalParams;
foreach (const ParamType &paramType, deviceClass.paramTypes()) {
if (params.hasParam(paramType.id())) {
finalParams.append(Param(paramType.id(), params.paramValue(paramType.id())));
} else if (descriptor.params().hasParam(paramType.id())) {
finalParams.append(Param(paramType.id(), descriptor.params().paramValue(paramType.id())));
}
}
return addConfiguredDeviceInternal(deviceClassId, name, finalParams, deviceId, descriptor.parentDeviceId());
return addConfiguredDeviceInternal(descriptor.deviceClassId(), name, finalParams, descriptor.parentDeviceId());
}
@ -331,7 +323,7 @@ DeviceSetupInfo *DeviceManagerImplementation::addConfiguredDevice(const DeviceCl
* from a discovery or if the user set them. If it came from discovery not writable parameters (readOnly) will be changed too.
*
* Returns \l{DeviceError} to inform about the result. */
DeviceSetupInfo* DeviceManagerImplementation::reconfigureDevice(const DeviceId &deviceId, const ParamList &params, bool fromDiscoveryOrAuto)
DeviceSetupInfo* DeviceManagerImplementation::reconfigureDevice(const DeviceId &deviceId, const ParamList &params, const QString &name)
{
Device *device = findConfiguredDevice(deviceId);
if (!device) {
@ -341,7 +333,6 @@ DeviceSetupInfo* DeviceManagerImplementation::reconfigureDevice(const DeviceId &
return info;
}
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.";
@ -350,32 +341,69 @@ DeviceSetupInfo* DeviceManagerImplementation::reconfigureDevice(const DeviceId &
return info;
}
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
foreach (const ParamType &paramType, deviceClass.paramTypes()) {
if (paramType.readOnly() && params.hasParam(paramType.id())) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
qCWarning(dcDeviceManager()) << "Parameter" << paramType.name() << paramType.id() << "is not writable";
info->finish(Device::DeviceErrorParameterNotWritable);
return info;
}
}
ParamList finalParams = buildParams(deviceClass.paramTypes(), params);
return reconfigureDeviceInternal(device, finalParams, name);
}
/*! Edit the \l{Param}{Params} of a configured device to the \l{Param}{Params} of the DeviceDescriptor with the
* given \a deviceId to the given DeviceDescriptorId.
* Only devices with \l{DeviceClass}{CreateMethodDiscovery} can be changed using this method.
* The \a deviceDescriptorId must refer to an existing DeviceDescriptorId from the discovery.
* This method allows to rediscover a device and update it's \l{Param}{Params}.
*
* Returns \l{DeviceError} to inform about the result. */
DeviceSetupInfo *DeviceManagerImplementation::reconfigureDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params, const QString &name)
{
DeviceDescriptor descriptor = m_discoveredDevices.value(deviceDescriptorId);
if (!descriptor.isValid()) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. No deviceDescriptor with ID" << deviceDescriptorId << "found.";
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
return info;
}
Device *device = findConfiguredDevice(descriptor.deviceId());
if (!device) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. No device with ID" << descriptor.deviceId() << "found.";
info->finish(Device::DeviceErrorDeviceNotFound);
return info;
}
DeviceClass deviceClass = findDeviceClass(device->deviceClassId());
if (!deviceClass.isValid()) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. No deviceClass with ID" << device->deviceClassId() << "found.";
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceClassNotFound);
return info;
}
ParamList finalParams = buildParams(device->deviceClass().paramTypes(), params, descriptor.params());
return reconfigureDeviceInternal(device, finalParams, name);
}
DeviceSetupInfo *DeviceManagerImplementation::reconfigureDeviceInternal(Device *device, const ParamList &params, const QString &name)
{
DevicePlugin *plugin = m_devicePlugins.value(device->deviceClass().pluginId());
if (!plugin) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Plugin for DeviceClass" << deviceClass.displayName() << deviceClass.id().toString() << "not found.";
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Plugin for DeviceClass" << device->deviceClassId().toString() << "not found.";
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorPluginNotFound);
return info;
}
// if the params are discovered and not set by the user
if (!fromDiscoveryOrAuto) {
// check if one of the given params is not editable
foreach (const ParamType &paramType, deviceClass.paramTypes()) {
foreach (const Param &param, params) {
if (paramType.id() == param.paramTypeId()) {
if (paramType.readOnly()) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Read-only parameters set by user.";
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorParameterNotWritable);
return info;
}
}
}
}
}
Device::DeviceError result = DeviceUtils::verifyParams(deviceClass.paramTypes(), effectiveParams, false);
ParamList finalParams = buildParams(device->deviceClass().paramTypes(), params);
Device::DeviceError result = DeviceUtils::verifyParams(device->deviceClass().paramTypes(), finalParams);
if (result != Device::DeviceErrorNoError) {
qCWarning(dcDeviceManager()) << "Cannot reconfigure device. Params failed validation.";
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
@ -390,10 +418,14 @@ DeviceSetupInfo* DeviceManagerImplementation::reconfigureDevice(const DeviceId &
device->setSetupComplete(false);
// set new params
foreach (const Param &param, effectiveParams) {
foreach (const Param &param, params) {
device->setParamValue(param.paramTypeId(), param.value());
}
if (!name.isEmpty()) {
device->setName(name);
}
// try to setup the device with the new params
DeviceSetupInfo *info = new DeviceSetupInfo(device, this, 30000);
plugin->setupDevice(info);
@ -415,44 +447,7 @@ DeviceSetupInfo* DeviceManagerImplementation::reconfigureDevice(const DeviceId &
});
return info;
}
/*! Edit the \l{Param}{Params} of a configured device to the \l{Param}{Params} of the DeviceDescriptor with the
* given \a deviceId to the given DeviceDescriptorId.
* Only devices with \l{DeviceClass}{CreateMethodDiscovery} can be changed using this method.
* The \a deviceDescriptorId must refer to an existing DeviceDescriptorId from the discovery.
* This method allows to rediscover a device and update it's \l{Param}{Params}.
*
* Returns \l{DeviceError} to inform about the result. */
DeviceSetupInfo *DeviceManagerImplementation::reconfigureDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId)
{
Device *device = findConfiguredDevice(deviceId);
if (!device) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceNotFound);
return info;
}
DeviceClass deviceClass = findDeviceClass(device->deviceClassId());
if (!deviceClass.isValid()) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceClassNotFound);
return info;
}
if (!deviceClass.createMethods().testFlag(DeviceClass::CreateMethodDiscovery)) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorCreationMethodNotSupported);
return info;
}
DeviceDescriptor descriptor = m_discoveredDevices.value(deviceClass.id()).value(deviceDescriptorId);
if (!descriptor.isValid()) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
return info;
}
return reconfigureDevice(deviceId, descriptor.params(), true);
}
/*! Edit the \a name of the \l{Device} with the given \a deviceId.
@ -478,57 +473,89 @@ Device::DeviceError DeviceManagerImplementation::setDeviceSettings(const DeviceI
qCWarning(dcDeviceManager()) << "Cannot set device settings. Device" << deviceId.toString() << "not found";
return Device::DeviceErrorDeviceNotFound;
}
ParamList effectiveSettings = settings;
Device::DeviceError status = DeviceUtils::verifyParams(findDeviceClass(device->deviceClassId()).settingsTypes(), effectiveSettings);
// build a list of settings using: a) provided new settings b) previous settings and c) default values
ParamList effectiveSettings = buildParams(device->deviceClass().settingsTypes(), settings, device->settings());
Device::DeviceError status = DeviceUtils::verifyParams(device->deviceClass().settingsTypes(), effectiveSettings);
if (status != Device::DeviceErrorNoError) {
qCWarning(dcDeviceManager()) << "Error setting device settings for device" << device->name() << device->id().toString();
return status;
}
foreach (const Param &setting, settings) {
device->setSettingValue(setting.paramTypeId(), setting.value());
}
device->setSettings(effectiveSettings);
return Device::DeviceErrorNoError;
}
/*! Initiates a pairing with a \l{DeviceClass}{Device} with the given \a pairingTransactionId, \a deviceClassId, \a name and \a params.
* Returns \l{Device::DeviceError}{DeviceError} to inform about the result. */
DevicePairingInfo* DeviceManagerImplementation::pairDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params)
DevicePairingInfo* DeviceManagerImplementation::pairDevice(const DeviceClassId &deviceClassId, const ParamList &params, const QString &name)
{
PairingTransactionId transactionId = PairingTransactionId::createPairingTransactionId();
// Create new device id
DeviceId newDeviceId = DeviceId::createDeviceId();
DevicePairingInfo *info = new DevicePairingInfo(transactionId, deviceClassId, newDeviceId, name, params, DeviceId(), this, 30000);
pairDeviceInternal(info);
return info;
}
/*! Initiates a pairing with a \l{DeviceClass}{Device} with the given \a pairingTransactionId, \a deviceClassId, \a name and \a deviceDescriptorId.
* Returns \l{Device::DeviceError}{DeviceError} to inform about the result. */
DevicePairingInfo* DeviceManagerImplementation::pairDevice(const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId)
{
PairingTransactionId pairingTransactionId = PairingTransactionId::createPairingTransactionId();
DeviceClass deviceClass = findDeviceClass(deviceClassId);
if (deviceClass.id().isNull()) {
qCWarning(dcDeviceManager) << "Cannot find a device class with id" << deviceClassId;
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, deviceClassId, DeviceId(), name, ParamList(), DeviceId(), this);
DeviceClass deviceClass = m_supportedDevices.value(deviceClassId);
if (!deviceClass.isValid()) {
qCWarning(dcDeviceManager) << "Cannot find a DeviceClass with ID" << deviceClassId.toString();
DevicePairingInfo *info = new DevicePairingInfo(transactionId, deviceClassId, DeviceId(), name, ParamList(), DeviceId(), this);
info->finish(Device::DeviceErrorDeviceClassNotFound);
return info;
}
DeviceDescriptor deviceDescriptor = m_discoveredDevices.value(deviceClassId).value(deviceDescriptorId);
if (!deviceDescriptor.isValid()) {
qCWarning(dcDeviceManager) << "Cannot find a DeviceDescriptor with ID" << deviceClassId.toString();
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, deviceClassId, DeviceId(), name, ParamList(), DeviceId(), this);
// Create new device id
DeviceId newDeviceId = DeviceId::createDeviceId();
// Use given params, if there are missing some, use the defaults ones.
ParamList finalParams = buildParams(deviceClass.paramTypes(), params);
DevicePairingInfo *info = new DevicePairingInfo(transactionId, deviceClassId, newDeviceId, name, finalParams, DeviceId(), this, 30000);
pairDeviceInternal(info);
return info;
}
DevicePairingInfo* DeviceManagerImplementation::pairDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params, const QString &name)
{
PairingTransactionId pairingTransactionId = PairingTransactionId::createPairingTransactionId();
DeviceDescriptor descriptor = m_discoveredDevices.value(deviceDescriptorId);
if (!descriptor.isValid()) {
qCWarning(dcDeviceManager) << "Cannot find a DeviceDescriptor with ID" << deviceDescriptorId.toString();
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, DeviceClassId(), DeviceId(), name, ParamList(), DeviceId(), this);
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
return info;
}
DeviceId deviceId = deviceDescriptor.deviceId();
DeviceClass deviceClass = m_supportedDevices.value(descriptor.deviceClassId());
if (!deviceClass.isValid()) {
qCWarning(dcDeviceManager) << "Cannot find a DeviceClass with ID" << descriptor.deviceClassId().toString();
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, descriptor.deviceClassId(), DeviceId(), name, ParamList(), DeviceId(), this);
info->finish(Device::DeviceErrorDeviceClassNotFound);
return info;
}
DeviceId deviceId = descriptor.deviceId();
// If it's a new device (not a reconfiguration), create a new DeviceId now.
if (deviceId.isNull()) {
deviceId = DeviceId::createDeviceId();
}
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, deviceClassId, deviceId, name, deviceDescriptor.params(), deviceDescriptor.parentDeviceId(), this, 30000);
// Use given params, if there are missing some, use the discovered ones.
ParamList finalParams = buildParams(deviceClass.paramTypes(), params, descriptor.params());
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, descriptor.deviceClassId(), deviceId, name, finalParams, descriptor.parentDeviceId(), this, 30000);
pairDeviceInternal(info);
return info;
}
DevicePairingInfo *DeviceManagerImplementation::pairDevice(const DeviceId &deviceId, const ParamList &params, const QString &name)
{
PairingTransactionId pairingTransactionId = PairingTransactionId::createPairingTransactionId();
Device *device = findConfiguredDevice(deviceId);
if (!device) {
qCWarning(dcDeviceManager) << "Cannot find a Device with ID" << deviceId.toString();
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, DeviceClassId(), deviceId, name, ParamList(), DeviceId(), this);
info->finish(Device::DeviceErrorDeviceDescriptorNotFound);
return info;
}
// Use new params, if there are missing some, use the existing ones.
ParamList finalParams = buildParams(device->deviceClass().paramTypes(), params, device->params());
DevicePairingInfo *info = new DevicePairingInfo(pairingTransactionId, device->deviceClassId(), deviceId, name, finalParams, DeviceId(), this, 30000);
pairDeviceInternal(info);
return info;
}
@ -599,9 +626,7 @@ DevicePairingInfo *DeviceManagerImplementation::confirmPairing(const PairingTran
}
device->setParams(internalInfo->params());
ParamList settings;
// Use verifyParams to populate it with defaults
DeviceUtils::verifyParams(deviceClass.settingsTypes(), settings);
ParamList settings = buildParams(deviceClass.settingsTypes(), ParamList());
device->setSettings(settings);
DeviceSetupInfo *info = setupDevice(device);
@ -642,7 +667,7 @@ DevicePairingInfo *DeviceManagerImplementation::confirmPairing(const PairingTran
/*! This method will only be used from the DeviceManagerImplementation in order to add a \l{Device} with the given \a deviceClassId, \a name, \a params and \ id.
* Returns \l{DeviceError} to inform about the result. */
DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId &deviceId, const DeviceId &parentDeviceId)
DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId &parentDeviceId)
{
DeviceClass deviceClass = findDeviceClass(deviceClassId);
if (deviceClass.id().isNull()) {
@ -657,10 +682,10 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const
return info;
}
if (m_configuredDevices.contains(deviceId)) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
info->finish(Device::DeviceErrorDuplicateUuid);
return info;
DeviceId deviceId = DeviceId::createDeviceId();
// Chances are like 0, but...
while (m_configuredDevices.contains(deviceId)) {
deviceId = DeviceId::createDeviceId();
}
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
@ -670,7 +695,8 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const
return info;
}
ParamList effectiveParams = params;
// set params
ParamList effectiveParams = buildParams(deviceClass.paramTypes(), params);
Device::DeviceError paramsResult = DeviceUtils::verifyParams(deviceClass.paramTypes(), effectiveParams);
if (paramsResult != Device::DeviceErrorNoError) {
DeviceSetupInfo *info = new DeviceSetupInfo(nullptr, this);
@ -687,8 +713,8 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const
}
device->setParams(effectiveParams);
ParamList settings;
DeviceUtils::verifyParams(deviceClass.settingsTypes(), settings);
// set settings (init with defaults)
ParamList settings = buildParams(deviceClass.settingsTypes(), ParamList());
qCDebug(dcDeviceManager()) << "Adding device settings" << settings << deviceId;
device->setSettings(settings);
@ -936,7 +962,7 @@ DeviceActionInfo *DeviceManagerImplementation::executeAction(const Action &actio
return info;
}
ParamList finalParams = action.params();
ParamList finalParams = buildParams(actionType.paramTypes(), action.params());
Device::DeviceError paramCheck = DeviceUtils::verifyParams(actionType.paramTypes(), finalParams);
if (paramCheck != Device::DeviceErrorNoError) {
qCWarning(dcDeviceManager()) << "Cannot execute action. Parameter verification failed.";
@ -1206,13 +1232,9 @@ void DeviceManagerImplementation::loadConfiguredDevices()
params.append(Param(ParamTypeId(paramTypeIdString), settings.value(paramTypeIdString)));
}
}
DeviceUtils::verifyParams(deviceClass.settingsTypes(), deviceSettings);
// Make sure all settings are around. if they aren't initialize with default values
foreach (const ParamType &settingsType, deviceClass.settingsTypes()) {
if (!deviceSettings.hasParam(settingsType.id())) {
deviceSettings.append(Param(settingsType.id(), settingsType.defaultValue().isValid() ? settingsType.defaultValue() : ""));
}
}
// Fill in any missing params with defaults
deviceSettings = buildParams(deviceClass.settingsTypes(), deviceSettings);
device->setSettings(deviceSettings);
@ -1332,7 +1354,8 @@ void DeviceManagerImplementation::onAutoDevicesAppeared(const DeviceDescriptors
continue;
}
qCDebug(dcDeviceManager()) << "Start reconfiguring auto device" << device;
reconfigureDevice(deviceDescriptor.deviceId(), deviceDescriptor.params(), true);
ParamList finalParams = buildParams(deviceClass.paramTypes(), deviceDescriptor.params());
reconfigureDeviceInternal(device, finalParams);
continue;
}
@ -1340,8 +1363,7 @@ void DeviceManagerImplementation::onAutoDevicesAppeared(const DeviceDescriptors
device->m_autoCreated = true;
device->setName(deviceDescriptor.title());
device->setParams(deviceDescriptor.params());
ParamList settings;
DeviceUtils::verifyParams(deviceClass.settingsTypes(), settings);
ParamList settings = buildParams(deviceClass.settingsTypes(), ParamList());
device->setSettings(settings);
device->setParentId(deviceDescriptor.parentDeviceId());
@ -1453,6 +1475,22 @@ void DeviceManagerImplementation::slotDeviceSettingChanged(const ParamTypeId &pa
emit deviceSettingChanged(device->id(), paramTypeId, value);
}
ParamList DeviceManagerImplementation::buildParams(const ParamTypes &types, const ParamList &first, const ParamList &second)
{
// Merge params from discovered descriptor and additional overrides provided on API call. User provided params have higher priority than discovery params.
ParamList finalParams;
foreach (const ParamType &paramType, types) {
if (first.hasParam(paramType.id())) {
finalParams.append(Param(paramType.id(), first.paramValue(paramType.id())));
} else if (second.hasParam(paramType.id())) {
finalParams.append(Param(paramType.id(), second.paramValue(paramType.id())));
} else if (paramType.defaultValue().isValid()){
finalParams.append(Param(paramType.id(), paramType.defaultValue()));
}
}
return finalParams;
}
void DeviceManagerImplementation::pairDeviceInternal(DevicePairingInfo *info)
{
DeviceClass deviceClass = m_supportedDevices.value(info->deviceClassId());

View File

@ -83,19 +83,20 @@ public:
DeviceDiscoveryInfo* discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
DeviceSetupInfo* addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id = DeviceId::createDeviceId()) override;
DeviceSetupInfo* addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const DeviceId &deviceId = DeviceId::createDeviceId()) override;
DeviceSetupInfo* addConfiguredDevice(const DeviceClassId &deviceClassId, const ParamList &params, const QString &name = QString()) override;
DeviceSetupInfo* addConfiguredDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const QString &name = QString()) override;
DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const ParamList &params, bool fromDiscoveryOrAuto = false) override;
DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId) override;
DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const ParamList &params, const QString &name = QString()) override;
DeviceSetupInfo* reconfigureDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const QString &name = QString()) override;
DevicePairingInfo* pairDevice(const DeviceClassId &deviceClassId, const ParamList &params, const QString &name = QString()) override;
DevicePairingInfo* pairDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const QString &name = QString()) override;
DevicePairingInfo* pairDevice(const DeviceId &deviceId, const ParamList &params, const QString &name = QString()) override;
DevicePairingInfo* confirmPairing(const PairingTransactionId &pairingTransactionId, const QString &username, const QString &secret) override;
Device::DeviceError editDevice(const DeviceId &deviceId, const QString &name) override;
Device::DeviceError setDeviceSettings(const DeviceId &deviceId, const ParamList &settings) override;
DevicePairingInfo* pairDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params) override;
DevicePairingInfo* pairDevice(const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId) override;
DevicePairingInfo* confirmPairing(const PairingTransactionId &pairingTransactionId, const QString &username, const QString &secret) override;
Device::DeviceError removeConfiguredDevice(const DeviceId &deviceId) override;
DeviceActionInfo* executeAction(const Action &action) override;
@ -130,8 +131,12 @@ private slots:
void slotDeviceSettingChanged(const ParamTypeId &paramTypeId, const QVariant &value);
private:
// Builds a list of params ready to create a device.
// Template is deviceClass.paramtypes, "first" has highest priority. If a param is not found neither in first nor in second, defaults apply.
ParamList buildParams(const ParamTypes &types, const ParamList &first, const ParamList &second = ParamList());
void pairDeviceInternal(DevicePairingInfo *info);
DeviceSetupInfo *addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId &deviceId = DeviceId::createDeviceId(), const DeviceId &parentDeviceId = DeviceId());
DeviceSetupInfo *addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId &parentDeviceId = DeviceId());
DeviceSetupInfo *reconfigureDeviceInternal(Device *device, const ParamList &params, const QString &name = QString());
DeviceSetupInfo *setupDevice(Device *device);
void postSetupDevice(Device *device);
void storeDeviceStates(Device *device);
@ -147,7 +152,7 @@ private:
QHash<VendorId, QList<DeviceClassId> > m_vendorDeviceMap;
QHash<DeviceClassId, DeviceClass> m_supportedDevices;
QHash<DeviceId, Device*> m_configuredDevices;
QHash<DeviceClassId, QHash<DeviceDescriptorId, DeviceDescriptor> > m_discoveredDevices;
QHash<DeviceDescriptorId, DeviceDescriptor> m_discoveredDevices;
QHash<PluginId, DevicePlugin*> m_devicePlugins;

View File

@ -127,7 +127,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
"Devices with CreateMethodJustAdd require all parameters to be supplied here. "
"Devices with CreateMethodDiscovery require the use of a deviceDescriptorId. For discovered "
"devices params are not required and will be taken from the DeviceDescriptor, however, they "
"may be overridden by supplying parameters here."
"may be overridden by supplying deviceParams."
);
params.insert("deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String));
@ -141,28 +141,44 @@ DeviceHandler::DeviceHandler(QObject *parent) :
returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String));
setReturns("AddConfiguredDevice", returns);
returns.clear(); // Reused params from above!
params.clear(); returns.clear();
setDescription("PairDevice", "Pair a device. "
"Use this for DeviceClasses with a setupMethod different than SetupMethodJustAdd. "
"Use deviceDescriptorId or deviceParams, depending on the createMethod of the device class. "
"CreateMethodJustAdd takes the parameters you want to have with that device. "
"CreateMethodDiscovery requires the use of a deviceDescriptorId, optionally, parameters can be overridden here. "
"Use this to set up or reconfigure devices for DeviceClasses with a setupMethod different than SetupMethodJustAdd. "
"Depending on the CreateMethod and whether a new devices is set up or an existing one is reconfigured, different parameters "
"are required:\n"
"CreateMethodJustAdd takes the deviceClassId and the parameters you want to have with that device.\n"
"CreateMethodDiscovery requires the use of a deviceDescriptorId, previously obtained with DiscoverDevices. Optionally, "
"parameters can be overridden with the give deviceParams.\n"
"If an existing device should be reconfigured, the deviceId of said device should be given additionally.\n"
"If success is true, the return values will contain a pairingTransactionId, a displayMessage and "
"the setupMethod. Depending on the setupMethod you should either proceed with AddConfiguredDevice "
"or PairDevice."
"the setupMethod. Depending on the setupMethod, the application should present the use an appropriate login mask, "
"that is, For SetupMethodDisplayPin the user should enter a pin that is displayed on the device, for SetupMethodEnterPin the "
"application should present the given PIN so the user can enter it on the device. For SetupMethodPushButton, the displayMessage "
"shall be presented to the user as informational hints to press a button on the device. For SetupMethodUserAndPassword a login "
"mask for a user and password login should be presented to the user. In case of SetupMethodOAuth, an OAuth URL will be returned "
"which shall be opened in a web view to allow the user logging in.\n"
"Once the login procedure has completed, the application shall proceed with ConfirmPairing, providing the results of the pairing "
"procedure."
);
params.insert("o:deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
params.insert("o:name", JsonTypes::basicTypeToString(JsonTypes::String));
params.insert("o:deviceDescriptorId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
params.insert("o:deviceParams", deviceParams);
params.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
setParams("PairDevice", params);
returns.insert("deviceError", JsonTypes::deviceErrorRef());
returns.insert("o:setupMethod", JsonTypes::setupMethodRef());
returns.insert("o:pairingTransactionId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String));
returns.insert("o:oAuthUrl", JsonTypes::basicTypeToString(JsonTypes::String));
returns.insert("o:pin", JsonTypes::basicTypeToString(JsonTypes::String));
setReturns("PairDevice", returns);
params.clear(); returns.clear();
setDescription("ConfirmPairing", "Confirm an ongoing pairing. For SetupMethodUserAndPassword, provide the username in the \"username\" field "
"and the password in the \"secret\" field. For SetupMethodEnterPin and provide the PIN in the \"secret\" "
"field. For SetupMethodOAuth, return the entire unmodified callback URL containing the code parameter back in the secret field.");
"field. In case of SetupMethodOAuth, the previously opened web view will eventually be redirected to http://128.0.0.1:8888 "
"and the OAuth code as query parameters to this url. Provide the entire unmodified URL in the secret field.");
params.insert("pairingTransactionId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
params.insert("o:username", JsonTypes::basicTypeToString(JsonTypes::String));
params.insert("o:secret", JsonTypes::basicTypeToString(JsonTypes::String));
@ -200,12 +216,14 @@ DeviceHandler::DeviceHandler(QObject *parent) :
setReturns("GetDiscoveredDevices", returns);
params.clear(); returns.clear();
setDescription("ReconfigureDevice", "Edit the parameter configuration of the device. The device params will be set to the "
"passed parameters and the setup device will be called. If the device is discoverable, "
"you can perform a GetDiscoveredDevices before calling this method and pass "
"the new DeviceDescriptor (rediscover). Only writable parameters can be changed. By default, "
"every Param is writable.");
params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
setDescription("ReconfigureDevice", "Reconfigure a device. This comes down to removing and recreating a device with new parameters "
"but keeping its device id the same (and with that keeping rules, tags etc). For devices with "
"create method CreateMethodDiscovery, a discovery (GetDiscoveredDevices) shall be performed first "
"and this method is to be called with a deviceDescriptorId of the re-discovered device instead of "
"the deviceId directly. Device parameters will be taken from the discovery, but can be overridden "
"individually here by providing them in the deviceParams parameter. Only writable parameters can "
"be changed.");
params.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
params.insert("o:deviceDescriptorId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
QVariantList newDeviceParams;
newDeviceParams.append(JsonTypes::paramRef());
@ -451,20 +469,19 @@ JsonReply* DeviceHandler::SetPluginConfiguration(const QVariantMap &params)
JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
{
DeviceClassId deviceClass(params.value("deviceClassId").toString());
DeviceClassId deviceClassId(params.value("deviceClassId").toString());
QString deviceName = params.value("name").toString();
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
DeviceId newDeviceId = DeviceId::createDeviceId();
QLocale locale = params.value("locale").toLocale();
JsonReply *jsonReply = createAsyncReply("AddConfiguredDevice");
DeviceSetupInfo *info;
if (deviceDescriptorId.isNull()) {
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceName, deviceParams, newDeviceId);
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceParams, deviceName);
} else {
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceName, deviceDescriptorId, deviceParams, newDeviceId);
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceDescriptorId, deviceParams, deviceName);
}
connect(info, &DeviceSetupInfo::finished, jsonReply, [info, jsonReply, locale](){
QVariantMap returns;
@ -486,28 +503,31 @@ JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
JsonReply *DeviceHandler::PairDevice(const QVariantMap &params)
{
DeviceClassId deviceClassId(params.value("deviceClassId").toString());
QString deviceName = params.value("name").toString();
DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(deviceClassId);
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
QLocale locale = params.value("locale").toLocale();
DevicePairingInfo *info;
if (params.contains("deviceDescriptorId")) {
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceDescriptorId);
DeviceDescriptorId deviceDescriptorId = DeviceDescriptorId(params.value("deviceDescriptorId").toString());
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceDescriptorId, deviceParams, deviceName);
} else if (params.contains("deviceId")) {
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceId, deviceParams, deviceName);
} else {
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceParams);
DeviceClassId deviceClassId(params.value("deviceClassId").toString());
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceParams, deviceName);
}
JsonReply *jsonReply = createAsyncReply("PairDevice");
connect(info, &DevicePairingInfo::finished, jsonReply, [jsonReply, info, locale, deviceClass](){
connect(info, &DevicePairingInfo::finished, jsonReply, [jsonReply, info, locale](){
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status()));
returns.insert("pairingTransactionId", info->transactionId().toString());
if (info->status() == Device::DeviceErrorNoError) {
DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(info->deviceClassId());
returns.insert("setupMethod", JsonTypes::setupMethodToString(deviceClass.setupMethod()));
}
@ -584,10 +604,15 @@ JsonReply *DeviceHandler::ReconfigureDevice(const QVariantMap &params)
JsonReply *jsonReply = createAsyncReply("ReconfigureDevice");
DeviceSetupInfo *info;
if (deviceDescriptorId.isNull()) {
if (!deviceDescriptorId.isNull()) {
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceDescriptorId, deviceParams);
} else if (!deviceId.isNull()){
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceId, deviceParams);
} else {
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceId, deviceDescriptorId);
qCWarning(dcJsonRpc()) << "Either deviceId or deviceDescriptorId are required";
QVariantMap ret;
ret.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorMissingParameter));
return createReply(ret);
}
connect(info, &DeviceSetupInfo::finished, jsonReply, [info, jsonReply, locale](){
@ -597,6 +622,7 @@ JsonReply *DeviceHandler::ReconfigureDevice(const QVariantMap &params)
returns.insert("displayMessage", info->translatedDisplayMessage(locale));
jsonReply->setData(returns);
jsonReply->finished();
});
return jsonReply;

View File

@ -375,7 +375,6 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
return createDeviceErrorReply(HttpReply::BadRequest, Device::DeviceErrorDeviceClassNotFound);
QString deviceName = params.value("name").toString();
DeviceId newDeviceId = DeviceId::createDeviceId();
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
@ -384,10 +383,10 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
DeviceSetupInfo *info;
if (deviceDescriptorId.isNull()) {
qCDebug(dcRest) << "Adding device" << deviceName << "with" << deviceParams;
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceName, deviceParams, newDeviceId);
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceParams, deviceName);
} else {
qCDebug(dcRest) << "Adding discovered device" << deviceName << "with DeviceDescriptorId" << deviceDescriptorId.toString();
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceName, deviceDescriptorId, deviceParams, newDeviceId);
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceDescriptorId, deviceParams, deviceName);
}
connect(info, &DeviceSetupInfo::finished, httpReply, [info, httpReply](){
@ -443,6 +442,7 @@ HttpReply *DevicesResource::pairDevice(const QByteArray &payload) const
}
QString deviceName = params.value("name").toString();
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
qCDebug(dcRest) << "Pair device" << deviceName << "with deviceClassId" << deviceClassId.toString();
@ -451,10 +451,9 @@ HttpReply *DevicesResource::pairDevice(const QByteArray &payload) const
DevicePairingInfo *info;
if (params.contains("deviceDescriptorId")) {
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceDescriptorId);
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceDescriptorId, deviceParams, deviceName);
} else {
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceParams);
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceParams, deviceName);
}
connect(info, &DevicePairingInfo::finished, httpReply, [info, httpReply](){
@ -533,7 +532,7 @@ HttpReply *DevicesResource::reconfigureDevice(Device *device, const QByteArray &
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(device->id(), deviceParams);
} else {
qCDebug(dcRest) << "Reconfigure device using the new discovered device with descriptorId:" << deviceDescriptorId.toString();
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(device->id(), deviceDescriptorId);
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceDescriptorId);
}
connect(info, &DeviceSetupInfo::finished, httpReply, [httpReply, info](){

View File

@ -101,19 +101,20 @@ public:
virtual DeviceDiscoveryInfo* discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) = 0;
virtual DeviceSetupInfo* addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id = DeviceId::createDeviceId()) = 0;
virtual DeviceSetupInfo* addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const DeviceId &deviceId = DeviceId::createDeviceId()) = 0;
virtual DeviceSetupInfo* addConfiguredDevice(const DeviceClassId &deviceClassId, const ParamList &params, const QString &name = QString()) = 0;
virtual DeviceSetupInfo* addConfiguredDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const QString &name = QString()) = 0;
virtual DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const ParamList &params, bool fromDiscoveryOrAuto = false) = 0;
virtual DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId) = 0;
virtual DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const ParamList &params, const QString &name = QString()) = 0;
virtual DeviceSetupInfo* reconfigureDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const QString &name = QString()) = 0;
virtual DevicePairingInfo* pairDevice(const DeviceClassId &deviceClassId, const ParamList &params, const QString &name = QString()) = 0;
virtual DevicePairingInfo* pairDevice(const DeviceDescriptorId &deviceDescriptorId, const ParamList &params = ParamList(), const QString &name = QString()) = 0;
virtual DevicePairingInfo* pairDevice(const DeviceId &deviceId, const ParamList &params, const QString &name = QString()) = 0;
virtual DevicePairingInfo* confirmPairing(const PairingTransactionId &pairingTransactionId, const QString &username = QString(), const QString &secret = QString()) = 0;
virtual Device::DeviceError editDevice(const DeviceId &deviceId, const QString &name) = 0;
virtual Device::DeviceError setDeviceSettings(const DeviceId &deviceId, const ParamList &settings) = 0;
virtual DevicePairingInfo* pairDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params) = 0;
virtual DevicePairingInfo* pairDevice(const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId) = 0;
virtual DevicePairingInfo* confirmPairing(const PairingTransactionId &pairingTransactionId, const QString &username = QString(), const QString &secret = QString()) = 0;
virtual Device::DeviceError removeConfiguredDevice(const DeviceId &deviceId) = 0;
virtual DeviceActionInfo* executeAction(const Action &action) = 0;

View File

@ -34,7 +34,7 @@ DeviceUtils::DeviceUtils()
/*! Verify if the given \a params matches the given \a paramTypes. Ith \a requireAll
* is true, all \l{ParamList}{Params} has to be valid. Returns \l{Device::DeviceError} to inform about the result.*/
Device::DeviceError DeviceUtils::verifyParams(const QList<ParamType> paramTypes, ParamList &params, bool requireAll)
Device::DeviceError DeviceUtils::verifyParams(const QList<ParamType> paramTypes, const ParamList &params)
{
foreach (const Param &param, params) {
Device::DeviceError result = verifyParam(paramTypes, param);
@ -42,25 +42,17 @@ Device::DeviceError DeviceUtils::verifyParams(const QList<ParamType> paramTypes,
return result;
}
}
if (!requireAll) {
return Device::DeviceErrorNoError;
}
foreach (const ParamType &paramType, paramTypes) {
bool found = false;
foreach (const Param &param, params) {
if (paramType.id() == param.paramTypeId()) {
found = true;
break;
}
}
// This paramType has a default value... lets fill in that one.
if (!paramType.defaultValue().isNull() && !found) {
found = true;
params.append(Param(paramType.id(), paramType.defaultValue()));
}
if (!found) {
qCWarning(dcDevice) << "Missing parameter:" << paramType.name();
qCWarning(dcDevice) << "Missing parameter:" << paramType.name() << params;
return Device::DeviceErrorMissingParameter;
}
}

View File

@ -34,7 +34,7 @@ class DeviceUtils
public:
DeviceUtils();
static Device::DeviceError verifyParams(const QList<ParamType> paramTypes, ParamList &params, bool requireAll = true);
static Device::DeviceError verifyParams(const QList<ParamType> paramTypes, const ParamList &params);
static Device::DeviceError verifyParam(const QList<ParamType> paramTypes, const Param &param);
static Device::DeviceError verifyParam(const ParamType &paramType, const Param &param);

View File

@ -3,7 +3,7 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"
# define protocol versions
JSON_PROTOCOL_VERSION_MAJOR=3
JSON_PROTOCOL_VERSION_MINOR=1
JSON_PROTOCOL_VERSION_MINOR=2
REST_API_VERSION=1
LIBNYMEA_API_VERSION_MAJOR=3
LIBNYMEA_API_VERSION_MINOR=0

View File

@ -1,4 +1,4 @@
3.1
3.2
{
"methods": {
"Actions.ExecuteAction": {
@ -260,7 +260,7 @@
}
},
"Devices.AddConfiguredDevice": {
"description": "Add a configured device with a setupMethod of SetupMethodJustAdd. For devices with a setupMethod different than SetupMethodJustAdd, use PairDevice. Devices with CreateMethodJustAdd require all parameters to be supplied here. Devices with CreateMethodDiscovery require the use of a deviceDescriptorId. For discovered devices params are not required and will be taken from the DeviceDescriptor, however, they may be overridden by supplying parameters here.",
"description": "Add a configured device with a setupMethod of SetupMethodJustAdd. For devices with a setupMethod different than SetupMethodJustAdd, use PairDevice. Devices with CreateMethodJustAdd require all parameters to be supplied here. Devices with CreateMethodDiscovery require the use of a deviceDescriptorId. For discovered devices params are not required and will be taken from the DeviceDescriptor, however, they may be overridden by supplying deviceParams.",
"params": {
"deviceClassId": "Uuid",
"name": "String",
@ -289,7 +289,7 @@
}
},
"Devices.ConfirmPairing": {
"description": "Confirm an ongoing pairing. For SetupMethodUserAndPassword, provide the username in the \"username\" field and the password in the \"secret\" field. For SetupMethodEnterPin and provide the PIN in the \"secret\" field. For SetupMethodOAuth, return the entire unmodified callback URL containing the code parameter back in the secret field.",
"description": "Confirm an ongoing pairing. For SetupMethodUserAndPassword, provide the username in the \"username\" field and the password in the \"secret\" field. For SetupMethodEnterPin and provide the PIN in the \"secret\" field. In case of SetupMethodOAuth, the previously opened web view will eventually be redirected to http://128.0.0.1:8888 and the OAuth code as query parameters to this url. Provide the entire unmodified URL in the secret field.",
"params": {
"o:secret": "String",
"o:username": "String",
@ -452,28 +452,30 @@
}
},
"Devices.PairDevice": {
"description": "Pair a device. Use this for DeviceClasses with a setupMethod different than SetupMethodJustAdd. Use deviceDescriptorId or deviceParams, depending on the createMethod of the device class. CreateMethodJustAdd takes the parameters you want to have with that device. CreateMethodDiscovery requires the use of a deviceDescriptorId, optionally, parameters can be overridden here. If success is true, the return values will contain a pairingTransactionId, a displayMessage and the setupMethod. Depending on the setupMethod you should either proceed with AddConfiguredDevice or PairDevice.",
"description": "Pair a device. Use this to set up or reconfigure devices for DeviceClasses with a setupMethod different than SetupMethodJustAdd. Depending on the CreateMethod and whether a new devices is set up or an existing one is reconfigured, different parameters are required:\nCreateMethodJustAdd takes the deviceClassId and the parameters you want to have with that device.\nCreateMethodDiscovery requires the use of a deviceDescriptorId, previously obtained with DiscoverDevices. Optionally, parameters can be overridden with the give deviceParams.\nIf an existing device should be reconfigured, the deviceId of said device should be given additionally.\nIf success is true, the return values will contain a pairingTransactionId, a displayMessage and the setupMethod. Depending on the setupMethod, the application should present the use an appropriate login mask, that is, For SetupMethodDisplayPin the user should enter a pin that is displayed on the device, for SetupMethodEnterPin the application should present the given PIN so the user can enter it on the device. For SetupMethodPushButton, the displayMessage shall be presented to the user as informational hints to press a button on the device. For SetupMethodUserAndPassword a login mask for a user and password login should be presented to the user. In case of SetupMethodOAuth, an OAuth URL will be returned which shall be opened in a web view to allow the user logging in.\nOnce the login procedure has completed, the application shall proceed with ConfirmPairing, providing the results of the pairing procedure.",
"params": {
"deviceClassId": "Uuid",
"name": "String",
"o:deviceClassId": "Uuid",
"o:deviceDescriptorId": "Uuid",
"o:deviceId": "Uuid",
"o:deviceParams": [
"$ref:Param"
]
],
"o:name": "String"
},
"returns": {
"deviceError": "$ref:DeviceError",
"o:displayMessage": "String",
"o:oAuthUrl": "String",
"o:pairingTransactionId": "Uuid",
"o:pin": "String",
"o:setupMethod": "$ref:SetupMethod"
}
},
"Devices.ReconfigureDevice": {
"description": "Edit the parameter configuration of the device. The device params will be set to the passed parameters and the setup device will be called. If the device is discoverable, you can perform a GetDiscoveredDevices before calling this method and pass the new DeviceDescriptor (rediscover). Only writable parameters can be changed. By default, every Param is writable.",
"description": "Reconfigure a device. This comes down to removing and recreating a device with new parameters but keeping its device id the same (and with that keeping rules, tags etc). For devices with create method CreateMethodDiscovery, a discovery (GetDiscoveredDevices) shall be performed first and this method is to be called with a deviceDescriptorId of the re-discovered device instead of the deviceId directly. Device parameters will be taken from the discovery, but can be overridden individually here by providing them in the deviceParams parameter. Only writable parameters can be changed.",
"params": {
"deviceId": "Uuid",
"o:deviceDescriptorId": "Uuid",
"o:deviceId": "Uuid",
"o:deviceParams": [
"$ref:Param"
]

View File

@ -338,13 +338,18 @@ void TestDevices::addConfiguredDevice_data()
QVariantMap fakeparam;
fakeparam.insert("paramTypeId", ParamTypeId::createParamTypeId());
invalidDeviceParams.append(fakeparam);
QTest::newRow("User, JustAdd, invalid param") << mockDeviceClassId << invalidDeviceParams << Device::DeviceErrorInvalidParameter;
QTest::newRow("User, JustAdd, invalid param") << mockDeviceClassId << invalidDeviceParams << Device::DeviceErrorMissingParameter;
fakeparam.insert("value", "buhuu");
QVariantMap fakeparam2;
fakeparam2.insert("paramTypeId", mockDeviceHttpportParamTypeId.toString());
fakeparam2.insert("value", "blabla");
invalidDeviceParams.clear();
invalidDeviceParams.append(fakeparam);
invalidDeviceParams.append(fakeparam2);
QTest::newRow("User, JustAdd, wrong param") << mockDeviceClassId << invalidDeviceParams << Device::DeviceErrorInvalidParameter;
deviceParams.clear(); deviceParams << httpportParam << fakeparam;
QTest::newRow("USer, JustAdd, additional invalid param") << mockDeviceClassId << deviceParams << Device::DeviceErrorNoError;
}
void TestDevices::addConfiguredDevice()
@ -1198,6 +1203,7 @@ void TestDevices::reconfigureByDiscovery()
QFETCH(Device::DeviceError, error);
QFETCH(QVariantList, discoveryParams);
qCDebug(dcTests()) << "Discovering...";
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
params.insert("discoveryParams", discoveryParams);
@ -1211,31 +1217,33 @@ void TestDevices::reconfigureByDiscovery()
// add Discovered Device 1 port 55555
QVariantList deviceDescriptors = response.toMap().value("params").toMap().value("deviceDescriptors").toList();
DeviceDescriptorId descriptorId1;
DeviceDescriptorId descriptorId;
foreach (const QVariant &descriptor, deviceDescriptors) {
// find the device with port 55555
if (descriptor.toMap().value("description").toString() == "55555") {
descriptorId1 = DeviceDescriptorId(descriptor.toMap().value("id").toString());
qDebug() << descriptorId1.toString();
descriptorId = DeviceDescriptorId(descriptor.toMap().value("id").toString());
qDebug() << descriptorId.toString();
break;
}
}
qDebug() << "adding descriptorId 1" << descriptorId1;
QVERIFY(!descriptorId.isNull());
QVERIFY(!descriptorId1.isNull());
qCDebug(dcTests()) << "Adding...";
params.clear();
response.clear();
params.insert("deviceClassId", deviceClassId);
params.insert("name", "Discoverd mock device");
params.insert("deviceDescriptorId", descriptorId1);
params.insert("deviceDescriptorId", descriptorId);
response = injectAndWait("Devices.AddConfiguredDevice", params);
DeviceId deviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!deviceId.isNull());
// and now rediscover, and edit the first device with the second
// and now rediscover and find the existing device in the discovery results
qCDebug(dcTests()) << "Re-Discovering...";
params.clear();
response.clear();
params.insert("deviceClassId", deviceClassId);
@ -1247,24 +1255,28 @@ void TestDevices::reconfigureByDiscovery()
QCOMPARE(response.toMap().value("params").toMap().value("deviceDescriptors").toList().count(), resultCount);
}
// get the second device
DeviceDescriptorId descriptorId2;
deviceDescriptors = response.toMap().value("params").toMap().value("deviceDescriptors").toList();
// find the already added device
descriptorId = DeviceDescriptorId(); // reset it first
foreach (const QVariant &descriptor, deviceDescriptors) {
// find the device with port 55556
if (descriptor.toMap().value("description").toString() == "55556") {
descriptorId2 = DeviceDescriptorId(descriptor.toMap().value("id").toString());
if (descriptor.toMap().value("deviceId").toUuid().toString() == deviceId.toString()) {
descriptorId = DeviceDescriptorId(descriptor.toMap().value("id").toString());
break;
}
}
QVERIFY(!descriptorId2.isNull());
QVERIFY2(!descriptorId.isNull(), QString("Device %1 not found in discovery results: %2").arg(deviceId.toString()).arg(qUtf8Printable(QJsonDocument::fromVariant(response).toJson())).toUtf8());
qDebug() << "edit device 1 (55555) with descriptor 2 (55556) " << descriptorId2;
qCDebug(dcTests()) << "Reconfiguring...";
// EDIT
response.clear();
params.clear();
params.insert("deviceId", deviceId.toString());
params.insert("deviceDescriptorId", descriptorId2);
params.insert("deviceDescriptorId", descriptorId);
// override port param
QVariantMap portParam;
portParam.insert("paramTypeId", mockDeviceHttpportParamTypeId);
portParam.insert("value", "55556");
params.insert("deviceParams", QVariantList() << portParam);
response = injectAndWait("Devices.ReconfigureDevice", params);
verifyDeviceError(response, error);
@ -1601,7 +1613,7 @@ void TestDevices::discoverDeviceParenting()
DeviceDescriptorId descriptorId = discoveryInfo->deviceDescriptors().first().id();
QSignalSpy addSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
DeviceSetupInfo *setupInfo = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockParentDeviceClassId, "Mock Parent (Discovered)", descriptorId);
DeviceSetupInfo *setupInfo = NymeaCore::instance()->deviceManager()->addConfiguredDevice(descriptorId, ParamList(), "Mock Parent (Discovered)");
{
QSignalSpy spy(setupInfo, &DeviceSetupInfo::finished);
spy.wait();
@ -1627,7 +1639,7 @@ void TestDevices::discoverDeviceParenting()
// Found one! Adding it...
addSpy.clear();
setupInfo = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockChildDeviceClassId, "Mock Child (Discovered)", descriptorId);
setupInfo = NymeaCore::instance()->deviceManager()->addConfiguredDevice(descriptorId, ParamList(), "Mock Child (Discovered)");
{
QSignalSpy spy(setupInfo, &DeviceSetupInfo::finished);
spy.wait();

View File

@ -732,19 +732,19 @@ void TestRestDevices::reconfigureByDiscovery()
// add Discovered Device 1 port 55555
request.setUrl(QUrl("https://localhost:3333/api/v1/devices"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
DeviceDescriptorId descriptorId1;
DeviceDescriptorId descriptorId;
foreach (const QVariant &descriptor, foundDevices) {
// find the device with port 55555
if (descriptor.toMap().value("description").toString() == "55555") {
descriptorId1 = DeviceDescriptorId(descriptor.toMap().value("id").toString());
qDebug() << descriptorId1.toString();
descriptorId = DeviceDescriptorId(descriptor.toMap().value("id").toString());
qDebug() << descriptorId.toString();
break;
}
}
params.clear();
params.insert("deviceClassId", deviceClassId);
params.insert("name", "Discovered mock device");
params.insert("deviceDescriptorId", descriptorId1.toString());
params.insert("deviceDescriptorId", descriptorId.toString());
QVariant response = postAndWait(request, params, expectedStatusCode);
QVERIFY2(!response.isNull(), "Could not delete device");
@ -767,23 +767,27 @@ void TestRestDevices::reconfigureByDiscovery()
foundDevices = response.toList();
QCOMPARE(foundDevices.count(), resultCount);
// get the second device
DeviceDescriptorId descriptorId2;
// find the already added device
descriptorId = DeviceDescriptorId(); // reset it first
foreach (const QVariant &descriptor, foundDevices) {
// find the device with port 55556
if (descriptor.toMap().value("description").toString() == "55556") {
descriptorId2 = DeviceDescriptorId(descriptor.toMap().value("id").toString());
if (descriptor.toMap().value("deviceId").toUuid().toString() == deviceId.toString()) {
descriptorId = DeviceDescriptorId(descriptor.toMap().value("id").toString());
break;
}
}
QVERIFY(!descriptorId2.isNull());
qDebug() << "edit device 1 (55555) with descriptor 2 (55556) " << descriptorId2;
QVERIFY(!descriptorId.isNull());
qDebug() << "edit device 1 (55555) with descriptor 2 (55556) " << descriptorId;
// RECONFIGURE
response.clear();
params.clear();
params.insert("deviceId", deviceId.toString());
params.insert("deviceDescriptorId", descriptorId2);
params.insert("deviceDescriptorId", descriptorId);
// override port param
QVariantMap portParam;
portParam.insert("paramTypeId", mockDeviceHttpportParamTypeId);
portParam.insert("value", "55556");
params.insert("deviceParams", QVariantList() << portParam);
request = QNetworkRequest(QUrl(QString("https://localhost:3333/api/v1/devices/%1").arg(deviceId.toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");