diff --git a/guh-control/android/gradle.properties b/guh-control/android/gradle.properties index ffb43466..e0b7cd25 100644 --- a/guh-control/android/gradle.properties +++ b/guh-control/android/gradle.properties @@ -6,4 +6,4 @@ androidBuildToolsVersion=26.0.1 androidCompileSdkVersion=26 buildDir=.build -qt5AndroidDir=/home/micha/Develop/Qt/5.8/android_armv7/src/android/java +qt5AndroidDir=/home/micha/Develop/Qt/5.10.1/android_armv7/src/android/java diff --git a/guh-control/devicemanager.cpp b/guh-control/devicemanager.cpp index b7685868..c6930b63 100644 --- a/guh-control/devicemanager.cpp +++ b/guh-control/devicemanager.cpp @@ -216,7 +216,7 @@ void DeviceManager::pairDeviceResponse(const QVariantMap ¶ms) emit pairDeviceReply(params.value("params").toMap()); } -void DeviceManager::confirmPairintResponse(const QVariantMap ¶ms) +void DeviceManager::confirmPairingResponse(const QVariantMap ¶ms) { emit confirmPairingReply(params.value("params").toMap()); } @@ -231,11 +231,11 @@ void DeviceManager::addDiscoveredDevice(const QUuid &deviceClassId, const QUuid m_jsonClient->sendCommand("Devices.AddConfiguredDevice", params); } -void DeviceManager::pairDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId) +void DeviceManager::pairDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId, const QString &name) { qDebug() << "JsonRpc: pair device " << deviceClassId.toString(); QVariantMap params; - params.insert("name", "name"); + params.insert("name", name); params.insert("deviceClassId", deviceClassId.toString()); params.insert("deviceDescriptorId", deviceDescriptorId.toString()); m_jsonClient->sendCommand("Devices.PairDevice", params, this, "pairDeviceResponse"); diff --git a/guh-control/devicemanager.h b/guh-control/devicemanager.h index d886d4fe..74f2f621 100644 --- a/guh-control/devicemanager.h +++ b/guh-control/devicemanager.h @@ -53,7 +53,7 @@ public: Q_INVOKABLE void addDevice(const QUuid &deviceClassId, const QString &name, const QVariantList &deviceParams); Q_INVOKABLE void addDiscoveredDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId, const QString &name); - Q_INVOKABLE void pairDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId); + Q_INVOKABLE void pairDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId, const QString &name); Q_INVOKABLE void confirmPairing(const QUuid &pairingTransactionId, const QString &secret = QString()); Q_INVOKABLE void removeDevice(const QUuid &deviceId); Q_INVOKABLE void executeAction(const QUuid &deviceId, const QUuid &actionTypeId, const QVariantList ¶ms = QVariantList()); @@ -67,7 +67,7 @@ private: Q_INVOKABLE void addDeviceResponse(const QVariantMap ¶ms); Q_INVOKABLE void removeDeviceResponse(const QVariantMap ¶ms); Q_INVOKABLE void pairDeviceResponse(const QVariantMap ¶ms); - Q_INVOKABLE void confirmPairintResponse(const QVariantMap ¶ms); + Q_INVOKABLE void confirmPairingResponse(const QVariantMap ¶ms); signals: void pairDeviceReply(const QVariantMap ¶ms); diff --git a/guh-control/engine.cpp b/guh-control/engine.cpp index 1585bf34..71734b44 100644 --- a/guh-control/engine.cpp +++ b/guh-control/engine.cpp @@ -22,6 +22,7 @@ #include "tcpsocketinterface.h" #include "rulemanager.h" +#include "logmanager.h" Engine* Engine::s_instance = 0; @@ -56,6 +57,11 @@ JsonRpcClient *Engine::jsonRpcClient() const return m_jsonRpcClient; } +LogManager *Engine::logManager() const +{ + return m_logManager; +} + GuhConnection *Engine::connection() const { return m_connection; @@ -66,7 +72,8 @@ Engine::Engine(QObject *parent) : m_connection(new GuhConnection(this)), m_jsonRpcClient(new JsonRpcClient(m_connection, this)), m_deviceManager(new DeviceManager(m_jsonRpcClient, this)), - m_ruleManager(new RuleManager(m_jsonRpcClient, this)) + m_ruleManager(new RuleManager(m_jsonRpcClient, this)), + m_logManager(new LogManager(m_jsonRpcClient, this)) { connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, &Engine::onConnectedChanged); connect(m_jsonRpcClient, &JsonRpcClient::authenticationRequiredChanged, this, &Engine::onConnectedChanged); diff --git a/guh-control/engine.h b/guh-control/engine.h index 5068a728..bc8d2250 100644 --- a/guh-control/engine.h +++ b/guh-control/engine.h @@ -29,8 +29,8 @@ #include "guhinterface.h" #include "jsonrpc/jsonrpcclient.h" - class RuleManager; +class LogManager; class Engine : public QObject { @@ -51,6 +51,7 @@ public: DeviceManager *deviceManager() const; RuleManager *ruleManager() const; JsonRpcClient *jsonRpcClient() const; + LogManager *logManager() const; private: explicit Engine(QObject *parent = 0); @@ -60,6 +61,7 @@ private: JsonRpcClient *m_jsonRpcClient; DeviceManager *m_deviceManager; RuleManager *m_ruleManager; + LogManager *m_logManager; private slots: void onConnectedChanged(); diff --git a/guh-control/guh-control.pro b/guh-control/guh-control.pro index d5fed17c..f0d44b49 100644 --- a/guh-control/guh-control.pro +++ b/guh-control/guh-control.pro @@ -35,7 +35,8 @@ HEADERS += engine.h \ models/rulesfiltermodel.h \ models/logsmodel.h \ models/valuelogsproxymodel.h \ - discovery/guhdiscovery.h + discovery/guhdiscovery.h \ + logmanager.h SOURCES += main.cpp \ @@ -66,7 +67,8 @@ SOURCES += main.cpp \ models/rulesfiltermodel.cpp \ models/logsmodel.cpp \ models/valuelogsproxymodel.cpp \ - discovery/guhdiscovery.cpp + discovery/guhdiscovery.cpp \ + logmanager.cpp withavahi { DEFINES += WITH_AVAHI diff --git a/guh-control/jsonrpc/jsonrpcclient.cpp b/guh-control/jsonrpc/jsonrpcclient.cpp index 6b2652ae..183faa3c 100644 --- a/guh-control/jsonrpc/jsonrpcclient.cpp +++ b/guh-control/jsonrpc/jsonrpcclient.cpp @@ -69,8 +69,8 @@ void JsonRpcClient::sendCommand(const QString &method, QObject *caller, const QS void JsonRpcClient::setNotificationsEnabled(bool enabled) { QVariantMap params; - params.insert("notificationsEnabled", enabled); - JsonRpcReply *reply = createReply("JSONRPC.SetNotificationsEnabled", params, this, "setNotificationsEnabledResponse"); + params.insert("enabled", enabled); + JsonRpcReply *reply = createReply("JSONRPC.SetNotificationStatus", params, this, "setNotificationsEnabledResponse"); m_replies.insert(reply->commandId(), reply); sendRequest(reply->requestMap()); } @@ -239,6 +239,13 @@ void JsonRpcClient::dataReceived(const QByteArray &data) if (reply) { // qDebug() << QString("JsonRpc: got response for %1.%2: %3").arg(reply->nameSpace(), reply->method(), QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Indented))) << reply->callback() << reply->callback(); + if (dataMap.value("status").toString() == "unauthorized") { + qWarning() << "Something's off with the token"; + m_authenticationRequired = true; + m_token.clear(); + emit authenticationRequiredChanged(); + } + if (reply->caller() != nullptr && !reply->callback().isEmpty()) { QMetaObject::invokeMethod(reply->caller(), reply->callback().toLatin1().data(), Q_ARG(QVariantMap, dataMap)); } diff --git a/guh-control/logmanager.cpp b/guh-control/logmanager.cpp new file mode 100644 index 00000000..a7023d17 --- /dev/null +++ b/guh-control/logmanager.cpp @@ -0,0 +1,20 @@ +#include "logmanager.h" + +#include "engine.h" + +LogManager::LogManager(JsonRpcClient *jsonClient, QObject *parent) : + JsonHandler(parent), + m_client(jsonClient) +{ + m_client->registerNotificationHandler(this, "notificationReceived"); +} + +QString LogManager::nameSpace() const +{ + return "Logging"; +} + +void LogManager::notificationReceived(const QVariantMap &data) +{ + emit logEntryReceived(data.value("params").toMap().value("logEntry").toMap()); +} diff --git a/guh-control/logmanager.h b/guh-control/logmanager.h new file mode 100644 index 00000000..2b25ee7e --- /dev/null +++ b/guh-control/logmanager.h @@ -0,0 +1,28 @@ +#ifndef LOGMANAGER_H +#define LOGMANAGER_H + +#include + +#include "jsonrpc/jsonhandler.h" + +class JsonRpcClient; + +class LogManager : public JsonHandler +{ + Q_OBJECT +public: + explicit LogManager(JsonRpcClient *jsonClient, QObject *parent = nullptr); + + QString nameSpace() const override; + +signals: + void logEntryReceived(const QVariantMap &data); + +private: + Q_INVOKABLE void notificationReceived(const QVariantMap &data); + +private: + JsonRpcClient *m_client = nullptr; +}; + +#endif // LOGMANAGER_H diff --git a/guh-control/models/logsmodel.cpp b/guh-control/models/logsmodel.cpp index 8e8ca485..7dea1170 100644 --- a/guh-control/models/logsmodel.cpp +++ b/guh-control/models/logsmodel.cpp @@ -1,10 +1,11 @@ #include "logsmodel.h" #include "engine.h" +#include "logmanager.h" LogsModel::LogsModel(QObject *parent) : QAbstractListModel(parent) { - + connect(Engine::instance()->logManager(), &LogManager::logEntryReceived, this, &LogsModel::newLogEntryReceived); } bool LogsModel::busy() const @@ -19,16 +20,48 @@ int LogsModel::rowCount(const QModelIndex &parent) const QVariant LogsModel::data(const QModelIndex &index, int role) const { + switch (role) { + case RoleTimestamp: + return m_list.at(index.row())->timestamp(); + case RoleValue: + return m_list.at(index.row())->value(); + case RoleDeviceId: + return m_list.at(index.row())->deviceId(); + case RoleTypeId: + return m_list.at(index.row())->typeId(); + case RoleSource: + return m_list.at(index.row())->source(); + case RoleLoggingEventType: + return m_list.at(index.row())->loggingEventType(); + } return QVariant(); } QHash LogsModel::roleNames() const { QHash roles; + roles.insert(RoleTimestamp, "timestamp"); roles.insert(RoleValue, "value"); + roles.insert(RoleDeviceId, "deviceId"); + roles.insert(RoleTypeId, "typeId"); + roles.insert(RoleSource, "source"); + roles.insert(RoleLoggingEventType, "loggingEventType"); return roles; } +bool LogsModel::live() const +{ + return m_live; +} + +void LogsModel::setLive(bool live) +{ + if (m_live != live) { + m_live = live; + emit liveChanged(); + } +} + QString LogsModel::deviceId() const { return m_deviceId; @@ -89,6 +122,11 @@ LogEntry *LogsModel::get(int index) const return nullptr; } +void LogsModel::notificationReceived(const QVariantMap &data) +{ + qDebug() << "KLogModel notificatiion" << data; +} + void LogsModel::update() { m_busy = true; @@ -116,6 +154,7 @@ void LogsModel::update() void LogsModel::logsReply(const QVariantMap &data) { + qDebug() << "logs reply"; m_busy = false; emit busyChanged(); beginResetModel(); @@ -124,11 +163,43 @@ void LogsModel::logsReply(const QVariantMap &data) QList logEntries = data.value("params").toMap().value("logEntries").toList(); foreach (const QVariant &logEntryVariant, logEntries) { - LogEntry *entry = new LogEntry(QDateTime::fromMSecsSinceEpoch(logEntryVariant.toMap().value("timestamp").toLongLong()), logEntryVariant.toMap().value("value"), this); + QVariantMap entryMap = logEntryVariant.toMap(); + QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(entryMap.value("timestamp").toLongLong()); + QString deviceId = entryMap.value("deviceId").toString(); + QVariant value = entryMap.value("value"); + QString typeId = entryMap.value("typeId").toString(); + QMetaEnum sourceEnum = QMetaEnum::fromType(); + LogEntry::LoggingSource loggingSource = (LogEntry::LoggingSource)sourceEnum.keyToValue(entryMap.value("source").toByteArray()); + QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType(); + LogEntry::LoggingEventType loggingEventType = (LogEntry::LoggingEventType)loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()); + LogEntry *entry = new LogEntry(timeStamp, value, deviceId, typeId, loggingSource, loggingEventType, this); m_list.append(entry); - qDebug() << "Added log entry" << entry->dayString() << QDateTime::fromMSecsSinceEpoch(logEntryVariant.toMap().value("timestamp").toLongLong()).date().dayOfWeek(); + qDebug() << "Added log entry" << entry->dayString() << entry->value() << entry->deviceId() << entryMap << loggingEventType; } endResetModel(); emit countChanged(); } + +void LogsModel::newLogEntryReceived(const QVariantMap &data) +{ + if (!m_live) { + return; + } + + beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); + QVariantMap entryMap = data; + QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(entryMap.value("timestamp").toLongLong()); + QString deviceId = entryMap.value("deviceId").toString(); + QVariant value = entryMap.value("value"); + QString typeId = entryMap.value("typeId").toString(); + QMetaEnum sourceEnum = QMetaEnum::fromType(); + LogEntry::LoggingSource loggingSource = (LogEntry::LoggingSource)sourceEnum.keyToValue(entryMap.value("source").toByteArray()); + QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType(); + LogEntry::LoggingEventType loggingEventType = (LogEntry::LoggingEventType)loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()); + LogEntry *entry = new LogEntry(timeStamp, value, deviceId, typeId, loggingSource, loggingEventType, this); + m_list.append(entry); + qDebug() << "Added log entry" << entry->dayString() << entry->value() << entry->deviceId() << entryMap << loggingEventType; + endInsertRows(); + emit countChanged(); +} diff --git a/guh-control/models/logsmodel.h b/guh-control/models/logsmodel.h index e67bccea..3f4ed3ed 100644 --- a/guh-control/models/logsmodel.h +++ b/guh-control/models/logsmodel.h @@ -3,6 +3,7 @@ #include +#include "jsonrpc/jsonhandler.h" #include "types/logentry.h" class LogsModel : public QAbstractListModel @@ -15,9 +16,16 @@ class LogsModel : public QAbstractListModel Q_PROPERTY(QDateTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged) Q_PROPERTY(QDateTime endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged) + Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged) + public: enum Roles { - RoleValue + RoleTimestamp, + RoleValue, + RoleDeviceId, + RoleTypeId, + RoleSource, + RoleLoggingEventType }; explicit LogsModel(QObject *parent = nullptr); @@ -26,6 +34,9 @@ public: QVariant data(const QModelIndex &index, int role) const override; QHash roleNames() const override; + bool live() const; + void setLive(bool live); + QString deviceId() const; void setDeviceId(const QString &deviceId); @@ -40,8 +51,11 @@ public: Q_INVOKABLE LogEntry* get(int index) const; + Q_INVOKABLE void notificationReceived(const QVariantMap &data); + signals: void busyChanged(); + void liveChanged(); void countChanged(); void deviceIdChanged(); void typeIdChanged(); @@ -53,6 +67,7 @@ public slots: private slots: virtual void logsReply(const QVariantMap &data); + void newLogEntryReceived(const QVariantMap &data); protected: QList m_list; @@ -60,7 +75,9 @@ protected: QString m_typeId; QDateTime m_startTime = QDateTime::currentDateTime().addDays(-1); QDateTime m_endTime = QDateTime::currentDateTime(); + bool m_busy = false; + bool m_live = false; }; diff --git a/guh-control/models/rulesfiltermodel.cpp b/guh-control/models/rulesfiltermodel.cpp index c7ab5ff8..d9bbb603 100644 --- a/guh-control/models/rulesfiltermodel.cpp +++ b/guh-control/models/rulesfiltermodel.cpp @@ -4,6 +4,8 @@ #include "types/eventdescriptors.h" #include "types/eventdescriptor.h" #include "types/stateevaluator.h" +#include "types/ruleactions.h" +#include "types/ruleaction.h" #include @@ -27,16 +29,16 @@ void RulesFilterModel::setRules(Rules *rules) } } -QUuid RulesFilterModel::filterEventDeviceId() const +QUuid RulesFilterModel::filterDeviceId() const { - return m_filterEventDeviceId; + return m_filterDeviceId; } -void RulesFilterModel::setFilterEventDeviceId(const QUuid &filterEventDeviceId) +void RulesFilterModel::setFilterDeviceId(const QUuid &filterDeviceId) { - if (m_filterEventDeviceId != filterEventDeviceId) { - m_filterEventDeviceId = filterEventDeviceId; - emit filterEventDeviceIdChanged(); + if (m_filterDeviceId != filterDeviceId) { + m_filterDeviceId = filterDeviceId; + emit filterDeviceIdChanged(); invalidateFilter(); } } @@ -49,19 +51,29 @@ Rule *RulesFilterModel::get(int index) const bool RulesFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { Q_UNUSED(source_parent) - if (!m_filterEventDeviceId.isNull()) { + bool found = true; + if (!m_filterDeviceId.isNull()) { Rule* rule = m_rules->get(source_row); - bool found = false; + found = false; for (int i = 0; i < rule->eventDescriptors()->rowCount(); i++) { EventDescriptor *ed = rule->eventDescriptors()->get(i); - if (ed->deviceId() == m_filterEventDeviceId) { + if (ed->deviceId() == m_filterDeviceId) { found = true; break; } } - if (!found && !rule->stateEvaluator()->containsDevice(m_filterEventDeviceId)) { - return false; + if (!found && rule->stateEvaluator()->containsDevice(m_filterDeviceId)) { + found = true; + } + if (!found) { + for (int i = 0; i < rule->ruleActions()->rowCount(); i++) { + RuleAction *ra = rule->ruleActions()->get(i); + if (ra->deviceId() == m_filterDeviceId) { + found = true; + break; + } + } } } - return true; + return found; } diff --git a/guh-control/models/rulesfiltermodel.h b/guh-control/models/rulesfiltermodel.h index e9cdce52..5de1af8d 100644 --- a/guh-control/models/rulesfiltermodel.h +++ b/guh-control/models/rulesfiltermodel.h @@ -11,7 +11,7 @@ class RulesFilterModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(Rules* rules READ rules WRITE setRules NOTIFY rulesChanged) - Q_PROPERTY(QUuid filterEventDeviceId READ filterEventDeviceId WRITE setFilterEventDeviceId NOTIFY filterEventDeviceIdChanged) + Q_PROPERTY(QUuid filterDeviceId READ filterDeviceId WRITE setFilterDeviceId NOTIFY filterDeviceIdChanged) public: explicit RulesFilterModel(QObject *parent = nullptr); @@ -19,21 +19,21 @@ public: Rules* rules() const; void setRules(Rules* rules); - QUuid filterEventDeviceId() const; - void setFilterEventDeviceId(const QUuid &filterEventDeviceId); + QUuid filterDeviceId() const; + void setFilterDeviceId(const QUuid &filterDeviceId); Q_INVOKABLE Rule* get(int index) const; signals: void rulesChanged(); - void filterEventDeviceIdChanged(); + void filterDeviceIdChanged(); protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: Rules *m_rules = nullptr; - QUuid m_filterEventDeviceId; + QUuid m_filterDeviceId; }; #endif // RULESFILTERMODEL_H diff --git a/guh-control/models/valuelogsproxymodel.cpp b/guh-control/models/valuelogsproxymodel.cpp index 30dc657c..cd965f71 100644 --- a/guh-control/models/valuelogsproxymodel.cpp +++ b/guh-control/models/valuelogsproxymodel.cpp @@ -108,16 +108,15 @@ void ValueLogsProxyModel::logsReply(const QVariantMap &data) if (counter > 0) { avg = avg.toDouble() / counter; } else if (entries[i-1].count() > 0) { - avg = entries[i-1].last(); + avg = entries[i-1].last().toDouble(); } else if (m_list.count() > 0){ - avg = m_list.last()->value(); + avg = m_list.last()->value().toDouble(); } else { continue; } - LogEntry *entry = new LogEntry(startTime().addSecs(stepSize * i)/*.addSecs(stepSize * .5)*/, avg, this); + LogEntry *entry = new LogEntry(startTime().addSecs(stepSize * i)/*.addSecs(stepSize * .5)*/, avg, m_deviceId, QString(), LogEntry::LoggingSourceStates, LogEntry::LoggingEventTypeTrigger, this); m_list.append(entry); -// qDebug() << "**" << m_minimumValue << entry->value(); if (m_minimumValue.isNull() || entry->value() < m_minimumValue) { m_minimumValue = qRound(entry->value().toDouble()); } @@ -130,6 +129,13 @@ void ValueLogsProxyModel::logsReply(const QVariantMap &data) endResetModel(); + if (m_minimumValue.isNull()) { + m_minimumValue = 0; + } + if (m_maximumValue.isNull()) { + m_maximumValue = 0; + } + emit minimumValueChanged(); emit maximumValueChanged(); emit countChanged(); diff --git a/guh-control/resources.qrc b/guh-control/resources.qrc index 2af4a17b..3f21d68d 100644 --- a/guh-control/resources.qrc +++ b/guh-control/resources.qrc @@ -118,5 +118,8 @@ ui/magic/SelectEventDescriptorPage.qml ui/paramdelegates/DoubleParamDelegate.qml ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml + ui/system/LogViewerPage.qml + ui/images/next.svg + ui/images/go-down.svg diff --git a/guh-control/rulemanager.cpp b/guh-control/rulemanager.cpp index 6b990a3b..dece0786 100644 --- a/guh-control/rulemanager.cpp +++ b/guh-control/rulemanager.cpp @@ -49,13 +49,13 @@ Rule *RuleManager::createNewRule() void RuleManager::addRule(const QVariantMap params) { - m_jsonClient->sendCommand("Rules.AddRule", params, this, "addRuleReply"); + m_jsonClient->sendCommand("Rules.AddRule", params, this, "onAddRuleReply"); } void RuleManager::addRule(Rule *rule) { QVariantMap params = JsonTypes::packRule(rule); - m_jsonClient->sendCommand("Rules.AddRule", params, this, "addRuleReply"); + m_jsonClient->sendCommand("Rules.AddRule", params, this, "onAddRuleReply"); } void RuleManager::removeRule(const QUuid &ruleId) @@ -80,9 +80,11 @@ void RuleManager::handleRulesNotification(const QVariantMap ¶ms) QUuid ruleId = ruleMap.value("id").toUuid(); QString name = ruleMap.value("name").toString(); bool enabled = ruleMap.value("enabled").toBool(); + bool active = ruleMap.value("active").toBool(); Rule* rule = new Rule(ruleId, m_rules); rule->setName(name); rule->setEnabled(enabled); + rule->setActive(active); parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule); StateEvaluator* stateEvaluator = parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()); stateEvaluator->setParent(rule); @@ -131,9 +133,10 @@ void RuleManager::getRuleDetailsReply(const QVariantMap ¶ms) parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()); } -void RuleManager::addRuleReply(const QVariantMap ¶ms) +void RuleManager::onAddRuleReply(const QVariantMap ¶ms) { qDebug() << "Add rule reply" << params; + emit addRuleReply(params.value("params").toMap().value("ruleError").toString()); } void RuleManager::removeRuleReply(const QVariantMap ¶ms) diff --git a/guh-control/rulemanager.h b/guh-control/rulemanager.h index 93159886..a50a0946 100644 --- a/guh-control/rulemanager.h +++ b/guh-control/rulemanager.h @@ -35,7 +35,7 @@ private slots: void handleRulesNotification(const QVariantMap ¶ms); void getRulesReply(const QVariantMap ¶ms); void getRuleDetailsReply(const QVariantMap ¶ms); - void addRuleReply(const QVariantMap ¶ms); + void onAddRuleReply(const QVariantMap ¶ms); void removeRuleReply(const QVariantMap ¶ms); void onEditRuleReply(const QVariantMap ¶ms); @@ -45,6 +45,7 @@ private: void parseRuleActions(const QVariantList &ruleActions, Rule *rule); signals: + void addRuleReply(const QString &ruleError); void editRuleReply(const QString &ruleError); private: diff --git a/guh-control/ui/ConnectPage.qml b/guh-control/ui/ConnectPage.qml index 78fba0ba..ff1fdd6d 100644 --- a/guh-control/ui/ConnectPage.qml +++ b/guh-control/ui/ConnectPage.qml @@ -26,6 +26,9 @@ Page { certDialog.fingerprint = fingerprint certDialog.open(); } + onConnectionError: { + pageStack.pop(root) + } } ColumnLayout { diff --git a/guh-control/ui/MagicPage.qml b/guh-control/ui/MagicPage.qml index c813823b..f2ec9b95 100644 --- a/guh-control/ui/MagicPage.qml +++ b/guh-control/ui/MagicPage.qml @@ -1,5 +1,6 @@ import QtQuick 2.8 import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.2 import "components" import Guh 1.0 @@ -22,7 +23,14 @@ Page { Connections { target: Engine.ruleManager + onAddRuleReply: { + if (ruleError == "RuleErrorNoError") { + pageStack.pop(); + } + } + onEditRuleReply: { + print("have add rule reply") if (ruleError == "RuleErrorNoError") { pageStack.pop(); } @@ -36,7 +44,21 @@ Page { delegate: SwipeDelegate { id: ruleDelegate width: parent.width - text: model.name + + contentItem: RowLayout { + spacing: app.margins + ColorIcon { + height: app.iconSize + width: height + name: "../images/magic.svg" + color: !model.enabled ? "gray" : (model.active ? "red" : app.guhAccent) + } + + Label { + Layout.fillWidth: true + text: model.name + } + } onClicked: { var editRulePage = pageStack.push(Qt.resolvedUrl("magic/EditRulePage.qml"), {rule: Engine.ruleManager.rules.get(index) }) diff --git a/guh-control/ui/MainPage.qml b/guh-control/ui/MainPage.qml index f651d9eb..433b48a6 100644 --- a/guh-control/ui/MainPage.qml +++ b/guh-control/ui/MainPage.qml @@ -56,11 +56,12 @@ Page { id: swipeView Layout.fillWidth: true Layout.fillHeight: true + currentIndex: pageIndicator.currentIndex DevicesPage { width: parent.view.width height: parent.view.height - shownInterfaces: ["light", "weather", "sensor", "media"] + shownInterfaces: ["light", "weather", "sensor", "media", "garagegate"] } DevicesPage { @@ -97,13 +98,11 @@ Page { } PageIndicator { + id: pageIndicator Layout.alignment: Qt.AlignHCenter count: swipeView.count currentIndex: swipeView.currentIndex + interactive: true } } - - - - } diff --git a/guh-control/ui/NewDeviceWizard.qml b/guh-control/ui/NewDeviceWizard.qml index 5ba828e8..7de0ad47 100644 --- a/guh-control/ui/NewDeviceWizard.qml +++ b/guh-control/ui/NewDeviceWizard.qml @@ -344,7 +344,7 @@ Page { case 1: case 2: case 3: - Engine.deviceManager.pairDevice(d.deviceClass.id, d.deviceDescriptorId); + Engine.deviceManager.pairDevice(d.deviceClass.id, d.deviceDescriptorId, nameTextField.text); break; } diff --git a/guh-control/ui/SystemInfoPage.qml b/guh-control/ui/SystemInfoPage.qml index 6246a94c..e9157ccb 100644 --- a/guh-control/ui/SystemInfoPage.qml +++ b/guh-control/ui/SystemInfoPage.qml @@ -15,30 +15,52 @@ Page { ColumnLayout { anchors.fill: parent - anchors.margins: app.margins - Label { - Layout.fillWidth: true - text: "Connected to:" - color: Material.accent - } - - RowLayout { + ColumnLayout { Layout.fillWidth: true + Layout.margins: app.margins Label { Layout.fillWidth: true - text: Engine.connection.url + text: "Connected to:" + color: Material.accent } - Button { - text: "Disconnect" - onClicked: { - settings.lastConnectedHost = ""; - Engine.connection.disconnect(); + RowLayout { + Layout.fillWidth: true + + Label { + Layout.fillWidth: true + text: Engine.connection.url + } + Button { + text: "Disconnect" + onClicked: { + settings.lastConnectedHost = ""; + Engine.connection.disconnect(); + } } } } + ThinDivider {} + + ItemDelegate { + Layout.fillWidth: true + contentItem: RowLayout { + Label { + text: "Log viewer" + Layout.fillWidth: true + } + Image { + source: "images/next.svg" + Layout.preferredHeight: parent.height + Layout.preferredWidth: height + } + } + + onClicked: pageStack.push(Qt.resolvedUrl("system/LogViewerPage.qml")) + } + Item { Layout.fillWidth: true Layout.fillHeight: true diff --git a/guh-control/ui/components/Graph.qml b/guh-control/ui/components/Graph.qml index aabf06e4..43ae7566 100644 --- a/guh-control/ui/components/Graph.qml +++ b/guh-control/ui/components/Graph.qml @@ -40,11 +40,11 @@ Item { property int minTemp: { var lower = Math.floor(root.model.minimumValue - 2); var upper = Math.ceil(root.model.maximumValue + 2); - print("upper", upper, "lower", lower) - if (!lower || !upper) { + if (lower == undefined || upper == undefined) { return 0 } + print("upper", upper, "lower", lower) while ((upper - lower) % 10 != 0) { lower -= 1; if ((upper - lower) % 10 != 0) { @@ -57,7 +57,7 @@ Item { property int maxTemp: { var lower = Math.floor(root.model.minimumValue - 2); var upper = Math.ceil(root.model.maximumValue + 2); - if (!lower || !upper) { + if (lower == undefined || upper == undefined) { return 0 } while ((upper - lower) % 10 != 0) { diff --git a/guh-control/ui/components/HeaderButton.qml b/guh-control/ui/components/HeaderButton.qml index 464d1d82..74d46cdf 100644 --- a/guh-control/ui/components/HeaderButton.qml +++ b/guh-control/ui/components/HeaderButton.qml @@ -4,6 +4,7 @@ import QtQuick.Controls 2.1 ToolButton { property alias imageSource: image.name property alias color: image.color + property alias keyColor: image.keyColor contentItem: Item { height: 20 diff --git a/guh-control/ui/devicepages/GenericDevicePage.qml b/guh-control/ui/devicepages/GenericDevicePage.qml index c5e6c85a..97dfd9fe 100644 --- a/guh-control/ui/devicepages/GenericDevicePage.qml +++ b/guh-control/ui/devicepages/GenericDevicePage.qml @@ -98,7 +98,7 @@ DevicePageBase { property var actionType: deviceClass.actionTypes.get(index) property var actionValue: device.hasState(actionType.id) ? device.states.getState(actionType.id).value : null source: { - print("actiontyoe is", actionType.name, actionValue, actionType.paramTypes.count) + print("actiontype is", actionType.name, actionValue, actionType.paramTypes.count) for (var i = 0; i < actionType.paramTypes.count; i++) { print("have actionType param:", actionType.paramTypes.get(i).name, actionType.paramTypes.get(i).type) } diff --git a/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml b/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml index 894928f2..e2222bf9 100644 --- a/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml +++ b/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 2.1 import QtQuick.Layouts 1.1 import Guh 1.0 import "../components" +import "../paramdelegates" Page { id: root @@ -14,28 +15,123 @@ Page { text: "Details for " + root.device.name onBackPressed: pageStack.pop() } - ColumnLayout { - anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins } - spacing: app.margins + Flickable { + anchors.fill: parent + contentHeight: statesColumn.height + app.margins*2 - Repeater { - model: deviceClass.stateTypes - delegate: RowLayout { - width: parent.width - height: app.largeFont + ColumnLayout { + id: statesColumn + anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins } + spacing: app.margins - Label { - id: stateLabel - Layout.preferredWidth: parent.width / 2 - text: displayName - } + Repeater { + model: deviceClass.stateTypes + delegate: RowLayout { + width: parent.width + height: app.largeFont - Label { - id: valueLable - Layout.fillWidth: true - text: device.states.getState(id).value + " " + deviceClass.stateTypes.getStateType(id).unitString + property var stateType: deviceClass.stateTypes.get(index) + + Label { + id: stateLabel + Layout.preferredWidth: parent.width / 2 + text: displayName + } + + Loader { + id: placeHolder + Layout.fillWidth: true + sourceComponent: { + var writable = deviceClass.actionTypes.getActionType(id) !== null; + if (!writable) { + return labelComponent; + } + + switch (stateType.type) { + case "Bool": + return boolComponent; + case "Int": + case "Double": + if (stateType.minValue !== undefined && stateType.maxValue !== undefined) { + return sliderComponent; + } + return textFieldComponent; + case "String": + return textFieldComponent; + } + console.warn("DeviceStateDetailsPage: Type delegate not implemented", stateType.type) + return null; + } + } + + Binding { + target: placeHolder.item + when: placeHolder.item + property: "value" + value: device.states.getState(id).value + } +// Binding { +// target: placeHolder.item +// when: placeHolder.item +// property: "enabled" +// value: deviceClass.actionTypes.getActionType(id) !== null +// } + Binding { + target: placeHolder.item + when: placeHolder.item + property: "stateTypeId" + value: id + } + + // Label { + // id: valueLable + // Layout.fillWidth: true + // text: device.states.getState(id).value + " " + deviceClass.stateTypes.getStateType(id).unitString + // } } } } } + + + Component { + id: labelComponent + Label { + property var value: "" + property var stateTypeId: null + text: value + " " + deviceClass.stateTypes.getStateType(stateTypeId).unitString + horizontalAlignment: Text.AlignHCenter + } + } + + Component { + id: textFieldComponent + TextField { + property var value: "" + property var stateTypeId: null + text: value + onEditingFinished: { + executeAction(stateTypeId, text) + } + } + } + + Component { + id: boolComponent + Switch { + property var value: false + property var stateTypeId: null + checked: value + onClicked: executeAction(stateTypeId, checked) + } + } + + function executeAction(stateTypeId, value) { + var paramList = [] + var muteParam = {} + muteParam["paramTypeId"] = stateTypeId; + muteParam["value"] = value; + paramList.push(muteParam) + Engine.deviceManager.executeAction(root.device.id, stateTypeId, paramList) + } } diff --git a/guh-control/ui/images/go-down.svg b/guh-control/ui/images/go-down.svg new file mode 100644 index 00000000..d4931a09 --- /dev/null +++ b/guh-control/ui/images/go-down.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/guh-control/ui/images/next.svg b/guh-control/ui/images/next.svg new file mode 100644 index 00000000..6313833b --- /dev/null +++ b/guh-control/ui/images/next.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/guh-control/ui/magic/DeviceRulesPage.qml b/guh-control/ui/magic/DeviceRulesPage.qml index 1cfac54b..9bdbcddb 100644 --- a/guh-control/ui/magic/DeviceRulesPage.qml +++ b/guh-control/ui/magic/DeviceRulesPage.qml @@ -1,5 +1,6 @@ import QtQuick 2.8 import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.2 import "../components" import Guh 1.0 @@ -20,7 +21,32 @@ Page { } function addRule() { - pageStack.push(Qt.resolvedUrl("NewThingMagicPage.qml"), {device: root.device, text: "Add magic"}) +// pageStack.push(Qt.resolvedUrl("NewThingMagicPage.qml"), {device: root.device, text: "Add magic"}) + var rule = Engine.ruleManager.createNewRule(); + var page = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule}); + var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor(); + eventDescriptor.deviceId = device.id; + page.selectEventDescriptorData(eventDescriptor); + page.onAccept.connect(function() { + Engine.ruleManager.addRule(page.rule); + }) + + } + + Connections { + target: Engine.ruleManager + onAddRuleReply: { + if (ruleError == "RuleErrorNoError") { + pageStack.pop(); + } + } + + onEditRuleReply: { + print("have add rule reply") + if (ruleError == "RuleErrorNoError") { + pageStack.pop(); + } + } } ListView { @@ -30,11 +56,46 @@ Page { model: RulesFilterModel { id: rulesFilterModel rules: Engine.ruleManager.rules - filterEventDeviceId: root.device.id + filterDeviceId: root.device.id } - delegate: ItemDelegate { - text: model.name + delegate: SwipeDelegate { + width: parent.width + contentItem: RowLayout { + spacing: app.margins + ColorIcon { + height: app.iconSize + width: height + name: "../images/magic.svg" + color: !model.enabled ? "gray" : (model.active ? "red" : app.guhAccent) + } + + Label { + Layout.fillWidth: true + text: model.name + } + } + + onClicked: { + var editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rulesFilterModel.get(index) }) + editRulePage.onAccept.connect(function() { + Engine.ruleManager.editRule(editRulePage.rule); + }) + } + + swipe.right: Item { + height: ruleDelegate.height + width: height + anchors.right: parent.right + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/delete.svg" + color: "red" + } + SwipeDelegate.onClicked: Engine.ruleManager.removeRule(model.id) + } + } } diff --git a/guh-control/ui/magic/SelectEventDescriptorPage.qml b/guh-control/ui/magic/SelectEventDescriptorPage.qml index 9e2c0ce6..03499629 100644 --- a/guh-control/ui/magic/SelectEventDescriptorPage.qml +++ b/guh-control/ui/magic/SelectEventDescriptorPage.qml @@ -23,7 +23,7 @@ Page { id: header onBackPressed: root.backPressed(); - property bool interfacesMode: true + property bool interfacesMode: false onInterfacesModeChanged: root.buildInterface() HeaderButton { @@ -79,6 +79,7 @@ Page { model: actualModel delegate: ItemDelegate { + width: parent.width text: model.text onClicked: { if (header.interfacesMode) { diff --git a/guh-control/ui/magic/SelectRuleActionPage.qml b/guh-control/ui/magic/SelectRuleActionPage.qml index 82494d08..92eaaac0 100644 --- a/guh-control/ui/magic/SelectRuleActionPage.qml +++ b/guh-control/ui/magic/SelectRuleActionPage.qml @@ -23,7 +23,7 @@ Page { id: header onBackPressed: root.backPressed(); - property bool interfacesMode: true + property bool interfacesMode: false onInterfacesModeChanged: root.buildInterface() HeaderButton { @@ -88,6 +88,7 @@ Page { delegate: ItemDelegate { text: model.text + width: parent.width onClicked: { if (header.interfacesMode) { if (root.device) { diff --git a/guh-control/ui/magic/SelectRuleActionParamsPage.qml b/guh-control/ui/magic/SelectRuleActionParamsPage.qml index 43531505..a176fc70 100644 --- a/guh-control/ui/magic/SelectRuleActionParamsPage.qml +++ b/guh-control/ui/magic/SelectRuleActionParamsPage.qml @@ -27,6 +27,7 @@ Page { id: delegateRepeater model: root.actionType.paramTypes delegate: ParamDelegate { + width: parent.width paramType: root.actionType.paramTypes.get(index) value: paramType.defaultValue diff --git a/guh-control/ui/magic/SelectThingPage.qml b/guh-control/ui/magic/SelectThingPage.qml index 20514bc9..eefa5193 100644 --- a/guh-control/ui/magic/SelectThingPage.qml +++ b/guh-control/ui/magic/SelectThingPage.qml @@ -35,14 +35,17 @@ Page { id: supportedInterfacesModel ListElement { interfaceName: "battery"; name: "Battery powered devices" } ListElement { interfaceName: "temperatureSensor"; name: "Temperature sensors" } + ListElement { interfaceName: "light"; name: "Lights" } } ListView { Layout.fillWidth: true Layout.fillHeight: true model: thingButton.checked ? Engine.deviceManager.devices : supportedInterfacesModel + clip: true delegate: ItemDelegate { text: model.name + width: parent.width onClicked: { if (thingButton.checked) { root.thingSelected(Engine.deviceManager.devices.get(index)) diff --git a/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml b/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml index f8cb1a17..128f3899 100644 --- a/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml +++ b/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml @@ -5,13 +5,15 @@ import Guh 1.0 ItemDelegate { id: root + height: layout.height property var paramType: null property var value: null property int operatorType: ParamDescriptors.ValueOperatorEquals RowLayout { - anchors.fill: parent + id: layout + anchors { left: parent.left; top: parent.top; right: parent.right} anchors.margins: app.margins spacing: app.margins Label { @@ -42,13 +44,14 @@ ItemDelegate { case "is smaller": root.operatorType = ParamDescriptor.ValueOperatorLess; break; - case "is greater of equal": + case "is greater or equal": root.operatorType = ParamDescriptor.ValueOperatorGreaterOrEqual; break; case "is smaller or equal": root.operatorType = ParamDescriptor.ValueOperatorLessOrEqual; break; } + print("set operator to", root.operatorType, currentText) } } @@ -78,6 +81,9 @@ ItemDelegate { id: textFieldComponent TextField { text: "" + onTextChanged: { + root.value = text; + } } } diff --git a/guh-control/ui/system/LogViewerPage.qml b/guh-control/ui/system/LogViewerPage.qml new file mode 100644 index 00000000..8fabd65a --- /dev/null +++ b/guh-control/ui/system/LogViewerPage.qml @@ -0,0 +1,166 @@ +import QtQuick 2.8 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import Guh 1.0 +import "../components" + +Page { + id: root + header: GuhHeader { + text: "Log viewer" + onBackPressed: pageStack.pop() + + HeaderButton { + imageSource: "../images/go-down.svg" + color: root.autoScroll ? app.guhAccent : keyColor + onClicked: root.autoScroll = !root.autoScroll + } + } + + property bool autoScroll: true + + LogsModel { + id: logsModel + startTime: { + var date = new Date(); + date.setHours(new Date().getHours() - 1); + return date; + } + endTime: new Date() + live: true + Component.onCompleted: update() + onCountChanged: { + if (root.autoScroll) { + listView.positionViewAtEnd() + } + } + } + + BusyIndicator { + anchors.centerIn: listView + visible: logsModel.busy + } + + ListView { + id: listView + model: logsModel + anchors.fill: parent + clip: true + headerPositioning: ListView.OverlayHeader + + property int column0Width: root.width / 10 * 3 + property int column1Width: root.width / 10 * 1 + property int column2Width: root.width / 10 * 3 + property int column3Width: root.width / 10 * 2 + property int column4Width: root.width / 10 * 1 + + header: Rectangle { + width: parent.width + height: app.margins * 3 + color: "white" + z: 2 + + Row { + width: parent.width + anchors.verticalCenter: parent.verticalCenter + Label { + width: listView.column0Width + text: "Time" + } + Label { + text: "Type" + width: listView.column1Width + } + + Label { + width: listView.column2Width + text: "Device" + } + Label { + width: listView.column3Width + text: "Object" + } + Label { + width: listView.column4Width + text: "Value" + } + } + ThinDivider { + anchors { left: parent.left; bottom: parent.bottom; right: parent.right } + } + } + + delegate: Row { + id: delegate + property var device: Engine.deviceManager.devices.getDevice(model.deviceId) + property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null + Label { + width: listView.column0Width + text: Qt.formatDateTime(model.timestamp,"dd.MM.yy - hh:mm:ss") + elide: Text.ElideRight + } + Label { + width: listView.column1Width + text: { + switch (model.source) { + case LogEntry.LoggingSourceStates: + return "SC"; + case LogEntry.LoggingSourceSystem: + return "SYS"; + case LogEntry.LoggingSourceActions: + return "AE"; + case LogEntry.LoggingSourceEvents: + return "E"; + case LogEntry.LoggingSourceRules: + return "R"; + } + +// switch (model.loggingEventType) { +// case LogEntry.LoggingEventTypeTrigger: +// return "T"; +// case LogEntry.LoggingEventTypeExitActionsExecuted: +// return "A"; +// case LogEntry.LoggingEventTypeActiveChange: +// return "R"; +// case LogEntry.LoggingEventTypeExitActionsExecuted: +// return "EA"; +// case LogEntry.LoggingEventTypeEnabledChange: +// return "E"; +// } + return "N/A"; + } + } + + Label { + width: listView.column2Width + text: delegate.device.name + elide: Text.ElideRight + } + Label { + width: listView.column3Width + text : { + switch (model.source) { + case LogEntry.LoggingSourceStates: + return delegate.deviceClass.stateTypes.getStateType(model.typeId).displayName; + case LogEntry.LoggingSourceSystem: + return "SYS"; + case LogEntry.LoggingSourceActions: + return delegate.deviceClass.actionTypes.getActionType(model.typeId).displayName; + case LogEntry.LoggingSourceEvents: + return delegate.deviceClass.eventTypes.getEventType(model.typeId).displayName; + case LogEntry.LoggingSourceRules: + return Engine.ruleManager.rules.getRule(model.typeId).name; + } + return "N/A"; + } + elide: Text.ElideRight + } + Label { + width: listView.column4Width + text: model.value + elide: Text.ElideRight + } + } + } +} diff --git a/libguh-common/types/logentry.cpp b/libguh-common/types/logentry.cpp index b486a464..56078272 100644 --- a/libguh-common/types/logentry.cpp +++ b/libguh-common/types/logentry.cpp @@ -2,10 +2,14 @@ #include -LogEntry::LogEntry(const QDateTime ×tamp, const QVariant &value, QObject *parent): +LogEntry::LogEntry(const QDateTime ×tamp, const QVariant &value, const QString &deviceId, const QString &typeId, LoggingSource source, LoggingEventType loggingEventType, QObject *parent): QObject(parent), m_value(value), - m_timeStamp(timestamp) + m_timeStamp(timestamp), + m_deviceId(deviceId), + m_typeId(typeId), + m_source(source), + m_loggingEventType(loggingEventType) { } @@ -20,6 +24,26 @@ QDateTime LogEntry::timestamp() const return m_timeStamp; } +QString LogEntry::deviceId() const +{ + return m_deviceId; +} + +QString LogEntry::typeId() const +{ + return m_typeId; +} + +LogEntry::LoggingSource LogEntry::source() const +{ + return m_source; +} + +LogEntry::LoggingEventType LogEntry::loggingEventType() const +{ + return m_loggingEventType; +} + QString LogEntry::timeString() const { return m_timeStamp.time().toString("hh:mm"); diff --git a/libguh-common/types/logentry.h b/libguh-common/types/logentry.h index 3ae85a4a..3a6c2b4a 100644 --- a/libguh-common/types/logentry.h +++ b/libguh-common/types/logentry.h @@ -9,6 +9,10 @@ class LogEntry : public QObject { Q_OBJECT Q_PROPERTY(QVariant value READ value CONSTANT) + Q_PROPERTY(QString deviceId READ deviceId CONSTANT) + Q_PROPERTY(QString typeId READ typeId CONSTANT) + Q_PROPERTY(LoggingSource source READ source CONSTANT) + Q_PROPERTY(LoggingEventType loggingEventType READ loggingEventType CONSTANT) Q_PROPERTY(QDateTime timestamp READ timestamp CONSTANT) Q_PROPERTY(QString timeString READ timeString CONSTANT) @@ -16,10 +20,33 @@ class LogEntry : public QObject Q_PROPERTY(QString dateString READ dateString CONSTANT) public: - explicit LogEntry(const QDateTime ×tamp, const QVariant &value, QObject *parent = nullptr); + enum LoggingSource { + LoggingSourceSystem, + LoggingSourceEvents, + LoggingSourceActions, + LoggingSourceStates, + LoggingSourceRules + }; + Q_ENUM(LoggingSource) + Q_DECLARE_FLAGS(LoggingSources, LoggingSource) + + enum LoggingEventType { + LoggingEventTypeTrigger, + LoggingEventTypeActiveChange, + LoggingEventTypeEnabledChange, + LoggingEventTypeActionsExecuted, + LoggingEventTypeExitActionsExecuted + }; + Q_ENUM(LoggingEventType) + + explicit LogEntry(const QDateTime ×tamp, const QVariant &value, const QString &deviceId = QString(), const QString &typeId = QString(), LoggingSource source = LoggingSourceSystem, LoggingEventType loggingEventType = LoggingEventTypeTrigger, QObject *parent = nullptr); QVariant value() const; QDateTime timestamp() const; + QString deviceId() const; + QString typeId() const; + LoggingSource source() const; + LoggingEventType loggingEventType() const; QString timeString() const; QString dayString() const; @@ -28,6 +55,10 @@ public: private: QVariant m_value; QDateTime m_timeStamp; + QString m_deviceId; + QString m_typeId; + LoggingSource m_source; + LoggingEventType m_loggingEventType; }; #endif // LOGENTRY_H diff --git a/libguh-common/types/rule.cpp b/libguh-common/types/rule.cpp index bb9b828f..b43f2a27 100644 --- a/libguh-common/types/rule.cpp +++ b/libguh-common/types/rule.cpp @@ -48,6 +48,19 @@ void Rule::setEnabled(bool enabled) } } +bool Rule::active() const +{ + return m_active; +} + +void Rule::setActive(bool active) +{ + if (m_active != active) { + m_active = active; + emit activeChanged(); + } +} + EventDescriptors *Rule::eventDescriptors() const { return m_eventDescriptors; diff --git a/libguh-common/types/rule.h b/libguh-common/types/rule.h index 9bc84c4e..a71fbd88 100644 --- a/libguh-common/types/rule.h +++ b/libguh-common/types/rule.h @@ -14,6 +14,7 @@ class Rule : public QObject Q_PROPERTY(QUuid id READ id CONSTANT) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) + Q_PROPERTY(bool active READ active NOTIFY activeChanged) Q_PROPERTY(EventDescriptors* eventDescriptors READ eventDescriptors CONSTANT) Q_PROPERTY(StateEvaluator* stateEvaluator READ stateEvaluator CONSTANT) Q_PROPERTY(RuleActions* ruleActions READ ruleActions CONSTANT) @@ -28,6 +29,9 @@ public: bool enabled() const; void setEnabled(bool enabled); + bool active() const; + void setActive(bool active); + EventDescriptors* eventDescriptors() const; StateEvaluator *stateEvaluator() const; RuleActions* ruleActions() const; @@ -37,11 +41,13 @@ public: signals: void nameChanged(); void enabledChanged(); + void activeChanged(); private: QUuid m_id; QString m_name; bool m_enabled = false; + bool m_active = false; EventDescriptors *m_eventDescriptors = nullptr; StateEvaluator *m_stateEvaluator = nullptr; RuleActions *m_ruleActions = nullptr; diff --git a/libguh-common/types/rules.cpp b/libguh-common/types/rules.cpp index 75f291d7..6884abda 100644 --- a/libguh-common/types/rules.cpp +++ b/libguh-common/types/rules.cpp @@ -25,6 +25,10 @@ QVariant Rules::data(const QModelIndex &index, int role) const return m_list.at(index.row())->name(); case RoleId: return m_list.at(index.row())->id(); + case RoleEnabled: + return m_list.at(index.row())->enabled(); + case RoleActive: + return m_list.at(index.row())->active(); } return QVariant(); } @@ -34,6 +38,8 @@ QHash Rules::roleNames() const QHash roles; roles.insert(RoleName, "name"); roles.insert(RoleId, "id"); + roles.insert(RoleEnabled, "enabled"); + roles.insert(RoleActive, "active"); return roles; } diff --git a/libguh-common/types/rules.h b/libguh-common/types/rules.h index 98d58f7b..62347a15 100644 --- a/libguh-common/types/rules.h +++ b/libguh-common/types/rules.h @@ -11,7 +11,9 @@ class Rules : public QAbstractListModel public: enum Roles { RoleName, - RoleId + RoleId, + RoleEnabled, + RoleActive }; explicit Rules(QObject *parent = nullptr);