Rework devicemanager and plugin api

pull/211/head
Michael Zanetti 2019-09-16 16:01:16 +02:00
parent c920ba43b2
commit 7f0f2d1d09
53 changed files with 2786 additions and 1773 deletions

View File

@ -20,6 +20,8 @@
#include "cloudnotifications.h"
#include "loggingcategories.h"
#include "devices/devicesetupinfo.h"
#include "devices/deviceactioninfo.h"
#include <QDebug>
#include <QJsonObject>
@ -136,31 +138,31 @@ PluginMetadata CloudNotifications::metaData() const
return PluginMetadata(QJsonObject::fromVariantMap(pluginMetaData), true);
}
Device::DeviceSetupStatus CloudNotifications::setupDevice(Device *device)
void CloudNotifications::setupDevice(DeviceSetupInfo *info)
{
Device *device = info->device();
device->setStateValue(connectedStateTypeId, m_awsConnector->isConnected());
qCDebug(dcCloud) << "Cloud Notifications Device setup:" << device->name() << "Connected:" << m_awsConnector->isConnected();
connect(m_awsConnector, &AWSConnector::connected, device, [device]() {
connect(m_awsConnector, &AWSConnector::connected, info->device(), [device]() {
device->setStateValue(connectedStateTypeId, true);
});
connect(m_awsConnector, &AWSConnector::disconnected, device, [device]() {
device->setStateValue(connectedStateTypeId, false);
});
return Device::DeviceSetupStatusSuccess;
info->finish(Device::DeviceErrorNoError);
}
void CloudNotifications::startMonitoringAutoDevices()
{
}
Device::DeviceError CloudNotifications::executeAction(Device *device, const Action &action)
void CloudNotifications::executeAction(DeviceActionInfo *info)
{
qCDebug(dcCloud()) << "executeAction" << device << action.id() << action.params();
QString userId = device->paramValue(cloudNotificationsDeviceClassUserParamId).toString();
QString endpointId = device->paramValue(cloudNotificationsDeviceClassEndpointParamId).toString();
int id = m_awsConnector->sendPushNotification(userId, endpointId, action.param(notifyActionParamTitleId).value().toString(), action.param(notifyActionParamBodyId).value().toString());
m_pendingPushNotifications.insert(id, action.id());
return Device::DeviceErrorAsync;
qCDebug(dcCloud()) << "executeAction" << info->device() << info->action().id() << info->action().params();
QString userId = info->device()->paramValue(cloudNotificationsDeviceClassUserParamId).toString();
QString endpointId = info->device()->paramValue(cloudNotificationsDeviceClassEndpointParamId).toString();
int id = m_awsConnector->sendPushNotification(userId, endpointId, info->action().param(notifyActionParamTitleId).value().toString(), info->action().param(notifyActionParamBodyId).value().toString());
m_pendingPushNotifications.insert(id, info);
}
void CloudNotifications::pushNotificationEndpointsUpdated(const QList<AWSConnector::PushNotificationsEndpoint> &endpoints)
@ -184,7 +186,7 @@ void CloudNotifications::pushNotificationEndpointsUpdated(const QList<AWSConnect
emit autoDeviceDisappeared(d->id());
}
QList<DeviceDescriptor> devicesToAdd;
DeviceDescriptors devicesToAdd;
foreach (const AWSConnector::PushNotificationsEndpoint &ep, endpoints) {
bool found = false;
qCDebug(dcCloud) << "Checking endoint:" << ep.endpointId;
@ -208,7 +210,7 @@ void CloudNotifications::pushNotificationEndpointsUpdated(const QList<AWSConnect
devicesToAdd.append(descriptor);
}
}
emit autoDevicesAppeared(cloudNotificationsDeviceClassId, devicesToAdd);
emit autoDevicesAppeared(devicesToAdd);
}
@ -229,12 +231,16 @@ void CloudNotifications::pushNotificationEndpointAdded(const AWSConnector::PushN
Param endpointIdParam(cloudNotificationsDeviceClassEndpointParamId, endpoint.endpointId);
params.append(endpointIdParam);
descriptor.setParams(params);
emit autoDevicesAppeared(cloudNotificationsDeviceClassId, {descriptor});
emit autoDevicesAppeared({descriptor});
}
void CloudNotifications::pushNotificationSent(int id, int status)
{
qCDebug(dcCloud()) << "Push notification sent" << id << status;
ActionId actionId = m_pendingPushNotifications.value(id);
emit actionExecutionFinished(actionId, status == 200 ? Device::DeviceErrorNoError : Device::DeviceErrorHardwareNotAvailable);
DeviceActionInfo *info = m_pendingPushNotifications.take(id);
if (!info) {
qCWarning(dcCloud()) << "Received a push notification send reponse for a request we're not waiting for.";
return;
}
info->finish(status == 200 ? Device::DeviceErrorNoError : Device::DeviceErrorHardwareNotAvailable);
}

View File

@ -36,9 +36,9 @@ public:
PluginMetadata metaData() const;
Device::DeviceSetupStatus setupDevice(Device *device) override;
void setupDevice(DeviceSetupInfo *info) override;
void startMonitoringAutoDevices() override;
Device::DeviceError executeAction(Device *device, const Action &action) override;
void executeAction(DeviceActionInfo *info) override;
private slots:
void pushNotificationEndpointsUpdated(const QList<AWSConnector::PushNotificationsEndpoint> &endpoints);
@ -47,7 +47,7 @@ private slots:
private:
AWSConnector *m_awsConnector = nullptr;
QHash<int, ActionId> m_pendingPushNotifications;
QHash<int, DeviceActionInfo*> m_pendingPushNotifications;
};
#endif // CLOUDNOTIFICATIONS_H

File diff suppressed because it is too large Load Diff

View File

@ -60,13 +60,14 @@ class DeviceManagerImplementation: public DeviceManager
public:
explicit DeviceManagerImplementation(HardwareManager *hardwareManager, const QLocale &locale, QObject *parent = nullptr);
~DeviceManagerImplementation();
~DeviceManagerImplementation() override;
static QStringList pluginSearchDirs();
static QList<QJsonObject> pluginsMetadata();
void registerStaticPlugin(DevicePlugin* plugin, const PluginMetadata &metaData);
DevicePlugins plugins() const override;
DevicePlugin *plugin(const PluginId &pluginId) const override;
Device::DeviceError setPluginConfig(const PluginId &pluginId, const ParamList &pluginConfig) override;
Vendors supportedVendors() const override;
@ -80,29 +81,29 @@ public:
Devices findChildDevices(const DeviceId &id) const override;
DeviceClass findDeviceClass(const DeviceClassId &deviceClassId) const override;
Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
DeviceDiscoveryInfo* discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
Device::DeviceError addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id = DeviceId::createDeviceId()) override;
Device::DeviceError 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 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;
Device::DeviceError reconfigureDevice(const DeviceId &deviceId, const ParamList &params, bool fromDiscoveryOrAuto = false) override;
Device::DeviceError reconfigureDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId) override;
DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const ParamList &params, bool fromDiscoveryOrAuto = false) override;
DeviceSetupInfo* reconfigureDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId) override;
Device::DeviceError editDevice(const DeviceId &deviceId, const QString &name) override;
Device::DeviceError setDeviceSettings(const DeviceId &deviceId, const ParamList &settings) override;
Device::DeviceError pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const QString &name, const ParamList &params) override;
Device::DeviceError pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId) override;
Device::DeviceError confirmPairing(const PairingTransactionId &pairingTransactionId, const QString &secret = QString()) 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;
Device::DeviceError executeAction(const Action &action) override;
DeviceActionInfo* executeAction(const Action &action) override;
Device::BrowseResult browseDevice(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) override;
Device::BrowserItemResult browserItemDetails(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) override;
Device::DeviceError executeBrowserItem(const BrowserAction &browserAction) override;
Device::DeviceError executeBrowserItemAction(const BrowserItemAction &browserItemAction) override;
BrowseResult* browseDevice(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) override;
BrowserItemResult* browserItemDetails(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) override;
BrowserActionInfo *executeBrowserItem(const BrowserAction &browserAction) override;
BrowserItemActionInfo *executeBrowserItemAction(const BrowserItemAction &browserItemAction) override;
QString translate(const PluginId &pluginId, const QString &string, const QLocale &locale) override;
@ -118,10 +119,7 @@ private slots:
void loadConfiguredDevices();
void storeConfiguredDevices();
void startMonitoringAutoDevices();
void slotDevicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
void slotDeviceSetupFinished(Device *device, Device::DeviceSetupStatus status);
void slotPairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceSetupStatus status);
void onAutoDevicesAppeared(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors);
void onAutoDevicesAppeared(const DeviceDescriptors &deviceDescriptors);
void onAutoDeviceDisappeared(const DeviceId &deviceId);
void onLoaded();
void cleanupDeviceStateCache();
@ -132,8 +130,9 @@ private slots:
void slotDeviceSettingChanged(const ParamTypeId &paramTypeId, const QVariant &value);
private:
Device::DeviceError addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id = DeviceId::createDeviceId(), const DeviceId &parentDeviceId = DeviceId());
Device::DeviceSetupStatus setupDevice(Device *device);
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 *setupDevice(Device *device);
void postSetupDevice(Device *device);
void storeDeviceStates(Device *device);
void loadDeviceStates(Device *device);
@ -148,15 +147,19 @@ private:
QHash<VendorId, QList<DeviceClassId> > m_vendorDeviceMap;
QHash<DeviceClassId, DeviceClass> m_supportedDevices;
QHash<DeviceId, Device*> m_configuredDevices;
QHash<DeviceDescriptorId, DeviceDescriptor> m_discoveredDevices;
QHash<DeviceClassId, QHash<DeviceDescriptorId, DeviceDescriptor> > m_discoveredDevices;
QHash<PluginId, DevicePlugin*> m_devicePlugins;
QHash<QUuid, DevicePairingInfo> m_pairingsJustAdd;
QHash<QUuid, DevicePairingInfo> m_pairingsDiscovery;
QList<Device *> m_asyncDeviceReconfiguration;
QList<DevicePlugin *> m_discoveringPlugins;
class PairingContext {
public:
DeviceId deviceId;
DeviceClassId deviceClassId;
DeviceId parentDeviceId;
ParamList params;
QString deviceName;
};
QHash<PairingTransactionId, PairingContext> m_pendingPairings;
};
#endif // DEVICEMANAGERIMPLEMENTATION_H

View File

@ -36,6 +36,9 @@
#include "nymeacore.h"
#include "devices/devicemanager.h"
#include "devices/deviceactioninfo.h"
#include "devices/browseractioninfo.h"
#include "devices/browseritemactioninfo.h"
#include "types/action.h"
#include "loggingcategories.h"
@ -52,6 +55,7 @@ ActionHandler::ActionHandler(QObject *parent) :
setDescription("ExecuteAction", "Execute a single action.");
setParams("ExecuteAction", JsonTypes::actionDescription());
returns.insert("deviceError", JsonTypes::deviceErrorRef());
returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String));
setReturns("ExecuteAction", returns);
params.clear(); returns.clear();
@ -80,9 +84,6 @@ ActionHandler::ActionHandler(QObject *parent) :
returns.insert("deviceError", JsonTypes::deviceErrorRef());
setReturns("ExecuteBrowserItemAction", returns);
connect(NymeaCore::instance(), &NymeaCore::actionExecuted, this, &ActionHandler::actionExecuted);
connect(NymeaCore::instance(), &NymeaCore::browserItemExecuted, this, &ActionHandler::browserItemExecuted);
connect(NymeaCore::instance(), &NymeaCore::browserItemActionExecuted, this, &ActionHandler::browserItemActionExecuted);
}
/*! Returns the name of the \l{ActionHandler}. In this case \b Actions.*/
@ -96,20 +97,24 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap &params)
DeviceId deviceId(params.value("deviceId").toString());
ActionTypeId actionTypeId(params.value("actionTypeId").toString());
ParamList actionParams = JsonTypes::unpackParams(params.value("params").toList());
QLocale locale = params.value("locale").toLocale();
Action action(actionTypeId, deviceId);
action.setParams(actionParams);
Device::DeviceError status = NymeaCore::instance()->executeAction(action);
if (status == Device::DeviceErrorAsync) {
JsonReply *reply = createAsyncReply("ExecuteAction");
ActionId id = action.id();
connect(reply, &JsonReply::finished, [this, id](){ m_asyncActionExecutions.remove(id); });
m_asyncActionExecutions.insert(id, reply);
return reply;
}
JsonReply *jsonReply = createAsyncReply("ExecuteAction");
return createReply(statusToReply(status));
DeviceActionInfo *info = NymeaCore::instance()->executeAction(action);
connect(info, &DeviceActionInfo::finished, jsonReply, [this, info, jsonReply, locale](){
QVariantMap data = statusToReply(info->status());
if (!info->displayMessage().isEmpty()) {
data.insert("displayMessage", info->translatedDisplayMessage(locale));
}
jsonReply->setData(data);
jsonReply->finished();
});
return jsonReply;
}
JsonReply *ActionHandler::GetActionType(const QVariantMap &params) const
@ -128,31 +133,21 @@ JsonReply *ActionHandler::GetActionType(const QVariantMap &params) const
return createReply(statusToReply(Device::DeviceErrorActionTypeNotFound));
}
void ActionHandler::actionExecuted(const ActionId &id, Device::DeviceError status)
{
if (!m_asyncActionExecutions.contains(id)) {
return; // Not the action we are waiting for.
}
JsonReply *reply = m_asyncActionExecutions.take(id);
reply->setData(statusToReply(status));
reply->finished();
}
JsonReply *ActionHandler::ExecuteBrowserItem(const QVariantMap &params)
{
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
QString itemId = params.value("itemId").toString();
BrowserAction action(deviceId, itemId);
Device::DeviceError status = NymeaCore::instance()->executeBrowserItem(action);
if (status == Device::DeviceErrorAsync) {
JsonReply *reply = createAsyncReply("ExecuteBrowserItem");
ActionId id = action.id();
connect(reply, &JsonReply::finished, [this, id](){ m_asyncActionExecutions.remove(id); });
m_asyncActionExecutions.insert(id, reply);
return reply;
}
return createReply(statusToReply(status));
JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItem");
BrowserActionInfo *info = NymeaCore::instance()->executeBrowserItem(action);
connect(info, &BrowserActionInfo::finished, jsonReply, [this, info, jsonReply](){
jsonReply->setData(statusToReply(info->status()));
jsonReply->finished();
});
return jsonReply;
}
JsonReply *ActionHandler::ExecuteBrowserItemAction(const QVariantMap &params)
@ -162,39 +157,16 @@ JsonReply *ActionHandler::ExecuteBrowserItemAction(const QVariantMap &params)
ActionTypeId actionTypeId = ActionTypeId(params.value("actionTypeId").toString());
ParamList paramList = JsonTypes::unpackParams(params.value("params").toList());
BrowserItemAction browserItemAction(deviceId, itemId, actionTypeId, paramList);
Device::DeviceError status = NymeaCore::instance()->executeBrowserItemAction(browserItemAction);
if (status == Device::DeviceErrorAsync) {
JsonReply *reply = createAsyncReply("ExecuteBrowserItemAction");
ActionId id = browserItemAction.id();
connect(reply, &JsonReply::finished, [this, id](){ m_asyncActionExecutions.remove(id); });
m_asyncActionExecutions.insert(id, reply);
return reply;
}
return createReply(statusToReply(status));
JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItemAction");
BrowserItemActionInfo *info = NymeaCore::instance()->executeBrowserItemAction(browserItemAction);
connect(info, &BrowserItemActionInfo::finished, jsonReply, [this, info, jsonReply](){
jsonReply->setData(statusToReply(info->status()));
jsonReply->finished();
});
return jsonReply;
}
void ActionHandler::browserItemExecuted(const ActionId &id, Device::DeviceError status)
{
if (!m_asyncActionExecutions.contains(id)) {
return; // Not the action we are waiting for.
}
JsonReply *reply = m_asyncActionExecutions.take(id);
reply->setData(statusToReply(status));
reply->finished();
}
void ActionHandler::browserItemActionExecuted(const ActionId &id, Device::DeviceError status)
{
if (!m_asyncActionExecutions.contains(id)) {
return; // Not the action we are waiting for.
}
JsonReply *reply = m_asyncActionExecutions.take(id);
reply->setData(statusToReply(status));
reply->finished();
}
}

View File

@ -41,13 +41,6 @@ public:
Q_INVOKABLE JsonReply *ExecuteBrowserItem(const QVariantMap &params);
Q_INVOKABLE JsonReply *ExecuteBrowserItemAction(const QVariantMap &params);
private slots:
void actionExecuted(const ActionId &id, Device::DeviceError status);
void browserItemExecuted(const ActionId &id, Device::DeviceError status);
void browserItemActionExecuted(const ActionId &id, Device::DeviceError status);
private:
QHash<ActionId, JsonReply *> m_asyncActionExecutions;
};
}

