Merge PR #211: Rework devicemanager and plugin api

This commit is contained in:
Jenkins nymea 2019-10-18 14:57:22 +02:00
commit 2fd3f7c0be
71 changed files with 4380 additions and 13623 deletions

4
debian/changelog vendored
View File

@ -1,3 +1,7 @@
nymea (0.16.0) UNRELEASED; urgency=medium
-- Michael Zanetti <michael.zanetti@guh.io> Fri, 20 Sep 2019 12:39:23 +0200
nymea (0.15.1) xenial; urgency=medium
[ Michael Zanetti ]

2
debian/control vendored
View File

@ -20,7 +20,7 @@ Build-Depends: debhelper (>= 9.0.0),
libqt5sql5-sqlite,
libqt5dbus5,
libssl-dev,
libnymea-mqtt-dev,
libnymea-mqtt-dev (>= 0.1.2),
dbus-test-runner,
Package: nymea

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

@ -55,6 +55,9 @@ QString Translator::translate(const PluginId &pluginId, const QString &string, c
QTranslator* translator = m_translatorContexts.value(plugin->pluginId()).translators.value(locale.name());
QString translatedString = translator->translate(plugin->pluginName().toUtf8(), string.toUtf8());
if (translatedString.isEmpty()) {
translatedString = translator->translate(plugin->metaObject()->className(), string.toUtf8());
}
return translatedString.isEmpty() ? string : translatedString;
}

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,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/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "browseractioninfo.h"
#include <QTimer>
BrowserActionInfo::BrowserActionInfo(Device *device, const BrowserAction &browserAction, QObject *parent, quint32 timeout):
QObject (parent),
m_device(device),
m_browserAction(browserAction)
{
connect(this, &BrowserActionInfo::finished, this, &BrowserActionInfo::deleteLater, Qt::QueuedConnection);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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,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 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, quint32 timeout = 0);
Device* device() const;
BrowserAction browserAction() const;
bool isFinished() const;
Device::DeviceError status() const;
signals:
void finished();
void aborted();
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,88 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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"
#include <QTimer>
BrowseResult::BrowseResult(Device *device, const QString &itemId, const QLocale &locale, QObject *parent, quint32 timeout):
QObject(parent),
m_device(device),
m_itemId(itemId),
m_locale(locale)
{
connect(this, &BrowseResult::finished, this, &BrowseResult::deleteLater, Qt::QueuedConnection);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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,66 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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, quint32 timeout = 0);
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();
void aborted();
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,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/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "browseritemactioninfo.h"
#include <QTimer>
BrowserItemActionInfo::BrowserItemActionInfo(Device *device, const BrowserItemAction &browserItemAction, QObject *parent, quint32 timeout):
QObject(parent),
m_device(device),
m_browserItemAction(browserItemAction)
{
connect(this, &BrowserItemActionInfo::finished, this, &BrowserItemActionInfo::deleteLater, Qt::QueuedConnection);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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,59 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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, quint32 timeout = 0);
Device *device() const;
BrowserItemAction browserItemAction() const;
bool isFinished() const;
Device::DeviceError status() const;
signals:
void finished();
void aborted();
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,84 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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"
#include <QTimer>
BrowserItemResult::BrowserItemResult(Device *device, const QString &itemId, const QLocale &locale, QObject *parent, quint32 timeout):
QObject(parent),
m_device(device),
m_itemId(itemId),
m_locale(locale)
{
connect(this, &BrowserItemResult::finished, this, &BrowserItemResult::deleteLater, Qt::QueuedConnection);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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,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 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, quint32 timeout = 0);
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();
void aborted();
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,
@ -74,36 +73,10 @@ public:
DeviceErrorItemNotFound,
DeviceErrorItemNotExecutable,
DeviceErrorUnsupportedFeature,
DeviceErrorTimeout,
};
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 +126,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 +157,5 @@ public:
};
Q_DECLARE_METATYPE(Device::DeviceError)
Q_DECLARE_METATYPE(Device::DeviceSetupStatus)
#endif

View File

