From 034f90d7a984acf0a86d85b9747bd85c2496ccdb Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 22 Nov 2021 00:43:36 +0100 Subject: [PATCH] Add totals to balance --- libnymea-energy/energylogs.cpp | 28 +++++++- libnymea-energy/energylogs.h | 16 ++++- libnymea-energy/energymanager.h | 4 ++ plugin/energyjsonhandler.cpp | 19 +++++- plugin/energylogger.cpp | 117 +++++++++++++++++++++++++------- plugin/energylogger.h | 14 +++- plugin/energymanagerimpl.cpp | 61 +++++++++++++++-- plugin/energymanagerimpl.h | 19 ++++-- 8 files changed, 239 insertions(+), 39 deletions(-) diff --git a/libnymea-energy/energylogs.cpp b/libnymea-energy/energylogs.cpp index 4483945..523078c 100644 --- a/libnymea-energy/energylogs.cpp +++ b/libnymea-energy/energylogs.cpp @@ -12,12 +12,16 @@ PowerBalanceLogEntry::PowerBalanceLogEntry() } -PowerBalanceLogEntry::PowerBalanceLogEntry(const QDateTime ×tamp, double consumption, double production, double acquisition, double storage): +PowerBalanceLogEntry::PowerBalanceLogEntry(const QDateTime ×tamp, double consumption, double production, double acquisition, double storage, double totalConsumption, double totalProduction, double totalAcquisition, double totalReturn): m_timestamp(timestamp), m_consumption(consumption), m_production(production), m_acquisition(acquisition), - m_storage(storage) + m_storage(storage), + m_totalConsumption(totalConsumption), + m_totalProduction(totalProduction), + m_totalAcquisition(totalAcquisition), + m_totalReturn(totalReturn) { } @@ -47,6 +51,26 @@ double PowerBalanceLogEntry::storage() const return m_storage; } +double PowerBalanceLogEntry::totalConsumption() const +{ + return m_totalConsumption; +} + +double PowerBalanceLogEntry::totalProduction() const +{ + return m_totalProduction; +} + +double PowerBalanceLogEntry::totalAcquisition() const +{ + return m_totalAcquisition; +} + +double PowerBalanceLogEntry::totalReturn() const +{ + return m_totalReturn; +} + QVariant PowerBalanceLogEntries::get(int index) const { return QVariant::fromValue(at(index)); diff --git a/libnymea-energy/energylogs.h b/libnymea-energy/energylogs.h index 9f92ae9..2881f2f 100644 --- a/libnymea-energy/energylogs.h +++ b/libnymea-energy/energylogs.h @@ -20,6 +20,7 @@ public: virtual ~EnergyLogs() = default; enum SampleRate { + SampleRateAny = 0, SampleRate1Min = 1, SampleRate15Mins = 15, SampleRate1Hour = 60, @@ -57,20 +58,33 @@ class PowerBalanceLogEntry Q_PROPERTY(double production READ production) Q_PROPERTY(double acquisition READ acquisition) Q_PROPERTY(double storage READ storage) + Q_PROPERTY(double totalConsumption READ totalConsumption) + Q_PROPERTY(double totalProduction READ totalProduction) + Q_PROPERTY(double totalAcquisition READ totalAcquisition) + Q_PROPERTY(double totalReturn READ totalReturn) public: PowerBalanceLogEntry(); - PowerBalanceLogEntry(const QDateTime ×tamp, double consumption, double production, double acquisition, double storage); + PowerBalanceLogEntry(const QDateTime ×tamp, double consumption, double production, double acquisition, double storage, double totalConsumption, double totalProduction, double totalAcquisition, double totalReturn); QDateTime timestamp() const; double consumption() const; double production() const; double acquisition() const; double storage() const; + double totalConsumption() const; + double totalProduction() const; + double totalAcquisition() const; + double totalReturn() const; + private: QDateTime m_timestamp; double m_consumption = 0; double m_production = 0; double m_acquisition = 0; double m_storage = 0; + double m_totalConsumption = 0; + double m_totalProduction = 0; + double m_totalAcquisition = 0; + double m_totalReturn = 0; }; Q_DECLARE_METATYPE(PowerBalanceLogEntry) diff --git a/libnymea-energy/energymanager.h b/libnymea-energy/energymanager.h index 8a560cd..2d18f5e 100644 --- a/libnymea-energy/energymanager.h +++ b/libnymea-energy/energymanager.h @@ -61,6 +61,10 @@ public: virtual double currentPowerProduction() const = 0; virtual double currentPowerAcquisition() const = 0; virtual double currentPowerStorage() const = 0; + virtual double totalConsumption() const = 0; + virtual double totalProduction() const = 0; + virtual double totalAcquisition() const = 0; + virtual double totalReturn() const = 0; virtual EnergyLogs* logs() const = 0; diff --git a/plugin/energyjsonhandler.cpp b/plugin/energyjsonhandler.cpp index 413ddb2..954e83b 100644 --- a/plugin/energyjsonhandler.cpp +++ b/plugin/energyjsonhandler.cpp @@ -33,6 +33,10 @@ EnergyJsonHandler::EnergyJsonHandler(EnergyManager *energyManager, QObject *pare returns.insert("currentPowerProduction", enumValueName(Double)); returns.insert("currentPowerAcquisition", enumValueName(Double)); returns.insert("currentPowerStorage", enumValueName(Double)); + returns.insert("totalConsumption", enumValueName(Double)); + returns.insert("totalProduction", enumValueName(Double)); + returns.insert("totalAcquisition", enumValueName(Double)); + returns.insert("totalReturn", enumValueName(Double)); registerMethod("GetPowerBalance", description, params, returns); params.clear(); returns.clear(); @@ -67,6 +71,10 @@ EnergyJsonHandler::EnergyJsonHandler(EnergyManager *energyManager, QObject *pare params.insert("currentPowerProduction", enumValueName(Double)); params.insert("currentPowerAcquisition", enumValueName(Double)); params.insert("currentPowerStorage", enumValueName(Double)); + params.insert("totalConsumption", enumValueName(Double)); + params.insert("totalProduction", enumValueName(Double)); + params.insert("totalAcquisition", enumValueName(Double)); + params.insert("totalReturn", enumValueName(Double)); registerNotification("PowerBalanceChanged", description, params); params.clear(); @@ -95,6 +103,10 @@ EnergyJsonHandler::EnergyJsonHandler(EnergyManager *energyManager, QObject *pare params.insert("currentPowerProduction", m_energyManager->currentPowerProduction()); params.insert("currentPowerAcquisition", m_energyManager->currentPowerAcquisition()); params.insert("currentPowerStorage", m_energyManager->currentPowerStorage()); + params.insert("totalConsumption", m_energyManager->totalConsumption()); + params.insert("totalProduction", m_energyManager->totalProduction()); + params.insert("totalAcquisition", m_energyManager->totalAcquisition()); + params.insert("totalReturn", m_energyManager->totalReturn()); emit PowerBalanceChanged(params); }); @@ -149,16 +161,17 @@ JsonReply *EnergyJsonHandler::GetPowerBalance(const QVariantMap ¶ms) ret.insert("currentPowerProduction", m_energyManager->currentPowerProduction()); ret.insert("currentPowerAcquisition", m_energyManager->currentPowerAcquisition()); ret.insert("currentPowerStorage", m_energyManager->currentPowerStorage()); + ret.insert("totalConsumption", m_energyManager->totalConsumption()); + ret.insert("totalProduction", m_energyManager->totalProduction()); + ret.insert("totalAcquisition", m_energyManager->totalAcquisition()); + ret.insert("totalReturn", m_energyManager->totalReturn()); return createReply(ret); } JsonReply *EnergyJsonHandler::GetPowerBalanceLogs(const QVariantMap ¶ms) { - qCDebug(dcEnergyExperience()) << "params" << params; - qCDebug(dcEnergyExperience()) << "from" << params.value("from"); EnergyLogs::SampleRate sampleRate = enumNameToValue(params.value("sampleRate").toString()); QDateTime from = params.contains("from") ? QDateTime::fromMSecsSinceEpoch(params.value("from").toLongLong() * 1000) : QDateTime(); - qCDebug(dcEnergyExperience()) << "from2" << from; QDateTime to = params.contains("to") ? QDateTime::fromMSecsSinceEpoch(params.value("to").toLongLong() * 1000) : QDateTime(); QVariantMap returns; returns.insert("powerBalanceLogEntries", pack(m_energyManager->logs()->powerBalanceLogs(sampleRate, from, to))); diff --git a/plugin/energylogger.cpp b/plugin/energylogger.cpp index 6ff2ef2..876ac8e 100644 --- a/plugin/energylogger.cpp +++ b/plugin/energylogger.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,6 @@ EnergyLogger::EnergyLogger(QObject *parent) : EnergyLogs(parent) } // Start the scheduling - scheduleNextSample(SampleRate1Min); foreach (SampleRate sampleRate, m_configs.keys()) { scheduleNextSample(sampleRate); @@ -71,9 +71,9 @@ EnergyLogger::EnergyLogger(QObject *parent) : EnergyLogs(parent) m_sampleTimer.start(1000); } -void EnergyLogger::logPowerBalance(double consumption, double production, double acquisition, double storage) +void EnergyLogger::logPowerBalance(double consumption, double production, double acquisition, double storage, double totalConsumption, double totalProduction, double totalAcquisition, double totalReturn) { - PowerBalanceLogEntry entry(QDateTime::currentDateTime(), consumption, production, acquisition, storage); + PowerBalanceLogEntry entry(QDateTime::currentDateTime(), consumption, production, acquisition, storage, totalConsumption, totalProduction, totalAcquisition, totalReturn); // Add everything to livelog, keep that for one day, in memory only m_balanceLiveLog.prepend(entry); @@ -124,8 +124,8 @@ PowerBalanceLogEntries EnergyLogger::powerBalanceLogs(SampleRate sampleRate, con } while (query.next()) { - qCDebug(dcEnergyExperience()) << "Adding result"; - result.append(PowerBalanceLogEntry(QDateTime::fromMSecsSinceEpoch(query.value("timestamp").toLongLong()), query.value("consumption").toDouble(), query.value("production").toDouble(), query.value("acquisition").toDouble(), query.value("storage").toDouble())); +// qCDebug(dcEnergyExperience()) << "Adding result"; + result.append(queryResultToBalanceLogEntry(query.record())); } return result; } @@ -178,6 +178,33 @@ ThingPowerLogEntries EnergyLogger::thingPowerLogs(SampleRate sampleRate, const Q } +PowerBalanceLogEntry EnergyLogger::latestLogEntry(SampleRate sampleRate) +{ + QSqlQuery query(m_db); + QString queryString = "SELECT MAX(timestamp), consumption, production, acquisition, storage, totalConsumption, totalProduction, totalAcquisition, totalReturn FROM powerBalance"; + QVariantList bindValues; + if (sampleRate != SampleRateAny) { + queryString += " WHERE sampleRate = ?"; + bindValues.append(sampleRate); + } + queryString += ";"; + query.prepare(queryString); + foreach (const QVariant &value, bindValues) { + query.addBindValue(value); + } + query.exec(); + if (query.lastError().isValid()) { + qCWarning(dcEnergyExperience()) << "Error obtaining latest log entry from DB:" << query.lastError() << query.executedQuery(); + return PowerBalanceLogEntry(); + } + if (!query.next()) { + qCDebug(dcEnergyExperience()) << "No power balance log entry in DB for sample rate:" << sampleRate; + return PowerBalanceLogEntry(); + } + qCDebug(dcEnergyExperience()) << "Loaded latest log entry:" << query.record(); + return queryResultToBalanceLogEntry(query.record()); +} + void EnergyLogger::sample() { QDateTime now = QDateTime::currentDateTime(); @@ -210,8 +237,19 @@ void EnergyLogger::sample() medianProduction /= sampleStart.msecsTo(sampleEnd); medianAcquisition /= sampleStart.msecsTo(sampleEnd); medianStorage /= sampleStart.msecsTo(sampleEnd); + + PowerBalanceLogEntry newest = m_balanceLiveLog.count() > 0 ? m_balanceLiveLog.at(0) : PowerBalanceLogEntry(); + double totalConsumption = newest.totalConsumption(); + double totalProduction = newest.totalProduction(); + double totalAcquisition = newest.totalAcquisition(); + double totalReturn = newest.totalReturn(); + qCDebug(dcEnergyExperience()) << "Power balance for sample:" << medianConsumption << medianProduction << medianAcquisition << medianStorage << "duration:" << sampleStart.msecsTo(sampleEnd); - insertPowerBalance(sampleEnd, SampleRate1Min, medianConsumption, medianProduction, medianAcquisition, medianStorage); + insertPowerBalance(sampleEnd, SampleRate1Min, medianConsumption, medianProduction, medianAcquisition, medianStorage, totalConsumption, totalProduction, totalAcquisition, totalReturn); + m_lastSampleTotalConsumption = totalConsumption; + m_lastSampleTotalProducation = totalProduction; + m_lastSampleTotalAcquisition = totalAcquisition; + m_lastSampleTotalReturn = totalReturn; foreach (const ThingId &thingId, m_thingsPowerLiveLogs.keys()) { medianConsumption = 0; @@ -307,7 +345,11 @@ bool EnergyLogger::initDB() "consumption FLOAT," "production FLOAT," "acquisition FLOAT," - "storage FLOAT" + "storage FLOAT," + "totalConsumption FLOAT," + "totalProduction FLOAT," + "totalAcquisition FLOAT," + "totalReturn FLOAT" ");"); if (m_db.lastError().isValid()) { @@ -333,7 +375,7 @@ bool EnergyLogger::initDB() } } - qCDebug(dcEnergyExperience()) << "Initialized logging DB successfully."; + qCDebug(dcEnergyExperience()) << "Initialized logging DB successfully." << m_db.databaseName(); return true; } @@ -412,16 +454,16 @@ void EnergyLogger::rectifySamples(SampleRate sampleRate, SampleRate baseSampleRa QDateTime newestSample = getNewestPowerBalanceSampleTimestamp(sampleRate); qCDebug(dcEnergyExperience()) << "Checking for missing samples for" << sampleRate; - qCDebug(dcEnergyExperience()) << "Newest sample:" << newestSample.toString() << "Oldest base sample:" << oldestBaseSample.toString(); +// qCDebug(dcEnergyExperience()) << "Newest sample:" << newestSample.toString() << "Oldest base sample:" << oldestBaseSample.toString(); if (newestSample.isNull()) { - qCDebug(dcEnergyExperience()) << "No sample at all so far. Using base as starting point."; +// qCDebug(dcEnergyExperience()) << "No sample at all so far. Using base as starting point."; newestSample = oldestBaseSample; } - qCDebug(dcEnergyExperience()) << "next sample after last in series:" << nextSampleTimestamp(sampleRate, newestSample).toString(); - qCDebug(dcEnergyExperience()) << "next scheduled sample:" << m_nextSamples.value(sampleRate).toString(); +// qCDebug(dcEnergyExperience()) << "next sample after last in series:" << nextSampleTimestamp(sampleRate, newestSample).toString(); +// qCDebug(dcEnergyExperience()) << "next scheduled sample:" << m_nextSamples.value(sampleRate).toString(); while (!newestSample.isNull() && nextSampleTimestamp(sampleRate, newestSample) < m_nextSamples[sampleRate]) { QDateTime nextSample = nextSampleTimestamp(sampleRate, newestSample.addMSecs(1000)); - qCDebug(dcEnergyExperience()) << "Rectifying missed sample for" << sampleRate << "from" << nextSample.toString(); +// qCDebug(dcEnergyExperience()) << "Rectifying missed sample for" << sampleRate << "from" << nextSample.toString(); samplePowerBalance(sampleRate, baseSampleRate, nextSample); newestSample = nextSample; } @@ -430,17 +472,17 @@ void EnergyLogger::rectifySamples(SampleRate sampleRate, SampleRate baseSampleRa QDateTime oldestBaseSample = getOldestThingPowerSampleTimestamp(thingId, baseSampleRate); QDateTime newestSample = getNewestThingPowerSampleTimestamp(thingId, sampleRate); - qCDebug(dcEnergyExperience()) << "T Checking for missing samples for" << sampleRate; - qCDebug(dcEnergyExperience()) << "T Newest sample:" << newestSample.toString() << "Oldest base sample:" << oldestBaseSample.toString(); +// qCDebug(dcEnergyExperience()) << "T Checking for missing samples for" << sampleRate; +// qCDebug(dcEnergyExperience()) << "T Newest sample:" << newestSample.toString() << "Oldest base sample:" << oldestBaseSample.toString(); if (newestSample.isNull()) { - qCDebug(dcEnergyExperience()) << "T No sample at all so far. Using base as starting point."; +// qCDebug(dcEnergyExperience()) << "T No sample at all so far. Using base as starting point."; newestSample = oldestBaseSample; } - qCDebug(dcEnergyExperience()) << "T next sample after last in series:" << nextSampleTimestamp(sampleRate, newestSample).toString(); - qCDebug(dcEnergyExperience()) << "T next scheduled sample:" << m_nextSamples.value(sampleRate).toString(); +// qCDebug(dcEnergyExperience()) << "T next sample after last in series:" << nextSampleTimestamp(sampleRate, newestSample).toString(); +// qCDebug(dcEnergyExperience()) << "T next scheduled sample:" << m_nextSamples.value(sampleRate).toString(); while (!newestSample.isNull() && nextSampleTimestamp(sampleRate, newestSample) < m_nextSamples[sampleRate]) { QDateTime nextSample = nextSampleTimestamp(sampleRate, newestSample.addMSecs(1000)); - qCDebug(dcEnergyExperience()) << "T Rectifying missed sample for" << sampleRate << "from" << nextSample.toString(); +// qCDebug(dcEnergyExperience()) << "T Rectifying missed sample for" << sampleRate << "from" << nextSample.toString(); sampleThingPower(thingId, sampleRate, baseSampleRate, nextSample); newestSample = nextSample; } @@ -453,6 +495,9 @@ QDateTime EnergyLogger::nextSampleTimestamp(SampleRate sampleRate, const QDateTi QDate date = dateTime.date(); QDateTime next; switch (sampleRate) { + case SampleRateAny: + qCWarning(dcEnergyExperience()) << "Cannot calculate next sample timestamp without a sample rate"; + return QDateTime(); case SampleRate1Min: time.setHMS(time.hour(), time.minute(), 0); next = QDateTime(date, time).addMSecs(60 * 1000); @@ -512,12 +557,20 @@ bool EnergyLogger::samplePowerBalance(SampleRate sampleRate, SampleRate baseSamp double medianProduction = 0; double medianAcquisition = 0; double medianStorage = 0; + double totalConsumption = 0; + double totalProduction = 0; + double totalAcquisition = 0; + double totalReturn = 0; while (query.next()) { qCDebug(dcEnergyExperience()) << "Frame:" << query.value("consumption").toDouble() << query.value("production").toDouble() << query.value("acquisition").toDouble() << QDateTime::fromMSecsSinceEpoch(query.value("timestamp").toLongLong()).toString(); medianConsumption += query.value("consumption").toDouble(); medianProduction += query.value("production").toDouble(); medianAcquisition += query.value("acquisition").toDouble(); medianStorage += query.value("storage").toDouble(); + totalConsumption = query.value("totalConsumption").toDouble(); + totalProduction = query.value("totalProduction").toDouble(); + totalAcquisition = query.value("totalAcquisition").toDouble(); + totalReturn = query.value("totalReturn").toDouble(); } qCDebug(dcEnergyExperience()) << "Totals:" << medianConsumption << medianProduction << medianAcquisition << medianStorage << "base samplerate" << baseSampleRate << "samplerate:" << sampleRate; medianConsumption = medianConsumption * baseSampleRate / sampleRate; @@ -526,25 +579,29 @@ bool EnergyLogger::samplePowerBalance(SampleRate sampleRate, SampleRate baseSamp medianStorage = medianStorage * baseSampleRate / sampleRate; qCDebug(dcEnergyExperience()) << "Sampled:" << medianConsumption << medianProduction << medianAcquisition << medianStorage; - return insertPowerBalance(sampleEnd, sampleRate, medianConsumption, medianProduction, medianAcquisition, medianStorage); + return insertPowerBalance(sampleEnd, sampleRate, medianConsumption, medianProduction, medianAcquisition, medianStorage, totalConsumption, totalProduction, totalAcquisition, totalReturn); } -bool EnergyLogger::insertPowerBalance(const QDateTime ×tamp, SampleRate sampleRate, double consumption, double production, double acquisition, double storage) +bool EnergyLogger::insertPowerBalance(const QDateTime ×tamp, SampleRate sampleRate, double consumption, double production, double acquisition, double storage, double totalConsumption, double totalProduction, double totalAcquisition, double totalReturn) { QSqlQuery query = QSqlQuery(m_db); - query.prepare("INSERT INTO powerBalance (timestamp, sampleRate, consumption, production, acquisition, storage) values (?, ?, ?, ?, ?, ?);"); + query.prepare("INSERT INTO powerBalance (timestamp, sampleRate, consumption, production, acquisition, storage, totalConsumption, totalProduction, totalAcquisition, totalReturn) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); query.addBindValue(timestamp.toMSecsSinceEpoch()); query.addBindValue(sampleRate); query.addBindValue(consumption); query.addBindValue(production); query.addBindValue(acquisition); query.addBindValue(storage); + query.addBindValue(totalConsumption); + query.addBindValue(totalProduction); + query.addBindValue(totalAcquisition); + query.addBindValue(totalReturn); query.exec(); if (query.lastError().isValid()) { qCWarning(dcEnergyExperience()) << "Error logging consumption sample:" << query.lastError(); return false; } - emit powerBalanceEntryAdded(sampleRate, PowerBalanceLogEntry(timestamp, consumption, production, acquisition, storage)); + emit powerBalanceEntryAdded(sampleRate, PowerBalanceLogEntry(timestamp, consumption, production, acquisition, storage, totalConsumption, totalProduction, totalAcquisition, totalReturn)); return true; } @@ -635,3 +692,17 @@ void EnergyLogger::trimThingPower(const ThingId &thingId, SampleRate sampleRate, qCDebug(dcEnergyExperience()).nospace() << "Trimmed " << query.numRowsAffected() << " from thing power series for: " << thingId << sampleRate << " (Older than: " << beforeTime.toString() << ")"; } } + +PowerBalanceLogEntry EnergyLogger::queryResultToBalanceLogEntry(const QSqlRecord &record) const +{ + return PowerBalanceLogEntry(QDateTime::fromMSecsSinceEpoch(record.value("timestamp").toLongLong()), + record.value("consumption").toDouble(), + record.value("production").toDouble(), + record.value("acquisition").toDouble(), + record.value("storage").toDouble(), + record.value("totalConsumption").toDouble(), + record.value("totalProduction").toDouble(), + record.value("totalAcquisition").toDouble(), + record.value("totalReturn").toDouble()); + +} diff --git a/plugin/energylogger.h b/plugin/energylogger.h index 8832b15..fed393f 100644 --- a/plugin/energylogger.h +++ b/plugin/energylogger.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,12 +18,14 @@ class EnergyLogger : public EnergyLogs public: explicit EnergyLogger(QObject *parent = nullptr); - void logPowerBalance(double consumption, double production, double acquisition, double storage); + void logPowerBalance(double consumption, double production, double acquisition, double storage, double totalConsumption, double totalProduction, double totalAcquisition, double totalReturn); void logThingPower(const ThingId &thingId, double currentPower, double totalConsumption, double totalProduction); PowerBalanceLogEntries powerBalanceLogs(SampleRate sampleRate, const QDateTime &from = QDateTime(), const QDateTime &to = QDateTime()) const override; ThingPowerLogEntries thingPowerLogs(SampleRate sampleRate, const QList &thingIds, const QDateTime &from = QDateTime(), const QDateTime &to = QDateTime()) const override; + PowerBalanceLogEntry latestLogEntry(SampleRate sampleRate); + private slots: void sample(); @@ -40,13 +43,15 @@ private: void rectifySamples(SampleRate sampleRate, EnergyLogger::SampleRate baseSampleRate); bool samplePowerBalance(SampleRate sampleRate, SampleRate baseSampleRate, const QDateTime &sampleEnd); - bool insertPowerBalance(const QDateTime ×tamp, SampleRate sampleRate, double consumption, double production, double acquisition, double storage); + bool insertPowerBalance(const QDateTime ×tamp, SampleRate sampleRate, double consumption, double production, double acquisition, double storage, double totalConsumption, double totalProduction, double totalAcquisition, double totalReturn); bool sampleThingsPower(SampleRate sampleRate, SampleRate baseSampleRate, const QDateTime &sampleEnd); bool sampleThingPower(const ThingId &thingId, SampleRate sampleRate, SampleRate baseSampleRate, const QDateTime &sampleEnd); bool insertThingPower(const QDateTime ×tamp, SampleRate sampleRate, const ThingId &thingId, double currentPower, double totalConsumption, double totalProduction); void trimPowerBalance(SampleRate sampleRate, const QDateTime &beforeTime); void trimThingPower(const ThingId &thingId, SampleRate sampleRate, const QDateTime &beforeTime); + PowerBalanceLogEntry queryResultToBalanceLogEntry(const QSqlRecord &record) const; + private: struct SampleConfig { SampleRate baseSampleRate; @@ -59,6 +64,11 @@ private: QTimer m_sampleTimer; QHash m_nextSamples; + double m_lastSampleTotalConsumption = 0; + double m_lastSampleTotalProducation = 0; + double m_lastSampleTotalAcquisition = 0; + double m_lastSampleTotalReturn = 0; + QSqlDatabase m_db; int m_maxMinuteSamples = 0; diff --git a/plugin/energymanagerimpl.cpp b/plugin/energymanagerimpl.cpp index 7b87807..3444ea7 100644 --- a/plugin/energymanagerimpl.cpp +++ b/plugin/energymanagerimpl.cpp @@ -24,6 +24,13 @@ EnergyManagerImpl::EnergyManagerImpl(ThingManager *thingManager, QObject *parent EnergyManagerImpl::setRootMeter(rootMeterThingId); qCDebug(dcEnergyExperience()) << "Loaded root meter" << rootMeterThingId; + PowerBalanceLogEntry latestEntry = m_logger->latestLogEntry(EnergyLogs::SampleRateAny); + m_totalConsumption = latestEntry.totalConsumption(); + m_totalProduction = latestEntry.totalProduction(); + m_totalAcquisition = latestEntry.totalAcquisition(); + m_totalReturn = latestEntry.totalReturn(); + qCDebug(dcEnergyExperience()) << "Loader power balance totals. Consumption:" << m_totalConsumption << "Production:" << m_totalProduction << "Acquisition:" << m_totalAcquisition << "Return:" << m_totalReturn; + foreach (Thing *thing, m_thingManager->configuredThings()) { watchThing(thing); } @@ -75,6 +82,26 @@ double EnergyManagerImpl::currentPowerStorage() const return m_currentPowerStorage; } +double EnergyManagerImpl::totalConsumption() const +{ + return m_totalConsumption; +} + +double EnergyManagerImpl::totalProduction() const +{ + return m_totalProduction; +} + +double EnergyManagerImpl::totalAcquisition() const +{ + return m_totalAcquisition; +} + +double EnergyManagerImpl::totalReturn() const +{ + return m_totalReturn; +} + EnergyLogs *EnergyManagerImpl::logs() const { return m_logger; @@ -106,6 +133,10 @@ void EnergyManagerImpl::watchThing(Thing *thing) || thing->thingClass().interfaces().contains("smartmeterconsumer") || thing->thingClass().interfaces().contains("smartmeterproducer") || thing->thingClass().interfaces().contains("energystorage")) { + + m_totalEnergyConsumedCache[thing] = thing->stateValue("totalEnergyConsumed").toDouble(); + m_totalEnergyProducedCache[thing] = thing->stateValue("totalEnergyProduced").toDouble(); + connect(thing, &Thing::stateValueChanged, this, [=](const StateTypeId &stateTypeId, const QVariant &value){ if (thing->thingClass().getStateType(stateTypeId).name() == "currentPower") { m_logger->logThingPower(thing->id(), value.toDouble(), thing->state("totalEnergyConsumed").value().toDouble(), thing->state("totalEnergyProduced").value().toDouble()); @@ -127,22 +158,44 @@ void EnergyManagerImpl::updatePowerBalance() double currentPowerAcquisition = 0; if (m_rootMeter) { currentPowerAcquisition = m_rootMeter->stateValue("currentPower").toDouble(); + + double oldAcquisition = m_totalEnergyConsumedCache.value(m_rootMeter); + double newAcquisition = m_rootMeter->stateValue("totalEnergyConsumed").toDouble(); + qCDebug(dcEnergyExperience()) << "Root meteter total consumption diff" << "old" << oldAcquisition << " new" << newAcquisition << (newAcquisition -oldAcquisition); + m_totalAcquisition += newAcquisition - oldAcquisition; + m_totalEnergyConsumedCache[m_rootMeter] = newAcquisition; + + double oldReturn = m_totalEnergyProducedCache.value(m_rootMeter); + double newReturn = m_rootMeter->stateValue("totalEnergyProduced").toDouble(); + qCDebug(dcEnergyExperience()) << "Root meteter total return diff" << "old" << oldReturn << " new" << newReturn << (newReturn - oldReturn); + m_totalReturn += newReturn - oldReturn; + m_totalEnergyProducedCache[m_rootMeter] = newReturn; } double currentPowerProduction = 0; foreach (Thing* thing, m_thingManager->configuredThings().filterByInterface("smartmeterproducer")) { currentPowerProduction += thing->stateValue("currentPower").toDouble(); + double oldProduction = m_totalEnergyProducedCache.value(thing); + double newProduction = thing->stateValue("totalEnergyProduced").toDouble(); + qCDebug(dcEnergyExperience()) << "inverter total production diff" << "old" << oldProduction << " new" << newProduction << (newProduction - oldProduction); + m_totalProduction += newProduction - oldProduction; + m_totalEnergyProducedCache[thing] = newProduction; } double currentPowerStorage = 0; + double totalFromStorage = 0; foreach (Thing *thing, m_thingManager->configuredThings().filterByInterface("energystorage")) { currentPowerStorage += thing->stateValue("currentPower").toDouble(); + double oldProduction = m_totalEnergyProducedCache.value(thing); + double newProduction = thing->stateValue("totalEnergyProduced").toDouble(); + totalFromStorage += newProduction - oldProduction; + m_totalEnergyProducedCache[thing] = newProduction; } - double currentPowerConsumption = -currentPowerProduction + currentPowerAcquisition - currentPowerStorage; + double currentPowerConsumption = currentPowerAcquisition + qAbs(qMin(0.0, currentPowerProduction)) - currentPowerStorage; + m_totalConsumption = m_totalAcquisition + m_totalProduction + totalFromStorage; - - qCDebug(dcEnergyExperience()) << "Consumption:" << currentPowerConsumption << "Production:" << currentPowerProduction << "Acquisition:" << currentPowerAcquisition << "Storage:" << currentPowerStorage; + qCDebug(dcEnergyExperience()).noquote().nospace() << "Power balance: " << "🔥: " << currentPowerConsumption << " W, 🌞: " << currentPowerProduction << " W, 💵: " << currentPowerAcquisition << " W, 🔋: " << currentPowerStorage << " W. Totals: 🔥: " << m_totalConsumption << " kWh, 🌞: " << m_totalProduction << " kWh, 💵↓: " << m_totalAcquisition << " kWh, 💵↑: " << m_totalReturn << " kWh"; if (currentPowerAcquisition != m_currentPowerAcquisition || currentPowerConsumption != m_currentPowerConsumption || currentPowerProduction != m_currentPowerProduction @@ -152,7 +205,7 @@ void EnergyManagerImpl::updatePowerBalance() m_currentPowerConsumption = currentPowerConsumption; m_currentPowerStorage = currentPowerStorage; emit powerBalanceChanged(); - m_logger->logPowerBalance(m_currentPowerConsumption, m_currentPowerProduction, m_currentPowerAcquisition, m_currentPowerStorage); + m_logger->logPowerBalance(m_currentPowerConsumption, m_currentPowerProduction, m_currentPowerAcquisition, m_currentPowerStorage, m_totalConsumption, m_totalProduction, m_totalAcquisition, m_totalReturn); } } diff --git a/plugin/energymanagerimpl.h b/plugin/energymanagerimpl.h index 617afa2..6b172a9 100644 --- a/plugin/energymanagerimpl.h +++ b/plugin/energymanagerimpl.h @@ -24,6 +24,10 @@ public: double currentPowerProduction() const override; double currentPowerAcquisition() const override; double currentPowerStorage() const override; + double totalConsumption() const override; + double totalProduction() const override; + double totalAcquisition() const override; + double totalReturn() const override; EnergyLogs* logs() const override; @@ -42,12 +46,19 @@ private: Thing *m_rootMeter = nullptr; QTimer m_balanceUpdateTimer; - double m_currentPowerConsumption; - double m_currentPowerProduction; - double m_currentPowerAcquisition; - double m_currentPowerStorage; + double m_currentPowerConsumption = 0; + double m_currentPowerProduction = 0; + double m_currentPowerAcquisition = 0; + double m_currentPowerStorage = 0; + double m_totalConsumption = 0; + double m_totalProduction = 0; + double m_totalAcquisition = 0; + double m_totalReturn = 0; EnergyLogger *m_logger = nullptr; + + QHash m_totalEnergyConsumedCache; + QHash m_totalEnergyProducedCache; }; #endif // ENERGYMANAGERIMPL_H