Refactor NymeaCore class
This moves all the things and rules logic away from NymeaCore into their respective modules where it belongs. One major change is the removal of the removePolicy functionality. This was somewhat broken as it was only working for rules but not for all the other modules like scripts, experiences etc. After an attempt to create something that works with all modules it really seemed that this does not make a lot of sence after all, given that updating rules would in most cases leave something very broken behind and removing them was the only sane thing to do. On the other hand, experience plugins may not work well with such a policy eithre as they may require to do their own special thing. So in the end the removePolicy was dropped altogether. Apps should instead figure out themselves what removal of a thing may imply and inform the user about that beforehand.
This commit is contained in:
parent
d43b9dc737
commit
92197cb97c
@ -59,6 +59,7 @@
|
|||||||
//#include "unistd.h"
|
//#include "unistd.h"
|
||||||
|
|
||||||
#include "plugintimer.h"
|
#include "plugintimer.h"
|
||||||
|
#include "logging/logengine.h"
|
||||||
|
|
||||||
#include <QPluginLoader>
|
#include <QPluginLoader>
|
||||||
#include <QStaticPlugin>
|
#include <QStaticPlugin>
|
||||||
@ -70,9 +71,10 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
ThingManagerImplementation::ThingManagerImplementation(HardwareManager *hardwareManager, const QLocale &locale, QObject *parent) :
|
ThingManagerImplementation::ThingManagerImplementation(HardwareManager *hardwareManager, LogEngine *logEngine, const QLocale &locale, QObject *parent) :
|
||||||
ThingManager(parent),
|
ThingManager(parent),
|
||||||
m_hardwareManager(hardwareManager),
|
m_hardwareManager(hardwareManager),
|
||||||
|
m_logEngine(logEngine),
|
||||||
m_locale(locale),
|
m_locale(locale),
|
||||||
m_translator(new Translator(this))
|
m_translator(new Translator(this))
|
||||||
{
|
{
|
||||||
@ -853,47 +855,66 @@ ThingSetupInfo* ThingManagerImplementation::addConfiguredThingInternal(const Thi
|
|||||||
}
|
}
|
||||||
|
|
||||||
Thing::ThingError ThingManagerImplementation::removeConfiguredThing(const ThingId &thingId)
|
Thing::ThingError ThingManagerImplementation::removeConfiguredThing(const ThingId &thingId)
|
||||||
|
{
|
||||||
|
Thing *thing = m_configuredThings.value(thingId);
|
||||||
|
if (!thing) {
|
||||||
|
return Thing::ThingErrorThingNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thing->parentId().isNull() && thing->autoCreated()) {
|
||||||
|
qCWarning(dcThingManager) << "Thing is an autocreated child of" << thing->parentId().toString() << ". Remove the parent instead.";
|
||||||
|
return Thing::ThingErrorThingIsChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeConfiguredThingInternal(thing);
|
||||||
|
|
||||||
|
return Thing::ThingErrorNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThingManagerImplementation::removeConfiguredThingInternal(Thing *thing)
|
||||||
{
|
{
|
||||||
// We're checking thingSetupStatus and abort any pending setup here. As setup finished()
|
// We're checking thingSetupStatus and abort any pending setup here. As setup finished()
|
||||||
// comes in as a QueuedConnection, make sure to process all events before going on so we
|
// comes in as a QueuedConnection, make sure to process all events before going on so we
|
||||||
// don't end up aborting an already finished setup instead of calling thingRemoved() on it.
|
// don't end up aborting an already finished setup instead of calling thingRemoved() on it.
|
||||||
qApp->processEvents();
|
qApp->processEvents();
|
||||||
|
|
||||||
Thing *thing = m_configuredThings.take(thingId);
|
Things toBeRemoved = findChilds(thing->id());
|
||||||
if (!thing) {
|
toBeRemoved.append(thing);
|
||||||
return Thing::ThingErrorThingNotFound;
|
while (!toBeRemoved.isEmpty()) {
|
||||||
}
|
Thing *t = m_configuredThings.take(toBeRemoved.takeFirst()->id());
|
||||||
IntegrationPlugin *plugin = m_integrationPlugins.value(thing->pluginId());
|
|
||||||
if (!plugin) {
|
|
||||||
qCWarning(dcThingManager()).nospace() << "Plugin not loaded for thing " << thing << ". Not calling thingRemoved on plugin.";
|
|
||||||
} else if (thing->setupStatus() == Thing::ThingSetupStatusInProgress) {
|
|
||||||
qCWarning(dcThingManager()).nospace() << "Thing " << thing << " is still being set up. Aborting setup.";
|
|
||||||
ThingSetupInfo *setupInfo = m_pendingSetups.value(thingId);
|
|
||||||
emit setupInfo->aborted();
|
|
||||||
} else if (thing->setupStatus() == Thing::ThingSetupStatusComplete) {
|
|
||||||
plugin->thingRemoved(thing);
|
|
||||||
}
|
|
||||||
|
|
||||||
thing->deleteLater();
|
IntegrationPlugin *plugin = m_integrationPlugins.value(t->pluginId());
|
||||||
|
if (!plugin) {
|
||||||
NymeaSettings settings(NymeaSettings::SettingsRoleThings);
|
qCWarning(dcThingManager()).nospace() << "Plugin not loaded for thing " << t << ". Not calling thingRemoved on plugin.";
|
||||||
settings.beginGroup("ThingConfig");
|
} else if (thing->setupStatus() == Thing::ThingSetupStatusInProgress) {
|
||||||
settings.beginGroup(thingId.toString());
|
qCWarning(dcThingManager()).nospace() << "Thing " << thing << " is still being set up. Aborting setup.";
|
||||||
settings.remove("");
|
ThingSetupInfo *setupInfo = m_pendingSetups.value(t->id());
|
||||||
settings.endGroup();
|
emit setupInfo->aborted();
|
||||||
|
} else if (thing->setupStatus() == Thing::ThingSetupStatusComplete) {
|
||||||
QFile::remove(statesCacheFile(thingId));
|
plugin->thingRemoved(t);
|
||||||
|
|
||||||
foreach (const IOConnectionId &ioConnectionId, m_ioConnections.keys()) {
|
|
||||||
IOConnection ioConnection = m_ioConnections.value(ioConnectionId);
|
|
||||||
if (ioConnection.inputThingId() == thing->id() || ioConnection.outputThingId() == thing->id()) {
|
|
||||||
disconnectIO(ioConnectionId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t->deleteLater();
|
||||||
|
|
||||||
|
NymeaSettings settings(NymeaSettings::SettingsRoleThings);
|
||||||
|
settings.beginGroup("ThingConfig");
|
||||||
|
settings.beginGroup(t->id().toString());
|
||||||
|
settings.remove("");
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
QFile::remove(statesCacheFile(t->id()));
|
||||||
|
|
||||||
|
foreach (const IOConnectionId &ioConnectionId, m_ioConnections.keys()) {
|
||||||
|
IOConnection ioConnection = m_ioConnections.value(ioConnectionId);
|
||||||
|
if (ioConnection.inputThingId() == t->id() || ioConnection.outputThingId() == t->id()) {
|
||||||
|
disconnectIO(ioConnectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_logEngine->removeThingLogs(thing->id());
|
||||||
|
|
||||||
|
emit thingRemoved(t->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit thingRemoved(thingId);
|
|
||||||
|
|
||||||
return Thing::ThingErrorNoError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowseResult *ThingManagerImplementation::browseThing(const ThingId &thingId, const QString &itemId, const QLocale &locale)
|
BrowseResult *ThingManagerImplementation::browseThing(const ThingId &thingId, const QString &itemId, const QLocale &locale)
|
||||||
@ -977,6 +998,9 @@ BrowserActionInfo* ThingManagerImplementation::executeBrowserItem(const BrowserA
|
|||||||
Thing *thing = m_configuredThings.value(browserAction.thingId());
|
Thing *thing = m_configuredThings.value(browserAction.thingId());
|
||||||
|
|
||||||
BrowserActionInfo *info = new BrowserActionInfo(thing, this, browserAction, this, 30000);
|
BrowserActionInfo *info = new BrowserActionInfo(thing, this, browserAction, this, 30000);
|
||||||
|
connect(info, &BrowserActionInfo::finished, info->thing(), [this, info](){
|
||||||
|
m_logEngine->logBrowserAction(info->browserAction(), info->status() == Thing::ThingErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, info->status());
|
||||||
|
});
|
||||||
|
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
info->finish(Thing::ThingErrorThingNotFound);
|
info->finish(Thing::ThingErrorThingNotFound);
|
||||||
@ -1009,6 +1033,9 @@ BrowserItemActionInfo* ThingManagerImplementation::executeBrowserItemAction(cons
|
|||||||
Thing *thing = m_configuredThings.value(browserItemAction.thingId());
|
Thing *thing = m_configuredThings.value(browserItemAction.thingId());
|
||||||
|
|
||||||
BrowserItemActionInfo *info = new BrowserItemActionInfo(thing, this, browserItemAction, this, 30000);
|
BrowserItemActionInfo *info = new BrowserItemActionInfo(thing, this, browserItemAction, this, 30000);
|
||||||
|
connect(info, &BrowserItemActionInfo::finished, info->thing(), [this, info](){
|
||||||
|
m_logEngine->logBrowserItemAction(info->browserItemAction(), info->status() == Thing::ThingErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, info->status());
|
||||||
|
});
|
||||||
|
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
info->finish(Thing::ThingErrorThingNotFound);
|
info->finish(Thing::ThingErrorThingNotFound);
|
||||||
@ -1359,6 +1386,7 @@ ThingActionInfo *ThingManagerImplementation::executeAction(const Action &action)
|
|||||||
|
|
||||||
ThingActionInfo *info = new ThingActionInfo(thing, finalAction, this, 15000);
|
ThingActionInfo *info = new ThingActionInfo(thing, finalAction, this, 15000);
|
||||||
connect(info, &ThingActionInfo::finished, this, [=](){
|
connect(info, &ThingActionInfo::finished, this, [=](){
|
||||||
|
m_logEngine->logAction(finalAction, info->status());
|
||||||
emit actionExecuted(action, info->status());
|
emit actionExecuted(action, info->status());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1810,7 +1838,7 @@ void ThingManagerImplementation::onAutoThingDisappeared(const ThingId &thingId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit thingDisappeared(thingId);
|
removeConfiguredThingInternal(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThingManagerImplementation::onLoaded()
|
void ThingManagerImplementation::onLoaded()
|
||||||
@ -1849,7 +1877,7 @@ void ThingManagerImplementation::onEventTriggered(Event event)
|
|||||||
}
|
}
|
||||||
// configure logging
|
// configure logging
|
||||||
if (thing->loggedEventTypeIds().contains(event.eventTypeId())) {
|
if (thing->loggedEventTypeIds().contains(event.eventTypeId())) {
|
||||||
event.setLogged(true);
|
m_logEngine->logEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward the event
|
// Forward the event
|
||||||
@ -1867,6 +1895,10 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s
|
|||||||
storeThingState(thing, stateTypeId);
|
storeThingState(thing, stateTypeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thing->loggedStateTypeIds().contains(stateTypeId)) {
|
||||||
|
m_logEngine->logStateChange(thing, stateTypeId, value);
|
||||||
|
}
|
||||||
|
|
||||||
emit thingStateChanged(thing, stateTypeId, value, minValue, maxValue);
|
emit thingStateChanged(thing, stateTypeId, value, minValue, maxValue);
|
||||||
|
|
||||||
syncIOConnection(thing, stateTypeId);
|
syncIOConnection(thing, stateTypeId);
|
||||||
|
|||||||
@ -61,6 +61,11 @@ class HardwareManager;
|
|||||||
class Translator;
|
class Translator;
|
||||||
class ApiKeysProvidersLoader;
|
class ApiKeysProvidersLoader;
|
||||||
|
|
||||||
|
namespace nymeaserver {
|
||||||
|
class LogEngine;
|
||||||
|
}
|
||||||
|
using namespace nymeaserver;
|
||||||
|
|
||||||
class ThingManagerImplementation: public ThingManager
|
class ThingManagerImplementation: public ThingManager
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -68,7 +73,7 @@ class ThingManagerImplementation: public ThingManager
|
|||||||
friend class IntegrationPlugin;
|
friend class IntegrationPlugin;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ThingManagerImplementation(HardwareManager *hardwareManager, const QLocale &locale, QObject *parent = nullptr);
|
explicit ThingManagerImplementation(HardwareManager *hardwareManager, LogEngine *logEngine, const QLocale &locale, QObject *parent = nullptr);
|
||||||
~ThingManagerImplementation() override;
|
~ThingManagerImplementation() override;
|
||||||
|
|
||||||
static QStringList pluginSearchDirs();
|
static QStringList pluginSearchDirs();
|
||||||
@ -131,9 +136,6 @@ public:
|
|||||||
ThingClass translateThingClass(const ThingClass &thingClass, const QLocale &locale) override;
|
ThingClass translateThingClass(const ThingClass &thingClass, const QLocale &locale) override;
|
||||||
Vendor translateVendor(const Vendor &vendor, const QLocale &locale) override;
|
Vendor translateVendor(const Vendor &vendor, const QLocale &locale) override;
|
||||||
|
|
||||||
signals:
|
|
||||||
void loaded();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void loadPlugins();
|
void loadPlugins();
|
||||||
void loadPlugin(IntegrationPlugin *pluginIface);
|
void loadPlugin(IntegrationPlugin *pluginIface);
|
||||||
@ -157,6 +159,7 @@ private:
|
|||||||
ParamList buildParams(const ParamTypes &types, const ParamList &first, const ParamList &second = ParamList());
|
ParamList buildParams(const ParamTypes &types, const ParamList &first, const ParamList &second = ParamList());
|
||||||
void pairThingInternal(ThingPairingInfo *info);
|
void pairThingInternal(ThingPairingInfo *info);
|
||||||
ThingSetupInfo *addConfiguredThingInternal(const ThingClassId &thingClassId, const QString &name, const ParamList ¶ms, const ThingId &parentId = ThingId());
|
ThingSetupInfo *addConfiguredThingInternal(const ThingClassId &thingClassId, const QString &name, const ParamList ¶ms, const ThingId &parentId = ThingId());
|
||||||
|
void removeConfiguredThingInternal(Thing *thing);
|
||||||
ThingSetupInfo *reconfigureThingInternal(Thing *thing, const ParamList ¶ms, const QString &name = QString());
|
ThingSetupInfo *reconfigureThingInternal(Thing *thing, const ParamList ¶ms, const QString &name = QString());
|
||||||
ThingSetupInfo *setupThing(Thing *thing);
|
ThingSetupInfo *setupThing(Thing *thing);
|
||||||
void initThing(Thing *thing);
|
void initThing(Thing *thing);
|
||||||
@ -176,6 +179,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
HardwareManager *m_hardwareManager;
|
HardwareManager *m_hardwareManager;
|
||||||
|
nymeaserver::LogEngine *m_logEngine;
|
||||||
|
|
||||||
QLocale m_locale;
|
QLocale m_locale;
|
||||||
Translator *m_translator = nullptr;
|
Translator *m_translator = nullptr;
|
||||||
|
|||||||
@ -29,7 +29,6 @@
|
|||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#include "integrationshandler.h"
|
#include "integrationshandler.h"
|
||||||
#include "nymeacore.h"
|
|
||||||
#include "integrations/thingmanager.h"
|
#include "integrations/thingmanager.h"
|
||||||
#include "integrations/thing.h"
|
#include "integrations/thing.h"
|
||||||
#include "integrations/integrationplugin.h"
|
#include "integrations/integrationplugin.h"
|
||||||
@ -43,9 +42,11 @@
|
|||||||
#include "integrations/thingsetupinfo.h"
|
#include "integrations/thingsetupinfo.h"
|
||||||
#include "integrations/browseresult.h"
|
#include "integrations/browseresult.h"
|
||||||
#include "integrations/browseritemresult.h"
|
#include "integrations/browseritemresult.h"
|
||||||
|
#include "ruleengine/ruleengine.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
@ -63,7 +64,6 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa
|
|||||||
registerEnum<Types::InputType>();
|
registerEnum<Types::InputType>();
|
||||||
registerEnum<Types::IOType>();
|
registerEnum<Types::IOType>();
|
||||||
registerEnum<Types::StateValueFilter>();
|
registerEnum<Types::StateValueFilter>();
|
||||||
registerEnum<RuleEngine::RemovePolicy>();
|
|
||||||
registerEnum<BrowserItem::BrowserIcon>();
|
registerEnum<BrowserItem::BrowserIcon>();
|
||||||
registerEnum<MediaBrowserItem::MediaBrowserIcon>();
|
registerEnum<MediaBrowserItem::MediaBrowserIcon>();
|
||||||
|
|
||||||
@ -268,17 +268,10 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa
|
|||||||
registerMethod("SetStateFilter", description, params, returns, Types::PermissionScopeConfigureThings);
|
registerMethod("SetStateFilter", description, params, returns, Types::PermissionScopeConfigureThings);
|
||||||
|
|
||||||
params.clear(); returns.clear();
|
params.clear(); returns.clear();
|
||||||
description = "Remove a thing from the system.";
|
description = "Remove a thing and all its childs from the system. RemovePolicy is deprecated and has no effect any more.";
|
||||||
params.insert("thingId", enumValueName(Uuid));
|
params.insert("thingId", enumValueName(Uuid));
|
||||||
params.insert("o:removePolicy", enumRef<RuleEngine::RemovePolicy>());
|
params.insert("d:o:removePolicy", enumValueName(String));
|
||||||
QVariantMap policy;
|
|
||||||
policy.insert("ruleId", enumValueName(Uuid));
|
|
||||||
policy.insert("policy", enumRef<RuleEngine::RemovePolicy>());
|
|
||||||
QVariantList removePolicyList;
|
|
||||||
removePolicyList.append(policy);
|
|
||||||
params.insert("o:removePolicyList", removePolicyList);
|
|
||||||
returns.insert("thingError", enumRef<Thing::ThingError>());
|
returns.insert("thingError", enumRef<Thing::ThingError>());
|
||||||
returns.insert("o:ruleIds", QVariantList() << enumValueName(Uuid));
|
|
||||||
registerMethod("RemoveThing", description, params, returns, Types::PermissionScopeConfigureThings);
|
registerMethod("RemoveThing", description, params, returns, Types::PermissionScopeConfigureThings);
|
||||||
|
|
||||||
params.clear(); returns.clear();
|
params.clear(); returns.clear();
|
||||||
@ -443,7 +436,7 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa
|
|||||||
description = "Emitted whenever an Event is triggered.";
|
description = "Emitted whenever an Event is triggered.";
|
||||||
params.insert("event", objectRef<Event>());
|
params.insert("event", objectRef<Event>());
|
||||||
registerNotification("EventTriggered", description, params);
|
registerNotification("EventTriggered", description, params);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::eventTriggered, this, [this](const Event &event){
|
connect(m_thingManager, &ThingManager::eventTriggered, this, [this](const Event &event){
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("event", pack(event));
|
params.insert("event", pack(event));
|
||||||
emit EventTriggered(params);
|
emit EventTriggered(params);
|
||||||
@ -469,14 +462,14 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa
|
|||||||
emit IOConnectionRemoved(params);
|
emit IOConnectionRemoved(params);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(NymeaCore::instance(), &NymeaCore::pluginConfigChanged, this, &IntegrationsHandler::pluginConfigChanged);
|
connect(m_thingManager, &ThingManager::pluginConfigChanged, this, &IntegrationsHandler::pluginConfigChanged);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::thingStateChanged, this, &IntegrationsHandler::thingStateChanged);
|
connect(m_thingManager, &ThingManager::thingStateChanged, this, &IntegrationsHandler::thingStateChanged);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::thingRemoved, this, &IntegrationsHandler::thingRemovedNotification);
|
connect(m_thingManager, &ThingManager::thingRemoved, this, &IntegrationsHandler::thingRemovedNotification);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::thingAdded, this, &IntegrationsHandler::thingAddedNotification);
|
connect(m_thingManager, &ThingManager::thingAdded, this, &IntegrationsHandler::thingAddedNotification);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::thingChanged, this, &IntegrationsHandler::thingChangedNotification);
|
connect(m_thingManager, &ThingManager::thingChanged, this, &IntegrationsHandler::thingChangedNotification);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::thingSettingChanged, this, &IntegrationsHandler::thingSettingChangedNotification);
|
connect(m_thingManager, &ThingManager::thingSettingChanged, this, &IntegrationsHandler::thingSettingChangedNotification);
|
||||||
|
|
||||||
connect(NymeaCore::instance(), &NymeaCore::initialized, this, [=](){
|
connect(m_thingManager, &ThingManager::loaded, this, [=](){
|
||||||
// Generating cache hashes.
|
// Generating cache hashes.
|
||||||
// NOTE: We need to sort the lists to get a stable result
|
// NOTE: We need to sort the lists to get a stable result
|
||||||
QHash<ThingClassId, ThingClass> thingClassesMap;
|
QHash<ThingClassId, ThingClass> thingClassesMap;
|
||||||
@ -535,8 +528,8 @@ JsonReply* IntegrationsHandler::GetVendors(const QVariantMap ¶ms, const Json
|
|||||||
{
|
{
|
||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
QVariantList vendors;
|
QVariantList vendors;
|
||||||
foreach (const Vendor &vendor, NymeaCore::instance()->thingManager()->supportedVendors()) {
|
foreach (const Vendor &vendor, m_thingManager->supportedVendors()) {
|
||||||
Vendor translatedVendor = NymeaCore::instance()->thingManager()->translateVendor(vendor, context.locale());
|
Vendor translatedVendor = m_thingManager->translateVendor(vendor, context.locale());
|
||||||
vendors.append(pack(translatedVendor));
|
vendors.append(pack(translatedVendor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,7 +543,7 @@ JsonReply* IntegrationsHandler::GetThingClasses(const QVariantMap ¶ms, const
|
|||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
QVariantList thingClasses;
|
QVariantList thingClasses;
|
||||||
|
|
||||||
foreach (const ThingClass &thingClass, NymeaCore::instance()->thingManager()->supportedThings()) {
|
foreach (const ThingClass &thingClass, m_thingManager->supportedThings()) {
|
||||||
if (params.contains("vendorId") && thingClass.vendorId() != VendorId(params.value("vendorId").toUuid())) {
|
if (params.contains("vendorId") && thingClass.vendorId() != VendorId(params.value("vendorId").toUuid())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -567,7 +560,7 @@ JsonReply* IntegrationsHandler::GetThingClasses(const QVariantMap ¶ms, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ThingClass translatedThingClass = NymeaCore::instance()->thingManager()->translateThingClass(thingClass, context.locale());
|
ThingClass translatedThingClass = m_thingManager->translateThingClass(thingClass, context.locale());
|
||||||
thingClasses.append(pack(translatedThingClass));
|
thingClasses.append(pack(translatedThingClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,7 +579,7 @@ JsonReply *IntegrationsHandler::DiscoverThings(const QVariantMap ¶ms, const
|
|||||||
ParamList discoveryParams = unpack<ParamList>(params.value("discoveryParams"));
|
ParamList discoveryParams = unpack<ParamList>(params.value("discoveryParams"));
|
||||||
|
|
||||||
JsonReply *reply = createAsyncReply("DiscoverThings");
|
JsonReply *reply = createAsyncReply("DiscoverThings");
|
||||||
ThingDiscoveryInfo *info = NymeaCore::instance()->thingManager()->discoverThings(thingClassId, discoveryParams);
|
ThingDiscoveryInfo *info = m_thingManager->discoverThings(thingClassId, discoveryParams);
|
||||||
connect(info, &ThingDiscoveryInfo::finished, reply, [this, reply, info, locale](){
|
connect(info, &ThingDiscoveryInfo::finished, reply, [this, reply, info, locale](){
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
returns.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
returns.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
||||||
@ -614,9 +607,9 @@ JsonReply* IntegrationsHandler::GetPlugins(const QVariantMap ¶ms, const Json
|
|||||||
{
|
{
|
||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
QVariantList plugins;
|
QVariantList plugins;
|
||||||
foreach (IntegrationPlugin* plugin, NymeaCore::instance()->thingManager()->plugins()) {
|
foreach (IntegrationPlugin* plugin, m_thingManager->plugins()) {
|
||||||
QVariantMap packedPlugin = pack(*plugin).toMap();
|
QVariantMap packedPlugin = pack(*plugin).toMap();
|
||||||
packedPlugin["displayName"] = NymeaCore::instance()->thingManager()->translate(plugin->pluginId(), plugin->pluginDisplayName(), context.locale());
|
packedPlugin["displayName"] = m_thingManager->translate(plugin->pluginId(), plugin->pluginDisplayName(), context.locale());
|
||||||
plugins.append(packedPlugin);
|
plugins.append(packedPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,7 +622,7 @@ JsonReply *IntegrationsHandler::GetPluginConfiguration(const QVariantMap ¶ms
|
|||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
|
|
||||||
IntegrationPlugin *plugin = NymeaCore::instance()->thingManager()->plugins().findById(PluginId(params.value("pluginId").toString()));
|
IntegrationPlugin *plugin = m_thingManager->plugins().findById(PluginId(params.value("pluginId").toString()));
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
returns.insert("thingError", enumValueName<Thing::ThingError>(Thing::ThingErrorPluginNotFound));
|
returns.insert("thingError", enumValueName<Thing::ThingError>(Thing::ThingErrorPluginNotFound));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
@ -649,7 +642,7 @@ JsonReply* IntegrationsHandler::SetPluginConfiguration(const QVariantMap ¶ms
|
|||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
PluginId pluginId = PluginId(params.value("pluginId").toString());
|
PluginId pluginId = PluginId(params.value("pluginId").toString());
|
||||||
ParamList pluginParams = unpack<ParamList>(params.value("configuration"));
|
ParamList pluginParams = unpack<ParamList>(params.value("configuration"));
|
||||||
Thing::ThingError result = NymeaCore::instance()->thingManager()->setPluginConfig(pluginId, pluginParams);
|
Thing::ThingError result = m_thingManager->setPluginConfig(pluginId, pluginParams);
|
||||||
returns.insert("thingError",enumValueName<Thing::ThingError>(result));
|
returns.insert("thingError",enumValueName<Thing::ThingError>(result));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
@ -674,10 +667,10 @@ JsonReply* IntegrationsHandler::AddThing(const QVariantMap ¶ms, const JsonCo
|
|||||||
jsonReply->finished();
|
jsonReply->finished();
|
||||||
return jsonReply;
|
return jsonReply;
|
||||||
}
|
}
|
||||||
info = NymeaCore::instance()->thingManager()->addConfiguredThing(thingClassId, thingParams, thingName);
|
info = m_thingManager->addConfiguredThing(thingClassId, thingParams, thingName);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
info = NymeaCore::instance()->thingManager()->addConfiguredThing(thingDescriptorId, thingParams, thingName);
|
info = m_thingManager->addConfiguredThing(thingDescriptorId, thingParams, thingName);
|
||||||
}
|
}
|
||||||
connect(info, &ThingSetupInfo::finished, jsonReply, [info, jsonReply, locale](){
|
connect(info, &ThingSetupInfo::finished, jsonReply, [info, jsonReply, locale](){
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
@ -706,24 +699,24 @@ JsonReply *IntegrationsHandler::PairThing(const QVariantMap ¶ms, const JsonC
|
|||||||
ThingPairingInfo *info;
|
ThingPairingInfo *info;
|
||||||
if (params.contains("thingDescriptorId")) {
|
if (params.contains("thingDescriptorId")) {
|
||||||
ThingDescriptorId thingDescriptorId = ThingDescriptorId(params.value("thingDescriptorId").toString());
|
ThingDescriptorId thingDescriptorId = ThingDescriptorId(params.value("thingDescriptorId").toString());
|
||||||
info = NymeaCore::instance()->thingManager()->pairThing(thingDescriptorId, thingParams, thingName);
|
info = m_thingManager->pairThing(thingDescriptorId, thingParams, thingName);
|
||||||
} else if (params.contains("thingId")) {
|
} else if (params.contains("thingId")) {
|
||||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||||
info = NymeaCore::instance()->thingManager()->pairThing(thingId, thingParams, thingName);
|
info = m_thingManager->pairThing(thingId, thingParams, thingName);
|
||||||
} else {
|
} else {
|
||||||
ThingClassId thingClassId(params.value("thingClassId").toString());
|
ThingClassId thingClassId(params.value("thingClassId").toString());
|
||||||
info = NymeaCore::instance()->thingManager()->pairThing(thingClassId, thingParams, thingName);
|
info = m_thingManager->pairThing(thingClassId, thingParams, thingName);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonReply *jsonReply = createAsyncReply("PairThing");
|
JsonReply *jsonReply = createAsyncReply("PairThing");
|
||||||
|
|
||||||
connect(info, &ThingPairingInfo::finished, jsonReply, [jsonReply, info, locale](){
|
connect(info, &ThingPairingInfo::finished, jsonReply, [jsonReply, info, locale, this](){
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
returns.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
returns.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
||||||
returns.insert("pairingTransactionId", info->transactionId().toString());
|
returns.insert("pairingTransactionId", info->transactionId().toString());
|
||||||
|
|
||||||
if (info->status() == Thing::ThingErrorNoError) {
|
if (info->status() == Thing::ThingErrorNoError) {
|
||||||
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(info->thingClassId());
|
ThingClass thingClass = m_thingManager->findThingClass(info->thingClassId());
|
||||||
returns.insert("setupMethod", enumValueName<ThingClass::SetupMethod>(thingClass.setupMethod()));
|
returns.insert("setupMethod", enumValueName<ThingClass::SetupMethod>(thingClass.setupMethod()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,7 +744,7 @@ JsonReply *IntegrationsHandler::ConfirmPairing(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
JsonReply *jsonReply = createAsyncReply("ConfirmPairing");
|
JsonReply *jsonReply = createAsyncReply("ConfirmPairing");
|
||||||
|
|
||||||
ThingPairingInfo *info = NymeaCore::instance()->thingManager()->confirmPairing(pairingTransactionId, username, secret);
|
ThingPairingInfo *info = m_thingManager->confirmPairing(pairingTransactionId, username, secret);
|
||||||
connect(info, &ThingPairingInfo::finished, jsonReply, [info, jsonReply, locale](){
|
connect(info, &ThingPairingInfo::finished, jsonReply, [info, jsonReply, locale](){
|
||||||
|
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
@ -774,22 +767,22 @@ JsonReply* IntegrationsHandler::GetThings(const QVariantMap ¶ms, const JsonC
|
|||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
QVariantList things;
|
QVariantList things;
|
||||||
if (params.contains("thingId")) {
|
if (params.contains("thingId")) {
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(ThingId(params.value("thingId").toString()));
|
Thing *thing = m_thingManager->findConfiguredThing(ThingId(params.value("thingId").toString()));
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
returns.insert("thingError", enumValueName<Thing::ThingError>(Thing::ThingErrorThingNotFound));
|
returns.insert("thingError", enumValueName<Thing::ThingError>(Thing::ThingErrorThingNotFound));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
} else {
|
} else {
|
||||||
QVariantMap packedThing = pack(thing).toMap();
|
QVariantMap packedThing = pack(thing).toMap();
|
||||||
QString translatedSetupStatus = NymeaCore::instance()->thingManager()->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale());
|
QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale());
|
||||||
if (!translatedSetupStatus.isEmpty()) {
|
if (!translatedSetupStatus.isEmpty()) {
|
||||||
packedThing["setupDisplayMessage"] = translatedSetupStatus;
|
packedThing["setupDisplayMessage"] = translatedSetupStatus;
|
||||||
}
|
}
|
||||||
things.append(packedThing);
|
things.append(packedThing);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
foreach (Thing *thing, NymeaCore::instance()->thingManager()->configuredThings()) {
|
foreach (Thing *thing, m_thingManager->configuredThings()) {
|
||||||
QVariantMap packedThing = pack(thing).toMap();
|
QVariantMap packedThing = pack(thing).toMap();
|
||||||
QString translatedSetupStatus = NymeaCore::instance()->thingManager()->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale());
|
QString translatedSetupStatus = m_thingManager->translate(thing->pluginId(), thing->setupDisplayMessage(), context.locale());
|
||||||
if (!translatedSetupStatus.isEmpty()) {
|
if (!translatedSetupStatus.isEmpty()) {
|
||||||
packedThing["setupDisplayMessage"] = translatedSetupStatus;
|
packedThing["setupDisplayMessage"] = translatedSetupStatus;
|
||||||
}
|
}
|
||||||
@ -812,9 +805,9 @@ JsonReply *IntegrationsHandler::ReconfigureThing(const QVariantMap ¶ms, cons
|
|||||||
|
|
||||||
ThingSetupInfo *info;
|
ThingSetupInfo *info;
|
||||||
if (!thingDescriptorId.isNull()) {
|
if (!thingDescriptorId.isNull()) {
|
||||||
info = NymeaCore::instance()->thingManager()->reconfigureThing(thingDescriptorId, thingParams);
|
info = m_thingManager->reconfigureThing(thingDescriptorId, thingParams);
|
||||||
} else if (!thingId.isNull()){
|
} else if (!thingId.isNull()){
|
||||||
info = NymeaCore::instance()->thingManager()->reconfigureThing(thingId, thingParams);
|
info = m_thingManager->reconfigureThing(thingId, thingParams);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcJsonRpc()) << "Either thingId or thingDescriptorId are required";
|
qCWarning(dcJsonRpc()) << "Either thingId or thingDescriptorId are required";
|
||||||
QVariantMap ret;
|
QVariantMap ret;
|
||||||
@ -842,7 +835,7 @@ JsonReply *IntegrationsHandler::EditThing(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
qCDebug(dcJsonRpc()) << "Edit thing" << thingId << name;
|
qCDebug(dcJsonRpc()) << "Edit thing" << thingId << name;
|
||||||
|
|
||||||
Thing::ThingError status = NymeaCore::instance()->thingManager()->editThing(thingId, name);
|
Thing::ThingError status = m_thingManager->editThing(thingId, name);
|
||||||
|
|
||||||
return createReply(statusToReply(status));
|
return createReply(statusToReply(status));
|
||||||
}
|
}
|
||||||
@ -851,33 +844,8 @@ JsonReply* IntegrationsHandler::RemoveThing(const QVariantMap ¶ms)
|
|||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||||
|
Thing::ThingError status = m_thingManager->removeConfiguredThing(thingId);
|
||||||
// global removePolicy has priority
|
returns.insert("thingError", enumValueName<Thing::ThingError>(status));
|
||||||
if (params.contains("removePolicy")) {
|
|
||||||
RuleEngine::RemovePolicy removePolicy = params.value("removePolicy").toString() == "RemovePolicyCascade" ? RuleEngine::RemovePolicyCascade : RuleEngine::RemovePolicyUpdate;
|
|
||||||
Thing::ThingError status = NymeaCore::instance()->removeConfiguredThing(thingId, removePolicy);
|
|
||||||
returns.insert("thingError", enumValueName<Thing::ThingError>(status));
|
|
||||||
return createReply(returns);
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<RuleId, RuleEngine::RemovePolicy> removePolicyList;
|
|
||||||
foreach (const QVariant &variant, params.value("removePolicyList").toList()) {
|
|
||||||
RuleId ruleId = RuleId(variant.toMap().value("ruleId").toString());
|
|
||||||
RuleEngine::RemovePolicy policy = variant.toMap().value("policy").toString() == "RemovePolicyCascade" ? RuleEngine::RemovePolicyCascade : RuleEngine::RemovePolicyUpdate;
|
|
||||||
removePolicyList.insert(ruleId, policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
QPair<Thing::ThingError, QList<RuleId> > status = NymeaCore::instance()->removeConfiguredThing(thingId, removePolicyList);
|
|
||||||
returns.insert("thingError", enumValueName<Thing::ThingError>(status.first));
|
|
||||||
|
|
||||||
if (!status.second.isEmpty()) {
|
|
||||||
QVariantList ruleIdList;
|
|
||||||
foreach (const RuleId &ruleId, status.second) {
|
|
||||||
ruleIdList.append(ruleId.toString());
|
|
||||||
}
|
|
||||||
returns.insert("ruleIds", ruleIdList);
|
|
||||||
}
|
|
||||||
|
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,7 +853,7 @@ JsonReply *IntegrationsHandler::SetThingSettings(const QVariantMap ¶ms)
|
|||||||
{
|
{
|
||||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||||
ParamList settings = unpack<ParamList>(params.value("settings"));
|
ParamList settings = unpack<ParamList>(params.value("settings"));
|
||||||
Thing::ThingError status = NymeaCore::instance()->thingManager()->setThingSettings(thingId, settings);
|
Thing::ThingError status = m_thingManager->setThingSettings(thingId, settings);
|
||||||
return createReply(statusToReply(status));
|
return createReply(statusToReply(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -894,7 +862,7 @@ JsonReply *IntegrationsHandler::SetStateLogging(const QVariantMap ¶ms)
|
|||||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||||
StateTypeId stateTypeId = StateTypeId(params.value("stateTypeId").toUuid());
|
StateTypeId stateTypeId = StateTypeId(params.value("stateTypeId").toUuid());
|
||||||
bool enabled = params.value("enabled").toBool();
|
bool enabled = params.value("enabled").toBool();
|
||||||
Thing::ThingError status = NymeaCore::instance()->thingManager()->setStateLogging(thingId, stateTypeId, enabled);
|
Thing::ThingError status = m_thingManager->setStateLogging(thingId, stateTypeId, enabled);
|
||||||
return createReply(statusToReply(status));
|
return createReply(statusToReply(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -903,7 +871,7 @@ JsonReply *IntegrationsHandler::SetEventLogging(const QVariantMap ¶ms)
|
|||||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||||
EventTypeId eventTypeId = EventTypeId(params.value("eventTypeId").toUuid());
|
EventTypeId eventTypeId = EventTypeId(params.value("eventTypeId").toUuid());
|
||||||
bool enabled = params.value("enabled").toBool();
|
bool enabled = params.value("enabled").toBool();
|
||||||
Thing::ThingError status = NymeaCore::instance()->thingManager()->setEventLogging(thingId, eventTypeId, enabled);
|
Thing::ThingError status = m_thingManager->setEventLogging(thingId, eventTypeId, enabled);
|
||||||
return createReply(statusToReply(status));
|
return createReply(statusToReply(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,14 +882,14 @@ JsonReply *IntegrationsHandler::SetStateFilter(const QVariantMap ¶ms)
|
|||||||
QString filterString = params.value("filter").toString();
|
QString filterString = params.value("filter").toString();
|
||||||
QMetaEnum metaEnum = QMetaEnum::fromType<Types::StateValueFilter>();
|
QMetaEnum metaEnum = QMetaEnum::fromType<Types::StateValueFilter>();
|
||||||
Types::StateValueFilter filter = static_cast<Types::StateValueFilter>(metaEnum.keyToValue(filterString.toUtf8()));
|
Types::StateValueFilter filter = static_cast<Types::StateValueFilter>(metaEnum.keyToValue(filterString.toUtf8()));
|
||||||
Thing::ThingError status = NymeaCore::instance()->thingManager()->setStateFilter(thingId, stateTypeId, filter);
|
Thing::ThingError status = m_thingManager->setStateFilter(thingId, stateTypeId, filter);
|
||||||
return createReply(statusToReply(status));
|
return createReply(statusToReply(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonReply* IntegrationsHandler::GetEventTypes(const QVariantMap ¶ms, const JsonContext &context) const
|
JsonReply* IntegrationsHandler::GetEventTypes(const QVariantMap ¶ms, const JsonContext &context) const
|
||||||
{
|
{
|
||||||
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(ThingClassId(params.value("thingClassId").toString()));
|
ThingClass thingClass = m_thingManager->findThingClass(ThingClassId(params.value("thingClassId").toString()));
|
||||||
ThingClass translatedThingClass = NymeaCore::instance()->thingManager()->translateThingClass(thingClass, context.locale());
|
ThingClass translatedThingClass = m_thingManager->translateThingClass(thingClass, context.locale());
|
||||||
|
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
returns.insert("eventTypes", pack(translatedThingClass.eventTypes()));
|
returns.insert("eventTypes", pack(translatedThingClass.eventTypes()));
|
||||||
@ -930,8 +898,8 @@ JsonReply* IntegrationsHandler::GetEventTypes(const QVariantMap ¶ms, const J
|
|||||||
|
|
||||||
JsonReply* IntegrationsHandler::GetActionTypes(const QVariantMap ¶ms, const JsonContext &context) const
|
JsonReply* IntegrationsHandler::GetActionTypes(const QVariantMap ¶ms, const JsonContext &context) const
|
||||||
{
|
{
|
||||||
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(ThingClassId(params.value("thingClassId").toString()));
|
ThingClass thingClass = m_thingManager->findThingClass(ThingClassId(params.value("thingClassId").toString()));
|
||||||
ThingClass translatedThingClass = NymeaCore::instance()->thingManager()->translateThingClass(thingClass, context.locale());
|
ThingClass translatedThingClass = m_thingManager->translateThingClass(thingClass, context.locale());
|
||||||
|
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
returns.insert("actionTypes", pack(translatedThingClass.actionTypes()));
|
returns.insert("actionTypes", pack(translatedThingClass.actionTypes()));
|
||||||
@ -940,8 +908,8 @@ JsonReply* IntegrationsHandler::GetActionTypes(const QVariantMap ¶ms, const
|
|||||||
|
|
||||||
JsonReply* IntegrationsHandler::GetStateTypes(const QVariantMap ¶ms, const JsonContext &context) const
|
JsonReply* IntegrationsHandler::GetStateTypes(const QVariantMap ¶ms, const JsonContext &context) const
|
||||||
{
|
{
|
||||||
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(ThingClassId(params.value("thingClassId").toString()));
|
ThingClass thingClass = m_thingManager->findThingClass(ThingClassId(params.value("thingClassId").toString()));
|
||||||
ThingClass translatedThingClass = NymeaCore::instance()->thingManager()->translateThingClass(thingClass, context.locale());
|
ThingClass translatedThingClass = m_thingManager->translateThingClass(thingClass, context.locale());
|
||||||
|
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
returns.insert("stateTypes", pack(translatedThingClass.stateTypes()));
|
returns.insert("stateTypes", pack(translatedThingClass.stateTypes()));
|
||||||
@ -950,7 +918,7 @@ JsonReply* IntegrationsHandler::GetStateTypes(const QVariantMap ¶ms, const J
|
|||||||
|
|
||||||
JsonReply* IntegrationsHandler::GetStateValue(const QVariantMap ¶ms) const
|
JsonReply* IntegrationsHandler::GetStateValue(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(ThingId(params.value("thingId").toString()));
|
Thing *thing = m_thingManager->findConfiguredThing(ThingId(params.value("thingId").toString()));
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||||
}
|
}
|
||||||
@ -966,7 +934,7 @@ JsonReply* IntegrationsHandler::GetStateValue(const QVariantMap ¶ms) const
|
|||||||
|
|
||||||
JsonReply *IntegrationsHandler::GetStateValues(const QVariantMap ¶ms) const
|
JsonReply *IntegrationsHandler::GetStateValues(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(ThingId(params.value("thingId").toString()));
|
Thing *thing = m_thingManager->findConfiguredThing(ThingId(params.value("thingId").toString()));
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||||
}
|
}
|
||||||
@ -983,7 +951,7 @@ JsonReply *IntegrationsHandler::BrowseThing(const QVariantMap ¶ms, const Jso
|
|||||||
|
|
||||||
JsonReply *jsonReply = createAsyncReply("BrowseThing");
|
JsonReply *jsonReply = createAsyncReply("BrowseThing");
|
||||||
|
|
||||||
BrowseResult *result = NymeaCore::instance()->thingManager()->browseThing(thingId, itemId, context.locale());
|
BrowseResult *result = m_thingManager->browseThing(thingId, itemId, context.locale());
|
||||||
connect(result, &BrowseResult::finished, jsonReply, [this, jsonReply, result, context](){
|
connect(result, &BrowseResult::finished, jsonReply, [this, jsonReply, result, context](){
|
||||||
|
|
||||||
QVariantMap returns = statusToReply(result->status());
|
QVariantMap returns = statusToReply(result->status());
|
||||||
@ -1010,7 +978,7 @@ JsonReply *IntegrationsHandler::GetBrowserItem(const QVariantMap ¶ms, const
|
|||||||
|
|
||||||
JsonReply *jsonReply = createAsyncReply("GetBrowserItem");
|
JsonReply *jsonReply = createAsyncReply("GetBrowserItem");
|
||||||
|
|
||||||
BrowserItemResult *result = NymeaCore::instance()->thingManager()->browserItemDetails(thingId, itemId, context.locale());
|
BrowserItemResult *result = m_thingManager->browserItemDetails(thingId, itemId, context.locale());
|
||||||
connect(result, &BrowserItemResult::finished, jsonReply, [this, jsonReply, result, context](){
|
connect(result, &BrowserItemResult::finished, jsonReply, [this, jsonReply, result, context](){
|
||||||
QVariantMap params = statusToReply(result->status());
|
QVariantMap params = statusToReply(result->status());
|
||||||
if (result->status() == Thing::ThingErrorNoError) {
|
if (result->status() == Thing::ThingErrorNoError) {
|
||||||
@ -1038,7 +1006,7 @@ JsonReply *IntegrationsHandler::ExecuteAction(const QVariantMap ¶ms, const J
|
|||||||
|
|
||||||
JsonReply *jsonReply = createAsyncReply("ExecuteAction");
|
JsonReply *jsonReply = createAsyncReply("ExecuteAction");
|
||||||
|
|
||||||
ThingActionInfo *info = NymeaCore::instance()->thingManager()->executeAction(action);
|
ThingActionInfo *info = m_thingManager->executeAction(action);
|
||||||
connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){
|
connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){
|
||||||
QVariantMap data;
|
QVariantMap data;
|
||||||
data.insert("thingError", enumValueName(info->status()));
|
data.insert("thingError", enumValueName(info->status()));
|
||||||
@ -1060,7 +1028,7 @@ JsonReply *IntegrationsHandler::ExecuteBrowserItem(const QVariantMap ¶ms, co
|
|||||||
|
|
||||||
JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItem");
|
JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItem");
|
||||||
|
|
||||||
BrowserActionInfo *info = NymeaCore::instance()->executeBrowserItem(action);
|
BrowserActionInfo *info = m_thingManager->executeBrowserItem(action);
|
||||||
connect(info, &BrowserActionInfo::finished, jsonReply, [info, jsonReply, context](){
|
connect(info, &BrowserActionInfo::finished, jsonReply, [info, jsonReply, context](){
|
||||||
QVariantMap data;
|
QVariantMap data;
|
||||||
data.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
data.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
||||||
@ -1084,7 +1052,7 @@ JsonReply *IntegrationsHandler::ExecuteBrowserItemAction(const QVariantMap ¶
|
|||||||
|
|
||||||
JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItemAction");
|
JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItemAction");
|
||||||
|
|
||||||
BrowserItemActionInfo *info = NymeaCore::instance()->executeBrowserItemAction(browserItemAction);
|
BrowserItemActionInfo *info = m_thingManager->executeBrowserItemAction(browserItemAction);
|
||||||
connect(info, &BrowserItemActionInfo::finished, jsonReply, [info, jsonReply, context](){
|
connect(info, &BrowserItemActionInfo::finished, jsonReply, [info, jsonReply, context](){
|
||||||
QVariantMap data;
|
QVariantMap data;
|
||||||
data.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
data.insert("thingError", enumValueName<Thing::ThingError>(info->status()));
|
||||||
|
|||||||
@ -525,7 +525,7 @@ void JsonRPCServerImplementation::setup()
|
|||||||
{
|
{
|
||||||
registerHandler(this);
|
registerHandler(this);
|
||||||
registerHandler(new IntegrationsHandler(NymeaCore::instance()->thingManager(), this));
|
registerHandler(new IntegrationsHandler(NymeaCore::instance()->thingManager(), this));
|
||||||
registerHandler(new RulesHandler(this));
|
registerHandler(new RulesHandler(NymeaCore::instance()->ruleEngine(), this));
|
||||||
registerHandler(new LoggingHandler(this));
|
registerHandler(new LoggingHandler(this));
|
||||||
registerHandler(new ConfigurationHandler(this));
|
registerHandler(new ConfigurationHandler(this));
|
||||||
registerHandler(new NetworkManagerHandler(NymeaCore::instance()->networkManager(), this));
|
registerHandler(new NetworkManagerHandler(NymeaCore::instance()->networkManager(), this));
|
||||||
|
|||||||
@ -62,7 +62,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ruleshandler.h"
|
#include "ruleshandler.h"
|
||||||
#include "nymeacore.h"
|
|
||||||
#include "ruleengine/ruleengine.h"
|
#include "ruleengine/ruleengine.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
@ -72,8 +71,9 @@
|
|||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
/*! Constructs a new \l{RulesHandler} with the given \a parent. */
|
/*! Constructs a new \l{RulesHandler} with the given \a parent. */
|
||||||
RulesHandler::RulesHandler(QObject *parent) :
|
RulesHandler::RulesHandler(RuleEngine *ruleEngine, QObject *parent) :
|
||||||
JsonHandler(parent)
|
JsonHandler(parent),
|
||||||
|
m_ruleEngine(ruleEngine)
|
||||||
{
|
{
|
||||||
// Enums
|
// Enums
|
||||||
registerEnum<RuleEngine::RuleError>();
|
registerEnum<RuleEngine::RuleError>();
|
||||||
@ -218,10 +218,10 @@ RulesHandler::RulesHandler(QObject *parent) :
|
|||||||
params.insert("rule", objectRef("Rule"));
|
params.insert("rule", objectRef("Rule"));
|
||||||
registerNotification("RuleConfigurationChanged", description, params);
|
registerNotification("RuleConfigurationChanged", description, params);
|
||||||
|
|
||||||
connect(NymeaCore::instance(), &NymeaCore::ruleAdded, this, &RulesHandler::ruleAddedNotification);
|
connect(m_ruleEngine, &RuleEngine::ruleAdded, this, &RulesHandler::ruleAddedNotification);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::ruleRemoved, this, &RulesHandler::ruleRemovedNotification);
|
connect(m_ruleEngine, &RuleEngine::ruleRemoved, this, &RulesHandler::ruleRemovedNotification);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::ruleActiveChanged, this, &RulesHandler::ruleActiveChangedNotification);
|
connect(m_ruleEngine, &RuleEngine::ruleActiveChanged, this, &RulesHandler::ruleActiveChangedNotification);
|
||||||
connect(NymeaCore::instance(), &NymeaCore::ruleConfigurationChanged, this, &RulesHandler::ruleConfigurationChangedNotification);
|
connect(m_ruleEngine, &RuleEngine::ruleConfigurationChanged, this, &RulesHandler::ruleConfigurationChangedNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns the name of the \l{RulesHandler}. In this case \b Rules.*/
|
/*! Returns the name of the \l{RulesHandler}. In this case \b Rules.*/
|
||||||
@ -235,7 +235,7 @@ JsonReply* RulesHandler::GetRules(const QVariantMap ¶ms)
|
|||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
|
|
||||||
QVariantList rulesList;
|
QVariantList rulesList;
|
||||||
foreach (const Rule &rule, NymeaCore::instance()->ruleEngine()->rules()) {
|
foreach (const Rule &rule, m_ruleEngine->rules()) {
|
||||||
rulesList.append(packRuleDescription(rule));
|
rulesList.append(packRuleDescription(rule));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ JsonReply* RulesHandler::GetRules(const QVariantMap ¶ms)
|
|||||||
JsonReply *RulesHandler::GetRuleDetails(const QVariantMap ¶ms)
|
JsonReply *RulesHandler::GetRuleDetails(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
RuleId ruleId = RuleId(params.value("ruleId").toString());
|
RuleId ruleId = RuleId(params.value("ruleId").toString());
|
||||||
Rule rule = NymeaCore::instance()->ruleEngine()->findRule(ruleId);
|
Rule rule = m_ruleEngine->findRule(ruleId);
|
||||||
if (rule.id().isNull()) {
|
if (rule.id().isNull()) {
|
||||||
QVariantMap data;
|
QVariantMap data;
|
||||||
data.insert("ruleError", enumValueName<RuleEngine::RuleError>(RuleEngine::RuleErrorRuleNotFound));
|
data.insert("ruleError", enumValueName<RuleEngine::RuleError>(RuleEngine::RuleErrorRuleNotFound));
|
||||||
@ -264,7 +264,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms)
|
|||||||
Rule rule = unpack<Rule>(params);
|
Rule rule = unpack<Rule>(params);
|
||||||
rule.setId(RuleId::createRuleId());
|
rule.setId(RuleId::createRuleId());
|
||||||
|
|
||||||
RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->addRule(rule);
|
RuleEngine::RuleError status = m_ruleEngine->addRule(rule);
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
if (status == RuleEngine::RuleErrorNoError) {
|
if (status == RuleEngine::RuleErrorNoError) {
|
||||||
returns.insert("ruleId", rule.id().toString());
|
returns.insert("ruleId", rule.id().toString());
|
||||||
@ -280,10 +280,10 @@ JsonReply *RulesHandler::EditRule(const QVariantMap ¶ms)
|
|||||||
// FIXME: Edit rule API currently has "ruleId" while the Rule type has "id". Auto unpacking will fail for this property
|
// FIXME: Edit rule API currently has "ruleId" while the Rule type has "id". Auto unpacking will fail for this property
|
||||||
rule.setId(params.value("ruleId").toUuid());
|
rule.setId(params.value("ruleId").toUuid());
|
||||||
|
|
||||||
RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->editRule(rule);
|
RuleEngine::RuleError status = m_ruleEngine->editRule(rule);
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
if (status == RuleEngine::RuleErrorNoError) {
|
if (status == RuleEngine::RuleErrorNoError) {
|
||||||
returns.insert("rule", pack(NymeaCore::instance()->ruleEngine()->findRule(rule.id())));
|
returns.insert("rule", pack(m_ruleEngine->findRule(rule.id())));
|
||||||
}
|
}
|
||||||
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
@ -293,7 +293,7 @@ JsonReply* RulesHandler::RemoveRule(const QVariantMap ¶ms)
|
|||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
RuleId ruleId(params.value("ruleId").toString());
|
RuleId ruleId(params.value("ruleId").toString());
|
||||||
RuleEngine::RuleError status = NymeaCore::instance()->removeRule(ruleId);
|
RuleEngine::RuleError status = m_ruleEngine->removeRule(ruleId);
|
||||||
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ JsonReply* RulesHandler::RemoveRule(const QVariantMap ¶ms)
|
|||||||
JsonReply *RulesHandler::FindRules(const QVariantMap ¶ms)
|
JsonReply *RulesHandler::FindRules(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||||
QList<RuleId> rules = NymeaCore::instance()->ruleEngine()->findRules(thingId);
|
QList<RuleId> rules = m_ruleEngine->findRules(thingId);
|
||||||
|
|
||||||
QVariantList rulesList;
|
QVariantList rulesList;
|
||||||
foreach (const RuleId &ruleId, rules) {
|
foreach (const RuleId &ruleId, rules) {
|
||||||
@ -315,7 +315,7 @@ JsonReply *RulesHandler::FindRules(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
JsonReply *RulesHandler::EnableRule(const QVariantMap ¶ms)
|
JsonReply *RulesHandler::EnableRule(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->enableRule(RuleId(params.value("ruleId").toString()));
|
RuleEngine::RuleError status = m_ruleEngine->enableRule(RuleId(params.value("ruleId").toString()));
|
||||||
QVariantMap ret;
|
QVariantMap ret;
|
||||||
ret.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
ret.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
||||||
return createReply(ret);
|
return createReply(ret);
|
||||||
@ -323,7 +323,7 @@ JsonReply *RulesHandler::EnableRule(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
JsonReply *RulesHandler::DisableRule(const QVariantMap ¶ms)
|
JsonReply *RulesHandler::DisableRule(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->disableRule(RuleId(params.value("ruleId").toString()));
|
RuleEngine::RuleError status = m_ruleEngine->disableRule(RuleId(params.value("ruleId").toString()));
|
||||||
QVariantMap ret;
|
QVariantMap ret;
|
||||||
ret.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
ret.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
||||||
return createReply(ret);
|
return createReply(ret);
|
||||||
@ -333,7 +333,7 @@ JsonReply *RulesHandler::ExecuteActions(const QVariantMap ¶ms)
|
|||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
RuleId ruleId(params.value("ruleId").toString());
|
RuleId ruleId(params.value("ruleId").toString());
|
||||||
RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->executeActions(ruleId);
|
RuleEngine::RuleError status = m_ruleEngine->executeActions(ruleId);
|
||||||
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
@ -342,7 +342,7 @@ JsonReply *RulesHandler::ExecuteExitActions(const QVariantMap ¶ms)
|
|||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
RuleId ruleId(params.value("ruleId").toString());
|
RuleId ruleId(params.value("ruleId").toString());
|
||||||
RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->executeExitActions(ruleId);
|
RuleEngine::RuleError status = m_ruleEngine->executeExitActions(ruleId);
|
||||||
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,11 +37,13 @@
|
|||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
|
class RuleEngine;
|
||||||
|
|
||||||
class RulesHandler : public JsonHandler
|
class RulesHandler : public JsonHandler
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit RulesHandler(QObject *parent = nullptr);
|
explicit RulesHandler(RuleEngine *ruleEngine, QObject *parent = nullptr);
|
||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
|
|
||||||
@ -73,6 +75,9 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QVariantMap packRuleDescription(const Rule &rule);
|
QVariantMap packRuleDescription(const Rule &rule);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RuleEngine *m_ruleEngine = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,14 +106,6 @@ LogEngine::~LogEngine()
|
|||||||
m_db.close();
|
m_db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEngine::setThingManager(ThingManager *thingManager)
|
|
||||||
{
|
|
||||||
m_thingManager = thingManager;
|
|
||||||
connect(thingManager, &ThingManager::eventTriggered, this, &LogEngine::logEvent);
|
|
||||||
connect(thingManager, &ThingManager::thingStateChanged, this, &LogEngine::logStateChange);
|
|
||||||
connect(thingManager, &ThingManager::actionExecuted, this, &LogEngine::logAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogEntriesFetchJob *LogEngine::fetchLogEntries(const LogFilter &filter)
|
LogEntriesFetchJob *LogEngine::fetchLogEntries(const LogFilter &filter)
|
||||||
{
|
{
|
||||||
QList<LogEntry> results;
|
QList<LogEntry> results;
|
||||||
@ -233,10 +225,6 @@ void LogEngine::logSystemEvent(const QDateTime &dateTime, bool active, Logging::
|
|||||||
|
|
||||||
void LogEngine::logEvent(const Event &event)
|
void LogEngine::logEvent(const Event &event)
|
||||||
{
|
{
|
||||||
if (!event.logged()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantList valueList;
|
QVariantList valueList;
|
||||||
foreach (const Param ¶m, event.params()) {
|
foreach (const Param ¶m, event.params()) {
|
||||||
valueList << param.value();
|
valueList << param.value();
|
||||||
@ -255,10 +243,6 @@ void LogEngine::logEvent(const Event &event)
|
|||||||
|
|
||||||
void LogEngine::logStateChange(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value)
|
void LogEngine::logStateChange(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value)
|
||||||
{
|
{
|
||||||
if (!thing->loggedStateTypeIds().contains(stateTypeId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogEntry entry(Logging::LoggingSourceStates);
|
LogEntry entry(Logging::LoggingSourceStates);
|
||||||
entry.setTypeId(stateTypeId);
|
entry.setTypeId(stateTypeId);
|
||||||
entry.setThingId(thing->id());
|
entry.setThingId(thing->id());
|
||||||
|
|||||||
@ -61,8 +61,6 @@ public:
|
|||||||
LogEngine(const QString &driver, const QString &dbName, const QString &hostname = QString("127.0.0.1"), const QString &username = QString(), const QString &password = QString(), int maxDBSize = 50000, QObject *parent = nullptr);
|
LogEngine(const QString &driver, const QString &dbName, const QString &hostname = QString("127.0.0.1"), const QString &username = QString(), const QString &password = QString(), int maxDBSize = 50000, QObject *parent = nullptr);
|
||||||
~LogEngine();
|
~LogEngine();
|
||||||
|
|
||||||
void setThingManager(ThingManager *thingManager);
|
|
||||||
|
|
||||||
LogEntriesFetchJob *fetchLogEntries(const LogFilter &filter = LogFilter());
|
LogEntriesFetchJob *fetchLogEntries(const LogFilter &filter = LogFilter());
|
||||||
ThingsFetchJob *fetchThings();
|
ThingsFetchJob *fetchThings();
|
||||||
|
|
||||||
@ -76,6 +74,9 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void logSystemEvent(const QDateTime &dateTime, bool active, Logging::LoggingLevel level = Logging::LoggingLevelInfo);
|
void logSystemEvent(const QDateTime &dateTime, bool active, Logging::LoggingLevel level = Logging::LoggingLevelInfo);
|
||||||
|
void logEvent(const Event &event);
|
||||||
|
void logStateChange(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value);
|
||||||
|
void logAction(const Action &action, Thing::ThingError status);
|
||||||
void logBrowserAction(const BrowserAction &browserAction, Logging::LoggingLevel level = Logging::LoggingLevelInfo, int errorCode = 0);
|
void logBrowserAction(const BrowserAction &browserAction, Logging::LoggingLevel level = Logging::LoggingLevelInfo, int errorCode = 0);
|
||||||
void logBrowserItemAction(const BrowserItemAction &browserItemAction, Logging::LoggingLevel level = Logging::LoggingLevelInfo, int errorCode = 0);
|
void logBrowserItemAction(const BrowserItemAction &browserItemAction, Logging::LoggingLevel level = Logging::LoggingLevelInfo, int errorCode = 0);
|
||||||
void logRuleTriggered(const Rule &rule);
|
void logRuleTriggered(const Rule &rule);
|
||||||
@ -84,11 +85,6 @@ public slots:
|
|||||||
void logRuleActionsExecuted(const Rule &rule);
|
void logRuleActionsExecuted(const Rule &rule);
|
||||||
void logRuleExitActionsExecuted(const Rule &rule);
|
void logRuleExitActionsExecuted(const Rule &rule);
|
||||||
|
|
||||||
private slots:
|
|
||||||
void logEvent(const Event &event);
|
|
||||||
void logStateChange(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value);
|
|
||||||
void logAction(const Action &action, Thing::ThingError status);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void logEntryAdded(const LogEntry &logEntry);
|
void logEntryAdded(const LogEntry &logEntry);
|
||||||
void logDatabaseUpdated();
|
void logDatabaseUpdated();
|
||||||
@ -122,8 +118,6 @@ private:
|
|||||||
bool m_initialized = false;
|
bool m_initialized = false;
|
||||||
bool m_dbMalformed = false;
|
bool m_dbMalformed = false;
|
||||||
|
|
||||||
ThingManager *m_thingManager = nullptr;
|
|
||||||
|
|
||||||
// When maxQueueLength is exceeded, jobs will be flagged and discarded if this source logs more events
|
// When maxQueueLength is exceeded, jobs will be flagged and discarded if this source logs more events
|
||||||
int m_maxQueueLength;
|
int m_maxQueueLength;
|
||||||
QHash<QString, QList<DatabaseJob*>> m_flaggedJobs;
|
QHash<QString, QList<DatabaseJob*>> m_flaggedJobs;
|
||||||
|
|||||||
@ -121,15 +121,14 @@ void NymeaCore::init(const QStringList &additionalInterfaces) {
|
|||||||
qCDebug(dcCore) << "Creating Hardware Manager";
|
qCDebug(dcCore) << "Creating Hardware Manager";
|
||||||
m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), m_zigbeeManager, m_zwaveManager, m_modbusRtuManager, this);
|
m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), m_zigbeeManager, m_zwaveManager, m_modbusRtuManager, this);
|
||||||
|
|
||||||
qCDebug(dcCore) << "Creating Thing Manager (locale:" << m_configuration->locale() << ")";
|
|
||||||
m_thingManager = new ThingManagerImplementation(m_hardwareManager, m_configuration->locale(), this);
|
|
||||||
|
|
||||||
qCDebug(dcCore) << "Creating Rule Engine";
|
|
||||||
m_ruleEngine = new RuleEngine(this);
|
|
||||||
|
|
||||||
qCDebug(dcCore) << "Creating Log Engine";
|
qCDebug(dcCore) << "Creating Log Engine";
|
||||||
m_logger = new LogEngine(m_configuration->logDBDriver(), m_configuration->logDBName(), m_configuration->logDBHost(), m_configuration->logDBUser(), m_configuration->logDBPassword(), m_configuration->logDBMaxEntries(), this);
|
m_logger = new LogEngine(m_configuration->logDBDriver(), m_configuration->logDBName(), m_configuration->logDBHost(), m_configuration->logDBUser(), m_configuration->logDBPassword(), m_configuration->logDBMaxEntries(), this);
|
||||||
m_logger->setThingManager(m_thingManager);
|
|
||||||
|
qCDebug(dcCore) << "Creating Thing Manager (locale:" << m_configuration->locale() << ")";
|
||||||
|
m_thingManager = new ThingManagerImplementation(m_hardwareManager, m_logger, m_configuration->locale(), this);
|
||||||
|
|
||||||
|
qCDebug(dcCore) << "Creating Rule Engine";
|
||||||
|
m_ruleEngine = new RuleEngine(m_thingManager, m_timeManager, m_logger, this);
|
||||||
|
|
||||||
qCDebug(dcCore()) << "Creating Script Engine";
|
qCDebug(dcCore()) << "Creating Script Engine";
|
||||||
m_scriptEngine = new scriptengine::ScriptEngine(m_thingManager, this);
|
m_scriptEngine = new scriptengine::ScriptEngine(m_thingManager, this);
|
||||||
@ -151,22 +150,8 @@ void NymeaCore::init(const QStringList &additionalInterfaces) {
|
|||||||
|
|
||||||
connect(m_configuration, &NymeaConfiguration::serverNameChanged, m_serverManager, &ServerManager::setServerName);
|
connect(m_configuration, &NymeaConfiguration::serverNameChanged, m_serverManager, &ServerManager::setServerName);
|
||||||
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::pluginConfigChanged, this, &NymeaCore::pluginConfigChanged);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::eventTriggered, this, &NymeaCore::onEventTriggered);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::thingStateChanged, this, &NymeaCore::onThingStateChanged);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::thingAdded, this, &NymeaCore::thingAdded);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::thingChanged, this, &NymeaCore::thingChanged);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::thingSettingChanged, this, &NymeaCore::thingSettingChanged);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::thingRemoved, this, &NymeaCore::thingRemoved);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::thingDisappeared, this, &NymeaCore::onThingDisappeared);
|
|
||||||
connect(m_thingManager, &ThingManagerImplementation::loaded, this, &NymeaCore::thingManagerLoaded);
|
connect(m_thingManager, &ThingManagerImplementation::loaded, this, &NymeaCore::thingManagerLoaded);
|
||||||
|
|
||||||
connect(m_ruleEngine, &RuleEngine::ruleAdded, this, &NymeaCore::ruleAdded);
|
|
||||||
connect(m_ruleEngine, &RuleEngine::ruleRemoved, this, &NymeaCore::ruleRemoved);
|
|
||||||
connect(m_ruleEngine, &RuleEngine::ruleConfigurationChanged, this, &NymeaCore::ruleConfigurationChanged);
|
|
||||||
|
|
||||||
connect(m_timeManager, &TimeManager::dateTimeChanged, this, &NymeaCore::onDateTimeChanged);
|
|
||||||
|
|
||||||
m_logger->logSystemEvent(m_timeManager->currentDateTime(), true);
|
m_logger->logSystemEvent(m_timeManager->currentDateTime(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,322 +200,6 @@ void NymeaCore::destroy()
|
|||||||
s_instance = nullptr;
|
s_instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<Thing::ThingError, QList<RuleId> > NymeaCore::removeConfiguredThing(const ThingId &thingId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList)
|
|
||||||
{
|
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
|
||||||
|
|
||||||
if (!thing) {
|
|
||||||
return QPair<Thing::ThingError, QList<RuleId> > (Thing::ThingErrorThingNotFound, QList<RuleId>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a child
|
|
||||||
if (!thing->parentId().isNull() && thing->autoCreated()) {
|
|
||||||
qCWarning(dcThingManager) << "Thing is an autocreated child of" << thing->parentId().toString() << ". Please remove the parent.";
|
|
||||||
return QPair<Thing::ThingError, QList<RuleId> > (Thing::ThingErrorThingIsChild, QList<RuleId>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Let's remove this for now. It will come back with more fine grained control, presumably introducing a RemoveMethod flag in the DeviceClass
|
|
||||||
// if (thing->autoCreated()) {
|
|
||||||
// qCWarning(dcThingManager) << "This thing has been auto-created and cannot be deleted manually.";
|
|
||||||
// return QPair<Thing::ThingError, QList<RuleId> >(Thing::ThingErrorCreationMethodNotSupported, {});
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Check if this thing has childs
|
|
||||||
QList<Thing *> thingsToRemove;
|
|
||||||
thingsToRemove.append(thing);
|
|
||||||
QList<Thing *> childs = m_thingManager->findChilds(thingId);
|
|
||||||
if (!childs.isEmpty()) {
|
|
||||||
foreach (Thing *child, childs) {
|
|
||||||
thingsToRemove.append(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check things
|
|
||||||
QList<RuleId> offendingRules;
|
|
||||||
qCDebug(dcThingManager) << "Things to remove:";
|
|
||||||
foreach (Thing *d, thingsToRemove) {
|
|
||||||
qCDebug(dcThingManager) << " -> " << d->name() << d->id().toString();
|
|
||||||
|
|
||||||
// Check if thing is in a rule
|
|
||||||
foreach (const RuleId &ruleId, m_ruleEngine->findRules(d->id())) {
|
|
||||||
qCDebug(dcThingManager) << " -> in rule:" << ruleId.toString();
|
|
||||||
if (!offendingRules.contains(ruleId)) {
|
|
||||||
offendingRules.append(ruleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check each offending rule if there is a corresponding remove policy
|
|
||||||
QHash<RuleId, RuleEngine::RemovePolicy> toBeChanged;
|
|
||||||
QList<RuleId> unhandledRules;
|
|
||||||
foreach (const RuleId &ruleId, offendingRules) {
|
|
||||||
bool found = false;
|
|
||||||
foreach (const RuleId &policyRuleId, removePolicyList.keys()) {
|
|
||||||
if (ruleId == policyRuleId) {
|
|
||||||
found = true;
|
|
||||||
toBeChanged.insert(ruleId, removePolicyList.value(ruleId));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
unhandledRules.append(ruleId);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!unhandledRules.isEmpty()) {
|
|
||||||
qCWarning(dcThingManager) << "There are unhandled rules which depend on this thing:\n" << unhandledRules;
|
|
||||||
return QPair<Thing::ThingError, QList<RuleId> > (Thing::ThingErrorThingInRule, unhandledRules);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the rules...
|
|
||||||
foreach (const RuleId &ruleId, toBeChanged.keys()) {
|
|
||||||
if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyCascade) {
|
|
||||||
m_ruleEngine->removeRule(ruleId);
|
|
||||||
} else if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyUpdate){
|
|
||||||
foreach (Thing *thing, thingsToRemove) {
|
|
||||||
m_ruleEngine->removeThingFromRule(ruleId, thing->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the childs
|
|
||||||
foreach (Thing *d, childs) {
|
|
||||||
Thing::ThingError removeError = m_thingManager->removeConfiguredThing(d->id());
|
|
||||||
if (removeError == Thing::ThingErrorNoError) {
|
|
||||||
m_logger->removeThingLogs(d->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the things
|
|
||||||
Thing::ThingError removeError = m_thingManager->removeConfiguredThing(thingId);
|
|
||||||
if (removeError == Thing::ThingErrorNoError) {
|
|
||||||
m_logger->removeThingLogs(thingId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return QPair<Thing::ThingError, QList<RuleId> > (Thing::ThingErrorNoError, QList<RuleId>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Thing::ThingError NymeaCore::removeConfiguredThing(const ThingId &thingId, const RuleEngine::RemovePolicy &removePolicy)
|
|
||||||
{
|
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
|
||||||
|
|
||||||
if (!thing) {
|
|
||||||
return Thing::ThingErrorThingNotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a child
|
|
||||||
if (!thing->parentId().isNull() && thing->autoCreated()) {
|
|
||||||
qCWarning(dcThingManager) << "Thing is an autocreated child of" << thing->parentId().toString() << ". Please remove the parent.";
|
|
||||||
return Thing::ThingErrorThingIsChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Let's remove this for now. It will come back with more fine grained control, presumably introducing a RemoveMethod flag in the DeviceClass
|
|
||||||
// if (thing->autoCreated()) {
|
|
||||||
// qCWarning(dcThingManager) << "This thing has been auto-created and cannot be deleted manually.";
|
|
||||||
// return Thing::ThingErrorCreationMethodNotSupported;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Check if this thing has childs
|
|
||||||
QList<Thing *> thingsToRemove;
|
|
||||||
thingsToRemove.append(thing);
|
|
||||||
QList<Thing *> childs = m_thingManager->findChilds(thingId);
|
|
||||||
if (!childs.isEmpty()) {
|
|
||||||
foreach (Thing *child, childs) {
|
|
||||||
thingsToRemove.append(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check things
|
|
||||||
QList<RuleId> offendingRules;
|
|
||||||
qCDebug(dcThingManager) << "Things to remove:";
|
|
||||||
foreach (Thing *d, thingsToRemove) {
|
|
||||||
qCDebug(dcThingManager) << " -> " << d->name() << d->id().toString();
|
|
||||||
|
|
||||||
// Check if thing is in a rule
|
|
||||||
foreach (const RuleId &ruleId, m_ruleEngine->findRules(d->id())) {
|
|
||||||
qCDebug(dcThingManager) << " -> in rule:" << ruleId.toString();
|
|
||||||
if (!offendingRules.contains(ruleId)) {
|
|
||||||
offendingRules.append(ruleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply removepolicy for foreach rule
|
|
||||||
foreach (const RuleId &ruleId, offendingRules) {
|
|
||||||
if (removePolicy == RuleEngine::RemovePolicyCascade) {
|
|
||||||
m_ruleEngine->removeRule(ruleId);
|
|
||||||
} else if (removePolicy == RuleEngine::RemovePolicyUpdate){
|
|
||||||
foreach (Thing *thing, thingsToRemove) {
|
|
||||||
m_ruleEngine->removeThingFromRule(ruleId, thing->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the childs
|
|
||||||
foreach (Thing *d, childs) {
|
|
||||||
Thing::ThingError removeError = m_thingManager->removeConfiguredThing(d->id());
|
|
||||||
if (removeError == Thing::ThingErrorNoError) {
|
|
||||||
m_logger->removeThingLogs(d->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the things
|
|
||||||
Thing::ThingError removeError = m_thingManager->removeConfiguredThing(thingId);
|
|
||||||
if (removeError == Thing::ThingErrorNoError) {
|
|
||||||
m_logger->removeThingLogs(thingId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return removeError;
|
|
||||||
}
|
|
||||||
|
|
||||||
BrowserActionInfo* NymeaCore::executeBrowserItem(const BrowserAction &browserAction)
|
|
||||||
{
|
|
||||||
BrowserActionInfo *info = m_thingManager->executeBrowserItem(browserAction);
|
|
||||||
connect(info, &BrowserActionInfo::finished, info->thing(), [this, info](){
|
|
||||||
m_logger->logBrowserAction(info->browserAction(), info->status() == Thing::ThingErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, info->status());
|
|
||||||
});
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
BrowserItemActionInfo *NymeaCore::executeBrowserItemAction(const BrowserItemAction &browserItemAction)
|
|
||||||
{
|
|
||||||
BrowserItemActionInfo *info = m_thingManager->executeBrowserItemAction(browserItemAction);
|
|
||||||
connect(info, &BrowserItemActionInfo::finished, info->thing(), [this, info](){
|
|
||||||
m_logger->logBrowserItemAction(info->browserItemAction(), info->status() == Thing::ThingErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, info->status());
|
|
||||||
});
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Execute the given \a ruleActions. */
|
|
||||||
void NymeaCore::executeRuleActions(const QList<RuleAction> ruleActions)
|
|
||||||
{
|
|
||||||
QList<Action> actions;
|
|
||||||
QList<BrowserAction> browserActions;
|
|
||||||
foreach (const RuleAction &ruleAction, ruleActions) {
|
|
||||||
if (ruleAction.type() == RuleAction::TypeThing) {
|
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(ruleAction.thingId());
|
|
||||||
if (!thing) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Unable to find thing" << ruleAction.thingId() << "for rule action" << ruleAction;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ActionTypeId actionTypeId = ruleAction.actionTypeId();
|
|
||||||
ParamList params;
|
|
||||||
bool ok = true;
|
|
||||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
|
||||||
if (ruleActionParam.isValueBased()) {
|
|
||||||
params.append(Param(ruleActionParam.paramTypeId(), ruleActionParam.value()));
|
|
||||||
} else if (ruleActionParam.isStateBased()) {
|
|
||||||
Thing *stateThing = m_thingManager->findConfiguredThing(ruleActionParam.stateThingId());
|
|
||||||
if (!stateThing) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Cannot find thing" << ruleActionParam.stateThingId() << "required by rule action";
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ThingClass stateThingClass = m_thingManager->findThingClass(stateThing->thingClassId());
|
|
||||||
if (!stateThingClass.hasStateType(ruleActionParam.stateTypeId())) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Device" << thing->name() << thing->id() << "does not have a state type" << ruleActionParam.stateTypeId();
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
params.append(Param(ruleActionParam.paramTypeId(), stateThing->stateValue(ruleActionParam.stateTypeId())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Not executing rule action";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Action action(actionTypeId, thing->id(), Action::TriggeredByRule);
|
|
||||||
action.setParams(params);
|
|
||||||
actions.append(action);
|
|
||||||
} else if (ruleAction.type() == RuleAction::TypeBrowser) {
|
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(ruleAction.thingId());
|
|
||||||
if (!thing) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Unable to find thing" << ruleAction.thingId() << "for rule action" << ruleAction;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BrowserAction browserAction(ruleAction.thingId(), ruleAction.browserItemId());
|
|
||||||
browserActions.append(browserAction);
|
|
||||||
} else {
|
|
||||||
Things things = m_thingManager->findConfiguredThings(ruleAction.interface());
|
|
||||||
foreach (Thing* thing, things) {
|
|
||||||
ThingClass thingClass = m_thingManager->findThingClass(thing->thingClassId());
|
|
||||||
ActionType actionType = thingClass.actionTypes().findByName(ruleAction.interfaceAction());
|
|
||||||
if (actionType.id().isNull()) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Error creating Action. The given ThingClass does not implement action:" << ruleAction.interfaceAction();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ParamList params;
|
|
||||||
bool ok = true;
|
|
||||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
|
||||||
ParamType paramType = actionType.paramTypes().findByName(ruleActionParam.paramName());
|
|
||||||
if (paramType.id().isNull()) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Error creating Action. The given ActionType does not have a parameter:" << ruleActionParam.paramName();
|
|
||||||
ok = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ruleActionParam.isValueBased()) {
|
|
||||||
params.append(Param(paramType.id(), ruleActionParam.value()));
|
|
||||||
} else if (ruleActionParam.isStateBased()) {
|
|
||||||
Thing *stateThing = m_thingManager->findConfiguredThing(ruleActionParam.stateThingId());
|
|
||||||
if (!stateThing) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Cannot find thing" << ruleActionParam.stateThingId() << "required by rule action";
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ThingClass stateThingClass = m_thingManager->findThingClass(stateThing->thingClassId());
|
|
||||||
if (!stateThingClass.hasStateType(ruleActionParam.stateTypeId())) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Thing" << thing->name() << thing->id() << "does not have a state type" << ruleActionParam.stateTypeId();
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
params.append(Param(paramType.id(), stateThing->stateValue(ruleActionParam.stateTypeId())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
qCWarning(dcRuleEngine()) << "Not executing rule action";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Action action = Action(actionType.id(), thing->id(), Action::TriggeredByRule);
|
|
||||||
action.setParams(params);
|
|
||||||
actions.append(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const Action &action, actions) {
|
|
||||||
qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params();
|
|
||||||
ThingActionInfo *info = m_thingManager->executeAction(action);
|
|
||||||
connect(info, &ThingActionInfo::finished, this, [info](){
|
|
||||||
if (info->status() != Thing::ThingErrorNoError) {
|
|
||||||
qCWarning(dcRuleEngine) << "Error executing action:" << info->status() << info->displayMessage();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const BrowserAction &browserAction, browserActions) {
|
|
||||||
BrowserActionInfo *info = executeBrowserItem(browserAction);
|
|
||||||
connect(info, &BrowserActionInfo::finished, this, [info](){
|
|
||||||
if (info->status() != Thing::ThingErrorNoError) {
|
|
||||||
qCWarning(dcRuleEngine) << "Error executing browser action:" << info->status();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Calls the metheod RuleEngine::removeRule(\a id).
|
|
||||||
* \sa RuleEngine, */
|
|
||||||
RuleEngine::RuleError NymeaCore::removeRule(const RuleId &id)
|
|
||||||
{
|
|
||||||
RuleEngine::RuleError removeError = m_ruleEngine->removeRule(id);
|
|
||||||
if (removeError == RuleEngine::RuleErrorNoError)
|
|
||||||
m_logger->removeRuleLogs(id);
|
|
||||||
|
|
||||||
return removeError;
|
|
||||||
}
|
|
||||||
|
|
||||||
NymeaConfiguration *NymeaCore::configuration() const
|
NymeaConfiguration *NymeaCore::configuration() const
|
||||||
{
|
{
|
||||||
return m_configuration;
|
return m_configuration;
|
||||||
@ -663,117 +332,6 @@ ExperienceManager *NymeaCore::experienceManager() const
|
|||||||
return m_experienceManager;
|
return m_experienceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NymeaCore::onEventTriggered(const Event &event)
|
|
||||||
{
|
|
||||||
emit eventTriggered(event);
|
|
||||||
evaluateRules(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NymeaCore::onThingStateChanged(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &minValue, const QVariant &maxValue)
|
|
||||||
{
|
|
||||||
emit thingStateChanged(thing, stateTypeId, value, minValue, maxValue);
|
|
||||||
|
|
||||||
// The rule engine can have event based rules that would trigger when a state changes
|
|
||||||
// without "binding" to the state (as a stateEvaluator would do). So generate a fake event
|
|
||||||
// for every state change.
|
|
||||||
// TODO: This whole rule engine related code in this file should probably move into the RuleEngine itself.
|
|
||||||
Param valueParam(ParamTypeId(stateTypeId.toString()), value);
|
|
||||||
Event event(EventTypeId(stateTypeId.toString()), thing->id(), ParamList() << valueParam);
|
|
||||||
evaluateRules(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NymeaCore::evaluateRules(const Event &event)
|
|
||||||
{
|
|
||||||
QList<RuleAction> actions;
|
|
||||||
QList<RuleAction> eventBasedActions;
|
|
||||||
foreach (const Rule &rule, m_ruleEngine->evaluateEvent(event)) {
|
|
||||||
if (m_executingRules.contains(rule.id())) {
|
|
||||||
qCWarning(dcRuleEngine()) << "WARNING: Loop detected in rule execution for rule" << rule.id().toString() << rule.name();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
m_executingRules.append(rule.id());
|
|
||||||
|
|
||||||
// Event based
|
|
||||||
if (!rule.eventDescriptors().isEmpty()) {
|
|
||||||
m_logger->logRuleTriggered(rule);
|
|
||||||
QList<RuleAction> tmp;
|
|
||||||
if (rule.statesActive() && rule.timeActive()) {
|
|
||||||
qCDebug(dcRuleEngineDebug()) << "Executing actions";
|
|
||||||
tmp = rule.actions();
|
|
||||||
} else {
|
|
||||||
qCDebug(dcRuleEngineDebug()) << "Executing exitActions";
|
|
||||||
tmp = rule.exitActions();
|
|
||||||
}
|
|
||||||
// check if we have an event based action or a normal action
|
|
||||||
foreach (const RuleAction &action, tmp) {
|
|
||||||
if (action.isEventBased()) {
|
|
||||||
eventBasedActions.append(action);
|
|
||||||
} else {
|
|
||||||
actions.append(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// State based rule
|
|
||||||
m_logger->logRuleActiveChanged(rule);
|
|
||||||
emit ruleActiveChanged(rule);
|
|
||||||
if (rule.active()) {
|
|
||||||
actions.append(rule.actions());
|
|
||||||
} else {
|
|
||||||
actions.append(rule.exitActions());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set action params, depending on the event value
|
|
||||||
foreach (RuleAction ruleAction, eventBasedActions) {
|
|
||||||
RuleActionParams newParams;
|
|
||||||
foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) {
|
|
||||||
// if this event param should be taken over in this action
|
|
||||||
if (event.eventTypeId() == ruleActionParam.eventTypeId()) {
|
|
||||||
QVariant eventValue = event.params().paramValue(ruleActionParam.eventParamTypeId());
|
|
||||||
|
|
||||||
// TODO: limits / scale calculation -> actionValue = eventValue * x
|
|
||||||
// something like a EventParamDescriptor
|
|
||||||
|
|
||||||
ruleActionParam.setValue(eventValue);
|
|
||||||
qCDebug(dcRuleEngine) << "Using param value from event:" << ruleActionParam.value();
|
|
||||||
}
|
|
||||||
newParams.append(ruleActionParam);
|
|
||||||
}
|
|
||||||
ruleAction.setRuleActionParams(newParams);
|
|
||||||
actions.append(ruleAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
executeRuleActions(actions);
|
|
||||||
m_executingRules.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NymeaCore::onDateTimeChanged(const QDateTime &dateTime)
|
|
||||||
{
|
|
||||||
QList<RuleAction> actions;
|
|
||||||
foreach (const Rule &rule, m_ruleEngine->evaluateTime(dateTime)) {
|
|
||||||
// TimeEvent based
|
|
||||||
if (!rule.timeDescriptor().timeEventItems().isEmpty()) {
|
|
||||||
m_logger->logRuleTriggered(rule);
|
|
||||||
if (rule.statesActive() && rule.timeActive()) {
|
|
||||||
actions.append(rule.actions());
|
|
||||||
} else {
|
|
||||||
actions.append(rule.exitActions());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Calendar based rule
|
|
||||||
m_logger->logRuleActiveChanged(rule);
|
|
||||||
emit ruleActiveChanged(rule);
|
|
||||||
if (rule.active()) {
|
|
||||||
actions.append(rule.actions());
|
|
||||||
} else {
|
|
||||||
actions.append(rule.exitActions());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
executeRuleActions(actions);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogEngine* NymeaCore::logEngine() const
|
LogEngine* NymeaCore::logEngine() const
|
||||||
{
|
{
|
||||||
return m_logger;
|
return m_logger;
|
||||||
@ -784,65 +342,8 @@ JsonRPCServerImplementation *NymeaCore::jsonRPCServer() const
|
|||||||
return m_serverManager->jsonServer();
|
return m_serverManager->jsonServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NymeaCore::onThingDisappeared(const ThingId &thingId)
|
|
||||||
{
|
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
|
||||||
if (!thing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this thing has childs
|
|
||||||
Things thingsToRemove;
|
|
||||||
thingsToRemove.append(thing);
|
|
||||||
QList<Thing *> childs = m_thingManager->findChilds(thingId);
|
|
||||||
if (!childs.isEmpty()) {
|
|
||||||
foreach (Thing *child, childs) {
|
|
||||||
thingsToRemove.append(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check things
|
|
||||||
QList<RuleId> offendingRules;
|
|
||||||
qCDebug(dcThingManager) << "Thing to remove:";
|
|
||||||
foreach (Thing *d, thingsToRemove) {
|
|
||||||
qCDebug(dcThingManager) << " -> " << d->name() << d->id().toString();
|
|
||||||
|
|
||||||
// Check if thing is in a rule
|
|
||||||
foreach (const RuleId &ruleId, m_ruleEngine->findRules(d->id())) {
|
|
||||||
qCDebug(dcThingManager) << " -> in rule:" << ruleId.toString();
|
|
||||||
if (!offendingRules.contains(ruleId)) {
|
|
||||||
offendingRules.append(ruleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update involved rules
|
|
||||||
foreach (const RuleId &ruleId, offendingRules) {
|
|
||||||
foreach (Thing *thing, thingsToRemove) {
|
|
||||||
m_ruleEngine->removeThingFromRule(ruleId, thing->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the child devices
|
|
||||||
foreach (Thing *d, childs) {
|
|
||||||
Thing::ThingError removeError = m_thingManager->removeConfiguredThing(d->id());
|
|
||||||
if (removeError == Thing::ThingErrorNoError) {
|
|
||||||
m_logger->removeThingLogs(d->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the thing
|
|
||||||
Thing::ThingError removeError = m_thingManager->removeConfiguredThing(thingId);
|
|
||||||
if (removeError == Thing::ThingErrorNoError) {
|
|
||||||
m_logger->removeThingLogs(thingId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NymeaCore::thingManagerLoaded()
|
void NymeaCore::thingManagerLoaded()
|
||||||
{
|
{
|
||||||
m_ruleEngine->init();
|
|
||||||
// Evaluate rules on current time
|
|
||||||
onDateTimeChanged(m_timeManager->currentDateTime());
|
|
||||||
|
|
||||||
// Tell hardare resources we're done with loading stuff...
|
// Tell hardare resources we're done with loading stuff...
|
||||||
m_hardwareManager->thingsLoaded();
|
m_hardwareManager->thingsLoaded();
|
||||||
@ -881,7 +382,8 @@ void NymeaCore::thingManagerLoaded()
|
|||||||
qCDebug(dcCore()) << "Cleaning up stale thing tag" << tag.tagId();
|
qCDebug(dcCore()) << "Cleaning up stale thing tag" << tag.tagId();
|
||||||
m_tagsStorage->removeTag(tag);
|
m_tagsStorage->removeTag(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,15 +87,6 @@ public:
|
|||||||
void init(const QStringList &additionalInterfaces = QStringList());
|
void init(const QStringList &additionalInterfaces = QStringList());
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
// Thing handling
|
|
||||||
QPair<Thing::ThingError, QList<RuleId> >removeConfiguredThing(const ThingId &thingId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList);
|
|
||||||
Thing::ThingError removeConfiguredThing(const ThingId &thingId, const RuleEngine::RemovePolicy &removePolicy);
|
|
||||||
|
|
||||||
BrowserActionInfo* executeBrowserItem(const BrowserAction &browserAction);
|
|
||||||
BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction);
|
|
||||||
|
|
||||||
void executeRuleActions(const QList<RuleAction> ruleActions);
|
|
||||||
|
|
||||||
RuleEngine::RuleError removeRule(const RuleId &id);
|
RuleEngine::RuleError removeRule(const RuleId &id);
|
||||||
|
|
||||||
NymeaConfiguration *configuration() const;
|
NymeaConfiguration *configuration() const;
|
||||||
@ -125,19 +116,6 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void initialized();
|
void initialized();
|
||||||
|
|
||||||
void pluginConfigChanged(const PluginId &id, const ParamList &config);
|
|
||||||
void eventTriggered(const Event &event);
|
|
||||||
void thingStateChanged(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &minValue, const QVariant &maxValue);
|
|
||||||
void thingRemoved(const ThingId &thingId);
|
|
||||||
void thingAdded(Thing *thing);
|
|
||||||
void thingChanged(Thing *thing);
|
|
||||||
void thingSettingChanged(const ThingId &thingId, const ParamTypeId &settingParamTypeId, const QVariant &value);
|
|
||||||
|
|
||||||
void ruleRemoved(const RuleId &ruleId);
|
|
||||||
void ruleAdded(const Rule &rule);
|
|
||||||
void ruleActiveChanged(const Rule &rule);
|
|
||||||
void ruleConfigurationChanged(const Rule &rule);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit NymeaCore(QObject *parent = nullptr);
|
explicit NymeaCore(QObject *parent = nullptr);
|
||||||
static NymeaCore *s_instance;
|
static NymeaCore *s_instance;
|
||||||
@ -165,14 +143,8 @@ private:
|
|||||||
SerialPortMonitor *m_serialPortMonitor;
|
SerialPortMonitor *m_serialPortMonitor;
|
||||||
ModbusRtuManager *m_modbusRtuManager;
|
ModbusRtuManager *m_modbusRtuManager;
|
||||||
|
|
||||||
QList<RuleId> m_executingRules;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onEventTriggered(const Event &event);
|
|
||||||
void onThingStateChanged(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &minValue, const QVariant &maxValue);
|
|
||||||
void evaluateRules(const Event &event);
|
|
||||||
void onDateTimeChanged(const QDateTime &dateTime);
|
|
||||||
void onThingDisappeared(const ThingId &thingId);
|
|
||||||
void thingManagerLoaded();
|
void thingManagerLoaded();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -207,19 +207,16 @@ bool Rule::isConsistent() const
|
|||||||
{
|
{
|
||||||
// check if this rules is based on any event and contains exit actions
|
// check if this rules is based on any event and contains exit actions
|
||||||
if (!eventDescriptors().isEmpty() && stateEvaluator().isEmpty() && timeDescriptor().calendarItems().isEmpty() && !exitActions().isEmpty()) {
|
if (!eventDescriptors().isEmpty() && stateEvaluator().isEmpty() && timeDescriptor().calendarItems().isEmpty() && !exitActions().isEmpty()) {
|
||||||
qCWarning(dcRuleEngine) << "Rule not consistent. The exitActions will never be executed if the rule contains an eventDescriptor but no stateEvaluator or calendarItem.";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this rules is based on any time events and contains exit actions
|
// check if this rules is based on any time events and contains exit actions
|
||||||
if (!timeDescriptor().timeEventItems().isEmpty() && stateEvaluator().isEmpty() && timeDescriptor().calendarItems().isEmpty() && !exitActions().isEmpty()) {
|
if (!timeDescriptor().timeEventItems().isEmpty() && stateEvaluator().isEmpty() && timeDescriptor().calendarItems().isEmpty() && !exitActions().isEmpty()) {
|
||||||
qCWarning(dcRuleEngine) << "Rule not consistent. The exitActions will never be executed if the rule contains a timeEvent but no stateEvaluator or calendarItem.";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there are any actions
|
// check if there are any actions
|
||||||
if (actions().isEmpty()) {
|
if (actions().isEmpty()) {
|
||||||
qCWarning(dcRuleEngine) << "Rule not consistent. A rule without actions has no effect.";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -110,31 +110,58 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "ruleengine.h"
|
#include "ruleengine.h"
|
||||||
#include "nymeacore.h"
|
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
#include "time/calendaritem.h"
|
#include "time/calendaritem.h"
|
||||||
#include "time/repeatingoption.h"
|
#include "time/repeatingoption.h"
|
||||||
#include "time/timeeventitem.h"
|
#include "time/timeeventitem.h"
|
||||||
|
#include "time/timemanager.h"
|
||||||
|
|
||||||
#include "types/eventdescriptor.h"
|
#include "types/eventdescriptor.h"
|
||||||
#include "types/paramdescriptor.h"
|
#include "types/paramdescriptor.h"
|
||||||
#include "nymeasettings.h"
|
#include "nymeasettings.h"
|
||||||
#include "integrations/thingmanager.h"
|
#include "integrations/thingmanager.h"
|
||||||
#include "integrations/thing.h"
|
#include "integrations/thing.h"
|
||||||
|
#include "logging/logengine.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
NYMEA_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine")
|
||||||
|
NYMEA_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug")
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
/*! Constructs the RuleEngine with the given \a parent. Although it wouldn't harm to have multiple RuleEngines, there is one
|
/*! Constructs the RuleEngine with the given \a parent. Although it wouldn't harm to have multiple RuleEngines, there is one
|
||||||
instance available from \l{NymeaCore}. This one should be used instead of creating multiple ones.
|
instance available from \l{NymeaCore}. This one should be used instead of creating multiple ones.
|
||||||
*/
|
*/
|
||||||
RuleEngine::RuleEngine(QObject *parent) :
|
RuleEngine::RuleEngine(ThingManager *thingManager, TimeManager *timeManager, LogEngine *logEngine, QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent),
|
||||||
|
m_thingManager(thingManager),
|
||||||
|
m_timeManager(timeManager),
|
||||||
|
m_logEngine(logEngine)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
connect(m_thingManager, &ThingManager::eventTriggered, this, &RuleEngine::onEventTriggered);
|
||||||
|
|
||||||
|
connect(m_thingManager, &ThingManager::thingStateChanged, this, [this](Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &/*minValue*/, const QVariant &/*maxValue*/){
|
||||||
|
// There can be event based rules that would trigger when a state changes
|
||||||
|
// without "binding" to the state (as a stateEvaluator would do). So generate a fake event
|
||||||
|
// for every state change.
|
||||||
|
Param valueParam(ParamTypeId(stateTypeId.toString()), value);
|
||||||
|
Event event(EventTypeId(stateTypeId.toString()), thing->id(), ParamList() << valueParam);
|
||||||
|
onEventTriggered(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_thingManager, &ThingManager::thingRemoved, this, &RuleEngine::onThingRemoved);
|
||||||
|
|
||||||
|
connect(m_timeManager, &TimeManager::dateTimeChanged, this, &RuleEngine::onDateTimeChanged);
|
||||||
|
|
||||||
|
connect(m_thingManager, &ThingManager::loaded, this, [=](){
|
||||||
|
init();
|
||||||
|
onDateTimeChanged(m_timeManager->currentDateTime());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Destructor of the \l{RuleEngine}. */
|
/*! Destructor of the \l{RuleEngine}. */
|
||||||
@ -150,7 +177,7 @@ RuleEngine::~RuleEngine()
|
|||||||
*/
|
*/
|
||||||
QList<Rule> RuleEngine::evaluateEvent(const Event &event)
|
QList<Rule> RuleEngine::evaluateEvent(const Event &event)
|
||||||
{
|
{
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(event.thingId());
|
Thing *thing = m_thingManager->findConfiguredThing(event.thingId());
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
qCWarning(dcRuleEngine()) << "Invalid event. ThingID does not reference a valid thing";
|
qCWarning(dcRuleEngine()) << "Invalid event. ThingID does not reference a valid thing";
|
||||||
return QList<Rule>();
|
return QList<Rule>();
|
||||||
@ -307,7 +334,7 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rule.isConsistent()) {
|
if (!rule.isConsistent()) {
|
||||||
qCWarning(dcRuleEngine) << "Rule inconsistent.";
|
qCWarning(dcRuleEngine) << "Invalid rule format. (Either missing actions, or exitActions without condition given.)";
|
||||||
return RuleErrorInvalidRuleFormat;
|
return RuleErrorInvalidRuleFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,14 +346,14 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
|||||||
}
|
}
|
||||||
if (eventDescriptor.type() == EventDescriptor::TypeThing) {
|
if (eventDescriptor.type() == EventDescriptor::TypeThing) {
|
||||||
// check thingId
|
// check thingId
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(eventDescriptor.thingId());
|
Thing *thing = m_thingManager->findConfiguredThing(eventDescriptor.thingId());
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured thing for eventTypeId" << eventDescriptor.eventTypeId();
|
qCWarning(dcRuleEngine) << "Cannot create rule. No configured thing for eventTypeId" << eventDescriptor.eventTypeId();
|
||||||
return RuleErrorThingNotFound;
|
return RuleErrorThingNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check eventTypeId for this deivce
|
// Check eventTypeId for this deivce
|
||||||
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(thing->thingClassId());
|
ThingClass thingClass = m_thingManager->findThingClass(thing->thingClassId());
|
||||||
bool eventTypeFound = false;
|
bool eventTypeFound = false;
|
||||||
foreach (const EventType &eventType, thingClass.eventTypes()) {
|
foreach (const EventType &eventType, thingClass.eventTypes()) {
|
||||||
if (eventType.id() == eventDescriptor.eventTypeId()) {
|
if (eventType.id() == eventDescriptor.eventTypeId()) {
|
||||||
@ -345,7 +372,7 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Interface based event
|
// Interface based event
|
||||||
Interface iface = NymeaCore::instance()->thingManager()->supportedInterfaces().findByName(eventDescriptor.interface());
|
Interface iface = m_thingManager->supportedInterfaces().findByName(eventDescriptor.interface());
|
||||||
if (!iface.isValid()) {
|
if (!iface.isValid()) {
|
||||||
qWarning(dcRuleEngine()) << "No such interface:" << eventDescriptor.interface();
|
qWarning(dcRuleEngine()) << "No such interface:" << eventDescriptor.interface();
|
||||||
return RuleErrorInterfaceNotFound;
|
return RuleErrorInterfaceNotFound;
|
||||||
@ -507,6 +534,8 @@ RuleEngine::RuleError RuleEngine::removeRule(const RuleId &ruleId, bool fromEdit
|
|||||||
settings.remove("");
|
settings.remove("");
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
|
m_logEngine->removeRuleLogs(ruleId);
|
||||||
|
|
||||||
if (!fromEdit)
|
if (!fromEdit)
|
||||||
emit ruleRemoved(ruleId);
|
emit ruleRemoved(ruleId);
|
||||||
|
|
||||||
@ -536,7 +565,7 @@ RuleEngine::RuleError RuleEngine::enableRule(const RuleId &ruleId)
|
|||||||
saveRule(rule);
|
saveRule(rule);
|
||||||
emit ruleConfigurationChanged(rule);
|
emit ruleConfigurationChanged(rule);
|
||||||
|
|
||||||
NymeaCore::instance()->logEngine()->logRuleEnabledChanged(rule, true);
|
m_logEngine->logRuleEnabledChanged(rule, true);
|
||||||
qCDebug(dcRuleEngine()) << "Rule" << rule.name() << rule.id().toString() << "enabled.";
|
qCDebug(dcRuleEngine()) << "Rule" << rule.name() << rule.id().toString() << "enabled.";
|
||||||
|
|
||||||
return RuleErrorNoError;
|
return RuleErrorNoError;
|
||||||
@ -562,7 +591,7 @@ RuleEngine::RuleError RuleEngine::disableRule(const RuleId &ruleId)
|
|||||||
saveRule(rule);
|
saveRule(rule);
|
||||||
emit ruleConfigurationChanged(rule);
|
emit ruleConfigurationChanged(rule);
|
||||||
|
|
||||||
NymeaCore::instance()->logEngine()->logRuleEnabledChanged(rule, false);
|
m_logEngine->logRuleEnabledChanged(rule, false);
|
||||||
qCDebug(dcRuleEngine()) << "Rule" << rule.name() << rule.id().toString() << "disabled.";
|
qCDebug(dcRuleEngine()) << "Rule" << rule.name() << rule.id().toString() << "disabled.";
|
||||||
return RuleErrorNoError;
|
return RuleErrorNoError;
|
||||||
}
|
}
|
||||||
@ -597,8 +626,8 @@ RuleEngine::RuleError RuleEngine::executeActions(const RuleId &ruleId)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcRuleEngine) << "Executing rule actions of rule" << rule.name() << rule.id().toString();
|
qCDebug(dcRuleEngine) << "Executing rule actions of rule" << rule.name() << rule.id().toString();
|
||||||
NymeaCore::instance()->logEngine()->logRuleActionsExecuted(rule);
|
m_logEngine->logRuleActionsExecuted(rule);
|
||||||
NymeaCore::instance()->executeRuleActions(rule.actions());
|
executeRuleActions(rule.actions());
|
||||||
return RuleErrorNoError;
|
return RuleErrorNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,8 +658,8 @@ RuleEngine::RuleError RuleEngine::executeExitActions(const RuleId &ruleId)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcRuleEngine) << "Executing rule exit actions of rule" << rule.name() << rule.id().toString();
|
qCDebug(dcRuleEngine) << "Executing rule exit actions of rule" << rule.name() << rule.id().toString();
|
||||||
NymeaCore::instance()->logEngine()->logRuleExitActionsExecuted(rule);
|
m_logEngine->logRuleExitActionsExecuted(rule);
|
||||||
NymeaCore::instance()->executeRuleActions(rule.exitActions());
|
executeRuleActions(rule.exitActions());
|
||||||
return RuleErrorNoError;
|
return RuleErrorNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -830,7 +859,7 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const Thing
|
|||||||
|
|
||||||
// If this is a interface based rule, the thing must implement the interface
|
// If this is a interface based rule, the thing must implement the interface
|
||||||
if (eventDescriptor.type() == EventDescriptor::TypeInterface) {
|
if (eventDescriptor.type() == EventDescriptor::TypeInterface) {
|
||||||
ThingClass dc = NymeaCore::instance()->thingManager()->findThingClass(thingClassId);
|
ThingClass dc = m_thingManager->findThingClass(thingClassId);
|
||||||
if (!dc.interfaces().contains(eventDescriptor.interface())) {
|
if (!dc.interfaces().contains(eventDescriptor.interface())) {
|
||||||
// ThingClass for this event doesn't implement the interface for this eventDescriptor
|
// ThingClass for this event doesn't implement the interface for this eventDescriptor
|
||||||
continue;
|
continue;
|
||||||
@ -863,7 +892,7 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const Thing
|
|||||||
allOK = false;
|
allOK = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ThingClass dc = NymeaCore::instance()->thingManager()->findThingClass(thingClassId);
|
ThingClass dc = m_thingManager->findThingClass(thingClassId);
|
||||||
EventType et = dc.eventTypes().findById(event.eventTypeId());
|
EventType et = dc.eventTypes().findById(event.eventTypeId());
|
||||||
StateType st = dc.stateTypes().findById(event.eventTypeId());
|
StateType st = dc.stateTypes().findById(event.eventTypeId());
|
||||||
if (et.isValid()) {
|
if (et.isValid()) {
|
||||||
@ -928,8 +957,8 @@ bool RuleEngine::containsState(const StateEvaluator &stateEvaluator, const Event
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(stateChangeEvent.thingId());
|
Thing *thing = m_thingManager->findConfiguredThing(stateChangeEvent.thingId());
|
||||||
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(thing->thingClassId());
|
ThingClass thingClass = m_thingManager->findThingClass(thing->thingClassId());
|
||||||
if (thingClass.interfaces().contains(stateEvaluator.stateDescriptor().interface())) {
|
if (thingClass.interfaces().contains(stateEvaluator.stateDescriptor().interface())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -954,13 +983,13 @@ RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction,
|
|||||||
|
|
||||||
ActionType actionType;
|
ActionType actionType;
|
||||||
if (ruleAction.type() == RuleAction::TypeThing) {
|
if (ruleAction.type() == RuleAction::TypeThing) {
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(ruleAction.thingId());
|
Thing *thing = m_thingManager->findConfiguredThing(ruleAction.thingId());
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured thing with ID" << ruleAction.thingId();
|
qCWarning(dcRuleEngine) << "Cannot create rule. No configured thing with ID" << ruleAction.thingId();
|
||||||
return RuleErrorThingNotFound;
|
return RuleErrorThingNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(thing->thingClassId());
|
ThingClass thingClass = m_thingManager->findThingClass(thing->thingClassId());
|
||||||
if (!thingClass.hasActionType(ruleAction.actionTypeId())) {
|
if (!thingClass.hasActionType(ruleAction.actionTypeId())) {
|
||||||
qCWarning(dcRuleEngine) << "Cannot create rule. Thing " + thing->name() + " has no action type:" << ruleAction.actionTypeId();
|
qCWarning(dcRuleEngine) << "Cannot create rule. Thing " + thing->name() + " has no action type:" << ruleAction.actionTypeId();
|
||||||
return RuleErrorActionTypeNotFound;
|
return RuleErrorActionTypeNotFound;
|
||||||
@ -968,7 +997,7 @@ RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction,
|
|||||||
|
|
||||||
actionType = thingClass.actionTypes().findById(ruleAction.actionTypeId());
|
actionType = thingClass.actionTypes().findById(ruleAction.actionTypeId());
|
||||||
} else if (ruleAction.type() == RuleAction::TypeInterface) {
|
} else if (ruleAction.type() == RuleAction::TypeInterface) {
|
||||||
Interface iface = NymeaCore::instance()->thingManager()->supportedInterfaces().findByName(ruleAction.interface());
|
Interface iface = m_thingManager->supportedInterfaces().findByName(ruleAction.interface());
|
||||||
if (!iface.isValid()) {
|
if (!iface.isValid()) {
|
||||||
qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleAction.interface();
|
qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleAction.interface();
|
||||||
return RuleError::RuleErrorInterfaceNotFound;
|
return RuleError::RuleErrorInterfaceNotFound;
|
||||||
@ -979,7 +1008,7 @@ RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction,
|
|||||||
return RuleError::RuleErrorActionTypeNotFound;
|
return RuleError::RuleErrorActionTypeNotFound;
|
||||||
}
|
}
|
||||||
} else if (ruleAction.type() == RuleAction::TypeBrowser) {
|
} else if (ruleAction.type() == RuleAction::TypeBrowser) {
|
||||||
Thing *thing = NymeaCore::instance()->thingManager()->findConfiguredThing(ruleAction.thingId());
|
Thing *thing = m_thingManager->findConfiguredThing(ruleAction.thingId());
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured thing with ID" << ruleAction.thingId();
|
qCWarning(dcRuleEngine) << "Cannot create rule. No configured thing with ID" << ruleAction.thingId();
|
||||||
return RuleErrorThingNotFound;
|
return RuleErrorThingNotFound;
|
||||||
@ -1057,12 +1086,12 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru
|
|||||||
return RuleErrorTypesNotMatching;
|
return RuleErrorTypesNotMatching;
|
||||||
}
|
}
|
||||||
} else if (ruleActionParam.isStateBased()) {
|
} else if (ruleActionParam.isStateBased()) {
|
||||||
Thing *d = NymeaCore::instance()->thingManager()->findConfiguredThing(ruleActionParam.stateThingId());
|
Thing *d = m_thingManager->findConfiguredThing(ruleActionParam.stateThingId());
|
||||||
if (!d) {
|
if (!d) {
|
||||||
qCWarning(dcRuleEngine()) << "Cannot create Rule. ThingId from RuleActionParam" << ruleActionParam.paramTypeId() << "not found in system.";
|
qCWarning(dcRuleEngine()) << "Cannot create Rule. ThingId from RuleActionParam" << ruleActionParam.paramTypeId() << "not found in system.";
|
||||||
return RuleErrorThingNotFound;
|
return RuleErrorThingNotFound;
|
||||||
}
|
}
|
||||||
ThingClass stateThingClass = NymeaCore::instance()->thingManager()->findThingClass(d->thingClassId());
|
ThingClass stateThingClass = m_thingManager->findThingClass(d->thingClassId());
|
||||||
StateType stateType = stateThingClass.stateTypes().findById(ruleActionParam.stateTypeId());
|
StateType stateType = stateThingClass.stateTypes().findById(ruleActionParam.stateTypeId());
|
||||||
QVariant::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId());
|
QVariant::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId());
|
||||||
QVariant v(stateType.type());
|
QVariant v(stateType.type());
|
||||||
@ -1090,7 +1119,7 @@ RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ru
|
|||||||
|
|
||||||
QVariant::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId)
|
QVariant::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId)
|
||||||
{
|
{
|
||||||
foreach (const ThingClass &thingClass, NymeaCore::instance()->thingManager()->supportedThings()) {
|
foreach (const ThingClass &thingClass, m_thingManager->supportedThings()) {
|
||||||
foreach (const ActionType &actionType, thingClass.actionTypes()) {
|
foreach (const ActionType &actionType, thingClass.actionTypes()) {
|
||||||
if (actionType.id() == actionTypeId) {
|
if (actionType.id() == actionTypeId) {
|
||||||
foreach (const ParamType ¶mType, actionType.paramTypes()) {
|
foreach (const ParamType ¶mType, actionType.paramTypes()) {
|
||||||
@ -1107,7 +1136,7 @@ QVariant::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId,
|
|||||||
|
|
||||||
QVariant::Type RuleEngine::getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId)
|
QVariant::Type RuleEngine::getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId)
|
||||||
{
|
{
|
||||||
foreach (const ThingClass &thingClass, NymeaCore::instance()->thingManager()->supportedThings()) {
|
foreach (const ThingClass &thingClass, m_thingManager->supportedThings()) {
|
||||||
foreach (const EventType &eventType, thingClass.eventTypes()) {
|
foreach (const EventType &eventType, thingClass.eventTypes()) {
|
||||||
if (eventType.id() == eventTypeId) {
|
if (eventType.id() == eventTypeId) {
|
||||||
foreach (const ParamType ¶mType, eventType.paramTypes()) {
|
foreach (const ParamType ¶mType, eventType.paramTypes()) {
|
||||||
@ -1371,6 +1400,231 @@ QList<RuleAction> RuleEngine::loadRuleActions(NymeaSettings *settings)
|
|||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RuleEngine::executeRuleActions(const QList<RuleAction> ruleActions)
|
||||||
|
{
|
||||||
|
QList<Action> actions;
|
||||||
|
QList<BrowserAction> browserActions;
|
||||||
|
foreach (const RuleAction &ruleAction, ruleActions) {
|
||||||
|
if (ruleAction.type() == RuleAction::TypeThing) {
|
||||||
|
Thing *thing = m_thingManager->findConfiguredThing(ruleAction.thingId());
|
||||||
|
if (!thing) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Unable to find thing" << ruleAction.thingId() << "for rule action" << ruleAction;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ActionTypeId actionTypeId = ruleAction.actionTypeId();
|
||||||
|
ParamList params;
|
||||||
|
bool ok = true;
|
||||||
|
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||||
|
if (ruleActionParam.isValueBased()) {
|
||||||
|
params.append(Param(ruleActionParam.paramTypeId(), ruleActionParam.value()));
|
||||||
|
} else if (ruleActionParam.isStateBased()) {
|
||||||
|
Thing *stateThing = m_thingManager->findConfiguredThing(ruleActionParam.stateThingId());
|
||||||
|
if (!stateThing) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Cannot find thing" << ruleActionParam.stateThingId() << "required by rule action";
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ThingClass stateThingClass = m_thingManager->findThingClass(stateThing->thingClassId());
|
||||||
|
if (!stateThingClass.hasStateType(ruleActionParam.stateTypeId())) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Device" << thing->name() << thing->id() << "does not have a state type" << ruleActionParam.stateTypeId();
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
params.append(Param(ruleActionParam.paramTypeId(), stateThing->stateValue(ruleActionParam.stateTypeId())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Not executing rule action";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Action action(actionTypeId, thing->id(), Action::TriggeredByRule);
|
||||||
|
action.setParams(params);
|
||||||
|
actions.append(action);
|
||||||
|
} else if (ruleAction.type() == RuleAction::TypeBrowser) {
|
||||||
|
Thing *thing = m_thingManager->findConfiguredThing(ruleAction.thingId());
|
||||||
|
if (!thing) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Unable to find thing" << ruleAction.thingId() << "for rule action" << ruleAction;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BrowserAction browserAction(ruleAction.thingId(), ruleAction.browserItemId());
|
||||||
|
browserActions.append(browserAction);
|
||||||
|
} else {
|
||||||
|
Things things = m_thingManager->findConfiguredThings(ruleAction.interface());
|
||||||
|
foreach (Thing* thing, things) {
|
||||||
|
ThingClass thingClass = m_thingManager->findThingClass(thing->thingClassId());
|
||||||
|
ActionType actionType = thingClass.actionTypes().findByName(ruleAction.interfaceAction());
|
||||||
|
if (actionType.id().isNull()) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Error creating Action. The given ThingClass does not implement action:" << ruleAction.interfaceAction();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamList params;
|
||||||
|
bool ok = true;
|
||||||
|
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||||
|
ParamType paramType = actionType.paramTypes().findByName(ruleActionParam.paramName());
|
||||||
|
if (paramType.id().isNull()) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Error creating Action. The given ActionType does not have a parameter:" << ruleActionParam.paramName();
|
||||||
|
ok = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ruleActionParam.isValueBased()) {
|
||||||
|
params.append(Param(paramType.id(), ruleActionParam.value()));
|
||||||
|
} else if (ruleActionParam.isStateBased()) {
|
||||||
|
Thing *stateThing = m_thingManager->findConfiguredThing(ruleActionParam.stateThingId());
|
||||||
|
if (!stateThing) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Cannot find thing" << ruleActionParam.stateThingId() << "required by rule action";
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ThingClass stateThingClass = m_thingManager->findThingClass(stateThing->thingClassId());
|
||||||
|
if (!stateThingClass.hasStateType(ruleActionParam.stateTypeId())) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Thing" << thing->name() << thing->id() << "does not have a state type" << ruleActionParam.stateTypeId();
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
params.append(Param(paramType.id(), stateThing->stateValue(ruleActionParam.stateTypeId())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Not executing rule action";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Action action = Action(actionType.id(), thing->id(), Action::TriggeredByRule);
|
||||||
|
action.setParams(params);
|
||||||
|
actions.append(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const Action &action, actions) {
|
||||||
|
qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params();
|
||||||
|
ThingActionInfo *info = m_thingManager->executeAction(action);
|
||||||
|
connect(info, &ThingActionInfo::finished, this, [info](){
|
||||||
|
if (info->status() != Thing::ThingErrorNoError) {
|
||||||
|
qCWarning(dcRuleEngine) << "Error executing action:" << info->status() << info->displayMessage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const BrowserAction &browserAction, browserActions) {
|
||||||
|
BrowserActionInfo *info = m_thingManager->executeBrowserItem(browserAction);
|
||||||
|
connect(info, &BrowserActionInfo::finished, this, [info, this](){
|
||||||
|
m_logEngine->logBrowserAction(info->browserAction(), info->status() == Thing::ThingErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, info->status());
|
||||||
|
if (info->status() != Thing::ThingErrorNoError) {
|
||||||
|
qCWarning(dcRuleEngine) << "Error executing browser action:" << info->status();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuleEngine::onEventTriggered(const Event &event)
|
||||||
|
{
|
||||||
|
QList<RuleAction> actions;
|
||||||
|
QList<RuleAction> eventBasedActions;
|
||||||
|
foreach (const Rule &rule, evaluateEvent(event)) {
|
||||||
|
if (m_executingRules.contains(rule.id())) {
|
||||||
|
qCWarning(dcRuleEngine()) << "WARNING: Loop detected in rule execution for rule" << rule.id().toString() << rule.name();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_executingRules.append(rule.id());
|
||||||
|
|
||||||
|
// Event based
|
||||||
|
if (!rule.eventDescriptors().isEmpty()) {
|
||||||
|
m_logEngine->logRuleTriggered(rule);
|
||||||
|
QList<RuleAction> tmp;
|
||||||
|
if (rule.statesActive() && rule.timeActive()) {
|
||||||
|
qCDebug(dcRuleEngineDebug()) << "Executing actions";
|
||||||
|
tmp = rule.actions();
|
||||||
|
} else {
|
||||||
|
qCDebug(dcRuleEngineDebug()) << "Executing exitActions";
|
||||||
|
tmp = rule.exitActions();
|
||||||
|
}
|
||||||
|
// check if we have an event based action or a normal action
|
||||||
|
foreach (const RuleAction &action, tmp) {
|
||||||
|
if (action.isEventBased()) {
|
||||||
|
eventBasedActions.append(action);
|
||||||
|
} else {
|
||||||
|
actions.append(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// State based rule
|
||||||
|
m_logEngine->logRuleActiveChanged(rule);
|
||||||
|
emit ruleActiveChanged(rule);
|
||||||
|
if (rule.active()) {
|
||||||
|
actions.append(rule.actions());
|
||||||
|
} else {
|
||||||
|
actions.append(rule.exitActions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set action params, depending on the event value
|
||||||
|
foreach (RuleAction ruleAction, eventBasedActions) {
|
||||||
|
RuleActionParams newParams;
|
||||||
|
foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) {
|
||||||
|
// if this event param should be taken over in this action
|
||||||
|
if (event.eventTypeId() == ruleActionParam.eventTypeId()) {
|
||||||
|
QVariant eventValue = event.params().paramValue(ruleActionParam.eventParamTypeId());
|
||||||
|
|
||||||
|
// TODO: limits / scale calculation -> actionValue = eventValue * x
|
||||||
|
// something like a EventParamDescriptor
|
||||||
|
|
||||||
|
ruleActionParam.setValue(eventValue);
|
||||||
|
qCDebug(dcRuleEngine) << "Using param value from event:" << ruleActionParam.value();
|
||||||
|
}
|
||||||
|
newParams.append(ruleActionParam);
|
||||||
|
}
|
||||||
|
ruleAction.setRuleActionParams(newParams);
|
||||||
|
actions.append(ruleAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
executeRuleActions(actions);
|
||||||
|
m_executingRules.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuleEngine::onDateTimeChanged(const QDateTime &dateTime)
|
||||||
|
{
|
||||||
|
QList<RuleAction> actions;
|
||||||
|
foreach (const Rule &rule, evaluateTime(dateTime)) {
|
||||||
|
// TimeEvent based
|
||||||
|
if (!rule.timeDescriptor().timeEventItems().isEmpty()) {
|
||||||
|
m_logEngine->logRuleTriggered(rule);
|
||||||
|
if (rule.statesActive() && rule.timeActive()) {
|
||||||
|
actions.append(rule.actions());
|
||||||
|
} else {
|
||||||
|
actions.append(rule.exitActions());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Calendar based rule
|
||||||
|
m_logEngine->logRuleActiveChanged(rule);
|
||||||
|
emit ruleActiveChanged(rule);
|
||||||
|
if (rule.active()) {
|
||||||
|
actions.append(rule.actions());
|
||||||
|
} else {
|
||||||
|
actions.append(rule.exitActions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
executeRuleActions(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuleEngine::onThingRemoved(const ThingId &thingId)
|
||||||
|
{
|
||||||
|
QList<RuleId> affectedRules;
|
||||||
|
|
||||||
|
foreach (const RuleId &ruleId, findRules(thingId)) {
|
||||||
|
if (!affectedRules.contains(ruleId)) {
|
||||||
|
affectedRules.append(ruleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!affectedRules.isEmpty()) {
|
||||||
|
removeRule(affectedRules.takeFirst());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RuleEngine::init()
|
void RuleEngine::init()
|
||||||
{
|
{
|
||||||
NymeaSettings settings(NymeaSettings::SettingsRoleRules);
|
NymeaSettings settings(NymeaSettings::SettingsRoleRules);
|
||||||
|
|||||||
@ -34,15 +34,24 @@
|
|||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
#include "stateevaluator.h"
|
#include "stateevaluator.h"
|
||||||
#include "types/event.h"
|
#include "types/event.h"
|
||||||
#include "types/thingclass.h"
|
|
||||||
|
#include "integrations/thingmanager.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine)
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(dcRuleEngineDebug)
|
||||||
|
|
||||||
|
class ThingManager;
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
|
class LogEngine;
|
||||||
|
class TimeManager;
|
||||||
|
|
||||||
class RuleEngine : public QObject
|
class RuleEngine : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -72,18 +81,8 @@ public:
|
|||||||
};
|
};
|
||||||
Q_ENUM(RuleError)
|
Q_ENUM(RuleError)
|
||||||
|
|
||||||
enum RemovePolicy {
|
explicit RuleEngine(ThingManager *thingManager, TimeManager *timeManager, LogEngine *logEngine, QObject *parent = nullptr);
|
||||||
RemovePolicyCascade,
|
|
||||||
RemovePolicyUpdate
|
|
||||||
};
|
|
||||||
Q_ENUM(RemovePolicy)
|
|
||||||
|
|
||||||
explicit RuleEngine(QObject *parent = nullptr);
|
|
||||||
~RuleEngine();
|
~RuleEngine();
|
||||||
void init();
|
|
||||||
|
|
||||||
QList<Rule> evaluateEvent(const Event &event);
|
|
||||||
QList<Rule> evaluateTime(const QDateTime &dateTime);
|
|
||||||
|
|
||||||
RuleError addRule(const Rule &rule, bool fromEdit = false);
|
RuleError addRule(const Rule &rule, bool fromEdit = false);
|
||||||
RuleError editRule(const Rule &rule);
|
RuleError editRule(const Rule &rule);
|
||||||
@ -109,8 +108,18 @@ signals:
|
|||||||
void ruleAdded(const Rule &rule);
|
void ruleAdded(const Rule &rule);
|
||||||
void ruleRemoved(const RuleId &ruleId);
|
void ruleRemoved(const RuleId &ruleId);
|
||||||
void ruleConfigurationChanged(const Rule &rule);
|
void ruleConfigurationChanged(const Rule &rule);
|
||||||
|
void ruleActiveChanged(const Rule &rule);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void init();
|
||||||
|
void onEventTriggered(const Event &event);
|
||||||
|
void onDateTimeChanged(const QDateTime &dateTime);
|
||||||
|
void onThingRemoved(const ThingId &thingId);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<Rule> evaluateEvent(const Event &event);
|
||||||
|
QList<Rule> evaluateTime(const QDateTime &dateTime);
|
||||||
|
|
||||||
private:
|
|
||||||
bool containsEvent(const Rule &rule, const Event &event, const ThingClassId &thingClassId);
|
bool containsEvent(const Rule &rule, const Event &event, const ThingClassId &thingClassId);
|
||||||
bool containsState(const StateEvaluator &stateEvaluator, const Event &stateChangeEvent);
|
bool containsState(const StateEvaluator &stateEvaluator, const Event &stateChangeEvent);
|
||||||
|
|
||||||
@ -125,12 +134,22 @@ private:
|
|||||||
void saveRuleActions(NymeaSettings *settings, const QList<RuleAction> &ruleActions);
|
void saveRuleActions(NymeaSettings *settings, const QList<RuleAction> &ruleActions);
|
||||||
QList<RuleAction> loadRuleActions(NymeaSettings *settings);
|
QList<RuleAction> loadRuleActions(NymeaSettings *settings);
|
||||||
|
|
||||||
|
void executeRuleActions(const QList<RuleAction> ruleActions);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ThingManager *m_thingManager = nullptr;
|
||||||
|
TimeManager *m_timeManager = nullptr;
|
||||||
|
LogEngine *m_logEngine = nullptr;
|
||||||
|
|
||||||
QList<RuleId> m_ruleIds; // Keeping a list of RuleIds to keep sorting order...
|
QList<RuleId> m_ruleIds; // Keeping a list of RuleIds to keep sorting order...
|
||||||
QHash<RuleId, Rule> m_rules; // ...but use a Hash for faster finding
|
QHash<RuleId, Rule> m_rules; // ...but use a Hash for faster finding
|
||||||
QList<RuleId> m_activeRules;
|
QList<RuleId> m_activeRules;
|
||||||
|
|
||||||
QDateTime m_lastEvaluationTime;
|
QDateTime m_lastEvaluationTime;
|
||||||
|
|
||||||
|
QList<RuleId> m_executingRules;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,11 +110,11 @@ protected:
|
|||||||
virtual IOConnectionResult connectIO(const IOConnection &connection) = 0;
|
virtual IOConnectionResult connectIO(const IOConnection &connection) = 0;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void loaded();
|
||||||
void pluginConfigChanged(const PluginId &id, const ParamList &config);
|
void pluginConfigChanged(const PluginId &id, const ParamList &config);
|
||||||
void eventTriggered(const Event &event);
|
void eventTriggered(const Event &event);
|
||||||
void thingStateChanged(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &minValue, const QVariant &maxValue);
|
void thingStateChanged(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &minValue, const QVariant &maxValue);
|
||||||
void thingRemoved(const ThingId &thingId);
|
void thingRemoved(const ThingId &thingId);
|
||||||
void thingDisappeared(const ThingId &thingId);
|
|
||||||
void thingAdded(Thing *thing);
|
void thingAdded(Thing *thing);
|
||||||
void thingChanged(Thing *thing);
|
void thingChanged(Thing *thing);
|
||||||
void thingSettingChanged(const ThingId &thingId, const ParamTypeId &settingParamTypeId, const QVariant &value);
|
void thingSettingChanged(const ThingId &thingId, const ParamTypeId &settingParamTypeId, const QVariant &value);
|
||||||
|
|||||||
@ -48,8 +48,6 @@ NYMEA_LOGGING_CATEGORY(dcPlatformUpdate, "PlatformUpdate")
|
|||||||
NYMEA_LOGGING_CATEGORY(dcPlatformZeroConf, "PlatformZeroConf")
|
NYMEA_LOGGING_CATEGORY(dcPlatformZeroConf, "PlatformZeroConf")
|
||||||
NYMEA_LOGGING_CATEGORY(dcExperiences, "Experiences")
|
NYMEA_LOGGING_CATEGORY(dcExperiences, "Experiences")
|
||||||
NYMEA_LOGGING_CATEGORY(dcTimeManager, "TimeManager")
|
NYMEA_LOGGING_CATEGORY(dcTimeManager, "TimeManager")
|
||||||
NYMEA_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine")
|
|
||||||
NYMEA_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug")
|
|
||||||
NYMEA_LOGGING_CATEGORY(dcHardware, "Hardware")
|
NYMEA_LOGGING_CATEGORY(dcHardware, "Hardware")
|
||||||
NYMEA_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
|
NYMEA_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
|
||||||
NYMEA_LOGGING_CATEGORY(dcServerManager, "ServerManager")
|
NYMEA_LOGGING_CATEGORY(dcServerManager, "ServerManager")
|
||||||
|
|||||||
@ -56,8 +56,6 @@ Q_DECLARE_LOGGING_CATEGORY(dcPlatformUpdate)
|
|||||||
Q_DECLARE_LOGGING_CATEGORY(dcPlatformZeroConf)
|
Q_DECLARE_LOGGING_CATEGORY(dcPlatformZeroConf)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcExperiences)
|
Q_DECLARE_LOGGING_CATEGORY(dcExperiences)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcTimeManager)
|
Q_DECLARE_LOGGING_CATEGORY(dcTimeManager)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine)
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcRuleEngineDebug)
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcHardware)
|
Q_DECLARE_LOGGING_CATEGORY(dcHardware)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
|
Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcServerManager)
|
Q_DECLARE_LOGGING_CATEGORY(dcServerManager)
|
||||||
|
|||||||
@ -154,7 +154,6 @@ bool RepeatingOption::isValid() const
|
|||||||
// Validate weekdays range
|
// Validate weekdays range
|
||||||
foreach (const uint &weekDay, m_weekDays) {
|
foreach (const uint &weekDay, m_weekDays) {
|
||||||
if (weekDay <= 0 || weekDay > 7) {
|
if (weekDay <= 0 || weekDay > 7) {
|
||||||
qCWarning(dcRuleEngine()) << "Invalid week day value:" << weekDay << ". Value out of range [1,7].";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,7 +161,6 @@ bool RepeatingOption::isValid() const
|
|||||||
// Validate monthdays range
|
// Validate monthdays range
|
||||||
foreach (const uint &monthDay, m_monthDays) {
|
foreach (const uint &monthDay, m_monthDays) {
|
||||||
if (monthDay <= 0 || monthDay > 31) {
|
if (monthDay <= 0 || monthDay > 31) {
|
||||||
qCWarning(dcRuleEngine()) << "Invalid month day value:" << monthDay << ". Value out of range [1,31].";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,16 +119,6 @@ QVariant Event::paramValue(const ParamTypeId ¶mTypeId) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Event::logged() const
|
|
||||||
{
|
|
||||||
return m_logged;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::setLogged(bool logged)
|
|
||||||
{
|
|
||||||
m_logged = logged;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Compare this Event to the Event given by \a other.
|
/*! Compare this Event to the Event given by \a other.
|
||||||
* Events are equal (returns true) if eventTypeId, deviceId and params match. */
|
* Events are equal (returns true) if eventTypeId, deviceId and params match. */
|
||||||
bool Event::operator ==(const Event &other) const
|
bool Event::operator ==(const Event &other) const
|
||||||
|
|||||||
@ -62,15 +62,10 @@ public:
|
|||||||
|
|
||||||
bool operator ==(const Event &other) const;
|
bool operator ==(const Event &other) const;
|
||||||
|
|
||||||
bool logged() const;
|
|
||||||
void setLogged(bool logged);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventTypeId m_eventTypeId;
|
EventTypeId m_eventTypeId;
|
||||||
ThingId m_thingId;
|
ThingId m_thingId;
|
||||||
ParamList m_params;
|
ParamList m_params;
|
||||||
|
|
||||||
bool m_logged = false;
|
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(Event)
|
Q_DECLARE_METATYPE(Event)
|
||||||
QDebug operator<<(QDebug dbg, const Event &event);
|
QDebug operator<<(QDebug dbg, const Event &event);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"
|
|||||||
|
|
||||||
# define protocol versions
|
# define protocol versions
|
||||||
JSON_PROTOCOL_VERSION_MAJOR=7
|
JSON_PROTOCOL_VERSION_MAJOR=7
|
||||||
JSON_PROTOCOL_VERSION_MINOR=0
|
JSON_PROTOCOL_VERSION_MINOR=1
|
||||||
JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}"
|
JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}"
|
||||||
LIBNYMEA_API_VERSION_MAJOR=7
|
LIBNYMEA_API_VERSION_MAJOR=7
|
||||||
LIBNYMEA_API_VERSION_MINOR=3
|
LIBNYMEA_API_VERSION_MINOR=3
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
7.0
|
7.1
|
||||||
{
|
{
|
||||||
"enums": {
|
"enums": {
|
||||||
"BasicType": [
|
"BasicType": [
|
||||||
@ -169,10 +169,6 @@
|
|||||||
"PermissionScopeConfigureRules",
|
"PermissionScopeConfigureRules",
|
||||||
"PermissionScopeAdmin"
|
"PermissionScopeAdmin"
|
||||||
],
|
],
|
||||||
"RemovePolicy": [
|
|
||||||
"RemovePolicyCascade",
|
|
||||||
"RemovePolicyUpdate"
|
|
||||||
],
|
|
||||||
"RepeatingMode": [
|
"RepeatingMode": [
|
||||||
"RepeatingModeNone",
|
"RepeatingModeNone",
|
||||||
"RepeatingModeHourly",
|
"RepeatingModeHourly",
|
||||||
@ -1121,22 +1117,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Integrations.RemoveThing": {
|
"Integrations.RemoveThing": {
|
||||||
"description": "Remove a thing from the system.",
|
"description": "Remove a thing and all its childs from the system. RemovePolicy is deprecated and has no effect any more.",
|
||||||
"params": {
|
"params": {
|
||||||
"o:removePolicy": "$ref:RemovePolicy",
|
"d:o:removePolicy": "String",
|
||||||
"o:removePolicyList": [
|
|
||||||
{
|
|
||||||
"policy": "$ref:RemovePolicy",
|
|
||||||
"ruleId": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"thingId": "Uuid"
|
"thingId": "Uuid"
|
||||||
},
|
},
|
||||||
"permissionScope": "PermissionScopeConfigureThings",
|
"permissionScope": "PermissionScopeConfigureThings",
|
||||||
"returns": {
|
"returns": {
|
||||||
"o:ruleIds": [
|
|
||||||
"Uuid"
|
|
||||||
],
|
|
||||||
"thingError": "$ref:ThingError"
|
"thingError": "$ref:ThingError"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1910,9 +1910,9 @@ void TestIntegrations::discoverThingsParenting()
|
|||||||
QVERIFY(childThing->thingClassId() == childMockThingClassId);
|
QVERIFY(childThing->thingClassId() == childMockThingClassId);
|
||||||
|
|
||||||
// Now delete the parent and make sure the child will be deleted too
|
// Now delete the parent and make sure the child will be deleted too
|
||||||
QSignalSpy removeSpy(NymeaCore::instance(), &NymeaCore::thingRemoved);
|
QSignalSpy removeSpy(NymeaCore::instance()->thingManager(), &ThingManager::thingRemoved);
|
||||||
QPair<Thing::ThingError, QList<RuleId> > ret = NymeaCore::instance()->removeConfiguredThing(parentThing->id(), QHash<RuleId, RuleEngine::RemovePolicy>());
|
Thing::ThingError ret = NymeaCore::instance()->thingManager()->removeConfiguredThing(parentThing->id());
|
||||||
QCOMPARE(ret.first, Thing::ThingErrorNoError);
|
QCOMPARE(ret, Thing::ThingErrorNoError);
|
||||||
QCOMPARE(removeSpy.count(), 3); // The parent, the auto-mock and the discovered mock
|
QCOMPARE(removeSpy.count(), 3); // The parent, the auto-mock and the discovered mock
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2107,8 +2107,8 @@ void TestIntegrations::triggerEvent()
|
|||||||
QVERIFY2(things.count() > 0, "There needs to be at least one configured Mock Device for this test");
|
QVERIFY2(things.count() > 0, "There needs to be at least one configured Mock Device for this test");
|
||||||
Thing *thing = things.first();
|
Thing *thing = things.first();
|
||||||
|
|
||||||
QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&)));
|
QSignalSpy spy(NymeaCore::instance()->thingManager(), &ThingManager::eventTriggered);
|
||||||
QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
QSignalSpy notificationSpy(m_mockTcpServer, &MockTcpServer::outgoingData);
|
||||||
|
|
||||||
// Setup connection to mock client
|
// Setup connection to mock client
|
||||||
QNetworkAccessManager nam;
|
QNetworkAccessManager nam;
|
||||||
@ -2148,8 +2148,8 @@ void TestIntegrations::triggerStateChangeSignal()
|
|||||||
QVERIFY2(things.count() > 0, "There needs to be at least one configured Mock for this test");
|
QVERIFY2(things.count() > 0, "There needs to be at least one configured Mock for this test");
|
||||||
Thing *thing = things.first();
|
Thing *thing = things.first();
|
||||||
|
|
||||||
QSignalSpy spy(NymeaCore::instance(), SIGNAL(thingStateChanged(Thing *, const StateTypeId &, const QVariant &, const QVariant &, const QVariant &)));
|
QSignalSpy spy(NymeaCore::instance()->thingManager(), &ThingManager::thingStateChanged);
|
||||||
QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
QSignalSpy notificationSpy(m_mockTcpServer, &MockTcpServer::outgoingData);
|
||||||
|
|
||||||
// Setup connection to mock client
|
// Setup connection to mock client
|
||||||
QNetworkAccessManager nam;
|
QNetworkAccessManager nam;
|
||||||
|
|||||||
@ -115,9 +115,7 @@ private slots:
|
|||||||
|
|
||||||
void testStateBasedAction();
|
void testStateBasedAction();
|
||||||
|
|
||||||
void removePolicyUpdate();
|
void removeThingCleansRule();
|
||||||
void removePolicyCascade();
|
|
||||||
void removePolicyUpdateRendersUselessRule();
|
|
||||||
|
|
||||||
void testRuleActionParams_data();
|
void testRuleActionParams_data();
|
||||||
void testRuleActionParams();
|
void testRuleActionParams();
|
||||||
@ -2385,7 +2383,7 @@ void TestRules::testStateBasedAction()
|
|||||||
qCDebug(dcTests()) << "Log entries:" << entries;
|
qCDebug(dcTests()) << "Log entries:" << entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestRules::removePolicyUpdate()
|
void TestRules::removeThingCleansRule()
|
||||||
{
|
{
|
||||||
// ADD parent
|
// ADD parent
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
@ -2441,16 +2439,10 @@ void TestRules::removePolicyUpdate()
|
|||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
response = injectAndWait("Integrations.RemoveThing", params);
|
||||||
verifyThingError(response, Thing::ThingErrorThingIsChild);
|
verifyThingError(response, Thing::ThingErrorThingIsChild);
|
||||||
|
|
||||||
// Try to remove child
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("thingId", parentId);
|
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
|
||||||
verifyThingError(response, Thing::ThingErrorThingInRule);
|
|
||||||
|
|
||||||
// Remove policy
|
// Remove policy
|
||||||
params.clear(); response.clear();
|
params.clear(); response.clear();
|
||||||
params.insert("thingId", parentId);
|
params.insert("thingId", parentId);
|
||||||
params.insert("removePolicy", "RemovePolicyUpdate");
|
params.insert("removePolicy", "RemovePolicyCascade"); // This is deprecated and doesn't do anything any more, keeping it as clients may pass it too still
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
response = injectAndWait("Integrations.RemoveThing", params);
|
||||||
verifyThingError(response);
|
verifyThingError(response);
|
||||||
|
|
||||||
@ -2458,182 +2450,6 @@ void TestRules::removePolicyUpdate()
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.insert("ruleId", ruleId);
|
params.insert("ruleId", ruleId);
|
||||||
response = injectAndWait("Rules.GetRuleDetails", params);
|
response = injectAndWait("Rules.GetRuleDetails", params);
|
||||||
verifyRuleError(response);
|
|
||||||
|
|
||||||
QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
|
|
||||||
qDebug() << "Updated rule:" << QJsonDocument::fromVariant(rule).toJson();
|
|
||||||
QVERIFY(rule.value("eventDescriptors").toList().count() == 1);
|
|
||||||
|
|
||||||
// REMOVE rule
|
|
||||||
QVariantMap removeParams;
|
|
||||||
removeParams.insert("ruleId", ruleId);
|
|
||||||
response = injectAndWait("Rules.RemoveRule", removeParams);
|
|
||||||
verifyRuleError(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestRules::removePolicyCascade()
|
|
||||||
{
|
|
||||||
// ADD parent
|
|
||||||
QVariantMap params;
|
|
||||||
params.insert("thingClassId", parentMockThingClassId);
|
|
||||||
params.insert("name", "Parent");
|
|
||||||
|
|
||||||
QSignalSpy addedSpy(NymeaCore::instance()->thingManager(), &ThingManager::thingAdded);
|
|
||||||
|
|
||||||
QVariant response = injectAndWait("Integrations.AddThing", params);
|
|
||||||
verifyThingError(response);
|
|
||||||
|
|
||||||
ThingId parentId = ThingId(response.toMap().value("params").toMap().value("thingId").toString());
|
|
||||||
QVERIFY(!parentId.isNull());
|
|
||||||
|
|
||||||
addedSpy.wait();
|
|
||||||
|
|
||||||
// find child
|
|
||||||
response = injectAndWait("Integrations.GetThings");
|
|
||||||
|
|
||||||
QVariantList things = response.toMap().value("params").toMap().value("things").toList();
|
|
||||||
|
|
||||||
ThingId childId;
|
|
||||||
foreach (const QVariant thingVariant, things) {
|
|
||||||
QVariantMap thingMap = thingVariant.toMap();
|
|
||||||
|
|
||||||
if (thingMap.value("thingClassId").toUuid() == childMockThingClassId) {
|
|
||||||
if (thingMap.value("parentId").toUuid() == parentId) {
|
|
||||||
childId = ThingId(thingMap.value("id").toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QVERIFY2(!childId.isNull(), "Could not find child");
|
|
||||||
|
|
||||||
// Add rule with child
|
|
||||||
QVariantList eventDescriptors;
|
|
||||||
eventDescriptors.append(createEventDescriptor(childId, childMockEvent1EventTypeId));
|
|
||||||
eventDescriptors.append(createEventDescriptor(parentId, parentMockEvent1EventTypeId));
|
|
||||||
eventDescriptors.append(createEventDescriptor(m_mockThingId, mockEvent1EventTypeId));
|
|
||||||
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("name", "RemovePolicy");
|
|
||||||
params.insert("eventDescriptors", eventDescriptors);
|
|
||||||
params.insert("actions", QVariantList() << createActionWithParams(m_mockThingId));
|
|
||||||
|
|
||||||
response = injectAndWait("Rules.AddRule", params);
|
|
||||||
verifyRuleError(response);
|
|
||||||
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
|
|
||||||
QVERIFY2(!ruleId.isNull(), "Could not get ruleId");
|
|
||||||
|
|
||||||
// Try to remove child
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("thingId", childId);
|
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
|
||||||
verifyThingError(response, Thing::ThingErrorThingIsChild);
|
|
||||||
|
|
||||||
// Try to remove child by removing parent
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("thingId", parentId);
|
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
|
||||||
verifyThingError(response, Thing::ThingErrorThingInRule);
|
|
||||||
|
|
||||||
// Remove policy
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("thingId", parentId);
|
|
||||||
params.insert("removePolicy", "RemovePolicyCascade");
|
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
|
||||||
verifyThingError(response);
|
|
||||||
|
|
||||||
// get updated rule
|
|
||||||
params.clear();
|
|
||||||
params.insert("ruleId", ruleId);
|
|
||||||
response = injectAndWait("Rules.GetRuleDetails", params);
|
|
||||||
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestRules::removePolicyUpdateRendersUselessRule()
|
|
||||||
{
|
|
||||||
// ADD parent
|
|
||||||
QVariantMap params;
|
|
||||||
params.insert("thingClassId", parentMockThingClassId);
|
|
||||||
params.insert("name", "Parent");
|
|
||||||
|
|
||||||
QSignalSpy addedSpy(NymeaCore::instance()->thingManager(), &ThingManager::thingAdded);
|
|
||||||
|
|
||||||
QVariant response = injectAndWait("Integrations.AddThing", params);
|
|
||||||
verifyThingError(response);
|
|
||||||
|
|
||||||
ThingId parentId = ThingId(response.toMap().value("params").toMap().value("thingId").toString());
|
|
||||||
QVERIFY(!parentId.isNull());
|
|
||||||
|
|
||||||
addedSpy.wait();
|
|
||||||
|
|
||||||
// find child
|
|
||||||
qCDebug(dcTests()) << "Get things";
|
|
||||||
response = injectAndWait("Integrations.GetThings");
|
|
||||||
|
|
||||||
QVariantList things = response.toMap().value("params").toMap().value("things").toList();
|
|
||||||
|
|
||||||
ThingId childId;
|
|
||||||
foreach (const QVariant thingVariant, things) {
|
|
||||||
QVariantMap thingMap = thingVariant.toMap();
|
|
||||||
|
|
||||||
if (thingMap.value("thingClassId").toUuid() == childMockThingClassId) {
|
|
||||||
if (thingMap.value("parentId").toUuid() == parentId) {
|
|
||||||
childId = ThingId(thingMap.value("id").toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QVERIFY2(!childId.isNull(), "Could not find child");
|
|
||||||
|
|
||||||
// Add rule with child
|
|
||||||
QVariantList eventDescriptors;
|
|
||||||
eventDescriptors.append(createEventDescriptor(childId, childMockEvent1EventTypeId));
|
|
||||||
eventDescriptors.append(createEventDescriptor(parentId, parentMockEvent1EventTypeId));
|
|
||||||
eventDescriptors.append(createEventDescriptor(m_mockThingId, mockEvent1EventTypeId));
|
|
||||||
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("name", "RemovePolicy");
|
|
||||||
params.insert("eventDescriptors", eventDescriptors);
|
|
||||||
|
|
||||||
QVariantMap action;
|
|
||||||
action.insert("thingId", childId);
|
|
||||||
action.insert("actionTypeId", childMockBoolValueActionTypeId);
|
|
||||||
QVariantMap ruleActionParam;
|
|
||||||
ruleActionParam.insert("paramTypeId", childMockBoolValueActionBoolValueParamTypeId);
|
|
||||||
ruleActionParam.insert("value", true);
|
|
||||||
action.insert("ruleActionParams", QVariantList() << ruleActionParam);
|
|
||||||
params.insert("actions", QVariantList() << action);
|
|
||||||
|
|
||||||
qCDebug(dcTests()) << "Adding Rule";
|
|
||||||
response = injectAndWait("Rules.AddRule", params);
|
|
||||||
verifyRuleError(response);
|
|
||||||
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
|
|
||||||
QVERIFY2(!ruleId.isNull(), "Could not get ruleId");
|
|
||||||
|
|
||||||
// Try to remove child
|
|
||||||
qCDebug(dcTests()) << "Removing thing (expecing failure - thing is child)";
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("thingId", childId);
|
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
|
||||||
verifyThingError(response, Thing::ThingErrorThingIsChild);
|
|
||||||
|
|
||||||
// Try to remove child by removing parent
|
|
||||||
qCDebug(dcTests()) << "Removing thing (expeciting failure - thing in use)";
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("thingId", parentId);
|
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
|
||||||
verifyThingError(response, Thing::ThingErrorThingInRule);
|
|
||||||
|
|
||||||
// Remove policy
|
|
||||||
qCDebug(dcTests()) << "Removing thing with update policy";
|
|
||||||
params.clear(); response.clear();
|
|
||||||
params.insert("thingId", parentId);
|
|
||||||
params.insert("removePolicy", "RemovePolicyUpdate");
|
|
||||||
response = injectAndWait("Integrations.RemoveThing", params);
|
|
||||||
verifyThingError(response);
|
|
||||||
|
|
||||||
// get updated rule. It should've been deleted given it ended up with no actions
|
|
||||||
qCDebug(dcTests()) << "Getting details";
|
|
||||||
params.clear();
|
|
||||||
params.insert("ruleId", ruleId);
|
|
||||||
response = injectAndWait("Rules.GetRuleDetails", params);
|
|
||||||
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
|
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user