Files
CuboBmsTool/qml/Screens/BmsSettingsScreen.qml
2022-08-29 02:57:42 +03:00

787 lines
32 KiB
QML

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.1
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
boundsBehavior: Flickable.StopAtBounds
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: {
let result = BmsInterface.bmsConfig().loadXml(loadFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration")
if (!result) {
BmsInterface.emitStatusMessage(BmsInterface.bmsConfig().xmlStatus(), false)
}
}
}
Settings {
category: "loadConfiguration"
property alias folder: loadFileDialog.folder
}
}
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: {
let result = BmsInterface.bmsConfig().saveXml(saveFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration")
if (!result) {
BmsInterface.emitStatusMessage(BmsInterface.bmsConfig().xmlStatus(), false)
} else {
BmsInterface.emitStatusMessage(qsTr("BMS configuration saved to file"), true)
}
}
}
Settings {
category: "saveConfiguration"
property alias folder: saveFileDialog.folder
}
}
}
ScrollBar.vertical: Controls.ScrollBar {}
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
settingsFlickable.returnToBounds()
}
}
Item {
Layout.fillHeight: true
}
ColumnLayout {
spacing: 15
Controls.OutlineButton {
text: qsTr("Read default settings")
Layout.fillWidth: true
onClicked: if (BmsInterface.isPortConnected()) {
BmsInterface.commands().getBMSconfDefault()
}
}
Controls.OutlineButton {
text: qsTr("Read current settings from BMS")
Layout.fillWidth: true
onClicked: if (BmsInterface.isPortConnected()) {
BmsInterface.commands().getBMSconf()
}
}
Controls.OutlineButton {
text: qsTr("Write current values to BMS")
Layout.fillWidth: true
onClicked: if (BmsInterface.isPortConnected()) {
writeValuesToConfig()
BmsInterface.commands().setBMSconf()
}
}
Controls.Button {
text: qsTr("Write to non-volatile memory of BMS")
Layout.fillWidth: true
onClicked: if (BmsInterface.isPortConnected()) {
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"))
}
}
}