View File

@ -61,6 +61,11 @@
#include "loggingcategories.h"
#include "types/deviceclass.h"
#include "devices/translator.h"
#include "devices/devicediscoveryinfo.h"
#include "devices/devicepairinginfo.h"
#include "devices/devicesetupinfo.h"
#include "devices/browseresult.h"
#include "devices/browseritemresult.h"
#include <QDebug>
@ -133,6 +138,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
setParams("AddConfiguredDevice", params);
returns.insert("deviceError", JsonTypes::deviceErrorRef());
returns.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String));
setReturns("AddConfiguredDevice", returns);
returns.clear(); // Reused params from above!
@ -147,17 +153,22 @@ DeviceHandler::DeviceHandler(QObject *parent) :
);
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:setupMethod", JsonTypes::setupMethodRef());
returns.insert("o:oAuthUrl", JsonTypes::basicTypeToString(JsonTypes::String));
setReturns("PairDevice", returns);
params.clear(); returns.clear();
setDescription("ConfirmPairing", "Confirm an ongoing pairing. In case of SetupMethodEnterPin also provide the pin in the params.");
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.");
params.insert("pairingTransactionId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
params.insert("o:username", JsonTypes::basicTypeToString(JsonTypes::String));
params.insert("o:secret", JsonTypes::basicTypeToString(JsonTypes::String));
setParams("ConfirmPairing", params);
returns.insert("deviceError", JsonTypes::deviceErrorRef());
returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String));
returns.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
setReturns("ConfirmPairing", returns);
@ -182,6 +193,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
params.insert("o:discoveryParams", discoveryParams);
setParams("GetDiscoveredDevices", params);
returns.insert("deviceError", JsonTypes::deviceErrorRef());
returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String));
QVariantList deviceDescriptors;
deviceDescriptors.append(JsonTypes::deviceDescriptorRef());
returns.insert("o:deviceDescriptors", deviceDescriptors);
@ -200,6 +212,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
params.insert("o:deviceParams", newDeviceParams);
setParams("ReconfigureDevice", params);
returns.insert("deviceError", JsonTypes::deviceErrorRef());
returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String));
setReturns("ReconfigureDevice", returns);
params.clear(); returns.clear();
@ -343,12 +356,6 @@ DeviceHandler::DeviceHandler(QObject *parent) :
connect(NymeaCore::instance(), &NymeaCore::deviceAdded, this, &DeviceHandler::deviceAddedNotification);
connect(NymeaCore::instance(), &NymeaCore::deviceChanged, this, &DeviceHandler::deviceChangedNotification);
connect(NymeaCore::instance(), &NymeaCore::deviceSettingChanged, this, &DeviceHandler::deviceSettingChangedNotification);
connect(NymeaCore::instance(), &NymeaCore::devicesDiscovered, this, &DeviceHandler::devicesDiscovered, Qt::QueuedConnection);
connect(NymeaCore::instance(), &NymeaCore::deviceSetupFinished, this, &DeviceHandler::deviceSetupFinished);
connect(NymeaCore::instance(), &NymeaCore::deviceReconfigurationFinished, this, &DeviceHandler::deviceReconfigurationFinished);
connect(NymeaCore::instance(), &NymeaCore::pairingFinished, this, &DeviceHandler::pairingFinished);
connect(NymeaCore::instance()->deviceManager(), &DeviceManager::browseRequestFinished, this, &DeviceHandler::browseRequestFinished);
connect(NymeaCore::instance()->deviceManager(), &DeviceManager::browserItemRequestFinished, this, &DeviceHandler::browserItemRequestFinished);
}
/*! Returns the name of the \l{DeviceHandler}. In this case \b Devices.*/
@ -375,21 +382,33 @@ JsonReply* DeviceHandler::GetSupportedDevices(const QVariantMap &params) const
JsonReply *DeviceHandler::GetDiscoveredDevices(const QVariantMap &params) const
{
QLocale locale = params.value("locale").toLocale();
QVariantMap returns;
DeviceClassId deviceClassId = DeviceClassId(params.value("deviceClassId").toString());
ParamList discoveryParams = JsonTypes::unpackParams(params.value("discoveryParams").toList());
Device::DeviceError status = NymeaCore::instance()->deviceManager()->discoverDevices(deviceClassId, discoveryParams);
if (status == Device::DeviceErrorAsync ) {
JsonReply *reply = createAsyncReply("GetDiscoveredDevices");
connect(reply, &JsonReply::finished, this, [this, deviceClassId](){ m_discoverRequests.remove(deviceClassId); });
m_discoverRequests.insert(deviceClassId, reply);
return reply;
}
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
return createReply(returns);
JsonReply *reply = createAsyncReply("GetDiscoveredDevices");
DeviceDiscoveryInfo *info = NymeaCore::instance()->deviceManager()->discoverDevices(deviceClassId, discoveryParams);
connect(info, &DeviceDiscoveryInfo::finished, reply, [reply, info, locale](){
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status()));
if (info->status() == Device::DeviceErrorNoError) {
returns.insert("deviceDescriptors", JsonTypes::packDeviceDescriptors(info->deviceDescriptors()));
}
if (!info->displayMessage().isEmpty()) {
returns.insert("displayMessage", info->translatedDisplayMessage(locale));
}
reply->setData(returns);
reply->finished();
});
return reply;
}
JsonReply* DeviceHandler::GetPlugins(const QVariantMap &params) const
@ -437,28 +456,32 @@ JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
DeviceId newDeviceId = DeviceId::createDeviceId();
Device::DeviceError status;
QLocale locale = params.value("locale").toLocale();
JsonReply *jsonReply = createAsyncReply("AddConfiguredDevice");
DeviceSetupInfo *info;
if (deviceDescriptorId.isNull()) {
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceName, deviceParams, newDeviceId);
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceName, deviceParams, newDeviceId);
} else {
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceName, deviceDescriptorId, deviceParams, newDeviceId);
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceName, deviceDescriptorId, deviceParams, newDeviceId);
}
QVariantMap returns;
switch (status) {
case Device::DeviceErrorAsync: {
JsonReply *asyncReply = createAsyncReply("AddConfiguredDevice");
connect(asyncReply, &JsonReply::finished, [this, newDeviceId](){ m_asynDeviceAdditions.remove(newDeviceId); });
m_asynDeviceAdditions.insert(newDeviceId, asyncReply);
return asyncReply;
}
case Device::DeviceErrorNoError:
returns.insert("deviceId", newDeviceId);
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
break;
default:
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
}
return createReply(returns);
connect(info, &DeviceSetupInfo::finished, jsonReply, [info, jsonReply, locale](){
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status()));
if (!info->displayMessage().isEmpty()) {
returns.insert("displayMessage", info->translatedDisplayMessage(locale));
}
if(info->status() == Device::DeviceErrorNoError) {
returns.insert("deviceId", info->device()->id());
}
jsonReply->setData(returns);
jsonReply->finished();
});
return jsonReply;
}
JsonReply *DeviceHandler::PairDevice(const QVariantMap &params)
@ -466,44 +489,68 @@ 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);
QLocale locale = params.value("locale").toLocale();
Device::DeviceError status;
PairingTransactionId pairingTransactionId = PairingTransactionId::createPairingTransactionId();
DevicePairingInfo *info;
if (params.contains("deviceDescriptorId")) {
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
status = NymeaCore::instance()->deviceManager()->pairDevice(pairingTransactionId, deviceClassId, deviceName, deviceDescriptorId);
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceDescriptorId);
} else {
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
status = NymeaCore::instance()->deviceManager()->pairDevice(pairingTransactionId, deviceClassId, deviceName, deviceParams);
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceParams);
}
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
if (status == Device::DeviceErrorNoError) {
returns.insert("displayMessage", NymeaCore::instance()->deviceManager()->translate(deviceClass.pluginId(), deviceClass.pairingInfo(), params.value("locale").toLocale()));
returns.insert("pairingTransactionId", pairingTransactionId.toString());
returns.insert("setupMethod", JsonTypes::setupMethod().at(deviceClass.setupMethod()));
}
return createReply(returns);
JsonReply *jsonReply = createAsyncReply("PairDevice");
connect(info, &DevicePairingInfo::finished, jsonReply, [jsonReply, info, locale, deviceClass](){
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status()));
returns.insert("pairingTransactionId", info->transactionId().toString());
if (info->status() == Device::DeviceErrorNoError) {
returns.insert("setupMethod", JsonTypes::setupMethodToString(deviceClass.setupMethod()));
}
if (!info->displayMessage().isEmpty()) {
returns.insert("displayMessage", info->translatedDisplayMessage(locale));
}
if (!info->oAuthUrl().isEmpty()) {
returns.insert("oAuthUrl", info->oAuthUrl());
}
jsonReply->setData(returns);
jsonReply->finished();
});
return jsonReply;
}
JsonReply *DeviceHandler::ConfirmPairing(const QVariantMap &params)
{
PairingTransactionId pairingTransactionId = PairingTransactionId(params.value("pairingTransactionId").toString());
QString secret = params.value("secret").toString();
Device::DeviceError status = NymeaCore::instance()->deviceManager()->confirmPairing(pairingTransactionId, secret);
QString username = params.value("username").toString();
QLocale locale = params.value("locale").toLocale();
JsonReply *reply = nullptr;
if (status == Device::DeviceErrorAsync) {
reply = createAsyncReply("ConfirmPairing");
connect(reply, &JsonReply::finished, [this, pairingTransactionId](){ m_asyncPairingRequests.remove(pairingTransactionId); });
m_asyncPairingRequests.insert(pairingTransactionId, reply);
return reply;
}
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
reply = createReply(returns);
return reply;
JsonReply *jsonReply = createAsyncReply("ConfirmPairing");
DevicePairingInfo *info = NymeaCore::instance()->deviceManager()->confirmPairing(pairingTransactionId, username, secret);
connect(info, &DevicePairingInfo::finished, jsonReply, [info, jsonReply, locale](){
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status()));
if (!info->displayMessage().isEmpty()) {
returns.insert("displayMessage", info->translatedDisplayMessage(locale));
}
if (info->status() == Device::DeviceErrorNoError) {
returns.insert("deviceId", info->deviceId().toString());
}
jsonReply->setData(returns);
jsonReply->finished();
});
return jsonReply;
}
JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
@ -529,28 +576,30 @@ JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
JsonReply *DeviceHandler::ReconfigureDevice(const QVariantMap &params)
{
Q_UNUSED(params);
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
Device::DeviceError status;
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
QLocale locale = params.value("locale").toLocale();
JsonReply *jsonReply = createAsyncReply("ReconfigureDevice");
DeviceSetupInfo *info;
if (deviceDescriptorId.isNull()) {
status = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceId, deviceParams);
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceId, deviceParams);
} else {
status = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceId, deviceDescriptorId);
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(deviceId, deviceDescriptorId);
}
if (status == Device::DeviceErrorAsync) {
JsonReply *asyncReply = createAsyncReply("ReconfigureDevice");
connect(asyncReply, &JsonReply::finished, [this, deviceId](){ m_asynDeviceEditAdditions.remove(deviceId); });
m_asynDeviceEditAdditions.insert(deviceId, asyncReply);
return asyncReply;
}
connect(info, &DeviceSetupInfo::finished, jsonReply, [info, jsonReply, locale](){
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
return createReply(returns);
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status()));
returns.insert("displayMessage", info->translatedDisplayMessage(locale));
jsonReply->setData(returns);
jsonReply->finished();
});
return jsonReply;
}
JsonReply *DeviceHandler::EditDevice(const QVariantMap &params)
@ -687,24 +736,22 @@ JsonReply *DeviceHandler::GetStateValues(const QVariantMap &params) const
JsonReply *DeviceHandler::BrowseDevice(const QVariantMap &params) const
{
QVariantMap returns;
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
QString itemId = params.value("itemId").toString();
Device::BrowseResult result = NymeaCore::instance()->deviceManager()->browseDevice(deviceId, itemId, params.value("locale").toLocale());
JsonReply *jsonReply = createAsyncReply("BrowseDevice");
if (result.status == Device::DeviceErrorAsync ) {
JsonReply *reply = createAsyncReply("BrowseDevice");
m_asyncBrowseRequests.insert(result.id(), reply);
connect(reply, &JsonReply::finished, this, [this, result](){
m_asyncBrowseRequests.remove(result.id());
});
return reply;
}
BrowseResult *result = NymeaCore::instance()->deviceManager()->browseDevice(deviceId, itemId, params.value("locale").toLocale());
connect(result, &BrowseResult::finished, jsonReply, [jsonReply, result](){
returns.insert("deviceError", JsonTypes::deviceErrorToString(result.status));
returns.insert("items", JsonTypes::packBrowserItems(result.items));
return createReply(returns);
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(result->status()));
returns.insert("items", JsonTypes::packBrowserItems(result->items()));
jsonReply->setData(returns);
jsonReply->finished();
});
return jsonReply;
}
JsonReply *DeviceHandler::GetBrowserItem(const QVariantMap &params) const
@ -713,22 +760,20 @@ JsonReply *DeviceHandler::GetBrowserItem(const QVariantMap &params) const
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
QString itemId = params.value("itemId").toString();
Device::BrowserItemResult result = NymeaCore::instance()->deviceManager()->browserItemDetails(deviceId, itemId, params.value("locale").toLocale());
JsonReply *jsonReply = createAsyncReply("GetBrowserItem");
if (result.status == Device::DeviceErrorAsync ) {
JsonReply *reply = createAsyncReply("GetBrowserItem");
m_asyncBrowseDetailsRequests.insert(result.id(), reply);
connect(reply, &JsonReply::finished, this, [this, result](){
m_asyncBrowseDetailsRequests.remove(result.id());
});
return reply;
}
BrowserItemResult *result = NymeaCore::instance()->deviceManager()->browserItemDetails(deviceId, itemId, params.value("locale").toLocale());
connect(result, &BrowserItemResult::finished, jsonReply, [jsonReply, result](){
QVariantMap params;
if (result->status() == Device::DeviceErrorNoError) {
params.insert("item", JsonTypes::packBrowserItem(result->item()));
}
params.insert("deviceError", JsonTypes::deviceErrorToString(result->status()));
jsonReply->setData(params);
jsonReply->finished();
});
returns.insert("deviceError", JsonTypes::deviceErrorToString(result.status));
if (result.status == Device::DeviceErrorNoError) {
returns.insert("item", JsonTypes::packBrowserItem(result.item));
}
return createReply(returns);
return jsonReply;
}
void DeviceHandler::pluginConfigChanged(const PluginId &id, const ParamList &config)
@ -786,105 +831,4 @@ void DeviceHandler::deviceSettingChangedNotification(const DeviceId deviceId, co
emit DeviceSettingChanged(params);
}
void DeviceHandler::devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors)
{
if (!m_discoverRequests.contains(deviceClassId)) {
return; // We didn't start this discovery... Ignore it.
}
JsonReply *reply = nullptr;
reply = m_discoverRequests.take(deviceClassId);
if (!reply)
return;
QVariantMap returns;
returns.insert("deviceDescriptors", JsonTypes::packDeviceDescriptors(deviceDescriptors));
returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorNoError));
reply->setData(returns);
reply->finished();
}
void DeviceHandler::deviceSetupFinished(Device *device, Device::DeviceError status)
{
qCDebug(dcJsonRpc) << "Got a device setup finished" << device->name() << device->id();
if (!m_asynDeviceAdditions.contains(device->id())) {
return; // Not the device we're waiting for...
}
JsonReply *reply = m_asynDeviceAdditions.take(device->id());
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
if(status == Device::DeviceErrorNoError) {
returns.insert("deviceId", device->id());
}
reply->setData(returns);
reply->finished();
}
void DeviceHandler::deviceReconfigurationFinished(Device *device, Device::DeviceError status)
{
qCDebug(dcJsonRpc) << "Got async device reconfiguration finished";
if (!m_asynDeviceEditAdditions.contains(device->id())) {
return;
}
JsonReply *reply = m_asynDeviceEditAdditions.take(device->id());
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
reply->setData(returns);
reply->finished();
}
void DeviceHandler::pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceError status, const DeviceId &deviceId)
{
qCDebug(dcJsonRpc) << "Got pairing finished";
JsonReply *reply = m_asyncPairingRequests.take(pairingTransactionId);
if (!reply) {
return;
}
if (status != Device::DeviceErrorNoError) {
QVariantMap returns;
returns.insert("deviceError", JsonTypes::deviceErrorToString(status));
reply->setData(returns);
reply->finished();
return;
}
m_asynDeviceAdditions.insert(deviceId, reply);
}
void DeviceHandler::browseRequestFinished(const Device::BrowseResult &result)
{
if (!m_asyncBrowseRequests.contains(result.id())) {
qCWarning(dcJsonRpc()) << "No pending JsonRpc reply. Did it time out?";
return;
}
JsonReply *reply = m_asyncBrowseRequests.take(result.id());
QVariantMap params;
params.insert("items", JsonTypes::packBrowserItems(result.items));
params.insert("deviceError", JsonTypes::deviceErrorToString(result.status));
reply->setData(params);
reply->finished();
}
void DeviceHandler::browserItemRequestFinished(const Device::BrowserItemResult &result)
{
if (!m_asyncBrowseDetailsRequests.contains(result.id())) {
qCWarning(dcJsonRpc()) << "No pending JsonRpc reply for result" << result.id() << ". Did it time out?";
return;
}
JsonReply *reply = m_asyncBrowseDetailsRequests.take(result.id());
QVariantMap params;
if (result.status == Device::DeviceErrorNoError) {
params.insert("item", JsonTypes::packBrowserItem(result.item));
}
params.insert("deviceError", JsonTypes::deviceErrorToString(result.status));
reply->setData(params);
reply->finished();
}
}

