Files
CuboBmsTool/qml/Screens/BmsSettingsScreen.qml

762 lines
31 KiB
QML

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Dialogs 1.2
import Controls 1.0 as Controls
import Cubo 1.0
import Utils 1.0
RowLayout {
property real contentPadding: 35
property real contentRowSpacing: 20
property real contentColumnSpacing: 35
signal needWait(bool active, string text)
spacing: contentColumnSpacing
Flickable {
id: settingsFlickable
clip: true
contentHeight: configLayout.height
ColumnLayout {
id: configLayout
width: parent.width
spacing: 15
Controls.Frame {
id: serialNumberSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
RowLayout {
spacing: contentColumnSpacing
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("Serial number")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.spacing) / 2
}
Controls.TextField {
id: serialNumberField
validator: RegExpValidator { regExp: /[1-9][0-9]*/ }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.spacing) / 2
}
}
}
Controls.Frame {
id: configurationSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
rowSpacing: contentRowSpacing
columnSpacing: contentColumnSpacing
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("Configuration")
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Number of boards")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Number of cells")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: numberOfBoardsField
validator: IntValidator {}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: numberOfCellsField
validator: IntValidator {}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
}
}
Controls.Frame {
id: socSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
rowSpacing: contentRowSpacing
columnSpacing: contentColumnSpacing
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("SOC")
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Number of cells connected in parallel")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Battery capacity")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: numberOfParallelCellsField
validator: IntValidator {}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: batteryCapacityField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
}
}
Controls.Frame {
id: limitSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
rowSpacing: contentRowSpacing
columnSpacing: contentColumnSpacing
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("Limits")
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Maximum charge current, A")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Maximum load current, A")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: maximumChargeCurrentField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: maximumLoadCurrentField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Maximum temperature, °C")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
}
Controls.TextField {
id: maximumTemperatureField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
}
}
}
Controls.Frame {
id: cellSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
rowSpacing: contentRowSpacing
columnSpacing: contentColumnSpacing
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("Cell configuration")
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Lower disable threshold, V")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Upper disable threshold, V")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: lowerDisableThresholdField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: upperDisableThresholdField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Lower enable threshold (should be higher than disable), V")
maximumLineCount: 3
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Upper enable threshold (should be higher than disable), V")
maximumLineCount: 3
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: lowerEnableThresholdField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: upperEnableThresholdField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
}
}
Controls.Frame {
id: balancingSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
rowSpacing: contentRowSpacing
columnSpacing: contentColumnSpacing
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("Balancing configuration")
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Balancing start voltage, V")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Cell voltage delta to start balancing, V")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: balancingStartVoltageField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: balancingStartDeltaVoltageField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Cell balancing interval, ms")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
}
Controls.TextField {
id: balancingCellIntervalField
validator: IntValidator {}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
}
}
}
Controls.Frame {
id: outputSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
property real outputNumberSize: 60
GridLayout {
columns: 2
rowSpacing: contentRowSpacing
columnSpacing: contentColumnSpacing
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("Output settings")
Layout.fillWidth: true
Layout.columnSpan: 2
}
RowLayout {
spacing: 20
Controls.LabelWithBackground {
text: qsTr("# 1")
Layout.preferredWidth: outputSettingsFrame.outputNumberSize
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Controls.CheckBox {
text: qsTr("Use for storage management")
Layout.fillWidth: true
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.LineSeparator {
Layout.fillWidth: true
Layout.columnSpan: 2
}
RowLayout {
spacing: 20
Controls.LabelWithBackground {
text: qsTr("# 2")
Layout.preferredWidth: outputSettingsFrame.outputNumberSize
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Controls.CheckBox {
text: qsTr("Normally closed")
Layout.fillWidth: true
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Change in value during SOC")
maximumLineCount: 2
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
}
Controls.TextField {
id: changeValueSocField
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
}
Controls.LineSeparator {
Layout.fillWidth: true
Layout.columnSpan: 2
}
RowLayout {
spacing: 20
Controls.LabelWithBackground {
text: qsTr("# 3")
Layout.preferredWidth: outputSettingsFrame.outputNumberSize
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Controls.CheckBox {
Layout.fillWidth: true
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Closes at t<, °C")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Opens at t>, °C")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: closesBelowTemperatureThirdField
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: opensGreaterTemperatureThirdField
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.LineSeparator {
Layout.fillWidth: true
Layout.columnSpan: 2
}
RowLayout {
spacing: 20
Controls.LabelWithBackground {
text: qsTr("# 4")
Layout.preferredWidth: outputSettingsFrame.outputNumberSize
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Controls.CheckBox {
Layout.fillWidth: true
Layout.preferredHeight: outputSettingsFrame.outputNumberSize
}
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.SubtitleLabel {
text: qsTr("Closes at t<, °C")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.SubtitleLabel {
text: qsTr("Opens at t>, °C")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: closesBelowTemperatureFourthField
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.TextField {
id: opensGreaterTemperatureFourthField
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
Controls.LineSeparator {
Layout.fillWidth: true
Layout.columnSpan: 2
}
}
}
Controls.Frame {
id: zeroSensorSettingsFrame
padding: contentPadding
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
rowSpacing: contentRowSpacing
columnSpacing: contentColumnSpacing
anchors.fill: parent
Controls.SubtitleLabel {
text: qsTr("Current sensor value \"0\"")
Layout.fillWidth: true
Layout.columnSpan: 2
}
Controls.TextField {
id: zeroSensorValueField
validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation }
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
}
Controls.Button {
id: zeroSensorValueCalibrationButton
text: qsTr("Calibrate \"0\"")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
Layout.columnSpan: 2
onClicked: BmsInterface.commands().sendTerminalCmd("setZeroCurrent")
}
}
}
Controls.OutlineButton {
text: qsTr("Load settings from file")
onClicked: loadFileDialog.open()
Layout.preferredWidth: 270
FileDialog {
id: loadFileDialog
title: qsTr("Select configuration file")
folder: shortcuts.documents
nameFilters: [ qsTr("Configuration files (*.xml)"), qsTr("All files (*)") ]
onAccepted: {
BmsInterface.bmsConfig().loadXml(loadFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration")
}
}
}
Controls.OutlineButton {
text: qsTr("Save settings to file")
onClicked: saveFileDialog.open()
Layout.preferredWidth: 270
FileDialog {
id: saveFileDialog
title: qsTr("Select configuration file")
selectExisting: false
folder: shortcuts.documents
nameFilters: [ qsTr("Configuration files (*.xml)"), qsTr("All files (*)") ]
onAccepted: {
BmsInterface.bmsConfig().saveXml(saveFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration")
}
}
}
}
ScrollBar.vertical: Controls.ScrollBar {
// policy: ScrollBar.AlwaysOn
}
Layout.fillWidth: true
Layout.fillHeight: true
}
ColumnLayout {
spacing: contentRowSpacing
Controls.LinkLabel {
text: qsTr("Serial number")
onClicked: settingsFlickable.contentY = serialNumberSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Controls.LinkLabel {
text: qsTr("Configuration")
onClicked: settingsFlickable.contentY = configurationSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Controls.LinkLabel {
text: qsTr("SOC")
onClicked: settingsFlickable.contentY = socSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Controls.LinkLabel {
text: qsTr("Limits")
onClicked: settingsFlickable.contentY = limitSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Controls.LinkLabel {
text: qsTr("Cell configuration")
onClicked: settingsFlickable.contentY = cellSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Controls.LinkLabel {
text: qsTr("Balancing configuration")
onClicked: settingsFlickable.contentY = balancingSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Controls.LinkLabel {
text: qsTr("Output settings")
onClicked: settingsFlickable.contentY = outputSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Controls.LinkLabel {
text: qsTr("Current sensor value \"0\"")
onClicked: settingsFlickable.contentY = zeroSensorSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y
}
Item {
Layout.fillHeight: true
}
ColumnLayout {
spacing: 15
Controls.OutlineButton {
text: qsTr("Read default settings")
Layout.fillWidth: true
onClicked: BmsInterface.commands().getBMSconfDefault()
}
Controls.OutlineButton {
text: qsTr("Read current settings from BMS")
Layout.fillWidth: true
onClicked: BmsInterface.commands().getBMSconf()
}
Controls.OutlineButton {
text: qsTr("Write current values to BMS")
Layout.fillWidth: true
onClicked: {
writeValuesToConfig()
BmsInterface.commands().setBMSconf()
}
}
Controls.Button {
text: qsTr("Write to non-volatile memory of BMS")
Layout.fillWidth: true
onClicked: {
needWait(true, qsTr("The settings are written to non-volatile memory.\nWait, please."))
writeValuesToConfig()
BmsInterface.commands().storeBMSConfig()
}
}
Layout.fillWidth: true
}
Layout.maximumWidth: 280
Layout.fillHeight: true
}
function writeValuesToConfig() {
BmsInterface.bmsConfig().setParamValue("notUsedCurrentThreshold", parseFloat(serialNumberField.text))
BmsInterface.bmsConfig().setParamValue("cellMonitorICCount", parseInt(numberOfBoardsField.text))
BmsInterface.bmsConfig().setParamValue("noOfCellsSeries", parseInt(numberOfCellsField.text))
BmsInterface.bmsConfig().setParamValue("noOfCellsParallel", parseInt(numberOfParallelCellsField.text))
BmsInterface.bmsConfig().setParamValue("batteryCapacity", parseFloat(batteryCapacityField.text))
BmsInterface.bmsConfig().setParamValue("maxAllowedCurrent", parseFloat(maximumChargeCurrentField.text))
BmsInterface.bmsConfig().setParamValue("maxMismatchThreshold", parseFloat(maximumLoadCurrentField.text))
BmsInterface.bmsConfig().setParamValue("allowedTempBattChargingMax", parseFloat(maximumTemperatureField.text))
BmsInterface.bmsConfig().setParamValue("cellHardUnderVoltage", parseFloat(lowerDisableThresholdField.text))
BmsInterface.bmsConfig().setParamValue("cellHardOverVoltage", parseFloat(upperDisableThresholdField.text))
BmsInterface.bmsConfig().setParamValue("cellLCSoftUnderVoltage", parseFloat(lowerEnableThresholdField.text))
BmsInterface.bmsConfig().setParamValue("cellSoftOverVoltage", parseFloat(upperEnableThresholdField.text))
BmsInterface.bmsConfig().setParamValue("cellBalanceStart", parseFloat(balancingStartVoltageField.text))
BmsInterface.bmsConfig().setParamValue("cellBalanceDifferenceThreshold", parseFloat(balancingStartDeltaVoltageField.text))
BmsInterface.bmsConfig().setParamValue("cellBalanceUpdateInterval", parseInt(balancingCellIntervalField.text))
BmsInterface.bmsConfig().setParamValue("shuntLCFactor", parseFloat(zeroSensorValueField.text))
}
Connections {
target: BmsInterface.bmsConfig()
onUpdated: {
serialNumberField.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed()
numberOfBoardsField.text = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount")
numberOfCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsSeries")
numberOfParallelCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsParallel")
batteryCapacityField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("batteryCapacity"))
maximumChargeCurrentField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("maxAllowedCurrent"))
maximumLoadCurrentField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("maxMismatchThreshold"))
maximumTemperatureField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("allowedTempBattChargingMax"))
lowerDisableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellHardUnderVoltage"))
upperDisableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellHardOverVoltage"))
lowerEnableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellLCSoftUnderVoltage"))
upperEnableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellSoftOverVoltage"))
balancingStartVoltageField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellBalanceStart"))
balancingStartDeltaVoltageField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellBalanceDifferenceThreshold"))
balancingCellIntervalField.text = BmsInterface.bmsConfig().getParamInt("cellBalanceUpdateInterval")
zeroSensorValueField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("shuntLCFactor"))
}
}
}