@ -0,0 +1,84 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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"
#include <QTimer>
DeviceActionInfo::DeviceActionInfo(Device *device, const Action &action, DeviceManager *parent, quint32 timeout):
QObject(parent),
m_device(device),
m_action(action),
m_deviceManager(parent)
{
connect(this, &DeviceActionInfo::finished, this, &DeviceActionInfo::deleteLater, Qt::QueuedConnection);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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,68 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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, quint32 timeout = 0);
Device* device() const;
Action action() const;
bool isFinished() const;
Device::DeviceError status() const;
QString displayMessage() const;
QString translatedDisplayMessage(const QLocale &locale);
signals:
void finished();
void aborted();
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,99 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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"
#include <QTimer>
DeviceDiscoveryInfo::DeviceDiscoveryInfo(const DeviceClassId &deviceClassId, const ParamList &params, DeviceManager *deviceManager, quint32 timeout):
QObject(deviceManager),
m_deviceClassId(deviceClassId),
m_params(params),
m_deviceManager(deviceManager)
{
connect(this, &DeviceDiscoveryInfo::finished, this, &DeviceDiscoveryInfo::deleteLater, Qt::QueuedConnection);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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,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/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#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, quint32 timeout = 0);
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();
void aborted();
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

@ -33,6 +33,49 @@
#include "types/browseraction.h"
#include "types/browseritemaction.h"
// Signals
/*! \fn void DeviceManager::loaded();
The DeviceManager will emit this signal when all \l{Device}{Devices} are loaded.
*/
/*! \fn void DeviceManager::pluginConfigChanged(const PluginId &id, const ParamList &config);
The DeviceManager will emit this signal when the \a config \l{ParamList}{Params} of the \l{DevicePlugin}{plugin} with the given \a id has changed.
*/
/*! \fn void DeviceManager::deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value);
This signal is emitted when the \l{State} of a \a device changed. The \a stateTypeId parameter describes the
\l{StateType} and the \a value parameter holds the new value.
*/
/*! \fn void DeviceManager::deviceDisappeared(const DeviceId &deviceId);
This signal is emitted when the automatically created \l{Device} with the given \a deviceId dissapeard. This signal will
create the Devices.DeviceRemoved notification.
*/
/*! \fn void DeviceManager::deviceRemoved(const DeviceId &deviceId);
This signal is emitted when the \l{Device} with the given \a deviceId was removed from the system. This signal will
create the Devices.DeviceRemoved notification.
*/
/*! \fn void DeviceManager::deviceAdded(Device *device);
This signal is emitted when a \a \device was added to the system. This signal will
create the Devices.DeviceAdded notification.
*/
/*! \fn void DeviceManager::deviceChanged(Device *device);
This signal is emitted when a \a \device was changed in the system (by edit or rediscover). This signal will
create the Devices.DeviceParamsChanged notification.
*/
/*! \fn void DeviceManager::eventTriggered(const Event &event)
The DeviceManager will emit a \l{Event} described in \a event whenever a Device
creates one. Normally only \l{nymeaserver::NymeaCore} should connect to this and execute actions
after checking back with the \{nymeaserver::RulesEngine}. Exceptions might be monitoring interfaces
or similar, but you should never directly react to this in a \l{DevicePlugin}.
*/
class DeviceManager : public QObject
{
Q_OBJECT
@ -41,6 +84,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 +99,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 +134,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,32 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "devicepairinginfo.h"
#include "devicemanager.h"
DevicePairingInfo::DevicePairingInfo()
#include <QTimer>
DevicePairingInfo::DevicePairingInfo(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const DeviceId &deviceId, const QString &deviceName, const ParamList &params, const DeviceId &parentDeviceId, DeviceManager *parent, quint32 timeout):
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);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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 +54,11 @@ DeviceClassId DevicePairingInfo::deviceClassId() const
return m_deviceClassId;
}
DeviceId DevicePairingInfo::deviceId() const
{
return m_deviceId;
}
QString DevicePairingInfo::deviceName() const
{
return m_deviceName;
@ -58,8 +69,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,55 @@
#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, quint32 timeout = 0);
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();
void aborted();
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

@ -31,50 +31,25 @@
*/
/*! \fn void DevicePlugin::devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &devices);
Emit this signal when the discovery of a \a deviceClassId of this DevicePlugin is finished. The \a devices parameter describes the
list of \l{DeviceDescriptor}{DeviceDescriptors} of all discovered \l{Device}{Devices}.
Note: During a discovery a plugin should always return the full result set. So even if a device is already known to the system and
a later discovery finds the device again, it should be included in the result set but the DeviceDescriptor's deviceId should be set
to the device ID.
\sa discoverDevices()
*/
/*! \fn void DevicePlugin::pairingFinished(const PairingTransactionId &pairingTransactionId, Device::DeviceSetupStatus status);
This signal is emitted when the pairing of a \a pairingTransactionId is finished.
The \a status of the will be described as \l{Device::DeviceError}{DeviceError}.
\sa confirmPairing()
*/
/*! \fn void DevicePlugin::deviceSetupFinished(Device *device, Device::DeviceSetupStatus status);
This signal is emitted when the setup of a \a device in this DevicePlugin is finished. The \a status parameter describes the
\l{Device::DeviceError}{DeviceError} that occurred.
*/
/*! \fn void DevicePlugin::configValueChanged(const ParamTypeId &paramTypeId, const QVariant &value);
This signal is emitted when the \l{Param} with a certain \a paramTypeId of a \l{Device} configuration changed the \a value.
*/
/*! \fn void DevicePlugin::actionExecutionFinished(const ActionId &id, Device::DeviceError status)
This signal is to be emitted when you previously have returned \l{DeviceManager}{DeviceErrorAsync}
in a call of executeAction(). The \a id refers to the executed \l{Action}. The \a status of the \l{Action}
execution will be described as \l{Device::DeviceError}{DeviceError}.
*/
/*! \fn void DevicePlugin::autoDevicesAppeared(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors)
This signal is emitted when a new \l{Device} of certain \a deviceClassId appeared. The description of the \l{Device}{Devices}
will be in \a deviceDescriptors. This signal can only emitted from devices with the \l{DeviceClass}{CreateMethodAuto}.
/*! \fn void DevicePlugin::autoDevicesAppeared(const DeviceDescriptors &deviceDescriptors)
A plugin emits this signal when new \l{Device} appeared. For instance a plugin connected to a bridge might detect
that new devices have been connected to the bridge. Emitting this signal will cause those devices to be added
to the nymea system and setupDevice will be called for them.
*/
/*! \fn void DevicePlugin::autoDeviceDisappeared(const DeviceId &id)
Emit this signal when a device with the given \a id and which was created by \l{DevicePlugin::autoDevicesAppeared} has been removed from the system.
Be careful with this, as this will completely remove the device from the system and with it all the associated rules. Only
emit this if you are sure that a device will never come back. This signal should not be emitted for child auto devices
when the parent who created them is removed. The system will automatically remove all child devices in such a case.
A plugin emits this signal when a device with the given \a id and which was created by \l{DevicePlugin::autoDevicesAppeared}
has been removed from the system. When emitting this signal, nymea will remove the device from the system and with it all the
associated rules and child devices. Because of this, this signal should only be emitted when it's certain that the given device
will never return to be available any more.
*/
/*! \fn void DevicePlugin::emitEvent(const Event &event)
To produce a new event in the system, create a new \l{Event} and emit it with \a event.
To produce a new event in the system, a plugin creates a new \l{Event} and emits this signal it with that \a event.
Usually events are emitted in response to incoming data or other other events happening. Find a configured
\l{Device} from the \l{DeviceManager} and get its \l{EventType}{EventTypes}, then
create a \l{Event} complying to that \l{EventType} and emit it here.
@ -89,6 +64,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"
@ -102,6 +85,7 @@
#include <QCoreApplication>
#include <QJsonArray>
#include <QJsonDocument>
#include <QStandardPaths>
/*! DevicePlugin constructor. DevicePlugins will be instantiated by the DeviceManager, its \a parent. */
DevicePlugin::DevicePlugin(QObject *parent):
@ -161,33 +145,40 @@ void DevicePlugin::startMonitoringAutoDevices()
}
/*! Reimplement this if you support a DeviceClass with createMethod \l{DeviceManager}{CreateMethodDiscovery}.
This will be called to discover Devices for the given \a deviceClassId with the given \a params. This will always
be an async operation. Return \l{DeviceManager}{DeviceErrorAsync} or \l{DeviceManager}{DeviceErrorNoError}
if the discovery has been started successfully. Return an appropriate error otherwise.
Once devices are discovered, emit devicesDiscovered().
/*! A plugin must reimplement this if it supports a DeviceClass with createMethod \l{DeviceManager}{CreateMethodDiscovery}.
When the nymea system needs to discover available devices, this will be called on the plugin. The plugin implementation
is set to discover devices for the \l{DeviceClassId} given in the \a info object.
When devices are discovered, they should be added to the info object by calling \l{DeviceDiscoveryInfo::addDeviceDescriptor}.
Once the discovery is complete a plugin must finish it by calling \l{DeviceDiscoveryInfo::finish} using \l{Device::DeviceErrorNoError}
in case of success, or a matching error code otherwise. An optional display message can be passed optionally which might be shown
to the user, indicating more details about the error. The displayMessage must be made translatable by wrapping it in a QT_TR_NOOP()
statement.
A discovery might be cancelled by nymea. In which case the \l{DeviceDiscoveryInfo::aborted} signal will be emitted.
The info object must not be accessed after \l{DeviceDiscoveryInfo::destroyed} is emitted.
*/
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.
Return \l{DeviceManager}{DeviceSetupStatusFailure} if something bad happened during the setup in which case the \a device
will be disabled. Return \l{DeviceManager}{DeviceSetupStatusSuccess} if everything went well. If you can't tell yet and
need more time to set up the \a device (note: you should never block in this method) you can
return \l{DeviceManager}{DeviceSetupStatusAsync}. In that case the \l{DeviceManager} will wait for you to emit
\l{DevicePlugin}{deviceSetupFinished} to report the status.
/*! This will be called when a new device is created. The plugin can do a setup of the device by reimplementing this method.
The passed \a info object will contain the information about the new \l{Device}. When the setup is completed, a plugin
must finish it by calling \l{DeviceSetupInfo::finish} on the \a info object. In case of success, \{Device::DeviceErrorNoError}
must be used, or an appropriate \l{Device::DeviceError} in case of failure. An optional display message can be passed optionally which might be shown
to the user, indicating more details about the error. The displayMessage must be made translatable by wrapping it in a QT_TR_NOOP()
statement.
A setup might be cancelled by nymea. In which case the \{DeviceSetupInfo::aborted} signal will be emitted.
The info object must not be accessed after \l{DeviceSetupInfo::destroyed} is emitted.
*/
Device::DeviceSetupStatus DevicePlugin::setupDevice(Device *device)
void DevicePlugin::setupDevice(DeviceSetupInfo *info)
{
Q_UNUSED(device)
return Device::DeviceSetupStatusSuccess;
info->finish(Device::DeviceErrorNoError);
}
/*! This will be called when a new \a device was added successfully and the device setup is finished.*/
/*! This will be called when a new \a device was added successfully and the device setup is finished. A plugin can optionally
trigger additional code to operate on the device by reimplementing this method.*/
void DevicePlugin::postSetupDevice(Device *device)
{
Q_UNUSED(device)
@ -202,112 +193,163 @@ 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 must 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
the \{Action} are contained in the \a device and \a action parameters.
Return the appropriate \l{Device::DeviceError}{DeviceError}.
/*! This will be called to execute actions on the device. The given \a info object contains
information about the target \l{Device} and the \l{Action} to be executed.
It is possible to execute actions asynchronously. You never should do anything blocking for
a long time (e.g. wait on a network reply from the internet) but instead return
Device::DeviceErrorAsync and continue processing in an async manner. Once
you have the reply ready, emit actionExecutionFinished() with the appropriate parameters.
When the execution is completed, a plugin must finish it by calling \l{DeviceActionInfo::finish} on the \a info
object. In case of success, \l{Device::DeviceErrorNoError} must be used, or an appropriate \l{Device::DeviceError}
in case of failure. An optional display message can be passed which might be shown
to the user, indicating more details about the error. The displayMessage must be made translatable by wrapping it in a QT_TR_NOOP()
statement.
\sa actionExecutionFinished()
An action execution might be cancelled by nymea. In which case the \l{DeviceActionInfo::aborted} signal will be emitted.
The info object must not be accessed after \l{DeviceActionInfo::destroyed} is emitted.
*/
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).
* When the system calls this method, fill the \a result object's items list with entries from the browser.
* If \a itemId is empty it means that the root node of the file system should be returned. Each item in
* the result set shall be uniquely identifiable using its \l{BrowserItem::id}{id} property.
* The system might call this method again, with an \a itemId returned in a previous query, provided
* that item's \l{BrowserItem::browsable} property is true. In this case all children of the given
* item shall be returned. All browser \l {BrowserItem::displayName} properties shall be localized
* using the given \a locale.
* When done, set the \l{BrowserResult::status}{result's status} field approprietly. Set the result's
* 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)
{
Q_UNUSED(device)
Q_UNUSED(itemId)
Q_UNUSED(locale)
/*! A plugin must implement this if devices support browsing ("browsable" being true in the metadata JSON).
When the system calls this method, the \a result must be filled with entries from the browser using
\l{BrowseResult::addItems}. The \a info object will contain information about which device and which item/node
should be browsed. If the itemId is empty it means that the root node of the file system should be returned otherwise
all the children of the given item/node should be returned.
result.status = Device::DeviceErrorUnsupportedFeature;
return result;
Each item in the result set shall be uniquely identifiable using its \l{BrowserItem::id}{id} property.
The system might call this method again, with an itemId returned in a previous query, provided
that item's \l{BrowserItem::browsable} property is true. In this case all children of the given
item shall be returned. All browser \l{BrowserItem::displayName} properties shall be localized
using the given locale in the \a info object.
If a returned item's \l{BrowserItem::executable} property is set to true, the system might call \l{DevicePlugin::executeBrowserAction}
for this itemId.
An item might have additional actions which must be defined in the plugin metadata JSON as "browserItemActionTypes". Such actions
might be context actions to items in a browser. For instance, a file browser might add copy/cut/paste actions to an item. The
system might call \l{DevicePlugin::executeBrowserItemAction} on such items.
When done, the browse result must be completed by calling \l{BrowserResult::finish} with \l{Device::DeviceErrorNoError}
in case of success or an appropriate \l{Device::DeviceError} otherwise. An optional display message can be passed which might be shown
to the user, indicating more details about the error. The displayMessage must be made translatable by wrapping it in a QT_TR_NOOP()
statement.
*/
void DevicePlugin::browseDevice(BrowseResult *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).
* When the system calls this method, fetch the item details required to create a BrowserItem
* for the item with the given \a id and append that one item to the \a result.
* When done, set the \l{BrowserResult::status}{result's status} field approprietly. Set the result's
* 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)
{
Q_UNUSED(device)
Q_UNUSED(itemId)
Q_UNUSED(locale)
/*! A plugin must implement this if devices support browsing ("browsable" being true in the metadata JSON).
When the system calls this method, the \a result must be filled with a single item identified by the \l{DeviceItemResult::itemId}
using \l{BrowseResult::addItem}. The \a result object will contain information about which device and which item/node
should be browsed. If the itemId is empty it means that the root node of the file system should be returned.
result.status = Device::DeviceErrorUnsupportedFeature;
return result;
Each item in the result set shall be uniquely identifiable using its \l{BrowserItem::id}{id} property. The system might
call this method again, with an itemId returned in a previous query, provided that item's \l{BrowserItem::browsable}
property is true. In this case all children of the given item shall be returned. All browser \l{BrowserItem::displayName} properties shall be localized
using the given locale in the \a info object.
When done, the browse result must be completed by calling \l{BrowserItemResult::finish} with \l{Device::DeviceErrorNoError}
in case of success or an appropriate \l{Device::DeviceError} otherwise. An optional display message can be passed which might be shown
to the user, indicating more details about the error. The displayMessage must be made translatable by wrapping it in a QT_TR_NOOP()
statement.
*/
void DevicePlugin::browserItem(BrowserItemResult *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)
/*! This will be called to execute browser items on the device. For instance, a file browser might execute a file here.
The given \a info object contains information about the target \l{Device} and the \l{BrowserAction} to be executed.
When the execution is completed, a plugin must finish it by calling \l{BrowserActionInfo::finish} on the \a info
object. In case of success, \{Device::DeviceErrorNoError} must be used, or an appropriate \l{Device::DeviceError}
in case of failure. An optional display message can be passed which might be shown
to the user, indicating more details about the error. The displayMessage must be made translatable by wrapping it in a QT_TR_NOOP()
statement.
An action execution might be cancelled by nymea. In which case the \{BrowserActionInfo::aborted} signal will be emitted.
The info object must not be accessed after \l{BrowsereActionInfo::destroyed} is emitted.
*/
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
* in \a browserItemAction.
* Return Device::DeviceErrorAsync if this operation requires async behavior and emit
* \l{browserItemActionExecutionFinished} when done.
*/
Device::DeviceError DevicePlugin::executeBrowserItemAction(Device *device, const BrowserItemAction &browserItemAction)
/*! This will be called to execute browser item actions on the device. For instance a file browser might have
"browserItemActionTypes" defined in the JSON in order to support context options like copy/cut/paste.
The given \a info object contains information about the target \l{Device} and the \l{BrowserItemAction} to be executed.
When the execution is completed, a plugin must finish it by calling \l{BrowserItemActionInfo::finish} on the \a info
object. In case of success, \l{Device::DeviceErrorNoError} must be used, or an appropriate \l{Device::DeviceError}
in case of failure. An optional display message can be passed which might be shown
to the user, indicating more details about the error. The displayMessage must be made translatable by wrapping it in a QT_TR_NOOP()
statement.
An action execution might be cancelled by nymea. In which case the \{BrowserItemActionInfo::aborted} signal will be emitted.
The info object must not be accessed after \l{BrowserItemActionInfo::destroyed} is emitted.
*/
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}. */
@ -316,15 +358,12 @@ ParamTypes DevicePlugin::configurationDescription() const
return m_metaData.pluginSettings();
}
/*! This will be called when the DeviceManager initializes the plugin and set up the things behind the scenes.
When implementing a new plugin, use \l{DevicePlugin::init()} instead in order to do initialisation work.
The \l{DevicePlugin::init()} method will be called once the plugin configuration has been loaded. */
void DevicePlugin::initPlugin(const PluginMetadata &metadata, DeviceManager *deviceManager, HardwareManager *hardwareManager)
{
m_metaData = metadata;
m_deviceManager = deviceManager;
m_hardwareManager = hardwareManager;
m_storage = new QSettings(NymeaSettings::settingsPath() + "/pluginconfig-" + pluginId().toString().remove(QRegExp("[{}]")) + ".conf", QSettings::IniFormat, this);
}
/*! Returns a map containing the plugin configuration.
@ -416,6 +455,14 @@ HardwareManager *DevicePlugin::hardwareManager() const
return m_hardwareManager;
}
/*! Returns a pointer to a QSettings object which is reserved for this plugin.
The plugin can store arbitrary data in this.
*/
QSettings* DevicePlugin::pluginStorage() const
{
return m_storage;
}
void DevicePlugin::setMetaData(const PluginMetadata &metaData)
{
m_metaData = metaData;

View File

@ -42,11 +42,20 @@
#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>
#include <QSettings>
class Device;
class DeviceManager;
class LIBNYMEA_EXPORT DevicePlugin: public QObject
@ -69,21 +78,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,21 +105,14 @@ 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;
HardwareManager *hardwareManager() const;
QSettings *pluginStorage() const;
private:
void setMetaData(const PluginMetadata &metaData);
@ -127,6 +129,7 @@ private:
DeviceManager *m_deviceManager = nullptr;
HardwareManager *m_hardwareManager = nullptr;
QSettings *m_storage = nullptr;
PluginMetadata m_metaData;
ParamList m_config;

View File

@ -0,0 +1,80 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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"
#include <QTimer>
DeviceSetupInfo::DeviceSetupInfo(Device *device, DeviceManager *deviceManager, quint32 timeout):
QObject(deviceManager),
m_device(device),
m_deviecManager(deviceManager)
{
connect(this, &DeviceSetupInfo::finished, this, &DeviceSetupInfo::deleteLater, Qt::QueuedConnection);
if (timeout > 0) {
QTimer::singleShot(timeout, this, [this] {
emit aborted();
finish(Device::DeviceErrorTimeout);
});
}
}
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,63 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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, quint32 timeout = 0);
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();
void aborted();
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

