From d1ba61acd8e9c82f70b1c86df50ee45d2e66f4ef Mon Sep 17 00:00:00 2001 From: Yury Shuvakin Date: Thu, 25 Aug 2022 07:59:16 +0300 Subject: [PATCH] Implemented a visualization screen for various board parameters --- main.cpp | 11 +- qml/Controls/Button.qml | 2 +- qml/Controls/ChartView.qml | 100 ++++++ qml/Controls/CheckBox.qml | 2 +- qml/Controls/ContentLabel.qml | 2 +- qml/Controls/LabelWithBackground.qml | 2 +- qml/Controls/LinkLabel.qml | 2 +- qml/Controls/OutlineButton.qml | 2 +- qml/Controls/SubtitleLabel.qml | 2 +- qml/Controls/TabBar.qml | 20 ++ qml/Controls/TabButton.qml | 44 +++ qml/Controls/TitleLabel.qml | 2 +- qml/Controls/qmldir | 3 + qml/MainWindow.qml | 8 +- qml/Screens/BmsSettingsScreen.qml | 2 +- qml/Screens/CellMonitorScreen.qml | 2 +- qml/Screens/VisualizationScreen.qml | 479 +++++++++++++++++++++++++++ qml/Screens/qmldir | 1 + qml/qml_items.qrc | 4 + 19 files changed, 675 insertions(+), 15 deletions(-) create mode 100644 qml/Controls/ChartView.qml create mode 100644 qml/Controls/TabBar.qml create mode 100644 qml/Controls/TabButton.qml create mode 100644 qml/Screens/VisualizationScreen.qml diff --git a/main.cpp b/main.cpp index 9cb76e9..cf96846 100644 --- a/main.cpp +++ b/main.cpp @@ -22,7 +22,7 @@ #include "utility.h" #include "mobile/fwhelper.h" -#include +#include #include #include @@ -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; diff --git a/qml/Controls/Button.qml b/qml/Controls/Button.qml index 33dd131..8caf41c 100644 --- a/qml/Controls/Button.qml +++ b/qml/Controls/Button.qml @@ -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 diff --git a/qml/Controls/ChartView.qml b/qml/Controls/ChartView.qml new file mode 100644 index 0000000..8bdcb1a --- /dev/null +++ b/qml/Controls/ChartView.qml @@ -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 + } + } + } +} diff --git a/qml/Controls/CheckBox.qml b/qml/Controls/CheckBox.qml index c9611ea..0bf4e72 100644 --- a/qml/Controls/CheckBox.qml +++ b/qml/Controls/CheckBox.qml @@ -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 diff --git a/qml/Controls/ContentLabel.qml b/qml/Controls/ContentLabel.qml index 2141feb..46923ac 100644 --- a/qml/Controls/ContentLabel.qml +++ b/qml/Controls/ContentLabel.qml @@ -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 } diff --git a/qml/Controls/LabelWithBackground.qml b/qml/Controls/LabelWithBackground.qml index 97cac16..54faf9c 100644 --- a/qml/Controls/LabelWithBackground.qml +++ b/qml/Controls/LabelWithBackground.qml @@ -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 diff --git a/qml/Controls/LinkLabel.qml b/qml/Controls/LinkLabel.qml index 57a9716..96b8009 100644 --- a/qml/Controls/LinkLabel.qml +++ b/qml/Controls/LinkLabel.qml @@ -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 diff --git a/qml/Controls/OutlineButton.qml b/qml/Controls/OutlineButton.qml index 98ad8f4..5361621 100644 --- a/qml/Controls/OutlineButton.qml +++ b/qml/Controls/OutlineButton.qml @@ -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 diff --git a/qml/Controls/SubtitleLabel.qml b/qml/Controls/SubtitleLabel.qml index 32549d4..ead6563 100644 --- a/qml/Controls/SubtitleLabel.qml +++ b/qml/Controls/SubtitleLabel.qml @@ -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 } diff --git a/qml/Controls/TabBar.qml b/qml/Controls/TabBar.qml new file mode 100644 index 0000000..8f4b795 --- /dev/null +++ b/qml/Controls/TabBar.qml @@ -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 + } + } +} diff --git a/qml/Controls/TabButton.qml b/qml/Controls/TabButton.qml new file mode 100644 index 0000000..5f1a80f --- /dev/null +++ b/qml/Controls/TabButton.qml @@ -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 +// } +// } + } + } +} diff --git a/qml/Controls/TitleLabel.qml b/qml/Controls/TitleLabel.qml index 6c4bcda..ca5d4d7 100644 --- a/qml/Controls/TitleLabel.qml +++ b/qml/Controls/TitleLabel.qml @@ -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 } diff --git a/qml/Controls/qmldir b/qml/Controls/qmldir index 60ca118..9872152 100644 --- a/qml/Controls/qmldir +++ b/qml/Controls/qmldir @@ -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 diff --git a/qml/MainWindow.qml b/qml/MainWindow.qml index 39eb673..0c99012 100644 --- a/qml/MainWindow.qml +++ b/qml/MainWindow.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 { + } } } } diff --git a/qml/Screens/BmsSettingsScreen.qml b/qml/Screens/BmsSettingsScreen.qml index c0969a3..5a56a3d 100644 --- a/qml/Screens/BmsSettingsScreen.qml +++ b/qml/Screens/BmsSettingsScreen.qml @@ -660,7 +660,7 @@ RowLayout { function getValues() { if (BmsInterface.isPortConnected() && visible) { - BmsInterface.bmsConfig().updateDone() + BmsInterface.commands().getBMSconf() } } } diff --git a/qml/Screens/CellMonitorScreen.qml b/qml/Screens/CellMonitorScreen.qml index fb01ce5..4a97b2d 100644 --- a/qml/Screens/CellMonitorScreen.qml +++ b/qml/Screens/CellMonitorScreen.qml @@ -70,7 +70,7 @@ Item { } Controls.SubtitleLabel { - text: index + text: index + 1 color: Palette.tableHeaderTextColor Layout.preferredWidth: 25 Layout.alignment: Qt.AlignCenter diff --git a/qml/Screens/VisualizationScreen.qml b/qml/Screens/VisualizationScreen.qml new file mode 100644 index 0000000..c0cd463 --- /dev/null +++ b/qml/Screens/VisualizationScreen.qml @@ -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 + } +} diff --git a/qml/Screens/qmldir b/qml/Screens/qmldir index 44ad1a4..05ce25a 100644 --- a/qml/Screens/qmldir +++ b/qml/Screens/qmldir @@ -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 diff --git a/qml/qml_items.qrc b/qml/qml_items.qrc index 78d1b5b..95f6b0d 100644 --- a/qml/qml_items.qrc +++ b/qml/qml_items.qrc @@ -26,5 +26,9 @@ Controls/CheckBox.qml Controls/LineSeparator.qml Controls/LinkLabel.qml + Screens/VisualizationScreen.qml + Controls/TabButton.qml + Controls/TabBar.qml + Controls/ChartView.qml