diff --git a/CUBO-BMS-Tool.pro b/CUBO-BMS-Tool.pro index 52356ff..082b930 100644 --- a/CUBO-BMS-Tool.pro +++ b/CUBO-BMS-Tool.pro @@ -104,6 +104,7 @@ SOURCES += main.cpp\ bmsinterface.cpp \ translator.cpp \ firmwareupdatehelper.cpp \ + currenttablemodel.cpp \ # visualizationchart.cpp \ # visualizationpage.cpp @@ -139,6 +140,7 @@ HEADERS += \ #mainwindow.h \ bmsinterface.h \ translator.h \ firmwareupdatehelper.h \ + currenttablemodel.h \ # visualizationchart.h \ # visualizationpage.h diff --git a/currenttablemodel.cpp b/currenttablemodel.cpp new file mode 100644 index 0000000..b1ab222 --- /dev/null +++ b/currenttablemodel.cpp @@ -0,0 +1,63 @@ +#include "currenttablemodel.h" + +CurrentTableModel::CurrentTableModel(QObject* parent) : + QAbstractTableModel(parent) +{ +} + +CurrentTableModel::~CurrentTableModel() +{ +} + +void CurrentTableModel::setCurrentData(const QVariantList& data) +{ + beginResetModel(); + data_.clear(); + + for (const auto& row: data) + { + QList rowData; + for (const auto& column: row.toList()) + { + rowData.push_back(column.toFloat()); + } + data_.push_back(rowData); + } + + endResetModel(); +} + +void CurrentTableModel::setCurrentData(const QList>& data) +{ + beginResetModel(); + data_ = data; + endResetModel(); +} + +int CurrentTableModel::rowCount(const QModelIndex&) const +{ + return data_.size(); +} + +int CurrentTableModel::columnCount(const QModelIndex&) const +{ + return data_.empty() ? 0 : data_.at(0).size(); +} + +QVariant CurrentTableModel::data(const QModelIndex& index, int role) const +{ + switch (role) + { + case Qt::DisplayRole: + return QString::number(data_.at(index.row()).at(index.column())); + default: + break; + } + + return {}; +} + +QHash CurrentTableModel::roleNames() const +{ + return { {Qt::DisplayRole, "display"} }; +} diff --git a/currenttablemodel.h b/currenttablemodel.h new file mode 100644 index 0000000..b2919ef --- /dev/null +++ b/currenttablemodel.h @@ -0,0 +1,27 @@ +#ifndef CURRENTTABLEMODEL_H +#define CURRENTTABLEMODEL_H + +#include + +class CurrentTableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit CurrentTableModel(QObject* parent = nullptr); + ~CurrentTableModel(); + + Q_INVOKABLE void setCurrentData(const QVariantList& data); + void setCurrentData(const QList>& data); + + int rowCount(const QModelIndex& = QModelIndex()) const override; + int columnCount(const QModelIndex& = QModelIndex()) const override; + + QVariant data(const QModelIndex& index, int role) const override; + QHash roleNames() const override; + +private: + QList> data_; +}; + +#endif // CURRENTTABLEMODEL_H diff --git a/main.cpp b/main.cpp index 36f7523..625ae49 100644 --- a/main.cpp +++ b/main.cpp @@ -22,6 +22,7 @@ #include "utility.h" #include "translator.h" #include "firmwareupdatehelper.h" +#include "currenttablemodel.h" #include #include @@ -76,6 +77,7 @@ int main(int argc, char *argv[]) qmlRegisterType("Cubo", 1, 0, "Commands"); qmlRegisterType("Cubo", 1, 0, "ConfigParams"); qmlRegisterType("Cubo", 1, 0, "FirmwareUpdateHelper"); + qmlRegisterType("Cubo", 1, 0, "CurrentTableModel"); engine.addImportPath(QStringLiteral("qrc:/")); engine.load(QUrl(QStringLiteral("qrc:/MainWindow.qml"))); diff --git a/qml/Icons/temperature.svg b/qml/Icons/temperature.svg new file mode 100644 index 0000000..2321fd1 --- /dev/null +++ b/qml/Icons/temperature.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qml/MainWindow.qml b/qml/MainWindow.qml index 1aa0b07..918b46d 100644 --- a/qml/MainWindow.qml +++ b/qml/MainWindow.qml @@ -67,7 +67,7 @@ ApplicationWindow { } Item { - Layout.preferredHeight: 70 + Layout.preferredHeight: 40 } ListView { @@ -78,6 +78,7 @@ ApplicationWindow { property var menuModel: [ {"text": qsTr("AKB monitor"), "icon": "qrc:/Icons/akb-monitor.svg"}, {"text": qsTr("Cell monitor"), "icon": "qrc:/Icons/cell-monitor.svg"}, + {"text": qsTr("Temperature monitor"), "icon": "qrc:/Icons/temperature.svg"}, {"text": qsTr("Configuration"), "icon": "qrc:/Icons/bms-configuration.svg"}, {"text": qsTr("Visualization"), "icon": "qrc:/Icons/visualization.svg"}, {"text": qsTr("History"), "icon": "qrc:/Icons/history.svg"}, @@ -90,6 +91,7 @@ ApplicationWindow { width: ListView.view.width text: menuView.menuModel[modelData].text icon.source: menuView.menuModel[modelData].icon + icon.color: "white" highlighted: ListView.isCurrentItem minimized: pane.minimized onClicked: menuView.currentIndex = index @@ -314,6 +316,10 @@ ApplicationWindow { property string title: qsTr("Cell monitor") } + Screens.TemperatureMonitorScreen { + property string title: qsTr("Temperature monitor") + } + Screens.BmsSettingsScreen { property string title: qsTr("BMS settings") onNeedWait: { diff --git a/qml/Screens/BmsSettingsScreen.qml b/qml/Screens/BmsSettingsScreen.qml index 98fb45a..fb5f5f5 100644 --- a/qml/Screens/BmsSettingsScreen.qml +++ b/qml/Screens/BmsSettingsScreen.qml @@ -62,6 +62,7 @@ RowLayout { Layout.fillWidth: true GridLayout { + id: configurationLayout columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing @@ -87,17 +88,137 @@ RowLayout { Controls.TextField { id: numberOfBoardsField - validator: IntValidator {} + validator: IntValidator { bottom: 0 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + + onTextChanged: configurationLayout.recalculateSensorsMasks() } Controls.TextField { id: numberOfCellsField - validator: IntValidator {} + validator: IntValidator { bottom: 0 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } + + Repeater { + id: bmsSensorsMaskRepeater + + property var bmsSensorsMaskModel: [] + + ColumnLayout { + id: bmsSensorsMaskLayout + Layout.fillWidth: true + + property var boardIndex: index + + Controls.SubtitleLabel { + text: index === 0 ? qsTr("BMS sensors mask for master board") : qsTr("BMS sensors mask for slave board #") + index + maximumLineCount: 2 + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + Controls.Frame { + padding: 10 + Layout.fillWidth: true + Layout.fillHeight: true + + ColumnLayout { + spacing: 10 + anchors.fill: parent + + Repeater { + model: 4 + Controls.CheckBox { + text: qsTr("#") + (index + 1) + opacity: (bmsSensorsMaskLayout.boardIndex === 0 && (index === 2 || index === 3)) ? 0 : 1 + enabled: opacity + checked: bmsSensorsMaskRepeater.bmsSensorsMaskModel[bmsSensorsMaskLayout.boardIndex * 4 + index] + onCheckedChanged: bmsSensorsMaskRepeater.bmsSensorsMaskModel[bmsSensorsMaskLayout.boardIndex * 4 + index] = checked + } + } + + Item { + visible: index === 0 + Layout.fillHeight: true + } + } + } + } + } + + Repeater { + id: batterySensorsMaskRepeater + + property var batterySensorsMaskModel: [] + + ColumnLayout { + id: batterySensorsMaskLayout + Layout.fillWidth: true + + property var boardIndex: index + + Controls.SubtitleLabel { + text: index === 0 ? qsTr("Battery sensors mask for master board") : qsTr("Battery sensors mask for slave board #") + index + maximumLineCount: 2 + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + Controls.Frame { + padding: 10 + Layout.fillWidth: true + Layout.fillHeight: true + + ColumnLayout { + spacing: 10 + anchors.fill: parent + + Repeater { + model: 4 + Controls.CheckBox { + text: qsTr("#") + (index + 1) + enabled: opacity + opacity: (batterySensorsMaskLayout.boardIndex === 0 && (index === 2 || index === 3)) ? 0 : 1 + checked: batterySensorsMaskRepeater.batterySensorsMaskModel[batterySensorsMaskLayout.boardIndex * 4 + index] + onCheckedChanged: batterySensorsMaskRepeater.batterySensorsMaskModel[batterySensorsMaskLayout.boardIndex * 4 + index] = checked + } + } + + Item { + visible: index === 0 + Layout.fillHeight: true + } + } + } + } + } + + function recalculateSensorsMasks() { + const bmsSensorsModel = bmsSensorsMaskRepeater.bmsSensorsMaskModel + const batterySensorsModel = batterySensorsMaskRepeater.batterySensorsMaskModel + + const newSize = parseInt(numberOfBoardsField.text) * 4 + if (newSize) { + arrayResize(bmsSensorsModel, newSize, false) + arrayResize(batterySensorsModel, newSize, true) + + bmsSensorsMaskRepeater.model = 0 + bmsSensorsMaskRepeater.bmsSensorsMaskModel = bmsSensorsModel + bmsSensorsMaskRepeater.model = parseInt(numberOfBoardsField.text) + + batterySensorsMaskRepeater.model = 0 + batterySensorsMaskRepeater.batterySensorsMaskModel = batterySensorsModel + batterySensorsMaskRepeater.model = parseInt(numberOfBoardsField.text) + } + } + + function arrayResize(array, size, value) { + while (array.length > size) { array.pop(); } + while (array.length < size) { array.push(value); } + } } } @@ -363,6 +484,82 @@ RowLayout { } } + Controls.Frame { + id: currentConfigurationFrame + padding: contentPadding + implicitWidth: parent.width + Layout.fillWidth: true + + GridLayout { + columns: 2 + rowSpacing: contentRowSpacing + columnSpacing: contentColumnSpacing + anchors.fill: parent + + Controls.TitleLabel { + text: qsTr("Current configuration") + Layout.fillWidth: true + Layout.columnSpan: 2 + } + + Controls.SubtitleLabel { + text: qsTr("Current factor K1") + maximumLineCount: 2 + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + Controls.SubtitleLabel { + text: qsTr("Current factor K2") + maximumLineCount: 2 + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + Controls.TextField { + id: currentFactorK1Field + validator: DoubleValidator { decimals: 3; locale: "en-US"; notation: DoubleValidator.StandardNotation } + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + Controls.TextField { + id: currentFactorK2Field + validator: DoubleValidator { decimals: 3; locale: "en-US"; notation: DoubleValidator.StandardNotation } + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + Controls.SubtitleLabel { + text: qsTr("Current sensor value \"0\"") + Layout.fillWidth: true + Layout.columnSpan: 2 + } + + Controls.TextField { + id: zeroSensorValueField + validator: DoubleValidator { decimals: 3; 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") + Qt.callLater(storeBmsConfigurationButton.clicked) + } + } + } + } + Controls.Frame { id: outputSettingsFrame padding: contentPadding @@ -581,43 +778,6 @@ RowLayout { } } - 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() @@ -710,14 +870,14 @@ RowLayout { } Controls.LinkLabel { - text: qsTr("Output settings") - onClicked: settingsFlickable.contentY = outputSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y + text: qsTr("Current configuration") + onClicked: settingsFlickable.contentY = currentConfigurationFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { - text: qsTr("Current sensor value \"0\"") + text: qsTr("Output settings") onClicked: { - settingsFlickable.contentY = zeroSensorSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y + settingsFlickable.contentY = outputSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y settingsFlickable.returnToBounds() } } @@ -746,6 +906,7 @@ RowLayout { } Controls.OutlineButton { + id: writeBmsConfigurationButton text: qsTr("Write current values to BMS") Layout.fillWidth: true onClicked: if (BmsInterface.isPortConnected()) { @@ -755,6 +916,7 @@ RowLayout { } Controls.Button { + id: storeBmsConfigurationButton text: qsTr("Write to non-volatile memory of BMS") Layout.fillWidth: true onClicked: if (BmsInterface.isPortConnected()) { @@ -777,6 +939,29 @@ RowLayout { BmsInterface.bmsConfig().setParamValue("cellMonitorICCount", parseInt(numberOfBoardsField.text)) BmsInterface.bmsConfig().setParamValue("noOfCellsSeries", parseInt(numberOfCellsField.text)) + const numberOfBoards = parseInt(numberOfBoardsField.text) + const bmsSensorsModel = bmsSensorsMaskRepeater.bmsSensorsMaskModel + const batterySensorsModel = batterySensorsMaskRepeater.batterySensorsMaskModel + + let bmsSensorsMask = 0 + let batterySensorsMask = 0 + for (let i = 0; i < numberOfBoards * 4; ++i) { + bmsSensorsMask |= Number(bmsSensorsModel[i]) << i + batterySensorsMask |= Number(batterySensorsModel[i]) << i + } + + // disable 3 and 4 sensor for master + bmsSensorsMask = bmsSensorsMask & ~(1 << 2) + bmsSensorsMask = bmsSensorsMask & ~(1 << 3) + + batterySensorsMask = batterySensorsMask & ~(1 << 2) + batterySensorsMask = batterySensorsMask & ~(1 << 3) + + print(bmsSensorsMask, batterySensorsMask) + + BmsInterface.bmsConfig().setParamValue("tempEnableMaskBMS", bmsSensorsMask) + BmsInterface.bmsConfig().setParamValue("tempEnableMaskBattery", batterySensorsMask) + BmsInterface.bmsConfig().setParamValue("noOfCellsParallel", parseInt(numberOfParallelCellsField.text)) BmsInterface.bmsConfig().setParamValue("batteryCapacity", parseFloat(batteryCapacityField.text)) @@ -793,6 +978,8 @@ RowLayout { BmsInterface.bmsConfig().setParamValue("cellBalanceDifferenceThreshold", parseFloat(balancingStartDeltaVoltageField.text)) BmsInterface.bmsConfig().setParamValue("cellBalanceUpdateInterval", parseInt(balancingCellIntervalField.text)) + BmsInterface.bmsConfig().setParamValue("floatCurrentK1", parseFloat(currentFactorK1Field.text)) + BmsInterface.bmsConfig().setParamValue("floatCurrentK2", parseFloat(currentFactorK2Field.text)) BmsInterface.bmsConfig().setParamValue("shuntLCFactor", parseFloat(zeroSensorValueField.text)) BmsInterface.bmsConfig().setParamValue("chargeBatteryOutputChecked", chargeBatteryOutputCheckBox.checked) @@ -819,6 +1006,21 @@ RowLayout { numberOfBoardsField.text = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount") numberOfCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsSeries") + const numberOfBoards = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount") + const numberOfSensorsPerBoard = BmsInterface.bmsConfig().getParamInt("noOfTempSensorPerModule") + const bmsSensorsMask = BmsInterface.bmsConfig().getParamInt("tempEnableMaskBMS") + const batterySensorsMask = BmsInterface.bmsConfig().getParamInt("tempEnableMaskBattery") + + const bmsSensorsModel = [] + const batterySensorsModel = [] + for (let i = 0; i < numberOfBoards * numberOfSensorsPerBoard; ++i) { + bmsSensorsModel.push((bmsSensorsMask & (1 << i)) != 0) + batterySensorsModel.push((batterySensorsMask & (1 << i)) != 0) + } + + bmsSensorsMaskRepeater.bmsSensorsMaskModel = bmsSensorsModel + batterySensorsMaskRepeater.batterySensorsMaskModel = batterySensorsModel + numberOfParallelCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsParallel") batteryCapacityField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("batteryCapacity")) @@ -835,7 +1037,9 @@ RowLayout { balancingStartDeltaVoltageField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellBalanceDifferenceThreshold")) balancingCellIntervalField.text = BmsInterface.bmsConfig().getParamInt("cellBalanceUpdateInterval") - zeroSensorValueField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("shuntLCFactor")) + currentFactorK1Field.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("floatCurrentK1"), 3) + currentFactorK2Field.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("floatCurrentK2"), 3) + zeroSensorValueField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("shuntLCFactor"), 3) chargeBatteryOutputCheckBox.checked = BmsInterface.bmsConfig().getParamBool("chargeBatteryOutputChecked") diff --git a/qml/Screens/CanSettingsScreen.qml b/qml/Screens/CanSettingsScreen.qml new file mode 100644 index 0000000..d15177b --- /dev/null +++ b/qml/Screens/CanSettingsScreen.qml @@ -0,0 +1,102 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 1.4 as OldControls + +import Controls 1.0 as Controls +import Cubo 1.0 + +ColumnLayout { + spacing: 10 + + Controls.Frame { + padding: 35 + topPadding: 20 + bottomPadding: 20 + + ColumnLayout { + anchors.fill: parent + spacing: 20 + + Controls.TitleLabel { + text: qsTr("CAN availability state") + Layout.fillWidth: true + } + + GridLayout { + columns: 2 + + Controls.AvailabilityIndicator { + neutral: false + } + + Controls.SubtitleLabel { + text: qsTr("External CAN") + } + + Controls.AvailabilityIndicator { + neutral: false + } + + Controls.SubtitleLabel { + text: qsTr("Charging CAN") + } + + Layout.fillWidth: true + } + + RowLayout { + Controls.CheckBox { + leftPadding: 0 + text: qsTr("External CAN") + } + + Controls.CheckBox { + leftPadding: 0 + text: qsTr("Charging CAN") + } + + Controls.Button { + text: qsTr("Apply") + } + } + } + + Layout.fillWidth: true + } + + Controls.Frame { + padding: 35 + topPadding: 20 + bottomPadding: 20 + + OldControls.TableView { + id: currentTable + anchors.fill: parent +// columnSpacing: 1 +// rowSpacing: 1 + clip: true + + property var currentModel: CurrentTableModel{} + + model: currentModel + +// delegate: Rectangle { +// implicitWidth: 100 +// implicitHeight: 50 +// border.width: 1 + +// Text { +// text: display +// anchors.centerIn: parent +// } +// } + } + + Component.onCompleted: { + currentTable.currentModel.setCurrentData([[0.2, 0.5, 1],[0.2, 0.7, 1],[0.2, 0.6, 1]]) + } + + Layout.fillWidth: true + Layout.fillHeight: true + } +} diff --git a/qml/Screens/TemperatureMonitorScreen.qml b/qml/Screens/TemperatureMonitorScreen.qml new file mode 100644 index 0000000..06c795c --- /dev/null +++ b/qml/Screens/TemperatureMonitorScreen.qml @@ -0,0 +1,287 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 + +import Controls 1.0 as Controls +import Cubo 1.0 +import Utils 1.0 + +Item { + id: root + + property var numberOfBoards: 0 + property var auxSensorsModel: [] + property var expSensorsModel: [] + + ColumnLayout { + spacing: 15 + anchors.fill: parent + + Controls.Frame { + padding: 25 + implicitWidth: parent.width + Layout.fillWidth: true + Layout.rightMargin: 10 + + GridLayout { + columns: 2 + columnSpacing: 70 + rowSpacing: 15 + anchors.fill: parent + + RowLayout { + spacing: 10 + Controls.ContentLabel { + text: qsTr("Minimum battery temperature, °C") + } + + Controls.DotSeparator { + Layout.fillWidth: true + } + + Controls.SubtitleLabel { + id: minBatteryTemperatureLabel + text: "-" + } + + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + RowLayout { + spacing: 10 + Controls.ContentLabel { + text: qsTr("Minimum BMS temperature, °C") + } + + Controls.DotSeparator { + Layout.fillWidth: true + } + + Controls.SubtitleLabel { + id: minBmsTemperatureLabel + text: "-" + } + + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + RowLayout { + spacing: 10 + Controls.ContentLabel { + text: qsTr("Average battery temperature, °C") + } + + Controls.DotSeparator { + Layout.fillWidth: true + } + + Controls.SubtitleLabel { + id: avgBatteryTemperatureLabel + text: "-" + } + + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + RowLayout { + spacing: 10 + Controls.ContentLabel { + text: qsTr("Average BMS temperature, °C") + } + + Controls.DotSeparator { + Layout.fillWidth: true + } + + Controls.SubtitleLabel { + id: avgBmsTemperatureLabel + text: "-" + } + + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + RowLayout { + spacing: 10 + Controls.ContentLabel { + text: qsTr("Maximum battery temperature, °C") + } + + Controls.DotSeparator { + Layout.fillWidth: true + } + + Controls.SubtitleLabel { + id: maxBatteryTemperatureLabel + text: "-" + } + + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + + + + RowLayout { + spacing: 10 + Controls.ContentLabel { + text: qsTr("Maximum BMS temperature, °C") + } + + Controls.DotSeparator { + Layout.fillWidth: true + } + + Controls.SubtitleLabel { + id: maxBmsTemperatureLabel + text: "-" + } + + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + } + } + + Flickable { + id: settingsFlickable + clip: true + contentWidth: width - rightMargin - leftMargin + contentHeight: boardsLayout.height + boundsBehavior: Flickable.StopAtBounds + rightMargin: 10 + + GridLayout { + id: boardsLayout + width: parent.width + columns: 2 + rowSpacing: 15 + columnSpacing: 15 + + Repeater { + model: numberOfBoards + + Controls.Frame { + padding: 25 + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + + ColumnLayout { + id: sensorsLayout + anchors.fill: parent + spacing: 15 + + property var boardIndex: index + + Controls.SubtitleLabel { + text: index === 0 ? qsTr("Sensors for master board") : qsTr("Sensors for slave board #") + index + maximumLineCount: 2 + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + Repeater { + model: 4 + + RowLayout { + spacing: 10 + opacity: (sensorsLayout.boardIndex === 0 && (index === 2 || index === 3)) ? 0 : 1 + Controls.ContentLabel { + text: qsTr("Sensor #") + (index + 1) + ", °C" + } + + Controls.DotSeparator { + Layout.fillWidth: true + } + + Controls.SubtitleLabel { + text: { + var value = auxSensorsModel[sensorsLayout.boardIndex * 4 + index] + return value ? value : 0 + } + } + + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } + } + } + } + } + } + + ScrollBar.vertical: Controls.ScrollBar {} + + Layout.fillWidth: true + Layout.fillHeight: true + } + } + + Connections { + target: BmsInterface.commands() + enabled: root.visible + + onValuesReceived: { + maxBatteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattHigh) + avgBatteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattAverage) + minBatteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattLow) + + maxBmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSHigh) + avgBmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSAverage) + minBmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSLow) + } + + onAuxReceived: { + let tempModel = [] + for (let temperature of auxVoltageArray) { + tempModel.push(temperature) + } + + auxSensorsModel = [] + auxSensorsModel = tempModel + } + + onExpTempReceived: { + let tempModel = [] + for (let temperature of expTempVoltageArray) { + tempModel.push(temperature) + } + + expSensorsModel = [] + expSensorsModel = tempModel + } + } + + Connections { + target: BmsInterface.bmsConfig() + onUpdated: { + numberOfBoards = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount") + } + } + + Connections { + target: BmsInterface + onPortConnectedChanged: getValues() + } + + onVisibleChanged: getValues() + + Timer { + id: refreshValuesTimer + interval: 1000 + onTriggered: getValues() + } + + function getValues() { + if (BmsInterface.isPortConnected() && visible) { + BmsInterface.commands().getValues() + BmsInterface.commands().getAux() +// BmsInterface.commands().getExpansionTemp() + refreshValuesTimer.start() + } + } +} diff --git a/qml/Screens/qmldir b/qml/Screens/qmldir index 73b47d6..1b900e3 100644 --- a/qml/Screens/qmldir +++ b/qml/Screens/qmldir @@ -12,3 +12,5 @@ TerminalScreen 1.0 TerminalScreen.qml FirmwareUpdateScreen 1.0 FirmwareUpdateScreen.qml NetworkSettingsScreen 1.0 NetworkSettingsScreen.qml TimeSettingsScreen 1.0 TimeSettingsScreen.qml +CanSettingsScreen 1.0 CanSettingsScreen.qml +TemperatureMonitorScreen 1.0 TemperatureMonitorScreen.qml diff --git a/qml/qml_icons.qrc b/qml/qml_icons.qrc index e4e65f8..dfffef1 100644 --- a/qml/qml_icons.qrc +++ b/qml/qml_icons.qrc @@ -18,5 +18,6 @@ Icons/italian-flag.svg Icons/russian-flag.svg Icons/refresh.svg + Icons/temperature.svg diff --git a/qml/qml_items.qrc b/qml/qml_items.qrc index 69e18f8..6f5045f 100644 --- a/qml/qml_items.qrc +++ b/qml/qml_items.qrc @@ -47,5 +47,7 @@ Screens/NetworkSettingsScreen.qml Screens/TimeSettingsScreen.qml Controls/RadioButton.qml + Screens/TemperatureMonitorScreen.qml + Screens/CanSettingsScreen.qml diff --git a/res/config.xml b/res/config.xml index 64ec9e8..e5d6844 100644 --- a/res/config.xml +++ b/res/config.xml @@ -2622,6 +2622,50 @@ p, li { white-space: pre-wrap; } °C 4 + + Current factor K1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current factor K1.</p></body></html> + FLOAT_CURRENT_K1 + 6 + 1 + 0 + 1.17549e-38 + 3.40282e+38 + 0 + 0.05 + 0 + 100000 + + 9 + + + Current factor K2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current factor K2.</p></body></html> + FLOAT_CURRENT_K1 + 6 + 1 + 0 + 1.17549e-38 + 3.40282e+38 + 0 + 0.05 + 0 + 100000 + + 9 + noOfCellsSeries @@ -2729,5 +2773,7 @@ p, li { white-space: pre-wrap; } heatingOutputChecked heatingStartThreshold heatingStopThreshold + floatCurrentK1 + floatCurrentK2 diff --git a/translations/cubo_en.ts b/translations/cubo_en.ts index 34a5ac1..dc09868 100644 --- a/translations/cubo_en.ts +++ b/translations/cubo_en.ts @@ -233,259 +233,325 @@ BmsSettingsScreen - + Serial number - - + + Configuration - + Number of boards - + Number of cells - - - SOC - - - - - Number of cells connected in parallel - - - - - Battery capacity - - - - - - Limits - - - - - Maximum charge current, A - - - - - Maximum load current, A - - - - - Maximum temperature, °C - - - - - - Cell configuration + + + # + + SOC + + + + + Number of cells connected in parallel + + + + + Battery capacity + + + + + + Limits + + + + + Maximum charge current, A + + + + + Maximum load current, A + + + + + Maximum temperature, °C + + + + + + Cell configuration + + + + Lower disable threshold, V - + Upper disable threshold, V - + Lower enable threshold (should be higher than disable), V - + Upper enable threshold (should be higher than disable), V - - + + Balancing configuration - + Balancing start voltage, V - + Cell voltage delta to start balancing, V - + Cell balancing interval, ms - - + + + Current configuration + + + + + Current factor K1 + + + + + Current factor K2 + + + + + Output settings - + # 1 - + # 2 - + Active - + Brush control - + Shunt charging contactor - + SOC threshold, % - + Delay, s - + # 3 - + Cooling activation - + # 4 - + Heating activation - + BMS configuration saved to file - + Read default settings - + The settings are written to non-volatile memory. Wait, please. - - + + Closes at t<, °C - + Use to control charger - - + + Opens at t>, °C - - + Current sensor value "0" - + + BMS sensors mask for master board + + + + + BMS sensors mask for slave board # + + + + + Battery sensors mask for master board + + + + + Battery sensors mask for slave board # + + + + Calibrate "0" - + Load settings from file - - + + Select configuration file - - + + Configuration files (*.xml) - - + + All files (*) - + Save settings to file - + Read current settings from BMS - + Write to non-volatile memory of BMS - + Write current values to BMS + + CanSettingsScreen + + + CAN availability state + + + + + + External CAN + + + + + + Charging CAN + + + + + Apply + + + CellMonitorScreen @@ -698,75 +764,81 @@ Reconnect to the board if you want to continue working with it. - + AKB monitor - + Cell monitor - Configuration + + Temperature monitor - - Visualization + Configuration - History + + Visualization + History + + + + BMS service - + Connection - + BMS settings - + Information output - - + + Disconnected - + Serial number - + Connected - + Firmware update - + Tool started @@ -830,6 +902,54 @@ Reconnect to the board if you want to continue working with it. + + TemperatureMonitorScreen + + + Minimum battery temperature, °C + + + + + Minimum BMS temperature, °C + + + + + Average battery temperature, °C + + + + + Average BMS temperature, °C + + + + + Maximum battery temperature, °C + + + + + Maximum BMS temperature, °C + + + + + Sensors for master board + + + + + Sensors for slave board # + + + + + Sensor # + + + TerminalScreen diff --git a/translations/cubo_it.ts b/translations/cubo_it.ts index 3848412..ba08213 100644 --- a/translations/cubo_it.ts +++ b/translations/cubo_it.ts @@ -233,259 +233,325 @@ BmsSettingsScreen - + Serial number - - + + Configuration - + Number of boards - + Number of cells - - - SOC - - - - - Number of cells connected in parallel - - - - - Battery capacity - - - - - - Limits - - - - - Maximum charge current, A - - - - - Maximum load current, A - - - - - Maximum temperature, °C - - - - - - Cell configuration + + + # + + SOC + + + + + Number of cells connected in parallel + + + + + Battery capacity + + + + + + Limits + + + + + Maximum charge current, A + + + + + Maximum load current, A + + + + + Maximum temperature, °C + + + + + + Cell configuration + + + + Lower disable threshold, V - + Upper disable threshold, V - + Lower enable threshold (should be higher than disable), V - + Upper enable threshold (should be higher than disable), V - - + + Balancing configuration - + Balancing start voltage, V - + Cell voltage delta to start balancing, V - + Cell balancing interval, ms - - + + + Current configuration + + + + + Current factor K1 + + + + + Current factor K2 + + + + + Output settings - + # 1 - + # 2 - + Active - + Brush control - + Shunt charging contactor - + SOC threshold, % - + Delay, s - + # 3 - + Cooling activation - + # 4 - + Heating activation - + BMS configuration saved to file - + Read default settings - + The settings are written to non-volatile memory. Wait, please. - - + + Closes at t<, °C - + Use to control charger - - + + Opens at t>, °C - - + Current sensor value "0" - + + BMS sensors mask for master board + + + + + BMS sensors mask for slave board # + + + + + Battery sensors mask for master board + + + + + Battery sensors mask for slave board # + + + + Calibrate "0" - + Load settings from file - - + + Select configuration file - - + + Configuration files (*.xml) - - + + All files (*) - + Save settings to file - + Read current settings from BMS - + Write to non-volatile memory of BMS - + Write current values to BMS + + CanSettingsScreen + + + CAN availability state + + + + + + External CAN + + + + + + Charging CAN + + + + + Apply + + + CellMonitorScreen @@ -698,75 +764,81 @@ Reconnect to the board if you want to continue working with it. - + AKB monitor - + Cell monitor - Configuration + + Temperature monitor - - Visualization + Configuration - History + + Visualization + History + + + + BMS service - + Connection - + BMS settings - + Information output - - + + Disconnected - + Serial number - + Connected - + Firmware update - + Tool started @@ -830,6 +902,54 @@ Reconnect to the board if you want to continue working with it. + + TemperatureMonitorScreen + + + Minimum battery temperature, °C + + + + + Minimum BMS temperature, °C + + + + + Average battery temperature, °C + + + + + Average BMS temperature, °C + + + + + Maximum battery temperature, °C + + + + + Maximum BMS temperature, °C + + + + + Sensors for master board + + + + + Sensors for slave board # + + + + + Sensor # + + + TerminalScreen diff --git a/translations/cubo_ru.qm b/translations/cubo_ru.qm index e604c23..fc9b69c 100644 Binary files a/translations/cubo_ru.qm and b/translations/cubo_ru.qm differ diff --git a/translations/cubo_ru.ts b/translations/cubo_ru.ts index 0dde5cd..341fa78 100644 --- a/translations/cubo_ru.ts +++ b/translations/cubo_ru.ts @@ -240,128 +240,170 @@ Time settings Настройки времени + + CAN settings + Настройки CAN + BmsSettingsScreen - + Serial number Серийный номер - - + + Configuration Конфигурация - + Number of boards Количество плат - + Number of cells Количество ячеек - - + Number of sensors + Количество сенсоров + + + Number of temperature sensors + Количество сенсоров температуры + + + Sensor mask for BMS temperature + Маска сенсоров для температуры BMS + + + + + # + + + + Sensor mask for battery temperature + Маска сенсоров для температуры батареи + + + + SOC SOC - + Number of cells connected in parallel Количество параллельно включенных ячеек - + Battery capacity Ёмкость батареи - - + + Limits Ограничения - + Maximum charge current, A Максимальный ток заряда, A - + Maximum load current, A Максимальный ток нагрузки, A - + Maximum temperature, °C Максимальная температура, C - - + + Cell configuration Конфигурация ячеек - + Lower disable threshold, V Нижний порог отключения, В - + Upper disable threshold, V Верхний порог отключения, В - + Lower enable threshold (should be higher than disable), V Нижний порог включения (должен быть выше отключения), В - + Upper enable threshold (should be higher than disable), V Верхний порог включения (должен быть выше отключения), В - - + + Balancing configuration Конфигурация балансировки - + Balancing start voltage, V Напряжение старта балансировки, В - + Cell voltage delta to start balancing, V Дельта напряжения ячеек для старта балансировки, В - + Cell balancing interval, ms Интервал балансировки ячейки, мс - - + + + Current configuration + Конфигурация тока + + + + Current factor K1 + Коэффициент тока К1 + + + + Current factor K2 + Коэффициент тока К2 + + + + Output settings Настройка выходов - + # 1 № 1 - + Use to control charger Использовать для управления ЗУ @@ -370,67 +412,67 @@ Использовать для управления ЗУ - + # 2 № 2 - + Active Активный - + Brush control Управление щетками - + Shunt charging contactor Шунтирование зарядного контактора - + SOC threshold, % Уровень SOC, % - + Delay, s Задержка, с - + # 3 № 3 - + Cooling activation Активация охлаждения - + # 4 № 4 - + Heating activation Активация обогрева - + BMS configuration saved to file БМС конфигурация сохранена в файл - + Read default settings Загрузить настройки по-умолчанию - + The settings are written to non-volatile memory. Wait, please. Выполняется запись настроек в энергонезависимую память. @@ -445,53 +487,72 @@ Wait, please. Изменение значения при SOC - - + + Closes at t<, °C Замыкается при t<, °C - - + + Opens at t>, °C Размыкается при t>, °C - - + Current sensor value "0" Значение датчика тока «0» - + + BMS sensors mask for master board + Маска сенсоров BMS для основной платы + + + + BMS sensors mask for slave board # + Маска сенсоров BMS для дополнительной платы № + + + + Battery sensors mask for master board + Маска сенсоров батареи для основной платы + + + + Battery sensors mask for slave board # + Маска сенсоров батареи для дополнительной платы № + + + Calibrate "0" Калибровать «0» - + Load settings from file Загрузить настройки из файла - - + + Select configuration file Выберите файл конфигурации - - + + Configuration files (*.xml) Файлы конфигурации (*.xml) - - + + All files (*) Все файлы (*) - + Save settings to file Сохранить настройки в файл @@ -500,21 +561,46 @@ Wait, please. Загрузить настройки из файла - + Read current settings from BMS Загрузить текущие настройки из BMS - + Write to non-volatile memory of BMS Записать в энергонезависимую память BMS - + Write current values to BMS Записать текущие значения в BMS + + CanSettingsScreen + + + CAN availability state + + + + + + External CAN + + + + + + Charging CAN + + + + + Apply + Применить + + CellMonitorScreen @@ -737,54 +823,60 @@ Reconnect to the board if you want to continue working with it. - + AKB monitor Монитор АКБ - + Cell monitor Монитор ячеек + + Temperature monitor + Монитор температур + + + Configuration Конфигурация - - + + Visualization Визуализация - + History История - + BMS service Сервис BMS - + Connection Подключение - + BMS settings Настройка BMS - + Information output Вывод информации - + Firmware update Обновление прошивки @@ -793,7 +885,7 @@ Reconnect to the board if you want to continue working with it. Терминал - + Tool started Утилита запущена @@ -802,18 +894,18 @@ Reconnect to the board if you want to continue working with it. Выход - - + + Disconnected Отключено - + Serial number Серийный номер - + Connected Подключено @@ -877,6 +969,54 @@ Reconnect to the board if you want to continue working with it. Не удалось автоматически подключиться. Убедитесь, что USB-кабель подключен и ENNOID-BMS включен. + + TemperatureMonitorScreen + + + Minimum battery temperature, °C + Минимальная температура батареи, °C + + + + Minimum BMS temperature, °C + Минимальная температура BMS, °C + + + + Average battery temperature, °C + Средняя температура батареи, °C + + + + Average BMS temperature, °C + Средняя температура BMS, °C + + + + Maximum battery temperature, °C + Максимальная температура батареи, °C + + + + Maximum BMS temperature, °C + Максимальная температура BMS, °C + + + + Sensors for master board + Сенсоры для основной платы + + + + Sensors for slave board # + Сенсоры для дополнительной платы № + + + + Sensor # + Сенсор № + + TerminalScreen