Some more work on the power balance stats

This commit is contained in:
Michael Zanetti 2021-11-26 11:16:33 +01:00
parent a2708d918b
commit 6f04164513
5 changed files with 303 additions and 143 deletions

View File

@ -75,6 +75,12 @@ void EnergyLogs::setSampleRate(SampleRate sampleRate)
if (m_sampleRate != sampleRate) { if (m_sampleRate != sampleRate) {
m_sampleRate = sampleRate; m_sampleRate = sampleRate;
emit sampleRateChanged(); emit sampleRateChanged();
beginResetModel();
qDeleteAll(m_list);
m_list.clear();
endResetModel();
fetchLogs();
} }
} }

View File

@ -121,7 +121,7 @@ void PowerBalanceLogs::addEntry(PowerBalanceLogEntry *entry)
EnergyLogEntry *PowerBalanceLogs::find(const QDateTime &timestamp) const EnergyLogEntry *PowerBalanceLogs::find(const QDateTime &timestamp) const
{ {
qWarning() << "Finding log entry for timestamp:" << timestamp; // qWarning() << "Finding log entry for timestamp:" << timestamp;
int oldest = 0; int oldest = 0;
int newest = rowCount() - 1; int newest = rowCount() - 1;
EnergyLogEntry *entry = nullptr; EnergyLogEntry *entry = nullptr;
@ -131,7 +131,7 @@ EnergyLogEntry *PowerBalanceLogs::find(const QDateTime &timestamp) const
EnergyLogEntry *newestEntry = get(newest); EnergyLogEntry *newestEntry = get(newest);
int middle = (newest - oldest) / 2 + oldest; int middle = (newest - oldest) / 2 + oldest;
EnergyLogEntry *middleEntry = get(middle); EnergyLogEntry *middleEntry = get(middle);
qWarning() << "Oldest:" << oldestEntry->timestamp().toString() << "Middle:" << middleEntry->timestamp().toString() << "Newest:" << newestEntry->timestamp().toString() << ":" << (newest - oldest); // qWarning() << "Oldest:" << oldestEntry->timestamp().toString() << "Middle:" << middleEntry->timestamp().toString() << "Newest:" << newestEntry->timestamp().toString() << ":" << (newest - oldest);
if (timestamp <= oldestEntry->timestamp()) { if (timestamp <= oldestEntry->timestamp()) {
return oldestEntry; return oldestEntry;
} }
@ -144,9 +144,9 @@ EnergyLogEntry *PowerBalanceLogs::find(const QDateTime &timestamp) const
} }
if (timestamp < middleEntry->timestamp()) { if (timestamp < middleEntry->timestamp()) {
oldest = middle;
} else {
newest = middle; newest = middle;
} else {
oldest = middle;
} }
if ((newest - oldest) <= 1) { if ((newest - oldest) <= 1) {

View File

@ -97,54 +97,54 @@ MainViewBase {
columnSpacing: 0 columnSpacing: 0
CurrentConsumptionBalancePieChart { // CurrentConsumptionBalancePieChart {
Layout.fillWidth: true // Layout.fillWidth: true
Layout.preferredHeight: width // Layout.preferredHeight: width
energyManager: energyManager // energyManager: energyManager
visible: producers.count > 0 // visible: producers.count > 0
} // }
CurrentProductionBalancePieChart { // CurrentProductionBalancePieChart {
Layout.fillWidth: true // Layout.fillWidth: true
Layout.preferredHeight: width // Layout.preferredHeight: width
energyManager: energyManager // energyManager: energyManager
visible: producers.count > 0 // visible: producers.count > 0
} // }
PowerConsumptionBalanceHistory { // PowerConsumptionBalanceHistory {
Layout.fillWidth: true // Layout.fillWidth: true
Layout.preferredHeight: width // Layout.preferredHeight: width
visible: producers.count > 0 // visible: producers.count > 0
} // }
PowerProductionBalanceHistory { // PowerProductionBalanceHistory {
Layout.fillWidth: true // Layout.fillWidth: true
Layout.preferredHeight: width // Layout.preferredHeight: width
visible: producers.count > 0 // visible: producers.count > 0
} // }
ConsumersBarChart { // ConsumersBarChart {
Layout.fillWidth: true // Layout.fillWidth: true
Layout.preferredHeight: width // Layout.preferredHeight: width
energyManager: energyManager // energyManager: energyManager
visible: consumers.count > 0 // visible: consumers.count > 0
} // }
ConsumersHistory { // ConsumersHistory {
Layout.fillWidth: true // Layout.fillWidth: true
Layout.preferredHeight: width // Layout.preferredHeight: width
visible: consumers.count > 0 // visible: consumers.count > 0
} // }
PowerBalanceStats { PowerBalanceStats {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: width Layout.preferredHeight: width
energyManager: energyManager energyManager: energyManager
} }
ConsumerStats { // ConsumerStats {
Layout.fillWidth: true // Layout.fillWidth: true
Layout.preferredHeight: width // Layout.preferredHeight: width
energyManager: energyManager // energyManager: energyManager
visible: consumers.count > 0 // visible: consumers.count > 0
} // }
} }
} }

View File

@ -21,6 +21,7 @@ ChartView {
property EnergyManager energyManager: null property EnergyManager energyManager: null
readonly property date dayStart: { readonly property date dayStart: {
var d = new Date(); var d = new Date();
d.setHours(0,0,0,0); d.setHours(0,0,0,0);

View File

@ -3,24 +3,55 @@ import QtQuick.Layouts 1.2
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import QtCharts 2.3 import QtCharts 2.3
import Nymea 1.0 import Nymea 1.0
import "qrc:/ui/components/"
ChartView { ColumnLayout {
id: root id: root
backgroundColor: "transparent"
legend.alignment: Qt.AlignBottom
legend.font: Style.extraSmallFont
legend.labelColor: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0 ? Style.foregroundColor : Style.gray
// margins.left: 0
margins.right: 0
margins.bottom: 0
margins.top: 0
title: qsTr("Energy consumption statistics")
titleColor: Style.foregroundColor
property EnergyManager energyManager: null property EnergyManager energyManager: null
readonly property date minuteStart: {
var d = new Date();
d.setSeconds(0, 0)
return d;
}
readonly property var minutesList: {
var ret = []
for (var i = 15; i >= 0; i--) {
var last = new Date(minuteStart)
ret.push(last.setTime(last.getTime() - i * 60 * 1000))
}
return ret;
}
readonly property var minutesListNames: {
var ret = []
for (var i = 0; i < minutesList.length; i++) {
ret.push(new Date(minutesList[i]).toLocaleString(Qt.locale(), "hh:mm"))
}
return ret;
}
readonly property date hourStart: {
var d = new Date();
d.setMinutes(0, 0, 0);
return d;
}
readonly property var hoursList: {
var ret = []
for (var i = 24; i >= 0; i--) {
var last = new Date(hourStart)
}
return ret;
}
readonly property var hoursListNames: {
var ret = [];
for (var i = 0; i < hoursList.length; i++) {
ret.push(new Date(hoursList[i]).toLocaleString(Qt.locale(), "dd"));
}
return ret;
}
readonly property date dayStart: { readonly property date dayStart: {
var d = new Date(); var d = new Date();
d.setHours(0,0,0,0); d.setHours(0,0,0,0);
@ -65,21 +96,101 @@ ChartView {
return d; return d;
} }
Label {
Layout.fillWidth: true
Layout.margins: Style.smallMargins
horizontalAlignment: Text.AlignHCenter
text: qsTr("Energy consumption statistics")
}
SelectionTabs {
id: selectionTabs
Layout.fillWidth: true
Layout.leftMargin: Style.smallMargins
Layout.rightMargin: Style.smallMargins
model: ListModel {
// ListElement {
// modelData: qsTr("Year")
// sampleRate: EnergyLogs.SampleRate1Year
// }
// ListElement {
// text: qsTr("Month")
// sampleRate: EnergyLogs.SampleRate1Month
// }
// ListElement {
// text: qsTr("Week")
// sampleRate: EnergyLogs.SampleRate1Week
// }
Component.onCompleted: {
append({modelData: qsTr("Day"), config: "days", sampleRate: EnergyLogs.SampleRate1Day, startTime: yearStart, sampleList: daysList, sampleListNames: daysListNames })
append({modelData: qsTr("Hour"), config: "hours", sampleRate: EnergyLogs.SampleRate1Hour, startTime: monthStart, sampleList: hoursList, sampleListNames: hoursListNames })
}
// ListElement {
// modelData: qsTr("Day")
// sampleRate: EnergyLogs.SampleRate1Day
// startTime: weekStart
// }
// ListElement {
// modelData: qsTr("Hour")
// sampleRate: EnergyLogs.SampleRate1Hour
// startTime: dayStart
// }
}
// currentIndex: 3
onCurrentValueChanged: {
print("Selecging model:", currentValue)
powerBalanceLogs.loadingInhibited = true
powerBalanceLogs.sampleRate = currentValue.sampleRate
powerBalanceLogs.startTime = currentValue.startTime
powerBalanceLogs.loadingInhibited = false
consumptionSeries.remove(0, consumptionSeries.count-1)
productionSeries.remove(0, productionSeries.count-1)
acquisitionSeries.remove(0, acquisitionSeries.count-1)
returnSeries.remove(0, returnSeries.count-1)
print("sample list names:", currentValue.sampleListNames)
categoryAxis.categories = currentValue.sampleListNames
}
}
Connections {
target: energyManager
onPowerBalanceChanged: {
var start = powerBalanceLogs.get(powerBalanceLogs.count - 1)
print("updating", start.timestamp, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
consumptionSeries.replace(consumptionSeries.count - 1, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
productionSeries.replace(productionSeries.count - 1, root.energyManager.totalProduction - (start ? start.totalProduction : 0))
acquisitionSeries.replace(acquisitionSeries.count - 1, root.energyManager.totalAcquisition - (start ? start.totalAcquisition : 0))
returnSeries.replace(returnSeries.count - 1, root.energyManager.totalReturn - (start ? start.totalReturn : 0))
}
}
PowerBalanceLogs { PowerBalanceLogs {
id: powerBalanceLogs id: powerBalanceLogs
engine: _engine engine: _engine
sampleRate: EnergyLogs.SampleRate1Day // sampleRate: EnergyLogs.SampleRate1Day
startTime: root.yearStart; // startTime: root.yearStart;
sampleRate: selectionTabs.currentValue.sampleRate// EnergyLogs.SampleRate1Min
startTime: selectionTabs.currentValue.startTime // root.weekStart;
property var sampleList: minutesList
onFetchingDataChanged: { onFetchingDataChanged: {
if (!fetchingData) { if (!fetchingData) {
for (var i = 0; i < daysList.length; i++) { for (var i = 0; i < sampleList.length; i++) {
var start = powerBalanceLogs.find(new Date(daysList[i])) var start = powerBalanceLogs.find(new Date(sampleList[i]))
var end = null; var end = null;
if (i+1 < daysList.length) { if (i+1 < sampleList.length) {
end = powerBalanceLogs.find(new Date(daysList[i+1])) end = powerBalanceLogs.find(new Date(sampleList[i+1]))
} }
print("** stats for", daysList[i], new Date(daysList[i]), start.timestamp, start.totalConsumption) print("** stats for:", new Date(sampleList[i]), start.timestamp, start.totalConsumption)
var consumptionValue = (end != null ? end.totalConsumption : root.energyManager.totalConsumption) - (start ? start.totalConsumption : 0) var consumptionValue = (end != null ? end.totalConsumption : root.energyManager.totalConsumption) - (start ? start.totalConsumption : 0)
var productionValue = (end != null ? end.totalProduction : root.energyManager.totalProduction) - (start ? start.totalProduction : 0) var productionValue = (end != null ? end.totalProduction : root.energyManager.totalProduction) - (start ? start.totalProduction : 0)
var acquisitionValue = (end != null ? end.totalAcquisition : root.energyManager.totalAcquisition) - (start ? start.totalAcquisition : 0) var acquisitionValue = (end != null ? end.totalAcquisition : root.energyManager.totalAcquisition) - (start ? start.totalAcquisition : 0)
@ -96,98 +207,140 @@ ChartView {
} }
} }
} }
}
Item { onEntryAdded: {
id: labelsLayout if (fetchingData) {
x: Style.smallMargins return
y: root.plotArea.y
height: root.plotArea.height
width: plotArea.x - x
enabled: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0
Repeater {
model: valueAxis.tickCount
delegate: Label {
y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2
width: parent.width - Style.smallMargins
horizontalAlignment: Text.AlignRight
text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1)))).toFixed(0) + "kWh"
verticalAlignment: Text.AlignTop
font: Style.extraSmallFont
} }
var start = entry
var consumptionValue = root.energyManager.totalConsumption - (start ? start.totalConsumption : 0)
var productionValue = root.energyManager.totalProduction - (start ? start.totalProduction : 0)
var acquisitionValue = root.energyManager.totalAcquisition - (start ? start.totalAcquisition : 0)
var returnValue = root.energyManager.totalReturn - (start ? start.totalReturn : 0)
consumptionSeries.append(consumptionValue)
productionSeries.append(productionValue)
acquisitionSeries.append(acquisitionValue)
returnSeries.append(returnValue)
consumptionSeries.remove(0, 1);
productionSeries.remove(0, 1);
acquisitionSeries.remove(0, 1);
returnSeries.remove(0, 1);
} }
} }
BarSeries {
axisX: BarCategoryAxis {
id: categoryAxis
categories: daysListNames
labelsColor: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0 ? Style.foregroundColor : Style.gray
labelsFont: Style.extraSmallFont ChartView {
gridVisible: false id: chartView
gridLineColor: Style.tileOverlayColor Layout.fillWidth: true
lineVisible: false Layout.fillHeight: true
titleVisible: false
shadesVisible: false
} backgroundColor: "transparent"
axisY: ValueAxis { legend.alignment: Qt.AlignBottom
id: valueAxis legend.font: Style.extraSmallFont
min: 0 legend.labelColor: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0 ? Style.foregroundColor : Style.gray
gridLineColor: Style.tileOverlayColor
labelsVisible: false
labelsColor: Style.foregroundColor
labelsFont: Style.extraSmallFont
lineVisible: false
titleVisible: false
shadesVisible: false
function adjustMax(newValue) { // margins.left: 0
if (max < newValue) { margins.right: 0
max = Math.ceil(newValue / 100) * 100 margins.bottom: 0
margins.top: 0
// title: qsTr("Energy consumption statistics")
// titleColor: "red"// Style.foregroundColor
Item {
id: labelsLayout
x: Style.smallMargins
y: chartView.plotArea.y
height: chartView.plotArea.height
width: chartView.plotArea.x - x
enabled: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0
Repeater {
model: valueAxis.tickCount
delegate: Label {
y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2
width: parent.width - Style.smallMargins
horizontalAlignment: Text.AlignRight
text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1)))).toFixed(0) + "kWh"
verticalAlignment: Text.AlignTop
font: Style.extraSmallFont
} }
} }
} }
BarSet { BarSeries {
id: consumptionSeries axisX: BarCategoryAxis {
label: qsTr("Consumed") id: categoryAxis
borderWidth: 0 // categories: daysListNames
} // categories: minutesListNames
BarSet { labelsColor: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0 ? Style.foregroundColor : Style.gray
id: productionSeries
label: qsTr("Produced")
color: Style.green
borderWidth: 0
borderColor: color
}
BarSet {
id: acquisitionSeries
label: qsTr("From grid")
color: Style.red
borderWidth: 0
borderColor: color
}
BarSet {
id: returnSeries
label: qsTr("To grid")
color: Style.orange
borderWidth: 0
borderColor: color
}
}
Label { labelsFont: Style.extraSmallFont
x: root.plotArea.x gridVisible: false
y: root.plotArea.y gridLineColor: Style.tileOverlayColor
width: root.plotArea.width lineVisible: false
height: root.plotArea.height titleVisible: false
wrapMode: Text.WordWrap shadesVisible: false
text: qsTr("No data available")
horizontalAlignment: Text.AlignHCenter }
verticalAlignment: Text.AlignVCenter axisY: ValueAxis {
visible: !powerBalanceLogs.fetchingData && powerBalanceLogs.count == 0 id: valueAxis
min: 0
gridLineColor: Style.tileOverlayColor
labelsVisible: false
labelsColor: Style.foregroundColor
labelsFont: Style.extraSmallFont
lineVisible: false
titleVisible: false
shadesVisible: false
function adjustMax(newValue) {
if (max < newValue) {
max = newValue // Math.ceil(newValue / 100) * 100
}
}
}
BarSet {
id: consumptionSeries
label: qsTr("Consumed")
borderWidth: 0
}
BarSet {
id: productionSeries
label: qsTr("Produced")
color: Style.green
borderWidth: 0
borderColor: color
}
BarSet {
id: acquisitionSeries
label: qsTr("From grid")
color: Style.red
borderWidth: 0
borderColor: color
}
BarSet {
id: returnSeries
label: qsTr("To grid")
color: Style.orange
borderWidth: 0
borderColor: color
}
}
Label {
x: chartView.plotArea.x
y: chartView.plotArea.y
width: chartView.plotArea.width
height: chartView.plotArea.height
wrapMode: Text.WordWrap
text: qsTr("No data available")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
visible: !powerBalanceLogs.fetchingData && powerBalanceLogs.count == 0
}
} }
} }