View File

@ -80,27 +80,6 @@ private slots:
void deviceChangedNotification(Device *device);
void deviceSettingChangedNotification(const DeviceId deviceId, const ParamTypeId &paramTypeId, const QVariant &value);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
void deviceSetupFinished(Device *device, Device::DeviceError status);
void deviceReconfigurationFinished(Device *device, Device::DeviceError status);
void pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceError status, const DeviceId &deviceId);
void browseRequestFinished(const Device::BrowseResult &result);
void browserItemRequestFinished(const Device::BrowserItemResult &result);
private:
// A cache for async replies
mutable QHash<DeviceClassId, JsonReply*> m_discoverRequests;
mutable QHash<DeviceId, JsonReply*> m_asynDeviceAdditions;
mutable QHash<DeviceId, JsonReply*> m_asynDeviceEditAdditions;
mutable QHash<QUuid, JsonReply*> m_asyncPairingRequests;
mutable QHash<QUuid, JsonReply*> m_asyncBrowseRequests;
mutable QHash<QUuid, JsonReply*> m_asyncBrowseDetailsRequests;
};
}

View File

@ -55,22 +55,6 @@
The \a status of the \l{Action} execution will be described as \l{Device::DeviceError}{DeviceError}.
*/
/*! \fn void nymeaserver::NymeaCore::devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
This signal is emitted when the discovery of a \a deviceClassId is finished. The \a deviceDescriptors parameter describes the
list of \l{DeviceDescriptor}{DeviceDescriptors} of all discovered \l{Device}{Devices}.
\sa DeviceManager::discoverDevices()
*/
/*! \fn void nymeaserver::NymeaCore::deviceSetupFinished(Device *device, Device::DeviceError status);
This signal is emitted when the setup of a \a device is finished. The \a status parameter describes the
\l{Device::DeviceError}{DeviceError} that occurred.
*/
/*! \fn void nymeaserver::NymeaCore::deviceReconfigurationFinished(Device *device, Device::DeviceError status);
This signal is emitted when the edit request of a \a device is finished. The \a status of the edit request will be
described as \l{Device::DeviceError}{DeviceError}.
*/
/*! \fn void nymeaserver::NymeaCore::pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceError status, const DeviceId &deviceId);
The DeviceManager will emit a this Signal when the pairing of a \l{Device} with the \a deviceId and \a pairingTransactionId is finished.
The \a status of the pairing will be described as \l{Device::DeviceError}{DeviceError}.
@ -116,6 +100,9 @@
#include "devices/devicemanagerimplementation.h"
#include "devices/device.h"
#include "devices/deviceactioninfo.h"
#include "devices/browseractioninfo.h"
#include "devices/browseritemactioninfo.h"
#include "cloud/cloudnotifications.h"
#include "cloud/cloudtransport.h"
@ -200,13 +187,6 @@ void NymeaCore::init() {
connect(m_deviceManager, &DeviceManagerImplementation::deviceSettingChanged, this, &NymeaCore::deviceSettingChanged);
connect(m_deviceManager, &DeviceManagerImplementation::deviceRemoved, this, &NymeaCore::deviceRemoved);
connect(m_deviceManager, &DeviceManagerImplementation::deviceDisappeared, this, &NymeaCore::onDeviceDisappeared);
connect(m_deviceManager, &DeviceManagerImplementation::actionExecutionFinished, this, &NymeaCore::actionExecutionFinished);
connect(m_deviceManager, &DeviceManagerImplementation::browserItemExecutionFinished, this, &NymeaCore::browserItemExecutionFinished);
connect(m_deviceManager, &DeviceManagerImplementation::browserItemActionExecutionFinished, this, &NymeaCore::browserItemActionExecutionFinished);
connect(m_deviceManager, &DeviceManagerImplementation::devicesDiscovered, this, &NymeaCore::devicesDiscovered);
connect(m_deviceManager, &DeviceManagerImplementation::deviceSetupFinished, this, &NymeaCore::deviceSetupFinished);
connect(m_deviceManager, &DeviceManagerImplementation::deviceReconfigurationFinished, this, &NymeaCore::deviceReconfigurationFinished);
connect(m_deviceManager, &DeviceManagerImplementation::pairingFinished, this, &NymeaCore::pairingFinished);
connect(m_deviceManager, &DeviceManagerImplementation::loaded, this, &NymeaCore::deviceManagerLoaded);
connect(m_ruleEngine, &RuleEngine::ruleAdded, this, &NymeaCore::ruleAdded);
@ -436,43 +416,36 @@ Device::DeviceError NymeaCore::removeConfiguredDevice(const DeviceId &deviceId,
/*! Calls the metheod DeviceManager::executeAction(\a action).
* \sa DeviceManager::executeAction(), */
Device::DeviceError NymeaCore::executeAction(const Action &action)
DeviceActionInfo* NymeaCore::executeAction(const Action &action)
{
Device::DeviceError ret = m_deviceManager->executeAction(action);
if (ret == Device::DeviceErrorNoError) {
m_logger->logAction(action);
} else if (ret == Device::DeviceErrorAsync) {
m_pendingActions.insert(action.id(), action);
} else {
m_logger->logAction(action, Logging::LoggingLevelAlert, ret);
}
return ret;
DeviceActionInfo *info = m_deviceManager->executeAction(action);
connect(info, &DeviceActionInfo::finished, this, [this, info](){
if (info->status() == Device::DeviceErrorNoError) {
m_logger->logAction(info->action());
} else {
m_logger->logAction(info->action(), Logging::LoggingLevelAlert, info->status());
}
});
return info;
}
Device::DeviceError NymeaCore::executeBrowserItem(const BrowserAction &browserAction)
BrowserActionInfo* NymeaCore::executeBrowserItem(const BrowserAction &browserAction)
{
Device::DeviceError ret = m_deviceManager->executeBrowserItem(browserAction);
if (ret == Device::DeviceErrorNoError) {
m_logger->logBrowserAction(browserAction);
} else if (ret == Device::DeviceErrorAsync) {
m_pendingBrowserActions.insert(browserAction.id(), browserAction);
} else {
m_logger->logBrowserAction(browserAction, Logging::LoggingLevelAlert, ret);
}
return ret;
BrowserActionInfo *info = m_deviceManager->executeBrowserItem(browserAction);
connect(info, &BrowserActionInfo::finished, info->device(), [this, info](){
m_logger->logBrowserAction(info->browserAction(), info->status() == Device::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, info->status());
});
return info;
}
Device::DeviceError NymeaCore::executeBrowserItemAction(const BrowserItemAction &browserItemAction)
BrowserItemActionInfo *NymeaCore::executeBrowserItemAction(const BrowserItemAction &browserItemAction)
{
Device::DeviceError ret = m_deviceManager->executeBrowserItemAction(browserItemAction);
if (ret == Device::DeviceErrorNoError) {
m_logger->logBrowserItemAction(browserItemAction);
} else if (ret == Device::DeviceErrorAsync) {
m_pendingBrowserItemActions.insert(browserItemAction.id(), browserItemAction);
} else {
m_logger->logBrowserItemAction(browserItemAction, Logging::LoggingLevelAlert, ret);
}
return ret;
BrowserItemActionInfo *info = m_deviceManager->executeBrowserItemAction(browserItemAction);
connect(info, &BrowserItemActionInfo::finished, info->device(), [this, info](){
m_logger->logBrowserItemAction(info->browserItemAction(), info->status() == Device::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, info->status());
});
return info;
}
/*! Execute the given \a ruleActions. */
@ -575,44 +548,21 @@ void NymeaCore::executeRuleActions(const QList<RuleAction> ruleActions)
foreach (const Action &action, actions) {
qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params();
Device::DeviceError status = executeAction(action);
switch(status) {
case Device::DeviceErrorNoError:
break;
case Device::DeviceErrorSetupFailed:
qCWarning(dcRuleEngine) << "Error executing action. Device setup failed.";
break;
case Device::DeviceErrorAsync:
qCDebug(dcRuleEngine) << "Executing asynchronous action.";
break;
case Device::DeviceErrorInvalidParameter:
qCWarning(dcRuleEngine) << "Error executing action. Invalid action parameter.";
break;
default:
qCWarning(dcRuleEngine) << "Error executing action:" << status;
}
// if (status != Device::DeviceErrorAsync)
// m_logger->logAction(action, status == Device::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status);
DeviceActionInfo *info = executeAction(action);
connect(info, &DeviceActionInfo::finished, this, [info](){
if (info->status() != Device::DeviceErrorNoError) {
qCWarning(dcRuleEngine) << "Error executing action:" << info->status() << info->displayMessage();
}
});
}
foreach (const BrowserAction &browserAction, browserActions) {
Device::DeviceError status = executeBrowserItem(browserAction);
switch(status) {
case Device::DeviceErrorNoError:
break;
case Device::DeviceErrorSetupFailed:
qCWarning(dcRuleEngine) << "Error executing action. Device setup failed.";
break;
case Device::DeviceErrorAsync:
qCDebug(dcRuleEngine) << "Executing asynchronous action.";
break;
case Device::DeviceErrorInvalidParameter:
qCWarning(dcRuleEngine) << "Error executing action. Invalid action parameter.";
break;
default:
qCWarning(dcRuleEngine) << "Error executing action:" << status;
}
BrowserActionInfo *info = executeBrowserItem(browserAction);
connect(info, &BrowserActionInfo::finished, this, [info](){
if (info->status() != Device::DeviceErrorNoError) {
qCWarning(dcRuleEngine) << "Error executing browser action:" << info->status();
}
});
}
}
@ -850,27 +800,6 @@ RestServer *NymeaCore::restServer() const
return m_serverManager->restServer();
}
void NymeaCore::actionExecutionFinished(const ActionId &id, Device::DeviceError status)
{
emit actionExecuted(id, status);
Action action = m_pendingActions.take(id);
m_logger->logAction(action, status == Device::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status);
}
void NymeaCore::browserItemExecutionFinished(const ActionId &id, Device::DeviceError status)
{
emit browserItemExecuted(id, status);
BrowserAction action = m_pendingBrowserActions.take(id);
m_logger->logBrowserAction(action, status == Device::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status);
}
void NymeaCore::browserItemActionExecutionFinished(const ActionId &id, Device::DeviceError status)
{
emit browserItemActionExecuted(id, status);
BrowserItemAction action = m_pendingBrowserItemActions.take(id);
m_logger->logBrowserItemAction(action, status == Device::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status);
}
void NymeaCore::onDeviceDisappeared(const DeviceId &deviceId)
{
Device *device = m_deviceManager->findConfiguredDevice(deviceId);

View File

@ -71,9 +71,9 @@ public:
QPair<Device::DeviceError, QList<RuleId> >removeConfiguredDevice(const DeviceId &deviceId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList);
Device::DeviceError removeConfiguredDevice(const DeviceId &deviceId, const RuleEngine::RemovePolicy &removePolicy);
Device::DeviceError executeAction(const Action &action);
Device::DeviceError executeBrowserItem(const BrowserAction &browserAction);
Device::DeviceError executeBrowserItemAction(const BrowserItemAction &browserItemAction);
DeviceActionInfo *executeAction(const Action &action);
BrowserActionInfo* executeBrowserItem(const BrowserAction &browserAction);
BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction);
void executeRuleActions(const QList<RuleAction> ruleActions);
@ -107,14 +107,6 @@ signals:
void deviceAdded(Device *device);
void deviceChanged(Device *device);
void deviceSettingChanged(const DeviceId deviceId, const ParamTypeId &settingParamTypeId, const QVariant &value);
void actionExecuted(const ActionId &id, Device::DeviceError status);
void browserItemExecuted(const ActionId &id, Device::DeviceError status);
void browserItemActionExecuted(const ActionId &id, Device::DeviceError status);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
void deviceSetupFinished(Device *device, Device::DeviceError status);
void deviceReconfigurationFinished(Device *device, Device::DeviceError status);
void pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceError status, const DeviceId &deviceId);
void ruleRemoved(const RuleId &ruleId);
void ruleAdded(const Rule &rule);
@ -142,17 +134,11 @@ private:
UserManager *m_userManager;
System *m_system;
QHash<ActionId, Action> m_pendingActions;
QHash<ActionId, BrowserAction> m_pendingBrowserActions;
QHash<ActionId, BrowserItemAction> m_pendingBrowserItemActions;
QList<RuleId> m_executingRules;
private slots:
void gotEvent(const Event &event);
void onDateTimeChanged(const QDateTime &dateTime);
void actionExecutionFinished(const ActionId &id, Device::DeviceError status);
void browserItemExecutionFinished(const ActionId &id, Device::DeviceError status);
void browserItemActionExecutionFinished(const ActionId &id, Device::DeviceError status);
void onDeviceDisappeared(const DeviceId &deviceId);
void deviceManagerLoaded();

View File

