Merge PR #620: Refactor NymeaCore class
This commit is contained in:
commit
9355694c24
@ -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, bool initialSetup);
|
ThingSetupInfo *setupThing(Thing *thing, bool initialSetup);
|
||||||
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()));
|
||||||
|
|||||||
@ -529,7 +529,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=4
|
LIBNYMEA_API_VERSION_MINOR=4
|
||||||
|
|||||||
@ -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