Update energy logs to latest log api
This commit is contained in:
parent
f161e23e0b
commit
d2f769bbf7
@ -227,12 +227,6 @@ void EnergyLogs::notificationReceivedInternal(const QVariantMap &data)
|
||||
return;
|
||||
}
|
||||
|
||||
QMetaEnum sampleRateEnum = QMetaEnum::fromType<SampleRate>();
|
||||
SampleRate sampleRate = static_cast<SampleRate>(sampleRateEnum.keyToValue(data.value("params").toMap().value("sampleRate").toByteArray()));
|
||||
if (sampleRate != m_sampleRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
notificationReceived(data);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "powerbalancelogs.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
|
||||
PowerBalanceLogEntry::PowerBalanceLogEntry(QObject *parent): EnergyLogEntry(parent)
|
||||
{
|
||||
|
||||
@ -180,6 +182,14 @@ void PowerBalanceLogs::notificationReceived(const QVariantMap &data)
|
||||
{
|
||||
QString notification = data.value("notification").toString();
|
||||
QVariantMap params = data.value("params").toMap();
|
||||
|
||||
QMetaEnum sampleRateEnum = QMetaEnum::fromType<EnergyLogs::SampleRate>();
|
||||
SampleRate sampleRate = static_cast<SampleRate>(sampleRateEnum.keyToValue(data.value("params").toMap().value("sampleRate").toByteArray()));
|
||||
|
||||
if (sampleRate != this->sampleRate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (notification == "Energy.PowerBalanceLogEntryAdded") {
|
||||
QVariantMap map = params.value("powerBalanceLogEntry").toMap();
|
||||
QDateTime timestamp = QDateTime::fromSecsSinceEpoch(map.value("timestamp").toLongLong());
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "thingpowerlogs.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
|
||||
ThingPowerLogEntry::ThingPowerLogEntry(QObject *parent):
|
||||
EnergyLogEntry(parent)
|
||||
{
|
||||
@ -69,7 +71,7 @@ double ThingPowerLogs::maxValue() const
|
||||
return m_maxValue;
|
||||
}
|
||||
|
||||
EnergyLogEntry *ThingPowerLogs::find(const QUuid &thingId, const QDateTime ×tamp)
|
||||
ThingPowerLogEntry *ThingPowerLogs::find(const QUuid &thingId, const QDateTime ×tamp)
|
||||
{
|
||||
// TODO: Can we do a binary search even if they key we're looking for is not unique (but still sorted)?
|
||||
// For now, 365 * consumers items is the max we'll have here which seems on the edge for doing a stupid linear search...
|
||||
@ -90,6 +92,11 @@ EnergyLogEntry *ThingPowerLogs::find(const QUuid &thingId, const QDateTime &time
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ThingPowerLogEntry *ThingPowerLogs::liveEntry(const QUuid &thingId)
|
||||
{
|
||||
return m_liveEntries.value(thingId);
|
||||
}
|
||||
|
||||
void ThingPowerLogs::addEntry(ThingPowerLogEntry *entry)
|
||||
{
|
||||
appendEntry(entry);
|
||||
@ -104,6 +111,16 @@ void ThingPowerLogs::addEntries(const QList<ThingPowerLogEntry *> &entries)
|
||||
appendEntries(energyLogEntries);
|
||||
}
|
||||
|
||||
ThingPowerLogEntry *ThingPowerLogs::unpack(const QVariantMap &map)
|
||||
{
|
||||
QDateTime timestamp = QDateTime::fromSecsSinceEpoch(map.value("timestamp").toLongLong());
|
||||
QUuid thingId = map.value("thingId").toUuid();
|
||||
double currentPower = map.value("currentPower").toDouble();
|
||||
double totalConsumption = map.value("totalConsumption").toDouble();
|
||||
double totalProduction = map.value("totalProduction").toDouble();
|
||||
return new ThingPowerLogEntry(timestamp, thingId, currentPower, totalConsumption, totalProduction, this);
|
||||
}
|
||||
|
||||
QString ThingPowerLogs::logsName() const
|
||||
{
|
||||
return "ThingPowerLogs";
|
||||
@ -117,11 +134,22 @@ QVariantMap ThingPowerLogs::fetchParams() const
|
||||
}
|
||||
QVariantMap ret;
|
||||
ret.insert("thingIds", thingIdsStrings);
|
||||
ret.insert("includeCurrent", true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ThingPowerLogs::logEntriesReceived(const QVariantMap ¶ms)
|
||||
{
|
||||
foreach (const QVariant &variant, params.value("currentEntries").toList()) {
|
||||
QVariantMap map = variant.toMap();
|
||||
ThingPowerLogEntry *entry = unpack(map);
|
||||
if (m_liveEntries.contains(entry->thingId())) {
|
||||
m_liveEntries[entry->thingId()]->deleteLater();
|
||||
}
|
||||
m_liveEntries[entry->thingId()] = entry;
|
||||
emit liveEntryChanged(entry);
|
||||
}
|
||||
|
||||
// Grouping them so when the UI gets entriesAdded, the whole set for this timstamp will be available at once
|
||||
QList<ThingPowerLogEntry*> groupForTimestamp;
|
||||
foreach (const QVariant &variant, params.value("thingPowerLogEntries").toList()) {
|
||||
@ -155,6 +183,32 @@ void ThingPowerLogs::notificationReceived(const QVariantMap &data)
|
||||
{
|
||||
QString notification = data.value("notification").toString();
|
||||
QVariantMap params = data.value("params").toMap();
|
||||
|
||||
QMetaEnum sampleRateEnum = QMetaEnum::fromType<EnergyLogs::SampleRate>();
|
||||
SampleRate sampleRate = static_cast<SampleRate>(sampleRateEnum.keyToValue(data.value("params").toMap().value("sampleRate").toByteArray()));
|
||||
QVariantMap entryMap = params.value("thingPowerLogEntry").toMap();
|
||||
QUuid thingId = entryMap.value("thingId").toUuid();
|
||||
|
||||
if (!m_thingIds.isEmpty() && !m_thingIds.contains(thingId)) {
|
||||
// Not watching this thing...
|
||||
return;
|
||||
}
|
||||
|
||||
// We'll use 1 Min samples in any case for the live value
|
||||
if (sampleRate == EnergyLogs::SampleRate1Min) {
|
||||
ThingPowerLogEntry *liveEntry = unpack(params.value("thingPowerLogEntry").toMap());
|
||||
if (m_liveEntries.contains(thingId)) {
|
||||
m_liveEntries.value(thingId)->deleteLater();
|
||||
}
|
||||
m_liveEntries[thingId] = liveEntry;
|
||||
emit liveEntryChanged(liveEntry);
|
||||
}
|
||||
|
||||
// And append the sample rate we're interested in
|
||||
if (sampleRate != this->sampleRate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (notification == "Energy.ThingPowerLogEntryAdded") {
|
||||
QVariantMap map = params.value("thingPowerLogEntry").toMap();
|
||||
QDateTime timestamp = QDateTime::fromSecsSinceEpoch(map.value("timestamp").toLongLong());
|
||||
@ -166,6 +220,11 @@ void ThingPowerLogs::notificationReceived(const QVariantMap &data)
|
||||
double totalConsumption = map.value("totalConsumption").toDouble();
|
||||
double totalProduction = map.value("totalProduction").toDouble();
|
||||
ThingPowerLogEntry *entry = new ThingPowerLogEntry(timestamp, thingId, currentPower, totalConsumption, totalProduction, this);
|
||||
|
||||
// In order to be easier on resources, we'll batch notifications by grouping them by timestamp
|
||||
// While the timestamp is the same, just cache the changes. Once the timestamp changes, we'll finalize the
|
||||
// batch and actually append them.
|
||||
// Also if we're not getting any more notification for a while and still have cached entries, we'll process the batch
|
||||
if (m_cachedEntries.isEmpty()) {
|
||||
m_cachedEntries.append(entry);
|
||||
} else if (entry->timestamp() == m_cachedEntries.first()->timestamp()) {
|
||||
|
||||
@ -44,7 +44,9 @@ public:
|
||||
double minValue() const;
|
||||
double maxValue() const;
|
||||
|
||||
Q_INVOKABLE EnergyLogEntry *find(const QUuid &thingId, const QDateTime ×tamp);
|
||||
Q_INVOKABLE ThingPowerLogEntry *find(const QUuid &thingId, const QDateTime ×tamp);
|
||||
|
||||
Q_INVOKABLE ThingPowerLogEntry *liveEntry(const QUuid &thingId);
|
||||
|
||||
signals:
|
||||
void thingIdsChanged();
|
||||
@ -52,6 +54,8 @@ signals:
|
||||
void minValueChanged();
|
||||
void maxValueChanged();
|
||||
|
||||
void liveEntryChanged(ThingPowerLogEntry *entry);
|
||||
|
||||
protected:
|
||||
QString logsName() const override;
|
||||
QVariantMap fetchParams() const override;
|
||||
@ -62,12 +66,16 @@ private:
|
||||
void addEntry(ThingPowerLogEntry *entry);
|
||||
void addEntries(const QList<ThingPowerLogEntry *> &entries);
|
||||
|
||||
ThingPowerLogEntry *unpack(const QVariantMap &map);
|
||||
|
||||
QList<QUuid> m_thingIds;
|
||||
double m_minValue = 0;
|
||||
double m_maxValue = 0;
|
||||
|
||||
QList<ThingPowerLogEntry*> m_cachedEntries;
|
||||
QTimer m_cacheTimer;
|
||||
|
||||
QHash<QUuid, ThingPowerLogEntry*> m_liveEntries;
|
||||
};
|
||||
|
||||
#endif // THINGPOWERLOGS_H
|
||||
|
||||
@ -113,8 +113,9 @@ StatsBase {
|
||||
var liveEntry = {}
|
||||
for (var j = 0; j < consumers.count; j++) {
|
||||
var consumer = consumers.get(j)
|
||||
// print("Got consumer:", consumer.id, consumer.name)
|
||||
var value = consumer.stateByName("totalEnergyConsumed").value;
|
||||
var liveLogEntry = powerLogs.liveEntry(consumer.id)
|
||||
// print("Got consumer:", consumer.id, consumer.name, liveLogEntry ? liveLogEntry.timestamp : "-")
|
||||
var value = liveLogEntry ? liveLogEntry.totalConsumption : 0;
|
||||
if (groupedEntry) {
|
||||
value -= groupedEntry.hasOwnProperty(consumer.id) ? groupedEntry[consumer.id] : 0
|
||||
}
|
||||
@ -205,20 +206,41 @@ StatsBase {
|
||||
var entry = entries[i]
|
||||
var thing = engine.thingManager.things.getThing(entry.thingId)
|
||||
// print("Adding new sample. thing:", thing.name);
|
||||
// print("Timestamp:", entry.timestamp)
|
||||
var totalEnergyConsumedState = thing.stateByName("totalEnergyConsumed")
|
||||
// print("current total:", entry.totalConsumption)
|
||||
// print("Timestamp:", entry.timestamp, entry.totalConsumption)
|
||||
// update current last
|
||||
var barSet = barSeries.thingBarSetMap[thing.id]
|
||||
var lastTimestamp = categoryAxis.timestamps[categoryAxis.count - 1]
|
||||
var previous = powerLogs.find(entry.thingId, lastTimestamp)
|
||||
var previousValue = previous ? previous.totalConsumption : 0
|
||||
// print("previousValue:", previousValue, "newValue:", entry.totalConsumption, "diff", entry.totalConsumption - previousValue)
|
||||
barSet.replace(barSet.count - 1, entry.totalConsumption - previousValue)
|
||||
|
||||
var consumptionValue = totalEnergyConsumedState.value - entry.totalConsumption
|
||||
// print("new slot total:", consumptionValue)
|
||||
// remove the oldest
|
||||
barSet.remove(0, 1)
|
||||
|
||||
categoryAxis.categories = configs[selectionTabs.currentValue.config].sampleListNames()
|
||||
barSeries.thingBarSetMap[thing].append(consumptionValue)
|
||||
barSeries.thingBarSetMap[thing].remove(0, 1);
|
||||
// and add a new one (always 0 for a start)
|
||||
barSet.append(0)
|
||||
}
|
||||
|
||||
var labels = categoryAxis.timestamps
|
||||
labels.splice(0, 1)
|
||||
labels.push(entries[0].timestamp)
|
||||
categoryAxis.timestamps = labels
|
||||
|
||||
chartView.animationOptions = ChartView.SeriesAnimations
|
||||
}
|
||||
|
||||
onLiveEntryChanged: {
|
||||
if (powerLogs.fetchingData) {
|
||||
return
|
||||
}
|
||||
|
||||
// print("live entry changed", entry.thingId, entry.timestamp)
|
||||
var previous = powerLogs.find(entry.thingId, new Date(categoryAxis.timestamps[categoryAxis.timestamps.length - 1]))
|
||||
var previousValue = previous ? previous.totalConsumption : 0
|
||||
var barSet = barSeries.thingBarSetMap[entry.thingId]
|
||||
barSet.replace(barSet.count - 1, entry.totalConsumption - previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
@ -385,7 +407,7 @@ StatsBase {
|
||||
margins: Style.smallMargins
|
||||
}
|
||||
Label {
|
||||
text: categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : ""
|
||||
text: toolTip.idx >= 0 && categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : ""
|
||||
font: Style.smallFont
|
||||
}
|
||||
|
||||
@ -395,7 +417,7 @@ StatsBase {
|
||||
Rectangle {
|
||||
width: Style.extraSmallFont.pixelSize
|
||||
height: width
|
||||
color: root.colors[index % root.colors.length]
|
||||
color: index >= 0 ? root.colors[index % root.colors.length] : "white"
|
||||
}
|
||||
Label {
|
||||
text: barSeries.thingBarSetMap.hasOwnProperty(model.id) ? "%1: %2 kWh".arg(model.name).arg(barSeries.thingBarSetMap[model.id].at(toolTip.idx).toFixed(2)) : ""
|
||||
|
||||
@ -319,7 +319,7 @@ ChartView {
|
||||
Rectangle {
|
||||
width: Style.extraSmallFont.pixelSize
|
||||
height: width
|
||||
color: root.colors[index % root.colors.length]
|
||||
color: index >= 0 ? root.colors[index % root.colors.length] : "white"
|
||||
}
|
||||
|
||||
Label {
|
||||
|
||||
@ -135,7 +135,7 @@ ChartView {
|
||||
}
|
||||
delegate: ColumnLayout {
|
||||
id: consumerDelegate
|
||||
width: parent.width
|
||||
width: parent ? parent.width : 0
|
||||
spacing: 0
|
||||
property Thing consumer: consumers.getThing(model.id)
|
||||
property State currentPowerState: consumer ? consumer.stateByName("currentPower") : null
|
||||
|
||||
@ -52,7 +52,7 @@ StatsBase {
|
||||
}
|
||||
|
||||
var config = root.configs[currentValue.config]
|
||||
print("config:", config.startTime(), config.sampleRate)
|
||||
// print("config:", config.startTime(), config.sampleRate)
|
||||
|
||||
powerBalanceLogs.loadingInhibited = true
|
||||
powerBalanceLogs.sampleRate = config.sampleRate
|
||||
@ -89,7 +89,7 @@ StatsBase {
|
||||
onPowerBalanceChanged: {
|
||||
var start = powerBalanceLogs.get(powerBalanceLogs.count - 1 )
|
||||
// print("balance changed:", d.consumptionSet, powerBalanceLogs, powerBalanceLogs.count)
|
||||
// print("updating", start.timestamp, start.totalConsumption, root.energyManager.totalConsumption, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
|
||||
// print("updating", start ? start.timestamp : "", start ? start.totalConsumption : 0, root.energyManager.totalConsumption, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
|
||||
d.consumptionSet.replace(d.consumptionSet.count - 1, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
|
||||
d.productionSet.replace(d.productionSet.count - 1, root.energyManager.totalProduction - (start ? start.totalProduction : 0))
|
||||
d.acquisitionSet.replace(d.acquisitionSet.count - 1, root.energyManager.totalAcquisition - (start ? start.totalAcquisition : 0))
|
||||
@ -106,7 +106,7 @@ StatsBase {
|
||||
if (!fetchingData) {
|
||||
chartView.animationOptions = ChartView.NoAnimation
|
||||
|
||||
print("Logs fetched")
|
||||
// print("Logs fetched")
|
||||
var config = root.configs[selectionTabs.currentValue.config]
|
||||
|
||||
var labels = []
|
||||
@ -130,7 +130,7 @@ StatsBase {
|
||||
liveEntry.acquisition -= entry.totalAcquisition
|
||||
liveEntry.returned -= entry.totalReturn
|
||||
}
|
||||
print("Adding live entry:", liveEntry.consumption, root.energyManager.totalConsumption, entry ? entry.totalConsumption : 0)
|
||||
// print("Adding live entry:", liveEntry.consumption, root.energyManager.totalConsumption, entry ? entry.totalConsumption : 0)
|
||||
entries.unshift(liveEntry)
|
||||
valueAxis.adjustMax(liveEntry.consumption)
|
||||
valueAxis.adjustMax(liveEntry.production)
|
||||
@ -206,6 +206,7 @@ StatsBase {
|
||||
return
|
||||
}
|
||||
|
||||
// print("Entry added")
|
||||
var config = root.configs[selectionTabs.currentValue.config]
|
||||
|
||||
|
||||
@ -219,18 +220,20 @@ StatsBase {
|
||||
chartView.animationOptions = ChartView.NoAnimation
|
||||
|
||||
var timestamps = categoryAxis.timestamps;
|
||||
timestamps.splice(0, 1)
|
||||
timestamps.push(entry.timestamp)
|
||||
timestamps.splice(0, 1)
|
||||
categoryAxis.timestamps = timestamps
|
||||
|
||||
d.consumptionSet.remove(0, 1);
|
||||
d.productionSet.remove(0, 1);
|
||||
d.acquisitionSet.remove(0, 1);
|
||||
d.returnSet.remove(0, 1);
|
||||
|
||||
d.consumptionSet.append(consumptionValue)
|
||||
d.productionSet.append(productionValue)
|
||||
d.acquisitionSet.append(acquisitionValue)
|
||||
d.returnSet.append(returnValue)
|
||||
d.consumptionSet.remove(0, 1);
|
||||
d.productionSet.remove(0, 1);
|
||||
d.acquisitionSet.remove(0, 1);
|
||||
d.returnSet.remove(0, 1);
|
||||
|
||||
chartView.animationOptions = ChartView.SeriesAnimations
|
||||
}
|
||||
}
|
||||
@ -359,7 +362,7 @@ StatsBase {
|
||||
}
|
||||
|
||||
Label {
|
||||
text: categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : ""
|
||||
text: toolTip.idx >= 0 && categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : ""
|
||||
font: Style.smallFont
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user