From ae38e185b6fec1b31afcd032bf1cc20e0a00a987 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 23 Dec 2020 13:00:08 +0100 Subject: [PATCH] more work... not really working yet --- .../thingmanagerimplementation.cpp | 45 ++++++++++++++++- .../integrations/thingmanagerimplementation.h | 2 +- libnymea-core/jsonrpc/actionhandler.cpp | 2 +- libnymea-core/jsonrpc/devicehandler.cpp | 3 +- libnymea-core/jsonrpc/integrationshandler.cpp | 3 +- libnymea-core/logging/logengine.cpp | 18 ++++++- libnymea-core/logging/logengine.h | 17 +++++-- libnymea-core/nymeacore.cpp | 34 ++----------- libnymea-core/nymeacore.h | 1 - libnymea/integrations/pluginmetadata.cpp | 48 ++++++++++-------- .../statevaluefilters/statevaluefilter.cpp | 6 +++ .../statevaluefilters/statevaluefilter.h | 18 +++++++ .../statevaluefilteradaptive.cpp | 11 +++++ .../statevaluefilteradaptive.h | 15 ++++++ libnymea/integrations/thing.cpp | 49 ++++++++++++------- libnymea/integrations/thing.h | 10 +++- libnymea/integrations/thingmanager.h | 1 + libnymea/integrations/thingutils.cpp | 17 +++++-- libnymea/jsonrpc/jsonhandler.cpp | 22 ++++++++- libnymea/libnymea.pro | 2 + libnymea/types/actiontype.cpp | 33 +++++++++++++ libnymea/types/actiontype.h | 3 ++ libnymea/types/event.cpp | 10 ++++ libnymea/types/event.h | 5 ++ libnymea/types/eventtype.cpp | 46 ++++++++++++++++- libnymea/types/eventtype.h | 7 +++ libnymea/types/interfaceeventtype.cpp | 8 +-- libnymea/types/interfaceeventtype.h | 6 +-- libnymea/types/interfacestatetype.cpp | 8 +-- libnymea/types/interfacestatetype.h | 6 +-- libnymea/types/state.cpp | 10 ---- libnymea/types/state.h | 7 +-- libnymea/types/statetype.cpp | 34 ++++++++++++- libnymea/types/statetype.h | 6 ++- 34 files changed, 390 insertions(+), 123 deletions(-) create mode 100644 libnymea/integrations/statevaluefilters/statevaluefilter.cpp create mode 100644 libnymea/integrations/statevaluefilters/statevaluefilter.h create mode 100644 libnymea/integrations/statevaluefilters/statevaluefilteradaptive.cpp create mode 100644 libnymea/integrations/statevaluefilters/statevaluefilteradaptive.h diff --git a/libnymea-core/integrations/thingmanagerimplementation.cpp b/libnymea-core/integrations/thingmanagerimplementation.cpp index 694fd9a3..14e7a992 100644 --- a/libnymea-core/integrations/thingmanagerimplementation.cpp +++ b/libnymea-core/integrations/thingmanagerimplementation.cpp @@ -650,6 +650,14 @@ ThingPairingInfo *ThingManagerImplementation::confirmPairing(const PairingTransa ParamList settings = buildParams(thingClass.settingsTypes(), ParamList()); thing->setSettings(settings); + QList loggedEventTypeIds; + foreach (const EventType &eventType, thingClass.eventTypes()) { + if (eventType.suggestLogging()) { + loggedEventTypeIds.append(eventType.id()); + } + } + thing->setLoggedEventTypeIds(loggedEventTypeIds); + ThingSetupInfo *info = setupThing(thing); connect(info, &ThingSetupInfo::finished, thing, [this, info, externalInfo, addNewThing](){ @@ -746,6 +754,14 @@ ThingSetupInfo* ThingManagerImplementation::addConfiguredThingInternal(const Thi ParamList settings = buildParams(thingClass.settingsTypes(), ParamList()); thing->setSettings(settings); + QList loggedEventTypeIds; + foreach (const EventType &eventType, thingClass.eventTypes()) { + if (eventType.suggestLogging()) { + loggedEventTypeIds.append(eventType.id()); + } + } + thing->setLoggedEventTypeIds(loggedEventTypeIds); + ThingSetupInfo *info = setupThing(thing); connect(info, &ThingSetupInfo::finished, this, [this, info](){ if (info->status() != Thing::ThingErrorNoError) { @@ -1258,6 +1274,10 @@ ThingActionInfo *ThingManagerImplementation::executeAction(const Action &action) return info; } + connect(info, &ThingActionInfo::finished, this, [=](){ + emit actionExecuted(action, info->status()); + }); + plugin->executeAction(info); return info; @@ -1541,6 +1561,14 @@ void ThingManagerImplementation::loadConfiguredThings() thing->setSettings(thingSettings); + QList loggedEventTypeIds; + foreach (const EventType &eventType, thingClass.eventTypes()) { + if (eventType.suggestLogging()) { + loggedEventTypeIds.append(eventType.id()); + } + } + thing->setLoggedEventTypeIds(loggedEventTypeIds); + settings.endGroup(); // ThingId // We always add the thing to the list in this case. If it's in the stored things @@ -1659,6 +1687,14 @@ void ThingManagerImplementation::onAutoThingsAppeared(const ThingDescriptors &th thing->setSettings(settings); thing->setParentId(thingDescriptor.parentId()); + QList loggedEventTypeIds; + foreach (const EventType &eventType, thingClass.eventTypes()) { + if (eventType.suggestLogging()) { + loggedEventTypeIds.append(eventType.id()); + } + } + thing->setLoggedEventTypeIds(loggedEventTypeIds); + qCDebug(dcThingManager()) << "Setting up auto thing:" << thing->name() << thing->id().toString(); ThingSetupInfo *info = setupThing(thing); @@ -1725,7 +1761,7 @@ void ThingManagerImplementation::cleanupThingStateCache() } } -void ThingManagerImplementation::onEventTriggered(const Event &event) +void ThingManagerImplementation::onEventTriggered(Event event) { // Doing some sanity checks here... Thing *thing = m_configuredThings.value(event.thingId()); @@ -1738,7 +1774,12 @@ void ThingManagerImplementation::onEventTriggered(const Event &event) qCWarning(dcThingManager()) << "The given thing does not have an event type of id " + event.eventTypeId().toString() + ". Not forwarding event."; return; } - // All good, forward the event + // configure logging + if (thing->loggedEventTypeIds().contains(event.eventTypeId())) { + event.setLogged(true); + } + + // Forward the event emit eventTriggered(event); } diff --git a/libnymea-core/integrations/thingmanagerimplementation.h b/libnymea-core/integrations/thingmanagerimplementation.h index e8628e81..df742069 100644 --- a/libnymea-core/integrations/thingmanagerimplementation.h +++ b/libnymea-core/integrations/thingmanagerimplementation.h @@ -140,7 +140,7 @@ private slots: void onAutoThingDisappeared(const ThingId &thingId); void onLoaded(); void cleanupThingStateCache(); - void onEventTriggered(const Event &event); + void onEventTriggered(Event event); // Only connect this to Things. It will query the sender() void slotThingStateValueChanged(const StateTypeId &stateTypeId, const QVariant &value); diff --git a/libnymea-core/jsonrpc/actionhandler.cpp b/libnymea-core/jsonrpc/actionhandler.cpp index 4a6721fe..b9f2999f 100644 --- a/libnymea-core/jsonrpc/actionhandler.cpp +++ b/libnymea-core/jsonrpc/actionhandler.cpp @@ -107,7 +107,7 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap ¶ms, const JsonCon JsonReply *jsonReply = createAsyncReply("ExecuteAction"); - ThingActionInfo *info = NymeaCore::instance()->executeAction(action); + ThingActionInfo *info = NymeaCore::instance()->thingManager()->executeAction(action); connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){ QVariantMap data; data.insert("deviceError", enumValueName(info->status()).replace("Thing", "Device")); diff --git a/libnymea-core/jsonrpc/devicehandler.cpp b/libnymea-core/jsonrpc/devicehandler.cpp index c8b86c67..281869a7 100644 --- a/libnymea-core/jsonrpc/devicehandler.cpp +++ b/libnymea-core/jsonrpc/devicehandler.cpp @@ -62,6 +62,7 @@ DeviceHandler::DeviceHandler(QObject *parent) : registerEnum(); registerEnum(); registerEnum(); + registerEnum(); registerEnum(); registerEnum(); registerEnum(); @@ -900,7 +901,7 @@ JsonReply *DeviceHandler::ExecuteAction(const QVariantMap ¶ms, const JsonCon JsonReply *jsonReply = createAsyncReply("ExecuteAction"); - ThingActionInfo *info = NymeaCore::instance()->executeAction(action); + ThingActionInfo *info = NymeaCore::instance()->thingManager()->executeAction(action); connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){ QVariantMap data; data.insert("deviceError", enumValueName(info->status()).replace("Thing", "Device")); diff --git a/libnymea-core/jsonrpc/integrationshandler.cpp b/libnymea-core/jsonrpc/integrationshandler.cpp index 08243330..d42e7e3c 100644 --- a/libnymea-core/jsonrpc/integrationshandler.cpp +++ b/libnymea-core/jsonrpc/integrationshandler.cpp @@ -61,6 +61,7 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa registerEnum(); registerEnum(); registerEnum(); + registerEnum(); registerEnum(); registerEnum(); registerEnum(); @@ -958,7 +959,7 @@ JsonReply *IntegrationsHandler::ExecuteAction(const QVariantMap ¶ms, const J JsonReply *jsonReply = createAsyncReply("ExecuteAction"); - ThingActionInfo *info = NymeaCore::instance()->executeAction(action); + ThingActionInfo *info = NymeaCore::instance()->thingManager()->executeAction(action); connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){ QVariantMap data; data.insert("thingError", enumValueName(info->status())); diff --git a/libnymea-core/logging/logengine.cpp b/libnymea-core/logging/logengine.cpp index 5f6630fc..4927e5a9 100644 --- a/libnymea-core/logging/logengine.cpp +++ b/libnymea-core/logging/logengine.cpp @@ -34,6 +34,8 @@ #include "logging.h" #include "logvaluetool.h" +#include "integrations/thingmanager.h" + #include #include #include @@ -104,6 +106,13 @@ LogEngine::~LogEngine() m_db.close(); } +void LogEngine::setThingManager(ThingManager *thingManager) +{ + m_thingManager = thingManager; + connect(thingManager, &ThingManager::eventTriggered, this, &LogEngine::logEvent); + connect(thingManager, &ThingManager::actionExecuted, this, &LogEngine::logAction); +} + LogEntriesFetchJob *LogEngine::fetchLogEntries(const LogFilter &filter) { QList results; @@ -222,6 +231,10 @@ void LogEngine::logSystemEvent(const QDateTime &dateTime, bool active, Logging:: void LogEngine::logEvent(const Event &event) { + if (!event.logged()) { + return; + } + QVariantList valueList; Logging::LoggingSource sourceType; if (event.isStateChangeEvent()) { @@ -249,9 +262,10 @@ void LogEngine::logEvent(const Event &event) appendLogEntry(entry); } -void LogEngine::logAction(const Action &action, Logging::LoggingLevel level, int errorCode) +void LogEngine::logAction(const Action &action, Thing::ThingError status) { - LogEntry entry(level, Logging::LoggingSourceActions, errorCode); + Logging::LoggingLevel level = status == Thing::ThingErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert; + LogEntry entry(QDateTime::currentDateTime(), level, Logging::LoggingSourceActions, status); entry.setTypeId(action.actionTypeId()); entry.setThingId(action.thingId()); diff --git a/libnymea-core/logging/logengine.h b/libnymea-core/logging/logengine.h index 8ce94c8c..a3749a2e 100644 --- a/libnymea-core/logging/logengine.h +++ b/libnymea-core/logging/logengine.h @@ -38,6 +38,7 @@ #include "types/browseritemaction.h" #include "types/browseraction.h" #include "ruleengine/rule.h" +#include "integrations/thingmanager.h" #include #include @@ -60,6 +61,8 @@ 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(); + void setThingManager(ThingManager *thingManager); + LogEntriesFetchJob *fetchLogEntries(const LogFilter &filter = LogFilter()); ThingsFetchJob *fetchThings(); @@ -68,9 +71,11 @@ public: void setMaxLogEntries(int maxLogEntries, int trimSize); void clearDatabase(); + void removeThingLogs(const ThingId &thingId); + void removeRuleLogs(const RuleId &ruleId); + +public slots: void logSystemEvent(const QDateTime &dateTime, bool active, Logging::LoggingLevel level = Logging::LoggingLevelInfo); - void logEvent(const Event &event); - void logAction(const Action &action, 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 logRuleTriggered(const Rule &rule); @@ -78,8 +83,10 @@ public: void logRuleEnabledChanged(const Rule &rule, const bool &enabled); void logRuleActionsExecuted(const Rule &rule); void logRuleExitActionsExecuted(const Rule &rule); - void removeThingLogs(const ThingId &thingId); - void removeRuleLogs(const RuleId &ruleId); + +private slots: + void logEvent(const Event &event); + void logAction(const Action &action, Thing::ThingError status); signals: void logEntryAdded(const LogEntry &logEntry); @@ -114,6 +121,8 @@ private: bool m_initialized = 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 int m_maxQueueLength; QHash> m_flaggedJobs; diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index 8a15050a..a746f8b8 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -99,9 +99,6 @@ void NymeaCore::init(const QStringList &additionalInterfaces) { } m_timeManager = new TimeManager(this); - 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); - qCDebug(dcCore()) << "Creating User Manager"; m_userManager = new UserManager(NymeaSettings::settingsPath() + "/user-db.sqlite", this); @@ -120,6 +117,10 @@ void NymeaCore::init(const QStringList &additionalInterfaces) { qCDebug(dcCore) << "Creating Rule Engine"; m_ruleEngine = new RuleEngine(this); + 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->setThingManager(m_thingManager); + qCDebug(dcCore()) << "Creating Script Engine"; m_scriptEngine = new ScriptEngine(m_thingManager, this); m_serverManager->jsonServer()->registerHandler(new ScriptsHandler(m_scriptEngine, m_scriptEngine)); @@ -380,20 +381,6 @@ Thing::ThingError NymeaCore::removeConfiguredThing(const ThingId &thingId, const return removeError; } -ThingActionInfo* NymeaCore::executeAction(const Action &action) -{ - ThingActionInfo *info = m_thingManager->executeAction(action); - connect(info, &ThingActionInfo::finished, this, [this, info](){ - if (info->status() == Thing::ThingErrorNoError) { - m_logger->logAction(info->action()); - } else { - m_logger->logAction(info->action(), Logging::LoggingLevelAlert, info->status()); - } - }); - - return info; -} - BrowserActionInfo* NymeaCore::executeBrowserItem(const BrowserAction &browserAction) { BrowserActionInfo *info = m_thingManager->executeBrowserItem(browserAction); @@ -512,7 +499,7 @@ void NymeaCore::executeRuleActions(const QList ruleActions) foreach (const Action &action, actions) { qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params(); - ThingActionInfo *info = executeAction(action); + 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(); @@ -660,17 +647,6 @@ ZigbeeManager *NymeaCore::zigbeeManager() const void NymeaCore::gotEvent(const Event &event) { - Thing *thing = m_thingManager->findConfiguredThing(event.thingId()); - ThingClass thingClass = thing ? thing->thingClass() : ThingClass(); - EventType eventType = thingClass.eventTypes().findById(event.eventTypeId()); - foreach (const QString &interfaceName, thingClass.interfaces()) { - Interface iface = m_thingManager->supportedInterfaces().findByName(interfaceName); - if (iface.eventTypes().findByName(eventType.name()).logged()) { - m_logger->logEvent(event); - break; - } - } - emit eventTriggered(event); QList actions; diff --git a/libnymea-core/nymeacore.h b/libnymea-core/nymeacore.h index 3391c258..3201b4d6 100644 --- a/libnymea-core/nymeacore.h +++ b/libnymea-core/nymeacore.h @@ -84,7 +84,6 @@ public: QPair >removeConfiguredThing(const ThingId &thingId, const QHash &removePolicyList); Thing::ThingError removeConfiguredThing(const ThingId &thingId, const RuleEngine::RemovePolicy &removePolicy); - ThingActionInfo *executeAction(const Action &action); BrowserActionInfo* executeBrowserItem(const BrowserAction &browserAction); BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction); diff --git a/libnymea/integrations/pluginmetadata.cpp b/libnymea/integrations/pluginmetadata.cpp index e63ad508..5e2b1f7d 100644 --- a/libnymea/integrations/pluginmetadata.cpp +++ b/libnymea/integrations/pluginmetadata.cpp @@ -469,6 +469,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) break; } stateType.setIOType(ioType); + stateType.setSuggestLogging(st.value("suggestLogging").toBool()); } stateTypes.append(stateType); @@ -485,6 +486,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) paramType.setUnit(stateType.unit()); eventType.setParamTypes(QList() << paramType); eventType.setIndex(stateType.index()); + eventType.setSuggestLogging(st.value("suggestLogging").toBool()); eventTypes.append(eventType); // ActionTypes for writeable StateTypes @@ -497,7 +499,6 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) actionTypes.append(actionType); } } - thingClass.setStateTypes(stateTypes); // ActionTypes index = 0; @@ -544,7 +545,6 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) actionTypes.append(actionType); } - thingClass.setActionTypes(actionTypes); // EventTypes index = 0; @@ -580,6 +580,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) EventType eventType(eventTypeId); eventType.setName(eventTypeName); eventType.setDisplayName(et.value("displayName").toString()); + eventType.setSuggestLogging(et.value("suggestLogging").toBool()); eventType.setIndex(index++); QPair > paramVerification = parseParamTypes(et.value("paramTypes").toArray()); @@ -590,7 +591,6 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) } eventTypes.append(eventType); } - thingClass.setEventTypes(eventTypes); // BrowserItemActionTypes index = 0; @@ -637,7 +637,6 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) browserItemActionTypes.append(actionType); } - thingClass.setBrowserItemActionTypes(browserItemActionTypes); // Read interfaces QStringList interfaces; @@ -646,22 +645,18 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) if (!iface.isValid()) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" uses non-existing interface \"" + value.toString() + "\""); hasError = true; + continue; } - StateTypes stateTypes(thingClass.stateTypes()); - ActionTypes actionTypes(thingClass.actionTypes()); - EventTypes eventTypes(thingClass.eventTypes()); - foreach (const InterfaceStateType &ifaceStateType, iface.stateTypes()) { - StateType stateType = stateTypes.findByName(ifaceStateType.name()); - if (stateType.id().isNull()) { + if (!stateTypes.contains(ifaceStateType.name())) { if (!ifaceStateType.optional()) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" claims to implement interface \"" + value.toString() + "\" but doesn't implement state \"" + ifaceStateType.name() + "\""); hasError = true; - } else { - continue; } + continue; } + StateType &stateType = stateTypes[ifaceStateType.name()]; if (ifaceStateType.type() != stateType.type()) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" claims to implement interface \"" + value.toString() + "\" but state \"" + stateType.name() + "\" has not matching type: \"" + QVariant::typeToName(stateType.type()) + "\" != \"" + QVariant::typeToName(ifaceStateType.type()) + "\""); hasError = true; @@ -697,18 +692,22 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) m_validationErrors.append("Thing class \"" + thingClass.name() + "\" claims to implement interface \"" + value.toString() + "\" but state \"" + stateType.name() + "\" has not matching unit: \"" + unitEnum.valueToKey(ifaceStateType.unit()) + "\" != \"" + unitEnum.valueToKey(stateType.unit())); hasError = true; } + + // Override logged property as the interface has higher priority than the plugin dev + if (ifaceStateType.loggingOverride()) { + stateType.setSuggestLogging(ifaceStateType.suggestLogging()); + } } foreach (const InterfaceActionType &ifaceActionType, iface.actionTypes()) { - ActionType actionType = actionTypes.findByName(ifaceActionType.name()); - if (actionType.id().isNull()) { + if (!actionTypes.contains(ifaceActionType.name())) { if (!ifaceActionType.optional()) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" claims to implement interface \"" + value.toString() + "\" but doesn't implement action \"" + ifaceActionType.name() + "\""); hasError = true; - } else { - continue; } + continue; } + ActionType &actionType = actionTypes[ifaceActionType.name()]; // Verify the params as required by the interface are available foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) { ParamType paramType = actionType.paramTypes().findByName(ifaceActionParamType.name()); @@ -779,15 +778,14 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) } foreach (const InterfaceEventType &ifaceEventType, iface.eventTypes()) { - EventType eventType = eventTypes.findByName(ifaceEventType.name()); - if (!eventType.isValid()) { + if (!eventTypes.contains(ifaceEventType.name())) { if (!ifaceEventType.optional()) { m_validationErrors.append("Thing class \"" + thingClass.name() + "\" claims to implement interface \"" + value.toString() + "\" but doesn't implement event \"" + ifaceEventType.name() + "\""); hasError = true; - } else { - continue; } + continue; } + EventType &eventType = eventTypes[ifaceEventType.name()]; // Verify all the params as required by the interface are available foreach (const ParamType &ifaceEventParamType, ifaceEventType.paramTypes()) { @@ -842,6 +840,11 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) } } + // Override logging + if (ifaceEventType.loggingOverride()) { + eventType.setSuggestLogging(ifaceEventType.suggestLogging()); + } + // Note: No need to check for default values (as with actions) for additional params as // an emitted event always needs to have params filled with values. The client might use them or not... } @@ -851,6 +854,11 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) interfaces.removeDuplicates(); thingClass.setInterfaces(interfaces); + thingClass.setStateTypes(stateTypes); + thingClass.setActionTypes(actionTypes); + thingClass.setEventTypes(eventTypes); + thingClass.setBrowserItemActionTypes(browserItemActionTypes); + m_thingClasses.append(thingClass); } } diff --git a/libnymea/integrations/statevaluefilters/statevaluefilter.cpp b/libnymea/integrations/statevaluefilters/statevaluefilter.cpp new file mode 100644 index 00000000..68e88626 --- /dev/null +++ b/libnymea/integrations/statevaluefilters/statevaluefilter.cpp @@ -0,0 +1,6 @@ +#include "statevaluefilter.h" + +StateValueFilter::StateValueFilter() +{ + +} diff --git a/libnymea/integrations/statevaluefilters/statevaluefilter.h b/libnymea/integrations/statevaluefilters/statevaluefilter.h new file mode 100644 index 00000000..83b59a88 --- /dev/null +++ b/libnymea/integrations/statevaluefilters/statevaluefilter.h @@ -0,0 +1,18 @@ +#ifndef STATEVALUEFILTER_H +#define STATEVALUEFILTER_H + +#include + +class StateValueFilter +{ +public: + StateValueFilter(); + virtual ~StateValueFilter(); + + virtual void addValue(const QVariant &value) = 0; + + virtual QVariant filteredValue() const = 0; + +}; + +#endif // STATEVALUEFILTER_H diff --git a/libnymea/integrations/statevaluefilters/statevaluefilteradaptive.cpp b/libnymea/integrations/statevaluefilters/statevaluefilteradaptive.cpp new file mode 100644 index 00000000..26f5217b --- /dev/null +++ b/libnymea/integrations/statevaluefilters/statevaluefilteradaptive.cpp @@ -0,0 +1,11 @@ +#include "statevaluefilteradaptive.h" + +StateValueFilterAdaptive::StateValueFilterAdaptive() +{ + +} + +void StateValueFilterAdaptive::addValue(const QVariant &value) +{ + +} diff --git a/libnymea/integrations/statevaluefilters/statevaluefilteradaptive.h b/libnymea/integrations/statevaluefilters/statevaluefilteradaptive.h new file mode 100644 index 00000000..dbb85b84 --- /dev/null +++ b/libnymea/integrations/statevaluefilters/statevaluefilteradaptive.h @@ -0,0 +1,15 @@ +#ifndef STATEVALUEFILTERADAPTIVE_H +#define STATEVALUEFILTERADAPTIVE_H + +#include "statevaluefilter.h" + +class StateValueFilterAdaptive : public StateValueFilter +{ +public: + StateValueFilterAdaptive(); + + void addValue(const QVariant &value) override; + QVariant filteredValue() const override; +}; + +#endif // STATEVALUEFILTERADAPTIVE_H diff --git a/libnymea/integrations/thing.cpp b/libnymea/integrations/thing.cpp index 48581061..17bee3fe 100644 --- a/libnymea/integrations/thing.cpp +++ b/libnymea/integrations/thing.cpp @@ -133,6 +133,7 @@ #include "thing.h" #include "types/event.h" #include "loggingcategories.h" +#include "statevaluefilters/statevaluefilteradaptive.h" #include @@ -334,9 +335,6 @@ void Thing::setStateValue(const StateTypeId &stateTypeId, const QVariant &value) } for (int i = 0; i < m_states.count(); ++i) { if (m_states.at(i).stateTypeId() == stateTypeId) { - if (m_states.at(i).value() == value) - return; - QVariant newValue = value; if (!newValue.convert(stateType.type())) { qCWarning(dcThing()).nospace() << m_name << ": Invalid value " << value << " for state " << stateType.name() << ". Type mismatch. Expected type: " << QVariant::typeToName(stateType.type()) << " (Discarding change)"; @@ -355,8 +353,13 @@ void Thing::setStateValue(const StateTypeId &stateTypeId, const QVariant &value) return; } - QVariant oldValue = m_states.at(i).value(); + StateValueFilter *filter = m_stateValueFilters.value(stateTypeId); + if (filter) { + filter->addValue(newValue); + newValue = filter->filteredValue(); + } + QVariant oldValue = m_states.at(i).value(); if (oldValue == newValue) { qCDebug(dcThing()).nospace() << m_name << ": Discarding state change for " << stateType.name() << " as the value did not actually change. Old value:" << oldValue << "New value:" << newValue; return; @@ -383,22 +386,9 @@ State Thing::state(const StateTypeId &stateTypeId) const return State(StateTypeId(), ThingId()); } -void Thing::setStateLogged(const StateTypeId &stateTypeId, bool logged) +QList Thing::loggedEventTypeIds() const { - for (int i = 0; i < m_states.count(); i++) { - if (m_states.at(i).stateTypeId() == stateTypeId) { - m_states[i].setLogged(logged); - } - } -} - -void Thing::setStateFilter(const StateTypeId &stateTypeId, Types::StateValueFilter filter) -{ - for (int i = 0; i < m_states.count(); i++) { - if (m_states.at(i).stateTypeId() == stateTypeId) { - m_states[i].setFilter(filter); - } - } + return m_loggedEventTypeIds; } /*! Returns the \l{ThingId} of the parent of this thing. If the parentId @@ -460,6 +450,27 @@ void Thing::setSetupStatus(Thing::ThingSetupStatus status, Thing::ThingError set emit setupStatusChanged(); } +void Thing::setLoggedEventTypeIds(const QList loggedEventTypeIds) +{ + m_loggedEventTypeIds = loggedEventTypeIds; +} + +void Thing::setStateValueFilter(const StateTypeId &stateTypeId, Types::StateValueFilter filter) +{ + for (int i = 0; i < m_states.count(); i++) { + if (m_states.at(i).stateTypeId() == stateTypeId) { + m_states[i].setFilter(filter); + StateValueFilter *stateValueFilter = m_stateValueFilters.take(stateTypeId); + if (stateValueFilter) { + delete stateValueFilter; + } + if (filter == Types::StateValueFilterAdaptive) { + m_stateValueFilters.insert(stateTypeId, new StateValueFilterAdaptive()); + } + } + } +} + Things::Things(const QList &other) { foreach (Thing* thing, other) { diff --git a/libnymea/integrations/thing.h b/libnymea/integrations/thing.h index f5b46244..efe941c7 100644 --- a/libnymea/integrations/thing.h +++ b/libnymea/integrations/thing.h @@ -45,6 +45,7 @@ #include class IntegrationPlugin; +class StateValueFilter; class LIBNYMEA_EXPORT Thing: public QObject { @@ -60,6 +61,7 @@ class LIBNYMEA_EXPORT Thing: public QObject Q_PROPERTY(QString setupDisplayMessage READ setupDisplayMessage NOTIFY setupStatusChanged USER true) Q_PROPERTY(ThingError setupError READ setupError NOTIFY setupStatusChanged) Q_PROPERTY(QUuid parentId READ parentId USER true) + Q_PROPERTY(QList loggedEventTypeIds READ loggedEventTypeIds USER true) public: enum ThingError { @@ -133,8 +135,7 @@ public: Q_INVOKABLE State state(const StateTypeId &stateTypeId) const; - void setStateLogged(const StateTypeId &stateTypeId, bool logged); - void setStateFilter(const StateTypeId &stateTypeId, Types::StateValueFilter filter); + QList loggedEventTypeIds() const; ThingId parentId() const; void setParentId(const ThingId &parentId); @@ -164,6 +165,8 @@ private: Thing(const PluginId &pluginId, const ThingClass &thingClass, QObject *parent = nullptr); void setSetupStatus(ThingSetupStatus status, ThingError setupError, const QString &displayMessage = QString()); + void setLoggedEventTypeIds(const QList loggedEventTypeIds); + void setStateValueFilter(const StateTypeId &stateTypeId, Types::StateValueFilter filter); private: ThingClass m_thingClass; @@ -179,6 +182,9 @@ private: ThingSetupStatus m_setupStatus = ThingSetupStatusNone; ThingError m_setupError = ThingErrorNoError; QString m_setupDisplayMessage; + + QList m_loggedEventTypeIds; + QHash m_stateValueFilters; }; QDebug operator<<(QDebug dbg, Thing *device); diff --git a/libnymea/integrations/thingmanager.h b/libnymea/integrations/thingmanager.h index 06e78647..635a98bb 100644 --- a/libnymea/integrations/thingmanager.h +++ b/libnymea/integrations/thingmanager.h @@ -116,6 +116,7 @@ signals: void thingSettingChanged(const ThingId &thingId, const ParamTypeId &settingParamTypeId, const QVariant &value); void ioConnectionAdded(const IOConnection &ioConnection); void ioConnectionRemoved(const IOConnectionId &ioConnectionId); + void actionExecuted(const Action &action, Thing::ThingError status); }; #endif // THINGMANAGER_H diff --git a/libnymea/integrations/thingutils.cpp b/libnymea/integrations/thingutils.cpp index 6c384562..59c728af 100644 --- a/libnymea/integrations/thingutils.cpp +++ b/libnymea/integrations/thingutils.cpp @@ -200,7 +200,10 @@ Interface ThingUtils::loadInterface(const QString &name) stateType.setMinValue(stateVariant.toMap().value("minValue")); stateType.setMaxValue(stateVariant.toMap().value("maxValue")); stateType.setOptional(stateVariant.toMap().value("optional", false).toBool()); - stateType.setLogged(stateVariant.toMap().value("logged", false).toBool()); + if (stateVariant.toMap().contains("logged")) { + stateType.setLoggingOverride(true); + stateType.setSuggestLogging(stateVariant.toMap().value("logged", false).toBool()); + } if (stateVariant.toMap().contains("unit")) { QMetaEnum unitEnum = QMetaEnum::fromType(); int enumValue = unitEnum.keyToValue("Unit" + stateVariant.toMap().value("unit").toByteArray()); @@ -215,7 +218,8 @@ Interface ThingUtils::loadInterface(const QString &name) InterfaceEventType stateChangeEventType; stateChangeEventType.setName(stateType.name()); stateChangeEventType.setOptional(stateType.optional()); - stateChangeEventType.setLogged(stateType.logged()); + stateChangeEventType.setSuggestLogging(stateType.suggestLogging()); + stateChangeEventType.setLoggingOverride(stateType.loggingOverride()); ParamType stateChangeEventParamType; stateChangeEventParamType.setName(stateType.name()); stateChangeEventParamType.setType(stateType.type()); @@ -238,6 +242,10 @@ Interface ThingUtils::loadInterface(const QString &name) InterfaceActionType actionType; actionType.setName(actionVariant.toMap().value("name").toString()); actionType.setOptional(actionVariant.toMap().value("optional").toBool()); +// if (actionVariant.toMap().contains("logged")) { +// actionType.setLoggingOverride(true); +// actionType.setSuggestLogging(actionVariant.toMap().value("logged").toBool()); +// } ParamTypes paramTypes; foreach (const QVariant &actionParamVariant, actionVariant.toMap().value("params").toList()) { ParamType paramType; @@ -256,7 +264,10 @@ Interface ThingUtils::loadInterface(const QString &name) InterfaceEventType eventType; eventType.setName(eventVariant.toMap().value("name").toString()); eventType.setOptional(eventVariant.toMap().value("optional").toBool()); - eventType.setLogged(eventVariant.toMap().value("logged").toBool()); + if (eventVariant.toMap().contains("logged")) { + eventType.setLoggingOverride(true); + eventType.setSuggestLogging(eventVariant.toMap().value("logged").toBool()); + } ParamTypes paramTypes; foreach (const QVariant &eventParamVariant, eventVariant.toMap().value("params").toList()) { ParamType paramType; diff --git a/libnymea/jsonrpc/jsonhandler.cpp b/libnymea/jsonrpc/jsonhandler.cpp index 1dc446ee..48bb5b44 100644 --- a/libnymea/jsonrpc/jsonhandler.cpp +++ b/libnymea/jsonrpc/jsonhandler.cpp @@ -29,7 +29,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "jsonhandler.h" - +#include "typeutils.h" #include "loggingcategories.h" #include @@ -207,6 +207,9 @@ void JsonHandler::registerObject(const QMetaObject &metaObject) typeName = QString("$ref:BasicType"); } else if (QString(metaProperty.typeName()).startsWith("QList")) { QString elementType = QString(metaProperty.typeName()).remove("QList<").remove(">"); + if (elementType == "EventTypeId" || elementType == "StateTypeId" || elementType == "ActionTypeId") { + elementType = "QUuid"; + } QVariant::Type variantType = QVariant::nameToType(elementType.toUtf8()); typeName = QVariantList() << enumValueName(variantTypeToBasicType(variantType)); } else { @@ -344,6 +347,18 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con foreach (const QUuid &entry, propertyValue.value>()) { list << entry; } + } else if (propertyTypeName == "QList") { + foreach (const EventTypeId &entry, propertyValue.value>()) { + list << entry; + } + } else if (propertyTypeName == "QList") { + foreach (const EventTypeId &entry, propertyValue.value>()) { + list << entry; + } + } else if (propertyTypeName == "QList") { + foreach (const EventTypeId &entry, propertyValue.value>()) { + list << entry; + } } else { Q_ASSERT_X(false, this->metaObject()->className(), QString("Unhandled list type: %1").arg(propertyTypeName).toUtf8()); qCWarning(dcJsonRpc()) << "Cannot pack property of unhandled list type" << propertyTypeName; @@ -455,7 +470,10 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu intList.append(val.toInt()); } metaProperty.writeOnGadget(ptr, QVariant::fromValue(intList)); - } else if (metaProperty.typeName() == QStringLiteral("QList")) { + } else if (metaProperty.typeName() == QStringLiteral("QList") + || metaProperty.typeName() == QStringLiteral("QList") + || metaProperty.typeName() == QStringLiteral("QList") + || metaProperty.typeName() == QStringLiteral("QList")) { QList uuidList; foreach (const QVariant &val, variant.toList()) { uuidList.append(val.toUuid()); diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index 74b577ca..8db49aff 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -126,6 +126,8 @@ SOURCES += \ integrations/thingsetupinfo.cpp \ integrations/thingutils.cpp \ integrations/servicedata.cpp \ + integrations/statevaluefilters/statevaluefilter.cpp \ + integrations/statevaluefilters/statevaluefilteradaptive.cpp \ jsonrpc/jsoncontext.cpp \ jsonrpc/jsonhandler.cpp \ jsonrpc/jsonreply.cpp \ diff --git a/libnymea/types/actiontype.cpp b/libnymea/types/actiontype.cpp index cb303e23..fe5f3045 100644 --- a/libnymea/types/actiontype.cpp +++ b/libnymea/types/actiontype.cpp @@ -130,6 +130,26 @@ ActionTypes::ActionTypes(const QList &other) } } +bool ActionTypes::contains(const ActionTypeId &id) const +{ + foreach (const ActionType &actionType, *this) { + if (actionType.id() == id) { + return true; + } + } + return false; +} + +bool ActionTypes::contains(const QString &name) const +{ + foreach (const ActionType &actionType, *this) { + if (actionType.name() == name) { + return true; + } + } + return false; +} + QVariant ActionTypes::get(int index) const { return QVariant::fromValue(at(index)); @@ -160,8 +180,21 @@ ActionType ActionTypes::findById(const ActionTypeId &id) return ActionType(ActionTypeId()); } +ActionType &ActionTypes::operator[](const QString &name) +{ + int index = -1; + for (int i = 0; i < count(); i++) { + if (at(i).name() == name) { + index = i; + break; + } + } + return QList::operator[](index); +} + QDebug operator<<(QDebug dbg, const ActionType &actionType) { dbg.nospace().noquote() << "ActionType: " << actionType.name() << actionType.displayName() << actionType.id(); return dbg; } + diff --git a/libnymea/types/actiontype.h b/libnymea/types/actiontype.h index f5ef88f5..9a216ab2 100644 --- a/libnymea/types/actiontype.h +++ b/libnymea/types/actiontype.h @@ -84,10 +84,13 @@ class ActionTypes: public QList public: ActionTypes() = default; ActionTypes(const QList &other); + bool contains(const ActionTypeId &id) const; + bool contains(const QString &name) const; Q_INVOKABLE QVariant get(int index) const; Q_INVOKABLE void put(const QVariant &variant); ActionType findByName(const QString &name); ActionType findById(const ActionTypeId &id); + ActionType &operator[](const QString &name); }; Q_DECLARE_METATYPE(ActionTypes) diff --git a/libnymea/types/event.cpp b/libnymea/types/event.cpp index da3e687f..72360375 100644 --- a/libnymea/types/event.cpp +++ b/libnymea/types/event.cpp @@ -126,6 +126,16 @@ bool Event::isStateChangeEvent() const return m_isStateChangeEvent; } +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. * Events are equal (returns true) if eventTypeId, deviceId and params match. */ bool Event::operator ==(const Event &other) const diff --git a/libnymea/types/event.h b/libnymea/types/event.h index 93590b89..bb92e445 100644 --- a/libnymea/types/event.h +++ b/libnymea/types/event.h @@ -46,6 +46,7 @@ class LIBNYMEA_EXPORT Event Q_PROPERTY(QUuid thingId READ thingId) Q_PROPERTY(QUuid deviceId READ thingId REVISION 1) Q_PROPERTY(ParamList params READ params) + Q_PROPERTY(bool logged READ logged) public: Event(); Event(const EventTypeId &eventTypeId, const ThingId &thingId, const ParamList ¶ms = ParamList(), bool isStateChangeEvent = false); @@ -65,12 +66,16 @@ public: bool isStateChangeEvent() const; + bool logged() const; + void setLogged(bool logged); + private: EventTypeId m_eventTypeId; ThingId m_thingId; ParamList m_params; bool m_isStateChangeEvent; + bool m_logged = false; }; Q_DECLARE_METATYPE(Event) QDebug operator<<(QDebug dbg, const Event &event); diff --git a/libnymea/types/eventtype.cpp b/libnymea/types/eventtype.cpp index 9001837b..42e589bb 100644 --- a/libnymea/types/eventtype.cpp +++ b/libnymea/types/eventtype.cpp @@ -110,6 +110,16 @@ void EventType::setParamTypes(const ParamTypes ¶mTypes) m_paramTypes = paramTypes; } +bool EventType::suggestLogging() const +{ + return m_logged; +} + +void EventType::setSuggestLogging(bool logged) +{ + m_logged = logged; +} + /*! Returns true if this EventType has a valid id and name */ bool EventType::isValid() const { @@ -130,11 +140,31 @@ QStringList EventType::mandatoryTypeProperties() EventTypes::EventTypes(const QList &other) { - foreach (const EventType &at, other) { - append(at); + foreach (const EventType &et, other) { + append(et); } } +bool EventTypes::contains(const EventTypeId &id) const +{ + foreach (const EventType &eventType, *this) { + if (eventType.id() == id) { + return true; + } + } + return false; +} + +bool EventTypes::contains(const QString &name) const +{ + foreach (const EventType &eventType, *this) { + if (eventType.name() == name) { + return true; + } + } + return false; +} + QVariant EventTypes::get(int index) const { return QVariant::fromValue(at(index)); @@ -164,3 +194,15 @@ EventType EventTypes::findById(const EventTypeId &id) } return EventType(EventTypeId()); } + +EventType &EventTypes::operator[](const QString &name) +{ + int index = -1; + for (int i = 0; i < count(); i++) { + if (at(i).name() == name) { + index = i; + break; + } + } + return QList::operator[](index); +} diff --git a/libnymea/types/eventtype.h b/libnymea/types/eventtype.h index cbcee65d..237bb9bb 100644 --- a/libnymea/types/eventtype.h +++ b/libnymea/types/eventtype.h @@ -64,6 +64,9 @@ public: ParamTypes paramTypes() const; void setParamTypes(const ParamTypes ¶mTypes); + bool suggestLogging() const; + void setSuggestLogging(bool logged); + bool isValid() const; static QStringList typeProperties(); @@ -75,6 +78,7 @@ private: QString m_displayName; int m_index; QList m_paramTypes; + bool m_logged = false; }; Q_DECLARE_METATYPE(EventType) @@ -85,10 +89,13 @@ class EventTypes: public QList public: EventTypes() = default; EventTypes(const QList &other); + bool contains(const EventTypeId &id) const; + bool contains(const QString &name) const; Q_INVOKABLE QVariant get(int index) const; Q_INVOKABLE void put(const QVariant &variant); EventType findByName(const QString &name); EventType findById(const EventTypeId &id); + EventType &operator[](const QString &name); }; Q_DECLARE_METATYPE(EventTypes) diff --git a/libnymea/types/interfaceeventtype.cpp b/libnymea/types/interfaceeventtype.cpp index 9d4ce6aa..6b1017d3 100644 --- a/libnymea/types/interfaceeventtype.cpp +++ b/libnymea/types/interfaceeventtype.cpp @@ -15,14 +15,14 @@ void InterfaceEventType::setOptional(bool optional) m_optional = optional; } -bool InterfaceEventType::logged() const +bool InterfaceEventType::loggingOverride() const { - return m_logged; + return m_loggingOverride; } -void InterfaceEventType::setLogged(bool logged) +void InterfaceEventType::setLoggingOverride(bool loggingOverride) { - m_logged = logged; + m_loggingOverride = loggingOverride; } InterfaceEventTypes::InterfaceEventTypes(const QList &other): diff --git a/libnymea/types/interfaceeventtype.h b/libnymea/types/interfaceeventtype.h index aa3a79c2..84eca98f 100644 --- a/libnymea/types/interfaceeventtype.h +++ b/libnymea/types/interfaceeventtype.h @@ -11,12 +11,12 @@ public: bool optional() const; void setOptional(bool optional); - bool logged() const; - void setLogged(bool logged); + bool loggingOverride() const; + void setLoggingOverride(bool loggingOverride); private: bool m_optional = false; - bool m_logged = false; + bool m_loggingOverride = false; }; class InterfaceEventTypes: public QList diff --git a/libnymea/types/interfacestatetype.cpp b/libnymea/types/interfacestatetype.cpp index e2b97191..02c72567 100644 --- a/libnymea/types/interfacestatetype.cpp +++ b/libnymea/types/interfacestatetype.cpp @@ -15,14 +15,14 @@ void InterfaceStateType::setOptional(bool optional) m_optional = optional; } -bool InterfaceStateType::logged() const +bool InterfaceStateType::loggingOverride() const { - return m_logged; + return m_loggingOverride; } -void InterfaceStateType::setLogged(bool logged) +void InterfaceStateType::setLoggingOverride(bool loggingOverride) { - m_logged = logged; + m_loggingOverride = loggingOverride; } InterfaceStateTypes::InterfaceStateTypes(const QList &other): diff --git a/libnymea/types/interfacestatetype.h b/libnymea/types/interfacestatetype.h index 88429916..946ea404 100644 --- a/libnymea/types/interfacestatetype.h +++ b/libnymea/types/interfacestatetype.h @@ -11,12 +11,12 @@ public: bool optional() const; void setOptional(bool optional); - bool logged() const; - void setLogged(bool logged); + bool loggingOverride() const; + void setLoggingOverride(bool loggingOverride); private: bool m_optional = false; - bool m_logged = false; + bool m_loggingOverride = false; }; class InterfaceStateTypes: public QList diff --git a/libnymea/types/state.cpp b/libnymea/types/state.cpp index 3717bf85..20cba66f 100644 --- a/libnymea/types/state.cpp +++ b/libnymea/types/state.cpp @@ -90,16 +90,6 @@ void State::setFilter(Types::StateValueFilter filter) m_filter = filter; } -bool State::logged() const -{ - return m_logged; -} - -void State::setLogged(bool logged) -{ - m_logged = logged; -} - /*! Writes the stateTypeId, the deviceId and the value of the given \a state to \a dbg. */ QDebug operator<<(QDebug dbg, const State &state) { diff --git a/libnymea/types/state.h b/libnymea/types/state.h index 754fd843..a5d77d3a 100644 --- a/libnymea/types/state.h +++ b/libnymea/types/state.h @@ -43,7 +43,6 @@ class LIBNYMEA_EXPORT State Q_PROPERTY(QUuid stateTypeId READ stateTypeId) Q_PROPERTY(QVariant value READ value) Q_PROPERTY(Types::StateValueFilter filter READ filter) - Q_PROPERTY(bool logged READ logged) public: State(); @@ -58,15 +57,11 @@ public: Types::StateValueFilter filter() const; void setFilter(Types::StateValueFilter filter); - bool logged() const; - void setLogged(bool logged); - private: StateTypeId m_stateTypeId; ThingId m_thingId; QVariant m_value; - Types::StateValueFilter m_filter; - bool m_logged = false; + Types::StateValueFilter m_filter = Types::StateValueFilterNone; }; Q_DECLARE_METATYPE(State) diff --git a/libnymea/types/statetype.cpp b/libnymea/types/statetype.cpp index d566752c..74b70ad5 100644 --- a/libnymea/types/statetype.cpp +++ b/libnymea/types/statetype.cpp @@ -208,6 +208,16 @@ void StateType::setCached(bool cached) m_cached = cached; } +bool StateType::suggestLogging() const +{ + return m_logged; +} + +void StateType::setSuggestLogging(bool logged) +{ + m_logged = logged; +} + Types::StateValueFilter StateType::filter() const { return m_filter; @@ -223,7 +233,7 @@ QStringList StateType::typeProperties() { return QStringList() << "id" << "name" << "displayName" << "displayNameEvent" << "type" << "defaultValue" << "cached" << "unit" << "minValue" << "maxValue" << "possibleValues" << "writable" - << "displayNameAction" << "ioType"; + << "displayNameAction" << "ioType" << "logged"; } /*! Returns a list of mandatory properties a DeviceClass definition must have. */ @@ -255,6 +265,16 @@ bool StateTypes::contains(const StateTypeId &stateTypeId) return false; } +bool StateTypes::contains(const QString &name) +{ + foreach (const StateType &stateType, *this) { + if (stateType.name() == name) { + return true; + } + } + return false; +} + QVariant StateTypes::get(int index) const { return QVariant::fromValue(at(index)); @@ -284,3 +304,15 @@ StateType StateTypes::findById(const StateTypeId &id) } return StateType(StateTypeId()); } + +StateType &StateTypes::operator[](const QString &name) +{ + int index = -1; + for (int i = 0; i < count(); i++) { + if (at(i).name() == name) { + index = i; + break; + } + } + return QList::operator[](index); +} diff --git a/libnymea/types/statetype.h b/libnymea/types/statetype.h index 0b542360..b1504e55 100644 --- a/libnymea/types/statetype.h +++ b/libnymea/types/statetype.h @@ -93,8 +93,8 @@ public: bool cached() const; void setCached(bool cached); - bool logged() const; - void setLogged(bool logged); + bool suggestLogging() const; + void setSuggestLogging(bool logged); Types::StateValueFilter filter() const; void setFilter(Types::StateValueFilter filter); @@ -131,10 +131,12 @@ public: StateTypes() = default; StateTypes(const QList &other); bool contains(const StateTypeId &stateTypeId); + bool contains(const QString &name); Q_INVOKABLE QVariant get(int index) const; Q_INVOKABLE void put(const QVariant &variant); StateType findByName(const QString &name); StateType findById(const StateTypeId &id); + StateType &operator[](const QString &name); }; Q_DECLARE_METATYPE(StateTypes)