@ -38,6 +38,7 @@
#include "deviceclassesresource.h"
#include "servers/httprequest.h"
#include "nymeacore.h"
#include "devices/devicediscoveryinfo.h"
#include <QJsonDocument>
@ -47,7 +48,6 @@ namespace nymeaserver {
DeviceClassesResource::DeviceClassesResource(QObject *parent) :
RestResource(parent)
{
connect(NymeaCore::instance(), &NymeaCore::devicesDiscovered, this, &DeviceClassesResource::devicesDiscovered, Qt::QueuedConnection);
}
/*! Returns the name of the \l{RestResource}. In this case \b deviceclasses.
@ -265,36 +265,24 @@ HttpReply *DeviceClassesResource::getDiscoverdDevices(const ParamList &discovery
qCDebug(dcRest) << "Discover devices for DeviceClass" << m_deviceClass.id();
qCDebug(dcRest) << discoveryParams;
Device::DeviceError status = NymeaCore::instance()->deviceManager()->discoverDevices(m_deviceClass.id(), discoveryParams);
DeviceDiscoveryInfo *info = NymeaCore::instance()->deviceManager()->discoverDevices(m_deviceClass.id(), discoveryParams);
HttpReply *reply = createAsyncReply();
connect(info, &DeviceDiscoveryInfo::finished, reply, [info, reply](){
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
QVariantMap response;
if (info->status() != Device::DeviceErrorNoError) {
reply->setHttpStatusCode(HttpReply::InternalServerError);
response.insert("error", JsonTypes::deviceErrorToString(info->status()));
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
reply->setHttpStatusCode(HttpReply::Ok);
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packDeviceDescriptors(info->deviceDescriptors())).toJson());
}
reply->finished();
});
if (status == Device::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
m_discoverRequests.insert(m_deviceClass.id(), reply);
return reply;
}
if (status != Device::DeviceErrorNoError)
return createDeviceErrorReply(HttpReply::InternalServerError, status);
return createSuccessReply();
}
void DeviceClassesResource::devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors)
{
if (!m_discoverRequests.contains(deviceClassId))
return; // Not the discovery we are waiting for.
qCDebug(dcRest) << "Discovery finished. Found" << deviceDescriptors.count() << "devices.";
if (m_discoverRequests.value(deviceClassId).isNull()) {
qCWarning(dcRest) << "Async reply for discovery does not exist any more (timeout).";
return;
}
HttpReply *reply = m_discoverRequests.take(deviceClassId);
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packDeviceDescriptors(deviceDescriptors)).toJson());
reply->finished();
return reply;
}
HttpReply *DeviceClassesResource::getDeviceClasses(const VendorId &vendorId)

View File

@ -67,9 +67,6 @@ private:
HttpReply *getDiscoverdDevices(const ParamList &discoveryParams);
private slots:
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
};
}

View File

@ -41,6 +41,9 @@
#include "servers/httprequest.h"
#include "jsonrpc/jsontypes.h"
#include "nymeacore.h"
#include "devices/devicesetupinfo.h"
#include "devices/devicepairinginfo.h"
#include "devices/deviceactioninfo.h"
#include <QJsonDocument>
@ -50,10 +53,6 @@ namespace nymeaserver {
DevicesResource::DevicesResource(QObject *parent) :
RestResource(parent)
{
connect(NymeaCore::instance(), &NymeaCore::actionExecuted, this, &DevicesResource::actionExecuted);
connect(NymeaCore::instance(), &NymeaCore::deviceSetupFinished, this, &DevicesResource::deviceSetupFinished);
connect(NymeaCore::instance(), &NymeaCore::deviceReconfigurationFinished, this, &DevicesResource::deviceReconfigurationFinished);
connect(NymeaCore::instance(), &NymeaCore::pairingFinished, this, &DevicesResource::pairingFinished);
}
/*! Returns the name of the \l{RestResource}. In this case \b devices.
@ -337,17 +336,30 @@ HttpReply *DevicesResource::executeAction(Device *device, const ActionTypeId &ac
Action action(actionTypeId, device->id());
action.setParams(actionParams);
Device::DeviceError status = NymeaCore::instance()->executeAction(action);
if (status == Device::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
m_asyncActionExecutions.insert(action.id(), reply);
return reply;
}
HttpReply *httpReply = createAsyncReply();
if (status != Device::DeviceErrorNoError)
return createDeviceErrorReply(HttpReply::InternalServerError, status);
DeviceActionInfo *info = NymeaCore::instance()->executeAction(action);
connect(info, &DeviceActionInfo::finished, this, [info, httpReply](){
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(info->status()));
return createDeviceErrorReply(HttpReply::Ok, status);
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
if (info->status() == Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Action execution finished successfully";
httpReply->setHttpStatusCode(HttpReply::Ok);
httpReply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
qCDebug(dcRest) << "Action execution finished with error" << info->status();
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(info->status()));
httpReply->setHttpStatusCode(HttpReply::InternalServerError);
httpReply->setPayload(QJsonDocument::fromVariant(response).toJson());
}
httpReply->finished();
});
return httpReply;
}
HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
@ -367,29 +379,35 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
Device::DeviceError status;
HttpReply *httpReply = createAsyncReply();
DeviceSetupInfo *info;
if (deviceDescriptorId.isNull()) {
qCDebug(dcRest) << "Adding device" << deviceName << "with" << deviceParams;
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceName, deviceParams, newDeviceId);
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceName, deviceParams, newDeviceId);
} else {
qCDebug(dcRest) << "Adding discovered device" << deviceName << "with DeviceDescriptorId" << deviceDescriptorId.toString();
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceName, deviceDescriptorId, deviceParams, newDeviceId);
}
if (status == Device::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
qCDebug(dcRest) << "Device setup async reply";
m_asyncDeviceAdditions.insert(newDeviceId, reply);
return reply;
info = NymeaCore::instance()->deviceManager()->addConfiguredDevice(deviceClassId, deviceName, deviceDescriptorId, deviceParams, newDeviceId);
}
if (status != Device::DeviceErrorNoError)
return createDeviceErrorReply(HttpReply::InternalServerError, status);
connect(info, &DeviceSetupInfo::finished, httpReply, [info, httpReply](){
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
if (info->status() != Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Device setup finished with error" << info->status();
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(info->status()));
httpReply->setHttpStatusCode(HttpReply::InternalServerError);
httpReply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
httpReply->setHttpStatusCode(HttpReply::Ok);
QVariant result = JsonTypes::packDevice(info->device());
httpReply->setPayload(QJsonDocument::fromVariant(result).toJson());
}
qCDebug(dcRest) << "Device setup finished successfully";
httpReply->finished();
});
QVariant result = JsonTypes::packDevice(NymeaCore::instance()->deviceManager()->findConfiguredDevice(newDeviceId));
HttpReply *reply = createSuccessReply();
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
reply->setPayload(QJsonDocument::fromVariant(result).toJson());
return reply;
return httpReply;
}
HttpReply *DevicesResource::editDevice(const QByteArray &payload) const
@ -428,27 +446,38 @@ HttpReply *DevicesResource::pairDevice(const QByteArray &payload) const
qCDebug(dcRest) << "Pair device" << deviceName << "with deviceClassId" << deviceClassId.toString();
Device::DeviceError status;
PairingTransactionId pairingTransactionId = PairingTransactionId::createPairingTransactionId();
HttpReply *httpReply = createAsyncReply();
DevicePairingInfo *info;
if (params.contains("deviceDescriptorId")) {
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
status = NymeaCore::instance()->deviceManager()->pairDevice(pairingTransactionId, deviceClassId, deviceName, deviceDescriptorId);
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceDescriptorId);
} else {
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
status = NymeaCore::instance()->deviceManager()->pairDevice(pairingTransactionId, deviceClassId, deviceName, deviceParams);
info = NymeaCore::instance()->deviceManager()->pairDevice(deviceClassId, deviceName, deviceParams);
}
if (status != Device::DeviceErrorNoError)
return createDeviceErrorReply(HttpReply::BadRequest, status);
connect(info, &DevicePairingInfo::finished, httpReply, [info, httpReply](){
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
if (info->status() != Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Device setup finished with error" << info->status();
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(info->status()));
httpReply->setHttpStatusCode(HttpReply::InternalServerError);
httpReply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
httpReply->setHttpStatusCode(HttpReply::Ok);
QVariantMap returns;
returns.insert("error", JsonTypes::deviceErrorToString(info->status()));
returns.insert("pairingTransactionId", info->transactionId().toString());
returns.insert("displayMessage", info->displayMessage());
httpReply->setPayload(QJsonDocument::fromVariant(returns).toJson());
}
qCDebug(dcRest) << "Device pairing initiated successfully";
httpReply->finished();
});
QVariantMap returns;
returns.insert("displayMessage", NymeaCore::instance()->deviceManager()->translate(deviceClass.pluginId(), deviceClass.pairingInfo(), NymeaCore::instance()->configuration()->locale()));
returns.insert("pairingTransactionId", pairingTransactionId.toString());
returns.insert("setupMethod", JsonTypes::setupMethod().at(deviceClass.setupMethod()));
HttpReply *reply = createSuccessReply();
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
reply->setPayload(QJsonDocument::fromVariant(returns).toJson());
return reply;
return httpReply;
}
HttpReply *DevicesResource::confirmPairDevice(const QByteArray &payload) const
@ -460,20 +489,29 @@ HttpReply *DevicesResource::confirmPairDevice(const QByteArray &payload) const
QVariantMap params = verification.second.toMap();
PairingTransactionId pairingTransactionId = PairingTransactionId(params.value("pairingTransactionId").toString());
QString username = params.value("username").toString();
QString secret = params.value("secret").toString();
Device::DeviceError status = NymeaCore::instance()->deviceManager()->confirmPairing(pairingTransactionId, secret);
if (status == Device::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
qCDebug(dcRest) << "Confirm pairing async reply";
m_asyncPairingRequests.insert(pairingTransactionId, reply);
return reply;
}
HttpReply *httpReply = createAsyncReply();
if (status != Device::DeviceErrorNoError)
return createDeviceErrorReply(HttpReply::InternalServerError, status);
DevicePairingInfo *info = NymeaCore::instance()->deviceManager()->confirmPairing(pairingTransactionId, username, secret);
connect(info, &DevicePairingInfo::finished, httpReply, [info, httpReply](){
qCDebug(dcRest()) << "Confirm pairing finished:" << info->status();
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(info->status()));
if (info->status() != Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Pairing device finished with error.";
httpReply->setHttpStatusCode(HttpReply::InternalServerError);
} else {
httpReply->setHttpStatusCode(HttpReply::Ok);
response.insert("id", info->deviceId().toString());
}
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
httpReply->setPayload(QJsonDocument::fromVariant(response).toJson());
httpReply->finished();
});
return createDeviceErrorReply(HttpReply::Ok, Device::DeviceErrorNoError);
return httpReply;
}
HttpReply *DevicesResource::reconfigureDevice(Device *device, const QByteArray &payload) const
@ -486,145 +524,35 @@ HttpReply *DevicesResource::reconfigureDevice(Device *device, const QByteArray &
QVariantMap params = verification.second.toMap();
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
Device::DeviceError status;
HttpReply *httpReply = createAsyncReply();
DeviceSetupInfo *info;
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
if (deviceDescriptorId.isNull()) {
qCDebug(dcRest) << "Reconfigure device with params:" << deviceParams;
status = NymeaCore::instance()->deviceManager()->reconfigureDevice(device->id(), deviceParams);
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(device->id(), deviceParams);
} else {
qCDebug(dcRest) << "Reconfigure device using the new discovered device with descriptorId:" << deviceDescriptorId.toString();
status = NymeaCore::instance()->deviceManager()->reconfigureDevice(device->id(), deviceDescriptorId);
info = NymeaCore::instance()->deviceManager()->reconfigureDevice(device->id(), deviceDescriptorId);
}
if (status == Device::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
qCDebug(dcRest) << "Device reconfiguration async reply";
m_asyncReconfigureDevice.insert(device, reply);
return reply;
}
connect(info, &DeviceSetupInfo::finished, httpReply, [httpReply, info](){
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
if (info->status() != Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Device reconfiguration finished with error" << info->status();
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(info->status()));
httpReply->setHttpStatusCode(HttpReply::InternalServerError);
httpReply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
qCDebug(dcRest) << "Device reconfiguration finished successfully";
httpReply->setHttpStatusCode(HttpReply::Ok);
QVariant result = JsonTypes::packDevice(info->device());
httpReply->setPayload(QJsonDocument::fromVariant(result).toJson());
}
httpReply->finished();
});
if (status != Device::DeviceErrorNoError)
return createDeviceErrorReply(HttpReply::InternalServerError, status);
return createDeviceErrorReply(HttpReply::Ok, Device::DeviceErrorNoError);
return httpReply;
}
void DevicesResource::actionExecuted(const ActionId &actionId, Device::DeviceError status)
{
if (!m_asyncActionExecutions.contains(actionId))
return; // Not the action we are waiting for.
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(status));
if (m_asyncActionExecutions.value(actionId).isNull()) {
qCWarning(dcRest) << "Async reply for execute action does not exist any more (timeout).";
return;
}
HttpReply *reply = m_asyncActionExecutions.take(actionId);
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
if (status == Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Action execution finished successfully";
reply->setHttpStatusCode(HttpReply::Ok);
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
qCDebug(dcRest) << "Action execution finished with error" << status;
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(status));
reply->setHttpStatusCode(HttpReply::InternalServerError);
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
}
reply->finished();
}
void DevicesResource::deviceSetupFinished(Device *device, Device::DeviceError status)
{
if (!m_asyncDeviceAdditions.contains(device->id()))
return; // Not the device we are waiting for.
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(status));
if (m_asyncDeviceAdditions.value(device->id()).isNull()) {
qCWarning(dcRest) << "Async reply for device setup does not exist any more (timeout).";
return;
}
HttpReply *reply = m_asyncDeviceAdditions.take(device->id());
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
if (status == Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Device setup finished successfully";
reply->setHttpStatusCode(HttpReply::Ok);
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
qCDebug(dcRest) << "Device setup finished with error" << status;
reply->setHttpStatusCode(HttpReply::InternalServerError);
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
}
QVariant result = JsonTypes::packDevice(device);
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
reply->setPayload(QJsonDocument::fromVariant(result).toJson());
reply->finished();
}
void DevicesResource::deviceReconfigurationFinished(Device *device, Device::DeviceError status)
{
if (!m_asyncReconfigureDevice.contains(device))
return; // Not the device we are waiting for.
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(status));
if (m_asyncReconfigureDevice.value(device).isNull()) {
qCWarning(dcRest) << "Async reply for device reconfiguration does not exist any more (timeout).";
return;
}
HttpReply *reply = m_asyncReconfigureDevice.take(device);
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
if (status == Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Device reconfiguration finished successfully";
reply->setHttpStatusCode(HttpReply::Ok);
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
} else {
qCDebug(dcRest) << "Device reconfiguration finished with error" << status;
reply->setHttpStatusCode(HttpReply::InternalServerError);
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
}
reply->finished();
}
void DevicesResource::pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceError status, const DeviceId &deviceId)
{
if (!m_asyncPairingRequests.contains(pairingTransactionId))
return; // Not the device pairing we are waiting for.
QVariantMap response;
response.insert("error", JsonTypes::deviceErrorToString(status));
if (m_asyncPairingRequests.value(pairingTransactionId).isNull()) {
qCWarning(dcRest) << "Async reply for device pairing does not exist any more.";
return;
}
HttpReply *reply = m_asyncPairingRequests.take(pairingTransactionId);
if (status != Device::DeviceErrorNoError) {
qCDebug(dcRest) << "Pairing device finished with error.";
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
reply->setHttpStatusCode(HttpReply::InternalServerError);
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
reply->finished();
return;
}
qCDebug(dcRest) << "Pairing device finished successfully";
// Add device to async device addtions
m_asyncDeviceAdditions.insert(deviceId, reply);
}
}

View File

@ -45,9 +45,6 @@ public:
private:
mutable QHash<ActionId, QPointer<HttpReply> > m_asyncActionExecutions;
mutable QHash<DeviceId, QPointer<HttpReply> > m_asyncDeviceAdditions;
mutable QHash<Device *, QPointer<HttpReply> > m_asyncReconfigureDevice;
mutable QHash<PairingTransactionId, QPointer<HttpReply> > m_asyncPairingRequests;
Device *m_device;
@ -77,11 +74,6 @@ private:
// Put methods
HttpReply *reconfigureDevice(Device *device, const QByteArray &payload) const;
private slots:
void actionExecuted(const ActionId &actionId, Device::DeviceError status);
void deviceSetupFinished(Device *device, Device::DeviceError status);
void deviceReconfigurationFinished(Device *device, Device::DeviceError status);
void pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceError status, const DeviceId &deviceId);
};
}

View File

@ -0,0 +1,58 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "browseractioninfo.h"
BrowserActionInfo::BrowserActionInfo(Device *device, const BrowserAction &browserAction, QObject *parent):
QObject (parent),
m_device(device),
m_browserAction(browserAction)
{
connect(this, &BrowserActionInfo::finished, this, &BrowserActionInfo::deleteLater, Qt::QueuedConnection);
}
Device *BrowserActionInfo::device() const
{
return m_device;
}
BrowserAction BrowserActionInfo::browserAction() const
{
return m_browserAction;
}
bool BrowserActionInfo::isFinished() const
{
return m_finished;
}
Device::DeviceError BrowserActionInfo::status() const
{
return m_status;
}
void BrowserActionInfo::finish(Device::DeviceError status)
{
m_finished = true;
m_status = status;
staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -0,0 +1,57 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BROWSERACTIONINFO_H
#define BROWSERACTIONINFO_H
#include <QObject>
#include "device.h"
#include "types/browseraction.h"
class BrowserActionInfo : public QObject
{
Q_OBJECT
public:
explicit BrowserActionInfo(Device* device, const BrowserAction &browserAction, QObject *parent = nullptr);
Device* device() const;
BrowserAction browserAction() const;
bool isFinished() const;
Device::DeviceError status() const;
signals:
void finished();
public slots:
void finish(Device::DeviceError status);
private:
Device *m_device = nullptr;
BrowserAction m_browserAction;
bool m_finished = false;
Device::DeviceError m_status = Device::DeviceErrorNoError;
};
#endif // BROWSERACTIONINFO_H

View File

@ -0,0 +1,79 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "browseresult.h"
BrowseResult::BrowseResult(Device *device, const QString &itemId, const QLocale &locale, QObject *parent):
QObject(parent),
m_device(device),
m_itemId(itemId),
m_locale(locale)
{
connect(this, &BrowseResult::finished, this, &BrowseResult::deleteLater, Qt::QueuedConnection);
}
Device *BrowseResult::device() const
{
return m_device;
}
QString BrowseResult::itemId() const
{
return m_itemId;
}
QLocale BrowseResult::locale() const
{
return m_locale;
}
BrowserItems BrowseResult::items() const
{
return m_items;
}
bool BrowseResult::isFinished() const
{
return m_finished;
}
Device::DeviceError BrowseResult::status() const
{
return m_status;
}
void BrowseResult::addItem(const BrowserItem &item)
{
m_items.append(item);
}
void BrowseResult::addItems(const BrowserItems &items)
{
m_items.append(items);
}
void BrowseResult::finish(Device::DeviceError status)
{
m_finished = true;
m_status = status;
staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -0,0 +1,65 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BROWSERESULT_H
#define BROWSERESULT_H
#include <QObject>
#include "device.h"
class BrowseResult : public QObject
{
Q_OBJECT
public:
explicit BrowseResult(Device *device, const QString &itemId, const QLocale &locale, QObject *parent = nullptr);
Device* device() const;
QString itemId() const;
QLocale locale() const;
BrowserItems items() const;
bool isFinished() const;
Device::DeviceError status() const;
public slots:
void addItem(const BrowserItem &item);
void addItems(const BrowserItems &items);
void finish(Device::DeviceError status);
signals:
void finished();
private:
Device *m_device = nullptr;
QString m_itemId;
QLocale m_locale;
BrowserItems m_items;
bool m_finished = false;
Device::DeviceError m_status = Device::DeviceErrorNoError;
};
#endif // BROWSERESULT_H

View File

@ -0,0 +1,58 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "browseritemactioninfo.h"
BrowserItemActionInfo::BrowserItemActionInfo(Device *device, const BrowserItemAction &browserItemAction, QObject *parent):
QObject(parent),
m_device(device),
m_browserItemAction(browserItemAction)
{
connect(this, &BrowserItemActionInfo::finished, this, &BrowserItemActionInfo::deleteLater, Qt::QueuedConnection);
}
Device *BrowserItemActionInfo::device() const
{
return m_device;
}
BrowserItemAction BrowserItemActionInfo::browserItemAction() const
{
return m_browserItemAction;
}
bool BrowserItemActionInfo::isFinished() const
{
return m_finished;
}
Device::DeviceError BrowserItemActionInfo::status() const
{
return m_status;
}
void BrowserItemActionInfo::finish(Device::DeviceError status)
{
m_finished = true;
m_status = status;
staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -0,0 +1,58 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BROWSERITEMACTIONINFO_H
#define BROWSERITEMACTIONINFO_H
#include <QObject>
#include "device.h"
#include "types/browseritemaction.h"
class BrowserItemActionInfo : public QObject
{
Q_OBJECT
public:
explicit BrowserItemActionInfo(Device *device, const BrowserItemAction &browserItemAction, QObject *parent = nullptr);
Device *device() const;
BrowserItemAction browserItemAction() const;
bool isFinished() const;
Device::DeviceError status() const;
signals:
void finished();
public slots:
void finish(Device::DeviceError status);
private:
Device *m_device = nullptr;
BrowserItemAction m_browserItemAction;
bool m_finished = false;
Device::DeviceError m_status = Device::DeviceErrorNoError;
};
#endif // BROWSERITEMACTIONINFO_H

View File

@ -0,0 +1,75 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "browseritemresult.h"
BrowserItemResult::BrowserItemResult(Device *device, const QString &itemId, const QLocale &locale, QObject *parent):
QObject(parent),
m_device(device),
m_itemId(itemId),
m_locale(locale)
{
connect(this, &BrowserItemResult::finished, this, &BrowserItemResult::deleteLater, Qt::QueuedConnection);
}
Device *BrowserItemResult::device() const
{
return m_device;
}
QString BrowserItemResult::itemId() const
{
return m_itemId;
}
QLocale BrowserItemResult::locale() const
{
return m_locale;
}
BrowserItem BrowserItemResult::item() const
{
return m_item;
}
bool BrowserItemResult::isFinished() const
{
return m_finished;
}
Device::DeviceError BrowserItemResult::status() const
{
return m_status;
}
void BrowserItemResult::finish(const BrowserItem &item)
{
m_item = item;
finish(Device::DeviceErrorNoError);
}
void BrowserItemResult::finish(Device::DeviceError status)
{
m_finished = true;
m_status = status;
staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -0,0 +1,64 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BROWSERITEMRESULT_H
#define BROWSERITEMRESULT_H
#include <QObject>
#include "device.h"
class BrowserItemResult : public QObject
{
Q_OBJECT
public:
explicit BrowserItemResult(Device *device, const QString &itemId, const QLocale &locale, QObject *parent = nullptr);
Device* device() const;
QString itemId() const;
QLocale locale() const;
BrowserItem item() const;
bool isFinished() const;
Device::DeviceError status() const;
public slots:
void finish(const BrowserItem &item);
void finish(Device::DeviceError status);
signals:
void finished();
private:
Device *m_device = nullptr;
QString m_itemId;
QLocale m_locale;
BrowserItem m_item;
bool m_finished = false;
Device::DeviceError m_status = Device::DeviceErrorNoError;
};
#endif // BROWSERITEMRESULT_H

View File

@ -371,7 +371,7 @@ bool Device::autoCreated() const
return m_autoCreated;
}
void Device::setSetupComplete(const bool &complete)
void Device::setSetupComplete(bool complete)
{
m_setupComplete = complete;
}

View File

@ -64,8 +64,7 @@ public:
DeviceErrorSetupMethodNotSupported,
DeviceErrorHardwareNotAvailable,
DeviceErrorHardwareFailure,
DeviceErrorAuthentificationFailure,
DeviceErrorAsync,
DeviceErrorAuthenticationFailure,
DeviceErrorDeviceInUse,
DeviceErrorDeviceInRule,
DeviceErrorDeviceIsChild,
@ -77,33 +76,6 @@ public:
};
Q_ENUM(DeviceError)
enum DeviceSetupStatus {
DeviceSetupStatusSuccess,
DeviceSetupStatusFailure,
DeviceSetupStatusAsync
};
Q_ENUM(DeviceSetupStatus)
class BrowseResult {
public:
BrowseResult(): m_id(QUuid::createUuid()) {}
Device::DeviceError status = Device::DeviceErrorNoError;
BrowserItems items;
QUuid id() const { return m_id; }
private:
QUuid m_id;
};
class BrowserItemResult {
public:
BrowserItemResult(): m_id(QUuid::createUuid()) {}
Device::DeviceError status = Device::DeviceErrorNoError;
BrowserItem item;
QUuid id() const { return m_id; }
private:
QUuid m_id;
};
DeviceId id() const;
DeviceClassId deviceClassId() const;
PluginId pluginId() const;
@ -153,7 +125,7 @@ private:
Device(DevicePlugin *plugin, const DeviceClass &deviceClass, QObject *parent = nullptr);
void setupCompleted();
void setSetupComplete(const bool &complete);
void setSetupComplete(bool complete);
private:
DeviceClass m_deviceClass;
@ -184,6 +156,5 @@ public:
};
Q_DECLARE_METATYPE(Device::DeviceError)
Q_DECLARE_METATYPE(Device::DeviceSetupStatus)
#endif

View File

@ -0,0 +1,75 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "deviceactioninfo.h"
#include "devicemanager.h"
DeviceActionInfo::DeviceActionInfo(Device *device, const Action &action, DeviceManager *parent):
QObject(parent),
m_device(device),
m_action(action),
m_deviceManager(parent)
{
connect(this, &DeviceActionInfo::finished, this, &DeviceActionInfo::deleteLater, Qt::QueuedConnection);
}
Device *DeviceActionInfo::device() const
{
return m_device;
}
Action DeviceActionInfo::action() const
{
return m_action;
}
bool DeviceActionInfo::isFinished() const
{
return m_finished;
}
Device::DeviceError DeviceActionInfo::status() const
{
return m_status;
}
QString DeviceActionInfo::displayMessage() const
{
return m_displayMessage;
}
QString DeviceActionInfo::translatedDisplayMessage(const QLocale &locale)
{
if (!m_deviceManager) {
return m_displayMessage;
}
return m_deviceManager->translate(m_device->pluginId(), m_displayMessage.toUtf8(), locale);
}
void DeviceActionInfo::finish(Device::DeviceError status, const QString &displayMessage)
{
m_finished = true;
m_status = status;
m_displayMessage = displayMessage;
staticQtMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -0,0 +1,67 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DEVICEACTIONINFO_H
#define DEVICEACTIONINFO_H
#include <QObject>
#include "device.h"
#include "typeutils.h"
#include "types/action.h"
class DeviceManager;
class DeviceActionInfo : public QObject
{
Q_OBJECT
public:
explicit DeviceActionInfo(Device *device, const Action &action, DeviceManager *parent);
Device* device() const;
Action action() const;
bool isFinished() const;
Device::DeviceError status() const;
QString displayMessage() const;
QString translatedDisplayMessage(const QLocale &locale);
signals:
void finished();
public slots:
void finish(Device::DeviceError status, const QString &displayMessage = QString());
private:
Device *m_device = nullptr;
Action m_action;
bool m_finished = false;
Device::DeviceError m_status = Device::DeviceErrorNoError;
QString m_displayMessage;
DeviceManager *m_deviceManager = nullptr;
};
#endif // DEVICEACTIONINFO_H

View File

@ -67,6 +67,15 @@ private:
ParamList m_params;
};
class DeviceDescriptors: public QList<DeviceDescriptor>
{
public:
DeviceDescriptors() {}
inline DeviceDescriptors(std::initializer_list<DeviceDescriptor> args): QList(args) {}
DeviceDescriptors(const QList<DeviceDescriptor> &other): QList<DeviceDescriptor>(other) {}
};
Q_DECLARE_METATYPE(DeviceDescriptor)
Q_DECLARE_METATYPE(DeviceDescriptors)
#endif // DEVICEDESCRIPTION_H

View File

@ -0,0 +1,90 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "devicediscoveryinfo.h"
#include "devicemanager.h"
DeviceDiscoveryInfo::DeviceDiscoveryInfo(const DeviceClassId &deviceClassId, const ParamList &params, DeviceManager *deviceManager):
QObject(deviceManager),
m_deviceClassId(deviceClassId),
m_params(params),
m_deviceManager(deviceManager)
{
connect(this, &DeviceDiscoveryInfo::finished, this, &DeviceDiscoveryInfo::deleteLater, Qt::QueuedConnection);
}
DeviceClassId DeviceDiscoveryInfo::deviceClassId() const
{
return m_deviceClassId;
}
ParamList DeviceDiscoveryInfo::params() const
{
return m_params;
}
bool DeviceDiscoveryInfo::isFinished() const
{
return m_finished;
}
Device::DeviceError DeviceDiscoveryInfo::status() const
{
return m_status;
}
void DeviceDiscoveryInfo::addDeviceDescriptor(const DeviceDescriptor &deviceDescriptor)
{
m_deviceDescriptors.append(deviceDescriptor);
}
void DeviceDiscoveryInfo::addDeviceDescriptors(const DeviceDescriptors &deviceDescriptors)
{
m_deviceDescriptors.append(deviceDescriptors);
}
DeviceDescriptors DeviceDiscoveryInfo::deviceDescriptors() const
{
return m_deviceDescriptors;
}
QString DeviceDiscoveryInfo::displayMessage() const
{
return m_displayMessage;
}
QString DeviceDiscoveryInfo::translatedDisplayMessage(const QLocale &locale)
{
if (!m_deviceManager) {
return m_displayMessage;
}
DeviceClass deviceClass = m_deviceManager->findDeviceClass(m_deviceClassId);
return m_deviceManager->translate(deviceClass.pluginId(), m_displayMessage.toUtf8(), locale);
}
void DeviceDiscoveryInfo::finish(Device::DeviceError status, const QString &displayMessage)
{
m_finished = true;
m_status = status;
m_displayMessage = displayMessage;
staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -0,0 +1,74 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DEVICEDISCOVERYINFO_H
#define DEVICEDISCOVERYINFO_H
#include <QObject>
#include "types/deviceclass.h"
#include "types/param.h"
#include "device.h"
#include "devicedescriptor.h"
class DeviceManager;
class LIBNYMEA_EXPORT DeviceDiscoveryInfo : public QObject
{
Q_OBJECT
public:
explicit DeviceDiscoveryInfo(const DeviceClassId &deviceClassId, const ParamList &params, DeviceManager *deviceManager);
DeviceClassId deviceClassId() const;
ParamList params() const;
bool isFinished() const;
Device::DeviceError status() const;
void addDeviceDescriptor(const DeviceDescriptor &deviceDescriptor);
void addDeviceDescriptors(const DeviceDescriptors &deviceDescriptors);
DeviceDescriptors deviceDescriptors() const;
QString displayMessage() const;
QString translatedDisplayMessage(const QLocale &locale);
public slots:
void finish(Device::DeviceError status, const QString &displayMessage = QString());
signals:
void finished();
private:
DeviceClassId m_deviceClassId;
ParamList m_params;
bool m_finished = false;
Device::DeviceError m_status;
QString m_displayMessage;
DeviceDescriptors m_deviceDescriptors;
DeviceManager *m_deviceManager = nullptr;
};
#endif // DEVICEDISCOVERYINFO_H

View File

@ -41,6 +41,7 @@ public:
virtual ~DeviceManager() = default;
virtual DevicePlugins plugins() const = 0;
virtual DevicePlugin* plugin(const PluginId &pluginId) const = 0;
virtual Device::DeviceError setPluginConfig(const PluginId &pluginId, const ParamList &pluginConfig) = 0;
virtual Vendors supportedVendors() const = 0;
@ -55,29 +56,29 @@ public:
virtual Devices findConfiguredDevices(const QString &interface) const = 0;
virtual Devices findChildDevices(const DeviceId &id) const = 0;
virtual Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) = 0;
virtual DeviceDiscoveryInfo* discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) = 0;
virtual Device::DeviceError addConfiguredDevice(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id = DeviceId::createDeviceId()) = 0;
virtual Device::DeviceError 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 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 Device::DeviceError reconfigureDevice(const DeviceId &deviceId, const ParamList &params, bool fromDiscoveryOrAuto = false) = 0;
virtual Device::DeviceError reconfigureDevice(const DeviceId &deviceId, const DeviceDescriptorId &deviceDescriptorId) = 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 Device::DeviceError editDevice(const DeviceId &deviceId, const QString &name) = 0;
virtual Device::DeviceError setDeviceSettings(const DeviceId &deviceId, const ParamList &settings) = 0;
virtual Device::DeviceError pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const QString &name, const ParamList &params) = 0;
virtual Device::DeviceError pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const QString &name, const DeviceDescriptorId &deviceDescriptorId) = 0;
virtual Device::DeviceError confirmPairing(const PairingTransactionId &pairingTransactionId, const QString &secret = QString()) = 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 Device::DeviceError executeAction(const Action &action) = 0;
virtual DeviceActionInfo* executeAction(const Action &action) = 0;
virtual Device::BrowseResult browseDevice(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) = 0;
virtual Device::BrowserItemResult browserItemDetails(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) = 0;
virtual Device::DeviceError executeBrowserItem(const BrowserAction &browserAction) = 0;
virtual Device::DeviceError executeBrowserItemAction(const BrowserItemAction &browserItemAction) = 0;
virtual BrowseResult* browseDevice(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) = 0;
virtual BrowserItemResult* browserItemDetails(const DeviceId &deviceId, const QString &itemId, const QLocale &locale) = 0;
virtual BrowserActionInfo* executeBrowserItem(const BrowserAction &browserAction) = 0;
virtual BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction) = 0;
virtual QString translate(const PluginId &pluginId, const QString &string, const QLocale &locale) = 0;
@ -90,16 +91,6 @@ signals:
void deviceAdded(Device *device);
void deviceChanged(Device *device);
void deviceSettingChanged(const DeviceId deviceId, const ParamTypeId &settingParamTypeId, const QVariant &value);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &devices);
void deviceSetupFinished(Device *device, Device::DeviceError status);
void deviceReconfigurationFinished(Device *device, Device::DeviceError status);
void pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceError status, const DeviceId &deviceId = DeviceId());
void actionExecutionFinished(const ActionId &actionId, Device::DeviceError status);
void browseRequestFinished(const Device::BrowseResult &result);
void browserItemRequestFinished(const Device::BrowserItemResult &result);
void browserItemExecutionFinished(const ActionId &actionId, Device::DeviceError status);
void browserItemActionExecutionFinished(const ActionId &actionId, Device::DeviceError status);
};
#endif // DEVICEMANAGER_H

View File

@ -21,26 +21,23 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "devicepairinginfo.h"
#include "devicemanager.h"
DevicePairingInfo::DevicePairingInfo()
DevicePairingInfo::DevicePairingInfo(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const DeviceId &deviceId, const QString &deviceName, const ParamList &params, const DeviceId &parentDeviceId, DeviceManager *parent):
QObject(parent),
m_transactionId(pairingTransactionId),
m_deviceClassId(deviceClassId),
m_deviceId(deviceId),
m_deviceName(deviceName),
m_params(params),
m_parentDeviceId(parentDeviceId)
{
connect(this, &DevicePairingInfo::finished, this, &DevicePairingInfo::deleteLater, Qt::QueuedConnection);
}
DevicePairingInfo::DevicePairingInfo(const DeviceClassId &deviceClassId, const QString &deviceName, const ParamList &params) :
m_deviceClassId(deviceClassId),
m_deviceName(deviceName),
m_params(params)
PairingTransactionId DevicePairingInfo::transactionId() const
{
}
DevicePairingInfo::DevicePairingInfo(const DeviceClassId &deviceClassId, const QString &deviceName, const DeviceDescriptorId &deviceDescriptorId) :
m_deviceClassId(deviceClassId),
m_deviceName(deviceName),
m_deviceDescriptorId(deviceDescriptorId)
{
return m_transactionId;
}
DeviceClassId DevicePairingInfo::deviceClassId() const
@ -48,6 +45,11 @@ DeviceClassId DevicePairingInfo::deviceClassId() const
return m_deviceClassId;
}
DeviceId DevicePairingInfo::deviceId() const
{
return m_deviceId;
}
QString DevicePairingInfo::deviceName() const
{
return m_deviceName;
@ -58,8 +60,45 @@ ParamList DevicePairingInfo::params() const
return m_params;
}
DeviceDescriptorId DevicePairingInfo::deviceDescriptorId() const
DeviceId DevicePairingInfo::parentDeviceId() const
{
return m_deviceDescriptorId;
return m_parentDeviceId;
}
QUrl DevicePairingInfo::oAuthUrl() const
{
return m_oAuthUrl;
}
void DevicePairingInfo::setOAuthUrl(const QUrl &oAuthUrl)
{
m_oAuthUrl = oAuthUrl;
}
Device::DeviceError DevicePairingInfo::status() const
{
return m_status;
}
QString DevicePairingInfo::displayMessage() const
{
return m_displayMessage;
}
QString DevicePairingInfo::translatedDisplayMessage(const QLocale &locale) const
{
if (!m_deviceManager) {
return m_displayMessage;
}
DeviceClass deviceClass = m_deviceManager->findDeviceClass(m_deviceClassId);
return m_deviceManager->translate(deviceClass.pluginId(), m_displayMessage.toUtf8(), locale);
}
void DevicePairingInfo::finish(Device::DeviceError status, const QString &displayMessage)
{
m_finished = true;
m_status = status;
m_displayMessage = displayMessage;
staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -23,30 +23,54 @@
#ifndef DEVICEPAIRINGINFO_H
#define DEVICEPAIRINGINFO_H
#include "libnymea.h"
#include "typeutils.h"
#include "types/param.h"
#include <QObject>
#include <QUrl>
class LIBNYMEA_EXPORT DevicePairingInfo
#include "device.h"
class DeviceManager;
class LIBNYMEA_EXPORT DevicePairingInfo: public QObject
{
Q_OBJECT
public:
DevicePairingInfo();
DevicePairingInfo(const DeviceClassId &deviceClassId, const QString &deviceName, const ParamList &params);
DevicePairingInfo(const DeviceClassId &deviceClassId, const QString &deviceName, const DeviceDescriptorId &deviceDescriptorId);
DevicePairingInfo(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const DeviceId &deviceId, const QString &deviceName, const ParamList &params, const DeviceId &parentDeviceId, DeviceManager *parent);
PairingTransactionId transactionId() const;
DeviceClassId deviceClassId() const;
DeviceId deviceId() const;
QString deviceName() const;
ParamList params() const;
DeviceId parentDeviceId() const;
DeviceDescriptorId deviceDescriptorId() const;
QUrl oAuthUrl() const;
void setOAuthUrl(const QUrl &oAuthUrl);
Device::DeviceError status() const;
QString displayMessage() const;
QString translatedDisplayMessage(const QLocale &locale) const;
public slots:
void finish(Device::DeviceError status, const QString &displayMessage = QString());
signals:
void finished();
private:
PairingTransactionId m_transactionId;
DeviceClassId m_deviceClassId;
DeviceId m_deviceId;
QString m_deviceName;
ParamList m_params;
DeviceDescriptorId m_deviceDescriptorId;
DeviceId m_parentDeviceId;
QUrl m_oAuthUrl;
bool m_finished = false;
Device::DeviceError m_status = Device::DeviceErrorNoError;
QString m_displayMessage;
DeviceManager *m_deviceManager = nullptr;
};
#endif // DEVICEPAIRINGINFO_H

View File

@ -89,6 +89,14 @@
#include "devicemanager.h"
#include "deviceutils.h"
#include "loggingcategories.h"
#include "devicediscoveryinfo.h"
#include "devicesetupinfo.h"
#include "devicepairinginfo.h"
#include "deviceactioninfo.h"
#include "browseresult.h"
#include "browseritemresult.h"
#include "browseractioninfo.h"
#include "browseritemactioninfo.h"
#include "nymeasettings.h"
@ -167,11 +175,9 @@ void DevicePlugin::startMonitoringAutoDevices()
if the discovery has been started successfully. Return an appropriate error otherwise.
Once devices are discovered, emit devicesDiscovered().
*/
Device::DeviceError DevicePlugin::discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params)
void DevicePlugin::discoverDevices(DeviceDiscoveryInfo *info)
{
Q_UNUSED(deviceClassId)
Q_UNUSED(params)
return Device::DeviceErrorCreationMethodNotSupported;
info->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! This will be called when a new device is created. The plugin has the chance to do some setup.
@ -181,10 +187,9 @@ Device::DeviceError DevicePlugin::discoverDevices(const DeviceClassId &deviceCla
return \l{DeviceManager}{DeviceSetupStatusAsync}. In that case the \l{DeviceManager} will wait for you to emit
\l{DevicePlugin}{deviceSetupFinished} to report the status.
*/
Device::DeviceSetupStatus DevicePlugin::setupDevice(Device *device)
void DevicePlugin::setupDevice(DeviceSetupInfo *info)
{
Q_UNUSED(device)
return Device::DeviceSetupStatusSuccess;
info->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! This will be called when a new \a device was added successfully and the device setup is finished.*/
@ -202,32 +207,55 @@ void DevicePlugin::deviceRemoved(Device *device)
Q_UNUSED(device)
}
/*! This method will be called for \l{Device}{Devices} with the \l{DeviceClass::SetupMethodDisplayPin} right after the paring request
with the given \a pairingTransactionId for the given \a deviceDescriptor.
/*! This method will be called to initiate a pairing. The plugin can do a initialisation for an upcoming pairing process.
Depending on the setupMethod of a device class, different actions may be required here.
SetupMethodDisplayPin should trigger the device to display a pin that will be entered in the client.
SetupMethodOAuth should generate the OAuthUrl which will be opened on the client to allow the user logging in and obtain
the OAuth code.
SetupMethodEnterPin, SetupMethodPushButton and SetupMethodUserAndPassword will typically not require to do anything here.
It is not required to reimplement this method for those setup methods, however, a Plugin reimplementing it should call
\l{DevicePairingInfo::finish}{finish()} on the \l{DevicePairingInfo} object and can provide an optional displayMessage which
might be presented to the user. Those strings need to be wrapped in QT_TR_NOOP() in order to be translatable for the client's
locale.
*/
Device::DeviceError DevicePlugin::displayPin(const PairingTransactionId &pairingTransactionId, const DeviceDescriptor &deviceDescriptor)
void DevicePlugin::startPairing(DevicePairingInfo *info)
{
Q_UNUSED(pairingTransactionId)
Q_UNUSED(deviceDescriptor)
qCWarning(dcDeviceManager) << "Plugin does not implement the display pin setup method.";
return Device::DeviceErrorNoError;
DeviceClass deviceClass = m_metaData.deviceClasses().findById(info->deviceClassId());
if (!deviceClass.isValid()) {
info->finish(Device::DeviceErrorDeviceClassNotFound);
return;
}
switch (deviceClass.setupMethod()) {
case DeviceClass::SetupMethodJustAdd:
info->finish(Device::DeviceErrorSetupMethodNotSupported);
return;
case DeviceClass::SetupMethodEnterPin:
case DeviceClass::SetupMethodPushButton:
case DeviceClass::SetupMethodUserAndPassword:
info->finish(Device::DeviceErrorNoError);
return;
case DeviceClass::SetupMethodDisplayPin:
case DeviceClass::SetupMethodOAuth:
// Those need to be handled by the plugin or it'll fail anyways.
qCWarning(dcDevice()) << "StartPairing called but Plugin does not reimplement it.";
info->finish(Device::DeviceErrorUnsupportedFeature);
}
}
/*! Confirms the pairing of a \a deviceClassId with the given \a pairingTransactionId and \a params.
Returns \l{Device::DeviceError}{DeviceError} to inform about the result. The optional paramerter
\a secret contains for example the pin for \l{Device}{Devices} with the setup method \l{DeviceClass::SetupMethodDisplayPin}.
/*! Confirms the pairing of the given \a info. \a username and \a secret are filled in depending on the setupmethod of the device class.
\a username will be used for SetupMethodUserAndPassword. \a secret will be used for SetupMethodUserAndPassword, SetupMethodDisplayPin
and SetupMethodOAuth.
Once the pairing is completed, the plugin implementation should call the info's finish() method reporting about the status of
the pairing operation. The optional displayMessage needs to be wrapped in QT_TR_NOOP in order to be translatable to the client's
locale.
*/
Device::DeviceSetupStatus DevicePlugin::confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList &params, const QString &secret = QString())
void DevicePlugin::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret)
{
Q_UNUSED(pairingTransactionId)
Q_UNUSED(deviceClassId)
Q_UNUSED(params)
Q_UNUSED(username)
Q_UNUSED(secret)
qCWarning(dcDeviceManager) << "Plugin does not implement pairing.";
return Device::DeviceSetupStatusFailure;
info->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! This will be called to actually execute actions on the hardware. The \{Device} and
@ -241,11 +269,9 @@ Device::DeviceSetupStatus DevicePlugin::confirmPairing(const PairingTransactionI
\sa actionExecutionFinished()
*/
Device::DeviceError DevicePlugin::executeAction(Device *device, const Action &action)
void DevicePlugin::executeAction(DeviceActionInfo *info)
{
Q_UNUSED(device)
Q_UNUSED(action)
return Device::DeviceErrorNoError;
info->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! Implement this if your devices support browsing (set "browsable" to true in the metadata).
@ -260,14 +286,10 @@ Device::DeviceError DevicePlugin::executeAction(Device *device, const Action &ac
* status to Device::DeviceErrorAsync if this operation requires async behavior and emit
* \l{browseRequestFinished} when done.
*/
Device::BrowseResult DevicePlugin::browseDevice(Device *device, Device::BrowseResult result, const QString &itemId, const QLocale &locale)
void DevicePlugin::browseDevice(BrowseResult *result)
{
Q_UNUSED(device)
Q_UNUSED(itemId)
Q_UNUSED(locale)
result.status = Device::DeviceErrorUnsupportedFeature;
return result;
qCWarning(dcDevice()) << "Device claims" << result->device()->deviceClass().name() << "to be browsable but plugin does not reimplement browseDevice!";
result->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! Implement this if your devices support browsing (set "browsable" to true in the metadata).
@ -277,25 +299,20 @@ Device::BrowseResult DevicePlugin::browseDevice(Device *device, Device::BrowseRe
* status to Device::DeviceErrorAsync if this operation requires async behavior and emit
* \l{browserItemRequestFinished} when done.
*/
Device::BrowserItemResult DevicePlugin::browserItem(Device *device, Device::BrowserItemResult result, const QString &itemId, const QLocale &locale)
void DevicePlugin::browserItem(BrowserItemResult *result)
{
Q_UNUSED(device)
Q_UNUSED(itemId)
Q_UNUSED(locale)
result.status = Device::DeviceErrorUnsupportedFeature;
return result;
qCWarning(dcDevice()) << "Device claims" << result->device()->deviceClass().name() << "to be browsable but plugin does not reimplement browserItem!";
result->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! Implement this if your devices support browsing and execute the itemId defined in \a browserAction.
* Return Device::DeviceErrorAsync if this operation requires async behavior and emit
* \l{browserItemExecutionFinished} when done.
*/
Device::DeviceError DevicePlugin::executeBrowserItem(Device *device, const BrowserAction &browserAction)
void DevicePlugin::executeBrowserItem(BrowserActionInfo *info)
{
Q_UNUSED(device)
Q_UNUSED(browserAction)
return Device::DeviceErrorUnsupportedFeature;
qCWarning(dcDevice()) << "Device claims" << info->device()->deviceClass().name() << "to be browsable but plugin does not reimplement browserItem!";
info->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! Implement this if your devices support browsing and execute the item's action for the itemId defined
@ -303,11 +320,10 @@ Device::DeviceError DevicePlugin::executeBrowserItem(Device *device, const Brows
* Return Device::DeviceErrorAsync if this operation requires async behavior and emit
* \l{browserItemActionExecutionFinished} when done.
*/
Device::DeviceError DevicePlugin::executeBrowserItemAction(Device *device, const BrowserItemAction &browserItemAction)
void DevicePlugin::executeBrowserItemAction(BrowserItemActionInfo *info)
{
Q_UNUSED(device)
Q_UNUSED(browserItemAction)
return Device::DeviceErrorUnsupportedFeature;
qCWarning(dcDevice()) << "Device claims" << info->device()->deviceClass().name() << "to be browsable but plugin does not reimplement browserItemAction!";
info->finish(Device::DeviceErrorUnsupportedFeature);
}
/*! Returns the configuration description of this DevicePlugin as a list of \l{ParamType}{ParamTypes}. */

View File

@ -42,11 +42,19 @@
#include "hardwaremanager.h"
#include "devicediscoveryinfo.h"
#include "devicepairinginfo.h"
#include "devicesetupinfo.h"
#include "deviceactioninfo.h"
#include "browseresult.h"
#include "browseritemresult.h"
#include "browseractioninfo.h"
#include "browseritemactioninfo.h"
#include <QObject>
#include <QTranslator>
#include <QPair>
class Device;
class DeviceManager;
class LIBNYMEA_EXPORT DevicePlugin: public QObject
@ -69,21 +77,21 @@ public:
DeviceClasses supportedDevices() const;
virtual void startMonitoringAutoDevices();
virtual Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params);
virtual void discoverDevices(DeviceDiscoveryInfo *info);
virtual Device::DeviceSetupStatus setupDevice(Device *device);
virtual void setupDevice(DeviceSetupInfo *info);
virtual void postSetupDevice(Device *device);
virtual void deviceRemoved(Device *device);
virtual Device::DeviceError displayPin(const PairingTransactionId &pairingTransactionId, const DeviceDescriptor &deviceDescriptor);
virtual Device::DeviceSetupStatus confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList &params, const QString &secret);
virtual void startPairing(DevicePairingInfo *info);
virtual void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret);
virtual Device::DeviceError executeAction(Device *device, const Action &action);
virtual void executeAction(DeviceActionInfo *info);
virtual Device::BrowseResult browseDevice(Device *device, Device::BrowseResult result, const QString &itemId, const QLocale &locale);
virtual Device::BrowserItemResult browserItem(Device *device, Device::BrowserItemResult result, const QString &itemId, const QLocale &locale);
virtual Device::DeviceError executeBrowserItem(Device *device, const BrowserAction &browserAction);
virtual Device::DeviceError executeBrowserItemAction(Device *device, const BrowserItemAction &browserItemAction);
virtual void browseDevice(BrowseResult *result);
virtual void browserItem(BrowserItemResult *result);
virtual void executeBrowserItem(BrowserActionInfo *info);
virtual void executeBrowserItemAction(BrowserItemActionInfo *info);
// Configuration
ParamTypes configurationDescription() const;
@ -96,17 +104,9 @@ public:
signals:
void emitEvent(const Event &event);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors);
void deviceSetupFinished(Device *device, Device::DeviceSetupStatus status);
void pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceSetupStatus status);
void actionExecutionFinished(const ActionId &id, Device::DeviceError status);
void configValueChanged(const ParamTypeId &paramTypeId, const QVariant &value);
void autoDevicesAppeared(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors);
void autoDevicesAppeared(const DeviceDescriptors &deviceDescriptors);
void autoDeviceDisappeared(const DeviceId &deviceId);
void browseRequestFinished(const Device::BrowseResult &result);
void browserItemRequestFinished(const Device::BrowserItemResult &result);
void browserItemExecutionFinished(const ActionId &actionid, Device::DeviceError status);
void browserItemActionExecutionFinished(const ActionId &actionid, Device::DeviceError status);
protected:
Devices myDevices() const;

View File

@ -0,0 +1,71 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "devicesetupinfo.h"
#include "deviceplugin.h"
#include "devicemanager.h"
DeviceSetupInfo::DeviceSetupInfo(Device *device, DeviceManager *deviceManager):
QObject(deviceManager),
m_device(device),
m_deviecManager(deviceManager)
{
connect(this, &DeviceSetupInfo::finished, this, &DeviceSetupInfo::deleteLater, Qt::QueuedConnection);
}
Device *DeviceSetupInfo::device() const
{
return m_device;
}
bool DeviceSetupInfo::isFinished() const
{
return m_finished;
}
Device::DeviceError DeviceSetupInfo::status() const
{
return m_status;
}
QString DeviceSetupInfo::displayMessage() const
{
return m_displayMessage;
}
QString DeviceSetupInfo::translatedDisplayMessage(const QLocale &locale)
{
if (!m_deviecManager || !m_device) {
return m_displayMessage;
}
return m_deviecManager->translate(m_device->pluginId(), m_displayMessage.toUtf8(), locale);
}
void DeviceSetupInfo::finish(Device::DeviceError status, const QString &displayMessage)
{
m_finished = true;
m_status = status;
m_displayMessage = displayMessage;
staticMetaObject.invokeMethod(this, "finished", Qt::QueuedConnection);
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DEVICESETUPINFO_H
#define DEVICESETUPINFO_H
#include "device.h"
#include <QObject>
class DeviceManager;
class LIBNYMEA_EXPORT DeviceSetupInfo : public QObject
{
Q_OBJECT
public:
explicit DeviceSetupInfo(Device *device, DeviceManager *deviceManager);
Device *device() const;
bool isFinished() const;
Device::DeviceError status() const;
QString displayMessage() const;
QString translatedDisplayMessage(const QLocale &locale);
public slots:
void finish(Device::DeviceError status, const QString &displayMessage = QString());
signals:
void finished();
private:
Device *m_device = nullptr;
bool m_finished = false;
Device::DeviceError m_status = Device::DeviceErrorNoError;
QString m_displayMessage;
DeviceManager *m_deviecManager = nullptr;
};
#endif // DEVICESETUPINFO_H

View File

@ -162,7 +162,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject)
QJsonObject deviceClassObject = deviceClassJson.toObject();
/*! Returns a list of all valid JSON properties a DeviceClass JSON definition can have. */
QStringList deviceClassProperties = QStringList() << "id" << "name" << "displayName" << "createMethods" << "setupMethod"
<< "interfaces" << "browsable" << "pairingInfo" << "discoveryParamTypes" << "discoveryParamTypes"
<< "interfaces" << "browsable" << "discoveryParamTypes" << "discoveryParamTypes"
<< "paramTypes" << "settingsTypes" << "stateTypes" << "actionTypes" << "eventTypes" << "browserItemActionTypes";
QStringList mandatoryDeviceClassProperties = QStringList() << "id" << "name" << "displayName";
@ -251,6 +251,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject)
setupMethod = DeviceClass::SetupMethodEnterPin;
} else if (setupMethodString.toLower() == "justadd") {
setupMethod = DeviceClass::SetupMethodJustAdd;
} else if (setupMethodString.toLower() == "userandpassword") {
setupMethod = DeviceClass::SetupMethodUserAndPassword;
} else if (setupMethodString.toLower() == "oauth") {
setupMethod = DeviceClass::SetupMethodOAuth;
} else {
qCWarning(dcPluginMetadata()) << "Unknown setupMethod" << setupMethod << "in deviceClass" << deviceClass.name() << ".";
hasError = true;
@ -258,9 +262,6 @@ void PluginMetadata::parse(const QJsonObject &jsonObject)
}
deviceClass.setSetupMethod(setupMethod);
// Read pairing info
deviceClass.setPairingInfo(deviceClassObject.value("pairingInfo").toString());
ActionTypes actionTypes;
StateTypes stateTypes;
EventTypes eventTypes;

View File

@ -10,9 +10,20 @@ DEFINES += LIBNYMEA_LIBRARY
QMAKE_LFLAGS += -fPIC
HEADERS += \
devices/browseractioninfo.h \
devices/browseritemactioninfo.h \
devices/browseritemresult.h \
devices/devicemanager.h \
devices/deviceutils.h \
devices/pluginmetadata.h \
devices/device.h \
devices/deviceplugin.h \
devices/devicedescriptor.h \
devices/devicediscoveryinfo.h \
devices/devicesetupinfo.h \
devices/devicepairinginfo.h \
devices/deviceactioninfo.h \
devices/browseresult.h \
libnymea.h \
platform/package.h \
platform/repository.h \
@ -23,10 +34,6 @@ HEADERS += \
typeutils.h \
loggingcategories.h \
nymeasettings.h \
devices/device.h \
devices/deviceplugin.h \
devices/devicedescriptor.h \
devices/devicepairinginfo.h \
hardware/gpio.h \
hardware/gpiomonitor.h \
hardware/pwm.h \
@ -77,17 +84,24 @@ HEADERS += \
platform/platformzeroconfcontroller.h \
SOURCES += \
devices/browseractioninfo.cpp \
devices/browseritemactioninfo.cpp \
devices/browseritemresult.cpp \
devices/devicemanager.cpp \
devices/deviceutils.cpp \
devices/pluginmetadata.cpp \
devices/device.cpp \
devices/deviceplugin.cpp \
devices/devicedescriptor.cpp \
devices/devicediscoveryinfo.cpp \
devices/devicesetupinfo.cpp \
devices/devicepairinginfo.cpp \
devices/deviceactioninfo.cpp \
devices/browseresult.cpp \
loggingcategories.cpp \
nymeasettings.cpp \
platform/package.cpp \
platform/repository.cpp \
devices/device.cpp \
devices/deviceplugin.cpp \
devices/devicedescriptor.cpp \
devices/devicepairinginfo.cpp \
hardware/gpio.cpp \
hardware/gpiomonitor.cpp \
hardware/pwm.cpp \

View File

@ -52,7 +52,9 @@ public:
SetupMethodJustAdd,
SetupMethodDisplayPin,
SetupMethodEnterPin,
SetupMethodPushButton
SetupMethodPushButton,
SetupMethodUserAndPassword,
SetupMethodOAuth
};
Q_ENUM(SetupMethod)

File diff suppressed because it is too large Load Diff

View File

@ -39,42 +39,37 @@ class DevicePluginMock : public DevicePlugin
public:
explicit DevicePluginMock();
~DevicePluginMock();
~DevicePluginMock() override;
Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
void discoverDevices(DeviceDiscoveryInfo *info) override;
Device::DeviceSetupStatus setupDevice(Device *device) override;
void setupDevice(DeviceSetupInfo *info) override;
void postSetupDevice(Device *device) override;
void deviceRemoved(Device *device) override;
void startMonitoringAutoDevices() override;
Device::DeviceSetupStatus confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList &params, const QString &secret) override;
Device::DeviceError displayPin(const PairingTransactionId &pairingTransactionId, const DeviceDescriptor &deviceDescriptor) override;
void startPairing(DevicePairingInfo *info) override;
void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override;
Device::BrowseResult browseDevice(Device *device, Device::BrowseResult result, const QString &itemId, const QLocale &locale) override;
Device::BrowserItemResult browserItem(Device *device, Device::BrowserItemResult result, const QString &itemId, const QLocale &locale) override;
void browseDevice(BrowseResult *result) override;
void browserItem(BrowserItemResult *result) override;
public slots:
Device::DeviceError executeAction(Device *device, const Action &action) override;
Device::DeviceError executeBrowserItem(Device *device, const BrowserAction &browserAction) override;
Device::DeviceError executeBrowserItemAction(Device *device, const BrowserItemAction &browserItemAction) override;
void executeAction(DeviceActionInfo *info) override;
void executeBrowserItem(BrowserActionInfo *info) override;
void executeBrowserItemAction(BrowserItemActionInfo *info) override;
private slots:
void setState(const StateTypeId &stateTypeId, const QVariant &value);
void triggerEvent(const EventTypeId &id);
void onDisappear();
void onReconfigureAutoDevice();
void emitDevicesDiscovered();
void emitPushButtonDevicesDiscovered();
void emitDisplayPinDevicesDiscovered();
void emitDeviceSetupFinished();
void emitActionExecuted();
void generateDiscoveredDevices(DeviceDiscoveryInfo *info);
void generateDiscoveredPushButtonDevices(DeviceDiscoveryInfo *info);
void generateDiscoveredDisplayPinDevices(DeviceDiscoveryInfo *info);
void onPushButtonPressed();
void onPushButtonPairingFinished();
void onDisplayPinPairingFinished();
void onChildDeviceDiscovered(const DeviceId &parentId);
void onPluginConfigChanged();
private:
@ -98,11 +93,8 @@ private:
};
QHash<Device*, HttpDaemon*> m_daemons;
QList<Device*> m_asyncSetupDevices;
QList<QPair<Action, Device*> > m_asyncActions;
PairingTransactionId m_pairingId;
int m_discoveredDeviceCount;
bool m_pushbuttonPressed;

View File

@ -326,7 +326,6 @@
"interfaces": ["system"],
"createMethods": ["discovery"],
"setupMethod": "pushButton",
"pairingInfo": "Wait 3 second before you continue, the push button will be pressed automatically.",
"paramTypes": [ ],
"discoveryParamTypes": [
{
@ -416,7 +415,6 @@
"interfaces": ["system"],
"createMethods": ["discovery"],
"setupMethod": "displayPin",
"pairingInfo": "Please enter the secret which normaly will be displayed on the device. For the mockdevice the pin is 243681.",
"discoveryParamTypes": [
{
"id": "35f6e4ba-28ad-4152-a58d-ec2600667bcf",
@ -849,6 +847,27 @@
"writable": true
}
]
},
{
"id": "805d1692-7bd0-449a-9d5c-43a332ff58f4",
"name": "mockOAuthGoogle",
"displayName": "Mock Device (Google OAuth)",
"createMethods": ["user"],
"setupMethod": "oauth"
},
{
"id": "783c615b-7bd6-49a4-98b0-8d1deb3c7156",
"name": "mockOAuthSonos",
"displayName": "Mock Device (Sonos OAuth)",
"createMethods": ["user"],
"setupMethod": "oauth"
},
{
"id": "6fe07a77-9c07-4736-81e2-d504314bbcb9",
"name": "mockUserAndPass",
"displayName": "Mock Device (User & Password)",
"createMethods": ["user"],
"setupMethod": "userandpassword"
}
]
}

View File

@ -243,5 +243,8 @@ extern ActionTypeId mockInputTypeWritableTimestampIntActionTypeId;
extern ParamTypeId mockInputTypeWritableTimestampIntActionWritableTimestampIntParamTypeId;
extern ActionTypeId mockInputTypeWritableTimestampUIntActionTypeId;
extern ParamTypeId mockInputTypeWritableTimestampUIntActionWritableTimestampUIntParamTypeId;
extern DeviceClassId mockOAuthGoogleDeviceClassId;
extern DeviceClassId mockOAuthSonosDeviceClassId;
extern DeviceClassId mockUserAndPassDeviceClassId;
#endif // EXTERNPLUGININFO_H

View File

@ -247,6 +247,9 @@ ActionTypeId mockInputTypeWritableTimestampIntActionTypeId = ActionTypeId("{88b6
ParamTypeId mockInputTypeWritableTimestampIntActionWritableTimestampIntParamTypeId = ParamTypeId("{88b6746a-b009-4df6-8986-d7884ffd94b2}");
ActionTypeId mockInputTypeWritableTimestampUIntActionTypeId = ActionTypeId("{45d0069a-63ac-4265-8170-8152778608ee}");
ParamTypeId mockInputTypeWritableTimestampUIntActionWritableTimestampUIntParamTypeId = ParamTypeId("{45d0069a-63ac-4265-8170-8152778608ee}");
DeviceClassId mockOAuthGoogleDeviceClassId = DeviceClassId("{805d1692-7bd0-449a-9d5c-43a332ff58f4}");
DeviceClassId mockOAuthSonosDeviceClassId = DeviceClassId("{783c615b-7bd6-49a4-98b0-8d1deb3c7156}");
DeviceClassId mockUserAndPassDeviceClassId = DeviceClassId("{6fe07a77-9c07-4736-81e2-d504314bbcb9}");
const QString translations[] {
//: The name of the Browser Item ActionType ({00b8f0a8-99ca-4aa4-833d-59eb8d4d6de3}) of DeviceClass mock
@ -387,6 +390,9 @@ const QString translations[] {
//: The name of the DeviceClass ({296f1fd4-e893-46b2-8a42-50d1bceb8730})
QT_TRANSLATE_NOOP("mockDevice", "Mock Device (Display Pin)"),
//: The name of the DeviceClass ({805d1692-7bd0-449a-9d5c-43a332ff58f4})
QT_TRANSLATE_NOOP("mockDevice", "Mock Device (Google OAuth)"),
//: The name of the DeviceClass ({515ffdf1-55e5-498d-9abc-4e2fe768f3a9})
QT_TRANSLATE_NOOP("mockDevice", "Mock Device (InputTypes)"),
@ -396,6 +402,12 @@ const QString translations[] {
//: The name of the DeviceClass ({9e03144c-e436-4eea-82d9-ccb33ef778db})
QT_TRANSLATE_NOOP("mockDevice", "Mock Device (Push Button)"),
//: The name of the DeviceClass ({783c615b-7bd6-49a4-98b0-8d1deb3c7156})
QT_TRANSLATE_NOOP("mockDevice", "Mock Device (Sonos OAuth)"),
//: The name of the DeviceClass ({6fe07a77-9c07-4736-81e2-d504314bbcb9})
QT_TRANSLATE_NOOP("mockDevice", "Mock Device (User & Password)"),
//: The name of the plugin mockDevice ({727a4a9a-c187-446f-aadf-f1b2220607d1})
QT_TRANSLATE_NOOP("mockDevice", "Mock Devices"),
@ -414,9 +426,6 @@ const QString translations[] {
//: The name of the ParamType (DeviceClass: mockInputType, Type: device, ID: {e5c0d14b-c9f1-4aca-a56e-85bfa6977150})
QT_TRANSLATE_NOOP("mockDevice", "Password text"),
//: The pairing info of deviceClass mockDisplayPin
QT_TRANSLATE_NOOP("mockDevice", "Please enter the secret which normaly will be displayed on the device. For the mockdevice the pin is 243681."),
//: The name of the Browser Item ActionType ({da6faef8-2816-430e-93bb-57e8f9582d29}) of DeviceClass mock
QT_TRANSLATE_NOOP("mockDevice", "Remove from favorites"),
@ -561,9 +570,6 @@ const QString translations[] {
//: The name of the ParamType (DeviceClass: mockInputType, Type: device, ID: {fa67229f-fcef-496f-b671-59a4b48f3ab5})
QT_TRANSLATE_NOOP("mockDevice", "URL"),
//: The pairing info of deviceClass mockPushButton
QT_TRANSLATE_NOOP("mockDevice", "Wait 3 second before you continue, the push button will be pressed automatically."),
//: The name of the ParamType (DeviceClass: mockInputType, ActionType: writableBool, ID: {a7c11774-f31f-4d64-99d1-e0ae5fb35a5c})
QT_TRANSLATE_NOOP("mockDevice", "Writable Bool"),

View File

@ -23,6 +23,9 @@
#include "nymeacore.h"
#include "nymeasettings.h"
#include "devices/devicediscoveryinfo.h"
#include "devices/devicesetupinfo.h"
using namespace nymeaserver;
class TestDevices : public NymeaTestBase
@ -486,7 +489,7 @@ void TestDevices::addPushButtonDevices_data()
QTest::addColumn<bool>("waitForButtonPressed");
QTest::newRow("Valid: Add PushButton device") << mockPushButtonDeviceClassId << Device::DeviceErrorNoError << true;
QTest::newRow("Invalid: Add PushButton device (press to early)") << mockPushButtonDeviceClassId << Device::DeviceErrorSetupFailed << false;
QTest::newRow("Invalid: Add PushButton device (press to early)") << mockPushButtonDeviceClassId << Device::DeviceErrorAuthenticationFailure << false;
}
void TestDevices::addPushButtonDevices()
@ -552,7 +555,7 @@ void TestDevices::addDisplayPinDevices_data()
QTest::addColumn<QString>("secret");
QTest::newRow("Valid: Add DisplayPin device") << mockDisplayPinDeviceClassId << Device::DeviceErrorNoError << "243681";
QTest::newRow("Invalid: Add DisplayPin device (wrong pin)") << mockDisplayPinDeviceClassId << Device::DeviceErrorSetupFailed << "243682";
QTest::newRow("Invalid: Add DisplayPin device (wrong pin)") << mockDisplayPinDeviceClassId << Device::DeviceErrorAuthenticationFailure << "243682";
}
void TestDevices::addDisplayPinDevices()
@ -616,12 +619,17 @@ void TestDevices::parentChildDevices()
params.insert("deviceClassId", mockParentDeviceClassId);
params.insert("name", "Parent device");
QSignalSpy deviceAddedSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId parentDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!parentDeviceId.isNull());
deviceAddedSpy.wait();
QCOMPARE(deviceAddedSpy.count(), 2);
// find child device
response = injectAndWait("Devices.GetConfiguredDevices");
@ -1430,7 +1438,6 @@ void TestDevices::reconfigureAutodevice()
QNetworkReply *reply = nam->get(QNetworkRequest(QUrl(QString("http://localhost:%1/reconfigureautodevice").arg(currentPort))));
spy.wait();
QCOMPARE(spy.count(), 1);
qCDebug(dcTests()) << "Reconfigure reply:" << reply->error() << reply->readAll();
reply->deleteLater();
Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(deviceId);
@ -1576,50 +1583,57 @@ void TestDevices::testBrowsing()
void TestDevices::discoverDeviceParenting()
{
// Try to discover a mock child device. We don't have a mockParent yet, so it should fail
QSignalSpy spy(NymeaCore::instance()->deviceManager(), &DeviceManager::devicesDiscovered);
Device::DeviceError status = NymeaCore::instance()->deviceManager()->discoverDevices(mockChildDeviceClassId, ParamList());
QCOMPARE(status, Device::DeviceErrorAsync);
spy.wait();
QCOMPARE(spy.first().at(0).value<DeviceClassId>().toString(), mockChildDeviceClassId.toString());
QList<DeviceDescriptor> descriptors = spy.first().at(1).value<QList<DeviceDescriptor> >();
QVERIFY(descriptors.count() == 0);
DeviceDiscoveryInfo *discoveryInfo = NymeaCore::instance()->deviceManager()->discoverDevices(mockChildDeviceClassId, ParamList());
{
QSignalSpy spy(discoveryInfo, &DeviceDiscoveryInfo::finished);
spy.wait();
}
QVERIFY(discoveryInfo->deviceDescriptors().count() == 0);
// Now create a mock parent by discovering...
spy.clear();
status = NymeaCore::instance()->deviceManager()->discoverDevices(mockParentDeviceClassId, ParamList());
QCOMPARE(status, Device::DeviceErrorAsync);
spy.wait();
QVERIFY(spy.count() == 1);
QCOMPARE(spy.first().at(0).value<DeviceClassId>().toString(), mockParentDeviceClassId.toString());
descriptors = spy.first().at(1).value<QList<DeviceDescriptor> >();
QVERIFY(descriptors.count() == 1);
DeviceDescriptorId descriptorId = descriptors.first().id();
discoveryInfo = NymeaCore::instance()->deviceManager()->discoverDevices(mockParentDeviceClassId, ParamList());
{
QSignalSpy spy(discoveryInfo, &DeviceDiscoveryInfo::finished);
spy.wait();
}
QVERIFY(discoveryInfo->deviceDescriptors().count() == 1);
DeviceDescriptorId descriptorId = discoveryInfo->deviceDescriptors().first().id();
QSignalSpy addSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockParentDeviceClassId, "Mock Parent (Discovered)", descriptorId);
QCOMPARE(status, Device::DeviceErrorNoError);
DeviceSetupInfo *setupInfo = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockParentDeviceClassId, "Mock Parent (Discovered)", descriptorId);
{
QSignalSpy spy(setupInfo, &DeviceSetupInfo::finished);
spy.wait();
}
QCOMPARE(setupInfo->status(), Device::DeviceErrorNoError);
addSpy.wait();
QCOMPARE(addSpy.count(), 2); // Mock device parent will also auto-create a child instantly
Device *parentDevice = addSpy.at(1).first().value<Device*>();
Device *parentDevice = addSpy.at(0).first().value<Device*>();
qCDebug(dcTests()) << "Added device:" << parentDevice->name();
QVERIFY(parentDevice->deviceClassId() == mockParentDeviceClassId);
// Ok we have our parent device, let's discover for childs again
spy.clear();
status = NymeaCore::instance()->deviceManager()->discoverDevices(mockChildDeviceClassId, ParamList());
QCOMPARE(status, Device::DeviceErrorAsync);
spy.wait();
QCOMPARE(spy.first().at(0).value<DeviceClassId>().toString(), mockChildDeviceClassId.toString());
descriptors = spy.first().at(1).value<QList<DeviceDescriptor> >();
QVERIFY(descriptors.count() == 1);
descriptorId = descriptors.first().id();
discoveryInfo = NymeaCore::instance()->deviceManager()->discoverDevices(mockChildDeviceClassId, ParamList());
{
QSignalSpy spy(discoveryInfo, &DeviceDiscoveryInfo::finished);
spy.wait();
}
QVERIFY(discoveryInfo->deviceDescriptors().count() == 1);
descriptorId = discoveryInfo->deviceDescriptors().first().id();
// Found one! Adding it...
addSpy.clear();
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockChildDeviceClassId, "Mock Child (Discovered)", descriptorId);
QCOMPARE(status, Device::DeviceErrorNoError);
setupInfo = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockChildDeviceClassId, "Mock Child (Discovered)", descriptorId);
{
QSignalSpy spy(setupInfo, &DeviceSetupInfo::finished);
spy.wait();
}
QCOMPARE(setupInfo->status(), Device::DeviceErrorNoError);
QCOMPARE(addSpy.count(), 1);
Device *childDevice = addSpy.at(0).first().value<Device*>();

View File

@ -218,6 +218,7 @@ void TestLogging::eventLogs()
QNetworkReply *reply = nam.get(request);
// Lets wait for the notification
QTest::qWait(200);
clientSpy.wait(1000);
reply->deleteLater();

View File

@ -54,6 +54,12 @@ void TestRestDeviceClasses::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\n"
"Tests.debug=true\n"
"Rest.debug=true\n"
"WebServer.debug=true\n"
"MockDevice.debug=true");
foreach (const WebServerConfiguration &config, NymeaCore::instance()->configuration()->webServerConfigurations()) {
if (config.port == 3333 && (config.address == QHostAddress("127.0.0.1") || config.address == QHostAddress("0.0.0.0"))) {
qDebug() << "Already have a webserver listening on 127.0.0.1:3333";

View File

@ -63,14 +63,17 @@ private slots:
void TestRestDevices::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\nTests.debug=true\nMockDevice.debug=true\nRest.debug=true");
foreach (const WebServerConfiguration &config, NymeaCore::instance()->configuration()->webServerConfigurations()) {
if (config.port == 3333 && (config.address == QHostAddress("127.0.0.1") || config.address == QHostAddress("0.0.0.0"))) {
qDebug() << "Already have a webserver listening on 127.0.0.1:3333";
qCWarning(dcTests()) << "Already have a webserver listening on 127.0.0.1:3333";
return;
}
}
qDebug() << "Creating new webserver instance on 127.0.0.1:3333";
qCDebug(dcTests()) << "Creating new webserver instance on 127.0.0.1:3333";
WebServerConfiguration config;
config.address = QHostAddress("127.0.0.1");
config.port = 3333;
@ -78,6 +81,7 @@ void TestRestDevices::initTestCase()
config.restServerEnabled = true;
NymeaCore::instance()->configuration()->setWebServerConfiguration(config);
qApp->processEvents();
}
void TestRestDevices::getConfiguredDevices()

View File

@ -238,6 +238,7 @@ void TestRules::setWritableStateValue(const DeviceId &deviceId, const StateTypeI
printJson(params);
response = injectAndWait("Actions.ExecuteAction", params);
qCDebug(dcTests()) << "Execute action response" << response;
verifyDeviceError(response);
if (shouldGetNotification) {
@ -386,7 +387,11 @@ void TestRules::generateEvent(const EventTypeId &eventTypeId)
void TestRules::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\nTests.debug=true\nRuleEngine.debug=true\nRuleEngineDebug.debug=true\nMockDevice.*=true");
QLoggingCategory::setFilterRules("*.debug=false\n"
"Tests.debug=true\n"
"RuleEngine.debug=true\n"
// "RuleEngineDebug.debug=true\n"
"MockDevice.*=true");
}
void TestRules::addRemoveRules_data()
@ -1934,10 +1939,10 @@ void TestRules::testChildEvaluator_data()
QTest::addColumn<bool>("active");
QTest::newRow("Unchanged | 2 | 2.5 | String value 1 | #FF0000") << testDeviceId << ruleMap << 2 << 2.5 << "String value 1" << "#FF0000" << false << false;
QTest::newRow("Unchanged | 60 | 2.5 | String value 2 | #FF0000") << testDeviceId << ruleMap << 60 << 2.5 << "String value 2" << "#FF0000" << false << false;
QTest::newRow("Unchanged | 60 | 20.5 | String value 2 | #FF0000") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#FF0000" << false << false;
QTest::newRow("Active | 60 | 20.5 | String value 2 | #00FF00") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#00FF00" << true << true;
QTest::newRow("Active | 60 | 20.5 | String value 2 | #00FF00") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#00FF00" << true << true;
// QTest::newRow("Unchanged | 60 | 2.5 | String value 2 | #FF0000") << testDeviceId << ruleMap << 60 << 2.5 << "String value 2" << "#FF0000" << false << false;
// QTest::newRow("Unchanged | 60 | 20.5 | String value 2 | #FF0000") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#FF0000" << false << false;
// QTest::newRow("Active | 60 | 20.5 | String value 2 | #00FF00") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#00FF00" << true << true;
// QTest::newRow("Active | 60 | 20.5 | String value 2 | #00FF00") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#00FF00" << true << true;
}
void TestRules::testChildEvaluator()
@ -1957,6 +1962,8 @@ void TestRules::testChildEvaluator()
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinAllowedValuesStateTypeId.toString()), QVariant("String value 1"));
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinColorStateTypeId.toString()), QVariant("#000000"));
qCDebug(dcTests()) << "Adding rule";
// Add rule
QVariant response = injectAndWait("Rules.AddRule", ruleMap);
verifyRuleError(response);
@ -1964,30 +1971,38 @@ void TestRules::testChildEvaluator()
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
// Set the states
qCDebug(dcTests()) << "Setting state 1";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinPercentageStateTypeId.toString()), QVariant::fromValue(percentageValue));
qCDebug(dcTests()) << "Setting state 2";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinDoubleActionDoubleParamTypeId.toString()), QVariant::fromValue(doubleValue));
qCDebug(dcTests()) << "Setting state 3";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinAllowedValuesStateTypeId.toString()), QVariant::fromValue(allowedValue));
qCDebug(dcTests()) << "Setting state 4";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinColorStateTypeId.toString()), QVariant::fromValue(colorValue));
// Verfiy if the rule executed successfully
// Actions
if (trigger && active) {
qCDebug(dcTests()) << "Checking if actions were executed";
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
}
// Exit actions
if (trigger && !active) {
qCDebug(dcTests()) << "Checking if exit actions were executed";
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
}
// Nothing triggert
if (!trigger) {
qCDebug(dcTests()) << "Making sure nothing triggered";
verifyRuleNotExecuted();
}
// REMOVE rule
qCDebug(dcTests()) << "Removing rule";
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
@ -2319,12 +2334,16 @@ void TestRules::removePolicyUpdate()
params.insert("deviceClassId", mockParentDeviceClassId);
params.insert("name", "Parent device");
QSignalSpy addedSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId parentDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!parentDeviceId.isNull());
addedSpy.wait();
// find child device
response = injectAndWait("Devices.GetConfiguredDevices");
@ -2402,12 +2421,16 @@ void TestRules::removePolicyCascade()
params.insert("deviceClassId", mockParentDeviceClassId);
params.insert("name", "Parent device");
QSignalSpy addedSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId parentDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!parentDeviceId.isNull());
addedSpy.wait();
// find child device
response = injectAndWait("Devices.GetConfiguredDevices");
@ -2475,13 +2498,16 @@ void TestRules::removePolicyUpdateRendersUselessRule()
params.insert("deviceClassId", mockParentDeviceClassId);
params.insert("name", "Parent device");
qCDebug(dcTests()) << "Adding device";
QSignalSpy addedSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId parentDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!parentDeviceId.isNull());
addedSpy.wait();
// find child device
qCDebug(dcTests()) << "Gettin devices";
response = injectAndWait("Devices.GetConfiguredDevices");

