More improvements on the energy view
Bring back title headers allow opening a single chart fullscreen allow selecting individual series in a chart
This commit is contained in:
parent
80f74e192f
commit
32853ce612
@ -281,5 +281,11 @@
|
||||
<file>ui/mainviews/energy/PowerBalanceHistory.qml</file>
|
||||
<file>ui/mainviews/energy/CurrentPowerBalancePieChart.qml</file>
|
||||
<file>ui/components/MultiSelectionTabs.qml</file>
|
||||
<file>ui/mainviews/energy/PowerBalanceHistoryPage.qml</file>
|
||||
<file>ui/mainviews/energy/CurrentPowerBalancePage.qml</file>
|
||||
<file>ui/mainviews/energy/PowerBalanceStatsPage.qml</file>
|
||||
<file>ui/mainviews/energy/ConsumersHistoryPage.qml</file>
|
||||
<file>ui/mainviews/energy/ConsumerStatsPage.qml</file>
|
||||
<file>ui/mainviews/energy/ConsumersPieChartPage.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -142,7 +142,7 @@ ApplicationWindow {
|
||||
property NymeaDiscovery nymeaDiscovery: NymeaDiscovery {
|
||||
objectName: "discovery"
|
||||
awsClient: AWSClient
|
||||
bluetoothDiscoveryEnabled: PlatformPermissions.bluetoothPermission === PlatformPermissions.PermissionStatusGranted
|
||||
bluetoothDiscoveryEnabled: false// PlatformPermissions.bluetoothPermission === PlatformPermissions.PermissionStatusGranted
|
||||
}
|
||||
|
||||
property var supportedInterfaces: [
|
||||
|
||||
@ -60,8 +60,6 @@ MainViewBase {
|
||||
engine: _engine
|
||||
}
|
||||
|
||||
property var thingColors: [Style.blue, Style.green, Style.red, Style.yellow, Style.purple, Style.orange, Style.lime, Style.pink, Style.darkBlue]
|
||||
|
||||
|
||||
ThingsProxy {
|
||||
id: energyMeters
|
||||
@ -169,7 +167,6 @@ MainViewBase {
|
||||
Layout.preferredHeight: width
|
||||
energyManager: energyManager
|
||||
visible: consumers.count > 0
|
||||
colors: root.thingColors
|
||||
consumers: consumers
|
||||
animationsEnabled: Qt.application.active && root.isCurrentItem && flickable.contentY < y + height && flickable.contentY + flickable.height > y
|
||||
onAnimationsEnabledChanged: print("animations for consumer balance chart", animationsEnabled ? "enabled" : "disabled")
|
||||
@ -180,7 +177,7 @@ MainViewBase {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
visible: consumers.count > 0
|
||||
colors: root.thingColors
|
||||
energyManager: energyManager
|
||||
consumers: consumers
|
||||
}
|
||||
|
||||
@ -189,7 +186,6 @@ MainViewBase {
|
||||
Layout.preferredHeight: width
|
||||
energyManager: energyManager
|
||||
visible: consumers.count > 0
|
||||
colors: root.thingColors
|
||||
consumers: consumers
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,9 +9,8 @@ StatsBase {
|
||||
id: root
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
property var colors: null
|
||||
|
||||
property ThingsProxy consumers: null
|
||||
property bool titleVisible: true
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
@ -20,6 +19,8 @@ StatsBase {
|
||||
|
||||
property int startOffset: 0
|
||||
|
||||
property Thing selectedThing: null
|
||||
|
||||
property date startTime: root.calculateTimestamp(config.startTime(), config.sampleRate, startOffset)
|
||||
property date endTime: root.calculateTimestamp(config.startTime(), config.sampleRate, startOffset + config.count)
|
||||
|
||||
@ -45,6 +46,14 @@ StatsBase {
|
||||
consumersRepeater.itemAt(i).refresh()
|
||||
}
|
||||
}
|
||||
|
||||
function selectThing(thing) {
|
||||
if (d.selectedThing === thing) {
|
||||
d.selectedThing = null
|
||||
} else {
|
||||
d.selectedThing = thing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThingPowerLogsLoader {
|
||||
@ -146,9 +155,11 @@ StatsBase {
|
||||
}
|
||||
|
||||
barSet = barSeries.append(consumerDelegate.thing.name, values)
|
||||
barSet.color = NymeaUtils.generateColor(Style.generationBaseColor, index)
|
||||
barSet.borderColor = barSet.color
|
||||
barSet.borderWith = 0
|
||||
barSet.color = Qt.binding(function() {
|
||||
return NymeaUtils.generateColor(Style.generationBaseColor, index, d.selectedThing == null || consumerDelegate.thing == d.selectedThing ? 1 : 0.3)
|
||||
})
|
||||
barSet.borderColor = Qt.binding(function(){ return barSet.color})
|
||||
barSet.borderWidth = 0
|
||||
}
|
||||
Component.onDestruction: {
|
||||
barSeries.remove(barSet)
|
||||
@ -160,12 +171,17 @@ StatsBase {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.margins: Style.smallMargins
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
// text: qsTr("Consumers totals")
|
||||
// }
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.smallMargins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Consumers totals")
|
||||
visible: root.titleVisible
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: pageStack.push(Qt.resolvedUrl("ConsumerStatsPage.qml"), {energyManager: root.energyManager, consumers: root.consumers})
|
||||
}
|
||||
}
|
||||
|
||||
SelectionTabs {
|
||||
id: selectionTabs
|
||||
@ -311,6 +327,7 @@ StatsBase {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: legend
|
||||
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||
anchors.leftMargin: chartView.plotArea.x
|
||||
height: Style.smallIconSize
|
||||
@ -318,17 +335,30 @@ StatsBase {
|
||||
|
||||
Repeater {
|
||||
model: root.consumers
|
||||
delegate: Item {
|
||||
delegate: MouseArea {
|
||||
id: legendDelegate
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
readonly property Thing thing: root.consumers.get(index)
|
||||
ColorIcon {
|
||||
name: app.interfacesToIcon(legendDelegate.thing.thingClass.interfaces)
|
||||
size: Style.smallIconSize
|
||||
color: index >= 0 ? NymeaUtils.generateColor(Style.generationBaseColor, index) : "white"
|
||||
onClicked: d.selectThing(thing)
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.smallMargins
|
||||
ColorIcon {
|
||||
name: app.interfacesToIcon(legendDelegate.thing.thingClass.interfaces)
|
||||
size: Style.smallIconSize
|
||||
color: index >= 0 ? NymeaUtils.generateColor(Style.generationBaseColor, index) : "white"
|
||||
}
|
||||
Label {
|
||||
text: legendDelegate.thing.name
|
||||
width: Math.max(0, legendDelegate.width - x)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
elide: Text.ElideRight
|
||||
font: Style.smallFont
|
||||
visible: legend.width / root.consumers.count >= 80
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -496,7 +526,7 @@ StatsBase {
|
||||
var consumerDelegate = consumersRepeater.itemAt(i)
|
||||
var consumer = consumerDelegate.thing
|
||||
var entry = {
|
||||
name: consumer.name,
|
||||
consumer: consumer,
|
||||
value: consumersRepeater.itemAt(i).barSet.at(toolTip.idx).toFixed(2),
|
||||
indexInModel: i
|
||||
}
|
||||
@ -518,14 +548,14 @@ StatsBase {
|
||||
}
|
||||
|
||||
delegate: RowLayout {
|
||||
opacity: d.selectedThing == null || d.selectedThing === model.consumer ? 1 : 0.3
|
||||
Rectangle {
|
||||
width: Style.extraSmallFont.pixelSize
|
||||
height: width
|
||||
// color: root.colors[model.indexInModel % root.colors.length]
|
||||
color: NymeaUtils.generateColor(Style.generationBaseColor, model.indexInModel)
|
||||
}
|
||||
Label {
|
||||
text: "%1: %2 kWh".arg(model.name).arg(model.value)
|
||||
text: "%1: %2 kWh".arg(model.consumer.name).arg(model.value)
|
||||
font: Style.extraSmallFont
|
||||
}
|
||||
}
|
||||
|
||||
24
nymea-app/ui/mainviews/energy/ConsumerStatsPage.qml
Normal file
24
nymea-app/ui/mainviews/energy/ConsumerStatsPage.qml
Normal file
@ -0,0 +1,24 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.2
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
property alias energyManager: consumersStats
|
||||
property alias consumers: consumersStats.consumers
|
||||
|
||||
header: NymeaHeader {
|
||||
text: qsTr("Consumers balance")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
ConsumerStats {
|
||||
id: consumersStats
|
||||
anchors.fill: parent
|
||||
titleVisible: false
|
||||
}
|
||||
}
|
||||
@ -8,8 +8,9 @@ import "qrc:/ui/components"
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var colors: null
|
||||
property EnergyManager energyManager: null
|
||||
property ThingsProxy consumers: null
|
||||
property bool titleVisible: true
|
||||
|
||||
PowerBalanceLogs {
|
||||
id: powerBalanceLogs
|
||||
@ -53,6 +54,8 @@ Item {
|
||||
|
||||
property date now: new Date()
|
||||
|
||||
property var selectedSeries: null
|
||||
|
||||
readonly property int range: selectionTabs.currentValue.range
|
||||
readonly property int sampleRate: selectionTabs.currentValue.sampleRate
|
||||
readonly property int visibleValues: range / sampleRate
|
||||
@ -95,6 +98,15 @@ Item {
|
||||
logsLoader.fetchLogs();
|
||||
}
|
||||
}
|
||||
|
||||
function selectSeries(series) {
|
||||
print("selecting series", series)
|
||||
if (d.selectedSeries === series) {
|
||||
d.selectedSeries = null
|
||||
} else {
|
||||
d.selectedSeries = series
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
@ -111,12 +123,17 @@ Item {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.margins: Style.smallMargins
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
// text: qsTr("Consumers history")
|
||||
// }
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.smallMargins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Consumers history")
|
||||
visible: root.titleVisible
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: pageStack.push(Qt.resolvedUrl("ConsumersHistoryPage.qml"), {energyManager: root.energyManager, consumers: root.consumers})
|
||||
}
|
||||
}
|
||||
|
||||
SelectionTabs {
|
||||
id: selectionTabs
|
||||
@ -456,8 +473,11 @@ Item {
|
||||
series.lowerSeries = lineSeriesComponent.createObject(series)
|
||||
series.upperSeries = lineSeriesComponent.createObject(series)
|
||||
series.color = NymeaUtils.generateColor(Style.generationBaseColor, index)
|
||||
series.opacity = Qt.binding(function() {
|
||||
return d.selectedSeries == null || d.selectedSeries == series ? 1 : 0.3
|
||||
})
|
||||
series.borderWidth = 0;
|
||||
series.borderColor = series.color
|
||||
series.borderColor = series.color
|
||||
|
||||
// Add a first point at 0 value
|
||||
series.lowerSeries.insert(0, new Date().getTime(), 0)
|
||||
@ -472,6 +492,7 @@ Item {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: legend
|
||||
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||
anchors.leftMargin: chartView.plotArea.x
|
||||
height: Style.smallIconSize
|
||||
@ -479,23 +500,34 @@ Item {
|
||||
|
||||
Repeater {
|
||||
model: root.consumers
|
||||
delegate: Item {
|
||||
delegate: MouseArea {
|
||||
id: legendDelegate
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
readonly property Thing thing: root.consumers.get(index)
|
||||
ColorIcon {
|
||||
name: app.interfacesToIcon(legendDelegate.thing.thingClass.interfaces)
|
||||
size: Style.smallIconSize
|
||||
color: index >= 0 ? NymeaUtils.generateColor(Style.generationBaseColor, index) : "white"
|
||||
onClicked: d.selectSeries(consumersRepeater.itemAt(index).series)
|
||||
opacity: d.selectedSeries == null || d.selectedSeries === consumersRepeater.itemAt(index).series ? 1 : 0.3
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.smallMargins
|
||||
ColorIcon {
|
||||
name: app.interfacesToIcon(legendDelegate.thing.thingClass.interfaces)
|
||||
size: Style.smallIconSize
|
||||
color: index >= 0 ? NymeaUtils.generateColor(Style.generationBaseColor, index) : "white"
|
||||
}
|
||||
Label {
|
||||
text: legendDelegate.thing.name
|
||||
width: Math.max(0, legendDelegate.width - x)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
elide: Text.ElideRight
|
||||
font: Style.smallFont
|
||||
visible: legend.width / root.consumers.count >= 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
@ -665,20 +697,21 @@ Item {
|
||||
Repeater {
|
||||
model: consumersRepeater.count
|
||||
delegate: RowLayout {
|
||||
readonly property Item chartItem: consumersRepeater.itemAt(index)
|
||||
id: consumerToolTipDelegate
|
||||
opacity: d.selectedSeries == null || d.selectedSeries === chartItem.series ? 1 : 0.3
|
||||
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: toolTip.idx >= 0 ? consumersRepeater.itemAt(index).logs.find(toolTip.timestamp) : null
|
||||
property ThingPowerLogEntry entry: toolTip.idx >= 0 ? chartItem.logs.find(toolTip.timestamp) : null
|
||||
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(consumersRepeater.itemAt(index).thing.name).arg(displayValue.toFixed(2)).arg(unit)
|
||||
text: "%1: %2 %3".arg(chartItem.thing.name).arg(displayValue.toFixed(2)).arg(unit)
|
||||
font: Style.extraSmallFont
|
||||
}
|
||||
}
|
||||
|
||||
24
nymea-app/ui/mainviews/energy/ConsumersHistoryPage.qml
Normal file
24
nymea-app/ui/mainviews/energy/ConsumersHistoryPage.qml
Normal file
@ -0,0 +1,24 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.2
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
property alias energyManager: consumersHistory
|
||||
property alias consumers: consumersHistory.consumers
|
||||
|
||||
header: NymeaHeader {
|
||||
text: qsTr("Power balance totals")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
ConsumersHistory {
|
||||
id: consumersHistory
|
||||
anchors.fill: parent
|
||||
titleVisible: false
|
||||
}
|
||||
}
|
||||
@ -7,23 +7,13 @@ import QtCharts 2.2
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
ChartView {
|
||||
Item {
|
||||
id: root
|
||||
backgroundColor: "transparent"
|
||||
animationOptions: animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||
// title: qsTr("Consumers balance")
|
||||
titleColor: Style.foregroundColor
|
||||
legend.visible: false
|
||||
|
||||
margins.left: 0
|
||||
margins.right: 0
|
||||
margins.bottom: 0
|
||||
margins.top: 0
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
property ThingsProxy consumers: null
|
||||
property var colors: null
|
||||
property bool animationsEnabled: true
|
||||
property bool titleVisible: true
|
||||
|
||||
readonly property Thing rootMeter: engine.thingManager.fetchingData ? null : engine.thingManager.things.getThing(energyManager.rootMeterId)
|
||||
onRootMeterChanged: updateConsumers()
|
||||
@ -72,7 +62,7 @@ ChartView {
|
||||
}
|
||||
|
||||
function updateConsumers() {
|
||||
root.animationOptions = ChartView.NoAnimation
|
||||
chart.animationOptions = ChartView.NoAnimation
|
||||
consumersBalanceSeries.clear();
|
||||
d.unknownSlice = null
|
||||
d.idleSlice = null
|
||||
@ -115,131 +105,164 @@ ChartView {
|
||||
|
||||
d.thingsColorMap = colorMap
|
||||
|
||||
root.animationOptions = Qt.binding(function() {
|
||||
chart.animationOptions = Qt.binding(function() {
|
||||
return root.animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||
})
|
||||
}
|
||||
|
||||
PieSeries {
|
||||
id: consumersBalanceSeries
|
||||
size: 0.88
|
||||
holeSize: 0.7
|
||||
Label {
|
||||
id: titleLabel
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right; margins: Style.smallMargins }
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Consumers balance")
|
||||
visible: root.titleVisible
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("ConsumersPieChartPage.qml"), {energyManager: root.energyManager, consumers: root.consumers})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: centerLayout
|
||||
x: root.plotArea.x + (root.plotArea.width - width) / 2
|
||||
y: root.plotArea.y + (root.plotArea.height - height) / 2
|
||||
width: Math.min(root.plotArea.width, root.plotArea.width) * 0.65
|
||||
height: Math.min(contentColumn.height + topMargin + bottomMargin, width)
|
||||
topMargin: Style.smallIconSize
|
||||
bottomMargin: Style.smallIconSize
|
||||
opacity: 0
|
||||
// property int maximumHeight: root.plotArea.height * 0.65
|
||||
|
||||
contentHeight: contentColumn.implicitHeight
|
||||
ChartView {
|
||||
id: chart
|
||||
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
width: parent.width
|
||||
spacing: Style.smallMargins
|
||||
anchors { left: parent.left; right: parent.right; bottom: parent.bottom; top: titleLabel.bottom}
|
||||
|
||||
backgroundColor: "transparent"
|
||||
animationOptions: animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||
titleColor: Style.foregroundColor
|
||||
legend.visible: false
|
||||
|
||||
margins.left: 0
|
||||
margins.right: 0
|
||||
margins.bottom: 0
|
||||
margins.top: 0
|
||||
|
||||
|
||||
PieSeries {
|
||||
id: consumersBalanceSeries
|
||||
size: 0.88
|
||||
holeSize: 0.7
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: centerLayout
|
||||
x: chart.plotArea.x + (chart.plotArea.width - width) / 2
|
||||
y: chart.plotArea.y + (chart.plotArea.height - height) / 2
|
||||
width: Math.min(chart.plotArea.width, chart.plotArea.width) * 0.65
|
||||
height: Math.min(contentColumn.height + topMargin + bottomMargin, width)
|
||||
topMargin: Style.smallIconSize
|
||||
bottomMargin: Style.smallIconSize
|
||||
opacity: 0
|
||||
// property int maximumHeight: chart.plotArea.height * 0.65
|
||||
|
||||
contentHeight: contentColumn.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
visible: root.rootMeter
|
||||
Label {
|
||||
text: qsTr("Total")
|
||||
font: Style.smallFont
|
||||
Layout.topMargin: Style.smallMargins
|
||||
id: contentColumn
|
||||
width: parent.width
|
||||
spacing: Style.smallMargins
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
// We're using the maximum value of the energy managers consumption, the sum of all consumers because:
|
||||
// * in a standard setup, the energy manager would know everything and the consumption will always be greater than the sum of all individual consumers
|
||||
// * if there is a producer which is unknown to nymea though, it will decrease the consumption on the root meter so it may be smaller than the
|
||||
// summation of all consumers. In this particular chart that would be nonsense so in the end we'll only lose the "unknown" power consumption in such a setup
|
||||
property double finalTotal: Math.max(energyManager.currentPowerConsumption, d.consumersSummation)
|
||||
text: "%1 %2"
|
||||
.arg((finalTotal / (finalTotal > 1000 ? 1000 : 1)).toFixed(1))
|
||||
.arg(finalTotal > 1000 ? "kW" : "W")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font: Style.bigFont
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: ThingsProxy {
|
||||
id: sortedConsumers
|
||||
engine: _engine
|
||||
parentProxy: root.consumers
|
||||
sortStateName: "currentPower"
|
||||
sortOrder: Qt.DescendingOrder
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: consumerDelegate
|
||||
width: parent ? parent.width : 0
|
||||
spacing: 0
|
||||
property Thing consumer: consumers.getThing(model.id)
|
||||
property State currentPowerState: consumer ? consumer.stateByName("currentPower") : null
|
||||
property double value: currentPowerState ? currentPowerState.value : 0
|
||||
visible: root.rootMeter
|
||||
Label {
|
||||
text: qsTr("Total")
|
||||
font: Style.smallFont
|
||||
Layout.topMargin: Style.smallMargins
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
text: model.name
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font: Style.extraSmallFont
|
||||
}
|
||||
Label {
|
||||
color: d.thingsColorMap.hasOwnProperty(consumer) ? d.thingsColorMap[consumer] : "transparent"
|
||||
// We're using the maximum value of the energy managers consumption, the sum of all consumers because:
|
||||
// * in a standard setup, the energy manager would know everything and the consumption will always be greater than the sum of all individual consumers
|
||||
// * if there is a producer which is unknown to nymea though, it will decrease the consumption on the root meter so it may be smaller than the
|
||||
// summation of all consumers. In this particular chart that would be nonsense so in the end we'll only lose the "unknown" power consumption in such a setup
|
||||
property double finalTotal: Math.max(energyManager.currentPowerConsumption, d.consumersSummation)
|
||||
text: "%1 %2"
|
||||
.arg((consumerDelegate.value / (consumerDelegate.value > 1000 ? 1000 : 1)).toFixed(1))
|
||||
.arg(consumerDelegate.value > 1000 ? "kW" : "W")
|
||||
.arg((finalTotal / (finalTotal > 1000 ? 1000 : 1)).toFixed(1))
|
||||
.arg(finalTotal > 1000 ? "kW" : "W")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font: Style.smallFont
|
||||
font: Style.bigFont
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: ThingsProxy {
|
||||
id: sortedConsumers
|
||||
engine: _engine
|
||||
parentProxy: root.consumers
|
||||
sortStateName: "currentPower"
|
||||
sortOrder: Qt.DescendingOrder
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: consumerDelegate
|
||||
width: parent ? parent.width : 0
|
||||
spacing: 0
|
||||
property Thing consumer: consumers.getThing(model.id)
|
||||
property State currentPowerState: consumer ? consumer.stateByName("currentPower") : null
|
||||
property double value: currentPowerState ? currentPowerState.value : 0
|
||||
|
||||
Label {
|
||||
text: model.name
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font: Style.extraSmallFont
|
||||
}
|
||||
Label {
|
||||
color: d.thingsColorMap.hasOwnProperty(consumer) ? d.thingsColorMap[consumer] : "transparent"
|
||||
text: "%1 %2"
|
||||
.arg((consumerDelegate.value / (consumerDelegate.value > 1000 ? 1000 : 1)).toFixed(1))
|
||||
.arg(consumerDelegate.value > 1000 ? "kW" : "W")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: innerMask
|
||||
anchors.fill: centerLayout
|
||||
radius: width / 2
|
||||
visible: false
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0; color: "transparent" }
|
||||
GradientStop { position: 1-(centerLayout.height - downArrow.height * 1.5) / centerLayout.height; color: "red" }
|
||||
GradientStop { position: (centerLayout.height - downArrow.height * 1.5) / centerLayout.height; color: "red" }
|
||||
GradientStop { position: 1; color: "transparent" }
|
||||
Rectangle {
|
||||
id: innerMask
|
||||
anchors.fill: centerLayout
|
||||
radius: width / 2
|
||||
visible: false
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0; color: "transparent" }
|
||||
GradientStop { position: 1-(centerLayout.height - downArrow.height * 1.5) / centerLayout.height; color: "red" }
|
||||
GradientStop { position: (centerLayout.height - downArrow.height * 1.5) / centerLayout.height; color: "red" }
|
||||
GradientStop { position: 1; color: "transparent" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpacityMask {
|
||||
anchors.fill: centerLayout
|
||||
source: centerLayout
|
||||
maskSource: innerMask
|
||||
}
|
||||
OpacityMask {
|
||||
anchors.fill: centerLayout
|
||||
source: centerLayout
|
||||
maskSource: innerMask
|
||||
}
|
||||
|
||||
ColorIcon {
|
||||
id: upArrow
|
||||
anchors { top: centerLayout.top; horizontalCenter: centerLayout.horizontalCenter }
|
||||
size: Style.smallIconSize
|
||||
name: "up"
|
||||
visible: !centerLayout.atYBeginning
|
||||
}
|
||||
ColorIcon {
|
||||
id: downArrow
|
||||
anchors { bottom: centerLayout.bottom; horizontalCenter: centerLayout.horizontalCenter }
|
||||
size: Style.smallIconSize
|
||||
name: "down"
|
||||
visible: !centerLayout.atYEnd
|
||||
ColorIcon {
|
||||
id: upArrow
|
||||
anchors { top: centerLayout.top; horizontalCenter: centerLayout.horizontalCenter }
|
||||
size: Style.smallIconSize
|
||||
name: "up"
|
||||
visible: !centerLayout.atYBeginning
|
||||
}
|
||||
ColorIcon {
|
||||
id: downArrow
|
||||
anchors { bottom: centerLayout.bottom; horizontalCenter: centerLayout.horizontalCenter }
|
||||
size: Style.smallIconSize
|
||||
name: "down"
|
||||
visible: !centerLayout.atYEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
nymea-app/ui/mainviews/energy/ConsumersPieChartPage.qml
Normal file
24
nymea-app/ui/mainviews/energy/ConsumersPieChartPage.qml
Normal file
@ -0,0 +1,24 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.2
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
property alias energyManager: consumersPieChart.energyManager
|
||||
property alias consumers: consumersPieChart.consumers
|
||||
|
||||
header: NymeaHeader {
|
||||
text: qsTr("Consumers balance")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
ConsumersPieChart {
|
||||
id: consumersPieChart
|
||||
anchors.fill: parent
|
||||
titleVisible: false
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,7 @@ ChartView {
|
||||
id: consumptionPieChart
|
||||
backgroundColor: "transparent"
|
||||
animationOptions: animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||
title: qsTr("My energy mix")
|
||||
title: qsTr("My energy consumption")
|
||||
titleColor: Style.foregroundColor
|
||||
legend.visible: false
|
||||
|
||||
|
||||
41
nymea-app/ui/mainviews/energy/CurrentPowerBalancePage.qml
Normal file
41
nymea-app/ui/mainviews/energy/CurrentPowerBalancePage.qml
Normal file
@ -0,0 +1,41 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.2
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
property ThingsProxy consumers: null
|
||||
property ThingsProxy producers: null
|
||||
|
||||
header: NymeaHeader {
|
||||
text: qsTr("My energy mix")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
columns: app.landscape ? 2 : 1
|
||||
|
||||
CurrentConsumptionBalancePieChart {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
energyManager: root.energyManager
|
||||
visible: root.producers.count > 0
|
||||
animationsEnabled: Qt.application.active
|
||||
}
|
||||
CurrentProductionBalancePieChart {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
energyManager: root.energyManager
|
||||
visible: root.producers.count > 0
|
||||
animationsEnabled: Qt.application.active
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,8 @@ import "qrc:/ui/components"
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool titleVisible: true
|
||||
|
||||
PowerBalanceLogs {
|
||||
id: powerBalanceLogs
|
||||
engine: _engine
|
||||
@ -26,6 +28,8 @@ Item {
|
||||
id: d
|
||||
property date now: new Date()
|
||||
|
||||
property var selectedSeries: null
|
||||
|
||||
readonly property int range: selectionTabs.currentValue.range
|
||||
readonly property int sampleRate: selectionTabs.currentValue.sampleRate
|
||||
readonly property int visibleValues: range / sampleRate
|
||||
@ -63,6 +67,13 @@ Item {
|
||||
return timestamp
|
||||
}
|
||||
|
||||
function selectSeries(series) {
|
||||
if (d.selectedSeries == series) {
|
||||
d.selectedSeries = null
|
||||
} else {
|
||||
d.selectedSeries = series
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
@ -105,12 +116,20 @@ Item {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.margins: Style.smallMargins
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
// text: qsTr("My production history")
|
||||
// }
|
||||
Label {
|
||||
id: titleLabel
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.smallMargins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("My power balance history")
|
||||
visible: root.titleVisible
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("PowerBalanceHistoryPage.qml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SelectionTabs {
|
||||
id: selectionTabs
|
||||
@ -265,6 +284,7 @@ Item {
|
||||
shadesVisible: false
|
||||
labelsColor: Style.foregroundColor
|
||||
}
|
||||
|
||||
AreaSeries {
|
||||
id: selfProductionConsumptionSeries
|
||||
axisX: dateTimeAxis
|
||||
@ -273,8 +293,10 @@ Item {
|
||||
// borderWidth: 2
|
||||
borderColor: color
|
||||
name: qsTr("From self production")
|
||||
opacity: d.selectedSeries == null || d.selectedSeries == selfProductionConsumptionSeries ? 1 : 0.3
|
||||
// visible: false
|
||||
|
||||
onClicked: d.selectedSeries(selfProductionConsumptionSeries)
|
||||
lowerSeries: LineSeries {
|
||||
id: zeroSeries
|
||||
XYPoint { x: dateTimeAxis.min.getTime(); y: 0 }
|
||||
@ -331,9 +353,11 @@ Item {
|
||||
color: Style.purple
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
opacity: d.selectedSeries == null || d.selectedSeries == toStorageSeries ? 1 : 0.3
|
||||
visible: root.batteries.count > 0
|
||||
name: qsTr("To battery")
|
||||
|
||||
onClicked: d.selectSeries(toStorageSeries)
|
||||
|
||||
function calculateValue(entry) {
|
||||
return selfProductionConsumptionSeries.calculateValue(entry) + Math.max(0, entry.storage);
|
||||
@ -352,7 +376,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AreaSeries {
|
||||
id: returnSeries
|
||||
axisX: dateTimeAxis
|
||||
@ -361,8 +384,11 @@ Item {
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
name: qsTr("To grid")
|
||||
opacity: d.selectedSeries == null || d.selectedSeries == returnSeries ? 1 : 0.3
|
||||
// visible: false
|
||||
|
||||
onClicked: d.selectSeries(returnSeries)
|
||||
|
||||
function calculateValue(entry) {
|
||||
return toStorageSeries.calculateValue(entry) + Math.max(0, -entry.acquisition)
|
||||
}
|
||||
@ -387,8 +413,10 @@ Item {
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
name: qsTr("From battery")
|
||||
opacity: d.selectedSeries == null || d.selectedSeries == fromStorageSeries ? 1 : 0.3
|
||||
visible: root.batteries.count > 0
|
||||
|
||||
onClicked: d.selectSeries(fromStorageSeries)
|
||||
lowerSeries: selfProductionConsumptionUpperSeries
|
||||
upperSeries: LineSeries {
|
||||
id: fromStorageUpperSeries
|
||||
@ -406,7 +434,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AreaSeries {
|
||||
id: acquisitionSeries
|
||||
axisX: dateTimeAxis
|
||||
@ -415,8 +442,11 @@ Item {
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
name: qsTr("From grid")
|
||||
opacity: d.selectedSeries == null || d.selectedSeries == acquisitionSeries ? 1 : 0.3
|
||||
// visible: false
|
||||
|
||||
onClicked: d.selectSeries(acquisitionSeries)
|
||||
|
||||
lowerSeries: fromStorageUpperSeries
|
||||
upperSeries: LineSeries {
|
||||
id: acquisitionUpperSeries
|
||||
@ -476,89 +506,158 @@ Item {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: legend
|
||||
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||
anchors.leftMargin: chartView.plotArea.x
|
||||
height: Style.smallIconSize
|
||||
anchors.margins: Style.margins
|
||||
|
||||
Item {
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
ColorIcon {
|
||||
name: "weathericons/weather-clear-day"
|
||||
size: Style.smallIconSize
|
||||
color: Style.green
|
||||
onClicked: d.selectSeries(selfProductionConsumptionSeries)
|
||||
opacity: selfProductionConsumptionSeries.opacity
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.smallMargins
|
||||
ColorIcon {
|
||||
name: "weathericons/weather-clear-day"
|
||||
size: Style.smallIconSize
|
||||
color: Style.green
|
||||
}
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("Produced")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
onClicked: d.selectSeries(acquisitionSeries)
|
||||
opacity: acquisitionSeries.opacity
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
spacing: Style.smallMargins
|
||||
Row {
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-down"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
}
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-down"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("From grid")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
onClicked: d.selectSeries(returnSeries)
|
||||
opacity: returnSeries.opacity
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
spacing: Style.smallMargins
|
||||
Row {
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-up"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
}
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-up"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("To grid")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: batteries.count > 0
|
||||
onClicked: d.selectSeries(toStorageSeries)
|
||||
opacity: toStorageSeries.opacity
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
ColorIcon {
|
||||
name: "battery/battery-080"
|
||||
size: Style.smallIconSize
|
||||
color: Style.purple
|
||||
spacing: Style.smallMargins
|
||||
Row {
|
||||
ColorIcon {
|
||||
name: "battery/battery-080"
|
||||
size: Style.smallIconSize
|
||||
color: Style.purple
|
||||
}
|
||||
ColorIcon {
|
||||
name: "plus"
|
||||
size: Style.smallIconSize
|
||||
color: Style.purple
|
||||
}
|
||||
}
|
||||
ColorIcon {
|
||||
name: "plus"
|
||||
size: Style.smallIconSize
|
||||
color: Style.purple
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("To battery")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: batteries.count > 0
|
||||
onClicked: d.selectSeries(fromStorageSeries)
|
||||
opacity: fromStorageSeries.opacity
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
ColorIcon {
|
||||
name: "battery/battery-040"
|
||||
size: Style.smallIconSize
|
||||
color: Style.orange
|
||||
spacing: Style.smallMargins
|
||||
Row {
|
||||
ColorIcon {
|
||||
name: "battery/battery-040"
|
||||
size: Style.smallIconSize
|
||||
color: Style.orange
|
||||
}
|
||||
ColorIcon {
|
||||
name: "minus"
|
||||
size: Style.smallIconSize
|
||||
color: Style.orange
|
||||
}
|
||||
}
|
||||
ColorIcon {
|
||||
name: "minus"
|
||||
size: Style.smallIconSize
|
||||
color: Style.orange
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("From battery")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -574,6 +673,7 @@ Item {
|
||||
|
||||
hoverEnabled: true
|
||||
preventStealing: tooltipping || dragging
|
||||
propagateComposedEvents: true
|
||||
|
||||
property int startMouseX: 0
|
||||
property bool dragging: false
|
||||
|
||||
21
nymea-app/ui/mainviews/energy/PowerBalanceHistoryPage.qml
Normal file
21
nymea-app/ui/mainviews/energy/PowerBalanceHistoryPage.qml
Normal file
@ -0,0 +1,21 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.2
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
header: NymeaHeader {
|
||||
text: qsTr("My power balance history")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
PowerBalanceHistory {
|
||||
id: powerBalanceHistory
|
||||
anchors.fill: parent
|
||||
titleVisible: false
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,8 @@ StatsBase {
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
|
||||
property bool titleVisible: true
|
||||
|
||||
property ThingsProxy producers: ThingsProxy {
|
||||
engine: _engine
|
||||
shownInterfaces: ["smartmeterproducer"]
|
||||
@ -22,6 +24,8 @@ StatsBase {
|
||||
property var config: root.configs[selectionTabs.currentValue.config]
|
||||
property int startOffset: 0
|
||||
|
||||
property var selectedSet: null
|
||||
|
||||
property date startTime: root.calculateTimestamp(config.startTime(), config.sampleRate, startOffset)
|
||||
property date endTime: root.calculateTimestamp(config.startTime(), config.sampleRate, startOffset + config.count)
|
||||
|
||||
@ -38,6 +42,14 @@ StatsBase {
|
||||
refresh()
|
||||
}
|
||||
|
||||
function selectSet(set) {
|
||||
if (d.selectedSet === set) {
|
||||
d.selectedSet = null
|
||||
} else {
|
||||
d.selectedSet = set
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
if (powerBalanceLogs.loadingInhibited) {
|
||||
return;
|
||||
@ -106,12 +118,17 @@ StatsBase {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.margins: Style.smallMargins
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
// text: qsTr("Totals")
|
||||
// }
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.smallMargins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Totals")
|
||||
visible: root.titleVisible
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: pageStack.push(Qt.resolvedUrl("PowerBalanceStatsPage.qml"), {energyManager: root.energyManager, producers: root.producers})
|
||||
}
|
||||
}
|
||||
|
||||
SelectionTabs {
|
||||
id: selectionTabs
|
||||
@ -278,7 +295,7 @@ StatsBase {
|
||||
BarSet {
|
||||
id: consumptionSet
|
||||
label: qsTr("Consumed")
|
||||
color: Style.blue
|
||||
color: Qt.rgba(Style.blue.r, Style.blue.g, Style.blue.b, d.selectedSet == null || d.selectedSet == consumptionSet ? 1 : 0.3)
|
||||
borderColor: color
|
||||
borderWidth: 0
|
||||
values: {
|
||||
@ -292,7 +309,7 @@ StatsBase {
|
||||
BarSet {
|
||||
id: productionSet
|
||||
label: qsTr("Produced")
|
||||
color: Style.green
|
||||
color: Qt.rgba(Style.green.r, Style.green.g, Style.green.b, d.selectedSet == null || d.selectedSet == productionSet ? 1 : 0.3)
|
||||
borderColor: color
|
||||
borderWidth: 0
|
||||
values: {
|
||||
@ -306,7 +323,7 @@ StatsBase {
|
||||
BarSet {
|
||||
id: acquisitionSet
|
||||
label: qsTr("From grid")
|
||||
color: Style.red
|
||||
color: Qt.rgba(Style.red.r, Style.red.g, Style.red.b, d.selectedSet == null || d.selectedSet == acquisitionSet ? 1 : 0.3)
|
||||
borderColor: color
|
||||
borderWidth: 0
|
||||
values: {
|
||||
@ -320,7 +337,7 @@ StatsBase {
|
||||
BarSet {
|
||||
id: returnSet
|
||||
label: qsTr("To grid")
|
||||
color: Style.yellow
|
||||
color: Qt.rgba(Style.yellow.r, Style.yellow.g, Style.yellow.b, d.selectedSet == null || d.selectedSet == returnSet ? 1 : 0.3)
|
||||
borderColor: color
|
||||
borderWidth: 0
|
||||
values: {
|
||||
@ -335,64 +352,113 @@ StatsBase {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: legend
|
||||
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||
anchors.leftMargin: chartView.plotArea.x
|
||||
height: Style.smallIconSize
|
||||
anchors.margins: Style.margins
|
||||
|
||||
Item {
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
ColorIcon {
|
||||
name: "powersocket"
|
||||
size: Style.smallIconSize
|
||||
color: Style.blue
|
||||
onClicked: d.selectSet(consumptionSet)
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.smallMargins
|
||||
ColorIcon {
|
||||
name: "powersocket"
|
||||
size: Style.smallIconSize
|
||||
color: Style.blue
|
||||
}
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("Consumed")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
ColorIcon {
|
||||
name: "weathericons/weather-clear-day"
|
||||
size: Style.smallIconSize
|
||||
color: Style.green
|
||||
onClicked: d.selectSet(productionSet)
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.smallMargins
|
||||
ColorIcon {
|
||||
name: "weathericons/weather-clear-day"
|
||||
size: Style.smallIconSize
|
||||
color: Style.green
|
||||
}
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("Produced")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
onClicked: d.selectSet(acquisitionSet)
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
spacing: Style.smallMargins
|
||||
Row {
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-down"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
}
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-down"
|
||||
size: Style.smallIconSize
|
||||
color: Style.red
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("From grid")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
MouseArea {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
onClicked: d.selectSet(returnSet)
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
spacing: Style.smallMargins
|
||||
Row {
|
||||
ColorIcon {
|
||||
name: "power-grid"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-up"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
}
|
||||
}
|
||||
ColorIcon {
|
||||
name: "arrow-up"
|
||||
size: Style.smallIconSize
|
||||
color: Style.yellow
|
||||
Label {
|
||||
width: parent.parent.width - x
|
||||
elide: Text.ElideRight
|
||||
visible: legend.width > 500
|
||||
text: qsTr("To grid")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: Style.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -564,7 +630,7 @@ StatsBase {
|
||||
Rectangle {
|
||||
width: Style.extraSmallFont.pixelSize
|
||||
height: width
|
||||
color: Style.yellow
|
||||
color: Style.green
|
||||
}
|
||||
Label {
|
||||
text: d.startOffset !== undefined ? qsTr("Produced: %1 kWh").arg(productionSet.at(toolTip.idx).toFixed(2)) : ""
|
||||
@ -586,7 +652,7 @@ StatsBase {
|
||||
Rectangle {
|
||||
width: Style.extraSmallFont.pixelSize
|
||||
height: width
|
||||
color: Style.green
|
||||
color: Style.yellow
|
||||
}
|
||||
Label {
|
||||
text: d.startOffset !== undefined ? qsTr("To grid: %1 kWh").arg(returnSet.at(toolTip.idx).toFixed(2)) : ""
|
||||
|
||||
24
nymea-app/ui/mainviews/energy/PowerBalanceStatsPage.qml
Normal file
24
nymea-app/ui/mainviews/energy/PowerBalanceStatsPage.qml
Normal file
@ -0,0 +1,24 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.2
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
property alias energyManager: powerBalanceStats
|
||||
property alias producers: powerBalanceStats.producers
|
||||
|
||||
header: NymeaHeader {
|
||||
text: qsTr("Power balance totals")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
PowerBalanceStats {
|
||||
id: powerBalanceStats
|
||||
anchors.fill: parent
|
||||
titleVisible: false
|
||||
}
|
||||
}
|
||||
@ -154,7 +154,7 @@ Item {
|
||||
property bool inhibitChartsAnimation: PlatformHelper.deviceModel.startsWith("SM-G950") // Samsung S8 has a buggy GPU driver :(
|
||||
property int chartsAnimationOptions: !inhibitChartsAnimation ? ChartView.SeriesAnimations : ChartView.NoAnimation
|
||||
|
||||
function generateColor(baseColor, index) {
|
||||
function generateColor(baseColor, index, alpha) {
|
||||
var stepSize = 30
|
||||
var baseHSV = rgb2hsv(baseColor.r, baseColor.g, baseColor.b)
|
||||
var currentHue = baseHSV[0]
|
||||
@ -170,7 +170,7 @@ Item {
|
||||
}
|
||||
handledColors.push(currentHue)
|
||||
}
|
||||
return Qt.hsva(currentHue / 360, baseHSV[1], baseHSV[2], 1);
|
||||
return Qt.hsva(currentHue / 360, baseHSV[1], baseHSV[2], alpha || 1);
|
||||
}
|
||||
|
||||
function rgb2hsv(r,g,b) {
|
||||
|
||||
Reference in New Issue
Block a user