Add better device setup status details to api
This commit is contained in:
parent
3015130c8f
commit
6e4a0bc84b
@ -436,7 +436,7 @@ DeviceSetupInfo *DeviceManagerImplementation::reconfigureDeviceInternal(Device *
|
|||||||
plugin->deviceRemoved(device);
|
plugin->deviceRemoved(device);
|
||||||
|
|
||||||
// mark setup as incomplete
|
// mark setup as incomplete
|
||||||
device->setSetupComplete(false);
|
device->setSetupStatus(Device::DeviceSetupStatusInProgress, Device::DeviceErrorNoError);
|
||||||
|
|
||||||
// set new params
|
// set new params
|
||||||
foreach (const Param ¶m, params) {
|
foreach (const Param ¶m, params) {
|
||||||
@ -454,6 +454,7 @@ DeviceSetupInfo *DeviceManagerImplementation::reconfigureDeviceInternal(Device *
|
|||||||
|
|
||||||
if (info->status() != Device::DeviceErrorNoError) {
|
if (info->status() != Device::DeviceErrorNoError) {
|
||||||
qCWarning(dcDeviceManager()) << "Device reconfiguration failed for" << info->device()->name() << info->device()->id().toString() << info->status() << info->displayMessage();
|
qCWarning(dcDeviceManager()) << "Device reconfiguration failed for" << info->device()->name() << info->device()->id().toString() << info->status() << info->displayMessage();
|
||||||
|
info->device()->setSetupStatus(Device::DeviceSetupStatusFailed, info->status(), info->displayMessage());
|
||||||
// TODO: recover old params.??
|
// TODO: recover old params.??
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -461,7 +462,7 @@ DeviceSetupInfo *DeviceManagerImplementation::reconfigureDeviceInternal(Device *
|
|||||||
storeConfiguredDevices();
|
storeConfiguredDevices();
|
||||||
|
|
||||||
postSetupDevice(info->device());
|
postSetupDevice(info->device());
|
||||||
info->device()->setupCompleted();
|
info->device()->setSetupStatus(Device::DeviceSetupStatusComplete, Device::DeviceErrorNoError);
|
||||||
|
|
||||||
emit deviceChanged(info->device());
|
emit deviceChanged(info->device());
|
||||||
|
|
||||||
@ -640,7 +641,7 @@ DevicePairingInfo *DeviceManagerImplementation::confirmPairing(const PairingTran
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
device = m_configuredDevices.value(internalInfo->deviceId());
|
device = m_configuredDevices.value(internalInfo->deviceId());
|
||||||
device->setSetupComplete(false);
|
device->setSetupStatus(Device::DeviceSetupStatusInProgress, Device::DeviceErrorNoError);
|
||||||
qCDebug(dcDeviceManager()) << "Reconfiguring device" << device;
|
qCDebug(dcDeviceManager()) << "Reconfiguring device" << device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,10 +655,17 @@ DevicePairingInfo *DeviceManagerImplementation::confirmPairing(const PairingTran
|
|||||||
externalInfo->finish(info->status(), info->displayMessage());
|
externalInfo->finish(info->status(), info->displayMessage());
|
||||||
|
|
||||||
if (info->status() != Device::DeviceErrorNoError) {
|
if (info->status() != Device::DeviceErrorNoError) {
|
||||||
qCWarning(dcDeviceManager()) << "Failed to set up device" << info->device()->name() << info->status() << info->displayMessage();
|
if (addNewDevice) {
|
||||||
info->device()->deleteLater();
|
qCWarning(dcDeviceManager()) << "Failed to set up device" << info->device()->name()
|
||||||
|
<< "Not adding device to the system. Error:"
|
||||||
|
<< info->status() << info->displayMessage();
|
||||||
|
info->device()->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
if (!addNewDevice) {
|
if (!addNewDevice) {
|
||||||
|
qCWarning(dcDeviceManager()) << "Failed to reconfigure device" << info->device()->name() <<
|
||||||
|
"Error:" << info->status() << info->displayMessage();
|
||||||
|
info->device()->setSetupStatus(Device::DeviceSetupStatusFailed, info->status(), info->displayMessage());
|
||||||
// TODO: restore parameters?
|
// TODO: restore parameters?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,7 +673,7 @@ DevicePairingInfo *DeviceManagerImplementation::confirmPairing(const PairingTran
|
|||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcDeviceManager()) << "Setup complete for device" << info->device();
|
qCDebug(dcDeviceManager()) << "Setup complete for device" << info->device();
|
||||||
info->device()->setupCompleted();
|
info->device()->setSetupStatus(Device::DeviceSetupStatusComplete, Device::DeviceErrorNoError);
|
||||||
|
|
||||||
if (addNewDevice) {
|
if (addNewDevice) {
|
||||||
qCDebug(dcDeviceManager()) << "Device added:" << info->device();
|
qCDebug(dcDeviceManager()) << "Device added:" << info->device();
|
||||||
@ -749,7 +757,7 @@ DeviceSetupInfo* DeviceManagerImplementation::addConfiguredDeviceInternal(const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->device()->setupCompleted();
|
info->device()->setSetupStatus(Device::DeviceSetupStatusComplete, Device::DeviceErrorNoError);
|
||||||
|
|
||||||
qCDebug(dcDeviceManager) << "Device setup complete.";
|
qCDebug(dcDeviceManager) << "Device setup complete.";
|
||||||
m_configuredDevices.insert(info->device()->id(), info->device());
|
m_configuredDevices.insert(info->device()->id(), info->device());
|
||||||
@ -1062,7 +1070,25 @@ void DeviceManagerImplementation::loadPlugins()
|
|||||||
if (!fi.exists())
|
if (!fi.exists())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Check plugin API version compatibility
|
||||||
|
QLibrary lib(fi.absoluteFilePath());
|
||||||
|
QFunctionPointer versionFunc = lib.resolve("libnymea_api_version");
|
||||||
|
if (!versionFunc) {
|
||||||
|
qCWarning(dcDeviceManager()).nospace() << "Unable to resolve version in plugin " << entry << ". Not loading plugin.";
|
||||||
|
lib.unload();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString version = reinterpret_cast<QString(*)()>(versionFunc)();
|
||||||
|
lib.unload();
|
||||||
|
QStringList parts = version.split('.');
|
||||||
|
QStringList coreParts = QString(LIBNYMEA_API_VERSION).split('.');
|
||||||
|
if (parts.length() != 3 || parts.at(0).toInt() != coreParts.at(0).toInt() || parts.at(1).toInt() > coreParts.at(1).toInt()) {
|
||||||
|
qCWarning(dcDeviceManager()).nospace() << "Libnymea API mismatch for " << entry << ". Core API: " << LIBNYMEA_API_VERSION << ", Plugin API: " << version;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version is ok. Now load the plugin
|
||||||
QPluginLoader loader;
|
QPluginLoader loader;
|
||||||
loader.setFileName(fi.absoluteFilePath());
|
loader.setFileName(fi.absoluteFilePath());
|
||||||
loader.setLoadHints(QLibrary::ResolveAllSymbolsHint);
|
loader.setLoadHints(QLibrary::ResolveAllSymbolsHint);
|
||||||
@ -1073,29 +1099,6 @@ void DeviceManagerImplementation::loadPlugins()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check plugin API version compatibility
|
|
||||||
QLibrary lib(fi.absoluteFilePath());
|
|
||||||
QFunctionPointer versionFunc = lib.resolve("libnymea_api_version");
|
|
||||||
if (!versionFunc) {
|
|
||||||
qCWarning(dcDeviceManager()).nospace() << "Unable to resolve version in plugin " << entry << ". Not loading plugin.";
|
|
||||||
loader.unload();
|
|
||||||
lib.unload();
|
|
||||||
continue;
|
|
||||||
|
|
||||||
}
|
|
||||||
QString version = reinterpret_cast<QString(*)()>(versionFunc)();
|
|
||||||
// QString *version = reinterpret_cast<QString*>(lib.resolve("libnymea_api_version"));
|
|
||||||
// if (!version) {
|
|
||||||
// }
|
|
||||||
lib.unload();
|
|
||||||
QStringList parts = version.split('.');
|
|
||||||
QStringList coreParts = QString(LIBNYMEA_API_VERSION).split('.');
|
|
||||||
if (parts.length() != 3 || parts.at(0).toInt() != coreParts.at(0).toInt() || parts.at(1).toInt() > coreParts.at(1).toInt()) {
|
|
||||||
qCWarning(dcDeviceManager()).nospace() << "Libnymea API mismatch for " << entry << ". Core API: " << LIBNYMEA_API_VERSION << ", Plugin API: " << version;
|
|
||||||
loader.unload();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginMetadata metaData(loader.metaData().value("MetaData").toObject());
|
PluginMetadata metaData(loader.metaData().value("MetaData").toObject());
|
||||||
if (!metaData.isValid()) {
|
if (!metaData.isValid()) {
|
||||||
foreach (const QString &error, metaData.validationErrors()) {
|
foreach (const QString &error, metaData.validationErrors()) {
|
||||||
@ -1357,6 +1360,7 @@ void DeviceManagerImplementation::loadConfiguredDevices()
|
|||||||
}
|
}
|
||||||
Q_ASSERT(device != nullptr);
|
Q_ASSERT(device != nullptr);
|
||||||
|
|
||||||
|
device->setSetupStatus(Device::DeviceSetupStatusInProgress, Device::DeviceErrorNoError);
|
||||||
DeviceSetupInfo *info = setupDevice(device);
|
DeviceSetupInfo *info = setupDevice(device);
|
||||||
// Set receiving object to "device" because at startup we load it in any case, knowing that it worked at
|
// Set receiving object to "device" because at startup we load it in any case, knowing that it worked at
|
||||||
// some point. However, it'll be marked as non-working until the setup succeeds so the user might delete
|
// some point. However, it'll be marked as non-working until the setup succeeds so the user might delete
|
||||||
@ -1365,11 +1369,14 @@ void DeviceManagerImplementation::loadConfiguredDevices()
|
|||||||
|
|
||||||
if (info->status() != Device::DeviceErrorNoError) {
|
if (info->status() != Device::DeviceErrorNoError) {
|
||||||
qCWarning(dcDeviceManager()) << "Error setting up device" << info->device()->name() << info->device()->id().toString() << info->status() << info->displayMessage();
|
qCWarning(dcDeviceManager()) << "Error setting up device" << info->device()->name() << info->device()->id().toString() << info->status() << info->displayMessage();
|
||||||
|
info->device()->setSetupStatus(Device::DeviceSetupStatusFailed, info->status(), info->displayMessage());
|
||||||
|
emit deviceChanged(info->device());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcDeviceManager()) << "Setup complete for device" << info->device();
|
qCDebug(dcDeviceManager()) << "Setup complete for device" << info->device();
|
||||||
info->device()->setupCompleted();
|
info->device()->setSetupStatus(Device::DeviceSetupStatusComplete, Device::DeviceErrorNoError);
|
||||||
|
emit deviceChanged(info->device());
|
||||||
postSetupDevice(info->device());
|
postSetupDevice(info->device());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1475,7 +1482,7 @@ void DeviceManagerImplementation::onAutoDevicesAppeared(const DeviceDescriptors
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->device()->setupCompleted();
|
info->device()->setSetupStatus(Device::DeviceSetupStatusComplete, Device::DeviceErrorNoError);
|
||||||
m_configuredDevices.insert(info->device()->id(), info->device());
|
m_configuredDevices.insert(info->device()->id(), info->device());
|
||||||
storeConfiguredDevices();
|
storeConfiguredDevices();
|
||||||
|
|
||||||
|
|||||||
@ -88,6 +88,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
|
|||||||
{
|
{
|
||||||
// Enums
|
// Enums
|
||||||
registerEnum<Device::DeviceError>();
|
registerEnum<Device::DeviceError>();
|
||||||
|
registerEnum<Device::DeviceSetupStatus>();
|
||||||
registerEnum<DeviceClass::SetupMethod>();
|
registerEnum<DeviceClass::SetupMethod>();
|
||||||
registerEnum<DeviceClass::CreateMethod, DeviceClass::CreateMethods>();
|
registerEnum<DeviceClass::CreateMethod, DeviceClass::CreateMethods>();
|
||||||
registerEnum<Types::Unit>();
|
registerEnum<Types::Unit>();
|
||||||
@ -374,7 +375,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
|
|||||||
registerNotification("DeviceAdded", description, params);
|
registerNotification("DeviceAdded", description, params);
|
||||||
|
|
||||||
params.clear(); returns.clear();
|
params.clear(); returns.clear();
|
||||||
description = "Emitted whenever the params or name of a Device are changed (by EditDevice or ReconfigureDevice).";
|
description = "Emitted whenever the params, name or setupStatus of a Device changes.";
|
||||||
params.insert("device", objectRef<Device>());
|
params.insert("device", objectRef<Device>());
|
||||||
registerNotification("DeviceChanged", description, params);
|
registerNotification("DeviceChanged", description, params);
|
||||||
|
|
||||||
@ -627,7 +628,7 @@ JsonReply *DeviceHandler::ConfirmPairing(const QVariantMap ¶ms, const JsonCo
|
|||||||
return jsonReply;
|
return jsonReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap ¶ms) const
|
JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap ¶ms, const JsonContext &context) const
|
||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
QVariantList configuredDeviceList;
|
QVariantList configuredDeviceList;
|
||||||
@ -641,7 +642,12 @@ JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap ¶ms) const
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
foreach (Device *device, NymeaCore::instance()->deviceManager()->configuredDevices()) {
|
foreach (Device *device, NymeaCore::instance()->deviceManager()->configuredDevices()) {
|
||||||
configuredDeviceList.append(pack(device));
|
QVariantMap packedDevice = pack(device).toMap();
|
||||||
|
QString translatedSetupStatus = NymeaCore::instance()->deviceManager()->translate(device->pluginId(), device->setupDisplayMessage(), context.locale());
|
||||||
|
if (!translatedSetupStatus.isEmpty()) {
|
||||||
|
packedDevice["setupDisplayMessage"] = translatedSetupStatus;
|
||||||
|
}
|
||||||
|
configuredDeviceList.append(packedDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
returns.insert("devices", configuredDeviceList);
|
returns.insert("devices", configuredDeviceList);
|
||||||
@ -977,6 +983,25 @@ void DeviceHandler::deviceSettingChangedNotification(const DeviceId deviceId, co
|
|||||||
emit DeviceSettingChanged(params);
|
emit DeviceSettingChanged(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantMap DeviceHandler::translateNotification(const QString ¬ification, const QVariantMap ¶ms, const QLocale &locale)
|
||||||
|
{
|
||||||
|
if (notification == "DeviceChanged") {
|
||||||
|
QVariantMap deviceMap = params.value("device").toMap();
|
||||||
|
DeviceId deviceId = params.value("device").toMap().value("id").toUuid();
|
||||||
|
Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(deviceId);
|
||||||
|
QString setupDisplayMessage = params.value("device").toMap().value("setupDisplayMessage").toString();
|
||||||
|
QString translatedSetupDisplayMessage = NymeaCore::instance()->deviceManager()->translate(device->pluginId(), setupDisplayMessage, locale);
|
||||||
|
if (!translatedSetupDisplayMessage.isEmpty()) {
|
||||||
|
deviceMap["setupDisplayMessage"] = translatedSetupDisplayMessage;
|
||||||
|
}
|
||||||
|
QVariantMap translatedParams = params;
|
||||||
|
translatedParams["device"] = deviceMap;
|
||||||
|
return translatedParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap DeviceHandler::statusToReply(Device::DeviceError status) const
|
QVariantMap DeviceHandler::statusToReply(Device::DeviceError status) const
|
||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
|
|||||||
@ -43,6 +43,7 @@ public:
|
|||||||
explicit DeviceHandler(QObject *parent = nullptr);
|
explicit DeviceHandler(QObject *parent = nullptr);
|
||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
|
QVariantMap translateNotification(const QString ¬ification, const QVariantMap ¶ms, const QLocale &locale) override;
|
||||||
|
|
||||||
Q_INVOKABLE JsonReply *GetSupportedVendors(const QVariantMap ¶ms, const JsonContext &context) const;
|
Q_INVOKABLE JsonReply *GetSupportedVendors(const QVariantMap ¶ms, const JsonContext &context) const;
|
||||||
Q_INVOKABLE JsonReply *GetSupportedDevices(const QVariantMap ¶ms, const JsonContext &context) const;
|
Q_INVOKABLE JsonReply *GetSupportedDevices(const QVariantMap ¶ms, const JsonContext &context) const;
|
||||||
@ -54,7 +55,7 @@ public:
|
|||||||
Q_INVOKABLE JsonReply *AddConfiguredDevice(const QVariantMap ¶ms, const JsonContext &context);
|
Q_INVOKABLE JsonReply *AddConfiguredDevice(const QVariantMap ¶ms, const JsonContext &context);
|
||||||
Q_INVOKABLE JsonReply *PairDevice(const QVariantMap ¶ms, const JsonContext &context);
|
Q_INVOKABLE JsonReply *PairDevice(const QVariantMap ¶ms, const JsonContext &context);
|
||||||
Q_INVOKABLE JsonReply *ConfirmPairing(const QVariantMap ¶ms, const JsonContext &context);
|
Q_INVOKABLE JsonReply *ConfirmPairing(const QVariantMap ¶ms, const JsonContext &context);
|
||||||
Q_INVOKABLE JsonReply *GetConfiguredDevices(const QVariantMap ¶ms) const;
|
Q_INVOKABLE JsonReply *GetConfiguredDevices(const QVariantMap ¶ms, const JsonContext &context) const;
|
||||||
Q_INVOKABLE JsonReply *ReconfigureDevice(const QVariantMap ¶ms, const JsonContext &context);
|
Q_INVOKABLE JsonReply *ReconfigureDevice(const QVariantMap ¶ms, const JsonContext &context);
|
||||||
Q_INVOKABLE JsonReply *EditDevice(const QVariantMap ¶ms);
|
Q_INVOKABLE JsonReply *EditDevice(const QVariantMap ¶ms);
|
||||||
Q_INVOKABLE JsonReply *RemoveConfiguredDevice(const QVariantMap ¶ms);
|
Q_INVOKABLE JsonReply *RemoveConfiguredDevice(const QVariantMap ¶ms);
|
||||||
|
|||||||
@ -738,26 +738,11 @@ void JsonRPCServerImplementation::sendNotification(const QVariantMap ¶ms)
|
|||||||
JsonHandler *handler = qobject_cast<JsonHandler *>(sender());
|
JsonHandler *handler = qobject_cast<JsonHandler *>(sender());
|
||||||
QMetaMethod method = handler->metaObject()->method(senderSignalIndex());
|
QMetaMethod method = handler->metaObject()->method(senderSignalIndex());
|
||||||
|
|
||||||
QList<QUuid> clientsToBeNotified;
|
|
||||||
foreach (const QUuid &clientId, m_clientNotifications.keys()) {
|
|
||||||
if (m_clientNotifications.value(clientId).contains(handler->name())) {
|
|
||||||
clientsToBeNotified.append(clientId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clientsToBeNotified.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap notification;
|
QVariantMap notification;
|
||||||
notification.insert("id", m_notificationId++);
|
notification.insert("id", m_notificationId++);
|
||||||
notification.insert("notification", handler->name() + "." + method.name());
|
notification.insert("notification", handler->name() + "." + method.name());
|
||||||
notification.insert("params", params);
|
|
||||||
|
|
||||||
JsonValidator validator;
|
|
||||||
Q_ASSERT_X(validator.validateNotificationParams(params, handler->name() + '.' + method.name(), m_api).success(),
|
|
||||||
validator.result().where().toUtf8(),
|
|
||||||
validator.result().errorString().toUtf8() + "\nGot:" + QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented));
|
|
||||||
|
|
||||||
|
// Add deprecation warning if necessary
|
||||||
if (m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().contains("deprecated")) {
|
if (m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().contains("deprecated")) {
|
||||||
QString deprecationMessage = m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().value("deprecated").toString();
|
QString deprecationMessage = m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().value("deprecated").toString();
|
||||||
qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!";
|
qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!";
|
||||||
@ -765,11 +750,28 @@ void JsonRPCServerImplementation::sendNotification(const QVariantMap ¶ms)
|
|||||||
notification.insert("deprecationWarning", deprecationMessage);
|
notification.insert("deprecationWarning", deprecationMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray data = QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact);
|
foreach (const QUuid &clientId, m_clientNotifications.keys()) {
|
||||||
qCDebug(dcJsonRpcTraffic()) << "Notification content:" << data;
|
|
||||||
|
// Check if this client wants to be notified
|
||||||
|
if (!m_clientNotifications.value(clientId).contains(handler->name())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLocale locale = m_clientLocales.value(clientId);
|
||||||
|
QVariantMap translatedParams = handler->translateNotification(method.name(), params, locale);
|
||||||
|
|
||||||
|
JsonValidator validator;
|
||||||
|
Q_ASSERT_X(validator.validateNotificationParams(translatedParams, handler->name() + '.' + method.name(), m_api).success(),
|
||||||
|
validator.result().where().toUtf8(),
|
||||||
|
validator.result().errorString().toUtf8() + "\nGot:" + QJsonDocument::fromVariant(translatedParams).toJson(QJsonDocument::Indented));
|
||||||
|
|
||||||
|
notification.insert("params", translatedParams);
|
||||||
|
|
||||||
|
QByteArray data = QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
qCDebug(dcJsonRpc()) << "Sending notification" << handler->name() + "." + method.name() << "to client" << clientId;
|
||||||
|
qCDebug(dcJsonRpcTraffic()) << "Notification content:" << data;
|
||||||
|
|
||||||
foreach (const QUuid &clientId, clientsToBeNotified) {
|
|
||||||
qCDebug(dcJsonRpc()) << "Sending notification:" << handler->name() + "." + method.name();
|
|
||||||
m_clientTransports.value(clientId)->sendData(clientId, data);
|
m_clientTransports.value(clientId)->sendData(clientId, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,7 +122,7 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QString trimmedKey = key;
|
QString trimmedKey = key;
|
||||||
trimmedKey.remove(QRegExp("^(o:|r:|d:)"));
|
trimmedKey.remove(QRegExp("^(o:|r:|d:)*"));
|
||||||
if (!map.contains(trimmedKey)) {
|
if (!map.contains(trimmedKey)) {
|
||||||
return Result(false, "Missing required key: " + key, key);
|
return Result(false, "Missing required key: " + key, key);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -138,11 +138,6 @@ Device::Device(DevicePlugin *plugin, const DeviceClass &deviceClass, QObject *pa
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::setupCompleted()
|
|
||||||
{
|
|
||||||
m_setupComplete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Returns the id of this Device. */
|
/*! Returns the id of this Device. */
|
||||||
DeviceId Device::id() const
|
DeviceId Device::id() const
|
||||||
{
|
{
|
||||||
@ -366,10 +361,16 @@ void Device::setParentId(const DeviceId &parentId)
|
|||||||
m_parentId = parentId;
|
m_parentId = parentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns true, if setup of this Device is already completed. */
|
/*! Returns true, if setup of this Device is already completed. This method is deprecated, use setupStatus() instead. */
|
||||||
bool Device::setupComplete() const
|
bool Device::setupComplete() const
|
||||||
{
|
{
|
||||||
return m_setupComplete;
|
return m_setupStatus == DeviceSetupStatusComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Returns the setup error display message, if any. */
|
||||||
|
QString Device::setupDisplayMessage() const
|
||||||
|
{
|
||||||
|
return m_setupDisplayMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns true if this device has been auto-created (not created by the user) */
|
/*! Returns true if this device has been auto-created (not created by the user) */
|
||||||
@ -378,9 +379,23 @@ bool Device::autoCreated() const
|
|||||||
return m_autoCreated;
|
return m_autoCreated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::setSetupComplete(bool complete)
|
/* Returns the current device setup status. */
|
||||||
|
Device::DeviceSetupStatus Device::setupStatus() const
|
||||||
{
|
{
|
||||||
m_setupComplete = complete;
|
return m_setupStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::DeviceError Device::setupError() const
|
||||||
|
{
|
||||||
|
return m_setupError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setSetupStatus(Device::DeviceSetupStatus status, Device::DeviceError setupError, const QString &displayMessage)
|
||||||
|
{
|
||||||
|
m_setupStatus = status;
|
||||||
|
m_setupError = setupError;
|
||||||
|
m_setupDisplayMessage = displayMessage;
|
||||||
|
emit setupStatusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Devices::Devices(const QList<Device*> &other)
|
Devices::Devices(const QList<Device*> &other)
|
||||||
|
|||||||
@ -50,12 +50,15 @@ class LIBNYMEA_EXPORT Device: public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QUuid id READ id)
|
Q_PROPERTY(QUuid id READ id)
|
||||||
Q_PROPERTY(QUuid deviceClassId READ deviceClassId)
|
Q_PROPERTY(QUuid deviceClassId READ deviceClassId)
|
||||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged USER true)
|
||||||
Q_PROPERTY(ParamList params READ params WRITE setParams)
|
Q_PROPERTY(ParamList params READ params)
|
||||||
Q_PROPERTY(ParamList settings READ settings WRITE setSettings)
|
Q_PROPERTY(ParamList settings READ settings WRITE setSettings USER true)
|
||||||
Q_PROPERTY(States states READ states WRITE setStates)
|
Q_PROPERTY(States states READ states)
|
||||||
Q_PROPERTY(bool setupComplete READ setupComplete WRITE setSetupComplete)
|
Q_PROPERTY(bool setupComplete READ setupComplete NOTIFY setupStatusChanged REVISION 1)
|
||||||
Q_PROPERTY(QUuid parentId READ parentId WRITE setParentId USER true)
|
Q_PROPERTY(DeviceSetupStatus setupStatus READ setupStatus NOTIFY setupStatusChanged)
|
||||||
|
Q_PROPERTY(QString setupDisplayMessage READ setupDisplayMessage NOTIFY setupStatusChanged USER true)
|
||||||
|
Q_PROPERTY(DeviceError setupError READ setupError NOTIFY setupStatusChanged)
|
||||||
|
Q_PROPERTY(QUuid parentId READ parentId USER true)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DeviceError {
|
enum DeviceError {
|
||||||
@ -89,6 +92,14 @@ public:
|
|||||||
};
|
};
|
||||||
Q_ENUM(DeviceError)
|
Q_ENUM(DeviceError)
|
||||||
|
|
||||||
|
enum DeviceSetupStatus {
|
||||||
|
DeviceSetupStatusNone,
|
||||||
|
DeviceSetupStatusInProgress,
|
||||||
|
DeviceSetupStatusComplete,
|
||||||
|
DeviceSetupStatusFailed,
|
||||||
|
};
|
||||||
|
Q_ENUM(DeviceSetupStatus)
|
||||||
|
|
||||||
DeviceId id() const;
|
DeviceId id() const;
|
||||||
DeviceClassId deviceClassId() const;
|
DeviceClassId deviceClassId() const;
|
||||||
PluginId pluginId() const;
|
PluginId pluginId() const;
|
||||||
@ -125,13 +136,19 @@ public:
|
|||||||
DeviceId parentId() const;
|
DeviceId parentId() const;
|
||||||
void setParentId(const DeviceId &parentId);
|
void setParentId(const DeviceId &parentId);
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
bool setupComplete() const;
|
bool setupComplete() const;
|
||||||
bool autoCreated() const;
|
bool autoCreated() const;
|
||||||
|
|
||||||
|
DeviceSetupStatus setupStatus() const;
|
||||||
|
DeviceError setupError() const;
|
||||||
|
QString setupDisplayMessage() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void stateValueChanged(const StateTypeId &stateTypeId, const QVariant &value);
|
void stateValueChanged(const StateTypeId &stateTypeId, const QVariant &value);
|
||||||
void settingChanged(const ParamTypeId ¶mTypeId, const QVariant &value);
|
void settingChanged(const ParamTypeId ¶mTypeId, const QVariant &value);
|
||||||
void nameChanged();
|
void nameChanged();
|
||||||
|
void setupStatusChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DeviceManager;
|
friend class DeviceManager;
|
||||||
@ -139,8 +156,7 @@ private:
|
|||||||
Device(DevicePlugin *plugin, const DeviceClass &deviceClass, const DeviceId &id, QObject *parent = nullptr);
|
Device(DevicePlugin *plugin, const DeviceClass &deviceClass, const DeviceId &id, QObject *parent = nullptr);
|
||||||
Device(DevicePlugin *plugin, const DeviceClass &deviceClass, QObject *parent = nullptr);
|
Device(DevicePlugin *plugin, const DeviceClass &deviceClass, QObject *parent = nullptr);
|
||||||
|
|
||||||
void setupCompleted();
|
void setSetupStatus(Device::DeviceSetupStatus status, Device::DeviceError setupError, const QString &displayMessage = QString());
|
||||||
void setSetupComplete(bool complete);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeviceClass m_deviceClass;
|
DeviceClass m_deviceClass;
|
||||||
@ -152,8 +168,11 @@ private:
|
|||||||
ParamList m_params;
|
ParamList m_params;
|
||||||
ParamList m_settings;
|
ParamList m_settings;
|
||||||
States m_states;
|
States m_states;
|
||||||
bool m_setupComplete = false;
|
|
||||||
bool m_autoCreated = false;
|
bool m_autoCreated = false;
|
||||||
|
|
||||||
|
DeviceSetupStatus m_setupStatus = DeviceSetupStatusNone;
|
||||||
|
DeviceError m_setupError = DeviceErrorNoError;
|
||||||
|
QString m_setupDisplayMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
QDebug operator<<(QDebug dbg, Device *device);
|
QDebug operator<<(QDebug dbg, Device *device);
|
||||||
|
|||||||
@ -41,6 +41,13 @@ JsonHandler::JsonHandler(QObject *parent) : QObject(parent)
|
|||||||
registerEnum<BasicType>();
|
registerEnum<BasicType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantMap JsonHandler::translateNotification(const QString ¬ification, const QVariantMap ¶ms, const QLocale &locale)
|
||||||
|
{
|
||||||
|
Q_UNUSED(notification)
|
||||||
|
Q_UNUSED(locale)
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap JsonHandler::jsonEnums() const
|
QVariantMap JsonHandler::jsonEnums() const
|
||||||
{
|
{
|
||||||
return m_enums;
|
return m_enums;
|
||||||
@ -186,6 +193,9 @@ void JsonHandler::registerObject(const QMetaObject &metaObject)
|
|||||||
if (!metaProperty.isWritable()) {
|
if (!metaProperty.isWritable()) {
|
||||||
name.prepend("r:");
|
name.prepend("r:");
|
||||||
}
|
}
|
||||||
|
if (metaProperty.revision() == 1) {
|
||||||
|
name.prepend("d:");
|
||||||
|
}
|
||||||
QVariant typeName;
|
QVariant typeName;
|
||||||
if (metaProperty.type() == QVariant::UserType) {
|
if (metaProperty.type() == QVariant::UserType) {
|
||||||
if (metaProperty.typeName() == QStringLiteral("QVariant::Type")) {
|
if (metaProperty.typeName() == QStringLiteral("QVariant::Type")) {
|
||||||
|
|||||||
@ -65,6 +65,8 @@ public:
|
|||||||
|
|
||||||
virtual QString name() const = 0;
|
virtual QString name() const = 0;
|
||||||
|
|
||||||
|
virtual QVariantMap translateNotification(const QString ¬ification, const QVariantMap ¶ms, const QLocale &locale);
|
||||||
|
|
||||||
QVariantMap jsonEnums() const;
|
QVariantMap jsonEnums() const;
|
||||||
QVariantMap jsonFlags() const;
|
QVariantMap jsonFlags() const;
|
||||||
QVariantMap jsonObjects() const;
|
QVariantMap jsonObjects() const;
|
||||||
|
|||||||
@ -76,6 +76,12 @@
|
|||||||
"DeviceErrorUnsupportedFeature",
|
"DeviceErrorUnsupportedFeature",
|
||||||
"DeviceErrorTimeout"
|
"DeviceErrorTimeout"
|
||||||
],
|
],
|
||||||
|
"DeviceSetupStatus": [
|
||||||
|
"DeviceSetupStatusNone",
|
||||||
|
"DeviceSetupStatusInProgress",
|
||||||
|
"DeviceSetupStatusComplete",
|
||||||
|
"DeviceSetupStatusFailed"
|
||||||
|
],
|
||||||
"InputType": [
|
"InputType": [
|
||||||
"InputTypeNone",
|
"InputTypeNone",
|
||||||
"InputTypeTextLine",
|
"InputTypeTextLine",
|
||||||
@ -1609,7 +1615,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Devices.DeviceChanged": {
|
"Devices.DeviceChanged": {
|
||||||
"description": "Emitted whenever the params or name of a Device are changed (by EditDevice or ReconfigureDevice).",
|
"description": "Emitted whenever the params, name or setupStatus of a Device changes.",
|
||||||
"params": {
|
"params": {
|
||||||
"device": "$ref:Device"
|
"device": "$ref:Device"
|
||||||
}
|
}
|
||||||
@ -1904,14 +1910,17 @@
|
|||||||
"$ref:CalendarItem"
|
"$ref:CalendarItem"
|
||||||
],
|
],
|
||||||
"Device": {
|
"Device": {
|
||||||
"name": "String",
|
"d:r:setupComplete": "Bool",
|
||||||
"o:parentId": "Uuid",
|
"o:name": "String",
|
||||||
"params": "$ref:ParamList",
|
"o:settings": "$ref:ParamList",
|
||||||
"r:deviceClassId": "Uuid",
|
"r:deviceClassId": "Uuid",
|
||||||
"r:id": "Uuid",
|
"r:id": "Uuid",
|
||||||
"settings": "$ref:ParamList",
|
"r:o:parentId": "Uuid",
|
||||||
"setupComplete": "Bool",
|
"r:o:setupDisplayMessage": "String",
|
||||||
"states": "$ref:States"
|
"r:params": "$ref:ParamList",
|
||||||
|
"r:setupError": "$ref:DeviceError",
|
||||||
|
"r:setupStatus": "$ref:DeviceSetupStatus",
|
||||||
|
"r:states": "$ref:States"
|
||||||
},
|
},
|
||||||
"DeviceClass": {
|
"DeviceClass": {
|
||||||
"r:actionTypes": "$ref:ActionTypes",
|
"r:actionTypes": "$ref:ActionTypes",
|
||||||
|
|||||||
@ -136,6 +136,8 @@ private slots:
|
|||||||
|
|
||||||
void params();
|
void params();
|
||||||
|
|
||||||
|
void asyncSetupEmitsSetupStatusUpdate();
|
||||||
|
|
||||||
// Keep those at last as they will remove devices
|
// Keep those at last as they will remove devices
|
||||||
void removeDevice_data();
|
void removeDevice_data();
|
||||||
void removeDevice();
|
void removeDevice();
|
||||||
@ -1971,6 +1973,55 @@ void TestDevices::params()
|
|||||||
QVERIFY(!event.param(ParamTypeId::createParamTypeId()).value().isValid());
|
QVERIFY(!event.param(ParamTypeId::createParamTypeId()).value().isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestDevices::asyncSetupEmitsSetupStatusUpdate()
|
||||||
|
{
|
||||||
|
QVariantMap configuredDevices = injectAndWait("Devices.GetConfiguredDevices").toMap();
|
||||||
|
foreach (const QVariant &deviceVariant, configuredDevices.value("params").toMap().value("devices").toList()) {
|
||||||
|
QVariantMap device = deviceVariant.toMap();
|
||||||
|
qCDebug(dcTests()) << "confdiguredd device" << device.value("setupStatus");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart the core instance to check if settings are loaded at startup
|
||||||
|
restartServer();
|
||||||
|
enableNotifications({"Devices"});
|
||||||
|
|
||||||
|
QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||||
|
|
||||||
|
configuredDevices = injectAndWait("Devices.GetConfiguredDevices").toMap();
|
||||||
|
QList<QUuid> devicesWithSetupInProgress;
|
||||||
|
foreach (const QVariant &deviceVariant, configuredDevices.value("params").toMap().value("devices").toList()) {
|
||||||
|
QVariantMap device = deviceVariant.toMap();
|
||||||
|
qCDebug(dcTests()) << "Configured device" << device.value("name").toString() << "with setup status" << device.value("setupStatus").toString();
|
||||||
|
if (device.value("setupStatus").toString() == "DeviceSetupStatusInProgress") {
|
||||||
|
devicesWithSetupInProgress << device.value("id").toUuid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QVERIFY2(devicesWithSetupInProgress.count() > 0, "This test requires at least one device that is still being set up at this point.");
|
||||||
|
|
||||||
|
QDateTime maxTime = QDateTime::currentDateTime().addSecs(10);
|
||||||
|
while (QDateTime::currentDateTime() < maxTime && devicesWithSetupInProgress.count() > 0) {
|
||||||
|
QList<QList<QVariant>> notifications = notificationSpy;
|
||||||
|
while (notifications.count() > 0) {
|
||||||
|
QByteArray notificationData = notifications.takeFirst().at(1).toByteArray();
|
||||||
|
QVariantMap notification = QJsonDocument::fromJson(notificationData).toVariant().toMap();
|
||||||
|
if (notification.value("notification").toString() == "Devices.DeviceChanged") {
|
||||||
|
QString setupStatus = notification.value("params").toMap().value("device").toMap().value("setupStatus").toString();
|
||||||
|
if (setupStatus == "DeviceSetupStatusComplete") {
|
||||||
|
qCDebug(dcTests()) << "Device setup completed for" << notification.value("params").toMap().value("device").toMap().value("name").toString();
|
||||||
|
DeviceId deviceId = notification.value("params").toMap().value("device").toMap().value("id").toUuid();
|
||||||
|
devicesWithSetupInProgress.removeAll(deviceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notificationSpy.clear();
|
||||||
|
if (devicesWithSetupInProgress.count() > 0) {
|
||||||
|
notificationSpy.wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVERIFY2(devicesWithSetupInProgress.isEmpty(), "Some devices did not finish the setup!");
|
||||||
|
}
|
||||||
|
|
||||||
#include "testdevices.moc"
|
#include "testdevices.moc"
|
||||||
QTEST_MAIN(TestDevices)
|
QTEST_MAIN(TestDevices)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user