View File

@ -125,7 +125,13 @@ private:
void TestTimeManager::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\nTests.debug=true\nRuleEngine.debug=true\nRuleEngineDebug.debug=true\nMockDevice.*=true\nTimeManager.debug=true");
QLoggingCategory::setFilterRules("*.debug=false\n"
"Tests.debug=true\n"
"RuleEngine.debug=true\n"
// "RuleEngineDebug.debug=true\n"
"MockDevice.debug=true\n"
"JsonRpc.debug=true\n"
"TimeManager.debug=true");
}
void TestTimeManager::changeTimeZone_data()
@ -2106,7 +2112,7 @@ void TestTimeManager::setIntState(const int &value)
void TestTimeManager::setBoolState(const bool &value)
{
qDebug() << "Setting mock bool state to" << value;
qCDebug(dcTests()) << "Setting mock bool state to" << value;
// Get the current state value to check if we have to wait for state changed notfication
QVariantMap params;
@ -2131,10 +2137,10 @@ void TestTimeManager::setBoolState(const bool &value)
if (shouldGetNotification) {
stateSpy.wait(100);
// Wait for state changed notification
QVariantList stateChangedVariants = checkNotifications(stateSpy, "Devices.StateChanged");
QVERIFY2(stateChangedVariants.count() == 1, "Did not get Devices.StateChanged notification.");
QVariantList stateChangedSignals = checkNotifications(stateSpy, "Devices.StateChanged");
QCOMPARE(stateChangedSignals.count(), 1);
QVariantMap notification = stateChangedVariants.first().toMap().value("params").toMap();
QVariantMap notification = stateChangedSignals.first().toMap().value("params").toMap();
QVERIFY2(notification.contains("deviceId"), "Devices.StateChanged notification does not contain deviceId");
QVERIFY2(DeviceId(notification.value("deviceId").toString()) == m_mockDeviceId, "Devices.StateChanged notification does not contain the correct deviceId");
QVERIFY2(notification.contains("stateTypeId"), "Devices.StateChanged notification does not contain stateTypeId");

View File

@ -124,29 +124,36 @@ QVariant NymeaTestBase::injectAndWait(const QString &method, const QVariantMap &
m_mockTcpServer->injectData(clientId.isNull() ? m_clientId : clientId, jsonDoc.toJson(QJsonDocument::Compact) + "\n");
if (spy.count() == 0) {
spy.wait();
int loop = 0;
while (loop < 5) {
if (spy.count() == 0 || loop > 0) {
spy.wait();
}
for (int i = 0; i < spy.count(); i++) {
// Make sure the response it a valid JSON string
QJsonParseError error;
jsonDoc = QJsonDocument::fromJson(spy.at(i).last().toByteArray(), &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "JSON parser error" << error.errorString() << spy.at(i).last().toByteArray();
return QVariant();
}
QVariantMap response = jsonDoc.toVariant().toMap();
// skip notifications
if (response.contains("notification"))
continue;
if (response.value("id").toInt() == m_commandId) {
m_commandId++;
return jsonDoc.toVariant();
}
}
loop++;
}
for (int i = 0; i < spy.count(); i++) {
// Make sure the response it a valid JSON string
QJsonParseError error;
jsonDoc = QJsonDocument::fromJson(spy.at(i).last().toByteArray(), &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "JSON parser error" << error.errorString() << spy.at(i).last().toByteArray();
return QVariant();
}
QVariantMap response = jsonDoc.toVariant().toMap();
// skip notifications
if (response.contains("notification"))
continue;
if (response.value("id").toInt() == m_commandId) {
m_commandId++;
return jsonDoc.toVariant();
}
}
m_commandId++;
return QVariant();
}
@ -205,10 +212,10 @@ QVariant NymeaTestBase::getAndWait(const QNetworkRequest &request, const int &ex
if (clientSpy.count() == 0) {
clientSpy.wait();
}
qDebug() << "*** finished" << reply->isFinished() << reply->error() << reply->errorString();
qCDebug(dcTests()) << "*** finished" << reply->isFinished() << reply->error() << reply->errorString();
if (clientSpy.count() == 0) {
qWarning() << "Got no response for get request";
qCWarning(dcTests()) << "Got no response for get request";
reply->deleteLater();
return QVariant();
}
@ -216,6 +223,8 @@ QVariant NymeaTestBase::getAndWait(const QNetworkRequest &request, const int &ex
QByteArray data = reply->readAll();
verifyReply(reply, data, expectedStatus);
qCDebug(dcTests()) << "Data is:" << data;
reply->deleteLater();
QJsonParseError error;
@ -295,7 +304,7 @@ QVariant NymeaTestBase::postAndWait(const QNetworkRequest &request, const QVaria
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "JSON parser error" << error.errorString();
qWarning() << "JSON parser error" << error.errorString() << qUtf8Printable(data);
return QVariant();
}

View File

@ -64,6 +64,7 @@ protected:
inline void verifyError(const QVariant &response, const QString &fieldName, const QString &error)
{
qCDebug(dcTests()) << "******* response 2" << response;
QJsonDocument jsonDoc = QJsonDocument::fromVariant(response);
QVERIFY2(response.toMap().value("status").toString() == QString("success"),
QString("\nExpected status: \"success\"\nGot: %2\nFull message: %3")
@ -79,6 +80,7 @@ protected:
}
inline void verifyRuleError(const QVariant &response, RuleEngine::RuleError error = RuleEngine::RuleErrorNoError) {
qCDebug(dcTests()) << "******* response" << response;
verifyError(response, "ruleError", JsonTypes::ruleErrorToString(error));
}

View File

@ -245,10 +245,6 @@ void PluginInfoCompiler::writeDeviceClass(const DeviceClass &deviceClass)
m_translationStrings.insert(deviceClass.displayName(), QString("The name of the DeviceClass (%1)").arg(deviceClass.id().toString()));
writeExtern(QString("extern DeviceClassId %1;").arg(variableName));
if (!deviceClass.pairingInfo().isEmpty()) {
m_translationStrings.insert(deviceClass.pairingInfo(), QString("The pairing info of deviceClass %1").arg(deviceClass.name()));
}
writeParams(deviceClass.paramTypes(), deviceClass.name(), "", "device");
writeParams(deviceClass.settingsTypes(), deviceClass.name(), "", "settings");
writeParams(deviceClass.discoveryParamTypes(), deviceClass.name(), "", "discovery");