From 64b31e7626bf7307476d33931b126a5ee955baeb Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 18 Nov 2021 13:27:00 +0100 Subject: [PATCH] Add energy logs support --- libnymea-app/energy/energylogs.cpp | 123 +++++++++++++++++++++ libnymea-app/energy/energylogs.h | 69 ++++++++++++ libnymea-app/energy/energymanager.cpp | 13 ++- libnymea-app/energy/powerbalancelogs.cpp | 129 +++++++++++++++++++++++ libnymea-app/energy/powerbalancelogs.h | 82 ++++++++++++++ libnymea-app/libnymea-app-core.h | 5 + libnymea-app/libnymea-app.pri | 4 + libnymea-app/rulemanager.cpp | 1 - 8 files changed, 422 insertions(+), 4 deletions(-) create mode 100644 libnymea-app/energy/energylogs.cpp create mode 100644 libnymea-app/energy/energylogs.h create mode 100644 libnymea-app/energy/powerbalancelogs.cpp create mode 100644 libnymea-app/energy/powerbalancelogs.h diff --git a/libnymea-app/energy/energylogs.cpp b/libnymea-app/energy/energylogs.cpp new file mode 100644 index 00000000..8e98aa2c --- /dev/null +++ b/libnymea-app/energy/energylogs.cpp @@ -0,0 +1,123 @@ +#include "energylogs.h" +#include "powerbalancelogs.h" + +#include + +#include "logging.h" +NYMEA_LOGGING_CATEGORY(dcEnergyLogs, "EnergyLogs") + + +EnergyLogs::EnergyLogs(QObject *parent) : QObject(parent) +{ + m_powerBalanceLogs = new PowerBalanceLogs(this); +} + +Engine *EnergyLogs::engine() const +{ + return m_engine; +} + +void EnergyLogs::setEngine(Engine *engine) +{ + if (m_engine != engine) { + m_engine = engine; + emit engineChanged(); + + if (!m_engine) { + return; + } + qCDebug(dcEnergyLogs()) << "************* getting energylogs" << m_engine->jsonRpcClient()->experiences(); + if (m_engine->jsonRpcClient()->experiences().value("Energy").toString() >= "1.0") { + + QVariantMap params; + QMetaEnum metaEnum = QMetaEnum::fromType(); + params.insert("sampleRate", metaEnum.valueToKey(m_sampleRate)); + m_engine->jsonRpcClient()->registerNotificationHandler(this, "Energy", "notificationReceived"); + m_engine->jsonRpcClient()->sendCommand("Energy.GetPowerBalanceLogs", params, this, "powerBalanceLogsReceived"); +// m_engine->jsonRpcClient()->sendCommand("Energy.GetThingPowerLogs", params, this, "thingPowerLogsReceived"); + + } + } +} + +EnergyLogs::SampleRate EnergyLogs::sampleRate() const +{ + return m_sampleRate; +} + +void EnergyLogs::setSampleRate(SampleRate sampleRate) +{ + if (m_sampleRate != sampleRate) { + m_sampleRate = sampleRate; + emit sampleRateChanged(); + } +} + +bool EnergyLogs::fetchPowerBalance() const +{ + return m_fetchPowerBalance; +} + +void EnergyLogs::setFetchPowerBalance(bool fetchPowerBalance) +{ + if (m_fetchPowerBalance != fetchPowerBalance) { + m_fetchPowerBalance = fetchPowerBalance; + emit fetchPowerBalanceChanged(); + } +} + +QList EnergyLogs::thingIds() const +{ + return m_thingIds; +} + +void EnergyLogs::setThingIds(const QList &thingIds) +{ + if (m_thingIds != thingIds) { + m_thingIds = thingIds; + emit thingIdsChanged(); + } +} + +PowerBalanceLogs *EnergyLogs::powerBalanceLogs() const +{ + return m_powerBalanceLogs; +} + +void EnergyLogs::powerBalanceLogsReceived(int commandId, const QVariantMap ¶ms) +{ + Q_UNUSED(commandId) + foreach (const QVariant &variant, params.value("powerBalanceLogEntries").toList()) { + QVariantMap map = variant.toMap(); + QDateTime timestamp = QDateTime::fromSecsSinceEpoch(map.value("timestamp").toLongLong()); + double consumption = map.value("consumption").toDouble(); + double production = map.value("production").toDouble(); + double acquisition = map.value("acquisition").toDouble(); + double storage = map.value("storage").toDouble(); + PowerBalanceLogEntry *entry = new PowerBalanceLogEntry(timestamp, consumption, production, acquisition, storage, this); + m_powerBalanceLogs->addEntry(entry); + } +} + +void EnergyLogs::thingPowerLogsReceived(int commandId, const QVariantMap ¶ms) +{ + Q_UNUSED(commandId) + qCDebug(dcEnergyLogs) << "got energy logs"; +} + +void EnergyLogs::notificationReceived(const QVariantMap &data) +{ + QString notification = data.value("notification").toString(); + QVariantMap params = data.value("params").toMap(); + + if (notification == "Energy.PowerBalanceLogEntryAdded") { + QVariantMap map = data.value("powerBalanceLogEntry").toMap(); + QDateTime timestamp = QDateTime::fromSecsSinceEpoch(map.value("timestamp").toLongLong()); + double consumption = map.value("consumption").toDouble(); + double production = map.value("production").toDouble(); + double acquisition = map.value("acquisition").toDouble(); + double storage = map.value("storage").toDouble(); + PowerBalanceLogEntry *entry = new PowerBalanceLogEntry(timestamp, consumption, production, acquisition, storage, this); + m_powerBalanceLogs->addEntry(entry); + } +} diff --git a/libnymea-app/energy/energylogs.h b/libnymea-app/energy/energylogs.h new file mode 100644 index 00000000..51b2c2d4 --- /dev/null +++ b/libnymea-app/energy/energylogs.h @@ -0,0 +1,69 @@ +#ifndef ENERGYLOGS_H +#define ENERGYLOGS_H + +#include "engine.h" + +#include +#include + +class PowerBalanceLogs; + +class EnergyLogs : public QObject +{ + Q_OBJECT + Q_PROPERTY(Engine *engine READ engine WRITE setEngine NOTIFY engineChanged) + Q_PROPERTY(SampleRate sampleRate READ sampleRate WRITE setSampleRate NOTIFY sampleRateChanged) + Q_PROPERTY(bool fetchPowerBalance READ fetchPowerBalance WRITE setFetchPowerBalance NOTIFY fetchPowerBalanceChanged) + Q_PROPERTY(QList thingIds READ thingIds WRITE setThingIds NOTIFY thingIdsChanged) + + Q_PROPERTY(PowerBalanceLogs *powerBalanceLogs READ powerBalanceLogs CONSTANT) +public: + enum SampleRate { + SampleRate1Min = 1, + SampleRate15Mins = 15, + SampleRate1Hour = 60, + SampleRate3Hours = 180, + SampleRate1Day = 1440, + SampleRate1Week = 10080, + SampleRate1Month = 43200, + SampleRate1Year = 525600 + }; + Q_ENUM(SampleRate) + + explicit EnergyLogs(QObject *parent = nullptr); + + Engine *engine() const; + void setEngine(Engine *engine); + + SampleRate sampleRate() const; + void setSampleRate(SampleRate sampleRate); + + bool fetchPowerBalance() const; + void setFetchPowerBalance(bool fetchPowerBalance); + + QList thingIds() const; + void setThingIds(const QList &thingIds); + + PowerBalanceLogs *powerBalanceLogs() const; + +signals: + void engineChanged(); + void sampleRateChanged(); + void fetchPowerBalanceChanged(); + void thingIdsChanged(); + +private slots: + void powerBalanceLogsReceived(int commandId, const QVariantMap ¶ms); + void thingPowerLogsReceived(int commandId, const QVariantMap ¶ms); + void notificationReceived(const QVariantMap &data); + +private: + Engine *m_engine = nullptr; + SampleRate m_sampleRate = SampleRate15Mins; + bool m_fetchPowerBalance = true; + QList m_thingIds; + + PowerBalanceLogs *m_powerBalanceLogs = nullptr; +}; + +#endif // ENERGYLOGS_H diff --git a/libnymea-app/energy/energymanager.cpp b/libnymea-app/energy/energymanager.cpp index 3d8de270..5aaf49a8 100644 --- a/libnymea-app/energy/energymanager.cpp +++ b/libnymea-app/energy/energymanager.cpp @@ -73,18 +73,25 @@ double EnergyManager::currentPowerAcquisition() const void EnergyManager::notificationReceived(const QVariantMap &data) { - qCDebug(dcEnergyExperience()) << "Energy notification received" << data; QString notification = data.value("notification").toString(); QVariantMap params = data.value("params").toMap(); if (notification == "Energy.RootMeterChanged") { m_rootMeterId = params.value("rootMeterThingId").toUuid(); emit rootMeterIdChanged(); - } - if (notification == "Energy.PowerBalanceChanged") { + + } else if (notification == "Energy.PowerBalanceChanged") { m_currentPowerConsumption = params.value("currentPowerConsumption").toDouble(); m_currentPowerProduction = params.value("currentPowerProduction").toDouble(); m_currentPowerAcquisition = params.value("currentPowerAcquisition").toDouble(); emit powerBalanceChanged(); + + } else if (notification == "Energy.PowerBalanceLogEntryAdded") { + // Handled in EnergyLogs + } else if (notification == "Energy.ThingPowerLogEntryAdded") { + // Handled in EnergyLogs + + } else { + qCDebug(dcEnergyExperience()) << "Unhandled energy notification received" << data; } } diff --git a/libnymea-app/energy/powerbalancelogs.cpp b/libnymea-app/energy/powerbalancelogs.cpp new file mode 100644 index 00000000..926edf93 --- /dev/null +++ b/libnymea-app/energy/powerbalancelogs.cpp @@ -0,0 +1,129 @@ +#include "powerbalancelogs.h" + +PowerBalanceLogEntry::PowerBalanceLogEntry(const QDateTime ×tamp, double consumption, double production, double acquisition, double storage, QObject *parent): + QObject(parent), + m_timestamp(timestamp), + m_consumption(consumption), + m_production(production), + m_acquisition(acquisition), + m_storage(storage) +{ + +} + +QDateTime PowerBalanceLogEntry::timestamp() const +{ + return m_timestamp; +} + +double PowerBalanceLogEntry::consumption() const +{ + return m_consumption; +} + +double PowerBalanceLogEntry::production() const +{ + return m_production; +} + +double PowerBalanceLogEntry::acquisition() const +{ + return m_acquisition; +} + +double PowerBalanceLogEntry::storage() const +{ + return m_storage; +} + + +PowerBalanceLogs::PowerBalanceLogs(QObject *parent) : QAbstractListModel(parent) +{ + +} + +int PowerBalanceLogs::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_list.count(); +} + +QVariant PowerBalanceLogs::data(const QModelIndex &index, int role) const +{ + return QVariant(); +} + +QHash PowerBalanceLogs::roleNames() const +{ + QHash roles; + return roles; +} + +double PowerBalanceLogs::minValue() const +{ + return m_minValue; +} + +double PowerBalanceLogs::maxValue() const +{ + return m_maxValue; +} + +void PowerBalanceLogs::addEntry(PowerBalanceLogEntry *entry) +{ + entry->setParent(this); + beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); + m_list.append(entry); + endInsertRows(); + emit entryAdded(entry); + emit countChanged(); + + if (entry->consumption() < m_minValue) { + m_minValue = entry->consumption(); + emit minValueChanged(); + } + if (entry->consumption() > m_maxValue) { + m_maxValue = entry->consumption(); + emit maxValueChanged(); + } + + if (entry->production() < m_minValue) { + m_minValue = entry->production(); + emit minValueChanged(); + } + if (entry->production() > m_maxValue) { + m_maxValue = entry->production(); + emit maxValueChanged(); + } + if (entry->acquisition() < m_minValue) { + m_minValue = entry->acquisition(); + emit minValueChanged(); + } + if (entry->acquisition() > m_maxValue) { + m_maxValue = entry->acquisition(); + emit maxValueChanged(); + } + if (entry->storage() < m_minValue) { + m_minValue = entry->storage(); + emit minValueChanged(); + } + if (entry->storage() > m_maxValue) { + m_maxValue = entry->storage(); + emit maxValueChanged(); + } + +} + +PowerBalanceLogs *PowerBalanceLogsProxy::powerBalanceLogs() const +{ + return m_powerBalanceLogs; +} + +void PowerBalanceLogsProxy::setPowerBalanceLogs(PowerBalanceLogs *powerBalanceLogs) +{ + if (m_powerBalanceLogs != powerBalanceLogs) { + m_powerBalanceLogs = powerBalanceLogs; + setSourceModel(powerBalanceLogs); + emit powerBalanceLogsChanged(); + } +} diff --git a/libnymea-app/energy/powerbalancelogs.h b/libnymea-app/energy/powerbalancelogs.h new file mode 100644 index 00000000..8407303f --- /dev/null +++ b/libnymea-app/energy/powerbalancelogs.h @@ -0,0 +1,82 @@ +#ifndef POWERBALANCELOGS_H +#define POWERBALANCELOGS_H + +#include +#include +#include +#include + +class PowerBalanceLogEntry: public QObject +{ + Q_OBJECT + Q_PROPERTY(QDateTime timestamp READ timestamp CONSTANT) + Q_PROPERTY(double consumption READ consumption CONSTANT) + Q_PROPERTY(double production READ production CONSTANT) + Q_PROPERTY(double acquisition READ acquisition CONSTANT) + Q_PROPERTY(double storage READ storage CONSTANT) +public: + PowerBalanceLogEntry() = default; + PowerBalanceLogEntry(const QDateTime ×tamp, double consumption, double production, double acquisition, double storage, QObject *parent); + + QDateTime timestamp() const; + double consumption() const; + double production() const; + double acquisition() const; + double storage() const; +private: + QDateTime m_timestamp; + double m_consumption = 0; + double m_production = 0; + double m_acquisition = 0; + double m_storage = 0; +}; + +class PowerBalanceLogs : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + Q_PROPERTY(double minValue READ minValue NOTIFY minValueChanged) + Q_PROPERTY(double maxValue READ maxValue NOTIFY maxValueChanged) +public: + explicit PowerBalanceLogs(QObject *parent = nullptr); + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + double minValue() const; + double maxValue() const; + + void addEntry(PowerBalanceLogEntry *entry); +signals: + void countChanged(); + void entryAdded(PowerBalanceLogEntry *entry); + void minValueChanged(); + void maxValueChanged(); +private: + QList m_list; + double m_minValue = 0; + double m_maxValue = 0; +}; + + +class PowerBalanceLogsProxy: public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(PowerBalanceLogs* powerBalanceLogs READ powerBalanceLogs WRITE setPowerBalanceLogs NOTIFY powerBalanceLogsChanged) + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + + +public: + PowerBalanceLogsProxy(QObject *parent); + + PowerBalanceLogs *powerBalanceLogs() const; + void setPowerBalanceLogs(PowerBalanceLogs *powerBalanceLogs); + +signals: + void countChanged(); + void powerBalanceLogsChanged(); + +private: + PowerBalanceLogs *m_powerBalanceLogs = nullptr; +}; + +#endif // POWERBALANCELOGS_H diff --git a/libnymea-app/libnymea-app-core.h b/libnymea-app/libnymea-app-core.h index 118b0523..b078ee8d 100644 --- a/libnymea-app/libnymea-app-core.h +++ b/libnymea-app/libnymea-app-core.h @@ -136,6 +136,8 @@ #include "modbus/modbusrtumasters.h" #include "types/serialportsproxy.h" #include "energy/energymanager.h" +#include "energy/energylogs.h" +#include "energy/powerbalancelogs.h" #include @@ -359,6 +361,9 @@ void registerQmlTypes() { qmlRegisterType(uri, 1, 0, "AppData"); qmlRegisterType(uri, 1, 0, "EnergyManager"); + qmlRegisterType(uri, 1, 0, "EnergyLogs"); + qmlRegisterType(uri, 1, 0, "PowerBalanceLogs"); + qmlRegisterType(uri, 1, 0, "PowerBalanceLogEntry"); qmlRegisterType(uri, 1, 0, "SortFilterProxyModel"); } diff --git a/libnymea-app/libnymea-app.pri b/libnymea-app/libnymea-app.pri index 9c8461cf..ba3736b5 100644 --- a/libnymea-app/libnymea-app.pri +++ b/libnymea-app/libnymea-app.pri @@ -21,7 +21,9 @@ INCLUDEPATH += \ SOURCES += \ $$PWD/appdata.cpp \ + $$PWD/energy/energylogs.cpp \ $$PWD/energy/energymanager.cpp \ + $$PWD/energy/powerbalancelogs.cpp \ $$PWD/models/scriptsproxymodel.cpp \ $$PWD/tagwatcher.cpp \ $$PWD/zigbee/zigbeenode.cpp \ @@ -178,7 +180,9 @@ SOURCES += \ HEADERS += \ $$PWD/appdata.h \ + $$PWD/energy/energylogs.h \ $$PWD/energy/energymanager.h \ + $$PWD/energy/powerbalancelogs.h \ $$PWD/models/scriptsproxymodel.h \ $$PWD/tagwatcher.h \ $$PWD/zigbee/zigbeenode.h \ diff --git a/libnymea-app/rulemanager.cpp b/libnymea-app/rulemanager.cpp index 0a232a42..99eecee3 100644 --- a/libnymea-app/rulemanager.cpp +++ b/libnymea-app/rulemanager.cpp @@ -217,7 +217,6 @@ void RuleManager::removeRuleResponse(int commandId, const QVariantMap ¶ms) qCDebug(dcRuleManager) << "Have remove rule reply" << commandId << params; QMetaEnum metaEnum = QMetaEnum::fromType(); RuleError ruleError = static_cast(metaEnum.keyToValue(params.value("ruleError").toByteArray())); - qCritical() << "DAFUQQQ" << commandId << ruleError; emit removeRuleReply(commandId, ruleError); }