Finish off param handling. New param structures now used everywhere.

Plugin params reworked. Added Devices.GetPluginConfiguration.
Cover params stuff with tests.
pull/1/head
Michael Zanetti 2014-05-04 23:59:08 +02:00
parent 0fb41afa7f
commit d84319fdcc
22 changed files with 528 additions and 225 deletions

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
guh (0.1.2) UNRELEASED; urgency=medium
* Added Plugin configs
-- Michael Zanetti <micha@noneyet> Sun, 04 May 2014 22:23:34 +0200
guh (0.1.1) trusty; urgency=low
* Initial release.

View File

@ -125,13 +125,26 @@ DevicePlugin *DeviceManager::plugin(const PluginId &id) const
return m_devicePlugins.value(id);
}
void DeviceManager::setPluginConfig(const PluginId &pluginId, const QVariantMap &pluginConfig)
QPair<DeviceManager::DeviceError, QString> DeviceManager::setPluginConfig(const PluginId &pluginId, const QList<Param> &pluginConfig)
{
DevicePlugin *plugin = m_devicePlugins.value(pluginId);
plugin->setConfiguration(pluginConfig);
if (!plugin) {
return report(DeviceErrorPluginNotFound, QString("No plugin with id % 1").arg(pluginId.toString()));
}
QPair<DeviceError, QString> result = plugin->setConfiguration(pluginConfig);
if (result.first != DeviceErrorNoError) {
return result;
}
QSettings settings;
settings.setValue(plugin->pluginId().toString(), pluginConfig);
settings.beginGroup("PluginConfig");
settings.beginGroup(plugin->pluginId().toString());
foreach (const Param &param, pluginConfig) {
settings.setValue(param.name(), param.value());
}
settings.endGroup();
settings.endGroup();
createNewAutoDevices();
return result;
}
QList<Vendor> DeviceManager::supportedVendors() const
@ -228,33 +241,9 @@ QPair<DeviceManager::DeviceError, QString> DeviceManager::addConfiguredDeviceInt
return qMakePair<DeviceError, QString>(DeviceErrorDeviceClassNotFound, deviceClassId.toString());
}
// Make sure we have all required params
foreach (const ParamType &paramType, deviceClass.params()) {
bool found = false;
foreach (const Param &param, params) {
if (param.name() == paramType.name()) {
found = true;
}
}
if (!found) {
qWarning() << "Missing parameter when creating device:" << paramType.name();
return qMakePair<DeviceError, QString>(DeviceErrorMissingParameter, paramType.name());
}
}
// Make sure we don't have unused params
foreach (const Param &param, params) {
bool found = false;
foreach (const ParamType &paramType, deviceClass.params()) {
if (paramType.name() == param.name()) {
found = true;
continue;
}
}
if (!found) {
// TODO: Check if parameter type matches
return qMakePair<DeviceError, QString>(DeviceErrorDeviceParameterError, param.name());
}
QPair<DeviceError, QString> result = verifyParams(deviceClass.params(), params);
if (result.first != DeviceErrorNoError) {
return result;
}
foreach(Device *device, m_configuredDevices) {
@ -310,8 +299,10 @@ QPair<DeviceManager::DeviceError, QString> DeviceManager::removeConfiguredDevice
device->deleteLater();
QSettings settings;
settings.beginGroup("DeviceConfig");
settings.beginGroup(deviceId.toString());
settings.remove("");
settings.endGroup();
return qMakePair<DeviceError, QString>(DeviceErrorNoError, QString());
}
@ -371,14 +362,12 @@ QPair<DeviceManager::DeviceError, QString> DeviceManager::executeAction(const Ac
bool found = false;
foreach (const ActionType &actionType, deviceClass.actions()) {
if (actionType.id() == action.actionTypeId()) {
found = true;
qDebug() << "checking params" << actionType.parameters().count() << action.params().count();
qDebug() << "action params:" << action.params();
QPair<bool, QString> paramCheck = verifyParams(actionType.parameters(), action.params());
if (!paramCheck.first) {
return qMakePair<DeviceError, QString>(DeviceErrorMissingParameter, paramCheck.second);
QPair<DeviceError, QString> paramCheck = verifyParams(actionType.parameters(), action.params());
if (paramCheck.first != DeviceErrorNoError) {
return paramCheck;
}
found = true;
continue;
}
}
@ -418,8 +407,26 @@ void DeviceManager::loadPlugins()
qDebug() << "* Loaded device class:" << deviceClass.name();
}
QSettings settings;
if (settings.contains(pluginIface->pluginId().toString())) {
pluginIface->setConfiguration(settings.value(pluginIface->pluginId().toString()).toMap());
settings.beginGroup("PluginConfig");
QList<Param> params;
if (settings.childGroups().contains(pluginIface->pluginId().toString())) {
settings.beginGroup(pluginIface->pluginId().toString());
foreach (const QString &paramName, settings.allKeys()) {
Param param(paramName, settings.value(paramName));
params.append(param);
}
settings.endGroup();
} else if (pluginIface->configurationDescription().count() > 0){
// plugin requires config but none stored. Init with defaults
foreach (const ParamType &paramType, pluginIface->configurationDescription()) {
Param param(paramType.name(), paramType.defaultValue());
params.append(param);
}
}
settings.endGroup();
QPair<DeviceError, QString> status = pluginIface->setConfiguration(params);
if (status.first != DeviceErrorNoError) {
qWarning() << "Error setting params to plugin. Broken configuration?" << status.second;
}
m_devicePlugins.insert(pluginIface->pluginId(), pluginIface);
@ -434,6 +441,7 @@ void DeviceManager::loadPlugins()
void DeviceManager::loadConfiguredDevices()
{
QSettings settings;
settings.beginGroup("DeviceConfig");
qDebug() << "loading devices from" << settings.fileName();
foreach (const QString &idString, settings.childGroups()) {
settings.beginGroup(idString);
@ -441,20 +449,17 @@ void DeviceManager::loadConfiguredDevices()
device->setName(settings.value("devicename").toString());
QList<Param> params;
foreach (QString paramNameString, settings.childGroups()) {
qDebug() << "got paramNameString" << paramNameString;
settings.beginGroup(paramNameString);
Param param(paramNameString.remove(QRegExp("Param-")));
param.setValue(settings.value("value"));
settings.beginGroup("Params");
foreach (QString paramNameString, settings.allKeys()) {
Param param(paramNameString);
param.setValue(settings.value(paramNameString));
params.append(param);
settings.endGroup();
}
qDebug() << "loaded params from config" << params;
device->setParams(params);
settings.endGroup();
settings.endGroup();
qDebug() << "found stored device" << device->name() << idString;
qDebug() << "found stored device" << device->id() << device->name() << device->deviceClassId() << device->pluginId();
// We always add the device to the list in this case. If its in the storedDevices
// it means that it was working at some point so lets still add it as there might
@ -462,23 +467,26 @@ void DeviceManager::loadConfiguredDevices()
setupDevice(device);
m_configuredDevices.append(device);
}
settings.endGroup();
}
void DeviceManager::storeConfiguredDevices()
{
QSettings settings;
settings.beginGroup("DeviceConfig");
foreach (Device *device, m_configuredDevices) {
settings.beginGroup(device->id().toString());
settings.setValue("devicename", device->name());
settings.setValue("deviceClassId", device->deviceClassId().toString());
settings.setValue("pluginid", device->pluginId());
settings.setValue("pluginid", device->pluginId().toString());
settings.beginGroup("Params");
foreach (const Param &param, device->params()) {
settings.beginGroup("Param-" + param.name());
settings.setValue("value", param.value());
settings.endGroup();
settings.setValue(param.name(), param.value());
}
settings.endGroup();
settings.endGroup();
}
settings.endGroup();
}
void DeviceManager::createNewAutoDevices()
@ -603,7 +611,7 @@ void DeviceManager::timerEvent()
foreach (Device *device, m_configuredDevices) {
DeviceClass deviceClass = m_supportedDevices.value(device->deviceClassId());
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
if (plugin->requiredHardware().testFlag(HardwareResourceTimer)) {
if (plugin && plugin->requiredHardware().testFlag(HardwareResourceTimer)) {
plugin->guhTimer();
}
}
@ -614,6 +622,10 @@ QPair<DeviceManager::DeviceSetupStatus,QString> DeviceManager::setupDevice(Devic
DeviceClass deviceClass = findDeviceClass(device->deviceClassId());
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
if (!plugin) {
return qMakePair<DeviceSetupStatus, QString>(DeviceSetupStatusFailure, "Can't find a plugin for this device");
}
QList<State> states;
foreach (const StateType &stateType, deviceClass.states()) {
State state(stateType.id(), device->id());
@ -649,22 +661,64 @@ QPair<DeviceManager::DeviceSetupStatus,QString> DeviceManager::setupDevice(Devic
return status;
}
QPair<bool, QString> DeviceManager::verifyParams(const QList<ParamType> paramTypes, const QList<Param> params)
QPair<DeviceManager::DeviceError, QString> DeviceManager::verifyParams(const QList<ParamType> paramTypes, const QList<Param> &params, bool requireAll)
{
foreach (const Param &param, params) {
QPair<DeviceManager::DeviceError, QString> result = verifyParam(paramTypes, param);
if (result.first != DeviceErrorNoError) {
return result;
}
}
if (!requireAll) {
return report();
}
foreach (const ParamType &paramType, paramTypes) {
qDebug() << "checking paramType" << paramType.name();
bool found = false;
foreach (const Param &param, params) {
qDebug() << "checking param" << param.name();
if (param.name() == paramType.name()) {
if (param.value().canConvert(paramType.type())) {
found = true;
}
if (paramType.name() == param.name()) {
found = true;
}
}
if (!found) {
return qMakePair<bool, QString>(false, paramType.name());
return report(DeviceErrorMissingParameter, QString("Missing parameter: %1").arg(paramType.name()));
}
}
return qMakePair<bool, QString>(true, QString());
return report();
}
QPair<DeviceManager::DeviceError, QString> DeviceManager::verifyParam(const QList<ParamType> paramTypes, const Param &param)
{
foreach (const ParamType &paramType, paramTypes) {
if (paramType.name() == param.name()) {
return verifyParam(paramType, param);
}
}
return report(DeviceErrorInvalidParameter, QString("Parameter %1 not in ParamTypes list").arg(param.name()));
}
QPair<DeviceManager::DeviceError, QString> DeviceManager::verifyParam(const ParamType &paramType, const Param &param)
{
if (paramType.name() == param.name()) {
if (!param.value().canConvert(paramType.type())) {
return report(DeviceManager::DeviceErrorInvalidParameter, QString("Wrong parameter type for param %1. Got: %2. Expected %3.")
.arg(param.name()).arg(param.value().toString()).arg(QVariant::typeToName(paramType.type())));
}
if (paramType.maxValue().isValid() && param.value() > paramType.maxValue()) {
return report(DeviceManager::DeviceErrorInvalidParameter, QString("Value out of range for param %1. Got: %2. Max: %3.")
.arg(param.name()).arg(param.value().toString()).arg(paramType.maxValue().toString()));
}
if (paramType.minValue().isValid() && param.value() < paramType.maxValue()) {
return report(DeviceManager::DeviceErrorInvalidParameter, QString("Value out of range for param %1. Got: %2. Min: %3.")
.arg(param.name()).arg(param.value().toString()).arg(paramType.minValue().toString()));
}
return report();
}
return report(DeviceErrorInvalidParameter, QString("Parameter name %1 does not match with ParamType name %2")
.arg(param.name()).arg(paramType.name()));
}
QPair<DeviceManager::DeviceError, QString> DeviceManager::report(DeviceManager::DeviceError error, const QString &message)
{
return qMakePair<DeviceManager::DeviceError, QString>(error, message);
}

View File

@ -52,11 +52,11 @@ public:
DeviceErrorDeviceClassNotFound,
DeviceErrorActionTypeNotFound,
DeviceErrorMissingParameter,
DeviceErrorInvalidParameter,
DeviceErrorPluginNotFound,
DeviceErrorSetupFailed,
DeviceErrorDuplicateUuid,
DeviceErrorCreationMethodNotSupported,
DeviceErrorDeviceParameterError,
DeviceErrorActionParameterError,
DeviceErrorDeviceDescriptorNotFound,
DeviceErrorAsync
@ -73,7 +73,7 @@ public:
QList<DevicePlugin*> plugins() const;
DevicePlugin* plugin(const PluginId &id) const;
void setPluginConfig(const PluginId &pluginId, const QVariantMap &pluginConfig);
QPair<DeviceError, QString> setPluginConfig(const PluginId &pluginId, const QList<Param> &pluginConfig);
QList<Vendor> supportedVendors() const;
QList<DeviceClass> supportedDevices(const VendorId &vendorId = VendorId()) const;
@ -116,7 +116,11 @@ private slots:
private:
QPair<DeviceError, QString> addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QList<Param> &params, const DeviceId id = DeviceId::createDeviceId());
QPair<DeviceSetupStatus, QString> setupDevice(Device *device);
QPair<bool, QString> verifyParams(const QList<ParamType> paramTypes, const QList<Param> params);
QPair<DeviceError, QString> verifyParams(const QList<ParamType> paramTypes, const QList<Param> &params, bool requireAll = true);
QPair<DeviceError, QString> verifyParam(const QList<ParamType> paramTypes, const Param &param);
QPair<DeviceError, QString> verifyParam(const ParamType &paramType, const Param &param);
QPair<DeviceError, QString> report(DeviceError error = DeviceErrorNoError, const QString &message = QString());
private:

View File

@ -177,6 +177,11 @@ void DevicePlugin::deviceRemoved(Device *device)
Q_UNUSED(device)
}
QList<ParamType> DevicePlugin::configurationDescription() const
{
return QList<ParamType>();
}
/*! This will be called when the DeviceManager initializes the plugin and set up the things behind the scenes.
When implementing a new plugin, use \l{DevicePlugin::init()} instead in order to do initialisation work. */
void DevicePlugin::initPlugin(DeviceManager *deviceManager)
@ -190,22 +195,82 @@ void DevicePlugin::initPlugin(DeviceManager *deviceManager)
When implementing a new plugin, override this and fill in the empty configuration if your plugin requires any.
*/
QVariantMap DevicePlugin::configuration() const
QList<Param> DevicePlugin::configuration() const
{
return QVariantMap();
return m_config;
}
/*!
Use this to retrieve the values for your parameters. Values might not be set
at the time when your plugin is loaded, but will be set soon after. Listen to
configurationValueChanged() to know when something changes.
When implementing a new plugin, specify in configurationDescription() what you want to see here.
*/
QVariant DevicePlugin::configValue(const QString &paramName) const
{
foreach (const Param &param, m_config) {
if (param.name() == paramName) {
return param.value();
}
}
return QVariant();
}
/*!
Will be called by the DeviceManager to set a plugin's \a configuration.
When implementing a new plugin, override this and react to configuration changes.
TODO: Still need to define a common format for the config.
*/
void DevicePlugin::setConfiguration(const QVariantMap &configuration)
QPair<DeviceManager::DeviceError, QString> DevicePlugin::setConfiguration(const QList<Param> &configuration)
{
Q_UNUSED(configuration)
qWarning() << "Plugin" << pluginName() << pluginId() << "does not support any configuration";
foreach (const Param &param, configuration) {
qDebug() << "setting config" << param;
QPair<DeviceManager::DeviceError, QString> result = setConfigValue(param.name(), param.value());
if (result.first != DeviceManager::DeviceErrorNoError) {
return result;
}
}
return report();
}
/*!
Will be called by the DeviceManager to set a plugin's \a configuration.
*/
QPair<DeviceManager::DeviceError, QString> DevicePlugin::setConfigValue(const QString &paramName, const QVariant &value)
{
bool found = false;
foreach (const ParamType &paramType, configurationDescription()) {
if (paramType.name() == paramName) {
if (!value.canConvert(paramType.type())) {
return report(DeviceManager::DeviceErrorInvalidParameter, QString("Wrong parameter type for param %1. Got %2. Expected %3.")
.arg(paramName).arg(value.toString()).arg(QVariant::typeToName(paramType.type())));
}
if (paramType.maxValue().isValid() && value > paramType.maxValue()) {
return report(DeviceManager::DeviceErrorInvalidParameter, QString("Value out of range for param %1. Got %2. Max: %3.")
.arg(paramName).arg(value.toString()).arg(paramType.maxValue().toString()));
}
if (paramType.minValue().isValid() && value < paramType.minValue()) {
return report(DeviceManager::DeviceErrorInvalidParameter, QString("Value out of range for param %1. Got: %2. Min: %3.")
.arg(paramName).arg(value.toString()).arg(paramType.minValue().toString()));
}
found = true;
break;
}
}
if (!found) {
return report(DeviceManager::DeviceErrorInvalidParameter, QString("Invalid parameter %1.").arg(paramName));
}
for (int i = 0; i < m_config.count(); i++) {
if (m_config.at(i).name() == paramName) {
m_config[i].setValue(value);
emit configValueChanged(paramName, value);
return report();
}
}
// Still here? need to create the param
Param newParam(paramName, value);
m_config.append(newParam);
emit configValueChanged(paramName, value);
return report();
}
/*!
@ -292,4 +357,3 @@ QPair<DeviceManager::DeviceSetupStatus, QString> DevicePlugin::reportDeviceSetup
{
return qMakePair<DeviceManager::DeviceSetupStatus, QString>(status, message);
}

View File

@ -26,6 +26,7 @@
#include "types/event.h"
#include "types/action.h"
#include "types/vendor.h"
#include "types/param.h"
#include <QObject>
@ -58,8 +59,12 @@ public:
virtual void radioData(QList<int> rawData) {Q_UNUSED(rawData)}
virtual void guhTimer() {}
virtual QVariantMap configuration() const;
virtual void setConfiguration(const QVariantMap &configuration);
// Configuration
virtual QList<ParamType> configurationDescription() const;
QPair<DeviceManager::DeviceError, QString> setConfiguration(const QList<Param> &configuration);
QList<Param> configuration() const;
QVariant configValue(const QString &paramName) const;
QPair<DeviceManager::DeviceError, QString> setConfigValue(const QString &paramName, const QVariant &value);
public slots:
virtual QPair<DeviceManager::DeviceError, QString> executeAction(Device *device, const Action &action) {
@ -72,6 +77,7 @@ signals:
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors);
void deviceSetupFinished(Device *device, DeviceManager::DeviceSetupStatus status, const QString &errorMessage);
void actionExecutionFinished(const ActionId &id, DeviceManager::DeviceError status, const QString &errorMessage);
void configValueChanged(const QString &paramName, const QVariant &value);
protected:
DeviceManager *deviceManager() const;
@ -87,6 +93,8 @@ private:
DeviceManager *m_deviceManager;
QList<Param> m_config;
friend class DeviceManager;
};
Q_DECLARE_INTERFACE(DevicePlugin, "guru.guh.DevicePlugin")

View File

@ -60,9 +60,9 @@ QDebug operator<<(QDebug dbg, const Param &param)
QDebug operator<<(QDebug dbg, const QList<Param> &params)
{
dbg.nospace() << "ParamList (count:" << params.count() << ")";
dbg.nospace() << "ParamList (count:" << params.count() << ")" << endl;
for (int i = 0; i < params.count(); i++ ) {
dbg.nospace() << " " << i << ": " << params.at(i);
dbg.nospace() << " " << i << ": " << params.at(i) << endl;
}
return dbg.space();

View File

@ -74,3 +74,36 @@ void ParamType::setMaxValue(const QVariant &maxValue)
{
m_maxValue = maxValue;
}
QPair<QVariant, QVariant> ParamType::limits() const
{
return qMakePair<QVariant, QVariant>(m_minValue, m_maxValue);
}
void ParamType::setLimits(const QVariant &min, const QVariant &max)
{
m_minValue = min;
m_maxValue = max;
}
QDebug operator<<(QDebug dbg, const ParamType &paramType)
{
dbg.nospace() << "ParamType(Name: " << paramType.name()
<< ", Type:" << QVariant::typeToName(paramType.type())
<< ", Default:" << paramType.defaultValue()
<< ", Min:" << paramType.minValue()
<< ", Max:" << paramType.maxValue()
<< ")";
return dbg.space();
}
QDebug operator<<(QDebug dbg, const QList<ParamType> &paramTypes)
{
dbg.nospace() << "ParamTypeList (count:" << paramTypes.count() << ")" << endl;
for (int i = 0; i < paramTypes.count(); i++ ) {
dbg.nospace() << " " << i << ": " << paramTypes.at(i) << endl;
}
return dbg.space();
}

View File

@ -20,6 +20,7 @@
#define PARAMTYPE_H
#include <QVariant>
#include <QDebug>
class ParamType
{
@ -41,6 +42,9 @@ public:
QVariant maxValue() const;
void setMaxValue(const QVariant &maxValue);
QPair<QVariant, QVariant> limits() const;
void setLimits(const QVariant &min, const QVariant &max);
private:
QString m_name;
QVariant::Type m_type;
@ -49,4 +53,7 @@ private:
QVariant m_maxValue;
};
QDebug operator<<(QDebug dbg, const ParamType &paramType);
QDebug operator<<(QDebug dbg, const QList<ParamType> &paramTypes);
#endif // PARAMTYPE_H

View File

@ -36,11 +36,7 @@ ActionTypeId setColorActionTypeId = ActionTypeId("668e1aa3-fa13-49ce-8630-17a5c0
DevicePluginBoblight::DevicePluginBoblight()
{
m_bobClient = new BobClient(this);
m_config.insert("boblighthost", "localhost");
m_config.insert("boblightport", "19333");
connectToBoblight();
connect(this, &DevicePlugin::configValueChanged, this, &DevicePluginBoblight::connectToBoblight);
}
QList<Vendor> DevicePluginBoblight::supportedVendors() const
@ -122,15 +118,12 @@ PluginId DevicePluginBoblight::pluginId() const
return boblightPluginUuid;
}
QVariantMap DevicePluginBoblight::configuration() const
QList<ParamType> DevicePluginBoblight::configurationDescription() const
{
return m_config;
}
void DevicePluginBoblight::setConfiguration(const QVariantMap &configuration)
{
m_config = configuration;
connectToBoblight();
QList<ParamType> params;
params.append(ParamType("boblighthost", QVariant::String, "localhost"));
params.append(ParamType("boblightport", QVariant::String, "19333"));
return params;
}
QPair<DeviceManager::DeviceError, QString> DevicePluginBoblight::executeAction(Device *device, const Action &action)
@ -152,5 +145,7 @@ QPair<DeviceManager::DeviceError, QString> DevicePluginBoblight::executeAction(D
void DevicePluginBoblight::connectToBoblight()
{
m_bobClient->connect(m_config.value("boblighthost").toString(), m_config.value("boblightport").toInt());
if (configValue("boblighthost").isValid() && configValue("boblightport").isValid()) {
m_bobClient->connect(configValue("boblighthost").toString(), configValue("boblightport").toInt());
}
}

View File

@ -44,8 +44,7 @@ public:
QString pluginName() const override;
PluginId pluginId() const override;
QVariantMap configuration() const override;
void setConfiguration(const QVariantMap &configuration) override;
QList<ParamType> configurationDescription() const override;
public slots:
QPair<DeviceManager::DeviceError, QString> executeAction(Device *device, const Action &action);
@ -55,7 +54,7 @@ private slots:
private:
BobClient *m_bobClient;
QVariantMap m_config;
QList<Param> m_config;
};
#endif // DEVICEPLUGINBOBLIGHT_H

View File

@ -270,6 +270,19 @@ bool DevicePluginMock::configureAutoDevice(QList<Device *> loadedDevices, Device
return true;
}
QList<ParamType> DevicePluginMock::configurationDescription() const
{
QList<ParamType> params;
ParamType mockParam1("configParamInt", QVariant::Int, 42);
mockParam1.setLimits(1, 50);
params.append(mockParam1);
ParamType mockParam2("configParamBool", QVariant::Bool, true);
params.append(mockParam2);
return params;
}
QPair<DeviceManager::DeviceError, QString> DevicePluginMock::executeAction(Device *device, const Action &action)
{
if (!myDevices().contains(device)) {

View File

@ -49,6 +49,8 @@ public:
bool configureAutoDevice(QList<Device *> loadedDevices, Device *device) const override;
QList<ParamType> configurationDescription() const override;
public slots:
QPair<DeviceManager::DeviceError, QString> executeAction(Device *device, const Action &action) override;
@ -60,6 +62,7 @@ private slots:
void emitActionExecuted();
private:
QList<Param> m_config;
QHash<Device*, HttpDaemon*> m_daemons;
QList<Device*> m_asyncSetupDevices;
QList<QPair<Action, Device*> > m_asyncActions;

View File

@ -83,27 +83,7 @@ void ActionHandler::actionExecuted(const ActionId &id, DeviceManager::DeviceErro
QVariantMap ActionHandler::statusToReply(DeviceManager::DeviceError status, const QString &errorMessage)
{
QVariantMap returns;
switch (status) {
case DeviceManager::DeviceErrorNoError:
returns.insert("success", true);
returns.insert("errorMessage", "");
break;
case DeviceManager::DeviceErrorDeviceNotFound:
returns.insert("errorMessage", QString("No such device: %1").arg(errorMessage));
returns.insert("success", false);
break;
case DeviceManager::DeviceErrorActionTypeNotFound:
returns.insert("errorMessage", QString("ActionType not found: %1").arg(errorMessage));
returns.insert("success", false);
break;
case DeviceManager::DeviceErrorMissingParameter:
returns.insert("errorMessage", QString("Missing parameter: %1").arg(errorMessage));
returns.insert("success", false);
break;
default:
returns.insert("errorMessage", QString("Unknown error %1 %2").arg(status).arg(errorMessage));
returns.insert("success", false);
}
returns.insert("success", status == DeviceManager::DeviceErrorNoError);
returns.insert("errorMessage", errorMessage);
return returns;
}

View File

@ -56,13 +56,24 @@ DeviceHandler::DeviceHandler(QObject *parent) :
returns.insert("plugins", plugins);
setReturns("GetPlugins", returns);
params.clear(); returns.clear();
setDescription("GetPluginConfiguration", "Get a plugin's params.");
params.insert("pluginId", "uuid");
setParams("GetPluginConfiguration", params);
QVariantList pluginParams;
pluginParams.append(JsonTypes::paramRef());
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
returns.insert("o:configuration", pluginParams);
setReturns("GetPluginConfiguration", returns);
params.clear(); returns.clear();
setDescription("SetPluginConfiguration", "Set a plugin's params.");
params.insert("pluginId", "uuid");
QVariantList pluginParams;
pluginParams.append(JsonTypes::paramTypeRef());
params.insert("pluginParams", pluginParams);
params.insert("configuration", pluginParams);
setParams("SetPluginConfiguration", params);
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
setReturns("SetPluginConfiguration", returns);
params.clear(); returns.clear();
@ -231,23 +242,55 @@ JsonReply* DeviceHandler::GetPlugins(const QVariantMap &params) const
QVariantMap pluginMap;
pluginMap.insert("id", plugin->pluginId());
pluginMap.insert("name", plugin->pluginName());
pluginMap.insert("params", plugin->configuration());
QVariantList params;
foreach (const ParamType &param, plugin->configurationDescription()) {
params.append(JsonTypes::packParamType(param));
}
pluginMap.insert("params", params);
plugins.append(pluginMap);
}
returns.insert("plugins", plugins);
return createReply(returns);
}
JsonReply *DeviceHandler::GetPluginConfiguration(const QVariantMap &params) const
{
DevicePlugin *plugin = 0;
foreach (DevicePlugin *p, GuhCore::instance()->deviceManager()->plugins()) {
if (p->pluginId() == PluginId(params.value("pluginId").toString())) {
plugin = p;
}
}
QVariantMap returns;
if (!plugin) {
returns.insert("success", false);
returns.insert("errorMessage", QString("Plugin not found: %1").arg(params.value("pluginId").toString()));
return createReply(returns);
}
QVariantList paramVariantList;
foreach (const Param &param, plugin->configuration()) {
paramVariantList.append(JsonTypes::packParam(param));
}
returns.insert("configuration", paramVariantList);
returns.insert("success", true);
returns.insert("errorMessage", QString());
return createReply(returns);
}
JsonReply* DeviceHandler::SetPluginConfiguration(const QVariantMap &params)
{
QVariantMap returns;
PluginId pluginId = PluginId(params.value("pluginId").toString());
QVariantMap pluginParams = params.value("pluginParams").toMap();
GuhCore::instance()->deviceManager()->setPluginConfig(pluginId, pluginParams);
// TODO: handle return values
returns.insert("errorMessage", QString());
returns.insert("success", true);
QList<Param> pluginParams;
foreach (const QVariant &param, params.value("configuration").toList()) {
qDebug() << "got param" << param;
pluginParams.append(JsonTypes::unpackParam(param.toMap()));
}
QPair<DeviceManager::DeviceError, QString> result = GuhCore::instance()->deviceManager()->setPluginConfig(pluginId, pluginParams);
returns.insert("success", result.first == DeviceManager::DeviceErrorNoError);
returns.insert("errorMessage", result.second);
return createReply(returns);
}
@ -298,7 +341,7 @@ JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
returns.insert("errorMessage", QString("Error creating device. This device can't be created this way: %1").arg(status.second));
returns.insert("success", false);
break;
case DeviceManager::DeviceErrorDeviceParameterError:
case DeviceManager::DeviceErrorInvalidParameter:
returns.insert("errorMessage", QString("Error creating device. Invalid device parameter: %1").arg(status.second));
returns.insert("success", false);
break;

View File

@ -38,6 +38,8 @@ public:
Q_INVOKABLE JsonReply* GetPlugins(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetPluginConfiguration(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* SetPluginConfiguration(const QVariantMap &params);
Q_INVOKABLE JsonReply* AddConfiguredDevice(const QVariantMap &params);

View File

@ -438,10 +438,10 @@ QPair<bool, QString> JsonTypes::validateMap(const QVariantMap &templateMap, cons
strippedKey.remove(QRegExp("^o:"));
if (!key.startsWith("o:") && !map.contains(strippedKey)) {
qDebug() << "*** missing key" << key;
qDebug() << "Expected:" << templateMap;
qDebug() << "Got:" << map;
qDebug() << "Expected: " << templateMap;
qDebug() << "Got: " << map;
QJsonDocument jsonDoc = QJsonDocument::fromVariant(map);
return report(false, QString("Missing key \"%1\" in %2").arg(key).arg(QString(jsonDoc.toJson())));
return report(false, QString("Missing key %1 in %2").arg(key).arg(QString(jsonDoc.toJson())));
}
if (map.contains(strippedKey)) {
QPair<bool, QString> result = validateVariant(templateMap.value(key), map.value(strippedKey));

View File

@ -1,4 +1,4 @@
0.1.1
0.1.2
{
"methods": {
"Actions.ExecuteAction": {
@ -78,6 +78,19 @@
]
}
},
"Devices.GetPluginConfiguration": {
"description": "Get a plugin's params.",
"params": {
"pluginId": "uuid"
},
"returns": {
"errorMessage": "string",
"o:configuration": [
"$ref:Param"
],
"success": "bool"
}
},
"Devices.GetPlugins": {
"description": "Returns a list of loaded plugins.",
"params": {
@ -145,12 +158,14 @@
"Devices.SetPluginConfiguration": {
"description": "Set a plugin's params.",
"params": {
"pluginId": "uuid",
"pluginParams": [
"$ref:ParamType"
]
"configuration": [
"$ref:Param"
],
"pluginId": "uuid"
},
"returns": {
"errorMessage": "string",
"success": "bool"
}
},
"JSONRPC.Introspect": {

View File

@ -19,6 +19,7 @@
#include "guhtestbase.h"
#include "guhcore.h"
#include "devicemanager.h"
#include "plugin/deviceplugin.h"
#include <QDebug>
#include <QSignalSpy>
@ -28,9 +29,14 @@ class TestDevices : public GuhTestBase
Q_OBJECT
private slots:
void getPlugins();
void getPluginConfig_data();
void getPluginConfig();
void setPluginConfig_data();
void setPluginConfig();
void getSupportedVendors();
void getSupportedDevices_data();
@ -49,6 +55,14 @@ private slots:
void discoverDevices_data();
void discoverDevices();
void getActionTypes_data();
void getActionTypes();
void getEventTypes_data();
void getEventTypes();
void getStateTypes_data();
void getStateTypes();
};
void TestDevices::getPlugins()
@ -61,6 +75,66 @@ void TestDevices::getPlugins()
QCOMPARE(PluginId(plugins.first().toMap().value("id").toString()), mockPluginId);
}
void TestDevices::getPluginConfig_data()
{
QTest::addColumn<PluginId>("pluginId");
QTest::addColumn<bool>("success");
QTest::newRow("valid plugin") << mockPluginId << true;
QTest::newRow("invalid plugin") << PluginId::createPluginId() << false;
}
void TestDevices::getPluginConfig()
{
QFETCH(PluginId, pluginId);
QFETCH(bool, success);
QVariantMap params;
params.insert("pluginId", pluginId);
QVariant response = injectAndWait("Devices.GetPluginConfiguration", params);
verifySuccess(response, success);
}
void TestDevices::setPluginConfig_data()
{
QTest::addColumn<PluginId>("pluginId");
QTest::addColumn<QVariant>("value");
QTest::addColumn<bool>("success");
QTest::newRow("valid") << mockPluginId << QVariant(13) << true;
QTest::newRow("invalid plugin") << PluginId::createPluginId() << QVariant(13) << false;
QTest::newRow("too big") << mockPluginId << QVariant(130) << false;
QTest::newRow("too small") << mockPluginId << QVariant(-13) << false;
QTest::newRow("wrong type") << mockPluginId << QVariant("wrontType") << false;
}
void TestDevices::setPluginConfig()
{
QFETCH(PluginId, pluginId);
QFETCH(QVariant, value);
QFETCH(bool, success);
QVariantMap params;
params.insert("pluginId", pluginId);
QVariantList configuration;
QVariantMap configParam;
configParam.insert("configParamInt", value);
configuration.append(configParam);
params.insert("configuration", configuration);
QVariant response = injectAndWait("Devices.SetPluginConfiguration", params);
verifySuccess(response, success);
if (success) {
params.clear();
params.insert("pluginId", pluginId);
response = injectAndWait("Devices.GetPluginConfiguration", params);
verifySuccess(response);
qDebug() << "222" << response.toMap().value("params").toMap().value("configuration").toList().first();
QVERIFY2(response.toMap().value("params").toMap().value("configuration").toList().first().toMap().value("configParamInt") == value, "Value not set correctly");
}
}
void TestDevices::getSupportedVendors()
{
QVariant supportedVendors = injectAndWait("Devices.GetSupportedVendors");
@ -172,6 +246,7 @@ void TestDevices::removeDevice()
QFETCH(bool, success);
QSettings settings;
settings.beginGroup("DeviceConfig");
if (success) {
settings.beginGroup(m_mockDeviceId.toString());
// Make sure we have some config values for this device
@ -212,6 +287,7 @@ void TestDevices::storedDevices()
response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap());
bool found = false;
foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) {
qDebug() << "found stored device" << device;
if (DeviceId(device.toMap().value("id").toString()) == addedDeviceId) {
@ -222,8 +298,11 @@ void TestDevices::storedDevices()
qDebug() << "found added device" << device.toMap().value("params").toList().first().toMap();
qDebug() << "expected deviceParams:" << deviceParams;
QCOMPARE(device.toMap().value("params").toList().first().toMap(), deviceParams);
found = true;
break;
}
}
QVERIFY2(found, "Device missing in config!");
params.clear();
params.insert("deviceId", addedDeviceId);
@ -274,6 +353,81 @@ void TestDevices::discoverDevices()
}
}
void TestDevices::getActionTypes_data()
{
QTest::addColumn<DeviceClassId>("deviceClassId");
QTest::addColumn<int>("resultCount");
QTest::newRow("valid deviceclass") << mockDeviceClassId << 5;
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
}
void TestDevices::getActionTypes()
{
QFETCH(DeviceClassId, deviceClassId);
QFETCH(int, resultCount);
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
QVariant response = injectAndWait("Devices.GetActionTypes", params);
QVariantList actionTypes = response.toMap().value("params").toMap().value("actionTypes").toList();
QCOMPARE(actionTypes.count(), resultCount);
if (resultCount > 0) {
QCOMPARE(actionTypes.first().toMap().value("id").toString(), mockActionIdWithParams.toString());
}
}
void TestDevices::getEventTypes_data()
{
QTest::addColumn<DeviceClassId>("deviceClassId");
QTest::addColumn<int>("resultCount");
QTest::newRow("valid deviceclass") << mockDeviceClassId << 2;
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
}
void TestDevices::getEventTypes()
{
QFETCH(DeviceClassId, deviceClassId);
QFETCH(int, resultCount);
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
QVariant response = injectAndWait("Devices.GetEventTypes", params);
QVariantList eventTypes = response.toMap().value("params").toMap().value("eventTypes").toList();
QCOMPARE(eventTypes.count(), resultCount);
if (resultCount > 0) {
QCOMPARE(eventTypes.first().toMap().value("id").toString(), mockEvent1Id.toString());
}
}
void TestDevices::getStateTypes_data()
{
QTest::addColumn<DeviceClassId>("deviceClassId");
QTest::addColumn<int>("resultCount");
QTest::newRow("valid deviceclass") << mockDeviceClassId << 2;
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
}
void TestDevices::getStateTypes()
{
QFETCH(DeviceClassId, deviceClassId);
QFETCH(int, resultCount);
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
QVariant response = injectAndWait("Devices.GetStateTypes", params);
QVariantList stateTypes = response.toMap().value("params").toMap().value("stateTypes").toList();
QCOMPARE(stateTypes.count(), resultCount);
if (resultCount > 0) {
QCOMPARE(stateTypes.first().toMap().value("id").toString(), mockIntStateId.toString());
}
}
#include "testdevices.moc"
QTEST_MAIN(TestDevices)

View File

@ -65,7 +65,7 @@ void GuhTestBase::initTestCase()
params.insert("deviceParams", deviceParams);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
verifySuccess(response);
m_mockDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY2(!m_mockDeviceId.isNull(), "Newly created mock device must not be null.");

View File

@ -38,15 +38,6 @@ private slots:
void testBasicCall();
void introspect();
void getActionTypes_data();
void getActionTypes();
void getEventTypes_data();
void getEventTypes();
void getStateTypes_data();
void getStateTypes();
void enableDisableNotifications_data();
void enableDisableNotifications();
@ -131,81 +122,6 @@ void TestJSONRPC::introspect()
}
}
void TestJSONRPC::getActionTypes_data()
{
QTest::addColumn<DeviceClassId>("deviceClassId");
QTest::addColumn<int>("resultCount");
QTest::newRow("valid deviceclass") << mockDeviceClassId << 2;
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
}
void TestJSONRPC::getActionTypes()
{
QFETCH(DeviceClassId, deviceClassId);
QFETCH(int, resultCount);
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
QVariant response = injectAndWait("Devices.GetActionTypes", params);
QVariantList actionTypes = response.toMap().value("params").toMap().value("actionTypes").toList();
QCOMPARE(actionTypes.count(), resultCount);
if (resultCount > 0) {
QCOMPARE(actionTypes.first().toMap().value("id").toString(), mockActionIdWithParams.toString());
}
}
void TestJSONRPC::getEventTypes_data()
{
QTest::addColumn<DeviceClassId>("deviceClassId");
QTest::addColumn<int>("resultCount");
QTest::newRow("valid deviceclass") << mockDeviceClassId << 2;
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
}
void TestJSONRPC::getEventTypes()
{
QFETCH(DeviceClassId, deviceClassId);
QFETCH(int, resultCount);
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
QVariant response = injectAndWait("Devices.GetEventTypes", params);
QVariantList eventTypes = response.toMap().value("params").toMap().value("eventTypes").toList();
QCOMPARE(eventTypes.count(), resultCount);
if (resultCount > 0) {
QCOMPARE(eventTypes.first().toMap().value("id").toString(), mockEvent1Id.toString());
}
}
void TestJSONRPC::getStateTypes_data()
{
QTest::addColumn<DeviceClassId>("deviceClassId");
QTest::addColumn<int>("resultCount");
QTest::newRow("valid deviceclass") << mockDeviceClassId << 2;
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
}
void TestJSONRPC::getStateTypes()
{
QFETCH(DeviceClassId, deviceClassId);
QFETCH(int, resultCount);
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
QVariant response = injectAndWait("Devices.GetStateTypes", params);
QVariantList stateTypes = response.toMap().value("params").toMap().value("stateTypes").toList();
QCOMPARE(stateTypes.count(), resultCount);
if (resultCount > 0) {
QCOMPARE(stateTypes.first().toMap().value("id").toString(), mockIntStateId.toString());
}
}
void TestJSONRPC::enableDisableNotifications_data()
{
QTest::addColumn<QString>("enabled");

View File

@ -0,0 +1,7 @@
#!/bin/bash
if [ -z $2 ]; then
echo "usage $0 host pluginid"
else
(echo '{"id":1, "method":"Devices.GetPluginConfiguration", "params":{"pluginId":"'$2'"}}'; sleep 1) | nc $1 1234
fi

View File

@ -3,9 +3,9 @@
if [ -z $4 ]; then
echo "usage $0 host pluginid param1name param1value [param2name param2value]"
elif [ -z $5 ]; then
(echo '{"id":1, "method":"Devices.SetPluginConfiguration", "params":{"pluginId":"'$2'", "pluginParams":{"'$3'":"'$4'"}}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Devices.SetPluginConfiguration", "params":{"pluginId":"'$2'", "configuration":[{"'$3'":"'$4'"}]}}'; sleep 1) | nc $1 1234
elif [ -z $6 ]; then
echo "usage $0 host pluginid param1name param1value [param2name param2value]"
else
(echo '{"id":1, "method":"Devices.SetPluginConfiguration", "params":{"pluginId":"'$2'", "pluginParams":{"'$3'":"'$4'", "'$5'":"'$6'"}}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Devices.SetPluginConfiguration", "params":{"pluginId":"'$2'", "configuration":{[{"'$3'":"'$4'"}, {"'$5'":"'$6'"}]}}}'; sleep 1) | nc $1 1234
fi