bump api versio

bump guh version
added tests for edit device
added tests for edit device (rediscovery)
added device params changed notification
This commit is contained in:
Simon Stürz 2015-05-06 11:05:24 +02:00 committed by Michael Zanetti
parent b366d45229
commit 5af2067308
18 changed files with 491 additions and 149 deletions

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
guh (0.4.0) vivid; urgency=medium
* add EditDevice and notifications
-- Simon Stürz <simon.stuerz@guh.guru> Wed, 06 May 2015 10:13:58 +0200
guh (0.3.0) utopic; urgency=medium
* update rule engine and many other small changes

View File

@ -1,6 +1,10 @@
# Parse and export GUH_VERSION_STRING
GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"')
DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\"
# define JSON protocol version
JSON_PROTOCOL_VERSION=21
DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" JSON_PROTOCOL_VERSION=21
QT+= network

View File

@ -22,7 +22,7 @@ test.commands = LD_LIBRARY_PATH=$$top_builddir/libguh make check
QMAKE_EXTRA_TARGETS += licensecheck doc test
message("Building guh version $${GUH_VERSION_STRING}")
message("Building guh version $${GUH_VERSION_STRING} (API version $${JSON_PROTOCOL_VERSION})")
coverage {
message("Building coverage.")

View File

@ -325,10 +325,8 @@ DeviceManager::DeviceError DeviceManager::addConfiguredDevice(const DeviceClassI
return addConfiguredDeviceInternal(deviceClassId, descriptor.params(), deviceId);
}
DeviceManager::DeviceError DeviceManager::editDevice(const DeviceId &deviceId, const ParamList &params)
DeviceManager::DeviceError DeviceManager::editDevice(const DeviceId &deviceId, const ParamList &params, const bool fromDiscovery)
{
qDebug() << "EDIT DEVICE!!!!";
Device *device = findConfiguredDevice(deviceId);
if (!device) {
return DeviceErrorDeviceNotFound;
@ -345,12 +343,15 @@ DeviceManager::DeviceError DeviceManager::editDevice(const DeviceId &deviceId, c
return DeviceErrorPluginNotFound;
}
// check if one of the given params is not editable
foreach (const ParamType &paramType, deviceClass.paramTypes()) {
foreach (const Param &param, params) {
if (paramType.name() == param.name()) {
if (!paramType.editable())
return DeviceErrorParameterNotEditable;
// if the params are discovered and not set by the user
if (!fromDiscovery) {
// check if one of the given params is not editable
foreach (const ParamType &paramType, deviceClass.paramTypes()) {
foreach (const Param &param, params) {
if (paramType.name() == param.name()) {
if (!paramType.editable())
return DeviceErrorParameterNotEditable;
}
}
}
}
@ -373,27 +374,42 @@ DeviceManager::DeviceError DeviceManager::editDevice(const DeviceId &deviceId, c
qWarning() << "Device edit failed. Not saving changes of device paramters.";
return DeviceErrorSetupFailed;
case DeviceSetupStatusAsync:
qDebug() << "Device edit async. Waiting for complete...";
m_asyncDeviceEdit.append(device);
return DeviceErrorAsync;
case DeviceSetupStatusSuccess:
qDebug() << "Device params edit complete.";
qDebug() << "Device edit complete.";
break;
}
storeConfiguredDevices();
postSetupDevice(device);
emit deviceParamsChanged(device);
device->setupCompleted();
emit deviceParamsChanged(device);
return DeviceErrorNoError;
}
DeviceManager::DeviceError DeviceManager::editDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId)
{
Q_UNUSED(deviceId)
Q_UNUSED(deviceDescriptorId)
Device *device = findConfiguredDevice(deviceId);
if (!device) {
return DeviceErrorDeviceNotFound;
}
return DeviceErrorNoError;
DeviceClass deviceClass = findDeviceClass(device->deviceClassId());
if (!deviceClass.isValid()) {
return DeviceErrorDeviceClassNotFound;
}
if (!deviceClass.createMethods().testFlag(DeviceClass::CreateMethodDiscovery)) {
return DeviceErrorCreationMethodNotSupported;
}
DeviceDescriptor descriptor = m_discoveredDevices.take(deviceDescriptorId);
if (!descriptor.isValid()) {
return DeviceErrorDeviceDescriptorNotFound;
}
return editDevice(deviceId, descriptor.params(), true);
}
/*! Initiates a pairing with a \l{DeviceClass}{Device} with the given \a pairingTransactionId, \a deviceClassId and \a params.
@ -836,6 +852,15 @@ void DeviceManager::slotDeviceSetupFinished(Device *device, DeviceManager::Devic
if (status == DeviceSetupStatusFailure) {
if (m_configuredDevices.contains(device)) {
if (m_asyncDeviceEdit.contains(device)) {
m_asyncDeviceEdit.removeAll(device);
qWarning() << QString("Error in device setup after edit params. Device %1 (%2) would not be functional.").arg(device->name()).arg(device->id().toString());
storeConfiguredDevices();
device->setupCompleted();
// TODO: recover old params.??
emit deviceEditFinished(device, DeviceError::DeviceErrorSetupFailed);
}
qWarning() << QString("Error in device setup. Device %1 (%2) will not be functional.").arg(device->name()).arg(device->id().toString());
emit deviceSetupFinished(device, DeviceError::DeviceErrorSetupFailed);
return;
@ -863,13 +888,13 @@ void DeviceManager::slotDeviceSetupFinished(Device *device, DeviceManager::Devic
m_pluginTimerUsers.append(device);
}
// if this is a async device edit
// if this is a async device edit result
if (m_asyncDeviceEdit.contains(device)) {
m_asyncDeviceEdit.removeAll(device);
storeConfiguredDevices();
device->setupCompleted();
qDebug() << "emit Device edit finished!!!";
emit deviceEditFinished(device, DeviceManager::DeviceErrorNoError);
emit deviceParamsChanged(device);
return;
}
@ -1031,7 +1056,7 @@ void DeviceManager::replyReady(const PluginId &pluginId, QNetworkReply *reply)
foreach (DevicePlugin *devicePlugin, m_devicePlugins) {
if (devicePlugin->requiredHardware().testFlag(HardwareResourceNetworkManager) && devicePlugin->pluginId() == pluginId) {
devicePlugin->networkManagerReplyReady(reply);
}
}
}
}
void DeviceManager::upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &deviceDescriptorList, const PluginId &pluginId)
@ -1143,7 +1168,7 @@ DeviceManager::DeviceError DeviceManager::verifyParams(const QList<ParamType> pa
}
// This paramType has a default value... lets fill in that one.
if (!paramType.defaultValue().isNull()) {
if (!paramType.defaultValue().isNull() && !found) {
found = true;
params.append(Param(paramType.name(), paramType.defaultValue()));
}

View File

@ -99,7 +99,7 @@ public:
DeviceError addConfiguredDevice(const DeviceClassId &deviceClassId, const ParamList &params, const DeviceId id = DeviceId::createDeviceId());
DeviceError addConfiguredDevice(const DeviceClassId &deviceClassId, const DeviceDescriptorId &deviceDescriptorId, const DeviceId &id = DeviceId::createDeviceId());
DeviceError editDevice(const DeviceId &deviceId, const ParamList &params);
DeviceError editDevice(const DeviceId &deviceId, const ParamList &params, const bool fromDiscovery = false);
DeviceError editDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId);
DeviceError pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList &params);

View File

@ -139,13 +139,13 @@ void ParamType::setAllowedValues(const QList<QVariant> allowedValues)
m_allowedValues = allowedValues;
}
/*! Returns true if this ParamType is editable by the user. By default each ParamType is editable. */
/*! Returns true if this ParamType is editable by the user. By default a ParamType is always editable. */
bool ParamType::editable() const
{
return m_editable;
}
/*! Sets this ParamType \a editable. By default each ParamType is editable. */
/*! Sets this ParamType \a editable. By default a ParamType is always editable. */
void ParamType::setEditable(const bool &editable)
{
m_editable = editable;

View File

@ -54,7 +54,11 @@ DeviceManager::DeviceError DevicePluginMock::discoverDevices(const DeviceClassId
DeviceManager::DeviceSetupStatus DevicePluginMock::setupDevice(Device *device)
{
qDebug() << "Mockdevice created returning true" << device->paramValue("httpport").toInt() << device->paramValue("async").toBool() << device->paramValue("broken").toBool();
qDebug() << "Mockdevice created returning true"
<< device->paramValue("name").toString()
<< device->paramValue("httpport").toInt()
<< device->paramValue("async").toBool()
<< device->paramValue("broken").toBool();
if (device->paramValue("broken").toBool()) {
qWarning() << "This device is intentionally broken.";
@ -82,7 +86,11 @@ DeviceManager::DeviceSetupStatus DevicePluginMock::setupDevice(Device *device)
DeviceManager::DeviceSetupStatus DevicePluginMock::editDevice(Device *device)
{
qDebug() << "Mockdevice edit params to" << device->paramValue("httpport").toInt() << device->paramValue("async").toBool() << device->paramValue("broken").toBool();
qDebug() << "Mockdevice edit params to"
<< device->paramValue("name").toString()
<< device->paramValue("httpport").toInt()
<< device->paramValue("async").toBool()
<< device->paramValue("broken").toBool();
if (device->paramValue("broken").toBool()) {
qWarning() << "This device is intentionally broken.";
@ -192,18 +200,22 @@ void DevicePluginMock::emitDevicesDiscovered()
QList<DeviceDescriptor> deviceDescriptors;
if (m_discoveredDeviceCount > 0) {
DeviceDescriptor d1(mockDeviceClassId, "Mock Device (Discovered)");
DeviceDescriptor d1(mockDeviceClassId, "Mock Device 1 (Discovered)", "55555");
ParamList params;
Param name("name", "Discovered Mock Device 1");
Param httpParam("httpport", "55555");
params.append(name);
params.append(httpParam);
d1.setParams(params);
deviceDescriptors.append(d1);
}
if (m_discoveredDeviceCount > 1) {
DeviceDescriptor d2(mockDeviceClassId, "Mock Device (Discovered)");
DeviceDescriptor d2(mockDeviceClassId, "Mock Device 2 (Discovered)", "55556");
ParamList params;
Param name("name", "Discovered Mock Device 2");
Param httpParam("httpport", "55556");
params.append(name);
params.append(httpParam);
d2.setParams(params);
deviceDescriptors.append(d2);

View File

@ -20,6 +20,13 @@
}
],
"paramTypes": [
{
"name": "name",
"type": "QString",
"inputType": "TextLine",
"defaultValue": "Mock device",
"editable": false
},
{
"name": "httpport",
"type": "int"
@ -32,8 +39,7 @@
{
"name": "broken",
"type": "bool",
"defaultValue": false,
"editable": false
"defaultValue": false
}
],
"stateTypes": [
@ -109,6 +115,13 @@
"name": "Mock Device (Auto created)",
"createMethods": ["auto"],
"paramTypes": [
{
"name": "name",
"type": "QString",
"inputType": "TextLine",
"defaultValue": "Mock device",
"editable": false
},
{
"name": "httpport",
"type": "int"

View File

@ -62,10 +62,13 @@ void HttpDaemon::actionExecuted(const ActionTypeId &actionTypeId)
void HttpDaemon::updateDevice(Device *device)
{
if (device->paramValue("httpport").toInt() != m_device->paramValue("httpport").toInt()) {
close();
listen(QHostAddress::Any, device->paramValue("httpport").toInt());
qDebug() << "Mockdevice httpport updated and listening now on" << device->paramValue("httpport").toInt();
}
m_device = device;
close();
listen(QHostAddress::Any, device->paramValue("httpport").toInt());
qDebug() << "Mockdevice updated and listening now on" << device->paramValue("httpport").toInt();
}
void HttpDaemon::readClient()

View File

@ -8,100 +8,105 @@ inputFile = open(sys.argv[1], "r")
outputfile = open(sys.argv[2], "w")
variableNames = []
def out(line):
outputfile.write("%s\n" % line)
try:
pluginMap = json.loads(inputFile.read())
except:
print("Error opening input file")
pluginMap = json.loads(inputFile.read())
except ValueError as e:
print " --> Error loading input file \"%s\"" % (sys.argv[1])
print " %s" % (e)
exit -1
def out(line):
outputfile.write("%s\n" % line)
def extractVendors(pluginMap):
for vendor in pluginMap['vendors']:
try:
out("VendorId %sVendorId = VendorId(\"%s\");" % pluginMap["idName"], pluginMap["id"])
except:
pass
extractDeviceClasses(vendor)
for vendor in pluginMap['vendors']:
try:
out("VendorId %sVendorId = VendorId(\"%s\");" % pluginMap["idName"], pluginMap["id"])
except:
pass
extractDeviceClasses(vendor)
def extractDeviceClasses(vendorMap):
for deviceClass in vendorMap["deviceClasses"]:
print("have deviceclass %s" % deviceClass["deviceClassId"])
try:
variableName = "%sDeviceClassId" % (deviceClass["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("DeviceClassId %s = DeviceClassId(\"%s\");" % (variableName, deviceClass["deviceClassId"]))
else:
print("duplicated variable name \"%s\" for DeviceClassId %s -> skipping") % (variableName, deviceClass["deviceClassId"])
except:
pass
extractActionTypes(deviceClass)
extractStateTypes(deviceClass)
extractEventTypes(deviceClass)
for deviceClass in vendorMap["deviceClasses"]:
print("have deviceclass %s" % deviceClass["deviceClassId"])
try:
variableName = "%sDeviceClassId" % (deviceClass["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("DeviceClassId %s = DeviceClassId(\"%s\");" % (variableName, deviceClass["deviceClassId"]))
else:
print("duplicated variable name \"%s\" for DeviceClassId %s -> skipping") % (variableName, deviceClass["deviceClassId"])
except:
pass
extractActionTypes(deviceClass)
extractStateTypes(deviceClass)
extractEventTypes(deviceClass)
def extractStateTypes(deviceClassMap):
try:
for stateType in deviceClassMap["stateTypes"]:
try:
variableName = "%sStateTypeId" % (stateType["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("StateTypeId %s = StateTypeId(\"%s\");" % (variableName, stateType["id"]))
else:
print("duplicated variable name \"%s\" for StateTypeId %s -> skipping") % (variableName, stateType["id"])
# create ActionTypeId if the state is writable
if 'writable' in stateType:
if stateType['writable'] == True:
print("create ActionTypeId for StateType %s" % stateType["id"])
vName = "%sActionTypeId" % (stateType["idName"])
if not vName in variableNames:
variableNames.append(vName)
out("ActionTypeId %s = ActionTypeId(\"%s\");" % (vName, stateType["id"]))
else:
print("duplicated variable name \"%s\" for ActionTypeId %s -> skipping") % (variableName, stateType["id"])
except:
pass
except:
pass
try:
for stateType in deviceClassMap["stateTypes"]:
try:
variableName = "%sStateTypeId" % (stateType["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("StateTypeId %s = StateTypeId(\"%s\");" % (variableName, stateType["id"]))
else:
print("duplicated variable name \"%s\" for StateTypeId %s -> skipping") % (variableName, stateType["id"])
# create ActionTypeId if the state is writable
if 'writable' in stateType:
if stateType['writable'] == True:
print("create ActionTypeId for StateType %s" % stateType["id"])
vName = "%sActionTypeId" % (stateType["idName"])
if not vName in variableNames:
variableNames.append(vName)
out("ActionTypeId %s = ActionTypeId(\"%s\");" % (vName, stateType["id"]))
else:
print("duplicated variable name \"%s\" for ActionTypeId %s -> skipping") % (variableName, stateType["id"])
except:
pass
except:
pass
def extractActionTypes(deviceClassMap):
try:
for actionType in deviceClassMap["actionTypes"]:
try:
variableName = "%sActionTypeId" % (actionType["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("ActionTypeId %s = ActionTypeId(\"%s\");" % (variableName, actionType["id"]))
else:
print("duplicated variable name \"%s\" for ActionTypeId %s -> skipping") % (variableName, actionType["id"])
except:
pass
except:
pass
try:
for actionType in deviceClassMap["actionTypes"]:
try:
variableName = "%sActionTypeId" % (actionType["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("ActionTypeId %s = ActionTypeId(\"%s\");" % (variableName, actionType["id"]))
else:
print("duplicated variable name \"%s\" for ActionTypeId %s -> skipping") % (variableName, actionType["id"])
except:
pass
except:
pass
def extractEventTypes(deviceClassMap):
try:
for eventType in deviceClassMap["eventTypes"]:
try:
variableName = "%sEventTypeId" % (eventType["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("EventTypeId %s = EventTypeId(\"%s\");" % (variableName, eventType["id"]))
else:
print("duplicated variable name \"%s\" for EventTypeId %s -> skipping") % (variableName, eventType["id"])
except:
pass
except:
pass
try:
for eventType in deviceClassMap["eventTypes"]:
try:
variableName = "%sEventTypeId" % (eventType["idName"])
if not variableName in variableNames:
variableNames.append(variableName)
out("EventTypeId %s = EventTypeId(\"%s\");" % (variableName, eventType["id"]))
else:
print("duplicated variable name \"%s\" for EventTypeId %s -> skipping") % (variableName, eventType["id"])
except:
pass
except:
pass
print " --> generate plugininfo.h"
print "PluginId for plugin \"%s\" = %s" %(pluginMap['name'], pluginMap['id'])
# write header
out("/* This file is generated by the guh build system. Any changes to this file will")
out(" * be lost.")
@ -115,6 +120,10 @@ out("#define PLUGININFO_H")
out("#include \"typeutils.h\"")
out("")
out("PluginId pluginId = PluginId(\"%s\");" % pluginMap['id'])
extractVendors(pluginMap)
out("")
out("#endif")
print " --> finished writing \"%s\"" % (sys.argv[2])

View File

@ -271,6 +271,11 @@ DeviceManager::DeviceError GuhCore::editDevice(const DeviceId &deviceId, const P
return m_deviceManager->editDevice(deviceId, params);
}
DeviceManager::DeviceError GuhCore::editDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId)
{
return m_deviceManager->editDevice(deviceId, deviceDescriptorId);
}
/*! Calls the metheod RuleEngine::rule().
* \sa RuleEngine, */
QList<Rule> GuhCore::rules() const

View File

@ -68,6 +68,7 @@ public:
Device *findConfiguredDevice(const DeviceId &deviceId) const;
QList<Device*> findConfiguredDevices(const DeviceClassId &deviceClassId) const;
DeviceManager::DeviceError editDevice(const DeviceId &deviceId, const ParamList &params);
DeviceManager::DeviceError editDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId);
DeviceManager::DeviceError removeConfiguredDevice(const DeviceId &deviceId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList);
DeviceManager::DeviceError pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const DeviceDescriptorId &deviceDescriptorId);
@ -92,6 +93,7 @@ signals:
void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value);
void deviceRemoved(const DeviceId &deviceId);
void deviceAdded(Device *device);
void deviceParamsChanged(Device *device);
void actionExecuted(const ActionId &id, DeviceManager::DeviceError status);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);

View File

@ -236,9 +236,15 @@ DeviceHandler::DeviceHandler(QObject *parent) :
params.insert("device", JsonTypes::deviceRef());
setParams("DeviceAdded", params);
params.clear(); returns.clear();
setDescription("DeviceParamsChanged", "Emitted whenever the params of a Device changed (by editing or rediscovering).");
params.insert("device", JsonTypes::deviceRef());
setParams("DeviceParamsChanged", params);
connect(GuhCore::instance(), &GuhCore::deviceStateChanged, this, &DeviceHandler::deviceStateChanged);
connect(GuhCore::instance(), &GuhCore::deviceRemoved, this, &DeviceHandler::deviceRemovedNotification);
connect(GuhCore::instance(), &GuhCore::deviceAdded, this, &DeviceHandler::deviceAddedNotification);
connect(GuhCore::instance(), &GuhCore::deviceParamsChanged, this, &DeviceHandler::deviceParamsChangedNotification);
connect(GuhCore::instance(), &GuhCore::devicesDiscovered, this, &DeviceHandler::devicesDiscovered, Qt::QueuedConnection);
connect(GuhCore::instance(), &GuhCore::deviceSetupFinished, this, &DeviceHandler::deviceSetupFinished);
connect(GuhCore::instance(), &GuhCore::deviceEditFinished, this, &DeviceHandler::deviceEditFinished);
@ -439,13 +445,13 @@ JsonReply *DeviceHandler::EditDevice(const QVariantMap &params)
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
DeviceManager::DeviceError status = GuhCore::instance()->editDevice(deviceId, deviceParams);
// if (deviceDescriptorId.isNull()) {
// status = GuhCore::instance()->addConfiguredDevice(deviceClass, deviceParams, newDeviceId);
// } else {
// status = GuhCore::instance()->addConfiguredDevice(deviceClass, deviceDescriptorId, newDeviceId);
// }
DeviceManager::DeviceError status;
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
if (deviceDescriptorId.isNull()) {
status = GuhCore::instance()->editDevice(deviceId, deviceParams);
} else {
status = GuhCore::instance()->editDevice(deviceId, deviceDescriptorId);
}
if (status == DeviceManager::DeviceErrorAsync) {
JsonReply *asyncReply = createAsyncReply("EditDevice");
@ -586,6 +592,14 @@ void DeviceHandler::deviceAddedNotification(Device *device)
emit DeviceAdded(params);
}
void DeviceHandler::deviceParamsChangedNotification(Device *device)
{
QVariantMap params;
params.insert("device", JsonTypes::packDevice(device));
emit DeviceParamsChanged(params);
}
void DeviceHandler::devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors)
{
if (!m_discoverRequests.contains(deviceClassId)) {

View File

@ -71,6 +71,7 @@ signals:
void StateChanged(const QVariantMap &params);
void DeviceRemoved(const QVariantMap &params);
void DeviceAdded(const QVariantMap &params);
void DeviceParamsChanged(const QVariantMap &params);
private slots:
void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value);
@ -79,6 +80,8 @@ private slots:
void deviceAddedNotification(Device *device);
void deviceParamsChangedNotification(Device *device);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
void deviceSetupFinished(Device *device, DeviceManager::DeviceError status);

View File

@ -47,8 +47,6 @@
#include <QJsonDocument>
#include <QStringList>
#define JSON_PROTOCOL_VERSION 20
JsonRPCServer::JsonRPCServer(QObject *parent):
JsonHandler(parent),
#ifdef TESTING_ENABLED

View File

@ -1,4 +1,4 @@
20
21
{
"methods": {
"Actions.ExecuteAction": {
@ -55,6 +55,19 @@
"o:deviceId": "Uuid"
}
},
"Devices.EditDevice": {
"description": "Edit the parameters of a 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). If a parameter is not editable, you will find a 'editable': false in the ParamType. By default, every Param is editable.",
"params": {
"deviceId": "Uuid",
"o:deviceDescriptorId": "Uuid",
"o:deviceParams": [
"$ref:Param"
]
},
"returns": {
"deviceError": "$ref:DeviceError"
}
},
"Devices.GetActionTypes": {
"description": "Get action types for a specified deviceClassId.",
"params": {
@ -371,6 +384,12 @@
"device": "$ref:Device"
}
},
"Devices.DeviceParamsChanged": {
"description": "Emitted whenever the params of a Device changed (by editing or rediscovering).",
"params": {
"device": "$ref:Device"
}
},
"Devices.DeviceRemoved": {
"description": "Emitted whenever a Device was removed.",
"params": {
@ -496,9 +515,11 @@
"DeviceErrorSetupMethodNotSupported",
"DeviceErrorHardwareNotAvailable",
"DeviceErrorHardwareFailure",
"DeviceErrorAuthentificationFailure",
"DeviceErrorAsync",
"DeviceErrorDeviceInUse",
"DeviceErrorPairingTransactionIdNotFound"
"DeviceErrorPairingTransactionIdNotFound",
"DeviceErrorParameterNotEditable"
],
"Event": {
"deviceId": "Uuid",
@ -578,6 +599,7 @@
"Variant"
],
"o:defaultValue": "Variant",
"o:editable": "Bool",
"o:inputType": "$ref:InputType",
"o:maxValue": "Variant",
"o:minValue": "Variant",

View File

@ -73,6 +73,9 @@ private slots:
void editDevices_data();
void editDevices();
void editByDiscovery_data();
void editByDiscovery();
// Keep this the last one! It'll remove the configured mock device
void removeDevice_data();
void removeDevice();
@ -288,6 +291,10 @@ void TestDevices::storedDevices()
QVariantMap params;
params.insert("deviceClassId", mockDeviceClassId);
QVariantList deviceParams;
QVariantMap nameParam;
nameParam.insert("name", "name");
nameParam.insert("value", "Blub Blub device");
deviceParams.append(nameParam);
QVariantMap asyncParam;
asyncParam.insert("name", "async");
asyncParam.insert("value", false);
@ -301,6 +308,7 @@ void TestDevices::storedDevices()
httpportParam.insert("value", 8888);
deviceParams.append(httpportParam);
params.insert("deviceParams", deviceParams);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId addedDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
@ -314,19 +322,16 @@ void TestDevices::storedDevices()
bool found = false;
foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) {
if (DeviceId(device.toMap().value("id").toString()) == addedDeviceId) {
// foreach (const QVariant &paramVariant, device.toMap().value("params").toList()) {
// if ()
// }
qDebug() << "found added device" << device.toMap().value("params");
qDebug() << "expected deviceParams:" << deviceParams;
QCOMPARE(device.toMap().value("params").toList(), deviceParams);
verifyParams(deviceParams, device.toMap().value("params").toList());
found = true;
break;
}
}
QVERIFY2(found, "Device missing in config!");
params.clear();
params.insert("deviceId", addedDeviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
@ -536,28 +541,39 @@ void TestDevices::editDevices_data()
brokenParamDifferent.insert("value", true);
brokenChangedDeviceParams.append(brokenParamDifferent);
QVariantList nameChangedDeviceParams;
QVariantMap nameParam;
nameParam.insert("name", "name");
nameParam.insert("value", "Awesome Mockdevice");
nameChangedDeviceParams.append(nameParam);
QVariantList asyncAndPortChangeDeviceParams;
asyncAndPortChangeDeviceParams.append(asyncParamDifferent);
asyncAndPortChangeDeviceParams.append(httpportParamDifferent);
QVariantList changeAllDeviceParams;
changeAllDeviceParams.append(asyncParamDifferent);
changeAllDeviceParams.append(httpportParamDifferent);
changeAllDeviceParams.append(brokenParamDifferent);
QVariantList changeAllEditableDeviceParams;
changeAllEditableDeviceParams.append(nameParam);
changeAllEditableDeviceParams.append(asyncParamDifferent);
changeAllEditableDeviceParams.append(httpportParamDifferent);
//changeAllEditableDeviceParams.append(brokenParamDifferent);
QTest::addColumn<bool>("broken");
QTest::addColumn<QVariantList>("newDeviceParams");
QTest::addColumn<DeviceManager::DeviceError>("deviceError");
QTest::newRow("valid - change async param") << asyncChangeDeviceParams << DeviceManager::DeviceErrorNoError;
QTest::newRow("valid - change httpport param") << httpportChangeDeviceParams << DeviceManager::DeviceErrorNoError;
QTest::newRow("valid - change httpport and async param") << asyncAndPortChangeDeviceParams << DeviceManager::DeviceErrorNoError;
QTest::newRow("invalid - change broken param (not editable)") << brokenChangedDeviceParams << DeviceManager::DeviceErrorParameterNotEditable;
QTest::newRow("invalid - change all params (also the not editable one)") << changeAllDeviceParams << DeviceManager::DeviceErrorParameterNotEditable;
QTest::newRow("valid - change async param") << false << asyncChangeDeviceParams << DeviceManager::DeviceErrorNoError;
QTest::newRow("valid - change httpport param") << false << httpportChangeDeviceParams << DeviceManager::DeviceErrorNoError;
QTest::newRow("valid - change httpport and async param") << false << asyncAndPortChangeDeviceParams << DeviceManager::DeviceErrorNoError;
QTest::newRow("invalid - change name param (not editable)") << false << nameChangedDeviceParams << DeviceManager::DeviceErrorParameterNotEditable;
QTest::newRow("invalid - change all params (except broken)") << false << changeAllEditableDeviceParams << DeviceManager::DeviceErrorParameterNotEditable;
}
void TestDevices::editDevices()
{
QFETCH(bool, broken);
QFETCH(QVariantList, newDeviceParams);
QFETCH(DeviceManager::DeviceError, deviceError);
@ -565,13 +581,17 @@ void TestDevices::editDevices()
QVariantMap params;
params.insert("deviceClassId", mockDeviceClassId);
QVariantList deviceParams;
QVariantMap nameParam;
nameParam.insert("name", "name");
nameParam.insert("value", "Test edit mockdevice");
deviceParams.append(nameParam);
QVariantMap asyncParam;
asyncParam.insert("name", "async");
asyncParam.insert("value", false);
deviceParams.append(asyncParam);
QVariantMap brokenParam;
brokenParam.insert("name", "broken");
brokenParam.insert("value", false);
brokenParam.insert("value", broken);
deviceParams.append(brokenParam);
QVariantMap httpportParam;
httpportParam.insert("name", "httpport");
@ -581,10 +601,13 @@ void TestDevices::editDevices()
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
// now edit the added device
DeviceId deviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!deviceId.isNull());
// now EDIT the added device
response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap());
// edit the added and verified device
QVariantMap editParams;
editParams.insert("deviceId", deviceId);
editParams.insert("deviceParams", newDeviceParams);
@ -593,40 +616,220 @@ void TestDevices::editDevices()
response = injectAndWait("Devices.EditDevice", editParams);
verifyDeviceError(response, deviceError);
if (deviceError != DeviceManager::DeviceErrorNoError) {
// if the edit should have been successfull
if (deviceError == DeviceManager::DeviceErrorNoError) {
response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap());
bool found = false;
foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) {
if (DeviceId(device.toMap().value("id").toString()) == deviceId) {
qDebug() << "found added device" << device.toMap().value("params");
qDebug() << "expected deviceParams:" << newDeviceParams;
// check if the edit was ok
verifyParams(newDeviceParams, device.toMap().value("params").toList(), false);
found = true;
break;
}
}
QVERIFY2(found, "Device missing in config!");
// Restart the core instance to check if settings are loaded at startup
restartServer();
response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap());
found = false;
foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) {
if (DeviceId(device.toMap().value("id").toString()) == deviceId) {
qDebug() << "found added device" << device.toMap().value("params");
qDebug() << "expected deviceParams:" << newDeviceParams;
// check if the edit was ok
verifyParams(newDeviceParams, device.toMap().value("params").toList(), false);
found = true;
break;
}
}
QVERIFY2(found, "Device missing in config!");
// delete it
params.clear();
params.insert("deviceId", deviceId);
response.clear();
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response);
return;
} else {
// The edit was not ok, check if the old params are still there
response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap());
bool found = false;
foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) {
if (DeviceId(device.toMap().value("id").toString()) == deviceId) {
qDebug() << "found added device" << device.toMap().value("params");
qDebug() << "expected deviceParams:" << newDeviceParams;
// check if the params are unchanged
verifyParams(deviceParams, device.toMap().value("params").toList());
found = true;
break;
}
}
QVERIFY2(found, "Device missing in config!");
// Restart the core instance to check if settings are loaded at startup
restartServer();
response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap());
found = false;
foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) {
if (DeviceId(device.toMap().value("id").toString()) == deviceId) {
qDebug() << "found added device" << device.toMap().value("params");
qDebug() << "expected deviceParams:" << newDeviceParams;
// check if after the reboot the settings are unchanged
verifyParams(deviceParams, device.toMap().value("params").toList());
found = true;
break;
}
}
QVERIFY2(found, "Device missing in config!");
}
// Restart the core instance to check if settings are loaded at startup
restartServer();
// delete it
params.clear();
params.insert("deviceId", deviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response);
}
void TestDevices::editByDiscovery_data()
{
QTest::addColumn<DeviceClassId>("deviceClassId");
QTest::addColumn<int>("resultCount");
QTest::addColumn<DeviceManager::DeviceError>("error");
QTest::addColumn<QVariantList>("discoveryParams");
QVariantList discoveryParams;
QVariantMap resultCountParam;
resultCountParam.insert("name", "resultCount");
resultCountParam.insert("value", 2);
discoveryParams.append(resultCountParam);
QTest::newRow("discover 2 devices with params") << mockDeviceClassId << 2 << DeviceManager::DeviceErrorNoError << discoveryParams;
}
void TestDevices::editByDiscovery()
{
QFETCH(DeviceClassId, deviceClassId);
QFETCH(int, resultCount);
QFETCH(DeviceManager::DeviceError, error);
QFETCH(QVariantList, discoveryParams);
QVariantMap params;
params.insert("deviceClassId", deviceClassId);
params.insert("discoveryParams", discoveryParams);
QVariant response = injectAndWait("Devices.GetDiscoveredDevices", params);
verifyDeviceError(response);
if (error == DeviceManager::DeviceErrorNoError) {
QCOMPARE(response.toMap().value("params").toMap().value("deviceDescriptors").toList().count(), resultCount);
}
// add Discovered Device 1 port 55555
QVariantList deviceDescriptors = response.toMap().value("params").toMap().value("deviceDescriptors").toList();
DeviceDescriptorId descriptorId1;
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();
break;
}
}
qDebug() << "adding descriptorId 1" << descriptorId1;
QVERIFY(!descriptorId1.isNull());
params.clear();
response.clear();
params.insert("deviceClassId", deviceClassId);
params.insert("deviceDescriptorId", descriptorId1);
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
params.clear();
response.clear();
params.insert("deviceClassId", deviceClassId);
params.insert("discoveryParams", discoveryParams);
response = injectAndWait("Devices.GetDiscoveredDevices", params);
verifyDeviceError(response, error);
if (error == DeviceManager::DeviceErrorNoError) {
QCOMPARE(response.toMap().value("params").toMap().value("deviceDescriptors").toList().count(), resultCount);
}
// get the second device
DeviceDescriptorId descriptorId2;
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());
break;
}
}
QVERIFY(!descriptorId2.isNull());
qDebug() << "edit device 1 (55555) with descriptor 2 (55556) " << descriptorId2;
// EDIT
response.clear();
params.clear();
params.insert("deviceId", deviceId.toString());
params.insert("deviceDescriptorId", descriptorId2);
response = injectAndWait("Devices.EditDevice", params);
verifyDeviceError(response, error);
response.clear();
response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap());
QVariantMap deviceMap;
bool found = false;
foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) {
if (DeviceId(device.toMap().value("id").toString()) == deviceId) {
qDebug() << "found added device" << device.toMap().value("params");
foreach (QVariant newParam, newDeviceParams) {
foreach (QVariant deviceParam, device.toMap().value("params").toList()) {
if (newParam.toMap().value("name").toString() == deviceParam.toMap().value("name").toString()) {
QCOMPARE(newParam.toMap().value("value"), deviceParam.toMap().value("value"));
}
}
}
found = true;
deviceMap = device.toMap();
break;
}
}
printJson(deviceMap);
QVERIFY2(found, "Device missing in config!");
QCOMPARE(deviceMap.value("id").toString(), deviceId.toString());
if (deviceMap.contains("setupComplete")) {
QVERIFY2(deviceMap.value("setupComplete").toBool(), "Setup not completed after edit");
}
// Note: this shows that by discovery a not editable param (name) can be changed!
foreach (QVariant param, deviceMap.value("params").toList()) {
if (param.toMap().value("name") == "name") {
QCOMPARE(param.toMap().value("value").toString(), QString("Discovered Mock Device 2"));
}
if (param.toMap().value("name") == "httpport") {
QCOMPARE(param.toMap().value("value").toInt(), 55556);
}
}
params.clear();
params.insert("deviceId", deviceId);
params.insert("deviceId", deviceId.toString());
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response);
}
@ -667,7 +870,6 @@ void TestDevices::removeDevice()
}
}
#include "testdevices.moc"
QTEST_MAIN(TestDevices)

View File

@ -88,6 +88,30 @@ protected:
verifyError(response, "deviceError", JsonTypes::deviceErrorToString(error));
}
inline void verifyParams(const QVariantList &requestList, const QVariantList &responseList, bool allRequired = true)
{
if (allRequired)
QVERIFY2(requestList.count() == responseList.count(), "Not the same count of param in response.");
foreach (const QVariant &requestParam, requestList) {
bool found = false;
foreach (const QVariant &responseParam, responseList) {
if (requestParam.toMap().value("name") == responseParam.toMap().value("name")){
QCOMPARE(requestParam.toMap().value("value"), responseParam.toMap().value("value"));
found = true;
break;
}
}
if (allRequired)
QVERIFY2(found, "Param missing");
}
}
// just for debugging
inline void printJson(const QVariant &response) {
QJsonDocument jsonDoc = QJsonDocument::fromVariant(response);
qDebug() << jsonDoc.toJson();
}
void restartServer();
protected: