This repository has been archived on 2026-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
powersync-app/nymea-app/ui/mainviews/energy/ConsumersHistory.qml
2022-04-25 01:27:35 +02:00

357 lines
12 KiB
QML

import QtQuick 2.0
import QtCharts 2.3
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.2
import Nymea 1.0
import "qrc:/ui/components"
Item {
id: root
property var colors: null
property ThingsProxy consumers: null
Connections {
target: consumers
onCountChanged: d.updateConsumers()
}
Connections {
target: engine.tagsManager
onBusyChanged: d.updateConsumers()
}
ThingPowerLogs {
id: thingPowerLogs
engine: _engine
startTime: dateTimeAxis.min
sampleRate: EnergyLogs.SampleRate15Mins
thingIds: []
loadingInhibited: thingIds.length === 0
onModelReset: {
for (var i = 0; i < consumers.count; i++) {
var consumer = consumers.get(i);
var series = d.thingsSeriesMap[consumer.id];
series.upperSeries.clear()
}
}
onEntriesAdded: {
var thingValues = ({})
var timestamp = entries[0].timestamp
for (var i = 0; i < entries.length; i++) {
var entry = entries[i]
var thing = engine.thingManager.things.getThing(entries[i].thingId)
thingValues[entry.thingId] = entry.currentPower
}
// Add them in the order of the chart (same as proxy), summing it up
var totalValue = 0;
for (var i = 0; i < consumers.count; i++) {
var consumer = consumers.get(i);
var value = thingValues.hasOwnProperty(consumer.id) ? thingValues[consumer.id] : 0
totalValue += thingValues.hasOwnProperty(consumer.id) ? thingValues[consumer.id] : 0;
var series = d.thingsSeriesMap[consumer.id];
series.upperSeries.append(timestamp, totalValue)
}
thingPowerLogs.maxValue = Math.max(thingPowerLogs.maxValue, totalValue)
}
property double maxValue: 0
}
property PowerBalanceLogs powerBalanceLogs: PowerBalanceLogs {
engine: _engine
startTime: dateTimeAxis.min
sampleRate: EnergyLogs.SampleRate15Mins
onEntryAdded: {
consumptionSeries.addEntry(entry)
if (dateTimeAxis.now < entry.timestamp) {
dateTimeAxis.now = entry.timestamp
zeroSeries.update(entry.timestamp)
}
}
}
Timer {
interval: 60000
repeat: true
onTriggered: {
var now = new Date()
if (dateTimeAxis.now < now) {
dateTimeAxis.now = now
zeroSeries.update(now)
}
}
}
Connections {
target: engine.thingManager
onFetchingDataChanged: d.updateConsumers()
onThingAdded: {
if (thing.thingClass.interfaces.indexOf("smartmeterconsumer") >= 0) {
d.updateConsumers();
}
}
}
Component.onCompleted: {
for (var i = 0; i < powerBalanceLogs.count; i++) {
var entry = powerBalanceLogs.get(i);
consumptionSeries.addEntry(entry)
}
d.updateConsumers();
}
QtObject {
id: d
property var thingsSeriesMap: ({})
function updateConsumers() {
if (engine.thingManager.fetchingData || engine.tagsManager.busy) {
return;
}
thingPowerLogs.loadingInhibited = true;
for (var thingId in d.thingsSeriesMap) {
chartView.removeSeries(d.thingsSeriesMap[thingId])
}
d.thingsSeriesMap = ({})
var consumerThingIds = []
for (var i = 0; i < consumers.count; i++) {
var thing = consumers.get(i);
var baseSeries = zeroSeries;
if (i > 0) {
baseSeries = d.thingsSeriesMap[consumerThingIds[i-1]].upperSeries
// print("base for:", thing.name, "is", engine.thingManager.things.getThing(consumerThingIds[i-1]).name)
}
var series = chartView.createSeries(ChartView.SeriesTypeArea, thing.name, dateTimeAxis, valueAxis)
series.lowerSeries = baseSeries
series.upperSeries = lineSeriesComponent.createObject(series)
// series.color = root.colors[i % root.colors.length]
series.color = NymeaUtils.generateColor(Style.generationBaseColor, i)
series.borderWidth = 0;
series.borderColor = series.color
var map = d.thingsSeriesMap
map[thing.id] = series
d.thingsSeriesMap = map
consumerThingIds.push(thing.id)
}
thingPowerLogs.thingIds = consumerThingIds;
thingPowerLogs.loadingInhibited = false;
}
}
Component {
id: lineSeriesComponent
LineSeries { }
}
ChartView {
id: chartView
anchors.fill: parent
backgroundColor: "transparent"
margins.left: 0
margins.right: 0
margins.bottom: 0
margins.top: 0
title: qsTr("Consumers history")
titleColor: Style.foregroundColor
legend.alignment: Qt.AlignBottom
legend.labelColor: Style.foregroundColor
legend.font: Style.extraSmallFont
ValueAxis {
id: valueAxis
min: 0
max: Math.ceil(Math.max(powerBalanceLogs.maxValue, thingPowerLogs.maxValue) / 1000) * 1000
labelFormat: ""
gridLineColor: Style.tileOverlayColor
labelsVisible: false
lineVisible: false
titleVisible: false
shadesVisible: false
// visible: false
}
Item {
id: labelsLayout
x: Style.smallMargins
y: chartView.plotArea.y
height: chartView.plotArea.height
width: chartView.plotArea.x - x
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))) / 1000).toFixed(2) + "kW"
verticalAlignment: Text.AlignTop
font: Style.extraSmallFont
}
}
}
DateTimeAxis {
id: dateTimeAxis
property date now: new Date()
min: {
var date = new Date(now);
date.setTime(date.getTime() - (1000 * 60 * 60 * 24) + 2000);
return date;
}
max: {
var date = new Date(now);
date.setTime(date.getTime() + 2000)
return date;
}
format: "hh:mm"
labelsFont: Style.extraSmallFont
gridVisible: false
minorGridVisible: false
lineVisible: false
shadesVisible: false
labelsColor: Style.foregroundColor
}
AreaSeries {
id: consumptionSeries
axisX: dateTimeAxis
axisY: valueAxis
color: Style.gray
borderWidth: 0
borderColor: color
name: qsTr("Unknown")
lowerSeries: LineSeries {
id: zeroSeries
XYPoint { x: dateTimeAxis.min.getTime(); y: 0 }
XYPoint { x: dateTimeAxis.max.getTime(); y: 0 }
function update(timestamp) {
append(timestamp, 0);
removePoints(1,1);
}
}
upperSeries: LineSeries {
id: consumptionUpperSeries
}
function addEntry(entry) {
consumptionUpperSeries.append(entry.timestamp.getTime(), entry.consumption)
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
anchors.leftMargin: chartView.plotArea.x
anchors.topMargin: chartView.plotArea.y
anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x
anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y
hoverEnabled: true
Timer {
interval: 300
running: mouseArea.pressed
onTriggered: mouseArea.preventStealing = true
}
onReleased: mouseArea.preventStealing = false
Rectangle {
height: parent.height
width: 1
color: Style.foregroundColor
x: Math.min(mouseArea.width - 1, Math.max(0, mouseArea.mouseX))
visible: mouseArea.containsMouse || mouseArea.preventStealing
}
NymeaToolTip {
id: toolTip
visible: mouseArea.containsMouse || mouseArea.preventStealing
backgroundItem: chartView
backgroundRect: Qt.rect(mouseArea.x + toolTip.x, mouseArea.y + toolTip.y, toolTip.width, toolTip.height)
property int idx: consumptionUpperSeries.count - Math.floor(mouseArea.mouseX * consumptionUpperSeries.count / mouseArea.width)
property int seriesIndex: Math.min(consumptionUpperSeries.count - 1, Math.max(0, consumptionUpperSeries.count - idx))
property int xOnRight: Math.max(0, mouseArea.mouseX) + Style.smallMargins
property int xOnLeft: Math.min(mouseArea.width, mouseArea.mouseX) - Style.smallMargins - width
x: xOnRight + width < mouseArea.width ? xOnRight : xOnLeft
property double maxValue: consumptionUpperSeries.at(seriesIndex).y
y: Math.min(Math.max(mouseArea.height - (maxValue * mouseArea.height / valueAxis.max) - height - Style.margins, 0), mouseArea.height - height)
width: tooltipLayout.implicitWidth + Style.smallMargins * 2
height: tooltipLayout.implicitHeight + Style.smallMargins * 2
property date timestamp: new Date(consumptionUpperSeries.at(seriesIndex).x)
ColumnLayout {
id: tooltipLayout
anchors {
left: parent.left
top: parent.top
margins: Style.smallMargins
}
Label {
text: toolTip.timestamp.toLocaleString(Qt.locale(), Locale.ShortFormat)
font: Style.smallFont
}
RowLayout {
Rectangle {
width: Style.extraSmallFont.pixelSize
height: width
color: consumptionSeries.color
}
Label {
property double rawValue: consumptionUpperSeries.at(toolTip.seriesIndex).y
property double displayValue: rawValue >= 1000 ? rawValue / 1000 : rawValue
property string unit: rawValue >= 1000 ? "kW" : "W"
text: "%1: %2 %3".arg(qsTr("Total")).arg(displayValue.toFixed(2)).arg(unit)
font: Style.extraSmallFont
}
}
Repeater {
model: consumers
delegate: RowLayout {
id: consumerToolTipDelegate
Rectangle {
width: Style.extraSmallFont.pixelSize
height: width
// color: index >= 0 ? root.colors[index % root.colors.length] : "white"
color: index >= 0 ? NymeaUtils.generateColor(Style.generationBaseColor, index) : "white"
}
Label {
property ThingPowerLogEntry entry: thingPowerLogs.find(model.id, toolTip.timestamp)
property double rawValue: entry ? entry.currentPower : 0
property double displayValue: rawValue >= 1000 ? rawValue / 1000 : rawValue
property string unit: rawValue >= 1000 ? "kW" : "W"
text: "%1: %2 %3".arg(model.name).arg(displayValue.toFixed(2)).arg(unit)
font: Style.extraSmallFont
}
}
}
}
}
}
}