Implemented a visualization screen for various board parameters
This commit is contained in:
11
main.cpp
11
main.cpp
@@ -22,7 +22,7 @@
|
||||
#include "utility.h"
|
||||
#include "mobile/fwhelper.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QApplication>
|
||||
#include <QFontDatabase>
|
||||
#include <QQmlApplicationEngine>
|
||||
|
||||
@@ -51,10 +51,15 @@ int main(int argc, char *argv[])
|
||||
QCoreApplication::setOrganizationDomain("Cubo.rus");
|
||||
QCoreApplication::setApplicationName("Cubo Verde BMS Tool");
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QFontDatabase::addApplicationFont("://res/fonts/Artifakt-Element.ttf");
|
||||
app.setFont(QFont("Artifakt Element", 16, QFont::Medium));
|
||||
|
||||
QFont font("Artifakt Element", 16, QFont::Normal);
|
||||
font.setStyleStrategy(QFont::PreferAntialias);
|
||||
app.setFont(font);
|
||||
|
||||
// app.setFont(QFont("Artifakt Element", 16, QFont::Medium));
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Button {
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
opacity: enabled ? 1.0 : 0.3
|
||||
color: Palette.alternativeTextColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
100
qml/Controls/ChartView.qml
Normal file
100
qml/Controls/ChartView.qml
Normal file
@@ -0,0 +1,100 @@
|
||||
import QtQuick 2.12
|
||||
import QtCharts 2.3
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
ChartView {
|
||||
id: chart
|
||||
|
||||
antialiasing: true
|
||||
backgroundColor: Palette.backgroundColor
|
||||
margins.left: 20
|
||||
|
||||
legend.visible: false
|
||||
legend.alignment: Qt.AlignRight
|
||||
legend.markerShape: Legend.MarkerShapeCircle
|
||||
|
||||
property AbstractAxis xAxis: valueAxisX
|
||||
property AbstractAxis yAxis: valueAxisY
|
||||
|
||||
property int defaultXMax: 10
|
||||
property int defaultYMax: 1
|
||||
property bool autoScaling: true
|
||||
|
||||
ValueAxis {
|
||||
id: valueAxisX
|
||||
min: 0
|
||||
max: chart.defaultXMax
|
||||
tickCount: 8
|
||||
gridVisible: false
|
||||
gridLineColor: Palette.borderColor
|
||||
labelsColor: Palette.contentTextColor
|
||||
labelsFont.pixelSize: 18
|
||||
color: Palette.borderColor
|
||||
titleVisible: false
|
||||
}
|
||||
|
||||
ValueAxis {
|
||||
id: valueAxisY
|
||||
min: 0
|
||||
max: chart.defaultYMax
|
||||
tickCount: 6
|
||||
labelsColor: Palette.contentTextColor
|
||||
labelsFont.pixelSize: 18
|
||||
color: Palette.borderColor
|
||||
titleVisible: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: chartMouseAreaA
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
|
||||
property real lastMouseX: 0
|
||||
property real lastMouseY: 0
|
||||
|
||||
property real scrollThreshold: 0
|
||||
|
||||
onMouseXChanged: {
|
||||
if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
|
||||
if (mouseX - lastMouseX > scrollThreshold) {
|
||||
chart.scrollLeft(mouseX - lastMouseX)
|
||||
lastMouseX = mouseX
|
||||
chart.autoScaling = false
|
||||
} else if (mouseX - lastMouseX < scrollThreshold) {
|
||||
chart.scrollRight(lastMouseX - mouseX)
|
||||
lastMouseX = mouseX
|
||||
chart.autoScaling = false
|
||||
}
|
||||
}
|
||||
}
|
||||
onMouseYChanged: {
|
||||
if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
|
||||
if (mouseY - lastMouseY > scrollThreshold) {
|
||||
chart.scrollUp(mouseY - lastMouseY)
|
||||
lastMouseY = mouseY
|
||||
chart.autoScaling = false
|
||||
} else if (mouseY - lastMouseY < scrollThreshold) {
|
||||
chart.scrollDown(lastMouseY - mouseY)
|
||||
lastMouseY = mouseY
|
||||
chart.autoScaling = false
|
||||
}
|
||||
}
|
||||
}
|
||||
onPressed: {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
lastMouseX = mouseX
|
||||
lastMouseY = mouseY
|
||||
}
|
||||
}
|
||||
onWheel: {
|
||||
if (wheel.angleDelta.y > 0) {
|
||||
chart.zoomIn()
|
||||
chart.autoScaling = false
|
||||
} else {
|
||||
chart.zoomOut()
|
||||
chart.autoScaling = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ CheckBox {
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
color: Palette.textColor
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
@@ -6,6 +6,6 @@ import Utils 1.0
|
||||
Label {
|
||||
color: Palette.contentTextColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Medium
|
||||
font.weight: Font.Normal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import Utils 1.0
|
||||
Label {
|
||||
color: Palette.textColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
@@ -7,7 +7,7 @@ Label {
|
||||
id: control
|
||||
color: Palette.selectedTextColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Medium
|
||||
font.weight: Font.Normal
|
||||
font.underline : true
|
||||
elide: Text.ElideRight
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Button {
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
opacity: enabled ? 1.0 : 0.3
|
||||
color: control.hovered ? Palette.alternativeTextColor : Palette.textColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
@@ -6,6 +6,6 @@ import Utils 1.0
|
||||
Label {
|
||||
color: Palette.textColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
20
qml/Controls/TabBar.qml
Normal file
20
qml/Controls/TabBar.qml
Normal file
@@ -0,0 +1,20 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
TabBar {
|
||||
id: control
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.backgroundColor
|
||||
|
||||
Rectangle {
|
||||
height: 1
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: Palette.borderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
44
qml/Controls/TabButton.qml
Normal file
44
qml/Controls/TabButton.qml
Normal file
@@ -0,0 +1,44 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
TabButton {
|
||||
id: control
|
||||
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
opacity: enabled ? 1.0 : 0.3
|
||||
color: control.checked ? Palette.selectedTextColor : Palette.textColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
background: Item {
|
||||
implicitWidth: 150
|
||||
implicitHeight: 58
|
||||
|
||||
Rectangle {
|
||||
property bool selected: control.checked
|
||||
|
||||
height: 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: Palette.alternativeBackgroundColor
|
||||
visible: selected
|
||||
|
||||
// Behavior on selected {
|
||||
// PropertyAnimation {
|
||||
// properties: "selected";
|
||||
// easing.type: Easing.OutElastic;
|
||||
// easing.amplitude: 0.2;
|
||||
// easing.period: 0.2
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,6 @@ import Utils 1.0
|
||||
Label {
|
||||
color: Palette.selectedTextColor
|
||||
font.pixelSize: 28
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
@@ -16,3 +16,6 @@ LabelWithBackground 1.0 LabelWithBackground.qml
|
||||
CheckBox 1.0 CheckBox.qml
|
||||
LineSeparator 1.0 LineSeparator.qml
|
||||
LinkLabel 1.0 LinkLabel.qml
|
||||
TabButton 1.0 TabButton.qml
|
||||
TabBar 1.0 TabBar.qml
|
||||
ChartView 1.0 ChartView.qml
|
||||
|
||||
@@ -133,7 +133,7 @@ ApplicationWindow {
|
||||
|
||||
Label {
|
||||
text: modelData.text
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
color: Palette.alternativeTextColor
|
||||
visible: !pane.minimized
|
||||
}
|
||||
@@ -173,12 +173,13 @@ ApplicationWindow {
|
||||
qsTr("AKB monitor"),
|
||||
qsTr("Cell monitor"),
|
||||
qsTr("BMS settings"),
|
||||
qsTr("Visualization"),
|
||||
]
|
||||
|
||||
Label {
|
||||
text: topBar.labels[stack.currentIndex]
|
||||
font.pixelSize: 38
|
||||
font.weight: Font.ExtraBold
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -207,6 +208,9 @@ ApplicationWindow {
|
||||
|
||||
Screens.BmsSettingsScreen {
|
||||
}
|
||||
|
||||
Screens.VisualizationScreen {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,7 +660,7 @@ RowLayout {
|
||||
|
||||
function getValues() {
|
||||
if (BmsInterface.isPortConnected() && visible) {
|
||||
BmsInterface.bmsConfig().updateDone()
|
||||
BmsInterface.commands().getBMSconf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ Item {
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: index
|
||||
text: index + 1
|
||||
color: Palette.tableHeaderTextColor
|
||||
Layout.preferredWidth: 25
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
479
qml/Screens/VisualizationScreen.qml
Normal file
479
qml/Screens/VisualizationScreen.qml
Normal file
@@ -0,0 +1,479 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtCharts 2.3
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
property int currentTime: 0
|
||||
|
||||
property var voltageData: []
|
||||
property var currentData: []
|
||||
property var batteryTemperatureData: []
|
||||
property var bmsTemperatureData: []
|
||||
property var cellVoltageData: []
|
||||
property var cellListData: []
|
||||
|
||||
Controls.Frame {
|
||||
padding: 20
|
||||
leftPadding: 1
|
||||
rightPadding: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.TabBar {
|
||||
id: bar
|
||||
implicitWidth: 300
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Voltage")
|
||||
width: bar.width / 6 * 0.9
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Current")
|
||||
width: bar.width / 6 * 0.9
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Battery temperature")
|
||||
width: bar.width / 6 * 1.2
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("BMS temperature")
|
||||
width: bar.width / 6 * 1.2
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Cell voltage")
|
||||
width: bar.width / 6 * 0.8
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Cell list")
|
||||
width: bar.width / 6 * 0.9
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
width: parent.width
|
||||
currentIndex: bar.currentIndex
|
||||
|
||||
Component {
|
||||
id: legendDelegate
|
||||
|
||||
RowLayout {
|
||||
width: ListView.view.width
|
||||
height: 60
|
||||
|
||||
property Controls.ChartView chartItem: undefined
|
||||
property color seriesColor: "black"
|
||||
|
||||
Controls.CheckBox {
|
||||
id: checkSeries
|
||||
checked: true
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
chartItem.series(modelData).color = seriesColor
|
||||
} else {
|
||||
chartItem.series(modelData).color = "transparent"
|
||||
}
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: seriesColor
|
||||
radius: width / 2
|
||||
Layout.preferredWidth: 18
|
||||
Layout.preferredHeight: 18
|
||||
Layout.rightMargin: 20
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
chartItem = ListView.view.chartItem
|
||||
seriesColor = chartItem.series(modelData).color
|
||||
checkSeries.text = chartItem.series(modelData).name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: chartComponent
|
||||
|
||||
RowLayout {
|
||||
property string xLabel: ""
|
||||
property string yLabel: ""
|
||||
property Controls.ChartView chart: chartView
|
||||
property int seriesCount: 0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: -20
|
||||
|
||||
Controls.ContentLabel {
|
||||
z: 1
|
||||
text: yLabel
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 30
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
}
|
||||
|
||||
Controls.ChartView {
|
||||
id: chartView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Controls.ContentLabel {
|
||||
z: 1
|
||||
text: xLabel
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.rightMargin: 30
|
||||
Layout.bottomMargin: 10
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
ListView {
|
||||
clip: true
|
||||
model: seriesCount
|
||||
delegate: legendDelegate
|
||||
|
||||
property Controls.ChartView chartItem: chart
|
||||
|
||||
Layout.preferredWidth: 300
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: voltageLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: currentLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Current, A") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: batteryTemperatureLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Temperature, °C") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: bmsTemperatureLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Temperature, °C") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: cellVoltageLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: cellListLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
Controls.Button {
|
||||
text: timer.running ? qsTr("Pause data collection") : qsTr("Resume data collection")
|
||||
onClicked: {
|
||||
if (timer.running)
|
||||
timer.stop()
|
||||
else
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Clear data")
|
||||
onClicked: {
|
||||
currentTime = 0
|
||||
|
||||
clearData(voltageData, voltageLoader)
|
||||
clearData(currentData, currentLoader)
|
||||
clearData(batteryTemperatureData, batteryTemperatureLoader)
|
||||
clearData(bmsTemperatureData, bmsTemperatureLoader)
|
||||
clearData(cellVoltageData, cellVoltageLoader)
|
||||
clearData(cellListData, cellListLoader)
|
||||
|
||||
resetZoomButton.clicked()
|
||||
}
|
||||
|
||||
function clearData(dataObject, chartObject) {
|
||||
for (var i = 0; i < dataObject.length; ++i) {
|
||||
dataObject[i].splice(0, dataObject[i].length)
|
||||
var series = chartObject.item.chart.series(i)
|
||||
series.removePoints(0, series.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
id: resetZoomButton
|
||||
text: qsTr("Reset zoom")
|
||||
onClicked: {
|
||||
resetChartZoom(voltageData, voltageLoader)
|
||||
resetChartZoom(currentData, currentLoader)
|
||||
resetChartZoom(batteryTemperatureData, batteryTemperatureLoader)
|
||||
resetChartZoom(bmsTemperatureData, bmsTemperatureLoader)
|
||||
resetChartZoom(cellVoltageData, cellVoltageLoader)
|
||||
resetChartZoom(cellListData, cellListLoader)
|
||||
}
|
||||
|
||||
function resetChartZoom(dataObject, chartObject) {
|
||||
chartObject.item.chart.zoomReset()
|
||||
chartObject.item.chart.autoScaling = true
|
||||
chartObject.item.chart.axes[1].min = closestMinValue(getMinValue(dataObject), 0.05)
|
||||
chartObject.item.chart.axes[1].max = closestMaxValue(getMaxValue(dataObject), 0.05)
|
||||
chartObject.item.chart.axes[0].min = 0
|
||||
chartObject.item.chart.axes[0].max = Math.max(chartObject.item.chart.defaultXMax, chartObject.item.chart.series(0).at(chartObject.item.chart.series(0).count - 1).x)
|
||||
}
|
||||
|
||||
function getMaxValue(dataObject, seriesIndex) {
|
||||
if (dataObject.length === 0 || dataObject[0].length === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
var max = dataObject[0][0].y
|
||||
for (var i = 0; i < dataObject.length; ++i) {
|
||||
for (var j = 0; j < dataObject[i].length; ++j) {
|
||||
if (dataObject[i][j].y > max) {
|
||||
max = dataObject[i][j].y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
|
||||
function getMinValue(dataObject) {
|
||||
if (dataObject.length === 0 || dataObject[0].length === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
var min = dataObject[0][0].y
|
||||
for (var i = 0; i < dataObject.length; ++i) {
|
||||
for (var j = 0; j < dataObject[i].length; ++j) {
|
||||
if (dataObject[i][j].y < min) {
|
||||
min = dataObject[i][j].y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return min
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
|
||||
onValuesReceived: {
|
||||
addValueToChart(values.packVoltage, voltageData, voltageLoader, 0, 0.05)
|
||||
addValueToChart(values.packCurrent, currentData, currentLoader, 0, 0.05)
|
||||
|
||||
addValueToChart(values.tempBMSHigh, batteryTemperatureData, batteryTemperatureLoader, 0, 0.05)
|
||||
addValueToChart(values.tempBMSAverage, batteryTemperatureData, batteryTemperatureLoader, 1, 0.05)
|
||||
addValueToChart(values.tempBMSLow, batteryTemperatureData, batteryTemperatureLoader, 2, 0.05)
|
||||
|
||||
addValueToChart(values.tempBattHigh, bmsTemperatureData, bmsTemperatureLoader, 0, 0.05)
|
||||
addValueToChart(values.tempBattAverage, bmsTemperatureData, bmsTemperatureLoader, 1, 0.05)
|
||||
addValueToChart(values.tempBattLow, bmsTemperatureData, bmsTemperatureLoader, 2, 0.05)
|
||||
|
||||
addValueToChart(values.cVHigh, cellVoltageData, cellVoltageLoader, 0, 0.05)
|
||||
addValueToChart(values.cVAverage, cellVoltageData, cellVoltageLoader, 1, 0.05)
|
||||
addValueToChart(values.cVLow, cellVoltageData, cellVoltageLoader, 2, 0.05)
|
||||
}
|
||||
|
||||
onCellsReceived: {
|
||||
for (var i = cellListLoader.item.chart.count; i < cellCount; ++i) {
|
||||
cellListLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Cell #") + (i + 1).toString(),
|
||||
cellListLoader.item.chart.xAxis, cellListLoader.item.chart.yAxis)
|
||||
cellListLoader.item.chart.axes[0].max = 10
|
||||
cellListLoader.item.seriesCount = cellListLoader.item.chart.count
|
||||
}
|
||||
|
||||
for (var j = 0; j < cellCount; ++j) {
|
||||
addValueToChart(cellVoltageArray[j], cellListData, cellListLoader, j, 0.05)
|
||||
}
|
||||
|
||||
currentTime += 1
|
||||
}
|
||||
}
|
||||
|
||||
function addValueToChart(value, dataObject, chartObject, seriesIndex, yScale) {
|
||||
if (seriesIndex >= dataObject.length) {
|
||||
for (var i = dataObject.length; i <= seriesIndex; ++i) {
|
||||
dataObject.push([])
|
||||
}
|
||||
}
|
||||
|
||||
var seriesData = dataObject[seriesIndex]
|
||||
seriesData.push(Qt.point(currentTime, value))
|
||||
chartObject.item.chart.series(seriesIndex).append(currentTime, value)
|
||||
|
||||
if (currentTime > chartObject.item.chart.defaultXMax && chartObject.item.chart.autoScaling) {
|
||||
chartObject.item.chart.axes[0].max = currentTime
|
||||
}
|
||||
|
||||
if (seriesData.length < 2 || (value >= chartObject.item.chart.axes[1].max && chartObject.item.chart.autoScaling)) {
|
||||
chartObject.item.chart.axes[1].max = closestMaxValue(value, yScale)
|
||||
}
|
||||
|
||||
if (seriesData.length < 2 || (value <= chartObject.item.chart.axes[1].min && chartObject.item.chart.autoScaling)) {
|
||||
chartObject.item.chart.axes[1].min = closestMinValue(value, yScale)
|
||||
}
|
||||
}
|
||||
|
||||
function closestMaxValue(value, scale) {
|
||||
return value === 0 ? 1 : Math.ceil(value * (value > 0 ? (1 + scale) : (1 - scale)))
|
||||
}
|
||||
|
||||
function closestMinValue(value, scale) {
|
||||
return value === 0 ? -1 : Math.floor(value * (value > 0 ? (1 - scale) : (1 + scale)))
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
running: true
|
||||
interval: 1000
|
||||
triggeredOnStart: true
|
||||
|
||||
onTriggered: {
|
||||
BmsInterface.commands().getValues()
|
||||
BmsInterface.commands().getCells()
|
||||
Qt.callLater(start)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
onPortConnectedChanged: getValues()
|
||||
}
|
||||
|
||||
onVisibleChanged: getValues()
|
||||
|
||||
function getValues() {
|
||||
if (BmsInterface.isPortConnected() && visible) {
|
||||
timer.start()
|
||||
} else {
|
||||
timer.stop()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
voltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Voltage indicator"),
|
||||
voltageLoader.item.chart.xAxis, voltageLoader.item.chart.yAxis)
|
||||
voltageLoader.item.chart.axes[0].max = 10
|
||||
voltageLoader.item.seriesCount = voltageLoader.item.chart.count
|
||||
|
||||
currentLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Current indicator"),
|
||||
currentLoader.item.chart.xAxis, currentLoader.item.chart.yAxis)
|
||||
currentLoader.item.chart.axes[0].max = 10
|
||||
currentLoader.item.seriesCount = currentLoader.item.chart.count
|
||||
|
||||
batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum temperature"),
|
||||
batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
|
||||
batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average temperature"),
|
||||
batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
|
||||
batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum temperature"),
|
||||
batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
|
||||
batteryTemperatureLoader.item.chart.axes[0].max = 10
|
||||
batteryTemperatureLoader.item.seriesCount = batteryTemperatureLoader.item.chart.count
|
||||
|
||||
bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum temperature"),
|
||||
bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
|
||||
bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average temperature"),
|
||||
bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
|
||||
bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum temperature"),
|
||||
bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
|
||||
bmsTemperatureLoader.item.chart.axes[0].max = 10
|
||||
bmsTemperatureLoader.item.seriesCount = bmsTemperatureLoader.item.chart.count
|
||||
|
||||
cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum voltage"),
|
||||
cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
|
||||
cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average voltage"),
|
||||
cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
|
||||
cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum voltage"),
|
||||
cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
|
||||
cellVoltageLoader.item.chart.axes[0].max = 10
|
||||
cellVoltageLoader.item.seriesCount = cellVoltageLoader.item.chart.count
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,4 @@ ConnectionScreen 1.0 ConnectionScreen.qml
|
||||
AkbMonitorScreen 1.0 AkbMonitorScreen.qml
|
||||
CellMonitorScreen 1.0 CellMonitorScreen.qml
|
||||
BmsSettingsScreen 1.0 BmsSettingsScreen.qml
|
||||
VisualizationScreen 1.0 VisualizationScreen.qml
|
||||
|
||||
@@ -26,5 +26,9 @@
|
||||
<file>Controls/CheckBox.qml</file>
|
||||
<file>Controls/LineSeparator.qml</file>
|
||||
<file>Controls/LinkLabel.qml</file>
|
||||
<file>Screens/VisualizationScreen.qml</file>
|
||||
<file>Controls/TabButton.qml</file>
|
||||
<file>Controls/TabBar.qml</file>
|
||||
<file>Controls/ChartView.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
Reference in New Issue
Block a user