@ -60,6 +60,9 @@ plugininfo_clean.commands = rm -fv $$OUT_PWD/plugininfo.h $$OUT_PWD/extern-plugi
clean.depends = plugininfo_clean
QMAKE_EXTRA_TARGETS += clean plugininfo_clean
# Make sure the plugininfo.h is found in HEADERS for extracting translations
HEADERS += $$OUT_PWD/plugininfo.h
# Install translation files
TRANSLATIONS *= $$files($${_PRO_FILE_PWD_}/translations/*ts, true)
lupdate.depends = FORCE

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)

View File

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

View File

@ -37,10 +37,10 @@ QMAKE_EXTRA_TARGETS += licensecheck
# Translations:
# make lupdate to update .ts files
CORE_TRANSLATIONS += $$files($${top_srcdir}/translations/*.ts, true)
lupdate.commands = lupdate -recursive -no-obsolete $${top_srcdir} -ts $${CORE_TRANSLATIONS};
lupdate.commands = lupdate -no-obsolete -recursive $${top_srcdir}/libnymea $${top_srcdir}/libnymea-core $${top_srcdir}/server $${top_srcdir}/libnymea $${top_srcdir}/tools -ts $${CORE_TRANSLATIONS};
lupdate.commands += make -C plugins/mock plugininfo;
PLUGIN_TRANSLATIONS += $$files($${top_srcdir}/plugins/mock/translations/*.ts, true)
lupdate.commands += lupdate -recursive -no-obsolete $${top_builddir}/plugins/mock/ -ts $${PLUGIN_TRANSLATIONS};
lupdate.commands += lupdate -no-obsolete -recursive $${top_srcdir}/plugins/mock/ $${top_builddir}/plugins/mock/ -ts $${PLUGIN_TRANSLATIONS};
lupdate.depends = FORCE qmake_all
TRANSLATIONS = $${CORE_TRANSLATIONS} $${PLUGIN_TRANSLATIONS}

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

@ -9,7 +9,7 @@
#include <QLoggingCategory>
#include <QObject>
extern "C" const QString libnymea_api_version() { return QString("2.1.0");}
extern "C" const QString libnymea_api_version() { return QString("3.0.0");}
Q_DECLARE_LOGGING_CATEGORY(dcMockDevice)
Q_LOGGING_CATEGORY(dcMockDevice, "MockDevice")
@ -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

@ -1,4 +1,4 @@
2.3
3.0
{
"methods": {
"Actions.ExecuteAction": {
@ -11,7 +11,8 @@
]
},
"returns": {
"deviceError": "$ref:DeviceError"
"deviceError": "$ref:DeviceError",
"o:displayMessage": "String"
}
},
"Actions.ExecuteBrowserItem": {
@ -270,7 +271,8 @@
},
"returns": {
"deviceError": "$ref:DeviceError",
"o:deviceId": "Uuid"
"o:deviceId": "Uuid",
"o:displayMessage": "String"
}
},
"Devices.BrowseDevice": {
@ -287,14 +289,16 @@
}
},
"Devices.ConfirmPairing": {
"description": "Confirm an ongoing pairing. In case of SetupMethodEnterPin also provide the pin in the params.",
"description": "Confirm an ongoing pairing. For SetupMethodUserAndPassword, provide the username in the \"username\" field and the password in the \"secret\" field. For SetupMethodEnterPin and provide the PIN in the \"secret\" field. For SetupMethodOAuth, return the entire unmodified callback URL containing the code parameter back in the secret field.",
"params": {
"o:secret": "String",
"o:username": "String",
"pairingTransactionId": "Uuid"
},
"returns": {
"deviceError": "$ref:DeviceError",
"o:deviceId": "Uuid"
"o:deviceId": "Uuid",
"o:displayMessage": "String"
}
},
"Devices.EditDevice": {
@ -352,7 +356,8 @@
"deviceError": "$ref:DeviceError",
"o:deviceDescriptors": [
"$ref:DeviceDescriptor"
]
],
"o:displayMessage": "String"
}
},
"Devices.GetEventTypes": {
@ -459,6 +464,7 @@
"returns": {
"deviceError": "$ref:DeviceError",
"o:displayMessage": "String",
"o:oAuthUrl": "String",
"o:pairingTransactionId": "Uuid",
"o:setupMethod": "$ref:SetupMethod"
}
@ -473,7 +479,8 @@
]
},
"returns": {
"deviceError": "$ref:DeviceError"
"deviceError": "$ref:DeviceError",
"o:displayMessage": "String"
}
},
"Devices.RemoveConfiguredDevice": {
@ -1523,8 +1530,7 @@
"DeviceErrorSetupMethodNotSupported",
"DeviceErrorHardwareNotAvailable",
"DeviceErrorHardwareFailure",
"DeviceErrorAuthentificationFailure",
"DeviceErrorAsync",
"DeviceErrorAuthenticationFailure",
"DeviceErrorDeviceInUse",
"DeviceErrorDeviceInRule",
"DeviceErrorDeviceIsChild",
@ -1532,7 +1538,8 @@
"DeviceErrorParameterNotWritable",
"DeviceErrorItemNotFound",
"DeviceErrorItemNotExecutable",
"DeviceErrorUnsupportedFeature"
"DeviceErrorUnsupportedFeature",
"DeviceErrorTimeout"
],
"Event": {
"deviceId": "Uuid",
@ -1801,7 +1808,9 @@
"SetupMethodJustAdd",
"SetupMethodDisplayPin",
"SetupMethodEnterPin",
"SetupMethodPushButton"
"SetupMethodPushButton",
"SetupMethodUserAndPassword",
"SetupMethodOAuth"
],
"State": {
"deviceId": "Uuid",

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

@ -25,6 +25,8 @@
#include "logging/logvaluetool.h"
#include "servers/mocktcpserver.h"
#include <qglobal.h>
using namespace nymeaserver;
class TestLogging : public NymeaTestBase
@ -34,6 +36,8 @@ class TestLogging : public NymeaTestBase
private:
private slots:
void initTestCase();
void initLogs();
void databaseSerializationTest_data();
@ -62,6 +66,15 @@ private slots:
void removeDevice();
};
void TestLogging::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\n"
"Tests.debug=true\n"
"MockDevice.debug=true\n"
"DeviceManager.debug=true\n");
}
void TestLogging::initLogs()
{
QVariant response = injectAndWait("Logging.GetLogEntries");
@ -218,6 +231,7 @@ void TestLogging::eventLogs()
QNetworkReply *reply = nam.get(request);
// Lets wait for the notification
QTest::qWait(200);
clientSpy.wait(1000);
reply->deleteLater();
@ -587,6 +601,14 @@ void TestLogging::testHouseKeeping()
restartServer();
// Wait for the mock device to complete the setup
do {
qApp->processEvents();
params.clear();
params.insert("deviceId", m_mockDeviceId);
response = injectAndWait("Devices.GetConfiguredDevices", params);
} while (!response.toMap().value("params").toMap().value("devices").toList().first().toMap().value("setupComplete").toBool());
response = injectAndWait("Logging.GetLogEntries", params);
QVERIFY2(response.toMap().value("params").toMap().value("logEntries").toList().count() == 0, "Device state change event still in log. Should've been cleaned by housekeeping.");
}

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

@ -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");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff