35 Commits

Author SHA1 Message Date
Yury Shuvakin
3ab8a2b92a Hidden BMS temperature from Monitor screen 2024-02-15 13:01:28 +09:00
Yury Shuvakin
a83ecbb042 Hidden BMS temperature controls. Fixed translations 2024-01-22 12:26:22 +09:00
Yury Shuvakin
649c9ed2a0 Added fault state popup 2023-03-26 23:45:49 +03:00
Yury Shuvakin
960dd6ba88 Hided CAN settings 2023-03-21 10:10:59 +03:00
Yury Shuvakin
0daea7162a Added temperature monitor screen. Added current factors for BMS configuration 2023-03-21 10:10:28 +03:00
Yury Shuvakin
7c732215ec Fixed point info display on visualization screen. Removed version number from app name 2022-11-28 06:32:26 +03:00
Yury Shuvakin
92c3e42039 Implemented functionality to control outputs for BMS 2022-11-26 09:28:58 +03:00
Yury Shuvakin
eb89c386a3 Added reading default network settings 2022-11-25 05:39:37 +03:00
Yury Shuvakin
c231735900 Fixed deployment svg images for MacOS 2022-11-11 12:56:22 +03:00
Yury Shuvakin
2595c7bb65 Fixed writing and reading time on the board 2022-11-03 06:29:20 +03:00
Yury Shuvakin
868a810eda Changed project name 2022-10-03 11:24:06 +03:00
Yury Shuvakin
7be70e1ade Fixed Akb monitor layout 2022-10-03 11:21:05 +03:00
Yury Shuvakin
1d77dcbfcd Implemented time adjustment on the board 2022-09-16 06:57:03 +03:00
Yury Shuvakin
dd63a2bf4c Added display of network settings application status. Added axis indicators for the legend that contains information about the point 2022-09-16 03:41:01 +03:00
Yury Shuvakin
12c4535e06 Implemented network settings 2022-09-16 03:22:47 +03:00
Yury Shuvakin
4dd1f95193 Added board firmware update functionality 2022-09-13 15:20:09 +03:00
Yury Shuvakin
d28efef208 Updated translations 2022-09-09 16:40:42 +03:00
Yury Shuvakin
3d0f39f846 Various changes have been made as a result of the discussion of the first version 2022-09-09 16:36:44 +03:00
Yury Shuvakin
1fc06361f8 Added some UI fixes 2022-08-29 02:57:42 +03:00
Yury Shuvakin
86b73ca662 Now the line is highlighted with a dotted line when hovering over it in the legend 2022-08-28 20:25:02 +03:00
Yury Shuvakin
46dedab567 Updated translations 2022-08-28 20:02:25 +03:00
Yury Shuvakin
e31c509341 Added a button to update the list of ports. Changed the colors of the lines on the charts. Added translations for qt libraries 2022-08-28 20:01:40 +03:00
Yury Shuvakin
545977a4b7 Added scrollbars for lists and text fields. Added saving to the path settings for configuration files and the current language. Various UI improvements 2022-08-28 16:32:07 +03:00
Yury Shuvakin
4a0f78c247 A system of translations into different languages has been implemented. Added translations into Russian. Various UI fixes for valid internationalization 2022-08-28 11:33:56 +03:00
Yury Shuvakin
2a960893d0 Added horizontal legend for a small number of series on the chart 2022-08-26 13:45:04 +03:00
Yury Shuvakin
fdaca40a06 Implemented writing configuration settings to the board. Added various fixes for configuration fields 2022-08-26 13:24:00 +03:00
Yury Shuvakin
046d1f55ce Cell balancing calculation added. Fixed rounding of real numbers to the second decimal place 2022-08-26 09:30:07 +03:00
Yury Shuvakin
6ae4386b37 Implemented a screen displaying the history of operations with the board. Added dialogs for displaying messages and statuses 2022-08-26 07:34:04 +03:00
Yury Shuvakin
79518df613 Implemented terminal screen 2022-08-25 09:19:00 +03:00
Yury Shuvakin
d1ba61acd8 Implemented a visualization screen for various board parameters 2022-08-25 07:59:16 +03:00
Yury Shuvakin
8abae06275 Added validators for various configuration settings. Implemented reading the configuration and loading the default configuration 2022-08-23 01:33:17 +03:00
Yury Shuvakin
eda44940d3 Added UI skeleton for BMS settings screen 2022-08-18 07:06:37 +03:00
Yury Shuvakin
4a5a0bcb3a Implemented cell monitor screen 2022-08-17 05:30:25 +03:00
Yury Shuvakin
a4196df821 Implemented AKB monitor screen 2022-08-17 01:09:17 +03:00
Yury Shuvakin
dce22c65d6 Implemented QML skeleton for the application 2022-08-15 08:49:12 +03:00
110 changed files with 11346 additions and 441 deletions

192
CUBO-BMS-Tool.pro Normal file
View File

@@ -0,0 +1,192 @@
#-------------------------------------------------
#
# Project created by QtCreator 2016-08-12T21:55:19
#
#-------------------------------------------------
INCLUDEPATH += $$PWD
# Version
DT_VERSION = 2.0
DEFINES += DT_VERSION=$$DT_VERSION
!android: {
# Serial port available
DEFINES += HAS_SERIALPORT
}
CONFIG += c++14
# Options
#Build mobile GUI
#CONFIG += build_mobile
# Bluetooth available
#DEFINES += HAS_BLUETOOTH
QT += core gui xml svg
#QT += widgets
#QT += printsupport
QT += network
#QT += bluetooth
QT += quick
QT += quickcontrols2
QT += charts
contains(DEFINES, HAS_SERIALPORT) {
QT += serialport
}
android: QT += androidextras
TARGET = CUBO-BMS-Tool
TEMPLATE = app
release_win {
DESTDIR = build/win
OBJECTS_DIR = build/win/obj
MOC_DIR = build/win/obj
RCC_DIR = build/win/obj
UI_DIR = build/win/obj
}
release_lin {
# http://micro.nicholaswilson.me.uk/post/31855915892/rules-of-static-linking-libstdc-libc-libgcc
# http://insanecoding.blogspot.se/2012/07/creating-portable-linux-binaries.html
QMAKE_LFLAGS += -static-libstdc++ -static-libgcc
DESTDIR = build/lin
OBJECTS_DIR = build/lin/obj
MOC_DIR = build/lin/obj
RCC_DIR = build/lin/obj
UI_DIR = build/lin/obj
}
release_android {
DESTDIR = build/android
OBJECTS_DIR = build/android/obj
MOC_DIR = build/android/obj
RCC_DIR = build/android/obj
UI_DIR = build/android/obj
}
#build_mobile {
# DEFINES += USE_MOBILE
#}
SOURCES += main.cpp\
# akbmonitorpage.cpp \
# bmsservicepage.cpp \
# bmssettings.cpp \
# bmssettingswidget.cpp \
# cellsmonitorcheckboxdelegate.cpp \
# cellsmonitorlabelvoltagedelegate.cpp \
# cellsmonitorpage.cpp \
# configparamsgetter.cpp \
# configurationpage.cpp \
# connectandenterpage.cpp \
# customlefttabbarbutton.cpp \
# debugprintpage.cpp \
# historylineeditbox.cpp \
# hoverablecombobox.cpp \
# languageselectorbutton.cpp \
# mainwindow.cpp \
# mainwindownew.cpp \
packet.cpp \
# settingsextrapage.cpp \
vbytearray.cpp \
commands.cpp \
configparams.cpp \
configparam.cpp \
# parametereditor.cpp \
# digitalfiltering.cpp \
# bleuart.cpp \
utility.cpp \
bmsinterface.cpp \
translator.cpp \
firmwareupdatehelper.cpp \
currenttablemodel.cpp \
# visualizationchart.cpp \
# visualizationpage.cpp
HEADERS += \ #mainwindow.h \
# akbmonitorpage.h \
# bmsservicepage.h \
# bmssettings.h \
# bmssettingswidget.h \
# cellsmonitorcheckboxdelegate.h \
# cellsmonitorlabelvoltagedelegate.h \
# cellsmonitorpage.h \
# configparamsgetter.h \
# configurationpage.h \
# connectandenterpage.h \
# customlefttabbarbutton.h \
# debugprintpage.h \
# historylineedit.h \
# historylineeditbox.h \
# hoverablecombobox.h \
# languageselectorbutton.h \
# mainwindownew.h \
packet.h \
# settingsextrapage.h \
vbytearray.h \
commands.h \
datatypes.h \
configparams.h \
configparam.h \
# parametereditor.h \
# digitalfiltering.h \
# bleuart.h \
utility.h \
bmsinterface.h \
translator.h \
firmwareupdatehelper.h \
currenttablemodel.h \
# visualizationchart.h \
# visualizationpage.h
#FORMS += mainwindow.ui \
# akbmonitorpage.ui \
# bmsservicepage.ui \
# bmssettings.ui \
# bmssettingswidget.ui \
# cellsmonitorpage.ui \
# configurationpage.ui \
# connectandenterpage.ui \
# debugprintpage.ui \
# mainwindownew.ui \
# parametereditor.ui \
# settingsextrapage.ui \
# visualizationpage.ui
#include(pages/pages.pri)
#include(widgets/widgets.pri)
#include(mobile/mobile.pri)
RESOURCES += res.qrc \
translations/translations.qrc
RESOURCES += qml/qml_icons.qrc \
qml/qml_items.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH *= $$PWD/qml
QML2_IMPORT_PATH *= $$PWD/qml
TRANSLATIONS = translations/cubo_en.ts \
translations/cubo_ru.ts \
translations/cubo_it.ts
RC_ICONS = qml/Icons/cubo-icon.ico
DISTFILES += \
android/AndroidManifest.xml \
android/gradle/wrapper/gradle-wrapper.jar \
android/gradlew \
android/res/values/libs.xml \
android/build.gradle \
android/gradle/wrapper/gradle-wrapper.properties
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
ANDROID_ABIS = x86

View File

@@ -1,176 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2016-08-12T21:55:19
#
#-------------------------------------------------
INCLUDEPATH += $$PWD
# Version
DT_VERSION = 1.3
DEFINES += DT_VERSION=$$DT_VERSION
!android: {
# Serial port available
DEFINES += HAS_SERIALPORT
}
CONFIG += c++11
QMAKE_CXXFLAGS += -Wno-deprecated-copy
# Options
#Build mobile GUI
#CONFIG += build_mobile
# Bluetooth available
DEFINES += HAS_BLUETOOTH
QT += core gui
QT += widgets
QT += printsupport
QT += network
QT += bluetooth
QT += quick
QT += quickcontrols2
QT += charts
contains(DEFINES, HAS_SERIALPORT) {
QT += serialport
}
android: QT += androidextras
android: TARGET = ENNOID-BMS-Tool
!android: TARGET = ENNOID-BMS-ToolV$$DT_VERSION
TEMPLATE = app
release_win {
DESTDIR = build/win
OBJECTS_DIR = build/win/obj
MOC_DIR = build/win/obj
RCC_DIR = build/win/obj
UI_DIR = build/win/obj
}
release_lin {
# http://micro.nicholaswilson.me.uk/post/31855915892/rules-of-static-linking-libstdc-libc-libgcc
# http://insanecoding.blogspot.se/2012/07/creating-portable-linux-binaries.html
QMAKE_LFLAGS += -static-libstdc++ -static-libgcc
DESTDIR = build/lin
OBJECTS_DIR = build/lin/obj
MOC_DIR = build/lin/obj
RCC_DIR = build/lin/obj
UI_DIR = build/lin/obj
}
release_android {
DESTDIR = build/android
OBJECTS_DIR = build/android/obj
MOC_DIR = build/android/obj
RCC_DIR = build/android/obj
UI_DIR = build/android/obj
}
build_mobile {
DEFINES += USE_MOBILE
}
SOURCES += main.cpp\
akbmonitorpage.cpp \
bmsservicepage.cpp \
bmssettings.cpp \
bmssettingswidget.cpp \
cellsmonitorcheckboxdelegate.cpp \
cellsmonitorlabelvoltagedelegate.cpp \
cellsmonitorpage.cpp \
configparamsgetter.cpp \
configurationpage.cpp \
connectandenterpage.cpp \
customlefttabbarbutton.cpp \
debugprintpage.cpp \
historylineeditbox.cpp \
hoverablecombobox.cpp \
languageselectorbutton.cpp \
mainwindow.cpp \
mainwindownew.cpp \
packet.cpp \
settingsextrapage.cpp \
vbytearray.cpp \
commands.cpp \
configparams.cpp \
configparam.cpp \
parametereditor.cpp \
digitalfiltering.cpp \
bleuart.cpp \
utility.cpp \
bmsinterface.cpp \
visualizationchart.cpp \
visualizationpage.cpp
HEADERS += mainwindow.h \
akbmonitorpage.h \
bmsservicepage.h \
bmssettings.h \
bmssettingswidget.h \
cellsmonitorcheckboxdelegate.h \
cellsmonitorlabelvoltagedelegate.h \
cellsmonitorpage.h \
configparamsgetter.h \
configurationpage.h \
connectandenterpage.h \
customlefttabbarbutton.h \
debugprintpage.h \
historylineedit.h \
historylineeditbox.h \
hoverablecombobox.h \
languageselectorbutton.h \
mainwindownew.h \
packet.h \
settingsextrapage.h \
vbytearray.h \
commands.h \
datatypes.h \
configparams.h \
configparam.h \
parametereditor.h \
digitalfiltering.h \
bleuart.h \
utility.h \
bmsinterface.h \
visualizationchart.h \
visualizationpage.h
FORMS += mainwindow.ui \
akbmonitorpage.ui \
bmsservicepage.ui \
bmssettings.ui \
bmssettingswidget.ui \
cellsmonitorpage.ui \
configurationpage.ui \
connectandenterpage.ui \
debugprintpage.ui \
mainwindownew.ui \
parametereditor.ui \
settingsextrapage.ui \
visualizationpage.ui
include(pages/pages.pri)
include(widgets/widgets.pri)
include(mobile/mobile.pri)
RESOURCES += res.qrc
DISTFILES += \
android/AndroidManifest.xml \
android/gradle/wrapper/gradle-wrapper.jar \
android/gradlew \
android/res/values/libs.xml \
android/build.gradle \
android/gradle/wrapper/gradle-wrapper.properties
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
ANDROID_ABIS = x86

View File

@@ -89,8 +89,11 @@ BMSInterface::BMSInterface(QObject *parent) : QObject(parent)
// BLE // BLE
#ifdef HAS_BLUETOOTH
mBleUart = new BleUart(this); mBleUart = new BleUart(this);
mLastBleAddr = QSettings().value("ble_addr").toString(); mLastBleAddr = QSettings().value("ble_addr").toString();
connect(mBleUart, SIGNAL(dataRx(QByteArray)), this, SLOT(bleDataRx(QByteArray)));
#endif
int size = mSettings.beginReadArray("bleNames"); int size = mSettings.beginReadArray("bleNames");
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
@@ -101,8 +104,6 @@ BMSInterface::BMSInterface(QObject *parent) : QObject(parent)
} }
mSettings.endArray(); mSettings.endArray();
connect(mBleUart, SIGNAL(dataRx(QByteArray)), this, SLOT(bleDataRx(QByteArray)));
mCommands->setbmsConfig(mbmsConfig); mCommands->setbmsConfig(mbmsConfig);
// Other signals/slots // Other signals/slots
@@ -112,8 +113,8 @@ BMSInterface::BMSInterface(QObject *parent) : QObject(parent)
connect(mCommands, SIGNAL(dataToSend(QByteArray&)),this, SLOT(cmdDataToSend(QByteArray&))); connect(mCommands, SIGNAL(dataToSend(QByteArray&)),this, SLOT(cmdDataToSend(QByteArray&)));
connect(mCommands, SIGNAL(fwVersionReceived(int,int,QString,QByteArray)),this, SLOT(fwVersionReceived(int,int,QString,QByteArray))); connect(mCommands, SIGNAL(fwVersionReceived(int,int,QString,QByteArray)),this, SLOT(fwVersionReceived(int,int,QString,QByteArray)));
connect(mCommands, SIGNAL(ackReceived(QString)), this, SLOT(ackReceived(QString))); connect(mCommands, SIGNAL(ackReceived(QString)), this, SLOT(ackReceived(QString)));
connect(mbmsConfig, SIGNAL(updated()), this, SLOT(bmsconfUpdated())); connect(mbmsConfig, SIGNAL(updated()), this, SLOT(bmsConfUpdated()));
connect(mbmsConfig, SIGNAL(stored()), this, SLOT(bmsconfStored())); connect(mbmsConfig, SIGNAL(stored()), this, SLOT(bmsConfStored()));
} }
BMSInterface::~BMSInterface() BMSInterface::~BMSInterface()
@@ -280,9 +281,11 @@ bool BMSInterface::isPortConnected()
res = true; res = true;
} }
#ifdef HAS_BLUETOOTH
if (mBleUart->isConnected()) { if (mBleUart->isConnected()) {
res = true; res = true;
} }
#endif
return res; return res;
} }
@@ -301,10 +304,12 @@ void BMSInterface::disconnectPort()
updateFwRx(false); updateFwRx(false);
} }
#ifdef HAS_BLUETOOTH
if (mBleUart->isConnected()) { if (mBleUart->isConnected()) {
mBleUart->disconnectBle(); mBleUart->disconnectBle();
updateFwRx(false); updateFwRx(false);
} }
#endif
mFwRetries = 0; mFwRetries = 0;
} }
@@ -321,8 +326,12 @@ bool BMSInterface::reconnectLastPort()
connectTcp(mLastTcpServer, mLastTcpPort); connectTcp(mLastTcpServer, mLastTcpPort);
return true; return true;
} else if (mLastConnType == CONN_BLE) { } else if (mLastConnType == CONN_BLE) {
#ifdef HAS_BLUETOOTH
mBleUart->startConnect(mLastBleAddr); mBleUart->startConnect(mLastBleAddr);
return true; return true;
#else
return false;
#endif
} else { } else {
#ifdef HAS_SERIALPORT #ifdef HAS_SERIALPORT
QList<VSerialInfo_t> ports = listSerialPorts(); QList<VSerialInfo_t> ports = listSerialPorts();
@@ -408,10 +417,12 @@ QString BMSInterface::getConnectedPortName()
connected = true; connected = true;
} }
#ifdef HAS_BLUETOOTH
if (mBleUart->isConnected()) { if (mBleUart->isConnected()) {
res = tr("Connected (BLE) to %1").arg(mLastBleAddr); res = tr("Connected (BLE) to %1").arg(mLastBleAddr);
connected = true; connected = true;
} }
#endif
if (connected && mCommands->isLimitedMode()) { if (connected && mCommands->isLimitedMode()) {
res += tr(", limited mode"); res += tr(", limited mode");
@@ -429,7 +440,7 @@ bool BMSInterface::connectSerial(QString port, int baudrate)
bool found = false; bool found = false;
for (VSerialInfo_t ser: listSerialPorts()) { for (VSerialInfo_t ser: listSerialPorts()) {
if (ser.systemPath == port) { if (ser.name == port) {
found = true; found = true;
break; break;
} }
@@ -517,6 +528,16 @@ QList<VSerialInfo_t> BMSInterface::listSerialPorts()
return res; return res;
} }
QStringList BMSInterface::serialPortNames()
{
QStringList names;
for (const auto& info: listSerialPorts())
{
names.append(info.name);
}
return names;
}
void BMSInterface::connectTcp(QString server, int port) void BMSInterface::connectTcp(QString server, int port)
{ {
mLastTcpServer = server; mLastTcpServer = server;
@@ -541,10 +562,12 @@ void BMSInterface::connectTcp(QString server, int port)
void BMSInterface::connectBle(QString address) void BMSInterface::connectBle(QString address)
{ {
#ifdef HAS_BLUETOOTH
mBleUart->startConnect(address); mBleUart->startConnect(address);
mLastConnType = CONN_BLE; mLastConnType = CONN_BLE;
mLastBleAddr = address; mLastBleAddr = address;
setLastConnectionType(CONN_BLE); setLastConnectionType(CONN_BLE);
#endif
} }
bool BMSInterface::isAutoconnectOngoing() const bool BMSInterface::isAutoconnectOngoing() const
@@ -605,7 +628,6 @@ void BMSInterface::ignoreCanChange(bool ignore)
#ifdef HAS_SERIALPORT #ifdef HAS_SERIALPORT
void BMSInterface::serialDataAvailable() void BMSInterface::serialDataAvailable()
{ {
bool b = true;
while (mSerialPort->bytesAvailable() > 0) { while (mSerialPort->bytesAvailable() > 0) {
mPacket->processData(mSerialPort->readAll()); mPacket->processData(mSerialPort->readAll());
} }
@@ -619,7 +641,7 @@ void BMSInterface::serialPortError(QSerialPort::SerialPortError error)
break; break;
default: default:
message = "Serial port error: " + mSerialPort->errorString(); message = tr("Serial port error: ") + mSerialPort->errorString();
break; break;
} }
@@ -637,7 +659,6 @@ void BMSInterface::serialPortError(QSerialPort::SerialPortError error)
void BMSInterface::tcpInputConnected() void BMSInterface::tcpInputConnected()
{ {
bool b = true;
mTcpConnected = true; mTcpConnected = true;
updateFwRx(false); updateFwRx(false);
} }
@@ -650,7 +671,6 @@ void BMSInterface::tcpInputDisconnected()
void BMSInterface::tcpInputDataAvailable() void BMSInterface::tcpInputDataAvailable()
{ {
bool b = true;
while (mTcpSocket->bytesAvailable() > 0) { while (mTcpSocket->bytesAvailable() > 0) {
mPacket->processData(mTcpSocket->readAll()); mPacket->processData(mTcpSocket->readAll());
} }
@@ -725,9 +745,13 @@ void BMSInterface::timerSlot()
if (mIsUploadingFw) { if (mIsUploadingFw) {
updateFwRx(false); updateFwRx(false);
mFwRetries = 0; mFwRetries = 0;
if (fwStatus.compare("FW Upload Done") == 0) { if (mCommands->getFirmwareUploadSuccess())
{
disconnectPort();
emit fwUploadStatus(fwStatus, 1.0, false); emit fwUploadStatus(fwStatus, 1.0, false);
} else { }
else
{
emit fwUploadStatus(fwStatus, 0.0, false); emit fwUploadStatus(fwStatus, 0.0, false);
} }
} }
@@ -752,9 +776,11 @@ void BMSInterface::packetDataToSend(QByteArray &data)
mTcpSocket->write(data); mTcpSocket->write(data);
} }
#ifdef HAS_BLUETOOTH
if (mBleUart->isConnected()) { if (mBleUart->isConnected()) {
mBleUart->writeData(data); mBleUart->writeData(data);
} }
#endif
} }
void BMSInterface::packetReceived(QByteArray &data) void BMSInterface::packetReceived(QByteArray &data)
@@ -771,7 +797,7 @@ void BMSInterface::fwVersionReceived(int major, int minor, QString hw, QByteArra
{ {
QList<QPair<int, int> > fwPairs = getSupportedFirmwarePairs(); QList<QPair<int, int> > fwPairs = getSupportedFirmwarePairs();
QString strUuid = Utility::uuid2Str(uuid, true); QString strUuid = uuid.toHex().toUpper();
if (fwPairs.isEmpty()) { if (fwPairs.isEmpty()) {
emit messageDialog(tr("Not Supported Firmwares"), emit messageDialog(tr("Not Supported Firmwares"),
@@ -836,16 +862,7 @@ void BMSInterface::fwVersionReceived(int major, int minor, QString hw, QByteArra
} }
} }
QString fwStr; auto fwStr = tr("Firmware version: %1.%2, Hardware: %3, UUID: %4").arg(major).arg(minor).arg(hw).arg(strUuid);
fwStr.sprintf("ENNOID-BMS Firmware Version %d.%d", major, minor);
if (!hw.isEmpty()) {
fwStr += ", Hardware: " + hw;
}
if (!strUuid.isEmpty()) {
fwStr += ", UUID: " + strUuid;
}
emit statusMessage(fwStr, true); emit statusMessage(fwStr, true);
#if 0 #if 0
} }
@@ -864,13 +881,15 @@ void BMSInterface::fwVersionReceived(int major, int minor, QString hw, QByteArra
} }
} }
void BMSInterface::bmsconfUpdated() void BMSInterface::bmsConfUpdated()
{ {
emit statusMessage(tr("BMS configuration updated"), true); emit statusMessage(tr("BMS configuration updated"), true);
emit bmsConfigurationUpdated();
} }
void BMSInterface::bmsconfStored() { void BMSInterface::bmsConfStored() {
emit statusMessage(tr("BMS configuration stored to Flash"), true); emit statusMessage(tr("BMS configuration stored to Flash"), true);
emit bmsConfigurationStored();
} }
void BMSInterface::ackReceived(QString ackType) void BMSInterface::ackReceived(QString ackType)

View File

@@ -106,8 +106,9 @@ public:
Q_INVOKABLE bool reconnectLastPort(); Q_INVOKABLE bool reconnectLastPort();
Q_INVOKABLE bool autoconnect(); Q_INVOKABLE bool autoconnect();
Q_INVOKABLE QString getConnectedPortName(); Q_INVOKABLE QString getConnectedPortName();
bool connectSerial(QString port, int baudrate = 115200); Q_INVOKABLE bool connectSerial(QString port, int baudrate = 115200);
QList<VSerialInfo_t> listSerialPorts(); QList<VSerialInfo_t> listSerialPorts();
Q_INVOKABLE QStringList serialPortNames();
Q_INVOKABLE void connectTcp(QString server, int port); Q_INVOKABLE void connectTcp(QString server, int port);
Q_INVOKABLE void connectBle(QString address); Q_INVOKABLE void connectBle(QString address);
Q_INVOKABLE bool isAutoconnectOngoing() const; Q_INVOKABLE bool isAutoconnectOngoing() const;
@@ -126,6 +127,8 @@ signals:
void autoConnectProgressUpdated(double progress, bool isOngoing); void autoConnectProgressUpdated(double progress, bool isOngoing);
void autoConnectFinished(); void autoConnectFinished();
void pairingListUpdated(); void pairingListUpdated();
void bmsConfigurationUpdated();
void bmsConfigurationStored();
public slots: public slots:
@@ -140,15 +143,17 @@ private slots:
void tcpInputDataAvailable(); void tcpInputDataAvailable();
void tcpInputError(QAbstractSocket::SocketError socketError); void tcpInputError(QAbstractSocket::SocketError socketError);
#ifdef HAS_BLUETOOTH
void bleDataRx(QByteArray data); void bleDataRx(QByteArray data);
#endif
void timerSlot(); void timerSlot();
void packetDataToSend(QByteArray &data); void packetDataToSend(QByteArray &data);
void packetReceived(QByteArray &data); void packetReceived(QByteArray &data);
void cmdDataToSend(QByteArray &data); void cmdDataToSend(QByteArray &data);
void fwVersionReceived(int major, int minor, QString hw, QByteArray uuid); void fwVersionReceived(int major, int minor, QString hw, QByteArray uuid);
void bmsconfUpdated(); void bmsConfUpdated();
void bmsconfStored(); void bmsConfStored();
void ackReceived(QString ackType); void ackReceived(QString ackType);
private: private:

View File

@@ -39,6 +39,8 @@ Commands::Commands(QObject *parent) : QObject(parent)
mFimwarePtr = 0; mFimwarePtr = 0;
mFirmwareTimer = 0; mFirmwareTimer = 0;
mFirmwareRetries = 0; mFirmwareRetries = 0;
mFirmwareIsBootloader = false;
mFirmwareUploadSuccess = false;
mFirmwareUploadStatus = "FW Upload Status"; mFirmwareUploadStatus = "FW Upload Status";
mCheckNextbmsConfig = false; mCheckNextbmsConfig = false;
@@ -159,7 +161,7 @@ void Commands::processPacket(QByteArray data)
values.opState = opStateToStr((OperationalStateTypedef)vb.vbPopFrontUint8()); values.opState = opStateToStr((OperationalStateTypedef)vb.vbPopFrontUint8());
values.balanceActive = vb.vbPopFrontUint8(); values.balanceActive = vb.vbPopFrontUint8();
values.faultState = faultStateToStr((bms_fault_code)vb.vbPopFrontUint8()); values.faultState = faultStateToString((bms_fault_code)vb.vbPopFrontUint8());
emit valuesReceived(values); emit valuesReceived(values);
} break; } break;
@@ -234,7 +236,7 @@ void Commands::processPacket(QByteArray data)
break; break;
case COMM_SET_MCCONF: case COMM_SET_MCCONF:
emit ackReceived("BMS Write OK"); emit ackReceived(tr("BMS configuration is set"));
break; break;
case COMM_STORE_BMS_CONF: case COMM_STORE_BMS_CONF:
@@ -252,6 +254,29 @@ void Commands::processPacket(QByteArray data)
emit pingCanRx(devs, false); emit pingCanRx(devs, false);
} break; } break;
case COMM_GET_BMS_NET_SETTINGS:
case COMM_GET_BMS_NET_DEFAULT_SETTINGS:
{
QStringList settings;
settings << vb.mid(0, 250);
settings << vb.mid(250, 250);
settings << vb.mid(500, 50);
settings << vb.mid(550, 50);
settings << vb.mid(600, 50);
emit netSettingsReceived(settings);
break;
}
case COMM_SET_BMS_NET_SETTINGS:
{
emit ackReceived(tr("Network settings applied successfully"));
break;
}
case COMM_GET_FAULT_STATE:
{
const auto state = static_cast<bms_fault_code>(vb.vbPopFrontUint16());
emit faultStateReceived(faultStateToType(state), faultStateToString(state));
break;
}
default: default:
break; break;
} }
@@ -321,6 +346,40 @@ void Commands::getExpansionTemp()
vb.vbAppendInt8(COMM_GET_BMS_EXP_TEMP); vb.vbAppendInt8(COMM_GET_BMS_EXP_TEMP);
emitData(vb); emitData(vb);
} }
void Commands::getNetSettings()
{
VByteArray vb;
vb.vbAppendInt8(COMM_GET_BMS_NET_SETTINGS);
emitData(vb);
}
void Commands::getNetDefaultSettings()
{
VByteArray vb;
vb.vbAppendInt8(COMM_GET_BMS_NET_DEFAULT_SETTINGS);
emitData(vb);
}
void Commands::setNetSettings(QStringList settings)
{
VByteArray vb;
vb.vbAppendInt8(COMM_SET_BMS_NET_SETTINGS);
vb.append(settings.at(0).leftJustified(250, '\0', true));
vb.append(settings.at(1).leftJustified(250, '\0', true));
vb.append(settings.at(2).leftJustified(50, '\0', true));
vb.append(settings.at(3).leftJustified(50, '\0', true));
vb.append(settings.at(4).leftJustified(50, '\0', true));
emitData(vb);
}
void Commands::getFaultState()
{
VByteArray vb;
vb.vbAppendInt8(COMM_GET_FAULT_STATE);
emitData(vb);
}
void Commands::sendTerminalCmd(QString cmd) void Commands::sendTerminalCmd(QString cmd)
{ {
VByteArray vb; VByteArray vb;
@@ -457,12 +516,12 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
const int timeout = 350; const int timeout = 350;
if (mFirmwareState == 0) { if (mFirmwareState == 0) {
mFirmwareUploadStatus = "Buffer Erase"; mFirmwareUploadStatus = tr("Buffer erase");
if (isTimeout) { if (isTimeout) {
// Erase timed out, abort. // Erase timed out, abort.
mFirmwareIsUploading = false; mFirmwareIsUploading = false;
mFimwarePtr = 0; mFimwarePtr = 0;
mFirmwareUploadStatus = "Buffer Erase Timeout"; mFirmwareUploadStatus = tr("Buffer erase timeout");
} else { } else {
mFirmwareState++; mFirmwareState++;
mFirmwareRetries = retries; mFirmwareRetries = retries;
@@ -470,7 +529,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
firmwareUploadUpdate(true); firmwareUploadUpdate(true);
} }
} else if (mFirmwareState == 1) { } else if (mFirmwareState == 1) {
mFirmwareUploadStatus = "CRC/Size Write"; mFirmwareUploadStatus = tr("CRC/Size write");
if (isTimeout) { if (isTimeout) {
if (mFirmwareRetries > 0) { if (mFirmwareRetries > 0) {
mFirmwareRetries--; mFirmwareRetries--;
@@ -479,7 +538,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
mFirmwareIsUploading = false; mFirmwareIsUploading = false;
mFimwarePtr = 0; mFimwarePtr = 0;
mFirmwareState = 0; mFirmwareState = 0;
mFirmwareUploadStatus = "CRC/Size Write Timeout"; mFirmwareUploadStatus = tr("CRC/Size write timeout");
return; return;
} }
@@ -498,7 +557,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
firmwareUploadUpdate(true); firmwareUploadUpdate(true);
} }
} else if (mFirmwareState == 2) { } else if (mFirmwareState == 2) {
mFirmwareUploadStatus = "FW Data Write"; mFirmwareUploadStatus = tr("Firmware data write");
if (isTimeout) { if (isTimeout) {
if (mFirmwareRetries > 0) { if (mFirmwareRetries > 0) {
mFirmwareRetries--; mFirmwareRetries--;
@@ -507,7 +566,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
mFirmwareIsUploading = false; mFirmwareIsUploading = false;
mFimwarePtr = 0; mFimwarePtr = 0;
mFirmwareState = 0; mFirmwareState = 0;
mFirmwareUploadStatus = "FW Data Write Timeout"; mFirmwareUploadStatus = tr("Firmware data write timeout");
return; return;
} }
@@ -534,7 +593,8 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
mFirmwareIsUploading = false; mFirmwareIsUploading = false;
mFimwarePtr = 0; mFimwarePtr = 0;
mFirmwareState = 0; mFirmwareState = 0;
mFirmwareUploadStatus = "FW Upload Done"; mFirmwareUploadSuccess = true;
mFirmwareUploadStatus = tr("Firmware update completed!\n\nReconnect to the board if you want to continue working with it.");
// Upload done. Enter bootloader! // Upload done. Enter bootloader!
if (!mFirmwareIsBootloader) { if (!mFirmwareIsBootloader) {
@@ -568,34 +628,67 @@ QString Commands::opStateToStr(OperationalStateTypedef fault)
} }
} }
QString Commands::faultStateToStr(bms_fault_code fault) QString Commands::faultStateToString(bms_fault_code fault)
{ {
switch (fault) { switch (fault)
case FAULT_CODE_NONE: return "System OK"; {
case FAULT_CODE_PACK_OVER_VOLTAGE: return "Pack overvoltage"; case FAULT_CODE_NONE: return tr("System ok");
case FAULT_CODE_PACK_UNDER_VOLTAGE: return "Pack undervoltage"; case FAULT_CODE_PACK_OVER_VOLTAGE: return tr("Pack overvoltage");
case FAULT_CODE_LOAD_OVER_VOLTAGE: return "Load overvoltage"; case FAULT_CODE_PACK_UNDER_VOLTAGE: return tr("Pack undervoltage");
case FAULT_CODE_LOAD_UNDER_VOLTAGE: return "Load undervoltage"; case FAULT_CODE_LOAD_OVER_VOLTAGE: return tr("Load overvoltage");
case FAULT_CODE_CHARGER_OVER_VOLTAGE: return "Charger overvoltage"; case FAULT_CODE_LOAD_UNDER_VOLTAGE: return tr("Load undervoltage");
case FAULT_CODE_CHARGER_UNDER_VOLTAGE: return "Charger undervoltgae"; case FAULT_CODE_CHARGER_OVER_VOLTAGE: return tr("Charger overvoltage");
case FAULT_CODE_CELL_HARD_OVER_VOLTAGE: return "Cell hard overvoltage"; case FAULT_CODE_CHARGER_UNDER_VOLTAGE: return tr("Charger undervoltgae");
case FAULT_CODE_CELL_HARD_UNDER_VOLTAGE: return "Cell hard undervoltage"; case FAULT_CODE_CELL_HARD_OVER_VOLTAGE: return tr("Cell hard overvoltage");
case FAULT_CODE_CELL_SOFT_OVER_VOLTAGE: return "Cell soft overvoltage"; case FAULT_CODE_CELL_HARD_UNDER_VOLTAGE: return tr("Cell hard undervoltage");
case FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE: return "Cell soft undervoltage"; case FAULT_CODE_CELL_SOFT_OVER_VOLTAGE: return tr("Cell soft overvoltage");
case FAULT_CODE_MAX_UVP_OVP_ERRORS: return "MAX OVP/UVP errors"; case FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE: return tr("Cell soft undervoltage");
case FAULT_CODE_MAX_UVT_OVT_ERRORS: return "MAX OVT/UVT errors"; case FAULT_CODE_MAX_UVP_OVP_ERRORS: return tr("Too high or too low voltage");
case FAULT_CODE_OVER_CURRENT: return "Over current"; case FAULT_CODE_MAX_UVT_OVT_ERRORS: return tr("Too high or too low temperature");
case FAULT_CODE_OVER_TEMP_BMS: return "Over temp BMS"; case FAULT_CODE_OVER_CURRENT: return tr("Over current");
case FAULT_CODE_UNDER_TEMP_BMS: return "Under temp BMS"; case FAULT_CODE_OVER_TEMP_BMS: return tr("Over temperature BMS");
case FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS: return "Discharge over temp cell"; case FAULT_CODE_UNDER_TEMP_BMS: return tr("Under temperature BMS");
case FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS: return "Discharge under temp cell"; case FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS: return tr("Discharge over temperature cell");
case FAULT_CODE_CHARGE_OVER_TEMP_CELLS: return "Charge over temp cell"; case FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS: return tr("Discharge under temperature cell");
case FAULT_CODE_CHARGE_UNDER_TEMP_CELLS: return "Charge under temp cell"; case FAULT_CODE_CHARGE_OVER_TEMP_CELLS: return tr("Charge over temperature cell");
case FAULT_CODE_PRECHARGE_TIMEOUT: return "Precharge timeout"; case FAULT_CODE_CHARGE_UNDER_TEMP_CELLS: return tr("Charge under temperature cell");
case FAULT_CODE_DISCHARGE_RETRY: return "Discharge retry"; case FAULT_CODE_PRECHARGE_TIMEOUT: return tr("Precharge timeout");
case FAULT_CODE_CHARGE_RETRY: return "Charge retry"; case FAULT_CODE_DISCHARGE_RETRY: return tr("Discharge retry");
case FAULT_CODE_CHARGER_DISCONNECT: return "Charge retry"; case FAULT_CODE_CHARGE_RETRY: return tr("Charge retry");
default: return "Unknown fault"; case FAULT_CODE_CHARGER_DISCONNECT: return tr("Charge retry");
default: return tr("Unknown state");
}
}
DataTypes::StateType Commands::faultStateToType(bms_fault_code fault)
{
switch (fault)
{
case FAULT_CODE_NONE: return DataTypes::StateType::Good;
case FAULT_CODE_PACK_OVER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_PACK_UNDER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_LOAD_OVER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_LOAD_UNDER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_CHARGER_OVER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_CHARGER_UNDER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_CELL_HARD_OVER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_CELL_HARD_UNDER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_CELL_SOFT_OVER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE: return DataTypes::StateType::Error;
case FAULT_CODE_MAX_UVP_OVP_ERRORS: return DataTypes::StateType::Error;
case FAULT_CODE_MAX_UVT_OVT_ERRORS: return DataTypes::StateType::Error;
case FAULT_CODE_OVER_CURRENT: return DataTypes::StateType::Error;
case FAULT_CODE_OVER_TEMP_BMS: return DataTypes::StateType::Error;
case FAULT_CODE_UNDER_TEMP_BMS: return DataTypes::StateType::Error;
case FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS: return DataTypes::StateType::Error;
case FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS: return DataTypes::StateType::Error;
case FAULT_CODE_CHARGE_OVER_TEMP_CELLS: return DataTypes::StateType::Error;
case FAULT_CODE_CHARGE_UNDER_TEMP_CELLS: return DataTypes::StateType::Error;
case FAULT_CODE_PRECHARGE_TIMEOUT: return DataTypes::StateType::Warning;
case FAULT_CODE_DISCHARGE_RETRY: return DataTypes::StateType::Info;
case FAULT_CODE_CHARGE_RETRY: return DataTypes::StateType::Info;
case FAULT_CODE_CHARGER_DISCONNECT: return DataTypes::StateType::Info;
default: return DataTypes::StateType::Info;
} }
} }
@@ -616,7 +709,8 @@ void Commands::startFirmwareUpload(QByteArray &newFirmware, bool isBootloader)
mFirmwareRetries = 5; mFirmwareRetries = 5;
mNewFirmware.clear(); mNewFirmware.clear();
mNewFirmware.append(newFirmware); mNewFirmware.append(newFirmware);
mFirmwareUploadStatus = "Buffer Erase"; mFirmwareUploadSuccess = false;
mFirmwareUploadStatus = tr("Buffer erase");
if (mFirmwareIsBootloader) { if (mFirmwareIsBootloader) {
firmwareUploadUpdate(true); firmwareUploadUpdate(true);
@@ -628,7 +722,12 @@ void Commands::startFirmwareUpload(QByteArray &newFirmware, bool isBootloader)
} }
} }
double Commands::getFirmwareUploadProgress() bool Commands::getFirmwareUploadSuccess() const
{
return mFirmwareUploadSuccess;
}
double Commands::getFirmwareUploadProgress() const
{ {
if (mFirmwareIsUploading) { if (mFirmwareIsUploading) {
return (double)mFimwarePtr / (double)mNewFirmware.size(); return (double)mFimwarePtr / (double)mNewFirmware.size();
@@ -637,7 +736,7 @@ double Commands::getFirmwareUploadProgress()
} }
} }
QString Commands::getFirmwareUploadStatus() QString Commands::getFirmwareUploadStatus() const
{ {
return mFirmwareUploadStatus; return mFirmwareUploadStatus;
} }
@@ -648,7 +747,7 @@ void Commands::cancelFirmwareUpload()
mFirmwareIsUploading = false; mFirmwareIsUploading = false;
mFimwarePtr = 0; mFimwarePtr = 0;
mFirmwareState = 0; mFirmwareState = 0;
mFirmwareUploadStatus = "Cancelled"; mFirmwareUploadStatus = tr("Cancelled");
} }
} }

View File

@@ -47,11 +47,12 @@ public:
Q_INVOKABLE int getCanSendId(); Q_INVOKABLE int getCanSendId();
void setbmsConfig(ConfigParams *bmsConfig); void setbmsConfig(ConfigParams *bmsConfig);
Q_INVOKABLE void startFirmwareUpload(QByteArray &newFirmware, bool isBootloader = false); Q_INVOKABLE void startFirmwareUpload(QByteArray &newFirmware, bool isBootloader = false);
Q_INVOKABLE double getFirmwareUploadProgress(); Q_INVOKABLE double getFirmwareUploadProgress() const;
Q_INVOKABLE QString getFirmwareUploadStatus(); Q_INVOKABLE QString getFirmwareUploadStatus() const;
Q_INVOKABLE bool getFirmwareUploadSuccess() const;
Q_INVOKABLE void cancelFirmwareUpload(); Q_INVOKABLE void cancelFirmwareUpload();
void checkbmsConfig(); void checkbmsConfig();
void storeBMSConfig(); Q_INVOKABLE void storeBMSConfig();
Q_INVOKABLE void emitEmptyValues(); Q_INVOKABLE void emitEmptyValues();
Q_INVOKABLE void emitEmptySetupValues(); Q_INVOKABLE void emitEmptySetupValues();
@@ -70,6 +71,8 @@ signals:
void bmsConfigCheckResult(QStringList paramsNotSet); void bmsConfigCheckResult(QStringList paramsNotSet);
void valuesSetupReceived(BMS_VALUES values); void valuesSetupReceived(BMS_VALUES values);
void pingCanRx(QVector<int> devs, bool isTimeout); void pingCanRx(QVector<int> devs, bool isTimeout);
void netSettingsReceived(QStringList settings);
void faultStateReceived(DataTypes::StateType faultType, QString faultString);
public slots: public slots:
void processPacket(QByteArray data); void processPacket(QByteArray data);
@@ -79,6 +82,10 @@ public slots:
void getCells(); void getCells();
void getAux(); void getAux();
void getExpansionTemp(); void getExpansionTemp();
void getNetSettings();
void getNetDefaultSettings();
void setNetSettings(QStringList settings);
void getFaultState();
void sendTerminalCmd(QString cmd); void sendTerminalCmd(QString cmd);
void setDetect(disp_pos_mode mode); void setDetect(disp_pos_mode mode);
void samplePrint(debug_sampling_mode mode, int sample_len, int dec); void samplePrint(debug_sampling_mode mode, int sample_len, int dec);
@@ -97,7 +104,8 @@ private:
void emitData(QByteArray data); void emitData(QByteArray data);
void firmwareUploadUpdate(bool isTimeout); void firmwareUploadUpdate(bool isTimeout);
QString opStateToStr(OperationalStateTypedef fault); QString opStateToStr(OperationalStateTypedef fault);
QString faultStateToStr(bms_fault_code fault); QString faultStateToString(bms_fault_code fault);
DataTypes::StateType faultStateToType(bms_fault_code fault);
QTimer *mTimer; QTimer *mTimer;
bool mSendCan; bool mSendCan;
@@ -112,6 +120,7 @@ private:
int mFirmwareTimer; int mFirmwareTimer;
int mFirmwareRetries; int mFirmwareRetries;
bool mFirmwareIsBootloader; bool mFirmwareIsBootloader;
bool mFirmwareUploadSuccess;
QString mFirmwareUploadStatus; QString mFirmwareUploadStatus;
ConfigParams *mbmsConfig; ConfigParams *mbmsConfig;

View File

@@ -575,102 +575,102 @@ void ConfigParams::setParamValue(const QString &name, QVariant val)
} }
QWidget *ConfigParams::getEditor(const QString &name, QWidget *parent) //QWidget *ConfigParams::getEditor(const QString &name, QWidget *parent)
{ //{
QWidget *retVal = 0; // QWidget *retVal = 0;
if (mParams.contains(name)) { // if (mParams.contains(name)) {
ConfigParam &p = mParams[name]; // ConfigParam &p = mParams[name];
switch (p.type) { // switch (p.type) {
case CFG_T_DOUBLE: { // case CFG_T_DOUBLE: {
ParamEditDouble *edit = new ParamEditDouble(parent); // ParamEditDouble *edit = new ParamEditDouble(parent);
edit->setName(name); // edit->setName(name);
edit->setSuffix(p.suffix); // edit->setSuffix(p.suffix);
edit->setDecimals(p.editorDecimalsDouble); // edit->setDecimals(p.editorDecimalsDouble);
edit->setShowAsPercentage(p.editAsPercentage); // edit->setShowAsPercentage(p.editAsPercentage);
edit->showDisplay(p.showDisplay); // edit->showDisplay(p.showDisplay);
edit->setProperty("type", int(p.type)); // edit->setProperty("type", int(p.type));
edit->setProperty("suffix", p.suffix); // edit->setProperty("suffix", p.suffix);
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble); // edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
edit->setProperty("editAsPercentage", p.editAsPercentage); // edit->setProperty("editAsPercentage", p.editAsPercentage);
edit->setProperty("value", p.valDouble); // edit->setProperty("value", p.valDouble);
edit->setConfig(this); // edit->setConfig(this);
retVal = edit; // retVal = edit;
} break; // } break;
case CFG_T_INT: { // case CFG_T_INT: {
ParamEditInt *edit = new ParamEditInt(parent); // ParamEditInt *edit = new ParamEditInt(parent);
edit->setName(name); // edit->setName(name);
edit->setSuffix(p.suffix); // edit->setSuffix(p.suffix);
edit->setShowAsPercentage(p.editAsPercentage); // edit->setShowAsPercentage(p.editAsPercentage);
edit->showDisplay(p.showDisplay); // edit->showDisplay(p.showDisplay);
edit->setProperty("type", int(p.type)); // edit->setProperty("type", int(p.type));
edit->setProperty("suffix", p.suffix); // edit->setProperty("suffix", p.suffix);
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble); // edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
edit->setProperty("editAsPercentage", p.editAsPercentage); // edit->setProperty("editAsPercentage", p.editAsPercentage);
edit->setProperty("value", p.valInt); // edit->setProperty("value", p.valInt);
edit->setConfig(this); // edit->setConfig(this);
retVal = edit; // retVal = edit;
} break; // } break;
case CFG_T_QSTRING: { // case CFG_T_QSTRING: {
ParamEditString *edit = new ParamEditString(parent); // ParamEditString *edit = new ParamEditString(parent);
edit->setName(name); // edit->setName(name);
edit->setProperty("type", int(p.type)); // edit->setProperty("type", int(p.type));
edit->setProperty("suffix", p.suffix); // edit->setProperty("suffix", p.suffix);
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble); // edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
edit->setProperty("editAsPercentage", p.editAsPercentage); // edit->setProperty("editAsPercentage", p.editAsPercentage);
edit->setProperty("value", p.valString); // edit->setProperty("value", p.valString);
edit->setConfig(this); // edit->setConfig(this);
retVal = edit; // retVal = edit;
} break; // } break;
case CFG_T_ENUM: { // case CFG_T_ENUM: {
ParamEditEnum *edit = new ParamEditEnum(parent); // ParamEditEnum *edit = new ParamEditEnum(parent);
edit->setName(name); // edit->setName(name);
edit->setProperty("type", int(p.type)); // edit->setProperty("type", int(p.type));
edit->setProperty("suffix", p.suffix); // edit->setProperty("suffix", p.suffix);
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble); // edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
edit->setProperty("editAsPercentage", p.editAsPercentage); // edit->setProperty("editAsPercentage", p.editAsPercentage);
edit->setProperty("value", p.valInt); // edit->setProperty("value", p.valInt);
edit->setConfig(this); // edit->setConfig(this);
retVal = edit; // retVal = edit;
} break; // } break;
case CFG_T_BOOL: { // case CFG_T_BOOL: {
ParamEditBool *edit = new ParamEditBool(parent); // ParamEditBool *edit = new ParamEditBool(parent);
edit->setName(name); // edit->setName(name);
edit->setProperty("type", int(p.type)); // edit->setProperty("type", int(p.type));
edit->setProperty("suffix", p.suffix); // edit->setProperty("suffix", p.suffix);
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble); // edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
edit->setProperty("editAsPercentage", p.editAsPercentage); // edit->setProperty("editAsPercentage", p.editAsPercentage);
edit->setProperty("value", p.valInt); // edit->setProperty("value", p.valInt);
edit->setConfig(this); // edit->setConfig(this);
retVal = edit; // retVal = edit;
} break; // } break;
default: // default:
qWarning() << "no editor for" << name << "could be created"; // qWarning() << "no editor for" << name << "could be created";
break; // break;
} // }
} else { // } else {
qWarning() << name << "not found"; // qWarning() << name << "not found";
} // }
return retVal; // return retVal;
} //}
/* /*
QWidget *ConfigParams::getEditor(const QString &name, QWidget *parent) QWidget *ConfigParams::getEditor(const QString &name, QWidget *parent)

View File

@@ -28,6 +28,7 @@
#include <QObject> #include <QObject>
#include <QHash> #include <QHash>
#include <QVariant>
#include <QXmlStreamWriter> #include <QXmlStreamWriter>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include "configparam.h" #include "configparam.h"
@@ -50,7 +51,7 @@ public:
Q_INVOKABLE bool hasParam(const QString &name); Q_INVOKABLE bool hasParam(const QString &name);
ConfigParam *getParam(const QString &name); ConfigParam *getParam(const QString &name);
ConfigParam getParamCopy(const QString &name) const; ConfigParam getParamCopy(const QString &name) const;
void setParamValue(const QString &name, QVariant val); Q_INVOKABLE void setParamValue(const QString &name, QVariant val);
Q_INVOKABLE bool isParamDouble(const QString &name); Q_INVOKABLE bool isParamDouble(const QString &name);
Q_INVOKABLE bool isParamInt(const QString &name); Q_INVOKABLE bool isParamInt(const QString &name);
@@ -83,7 +84,7 @@ public:
QStringList getParamOrder() const; QStringList getParamOrder() const;
void setParamOrder(const QStringList &order); void setParamOrder(const QStringList &order);
QWidget *getEditor(const QString &name, QWidget *parent = 0); // QWidget *getEditor(const QString &name, QWidget *parent = 0);
void getParamSerial(VByteArray &vb, const QString &name); void getParamSerial(VByteArray &vb, const QString &name);
void setParamSerial(VByteArray &vb, const QString &name, QObject *src = 0); void setParamSerial(VByteArray &vb, const QString &name, QObject *src = 0);
@@ -97,14 +98,14 @@ public:
void getXML(QXmlStreamWriter &stream, QString configName); void getXML(QXmlStreamWriter &stream, QString configName);
bool setXML(QXmlStreamReader &stream, QString configName); bool setXML(QXmlStreamReader &stream, QString configName);
bool saveXml(QString fileName, QString configName); Q_INVOKABLE bool saveXml(QString fileName, QString configName);
bool loadXml(QString fileName, QString configName); Q_INVOKABLE bool loadXml(QString fileName, QString configName);
QString xmlStatus(); Q_INVOKABLE QString xmlStatus();
void getParamsXML(QXmlStreamWriter &stream); void getParamsXML(QXmlStreamWriter &stream);
bool setParamsXML(QXmlStreamReader &stream); bool setParamsXML(QXmlStreamReader &stream);
bool saveParamsXml(QString fileName); Q_INVOKABLE bool saveParamsXml(QString fileName);
bool loadParamsXml(QString fileName); Q_INVOKABLE bool loadParamsXml(QString fileName);
bool saveCDefines(const QString &fileName, bool wrapIfdef = false); bool saveCDefines(const QString &fileName, bool wrapIfdef = false);

63
currenttablemodel.cpp Normal file
View File

@@ -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<float> rowData;
for (const auto& column: row.toList())
{
rowData.push_back(column.toFloat());
}
data_.push_back(rowData);
}
endResetModel();
}
void CurrentTableModel::setCurrentData(const QList<QList<float>>& 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<int, QByteArray> CurrentTableModel::roleNames() const
{
return { {Qt::DisplayRole, "display"} };
}

27
currenttablemodel.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef CURRENTTABLEMODEL_H
#define CURRENTTABLEMODEL_H
#include <QAbstractTableModel>
class CurrentTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit CurrentTableModel(QObject* parent = nullptr);
~CurrentTableModel();
Q_INVOKABLE void setCurrentData(const QVariantList& data);
void setCurrentData(const QList<QList<float>>& 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<int, QByteArray> roleNames() const override;
private:
QList<QList<float>> data_;
};
#endif // CURRENTTABLEMODEL_H

View File

@@ -84,6 +84,8 @@ typedef enum {
FAULT_CODE_PRECHARGE_TIMEOUT, FAULT_CODE_PRECHARGE_TIMEOUT,
FAULT_CODE_DISCHARGE_RETRY, FAULT_CODE_DISCHARGE_RETRY,
FAULT_CODE_CHARGE_RETRY, FAULT_CODE_CHARGE_RETRY,
FAULT_CODE_CAN_DELAYED_POWER_DOWN,
FAULT_CODE_NOT_USED_TIMEOUT,
FAULT_CODE_CHARGER_DISCONNECT FAULT_CODE_CHARGER_DISCONNECT
} bms_fault_code; } bms_fault_code;
@@ -415,7 +417,11 @@ typedef enum {
COMM_STORE_BMS_CONF = 150, COMM_STORE_BMS_CONF = 150,
COMM_GET_BMS_CELLS, COMM_GET_BMS_CELLS,
COMM_GET_BMS_AUX, COMM_GET_BMS_AUX,
COMM_GET_BMS_EXP_TEMP COMM_GET_BMS_EXP_TEMP,
COMM_GET_BMS_NET_SETTINGS,
COMM_GET_BMS_NET_DEFAULT_SETTINGS,
COMM_SET_BMS_NET_SETTINGS,
COMM_GET_FAULT_STATE,
} COMM_PACKET_ID; } COMM_PACKET_ID;
typedef struct { typedef struct {
@@ -466,4 +472,19 @@ typedef enum {
OP_STATE_FORCEON, // 11 OP_STATE_FORCEON, // 11
} OperationalStateTypedef; } OperationalStateTypedef;
namespace DataTypes
{
Q_NAMESPACE
enum class StateType
{
Neutral,
Info,
Good,
Warning,
Error
};
Q_ENUM_NS(StateType);
}
#endif // DATATYPES_H #endif // DATATYPES_H

29
firmwareupdatehelper.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include "firmwareupdatehelper.h"
#include "bmsinterface.h"
#include <QFile>
#include <QByteArray>
FirmwareUpdateHelper::FirmwareUpdateHelper(QObject *parent) : QObject(parent)
{
}
bool FirmwareUpdateHelper::uploadFirmware(QString filename, BMSInterface *interface)
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly))
{
interface->emitMessageDialog(tr("Upload error"),
tr("Could not open file. Make sure that the path is valid."),
false);
return false;
}
auto data = file.readAll();
interface->commands()->startFirmwareUpload(data, false);
return true;
}

17
firmwareupdatehelper.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef FIRMWAREUPDATEHELPER_H
#define FIRMWAREUPDATEHELPER_H
#include <QObject>
class BMSInterface;
class FirmwareUpdateHelper : public QObject
{
Q_OBJECT
public:
explicit FirmwareUpdateHelper(QObject *parent = nullptr);
Q_INVOKABLE bool uploadFirmware(QString filename, BMSInterface *interface);
};
#endif // FIRMWAREUPDATEHELPER_H

155
main.cpp
View File

@@ -18,129 +18,72 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "mainwindow.h" #include "bmsinterface.h"
#include "mainwindownew.h" #include "utility.h"
#include "connectandenterpage.h" #include "translator.h"
#include "firmwareupdatehelper.h"
#include "currenttablemodel.h"
#include <QApplication> #include <QApplication>
#include <QStyleFactory>
#include <QSettings>
#include <QDesktopWidget>
#include <QFontDatabase> #include <QFontDatabase>
#include <QQmlApplicationEngine>
#include <QtSvg>
#include "mobile/qmlui.h" QObject *bmsInterfaceSingletontypeProvider(QQmlEngine */*engine*/, QJSEngine */*scriptEngine*/)
{
auto *bmsInterface = new BMSInterface();
bmsInterface->bmsConfig()->loadParamsXml("://res/config.xml");
bmsInterface->infoConfig()->loadParamsXml("://res/info.xml");
return bmsInterface;
}
#define NEW_GUI 1 QObject *utilitySingletontypeProvider(QQmlEngine */*engine*/, QJSEngine */*scriptEngine*/)
{
auto *utility = new Utility();
return utility;
}
QObject *translatorSingletontypeProvider(QQmlEngine *engine, QJSEngine */*scriptEngine*/)
{
auto *translator = new Translator(engine);
return translator;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
constexpr char const *APP_NAME = "ENNOID-BMS Tool"; Q_INIT_RESOURCE(res);
// Settings Q_INIT_RESOURCE(translations);
QCoreApplication::setOrganizationName("DieBie"); Q_INIT_RESOURCE(qml_icons);
QCoreApplication::setOrganizationDomain("diebie.nl"); Q_INIT_RESOURCE(qml_items);
QCoreApplication::setApplicationName(APP_NAME);
// DPI settings
// TODO: http://www.qcustomplot.com/index.php/support/forum/1344
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#ifdef USE_MOBILE
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#else QCoreApplication::setOrganizationName("Cubo");
QCoreApplication::setAttribute(Qt::AA_Use96Dpi); QCoreApplication::setOrganizationDomain("Cubo.rus");
QCoreApplication::setApplicationName("Cubo Verde BMS Tool");
QSettings set; QApplication app(argc, argv);
bool scaleAuto = true;
double scale = 1.0;
if (set.contains("app_scale_auto")) {
scaleAuto = set.value("app_scale_auto").toBool();
} else {
set.setValue("app_scale_auto", scaleAuto);
}
if (scaleAuto) {
QApplication tmp(argc, argv);
QRect rec = tmp.desktop()->screenGeometry();
int height = rec.height();
int width = rec.width();
double ptFont = tmp.font().pointSizeF();
if (ptFont < 0.0) {
ptFont = tmp.font().pixelSize();
}
if (width > 3000 && height > 1700) {
scale = 1.5;
} else {
if (ptFont > 11.0) {
scale = ptFont / 11.0;
}
}
set.setValue("app_scale_factor", scale);
} else if (set.contains("app_scale_factor")) {
scale = set.value("app_scale_factor").toDouble();
}
set.setValue("app_scale_factor", scale);
#ifdef Q_OS_ANDROID
scale = 1.0;
#endif
if (scale > 1.01) {
qputenv("QT_SCALE_FACTOR", QString::number(scale).toLocal8Bit());
}
#endif
QApplication a(argc, argv);
#if NEW_GUI
// Fonts
QFontDatabase::addApplicationFont("://res/fonts/Artifakt-Element.ttf"); QFontDatabase::addApplicationFont("://res/fonts/Artifakt-Element.ttf");
qApp->setFont(QFont("Artifakt Element", 12)); QFont font("Artifakt Element", 16, QFont::Normal);
font.setStyleStrategy(QFont::PreferAntialias);
app.setFont(font);
#else QQmlApplicationEngine engine;
// Fonts
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans.ttf");
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans-Bold.ttf");
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans-BoldOblique.ttf");
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans-Oblique.ttf");
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono.ttf");
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono-Bold.ttf");
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono-BoldOblique.ttf");
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono-Oblique.ttf");
qApp->setFont(QFont("DejaVu Sans", 11)); qmlRegisterSingletonType<BMSInterface>("Cubo", 1, 0, "BmsInterface", bmsInterfaceSingletontypeProvider);
qmlRegisterSingletonType<Utility>("Cubo", 1, 0, "Utility", utilitySingletontypeProvider);
qmlRegisterSingletonType<Translator>("Cubo", 1, 0, "Translator", translatorSingletontypeProvider);
qmlRegisterType<Commands>("Cubo", 1, 0, "Commands");
qmlRegisterType<ConfigParams>("Cubo", 1, 0, "ConfigParams");
qmlRegisterType<FirmwareUpdateHelper>("Cubo", 1, 0, "FirmwareUpdateHelper");
qmlRegisterType<CurrentTableModel>("Cubo", 1, 0, "CurrentTableModel");
// Style qmlRegisterUncreatableMetaObject(DataTypes::staticMetaObject, "Cubo", 1, 0, "DataTypes", "Error: only enums");
a.setStyleSheet(""); qRegisterMetaType<DataTypes::StateType>("DataTypes::StateType");
a.setStyle(QStyleFactory::create("Fusion"));
#endif
#ifdef USE_MOBILE engine.addImportPath(QStringLiteral("qrc:/"));
QmlUi q; engine.load(QUrl(QStringLiteral("qrc:/MainWindow.qml")));
q.startQmlUi();
#else
#if NEW_GUI return app.exec();
MainWindowNew w;
w.setWindowTitle(APP_NAME);
w.show();
//} else {
// a.closeAllWindows();
// return 0;
//}
#else
MainWindow w;
w.show();
#endif
#endif
return a.exec();
} }

View File

@@ -1,7 +1,5 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/"/>
<file>qtquickcontrols2.conf</file>
</qresource>
<qresource prefix="/mobile"> <qresource prefix="/mobile">
<file>main.qml</file> <file>main.qml</file>
<file>ConnectBle.qml</file> <file>ConnectBle.qml</file>

View File

@@ -0,0 +1,14 @@
import QtQuick 2.12
import Utils 1.0
Rectangle {
property bool enabled: false
property bool neutral: true
implicitWidth: 18
implicitHeight: 18
radius: implicitWidth / 2
color: enabled ? Palette.goodColor :
(neutral ? Palette.borderColor : Palette.invalidColor)
}

View File

@@ -0,0 +1,57 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
BusyIndicator {
id: control
running: true
implicitWidth: 86
implicitHeight: 86
contentItem: Item {
id: item
width: parent.width
height: parent.height
opacity: control.running ? 1 : 0
Behavior on opacity {
OpacityAnimator {
duration: 250
}
}
RotationAnimator {
target: item
running: control.visible && control.running
from: 0
to: 360
loops: Animation.Infinite
duration: 5000
}
Repeater {
id: repeater
model: 6
Rectangle {
x: item.width / 2 - width / 2
y: item.height / 2 - height / 2
implicitWidth: 12
implicitHeight: 12
radius: 6
color: Palette.alternativeBackgroundColor
transform: [
Translate {
y: -Math.min(item.width, item.height) * 0.5 + 6
},
Rotation {
angle: index / repeater.count * 360
origin.x: 6
origin.y: 6
}
]
}
}
}
}

30
qml/Controls/Button.qml Normal file
View File

@@ -0,0 +1,30 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Button {
id: control
contentItem: Text {
text: control.text
font.pixelSize: 16
font.weight: Font.Bold
opacity: enabled ? 1.0 : 0.3
color: Palette.alternativeTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
maximumLineCount: 2
wrapMode: Text.Wrap
}
background: Rectangle {
implicitWidth: 200
implicitHeight: 52
opacity: enabled ? 1 : 0.3
color: control.pressed ? Palette.pressedButtonColor :
control.hovered ? Palette.hoveredButtonColor : Palette.buttonColor
radius: 5
}
}

208
qml/Controls/ChartView.qml Normal file
View File

@@ -0,0 +1,208 @@
import QtQuick 2.12
import QtCharts 2.3
import QtQuick.Shapes 1.12
import Controls 1.0 as Controls
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
property int selectedSeriesIndex: 0
property string infoXMark: ""
property string infoYMark: ""
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
}
Shape {
id: currentPointLine
implicitWidth: 1
implicitHeight: chart.plotArea.height
x: chart.plotArea.x
y: chart.plotArea.y
ShapePath {
strokeColor: Palette.borderColor
strokeStyle: ShapePath.SolidLine
startX: 0
startY: 0
PathLine { x: 0; y: currentPointLine.height }
}
}
Rectangle {
id: currentPointInfo
width: currentPointInfoLabel.width
height: currentPointInfoLabel.height
color: Palette.backgroundColor
border.width: 1
border.color: Palette.borderColor
opacity: 0.9
radius: 6
visible: false
Controls.SubtitleLabel {
id: currentPointInfoLabel
horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent
padding: 10
}
}
MouseArea {
id: chartMouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: true
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)
} else if (mouseX - lastMouseX < scrollThreshold) {
chart.scrollRight(lastMouseX - mouseX)
}
lastMouseX = mouseX
chart.autoScaling = false
}
updatePointInfo()
}
onMouseYChanged: {
if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
if (mouseY - lastMouseY > scrollThreshold) {
chart.scrollUp(mouseY - lastMouseY)
} else if (mouseY - lastMouseY < scrollThreshold) {
chart.scrollDown(lastMouseY - mouseY)
}
lastMouseY = mouseY
chart.autoScaling = false
}
updatePointInfo()
}
onPressed: {
if (mouse.button === Qt.LeftButton) {
lastMouseX = mouseX
lastMouseY = mouseY
}
}
onWheel: {
var scaleFactor = 0.75
var area = chart.plotArea
chart.autoScaling = false
var yAxisPosition = mouseX <= chart.plotArea.x
if (yAxisPosition) {
if (wheel.angleDelta.y > 0) {
chart.zoomIn(Qt.rect(area.x, area.y + Math.round(area.height * (1 - scaleFactor) / 2), area.width, Math.round(area.height * scaleFactor)))
} else {
chart.zoomIn(Qt.rect(area.x, area.y - Math.round((area.height / scaleFactor) * (1 - scaleFactor) / 2), area.width, Math.round(area.height / scaleFactor)))
}
return
}
var xAxisPosition = mouseY >= (chart.plotArea.y + chart.plotArea.height)
if (xAxisPosition) {
if (wheel.angleDelta.y > 0) {
chart.zoomIn(Qt.rect(area.x + area.width * (1 - scaleFactor) / 2, area.y, Math.round(area.width * scaleFactor), area.height))
} else {
chart.zoomIn(Qt.rect(area.x - (area.width / scaleFactor) * (1 - scaleFactor) / 2, area.y, Math.round(area.width / scaleFactor), area.height))
}
return
}
if (wheel.angleDelta.y > 0) {
let zoomedInArea = Qt.rect(area.x + Math.round((mouseX - area.x) * (1 - scaleFactor)),
area.y + Math.round((mouseY - area.y) * (1 - scaleFactor)),
Math.round(area.width * scaleFactor),
Math.round(area.height * scaleFactor))
chart.zoomIn(zoomedInArea)
} else {
let zoomedOutArea = Qt.rect(area.x - Math.floor((mouseX - area.x) * (1 - scaleFactor)),
area.y - Math.floor((mouseY - area.y) * (1 - scaleFactor)),
Math.round(area.width * (1 + (1 - scaleFactor))),
Math.round(area.height * (1 + (1 - scaleFactor))))
chart.zoomIn(zoomedOutArea)
}
updatePointInfo()
}
function updatePointInfo() {
let currentPointVisibility = mouseX >= chart.plotArea.x && mouseX <= chart.plotArea.x + chart.plotArea.width &&
mouseY >= chart.plotArea.y && mouseY <= chart.plotArea.y + chart.plotArea.height
currentPointInfo.visible = currentPointVisibility
currentPointInfo.x = mouseX + 5
currentPointInfo.y = mouseY - currentPointInfo.height - 5
let currentX = mapToValue(Qt.point(mouseX, mouseY), chart.series(selectedSeriesIndex)).x
let selectedPoint = Qt.point(0, 0)
for(let i = 0; i < chart.series(selectedSeriesIndex).count; ++i) {
let point = chart.series(selectedSeriesIndex).at(i)
if (point.x > currentX || i === chart.series(selectedSeriesIndex).count - 1) {
selectedPoint = chart.series(selectedSeriesIndex).at(i)
currentPointInfoLabel.text = selectedPoint.x + " " + infoXMark + ", " + selectedPoint.y + " " + infoYMark
break
}
}
if (chart.series(selectedSeriesIndex).count === 0) {
currentPointInfo.visible = false
}
currentPointLine.visible = currentPointVisibility
currentPointLine.x = mouseX
}
}
onSeriesAdded: if (count === 1) {
series.pointAdded.connect(function (index){ chartMouseArea.updatePointInfo() })
}
}

37
qml/Controls/CheckBox.qml Normal file
View File

@@ -0,0 +1,37 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
CheckBox {
id: control
implicitHeight: 25
spacing: 15
indicator: Rectangle {
implicitWidth: control.implicitHeight
implicitHeight: control.implicitHeight
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: 5
border.color: Palette.borderColor
border.width: 1
color: control.checked ? Palette.alternativeBackgroundColor : Palette.backgroundColor
Image {
source: "qrc:/Icons/check-indicator.svg"
anchors.centerIn: parent
visible: control.checked
}
}
contentItem: Text {
text: control.text
font.pixelSize: 18
font.weight: Font.Bold
color: Palette.textColor
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
leftPadding: control.indicator.width + control.spacing
}
}

113
qml/Controls/ComboBox.qml Normal file
View File

@@ -0,0 +1,113 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Controls 1.0 as Controls
import Utils 1.0
ComboBox {
id: control
leftPadding: 16
rightPadding: 16
font.pixelSize: 16
delegate: ItemDelegate {
width: control.width
leftPadding: control.leftPadding
clip: true
contentItem: Text {
text: modelData
color: pressed ? Palette.selectedTextColor : Palette.textColor
font: control.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: control.currentIndex === index ?
Palette.selectedBackgroundColor :
(highlighted ? Palette.hoveredBackgroundColor : Palette.backgroundColor)
}
highlighted: control.highlightedIndex === index
}
indicator: Canvas {
id: canvas
x: control.width - width - control.rightPadding
y: control.topPadding + (control.availableHeight - height) / 2
width: 8
height: 5
contextType: "2d"
Connections {
target: control
onDownChanged: canvas.requestPaint()
}
onPaint: {
var context = getContext("2d")
context.reset()
if (control.down) {
context.moveTo(0, height);
context.lineTo(width, height);
context.lineTo(width / 2, 0);
} else {
context.moveTo(0, 0);
context.lineTo(width, 0);
context.lineTo(width / 2, height);
}
context.closePath();
context.fillStyle = control.down ? Palette.selectedTextColor : Palette.textColor;
context.fill();
}
}
contentItem: Text {
rightPadding: control.indicator.width + 8
text: control.displayText
font: control.font
color: control.down ? Palette.selectedTextColor : Palette.textColor
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
implicitWidth: 120
implicitHeight: 46
color: control.enabled
? (control.down ? Palette.selectedBackgroundColor : Palette.backgroundColor)
: Palette.hoveredBackgroundColor
border.color: Palette.borderColor
border.width: 1
radius: 5
}
popup: Popup {
y: control.height + 2
width: control.width
implicitHeight: contentItem.implicitHeight
padding: 1
contentItem: ListView {
clip: true
implicitHeight: contentHeight
model: control.popup.visible ? control.delegateModel : null
currentIndex: control.highlightedIndex
ScrollBar.vertical: Controls.ScrollBar {}
}
background: Rectangle {
color: Palette.backgroundColor
border.color: Palette.borderColor
border.width: 1
radius: 5
}
}
}

View File

@@ -0,0 +1,11 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Label {
color: Palette.contentTextColor
font.pixelSize: 18
font.weight: Font.Normal
elide: Text.ElideRight
}

View File

@@ -0,0 +1,8 @@
import QtQuick 2.12
import Utils 1.0
Rectangle {
color: Palette.screenBackgroundColor
radius: 6
}

View File

@@ -0,0 +1,75 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Utils 1.0
Rectangle {
color: Qt.darker(Palette.hoveredBackgroundColor, 1.05)
height: 50
radius: 6
property Dialog dialog: undefined
RowLayout {
anchors.fill: parent
Controls.SubtitleLabel {
text: root.title
leftPadding: 20
topPadding: 0
bottomPadding: 0
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
Layout.preferredHeight: parent.height
MouseArea {
anchors.fill: parent
property int lastX: 0
property int lastY: 0
onPressed: {
lastX = mouse.x
lastY = mouse.y
}
onPositionChanged:{
var deltaX = mouse.x - lastX
dialog.x += deltaX
lastX = mouse.x - deltaX
var deltaY = mouse.y - lastY
dialog.y += deltaY
lastY = mouse.y - deltaY
}
}
}
Image {
id: closeImage
source: "qrc:/Icons/close.svg"
sourceSize.width: 36
sourceSize.height: 36
Layout.rightMargin: 10
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onPressed: {
closeImage.sourceSize.width = 32
closeImage.sourceSize.height = 32
}
onReleased: {
closeImage.sourceSize.width = 36
closeImage.sourceSize.height = 36
}
onClicked: {
root.close()
}
}
}
}
}

View File

@@ -0,0 +1,19 @@
import QtQuick 2.12
import QtQuick.Shapes 1.12
import Utils 1.0
Shape {
id: shape
implicitHeight: 1
ShapePath {
strokeColor: Palette.contentTextColor
strokeWidth: 1
strokeStyle: ShapePath.DashLine
dashPattern: [1, 3]
startX: 0
startY: 0
PathLine { x: shape.width; y: 0 }
}
}

13
qml/Controls/Frame.qml Normal file
View File

@@ -0,0 +1,13 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Frame {
background: Rectangle {
color: Palette.backgroundColor
border.color: Palette.borderColor
border.width: 1
radius: 8
}
}

View File

@@ -0,0 +1,27 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Button {
id: control
icon.width: 24
icon.height: 24
contentItem: Image {
source: control.icon.source
sourceSize.width: control.icon.width
sourceSize.height: control.icon.height
fillMode: Image.PreserveAspectFit
}
background: Rectangle {
implicitWidth: 44
implicitHeight: 44
opacity: enabled ? 1 : 0.3
color: control.pressed ? Palette.pressedButtonColor :
control.hovered ? Palette.hoveredButtonColor : Palette.buttonColor
radius: 5
}
}

View File

@@ -0,0 +1,18 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Label {
color: Palette.textColor
font.pixelSize: 18
font.weight: Font.Bold
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
background: Rectangle {
color: Palette.hoveredBackgroundColor
radius: 8
}
}

View File

@@ -0,0 +1,19 @@
import QtQuick 2.12
import QtQuick.Shapes 1.12
import Utils 1.0
Shape {
id: shape
implicitWidth: 1
implicitHeight: 1
property bool horizontal: true
ShapePath {
strokeColor: Palette.borderColor
strokeStyle: ShapePath.SolidLine
startX: 0
startY: 0
PathLine { x: horizontal ? shape.width : 0; y: horizontal ? 0 : shape.height }
}
}

View File

@@ -0,0 +1,22 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Label {
id: control
color: Palette.selectedTextColor
font.pixelSize: 18
font.weight: Font.Normal
font.underline : true
elide: Text.ElideRight
signal clicked()
MouseArea{
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: control.clicked()
}
}

View File

@@ -0,0 +1,63 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import Utils 1.0
ItemDelegate {
id: control
implicitHeight: 52
padding: 0
leftPadding: control.minimized ? 0 : 40
font.pixelSize: 18
font.weight: Font.Bold
icon.color: "transparent"
icon.width: 24
icon.height: 24
property bool minimized: false
property bool mirroredIcon: false
contentItem: RowLayout {
spacing: control.minimized ? 0 : 25
Item {
visible: control.minimized
Layout.fillWidth: true
}
Image {
source: control.icon.source
sourceSize.width: control.icon.width
sourceSize.height: control.icon.height
mirror: control.mirroredIcon
Layout.alignment: Qt.AlignCenter
ColorOverlay {
anchors.fill: parent
source: parent
color: icon.color
visible: icon.color !== "transparent"
}
}
Label {
text: control.text
font: control.font
color: Palette.alternativeTextColor
visible: !control.minimized
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
}
Item {
Layout.fillWidth: true
}
}
background: Rectangle {
color: control.pressed || control.highlighted ?
Palette.pressedButtonColor : control.hovered ?
Palette.hoveredButtonColor : Palette.buttonColor
}
}

View File

@@ -0,0 +1,33 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Button {
id: control
contentItem: Text {
text: control.text
font.pixelSize: 16
font.weight: Font.Bold
opacity: enabled ? 1.0 : 0.7
color: control.hovered ? Palette.alternativeTextColor : Palette.textColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
maximumLineCount: 2
wrapMode: Text.Wrap
}
background: Rectangle {
implicitWidth: 200
implicitHeight: 52
opacity: enabled ? 1 : 0.7
color: control.pressed ? Palette.pressedButtonColor :
control.hovered ? Palette.hoveredButtonColor : Palette.outlineButtonColor
border.color: control.pressed ? Palette.pressedButtonColor :
control.hovered ? Palette.hoveredButtonColor : Palette.buttonColor
border.width: 1
radius: 5
}
}

View File

@@ -0,0 +1,38 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.0
import Utils 1.0
Button {
id: control
icon.width: 24
icon.height: 24
contentItem: Image {
source: control.icon.source
sourceSize.width: control.icon.width
sourceSize.height: control.icon.height
fillMode: Image.PreserveAspectFit
ColorOverlay {
anchors.fill: parent
source: parent
color: "#FFFFFF"
visible: control.hovered
}
}
background: Rectangle {
implicitWidth: 44
implicitHeight: 44
color: control.enabled ? (control.pressed ? Palette.pressedButtonColor :
control.hovered ? Palette.hoveredButtonColor : Palette.backgroundColor) :
Palette.hoveredBackgroundColor
border.color: control.pressed ? Palette.pressedButtonColor :
control.hovered ? Palette.hoveredButtonColor : Palette.borderColor
border.width: 1
radius: 5
}
}

View File

@@ -0,0 +1,38 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
ProgressBar {
id: control
padding: 2
background: Rectangle {
implicitWidth: 250
implicitHeight: 26
border.width: 1
border.color: Palette.borderColor
color: Palette.screenBackgroundColor
radius: 5
}
contentItem: Item {
implicitWidth: 250
implicitHeight: 24
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
radius: 5
color: Palette.alternativeBackgroundColor
}
Text {
text: Math.floor((control.value / control.to) * 100) + '%'
anchors.centerIn: parent
color: Palette.textColor
font.pixelSize: 18
font.weight: Font.Bold
}
}
}

View File

@@ -0,0 +1,42 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
RadioButton {
id: control
implicitHeight: 30
spacing: 15
leftPadding: 0
indicator: Rectangle {
implicitWidth: control.implicitHeight
implicitHeight: control.implicitHeight
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: implicitWidth / 2
border.color: Palette.borderColor
Rectangle {
property int spacing: 10
width: parent.implicitWidth - spacing
height: parent.implicitHeight - spacing
x: spacing / 2
y: spacing / 2
radius: width / 2
color: Palette.alternativeBackgroundColor
visible: control.checked
}
}
contentItem: Text {
text: control.text
font.pixelSize: 18
font.weight: Font.Bold
color: Palette.textColor
maximumLineCount: 2
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
leftPadding: control.indicator.width + control.spacing
}
}

View File

@@ -0,0 +1,40 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
ScrollBar {
id: control
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
padding: 2
visible: control.policy !== ScrollBar.AlwaysOff
minimumSize: orientation == Qt.Horizontal ? height / width : width / height
contentItem: Rectangle {
implicitWidth: control.interactive ? 6 : 2
implicitHeight: control.interactive ? 6 : 2
radius: width / 2
color: control.pressed ? Palette.alternativeBackgroundColor : Qt.lighter(Palette.alternativeBackgroundColor, 1.1)
opacity: 0.0
states: State {
name: "active"
when: control.policy === ScrollBar.AlwaysOn || (control.active && control.size < 1.0)
PropertyChanges { target: control.contentItem; opacity: 0.75 }
}
transitions: Transition {
from: "active"
SequentialAnimation {
PauseAnimation { duration: 450 }
NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
}
}
}
}

View File

@@ -0,0 +1,40 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
ScrollIndicator {
id: control
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
padding: 2
contentItem: Rectangle {
implicitWidth: 2
implicitHeight: 2
color: Palette.alternativeBackgroundColor
visible: control.size < 1.0
opacity: 0.0
states: State {
name: "active"
when: control.active
PropertyChanges { target: control.contentItem; opacity: 0.75 }
}
transitions: [
Transition {
from: "active"
SequentialAnimation {
PauseAnimation { duration: 450 }
NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
}
}
]
}
}

View File

@@ -0,0 +1,11 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Label {
color: Palette.textColor
font.pixelSize: 18
font.weight: Font.Bold
elide: Text.ElideRight
}

20
qml/Controls/TabBar.qml Normal file
View File

@@ -0,0 +1,20 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
TabBar {
id: control
background: Rectangle {
color: Palette.backgroundColor
Rectangle {
height: 1
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
color: Palette.borderColor
}
}
}

View File

@@ -0,0 +1,46 @@
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
maximumLineCount: 2
wrapMode: Text.Wrap
}
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
// }
// }
}
}
}

11
qml/Controls/TextArea.qml Normal file
View File

@@ -0,0 +1,11 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
TextArea {
color: Palette.textColor
selectByMouse: true
selectionColor: Palette.selectedTextBackgroundColor
font.pixelSize: 16
}

View File

@@ -0,0 +1,21 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
TextField {
implicitHeight: 58
font.pixelSize: 16
color: Palette.textColor
selectByMouse: true
selectionColor: Palette.selectedTextBackgroundColor
leftPadding: 16
rightPadding: 16
background: Rectangle {
color: enabled ? Palette.backgroundColor : Palette.hoveredBackgroundColor
border.color: Palette.borderColor
border.width: 1
radius: 8
}
}

View File

@@ -0,0 +1,11 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Label {
color: Palette.selectedTextColor
font.pixelSize: 28
font.weight: Font.Bold
elide: Text.ElideRight
}

29
qml/Controls/qmldir Normal file
View File

@@ -0,0 +1,29 @@
module Controls
ComboBox 1.0 ComboBox.qml
ScrollBar 1.0 ScrollBar.qml
Button 1.0 Button.qml
OutlineButton 1.0 OutlineButton.qml
TextField 1.0 TextField.qml
Frame 1.0 Frame.qml
TitleLabel 1.0 TitleLabel.qml
SubtitleLabel 1.0 SubtitleLabel.qml
ContentLabel 1.0 ContentLabel.qml
DotSeparator 1.0 DotSeparator.qml
AvailabilityIndicator 1.0 AvailabilityIndicator.qml
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
TextArea 1.0 TextArea.qml
DialogHeader 1.0 DialogHeader.qml
DialogBackground 1.0 DialogBackground.qml
BusyIndicator 1.0 BusyIndicator.qml
MenuItemDelegate 1.0 MenuItemDelegate.qml
ScrollIndicator 1.0 ScrollIndicator.qml
OutlineImageButton 1.0 OutlineImageButton.qml
ImageButton 1.0 ImageButton.qml
ProgressBar 1.0 ProgressBar.qml
RadioButton 1.0 RadioButton.qml

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22 11.6154V16.9231H2V3H7.71429V1H1.71429C1.25963 1 0.823594 1.1864 0.502103 1.5182C0.180612 1.84999 0 2.3 0 2.76923V17.2308C0 17.7 0.180612 18.15 0.502103 18.4818C0.823594 18.8136 1.25963 19 1.71429 19H8.57143V22.2308H5.14286V24H18.8571V22.2308H15.4286V19H22.2857C22.7404 19 23.1764 18.8136 23.4979 18.4818C23.8194 18.15 24 17.7 24 17.2308V11.6154H22ZM13.7143 22.2308H10.2857V19H13.7143V22.2308Z" fill="white"/>
<path d="M13.2632 15H13.2542C13.0614 14.9977 12.8744 14.926 12.7211 14.7953C12.5678 14.6647 12.4563 14.4822 12.4033 14.275L10.7991 8.00005H7V6.00007H11.4737C11.6682 5.99995 11.8574 6.07065 12.0127 6.20146C12.168 6.33228 12.2809 6.51609 12.3344 6.72506L13.2954 10.485L15.9876 0.705106C16.0457 0.502156 16.1595 0.324815 16.3129 0.198262C16.4663 0.0717101 16.6515 0.00237827 16.8421 0.000110855C17.0306 -0.00305764 17.215 0.0617711 17.368 0.184981C17.5209 0.308191 17.6343 0.48322 17.6912 0.684106L19.2758 6.00007H24V8.00005H18.6316C18.4437 8.0001 18.2606 7.93406 18.1082 7.8113C17.9558 7.68853 17.8418 7.51526 17.7825 7.31606L16.8761 4.27608L14.1185 14.294C14.0623 14.4985 13.9488 14.6774 13.7949 14.8044C13.6409 14.9315 13.4545 15 13.2632 15Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 10V4.22222C20 2.99492 18.9767 2 17.7143 2H6.28571C5.02335 2 4 2.99492 4 4.22222V19.7778C4 21.0051 5.02335 22 6.28571 22H9" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 14H13.3333M8 7H16H8ZM8 10.5H16H8Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.1046 13.0108C21.2559 13.0039 21.4068 13.03 21.547 13.0872C21.6871 13.1444 21.813 13.2314 21.9159 13.3421L22.6921 14.1259C22.8895 14.3271 23 14.5973 23 14.8787C23 15.16 22.8895 15.4302 22.6921 15.6315L21.2452 17.0725L18.9464 14.7723L20.3933 13.3313C20.5823 13.1388 20.835 13.0211 21.1046 13V13.0108ZM18.9464 14.7723L21.2452 17.0617L17.2724 21.0291L16.1067 22.1954C16.0513 22.2593 15.9806 22.3083 15.9012 22.3381L13.4672 22.9872C13.4043 23.0042 13.338 23.0043 13.275 22.9875C13.212 22.9708 13.1546 22.9378 13.1085 22.8919C13.0624 22.846 13.0293 22.7888 13.0125 22.7261C12.9957 22.6634 12.9958 22.5974 13.0128 22.5347L13.6619 20.1106C13.693 20.0301 13.7442 19.9587 13.8106 19.9032L14.2569 19.4588L18.9464 14.7723Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9998 1C12.5514 1 13.0951 1.04086 13.6246 1.11943L14.4229 3.53782C15.1222 3.73739 15.7869 4.02181 16.4028 4.38009L18.6971 3.27382C19.5095 3.89767 20.2323 4.63308 20.842 5.4565L19.6949 7.73032C20.0422 8.3526 20.3156 9.02201 20.5026 9.726L22.9068 10.5636C23.0393 11.5803 23.0303 12.6104 22.8801 13.6247L20.4617 14.4229C20.2635 15.1151 19.9806 15.7801 19.6195 16.4029L20.7257 18.6971C20.101 19.5098 19.3665 20.2317 18.5431 20.8421L16.2693 19.695C15.647 20.0423 14.9776 20.3157 14.2736 20.5027L13.4361 22.9069C12.4194 23.0394 11.3892 23.0304 10.375 22.8802L9.57675 20.4618C8.88462 20.2636 8.21961 19.9807 7.5968 19.6196L5.30258 20.7258C4.48995 20.1011 3.76806 19.3666 3.15763 18.5431L4.30475 16.2693C3.95434 15.6399 3.68306 14.9696 3.49705 14.2736L1.09283 13.4345C0.960511 12.4183 0.9695 11.3887 1.11955 10.375L3.53791 9.57672C3.73747 8.87745 4.0219 8.21274 4.38017 7.59675L3.27392 5.3025C3.8986 4.48986 4.63318 3.76797 5.45657 3.15754L7.73037 4.30466C8.35264 3.95738 9.02205 3.68396 9.72603 3.49696L10.5651 1.09271C11.035 1.03143 11.5143 1 11.9998 1Z" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M11.9999 16C14.209 16 15.9999 14.2091 15.9999 12C15.9999 9.79086 14.209 8 11.9999 8C9.79074 8 7.99988 9.79086 7.99988 12C7.99988 14.2091 9.79074 16 11.9999 16Z" stroke="white" stroke-width="2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,18 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="path-1-inside-1_973_566" fill="white">
<rect x="1" y="1" width="9" height="13" rx="1"/>
</mask>
<rect x="1" y="1" width="9" height="13" rx="1" stroke="white" stroke-width="2" mask="url(#path-1-inside-1_973_566)"/>
<mask id="path-2-inside-2_973_566" fill="white">
<rect x="13" y="1" width="9" height="7" rx="1"/>
</mask>
<rect x="13" y="1" width="9" height="7" rx="1" stroke="white" stroke-width="2" mask="url(#path-2-inside-2_973_566)"/>
<mask id="path-3-inside-3_973_566" fill="white">
<rect x="13" y="11" width="9" height="12" rx="1"/>
</mask>
<rect x="13" y="11" width="9" height="12" rx="1" stroke="white" stroke-width="2" mask="url(#path-3-inside-3_973_566)"/>
<mask id="path-4-inside-4_973_566" fill="white">
<rect x="1" y="17" width="9" height="6" rx="1"/>
</mask>
<rect x="1" y="17" width="9" height="6" rx="1" stroke="white" stroke-width="2" mask="url(#path-4-inside-4_973_566)"/>
</svg>

After

Width:  |  Height:  |  Size: 1003 B

View File

@@ -0,0 +1,3 @@
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.7203 7.19847C20.0643 7.48676 20.0953 7.98339 19.7895 8.30772L10.9006 17.7363C10.7425 17.904 10.5158 18 10.2778 18C10.0397 18 9.81308 17.904 9.65494 17.7363L5.2105 13.022C4.90474 12.6977 4.93572 12.201 5.27971 11.9128C5.62369 11.6245 6.15042 11.6537 6.45618 11.978L10.2778 16.0316L18.5438 7.26372C18.8496 6.93939 19.3763 6.91018 19.7203 7.19847Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 477 B

1
qml/Icons/close.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g data-name="Layer 2"><g data-name="close"><rect width="24" height="24" transform="rotate(180 12 12)" opacity="0"/><path d="M13.41 12l4.3-4.29a1 1 0 1 0-1.42-1.42L12 10.59l-4.29-4.3a1 1 0 0 0-1.42 1.42l4.3 4.29-4.3 4.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l4.29-4.3 4.29 4.3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 411 B

3
qml/Icons/connection.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="#000" stroke-width="2" d="M10,21 C7.50000053,23.5 5.00000002,23 3,21 C0.999999977,19 0.500000114,16.5 3.00000004,14 C5.49999997,11.5 5.99999998,11 5.99999998,11 L13.0000005,18 C13.0000005,18 12.4999995,18.5 10,21 Z M14.0003207,3 C16.5,0.499999776 19,0.999999776 21.001068,3 C23.002136,5.00000022 23.5,7.49999978 21.001068,10 C18.5021359,12.5000002 18.0007478,13 18.0007478,13 L11,6 C11,6 11.5006414,5.50000022 14.0003207,3 Z M11,9.9999 L8.5,12.4999999 L11,9.9999 Z M14,13 L11.5,15.5 L14,13 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 618 B

BIN
qml/Icons/cubo-icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

15
qml/Icons/cubo-logo.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg width="115" height="115" viewBox="0 0 115 115" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M91.0183 45.5542C91.0183 51.3591 86.0875 56.038 80.0087 56.038C73.9189 56.038 68.999 51.3591 68.999 45.5542C68.999 39.782 73.9189 35.0977 80.0087 35.0977C86.0875 35.1031 91.0183 39.782 91.0183 45.5542ZM86.0328 45.5542C86.0328 42.3456 83.3323 39.7493 80.0087 39.7493C76.6741 39.7493 73.9845 42.3456 73.9845 45.5542C73.9845 48.7955 76.6741 51.3919 80.0087 51.3919C83.3323 51.3919 86.0328 48.7955 86.0328 45.5542Z" fill="white"/>
<path d="M64.2045 44.6847C65.839 45.8817 66.8121 47.6965 66.8121 49.7298C66.8121 53.3101 63.8 56.1634 59.5361 56.1634H50.9263V42.0282C50.9263 37.8958 54.2171 35.0098 58.3225 35.0098C62.3295 35.0098 65.44 37.956 65.44 41.5581C65.4291 42.8043 64.9808 43.8757 64.2045 44.6847ZM61.4166 49.7298C61.4166 48.3852 60.2632 47.5379 58.6943 47.5379H55.9992V51.9272H58.6943C60.2577 51.9326 61.4166 51.0854 61.4166 49.7298ZM58.5303 43.2744C59.5962 43.2744 60.378 42.3671 60.378 41.3066C60.378 40.0768 59.4705 39.2678 58.2187 39.2678C56.9067 39.2678 55.9938 40.0768 55.9938 41.4269V43.2744H58.5303Z" fill="white"/>
<path d="M46.9142 35.3159V47.4396C46.9142 51.9163 44.5144 56.3875 38.3973 56.3875C32.1709 56.3875 29.9187 52.2497 29.6945 47.8441C29.6891 47.7074 29.6836 47.5762 29.6836 47.4396V35.3159H34.7566V47.6965C34.7566 49.5659 35.3633 51.8179 38.3699 51.8179C41.2071 51.8179 41.8357 49.5331 41.8357 47.6965V35.3159H46.9142Z" fill="white"/>
<path d="M26.7753 40.4541L23.4626 42.1541L22.4841 42.657C22.331 42.4001 22.1014 42.0885 21.921 41.8644C21.5055 41.3615 20.9808 40.9242 20.4505 40.5853C20.0077 40.3394 19.472 40.0825 18.9691 39.9567C18.5263 39.8365 17.9906 39.7764 17.4876 39.7764C16.9956 39.7764 16.4599 39.8419 16.0171 39.9567C15.5142 40.0825 14.9785 40.3394 14.5357 40.5853C14 40.8969 13.4752 41.367 13.0652 41.8371C12.2561 42.9357 11.8133 44.3077 11.786 45.6851C11.7532 47.1828 12.3709 48.4838 13.1198 49.7136C13.5353 50.1837 14.071 50.621 14.6013 50.9325C15.0441 51.1785 15.5798 51.4026 16.0827 51.5338C16.5255 51.6541 17.0503 51.7142 17.5587 51.7142C18.0616 51.7142 18.5973 51.6158 19.0401 51.501C19.5431 51.3753 20.0788 51.1293 20.5216 50.8724C21.0464 50.5281 21.5821 50.058 21.9921 49.5606C22.1725 49.3365 22.3474 49.0905 22.495 48.8336L23.4735 49.3365L26.7862 51.0364C25.9608 52.4794 24.78 53.7311 23.4134 54.6713C22.9706 54.9829 22.4349 55.2999 21.9319 55.5131C21.4891 55.7372 20.9644 55.9176 20.4614 56.0815C19.5103 56.3275 18.5317 56.486 17.4931 56.486C16.4927 56.486 15.4541 56.3549 14.5357 56.0815C14.0328 55.923 13.5572 55.77 13.1144 55.5459C12.6224 55.3218 12.0265 54.9501 11.5783 54.6713C8.70287 52.7582 6.84424 49.4676 6.84424 45.7398C6.84424 42.012 8.70287 38.7542 11.5783 36.8411C13.262 35.7534 15.3338 35.0264 17.4931 35.0264C19.6852 35.0264 21.7953 35.7206 23.479 36.8739C24.8292 37.7976 25.9499 39.0166 26.7753 40.4541Z" fill="white"/>
<path d="M11.3816 76.7814L6.78418 58.8473H9.74705C11.0645 58.8473 12.2125 59.7437 12.535 61.0173L15.968 74.6988C16.0609 75.0431 16.3725 75.2345 16.7825 75.2345C17.1925 75.2345 17.4713 75.0431 17.5642 74.6988L21.5767 58.8418H26.7808L22.4896 75.8576C21.2104 80.378 21.4783 80.0009 17.0886 79.9681C12.1906 79.9407 12.3109 80.4545 11.3816 76.7814Z" fill="white"/>
<path d="M34.8547 64.6359V67.3907H44.7984V71.6215H34.8547V74.5021C34.8547 75.2509 35.385 75.7538 36.1721 75.7538H46.903V79.9845H36.1721C32.4768 79.9845 29.7817 80.2906 29.7817 73.9063V65.2262C29.7817 61.717 32.4768 59.1479 36.1721 59.1479H46.903V63.3787H36.1721C35.3904 63.3841 34.8547 63.887 34.8547 64.6359Z" fill="white"/>
<path d="M50.7682 67.019C50.7682 62.4767 54.6221 58.8418 59.3889 58.8418C64.1503 58.8418 67.9714 62.4767 67.9714 67.019C67.9714 69.5552 66.7797 71.6269 64.5548 72.9387L68.3158 79.9899H62.9914L59.3124 72.6927C58.9953 72.0641 59.2413 71.2825 59.8754 70.9764C61.9582 69.9761 62.893 68.7025 62.893 67.019C62.893 65.1059 61.3569 63.5754 59.3835 63.5754C57.41 63.5754 55.8411 65.1113 55.8411 67.019V79.9899H50.7627V67.019H50.7682Z" fill="white"/>
<path d="M78.4942 59.1533H71.6665V79.9898H78.4942C84.5731 79.9898 89.4602 75.3219 89.4602 69.5552C89.4602 63.8268 84.5731 59.1533 78.4942 59.1533ZM78.4942 75.7646H76.7395V63.3895H78.4942C81.7523 63.3895 84.3872 66.1444 84.3872 69.5607C84.3817 73.0043 81.7523 75.7646 78.4942 75.7646Z" fill="white"/>
<path d="M107.243 42.3945C106.505 42.3945 105.925 42.8263 105.794 43.4659L105.472 45.062L105.149 43.4659C105.018 42.8263 104.439 42.3945 103.701 42.3945C102.902 42.3945 102.279 42.9193 102.279 43.5861V48.1339H103.493V43.6736C103.493 43.608 103.602 43.5643 103.706 43.5643C103.744 43.5643 103.93 43.5697 103.958 43.7173L104.925 48.1394H106.007L106.981 43.7119C107.008 43.5697 107.194 43.5643 107.232 43.5643C107.336 43.5643 107.445 43.608 107.445 43.6736V48.1339H108.659V43.5861C108.659 42.9193 108.036 42.3945 107.243 42.3945Z" fill="white"/>
<path d="M97.6382 43.5535H99.0978V48.134H100.311V43.5535H101.771V42.4712H97.6382V43.5535Z" fill="white"/>
<path d="M96.5667 64.6031V67.358H106.51V71.5887H96.5667V74.4693C96.5667 75.2182 97.097 75.7211 97.8842 75.7211H108.615V79.9518H97.8842C94.1888 79.9518 91.4883 80.2633 91.4883 73.8735V65.1935C91.4883 61.6843 94.1833 59.1152 97.8842 59.1152H108.615V63.3459H97.8842C97.097 63.3459 96.5667 63.8488 96.5667 64.6031Z" fill="white"/>
<path d="M2.93554 0C1.31744 0 0 1.31185 0 2.93526V5.07795V17.3H5.07843V5.07795H17.3017V0H2.93554Z" fill="white"/>
<path d="M109.921 97.7056V109.928H97.6982V115H112.064C113.682 115 115 113.688 115 112.065V109.922V97.7056H109.921Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#41479B;" d="M473.655,88.276H38.345C17.167,88.276,0,105.443,0,126.621V385.38
c0,21.177,17.167,38.345,38.345,38.345h435.31c21.177,0,38.345-17.167,38.345-38.345V126.621
C512,105.443,494.833,88.276,473.655,88.276z"/>
<path style="fill:#F5F5F5;" d="M511.469,120.282c-3.022-18.159-18.797-32.007-37.814-32.007h-9.977l-163.54,107.147V88.276h-88.276
v107.147L48.322,88.276h-9.977c-19.017,0-34.792,13.847-37.814,32.007l139.778,91.58H0v88.276h140.309L0.531,391.717
c3.022,18.159,18.797,32.007,37.814,32.007h9.977l163.54-107.147v107.147h88.276V316.577l163.54,107.147h9.977
c19.017,0,34.792-13.847,37.814-32.007l-139.778-91.58H512v-88.276H371.691L511.469,120.282z"/>
<g>
<polygon style="fill:#FF4B55;" points="282.483,88.276 229.517,88.276 229.517,229.517 0,229.517 0,282.483 229.517,282.483
229.517,423.724 282.483,423.724 282.483,282.483 512,282.483 512,229.517 282.483,229.517 "/>
<path style="fill:#FF4B55;" d="M24.793,421.252l186.583-121.114h-32.428L9.224,410.31
C13.377,415.157,18.714,418.955,24.793,421.252z"/>
<path style="fill:#FF4B55;" d="M346.388,300.138H313.96l180.716,117.305c5.057-3.321,9.277-7.807,12.287-13.075L346.388,300.138z"
/>
<path style="fill:#FF4B55;" d="M4.049,109.475l157.73,102.387h32.428L15.475,95.842C10.676,99.414,6.749,104.084,4.049,109.475z"/>
<path style="fill:#FF4B55;" d="M332.566,211.862l170.035-110.375c-4.199-4.831-9.578-8.607-15.699-10.86L300.138,211.862H332.566z"
/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

12
qml/Icons/error-state.svg Normal file
View File

@@ -0,0 +1,12 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1401_2121)">
<circle cx="12" cy="12.5" r="11" stroke="#CF3200" stroke-width="2"/>
<path d="M12 6.5L12 14.5" stroke="#CF3200" stroke-width="2"/>
<path d="M12 16L12 18" stroke="#CF3200" stroke-width="2" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1401_2121">
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 492 B

4
qml/Icons/exit.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.4001 3.60017C20.7183 3.60017 21.0235 3.72659 21.2485 3.95165C21.4736 4.17669 21.6001 4.48191 21.6001 4.80017V19.2002C21.6001 19.5184 21.4736 19.8237 21.2485 20.0487C21.0235 20.2737 20.7183 20.4002 20.4001 20.4002C20.0817 20.4002 19.7766 20.2737 19.5515 20.0487C19.3265 19.8237 19.2001 19.5184 19.2001 19.2002V4.80017C19.2001 4.48191 19.3265 4.17669 19.5515 3.95165C19.7766 3.72659 20.0817 3.60017 20.4001 3.60017ZM8.04841 14.7518C8.267 14.9781 8.38795 15.2812 8.38522 15.5959C8.38248 15.9105 8.25629 16.2115 8.0338 16.4339C7.81131 16.6564 7.51033 16.7827 7.19569 16.7853C6.88106 16.7881 6.57793 16.6671 6.35161 16.4486L2.75161 12.8486C2.52665 12.6236 2.40027 12.3183 2.40027 12.0002C2.40027 11.682 2.52665 11.3768 2.75161 11.1518L6.35161 7.55177C6.46231 7.43716 6.59472 7.34574 6.74113 7.28284C6.88753 7.21996 7.045 7.18685 7.20433 7.18547C7.36367 7.18409 7.52168 7.21445 7.66916 7.27479C7.81663 7.33512 7.95061 7.42422 8.06328 7.53689C8.17595 7.64957 8.26506 7.78355 8.3254 7.93103C8.38573 8.07851 8.4161 8.23652 8.41471 8.39585C8.41333 8.55519 8.38023 8.71269 8.31733 8.85909C8.25444 9.00549 8.16303 9.13792 8.04841 9.24857L6.49681 10.8002H15.6001C15.9183 10.8002 16.2235 10.9266 16.4485 11.1516C16.6736 11.3767 16.8001 11.6819 16.8001 12.0002C16.8001 12.3184 16.6736 12.6237 16.4485 12.8487C16.2235 13.0737 15.9183 13.2002 15.6001 13.2002H6.49681L8.04841 14.7518Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

12
qml/Icons/good-state.svg Normal file
View File

@@ -0,0 +1,12 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1401_2104)">
<path d="M6 12.95L9.85714 17L18 8" stroke="#009352" stroke-width="2" stroke-linejoin="round"/>
<circle cx="12" cy="12.5" r="11" stroke="#009352" stroke-width="2"/>
</g>
<defs>
<clipPath id="clip0_1401_2104">
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 443 B

4
qml/Icons/hide-menu.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 19L11 10L20 1" stroke="white" stroke-width="2"/>
<path d="M11 19L2 10L11 1" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 226 B

3
qml/Icons/history.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 4.66667V11.2792C12 11.7097 12.2754 12.0918 12.6838 12.2279L17.5 13.8333M12 23C14.9174 23 17.7153 21.8411 19.7782 19.7782C21.8411 17.7153 23 14.9174 23 12C23 9.08262 21.8411 6.28473 19.7782 4.22183C17.7153 2.15893 14.9174 1 12 1C9.08262 1 6.28473 2.15893 4.22183 4.22183C2.15893 6.28473 1 9.08262 1 12C1 14.9174 2.15893 17.7153 4.22183 19.7782C6.28473 21.8411 9.08262 23 12 23Z" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 528 B

12
qml/Icons/info-state.svg Normal file
View File

@@ -0,0 +1,12 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1401_2130)">
<path d="M12 23.5V24.5V23.5ZM12 1.5V0.5V1.5ZM1 12.5H0H1ZM2.65602 18.3044L3.60879 18.6081C3.69622 18.3338 3.66119 18.0351 3.51265 17.7885L2.65602 18.3044ZM1 23.5L0.0472261 23.1963C-0.0638084 23.5447 0.0241315 23.9259 0.276556 24.1904C0.52898 24.4549 0.905642 24.5606 1.25881 24.4659L1 23.5ZM6.5 22.0263L6.99158 21.1555C6.76354 21.0268 6.49412 20.9926 6.24119 21.0604L6.5 22.0263ZM2.5 18.0453L1.63627 18.5495L1.64336 18.5612L2.5 18.0453ZM6.68517 22.1308L6.19357 23.0017L6.20203 23.0064L6.68517 22.1308ZM12 24.5C15.1826 24.5 18.2348 23.2357 20.4853 20.9853L19.0711 19.5711C17.1957 21.4464 14.6522 22.5 12 22.5V24.5ZM20.4853 20.9853C22.7357 18.7348 24 15.6826 24 12.5H22C22 15.1522 20.9464 17.6957 19.0711 19.5711L20.4853 20.9853ZM24 12.5C24 9.3174 22.7357 6.26516 20.4853 4.01472L19.0711 5.42893C20.9464 7.3043 22 9.84783 22 12.5H24ZM20.4853 4.01472C18.2348 1.76428 15.1826 0.5 12 0.5V2.5C14.6522 2.5 17.1957 3.55357 19.0711 5.42893L20.4853 4.01472ZM12 0.5C8.8174 0.5 5.76516 1.76428 3.51472 4.01472L4.92893 5.42893C6.8043 3.55357 9.34784 2.5 12 2.5V0.5ZM3.51472 4.01472C1.26428 6.26516 0 9.3174 0 12.5H2C2 9.84784 3.05357 7.3043 4.92893 5.42893L3.51472 4.01472ZM1.70324 18.0007L0.0472261 23.1963L1.95277 23.8037L3.60879 18.6081L1.70324 18.0007ZM1.25881 24.4659L6.75881 22.9922L6.24119 21.0604L0.741187 22.5341L1.25881 24.4659ZM0 12.5C0 14.6441 0.573832 16.729 1.63635 18.5494L3.36365 17.5412C2.47814 16.0241 2 14.2867 2 12.5H0ZM6.20203 23.0064C7.96181 23.9775 9.95397 24.5 12 24.5V22.5C10.295 22.5 8.63494 22.0646 7.16831 21.2553L6.20203 23.0064ZM1.64336 18.5612L1.79938 18.8203L3.51265 17.7885L3.35664 17.5294L1.64336 18.5612ZM6.00842 22.8971L6.19359 23.0017L7.17675 21.26L6.99158 21.1555L6.00842 22.8971Z" fill="#0A72BA"/>
<path d="M7.25 10.75H16.75" stroke="#0A72BA" stroke-width="2" stroke-linejoin="round"/>
<path d="M7.25 14.25H13.75" stroke="#0A72BA" stroke-width="2" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1401_2130">
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

9
qml/Icons/info.svg Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<g transform="translate(0 -1028.4)">
<path d="m22 12a10 10 0 1 1 -20 0 10 10 0 1 1 20 0z" transform="translate(0 1029.4)" fill="#2980b9"/>
<path d="m22 12a10 10 0 1 1 -20 0 10 10 0 1 1 20 0z" transform="translate(0 1028.4)" fill="#3498db"/>
<path d="m11 1035.4v2h2v-2h-2zm-1 4-1 1h2v6h-2v1h1 4 1v-1h-2v-7h-3z" fill="#2980b9"/>
<path d="m11 6v2h2v-2h-2zm-1 4l-1 1h2v6h-2v1h1 4 1v-1h-2v-7h-3z" transform="translate(0 1028.4)" fill="#ecf0f1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 762 B

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#73AF00;" d="M38.345,88.273C17.167,88.273,0,105.44,0,126.618v258.759c0,21.177,17.167,38.345,38.345,38.345
h132.322V88.273H38.345z"/>
<rect x="170.67" y="88.277" style="fill:#F5F5F5;" width="170.67" height="335.45"/>
<path style="fill:#FF4B55;" d="M473.655,88.273H341.333v335.448h132.322c21.177,0,38.345-17.167,38.345-38.345V126.618
C512,105.44,494.833,88.273,473.655,88.273z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@@ -0,0 +1,12 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1401_2140)">
<circle cx="12" cy="12.5" r="11" stroke="#838D97" stroke-width="2"/>
<path d="M12 18L12 10" stroke="#838D97" stroke-width="2"/>
<path d="M12 8.5L12 6.5" stroke="#838D97" stroke-width="2" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1401_2140">
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 491 B

3
qml/Icons/refresh.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.8316 19.7618L15.3483 18.8863L15.8316 19.7618ZM6.16651 2.25214L5.68325 1.37666L6.16651 2.25214ZM1.39134 8.23348L0.430573 7.95614H0.430573L1.39134 8.23348ZM2.24424 15.8395L1.36876 16.3227H1.36876L2.24424 15.8395ZM20.2444 6.95135L20.0588 7.93397C20.3246 7.98418 20.5994 7.92457 20.8205 7.76874C21.0416 7.61291 21.1901 7.37416 21.2322 7.10695L20.2444 6.95135ZM7.94823 21.5754C10.7512 22.3845 13.7607 22.0471 16.3148 20.6372L15.3483 18.8863C13.2586 20.0398 10.7962 20.3159 8.50293 19.6539L7.94823 21.5754ZM16.3148 20.6372C18.8689 19.2274 20.7584 16.8607 21.5675 14.0578L19.646 13.5031C18.984 15.7964 17.4381 17.7328 15.3483 18.8863L16.3148 20.6372ZM20.6293 5.69116C19.2195 3.13705 16.8528 1.2476 14.0499 0.438477L13.4952 2.36002C15.7885 3.02203 17.7249 4.56794 18.8784 6.65767L20.6293 5.69116ZM14.0499 0.438477C11.2469 -0.370648 8.23736 -0.0331718 5.68325 1.37666L6.64976 3.12762C8.73949 1.97412 11.2018 1.69801 13.4952 2.36002L14.0499 0.438477ZM5.68325 1.37666C3.12914 2.7865 1.2397 5.1532 0.430573 7.95614L2.35211 8.51083C3.01412 6.21752 4.56003 4.28113 6.64976 3.12762L5.68325 1.37666ZM0.430573 7.95614C-0.378552 10.7591 -0.0410769 13.7686 1.36876 16.3227L3.11972 15.3562C1.96622 13.2665 1.6901 10.8041 2.35211 8.51083L0.430573 7.95614ZM1.36876 16.3227C2.77859 18.8769 5.1453 20.7663 7.94823 21.5754L8.50293 19.6539C6.20962 18.9919 4.27322 17.446 3.11972 15.3562L1.36876 16.3227ZM14.6458 6.9115L20.0588 7.93397L20.43 5.96872L15.017 4.94625L14.6458 6.9115ZM21.2322 7.10695L22.0398 1.98023L20.0642 1.66902L19.2566 6.79574L21.2322 7.10695Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#F5F5F5;" d="M473.655,88.276H38.345C17.167,88.276,0,105.443,0,126.621v73.471h512v-73.471
C512,105.443,494.833,88.276,473.655,88.276z"/>
<path style="fill:#FF4B55;" d="M0,385.379c0,21.177,17.167,38.345,38.345,38.345h435.31c21.177,0,38.345-17.167,38.345-38.345
v-73.471H0V385.379z"/>
<rect y="200.09" style="fill:#41479B;" width="512" height="111.81"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 867 B

46
qml/Icons/temperature.svg Normal file
View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 250.189 250.189" style="enable-background:new 0 0 250.189 250.189;" xml:space="preserve">
<g>
<path d="M159.845,147.251V34.744C159.845,15.586,144.255,0,125.093,0c-19.159,0-34.746,15.586-34.746,34.744v112.506
c-14.234,10.843-22.617,27.59-22.617,45.575c0,31.631,25.732,57.364,57.363,57.364c31.633,0,57.367-25.733,57.367-57.364
C182.46,174.842,174.077,158.095,159.845,147.251z M125.093,235.189c-23.359,0-42.363-19.004-42.363-42.364
c0-14.294,7.188-27.537,19.228-35.425c2.115-1.386,3.39-3.745,3.39-6.273V34.744c0-10.887,8.858-19.744,19.746-19.744
c10.892,0,19.752,8.857,19.752,19.744v116.383c0,2.529,1.274,4.887,3.39,6.273c12.038,7.889,19.226,21.132,19.226,35.425
C167.46,216.185,148.454,235.189,125.093,235.189z"/>
<path d="M132.595,169.042V69.924c0-4.142-3.357-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v99.118c-10.104,3.183-17.43,12.622-17.43,23.783
c0,13.767,11.16,24.931,24.93,24.931c13.773,0,24.932-11.164,24.932-24.931C150.026,181.663,142.7,172.223,132.595,169.042z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 2V21H23" stroke="white" stroke-width="2"/>
<path d="M21 8L16.4181 11.7419C16.1572 11.955 15.8065 12.0224 15.4851 11.9211L11.0391 10.5206C10.6751 10.406 10.2776 10.5085 10.0145 10.7848L6 15" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

View File

@@ -0,0 +1,12 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1401_2112)">
<path d="M12 23.5V24.5V23.5ZM12 1.5V0.5V1.5ZM1 12.5H0H1ZM2.65602 18.3044L3.60879 18.6081C3.69622 18.3338 3.66119 18.0351 3.51265 17.7885L2.65602 18.3044ZM1 23.5L0.0472261 23.1963C-0.0638084 23.5447 0.0241315 23.9259 0.276556 24.1904C0.52898 24.4549 0.905642 24.5606 1.25881 24.4659L1 23.5ZM6.5 22.0263L6.99158 21.1555C6.76354 21.0268 6.49412 20.9926 6.24119 21.0604L6.5 22.0263ZM2.5 18.0453L1.63627 18.5495L1.64336 18.5612L2.5 18.0453ZM6.68517 22.1308L6.19357 23.0017L6.20203 23.0064L6.68517 22.1308ZM12 24.5C15.1826 24.5 18.2348 23.2357 20.4853 20.9853L19.0711 19.5711C17.1957 21.4464 14.6522 22.5 12 22.5V24.5ZM20.4853 20.9853C22.7357 18.7348 24 15.6826 24 12.5H22C22 15.1522 20.9464 17.6957 19.0711 19.5711L20.4853 20.9853ZM24 12.5C24 9.3174 22.7357 6.26516 20.4853 4.01472L19.0711 5.42893C20.9464 7.3043 22 9.84783 22 12.5H24ZM20.4853 4.01472C18.2348 1.76428 15.1826 0.5 12 0.5V2.5C14.6522 2.5 17.1957 3.55357 19.0711 5.42893L20.4853 4.01472ZM12 0.5C8.8174 0.5 5.76516 1.76428 3.51472 4.01472L4.92893 5.42893C6.8043 3.55357 9.34784 2.5 12 2.5V0.5ZM3.51472 4.01472C1.26428 6.26516 0 9.3174 0 12.5H2C2 9.84784 3.05357 7.3043 4.92893 5.42893L3.51472 4.01472ZM1.70324 18.0007L0.0472261 23.1963L1.95277 23.8037L3.60879 18.6081L1.70324 18.0007ZM1.25881 24.4659L6.75881 22.9922L6.24119 21.0604L0.741187 22.5341L1.25881 24.4659ZM0 12.5C0 14.6441 0.573832 16.729 1.63635 18.5494L3.36365 17.5412C2.47814 16.0241 2 14.2867 2 12.5H0ZM6.20203 23.0064C7.96181 23.9775 9.95397 24.5 12 24.5V22.5C10.295 22.5 8.63494 22.0646 7.16831 21.2553L6.20203 23.0064ZM1.64336 18.5612L1.79938 18.8203L3.51265 17.7885L3.35664 17.5294L1.64336 18.5612ZM6.00842 22.8971L6.19359 23.0017L7.17675 21.26L6.99158 21.1555L6.00842 22.8971Z" fill="#E6C207"/>
<path d="M12 6.5L12 14.5" stroke="#E6C207" stroke-width="2"/>
<path d="M12 16L12 18" stroke="#E6C207" stroke-width="2" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1401_2112">
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

8
qml/Icons/warning.svg Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<g transform="translate(0 -1028.4)">
<path d="m12 1031.4c-0.985-0.1-1.715 0.7-2.0313 1.6-2.6053 5.2-5.2088 10.4-7.8125 15.6-0.6178 1.3 0.5802 2.9 2 2.8h7.8438 7.844c1.42 0.1 2.618-1.5 2-2.8-2.604-5.2-5.207-10.4-7.813-15.6-0.316-0.9-1.046-1.7-2.031-1.6z" fill="#f39c12"/>
<path d="m12 2c-0.985-0.0372-1.715 0.7682-2.0312 1.625-2.6054 5.2106-5.2089 10.418-7.8126 15.625-0.6178 1.307 0.5802 2.919 2 2.75 2.6101-0.003 5.2337-0.001 7.8438 0 2.61-0.001 5.234-0.003 7.844 0 1.42 0.169 2.618-1.443 2-2.75-2.604-5.207-5.207-10.414-7.813-15.625-0.316-0.8568-1.046-1.6622-2.031-1.625z" transform="translate(0 1028.4)" fill="#f1c40f"/>
<path d="m12 8c-0.552 0-1 0.4477-1 1l0.5 7h1l0.5-7c0-0.5523-0.448-1-1-1zm0 9c-0.552 0-1 0.448-1 1s0.448 1 1 1 1-0.448 1-1-0.448-1-1-1z" transform="translate(0 1028.4)" fill="#34495e"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

607
qml/MainWindow.qml Normal file
View File

@@ -0,0 +1,607 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Screens 1.0 as Screens
import Cubo 1.0
import Utils 1.0
ApplicationWindow {
id: window
title: qsTr("Cubo Verde BMS")
width: 1366
height: 768
visible: true
RowLayout {
anchors.fill: parent
spacing: 0
Rectangle {
id: pane
color: Palette.alternativeBackgroundColor
implicitWidth: 300
property bool minimized: false
ColumnLayout {
anchors.fill: parent
spacing: 0
Item {
Layout.preferredHeight: 40
}
Image {
source: "qrc:/Icons/cubo-logo.svg"
sourceSize.width: pane.minimized ? 70 : 115
sourceSize.height: pane.minimized ? 70 : 115
Layout.alignment: Qt.AlignCenter
}
Item {
Layout.preferredHeight: pane.minimized ? 85 : 40
}
Controls.MenuItemDelegate {
text: qsTr("Hide menu")
font.weight: Font.Normal
icon.source: "qrc:/Icons/hide-menu.svg"
minimized: pane.minimized
mirroredIcon: pane.minimized
onClicked: if (pane.implicitWidth === 300) {
animation.from = 300
animation.to = 100
animation.running = true
pane.minimized = true
} else {
animation.from = 100
animation.to = 300
animation.running = true
pane.minimized = false
}
Layout.fillWidth: true
}
Item {
Layout.preferredHeight: 40
}
ListView {
id: menuView
clip: true
boundsBehavior: Flickable.StopAtBounds
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"},
{"text": qsTr("BMS service"), "icon": "qrc:/Icons/bms-service.svg"}
]
model: menuModel.length
delegate: Controls.MenuItemDelegate {
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
}
Layout.fillHeight: true
Layout.fillWidth: true
}
Controls.MenuItemDelegate {
text: qsTr("Connection")
icon.source: "qrc:/Icons/connection.svg"
icon.color: "#FFFFFF"
minimized: pane.minimized
onClicked: connectionDialog.open()
Layout.fillWidth: true
}
Item {
Layout.preferredHeight: 40
}
}
PropertyAnimation {
id: animation
target: pane
property: "implicitWidth"
duration: 200
easing.type: Easing.InQuad
}
Layout.preferredWidth: implicitWidth
Layout.fillHeight: true
}
ColumnLayout {
spacing: 0
RowLayout {
id: topBar
Label {
text: stack.itemAt(stack.currentIndex).title
font.pixelSize: 38
font.weight: Font.Bold
color: Palette.textColor
}
Item {
Layout.fillWidth: true
}
RowLayout {
spacing: 20
ColumnLayout {
spacing: 5
RowLayout {
spacing: 7
Controls.ContentLabel {
id: connectionStatusLabel
text: qsTr("Disconnected")
Layout.alignment: Qt.AlignRight
}
Controls.AvailabilityIndicator {
id: connectionStatusIndicator
enabled: false
neutral: false
Layout.alignment: Qt.AlignCenter
}
Controls.ContentLabel {
id: firmwareLabel
text: "-"
Layout.alignment: Qt.AlignRight
}
Layout.alignment: Qt.AlignRight
}
RowLayout {
spacing: 5
Controls.ContentLabel {
text: qsTr("Serial number") + ":"
Layout.alignment: Qt.AlignRight
}
Controls.SubtitleLabel {
id: serialLabel
text: "-"
Layout.alignment: Qt.AlignRight
}
Layout.alignment: Qt.AlignRight
}
Layout.topMargin: 15
Layout.bottomMargin: 15
Layout.fillHeight: true
}
Controls.LineSeparator {
horizontal: false
Layout.fillHeight: true
Layout.topMargin: 15
Layout.bottomMargin: 15
}
Item {
RowLayout {
id: languagesLayout
anchors.fill: parent
spacing: 10
Controls.ContentLabel {
text: Translator.currentLanguageName
}
Image {
source: Translator.currentLanguageIcon
sourceSize.width: 30
sourceSize.height: 26
}
}
MouseArea {
anchors.fill: parent
onClicked: languagesPopup.open()
}
Popup {
id: languagesPopup
width: 90
contentHeight: languagesList.contentHeight
padding: 1
x: -(width - languagesLayout.width) / 2
y: languagesLayout.height + 2
background: Rectangle {
color: Palette.backgroundColor
radius: 6
border.width: 1
border.color: Palette.borderColor
}
contentItem: ListView {
id: languagesList
model: [Translator.Russian, Translator.English, Translator.Italian]
width: languagesPopup.width
height: 120
clip: true
spacing: 0
delegate: Rectangle {
width: ListView.view.width
height: 40
color: Palette.backgroundColor
RowLayout {
anchors.fill: parent
spacing: 10
Controls.ContentLabel {
text: Translator.languageName(modelData)
Layout.fillWidth: true
Layout.leftMargin: 10
}
Image {
source: Translator.languageIcon(modelData)
sourceSize.width: 30
sourceSize.height: 26
Layout.rightMargin: 10
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPressed: parent.color = Palette.selectedBackgroundColor
onReleased: parent.color = Palette.backgroundColor
onEntered: parent.color = Palette.hoveredBackgroundColor
onExited: parent.color = Palette.backgroundColor
onClicked: {
languagesPopup.close()
Translator.currentLanguage = modelData
}
}
}
}
}
Layout.preferredWidth: languagesLayout.implicitWidth
Layout.preferredHeight: languagesLayout.implicitHeight
}
}
Layout.leftMargin: 45
Layout.rightMargin: 45
Layout.maximumHeight: 90
}
StackLayout {
id: stack
currentIndex: menuView.currentIndex
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 45
Layout.rightMargin: 45
Layout.bottomMargin: 30
Screens.AkbMonitorScreen {
property string title: qsTr("AKB monitor")
}
Screens.CellMonitorScreen {
property string title: qsTr("Cell monitor")
}
Screens.TemperatureMonitorScreen {
property string title: qsTr("Temperature monitor")
}
Screens.BmsSettingsScreen {
property string title: qsTr("BMS settings")
onNeedWait: {
if (active) {
busyPopup.text = text
busyPopup.open()
} else {
busyPopup.close()
}
}
}
Screens.VisualizationScreen {
property string title: qsTr("Visualization")
}
Screens.DebugInformationScreen {
id: debugScreen
property string title: qsTr("Information output")
}
Screens.BmsServiceScreen {
}
}
}
}
Connections {
target: BmsInterface
onPortConnectedChanged: {
connectionStatusLabel.text = Qt.binding(function(){ return BmsInterface.isPortConnected() ? qsTr("Connected") : qsTr("Disconnected") })
connectionStatusIndicator.enabled = BmsInterface.isPortConnected()
faultStateTimer.running = BmsInterface.isPortConnected()
if (BmsInterface.isPortConnected()) {
BmsInterface.commands().getBMSconf()
BmsInterface.commands().getFaultState()
} else {
serialLabel.text = "-"
firmwareLabel.text = "-"
statusPopup.queue = []
faultStatePopup.lastState = ""
}
}
onMessageDialog: {
if (!messageDialog.visible) {
messageDialog.title = title
messageDialog.description = msg
messageDialog.good = isGood
messageDialog.open()
} else {
messageDialog.queue.push({"title": title, "description": msg, "good": isGood})
}
}
onStatusMessage: {
for (var i = 0; i < statusPopup.filteredStatuses.length; ++i) {
if (msg === statusPopup.filteredStatuses[i]) {
return
}
}
if (!statusPopup.visible) {
statusPopup.text = msg
statusPopup.good = isGood
statusPopup.open()
} else {
if (statusPopup.text !== msg) {
statusPopup.queue.push({"text": msg, "good": isGood})
}
}
}
onFwUploadStatus: {
if (isOngoing) {
if (!progressPopup.opened) {
progressPopup.open()
}
progressPopup.text = status
progressPopup.progress = progress
} else {
progressPopup.close()
BmsInterface.emitMessageDialog(qsTr("Firmware update"), status, true)
}
}
onBmsConfigurationStored: busyPopup.close()
}
Connections {
target: BmsInterface.bmsConfig()
onUpdated: {
serialLabel.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed()
}
}
Connections {
target: BmsInterface.commands()
onFwVersionReceived: {
firmwareLabel.text = major + "." + minor
}
onFaultStateReceived: {
if (faultStatePopup.lastState != faultString) {
faultStatePopup.close()
faultStatePopup.lastState = faultString
faultStatePopup.text = faultString
faultStatePopup.type = faultType
faultStatePopup.open()
Qt.callLater(debugScreen.printMessage, faultString, faultStatePopup.color)
}
}
}
Screens.ConnectionDialog {
id: connectionDialog
}
Screens.MessageDialog {
id: messageDialog
property var queue: []
onClosed: {
if (queue.length > 0) {
var message = queue.pop()
messageDialog.title = message.title
messageDialog.description = message.description
messageDialog.good = message.good
messageDialog.open()
}
}
}
Screens.StatusPopup {
id: statusPopup
property var filteredStatuses: []
property var queue: []
onClosed: {
if (queue.length > 0) {
var message = queue.pop()
statusPopup.text = message.text
statusPopup.good = message.good
statusPopup.open()
}
}
onOpened: {
hideStatusTimer.start()
}
Timer {
id: hideStatusTimer
interval: 3000
onTriggered: statusPopup.close()
}
}
Popup {
id: busyPopup
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
property string text: ""
background: Rectangle {
color: "transparent"
}
ColumnLayout {
Controls.BusyIndicator {
running: true
Layout.alignment: Qt.AlignCenter
}
Controls.SubtitleLabel {
text: busyPopup.text
color: Palette.alternativeTextColor
maximumLineCount: 3
wrapMode: Text.Wrap
font.pixelSize: 20
Layout.alignment: Qt.AlignCenter
horizontalAlignment: Text.AlignHCenter
leftPadding: 10
rightPadding: 10
background: Rectangle {
color: Palette.textColor
opacity: 0.3
radius: 6
}
}
}
onOpened: hideBusyTimer.start()
onClosed: hideBusyTimer.stop()
Timer {
id: hideBusyTimer
interval: 30000
onTriggered: busyPopup.close()
}
}
Popup {
id: progressPopup
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
property alias text: progressText.text
property alias progress: progressBar.value
background: Rectangle {
color: "transparent"
}
ColumnLayout {
Controls.ProgressBar {
id: progressBar
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 500
}
Controls.SubtitleLabel {
text: "asdfzasdf"
id: progressText
color: Palette.alternativeTextColor
maximumLineCount: 3
wrapMode: Text.Wrap
font.pixelSize: 20
Layout.alignment: Qt.AlignCenter
horizontalAlignment: Text.AlignHCenter
leftPadding: 10
rightPadding: 10
background: Rectangle {
color: Palette.textColor
opacity: 0.3
radius: 6
}
}
}
}
Screens.StatePopup {
id: faultStatePopup
x: parent.width - width - 45
y: 18
property var lastState: ""
onOpened: {
hideStateTimer.start()
}
Timer {
id: hideStateTimer
interval: 3000
onTriggered: faultStatePopup.close()
}
Timer {
id: faultStateTimer
interval: 50000
repeat: true
onTriggered: BmsInterface.commands().getFaultState()
}
}
background: Rectangle {
color: Palette.screenBackgroundColor
}
Component.onCompleted: {
connectionDialog.open()
Qt.callLater(debugScreen.printMessage, qsTr("Tool started"))
}
}

View File

@@ -0,0 +1,329 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Cubo 1.0
import Utils 1.0
Item {
id: root
ColumnLayout {
spacing: 15
anchors.fill: parent
Controls.Frame {
padding: 35
implicitWidth: parent.width
Layout.fillWidth: true
RowLayout {
spacing: 70
anchors.fill: parent
Controls.TitleLabel {
text: qsTr("Serial number")
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.spacing) / 2
}
Controls.TextField {
id: serialNumberField
enabled: false
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.spacing) / 2
}
}
}
Controls.Frame {
padding: 35
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
columnSpacing: 70
rowSpacing: 20
anchors.fill: parent
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Battery charge level, %")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: batteryChargeLevelLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Number of modules")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: numberOfModulesLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Battery voltage, V")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: batteryVoltageLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Number of cells")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: numberOfCellsLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Nominal capacity, A/h")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: nominalCapacityLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Actual capacity, A/h")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: actualCapacityLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Battery temperature, °C")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: batteryTemperatureLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
// RowLayout {
// spacing: 10
// Controls.ContentLabel {
// text: qsTr("BMS temperature, °C")
// }
// Controls.DotSeparator {
// Layout.fillWidth: true
// }
// Controls.SubtitleLabel {
// id: bmsTemperatureLabel
// text: "-"
// }
// Layout.fillWidth: true
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
// }
}
}
Controls.Frame {
padding: 35
implicitWidth: parent.width
Layout.fillWidth: true
GridLayout {
columns: 2
columnSpacing: 70
rowSpacing: 20
anchors.fill: parent
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Maximum cell voltage, V")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: maximumCellVoltageLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Minimum cell voltage, V")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: minimumCellVoltageLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Current")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
id: currentLabel
text: "-"
}
Layout.fillWidth: true
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
}
}
}
Item {
Layout.fillHeight: true
}
}
Connections {
target: BmsInterface.commands()
enabled: root.visible
onValuesReceived: {
batteryChargeLevelLabel.text = values.soC
batteryVoltageLabel.text = MathHelper.roundDouble(values.packVoltage)
batteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattHigh)
// bmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSHigh)
maximumCellVoltageLabel.text = MathHelper.roundDouble(values.cVHigh)
minimumCellVoltageLabel.text = MathHelper.roundDouble(values.cVLow)
currentLabel.text = MathHelper.roundDouble(values.packCurrent)
}
}
Connections {
target: BmsInterface.bmsConfig()
onUpdated: {
serialNumberField.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed()
numberOfModulesLabel.text = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount")
numberOfCellsLabel.text = BmsInterface.bmsConfig().getParamInt("noOfCellsSeries")
nominalCapacityLabel.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("batteryCapacity"))
actualCapacityLabel.text = nominalCapacityLabel.text // TODO
}
}
Connections {
target: BmsInterface
onPortConnectedChanged: getValues()
}
onVisibleChanged: getValues()
Timer {
id: refreshValuesTimer
interval: 1000
onTriggered: getValues()
}
function getValues() {
if (BmsInterface.isPortConnected() && visible) {
BmsInterface.commands().getValues()
refreshValuesTimer.start()
}
}
}

View File

@@ -0,0 +1,68 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Screens 1.0 as Screens
RowLayout {
spacing: 20
property string title: stack.itemAt(stack.currentIndex).title
StackLayout {
id: stack
Screens.TerminalScreen {
id: terminalScreen
property string title: qsTr("Terminal")
}
Screens.FirmwareUpdateScreen {
id: firmwareUpdateScreen
property string title: qsTr("Firmware update")
}
Screens.NetworkSettingsScreen {
id: networkSettingsScreen
property string title: qsTr("Network settings")
}
Screens.TimeSettingsScreen {
id: timeSettingsScreen
property string title: qsTr("Time settings")
}
// Screens.CanSettingsScreen {
// id: canSettingsScreen
// property string title: qsTr("CAN settings")
// }
Layout.fillWidth: true
Layout.fillHeight: true
}
ColumnLayout {
spacing: 20
Repeater {
model: [
terminalScreen.title,
firmwareUpdateScreen.title,
networkSettingsScreen.title,
timeSettingsScreen.title,
// canSettingsScreen.title
]
delegate: Controls.LinkLabel {
text: modelData
onClicked: stack.currentIndex = index
}
}
Item {
Layout.fillHeight: true
}
Layout.minimumWidth: 180
Layout.maximumWidth: 180
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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
}
}

View File

@@ -0,0 +1,208 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import Controls 1.0 as Controls
import Cubo 1.0
import Utils 1.0
Item {
id: root
Component {
id: cellListHeader
RowLayout {
spacing: 0
width: ListView.view.width
Rectangle {
id: numberTab
color: Palette.tableHeaderBackgroundColor
Layout.preferredHeight: 60
Layout.fillWidth: true
Controls.SubtitleLabel {
id: indexTitleLabel
text: qsTr("#")
color: Palette.tableHeaderTextColor
anchors.centerIn: parent
}
}
Rectangle {
id: voltageTab
color: Palette.tableHeaderBackgroundColor
Layout.preferredHeight: 60
Layout.fillWidth: true
Controls.SubtitleLabel {
id: voltageTitleLabel
text: qsTr("Voltage")
color: Palette.tableHeaderTextColor
anchors.centerIn: parent
}
}
Rectangle {
id: balancingTab
color: Palette.tableHeaderBackgroundColor
Layout.preferredHeight: 60
Layout.fillWidth: true
Controls.SubtitleLabel {
id: balancingTitleLabel
text: qsTr("Balancing")
color: Palette.tableHeaderTextColor
anchors.centerIn: parent
}
}
Layout.fillWidth: true
}
}
Component {
id: cellListDelegate
RowLayout {
spacing: 10
width: ListView.view.width
height: 36
Item {
Layout.preferredWidth: parent.width / 6 - 24
}
Controls.SubtitleLabel {
id: indexLabel
color: Palette.tableHeaderTextColor
horizontalAlignment: Text.AlignHCenter
Layout.preferredWidth: 25
Layout.alignment: Qt.AlignCenter
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.SubtitleLabel {
text: modelData.voltage + " " + qsTr("V")
color: Palette.tableHeaderTextColor
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.AvailabilityIndicator {
enabled: modelData.balancing
Layout.alignment: Qt.AlignCenter
}
Item {
Layout.preferredWidth: parent.width / 6 - 24
}
Component.onCompleted: {
indexLabel.text = index + ListView.view.indexOffset
}
}
}
RowLayout {
anchors.fill: parent
spacing: 20
Controls.Frame {
padding: 1
ListView {
id: firstCellGroup
anchors.fill: parent
clip: true
model: []
spacing: 0
boundsBehavior: Flickable.StopAtBounds
property int indexOffset: 1
header: cellListHeader
delegate: cellListDelegate
ScrollBar.vertical: Controls.ScrollBar {}
}
Layout.fillWidth: true
Layout.fillHeight: true
}
Controls.Frame {
padding: 1
visible: secondCellGroup.model.length > 0
ListView {
id: secondCellGroup
anchors.fill: parent
clip: true
model: []
spacing: 0
boundsBehavior: Flickable.StopAtBounds
property int indexOffset: 17
header: cellListHeader
delegate: cellListDelegate
ScrollBar.vertical: Controls.ScrollBar {}
}
Layout.fillWidth: true
Layout.fillHeight: true
}
}
Connections {
target: BmsInterface.commands()
enabled: root.visible
onCellsReceived: {
firstCellGroup.model = []
var firstModel = []
for (var i = 0; i < Math.min(cellCount, 16); ++i) {
firstModel.push({"voltage": Math.abs(MathHelper.roundDouble(cellVoltageArray[i], 3)), "balancing": cellVoltageArray[i] < 0})
}
firstCellGroup.model = firstModel
if (cellCount > 16) {
secondCellGroup.model = []
var secondModel = []
for (var j = 16; j < Math.min(cellCount, 32); ++j) {
secondModel.push({"voltage": Math.abs(MathHelper.roundDouble(cellVoltageArray[j], 3)), "balancing": cellVoltageArray[i] < 0})
}
secondCellGroup.model = secondModel
}
}
}
Connections {
target: BmsInterface
onPortConnectedChanged: getValues()
}
onVisibleChanged: getValues()
Timer {
id: refreshValuesTimer
interval: 1000
onTriggered: getValues()
}
function getValues() {
if (BmsInterface.isPortConnected() && visible) {
BmsInterface.commands().getCells()
refreshValuesTimer.start()
}
}
}

View File

@@ -0,0 +1,103 @@
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
Dialog {
id: root
title: qsTr("Connection screen")
width: 470
height: 320
modal: true
closePolicy: Popup.CloseOnEscape
header: Controls.DialogHeader {
dialog: root
}
contentItem: Rectangle {
color: Palette.screenBackgroundColor
ColumnLayout {
anchors.fill: parent
anchors.leftMargin: 45
anchors.rightMargin: 45
spacing: 20
Item {
Layout.fillHeight: true
}
Controls.SubtitleLabel {
text: qsTr("Select serial port")
maximumLineCount: 2
wrapMode: Text.Wrap
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
}
RowLayout {
spacing: 15
Controls.ComboBox {
id: serialBox
model: BmsInterface.serialPortNames()
Layout.fillWidth: true
}
Controls.OutlineImageButton {
id: refreshButton
icon.source: "qrc:/Icons/refresh.svg"
icon.width: 30
icon.height: 30
onClicked: serialBox.model = BmsInterface.serialPortNames()
}
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
}
Controls.Button {
id: connectButton
text: qsTr("Connect")
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
onClicked: {
if (BmsInterface.isPortConnected()) {
BmsInterface.disconnectPort()
} else {
var currentPort = BmsInterface.serialPortNames()[serialBox.currentIndex]
if (BmsInterface.connectSerial(currentPort)) {
root.close()
}
}
}
}
Item {
Layout.fillHeight: true
}
}
}
background: Controls.DialogBackground {}
onVisibleChanged: {
x = Qt.binding(function() { return (parent.width - width) / 2})
y = Qt.binding(function() { return (parent.height - height) / 2})
serialBox.model = BmsInterface.serialPortNames()
}
Connections {
target: BmsInterface
onPortConnectedChanged: {
connectButton.text = Qt.binding(function() { return BmsInterface.isPortConnected() ? qsTr("Disconnect") : qsTr("Connect") })
serialBox.enabled = !BmsInterface.isPortConnected()
refreshButton.enabled = !BmsInterface.isPortConnected()
}
}
}

View File

@@ -0,0 +1,56 @@
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
ColumnLayout {
spacing: 20
Controls.Frame {
Flickable {
id: outputFlickable
clip: true
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds
TextArea.flickable: Controls.TextArea {
id: outputArea
textFormat: Text.RichText
}
ScrollBar.horizontal: Controls.ScrollBar { }
ScrollBar.vertical: Controls.ScrollBar { }
}
Layout.fillWidth: true
Layout.fillHeight: true
}
Controls.Button {
text: qsTr("Clear")
Layout.preferredWidth: 120
onClicked: outputArea.clear()
}
Connections {
target: BmsInterface
onStatusMessage: printMessage(msg, isGood ? Palette.textColor : Palette.invalidColor)
onPortConnectedChanged: printMessage(BmsInterface.getConnectedPortName())
}
function printMessage(msg, color = Palette.textColor) {
var message = "<font color=\"" + color + "\">"
message += new Date().toLocaleString(Qt.locale("en-US"), "dd.MM.yyyy hh:mm:ss") + ": " + msg
message += "</font>"
message += "<br>"
outputArea.insert(outputArea.length, message)
outputArea.cursorPosition = outputArea.length
outputFlickable.contentX = 0
}
}

View File

@@ -0,0 +1,126 @@
import QtQuick 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
ColumnLayout {
spacing: 20
Controls.Frame {
padding: 35
ColumnLayout {
anchors.fill: parent
spacing: 20
Controls.TitleLabel {
text: qsTr("Board information")
Layout.fillWidth: true
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Firmware")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.ContentLabel {
id: firmwareLabel
}
Layout.fillWidth: true
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("Hardware")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.ContentLabel {
id: hardwareLabel
}
Layout.fillWidth: true
}
RowLayout {
spacing: 10
Controls.ContentLabel {
text: qsTr("UUID")
}
Controls.DotSeparator {
Layout.fillWidth: true
}
Controls.ContentLabel {
id: uuidLabel
}
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
Controls.Button {
text: qsTr("Upload firmware")
onClicked: firmwareFileDialog.open()
FileDialog {
id: firmwareFileDialog
title: qsTr("Select firmware file")
folder: shortcuts.documents
nameFilters: [ qsTr("Firmware files (*.bin)"), qsTr("All files (*)") ]
onAccepted: {
if (BmsInterface.isPortConnected()) {
updateHelper.uploadFirmware(firmwareFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), BmsInterface)
}
}
}
Settings {
category: "firmwareUpdate"
property alias folder: firmwareFileDialog.folder
}
}
Item {
Layout.fillWidth: true
}
FirmwareUpdateHelper {
id: updateHelper
}
Connections {
target: BmsInterface.commands()
onFwVersionReceived: {
firmwareLabel.text = major + "." + minor
hardwareLabel.text = hw
uuidLabel.text = bufferToHex(uuid)
}
}
function bufferToHex(buffer) {
return [...new Uint8Array(buffer)]
.map(b => b.toString(16).padStart(2, "0"))
.join("").toUpperCase();
}
}

View File

@@ -0,0 +1,65 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Utils 1.0
Dialog {
id: root
width: 500
height: 350
modal: true
closePolicy: Popup.CloseOnEscape
bottomPadding: 0
property string description: ""
property bool good: true
header: Controls.DialogHeader {
dialog: root
}
contentItem: ColumnLayout {
spacing: 20
RowLayout {
spacing: 20
Image {
source: good ? "qrc:/Icons/info.svg" : "qrc:/Icons/warning.svg"
sourceSize.width: 52
sourceSize.height: 48
}
Controls.SubtitleLabel {
text: root.description
maximumLineCount: 10
wrapMode: Text.Wrap
Layout.fillWidth: true
}
Layout.fillWidth: true
Layout.fillHeight: true
}
RowLayout {
Controls.Button {
text: qsTr("Ok")
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 100
onClicked: root.close()
}
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
}
}
background: Controls.DialogBackground {}
onVisibleChanged: {
x = Qt.binding(function() { return (parent.width - width) / 2})
y = Qt.binding(function() { return (parent.height - height) / 2})
}
}

View File

@@ -0,0 +1,221 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Cubo 1.0
ColumnLayout {
spacing: 10
Controls.Frame {
padding: 35
topPadding: 20
bottomPadding: 20
RowLayout {
anchors.fill: parent
spacing: 20
Controls.SubtitleLabel {
id: firstUrlLabel
text: qsTr("Url 1")
TextMetrics {
id: firstUrlMetrics
font: firstUrlLabel.font
text: firstUrlLabel.text
}
Layout.preferredWidth: getMaxLabelWidth()
}
Controls.TextField {
id: firstUrlField
validator: RegExpValidator { regExp: /.{0,250}/ }
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
Controls.Frame {
padding: 35
topPadding: 20
bottomPadding: 20
RowLayout {
anchors.fill: parent
spacing: 20
Controls.SubtitleLabel {
id: secondUrlLabel
text: qsTr("Url 2")
TextMetrics {
id: secondUrlMetrics
font: secondUrlLabel.font
text: secondUrlLabel.text
}
Layout.preferredWidth: getMaxLabelWidth()
}
Controls.TextField {
id: secondUrlField
validator: RegExpValidator { regExp: /.{0,250}/ }
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
Controls.Frame {
padding: 35
topPadding: 20
bottomPadding: 20
RowLayout {
anchors.fill: parent
spacing: 20
Controls.SubtitleLabel {
id: apnLabel
text: qsTr("APN")
TextMetrics {
id: apnMetrics
font: apnLabel.font
text: apnLabel.text
}
Layout.preferredWidth: getMaxLabelWidth()
}
Controls.TextField {
id: apnField
validator: RegExpValidator { regExp: /.{0,50}/ }
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
Controls.Frame {
padding: 35
topPadding: 20
bottomPadding: 20
RowLayout {
anchors.fill: parent
spacing: 20
Controls.SubtitleLabel {
id: userLabel
text: qsTr("User")
TextMetrics {
id: userMetrics
font: userLabel.font
text: userLabel.text
}
Layout.preferredWidth: getMaxLabelWidth()
}
Controls.TextField {
id: userField
validator: RegExpValidator { regExp: /.{0,50}/ }
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
Controls.Frame {
padding: 35
topPadding: 20
bottomPadding: 20
RowLayout {
anchors.fill: parent
spacing: 20
Controls.SubtitleLabel {
id: passwordLabel
text: qsTr("Password")
TextMetrics {
id: passwordMetrics
font: passwordLabel.font
text: passwordLabel.text
}
Layout.preferredWidth: getMaxLabelWidth()
}
Controls.TextField {
id: passwordField
validator: RegExpValidator { regExp: /.{0,50}/ }
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
RowLayout {
spacing: 20
Controls.OutlineButton {
text: qsTr("Default")
onClicked: BmsInterface.commands().getNetDefaultSettings()
}
Controls.Button {
text: qsTr("Apply")
onClicked: {
if (!BmsInterface.isPortConnected())
return
var settings = [
firstUrlField.text,
secondUrlField.text,
apnField.text,
userField.text,
passwordField.text,
]
BmsInterface.commands().setNetSettings(settings)
}
}
}
Connections {
target: BmsInterface.commands()
onNetSettingsReceived: {
if (settings.length < 5) {
return
}
firstUrlField.text = settings[0]
secondUrlField.text = settings[1]
apnField.text = settings[2]
userField.text = settings[3]
passwordField.text = settings[4]
}
}
onVisibleChanged: if (visible) {
if (BmsInterface.isPortConnected()) {
BmsInterface.commands().getNetSettings()
}
}
function getMaxLabelWidth() {
return Math.max(firstUrlMetrics.width, secondUrlMetrics.width, apnMetrics.width, userMetrics.width, passwordMetrics.width)
}
}

View File

@@ -0,0 +1,97 @@
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
Popup {
id: root
closePolicy: Popup.NoAutoClose
property string text: ""
property var type: DataTypes.StateType.Info
property color color: switch (type) {
case DataTypes.StateType.Info:
return "#0A72BA"
case DataTypes.StateType.Good:
return "#009352"
case DataTypes.StateType.Warning:
return "#E5C207"
case DataTypes.StateType.Error:
return "#CF3200"
case DataTypes.StateType.Neutral:
default:
return "#838D97"
}
property var icon: switch (type) {
case DataTypes.StateType.Info:
return "qrc:/Icons/info-state.svg"
case DataTypes.StateType.Good:
return "qrc:/Icons/good-state.svg"
case DataTypes.StateType.Warning:
return "qrc:/Icons/warning-state.svg"
case DataTypes.StateType.Error:
return "qrc:/Icons/error-state.svg"
case DataTypes.StateType.Neutral:
default:
return "qrc:/Icons/neutral-state.svg"
}
RowLayout {
spacing: 15
Image {
source: root.icon
Layout.leftMargin: 5
}
Controls.SubtitleLabel {
id: label
text: root.text
maximumLineCount: 10
wrapMode: Text.Wrap
}
}
background: Rectangle {
radius: 6
color: "#F7F8FC"
Rectangle {
radius: 6
anchors.fill: parent
color: Qt.rgba(root.color.r, root.color.g, root.color.b, 0.1)
}
Rectangle {
radius: 6
width: 4
height: parent.height
anchors.left: parent.left
color: root.color
}
}
enter: Transition {
NumberAnimation {
property: "opacity"
from: 0.0
to: 1.0
duration: 300
}
}
exit: Transition {
NumberAnimation {
property: "opacity"
from: 1.0
to: 0.0
duration: 2500
}
}
}

View File

@@ -0,0 +1,46 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Controls 1.0 as Controls
import Utils 1.0
Popup {
id: root
x: (parent.width - width) / 2
y: parent.height - height - 20
closePolicy: Popup.NoAutoClose
property string text: ""
property bool good: true
Controls.SubtitleLabel {
id: label
text: root.text
maximumLineCount: 10
wrapMode: Text.Wrap
color: Palette.alternativeTextColor
}
background: Rectangle {
radius: 6
color: good ? Palette.informationColor : Palette.invalidColor
}
enter: Transition {
NumberAnimation {
property: "opacity"
from: 0.0
to: 1.0
duration: 300
}
}
exit: Transition {
NumberAnimation {
property: "opacity"
from: 1.0
to: 0.0
duration: 2500
}
}
}

View File

@@ -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: 1 // 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()
}
}
}

View File

@@ -0,0 +1,76 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Cubo 1.0
ColumnLayout {
id: root
spacing: 20
Keys.onReturnPressed: sendButton.clicked()
Keys.onEnterPressed: sendButton.clicked()
Controls.Frame {
Flickable {
id: outputFlickable
clip: true
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds
TextArea.flickable: Controls.TextArea {
id: outputArea
}
ScrollBar.horizontal: Controls.ScrollBar {}
ScrollBar.vertical: Controls.ScrollBar {}
}
Layout.fillWidth: true
Layout.fillHeight: true
}
RowLayout {
spacing: 20
Controls.Button {
text: qsTr("Clear")
Layout.preferredWidth: 120
onClicked: outputArea.clear()
}
Controls.TextField {
id: commandField
implicitHeight: 52
Layout.fillWidth: true
}
Controls.Button {
id: sendButton
text: qsTr("Send")
Layout.preferredWidth: 120
onClicked: {
BmsInterface.commands().sendTerminalCmd(commandField.text)
commandField.clear()
}
}
Controls.Button {
text: qsTr("Help")
Layout.preferredWidth: 120
onClicked: BmsInterface.commands().sendTerminalCmd("help")
}
Layout.fillWidth: true
}
Connections {
target: BmsInterface.commands()
enabled: root.visible
onPrintReceived: {
outputArea.append(str)
outputArea.cursorPosition = outputArea.length
}
}
}

View File

@@ -0,0 +1,278 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Controls 1.0 as Controls
import Cubo 1.0
ColumnLayout {
id: root
spacing: 20
GridLayout {
columns: 2
rowSpacing: 20
columnSpacing: 20
Controls.TitleLabel {
text: qsTr("Date")
}
Controls.TitleLabel {
text: qsTr("Time")
}
Controls.Frame {
GridLayout {
anchors.fill: parent
columns: 3
columnSpacing: 10
Controls.SubtitleLabel {
text: qsTr("Day")
Layout.alignment: Qt.AlignCenter
}
Controls.SubtitleLabel {
text: qsTr("Month")
Layout.alignment: Qt.AlignCenter
}
Controls.SubtitleLabel {
text: qsTr("Year")
Layout.alignment: Qt.AlignCenter
}
Controls.LineSeparator {
Layout.fillWidth: true
}
Controls.LineSeparator {
Layout.fillWidth: true
}
Controls.LineSeparator {
Layout.fillWidth: true
}
Tumbler {
id: dayTumbler
model: {
switch (monthTumbler.currentIndex) {
case 0: return range(1, 31)
case 1: return range(1, yearTumbler.model[yearTumbler.currentIndex] % 4 || monthTumbler.currentIndex !== 1 ? 28 : 29)
case 2: return range(1, 31)
case 3: return range(1, 30)
case 4: return range(1, 31)
case 5: return range(1, 30)
case 6: return range(1, 31)
case 7: return range(1, 31)
case 8: return range(1, 30)
case 9: return range(1, 31)
case 10: return range(1, 30)
case 11: return range(1, 31)
default: return range(1, 0)
}
}
delegate: tumblerComponent
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
}
Tumbler {
id: monthTumbler
model: [
qsTr("January"),
qsTr("February"),
qsTr("March"),
qsTr("April"),
qsTr("May"),
qsTr("June"),
qsTr("July"),
qsTr("August"),
qsTr("September"),
qsTr("October"),
qsTr("November"),
qsTr("December")
]
delegate: tumblerComponent
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
}
Tumbler {
id: yearTumbler
model: range(2000, 200)
delegate: tumblerComponent
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
Controls.Frame {
GridLayout {
anchors.fill: parent
columns: 3
columnSpacing: 10
Controls.SubtitleLabel {
text: qsTr("Hour")
Layout.alignment: Qt.AlignCenter
}
Controls.SubtitleLabel {
text: qsTr("Minute")
Layout.alignment: Qt.AlignCenter
}
Controls.SubtitleLabel {
text: qsTr("Second")
Layout.alignment: Qt.AlignCenter
}
Controls.LineSeparator {
Layout.fillWidth: true
}
Controls.LineSeparator {
Layout.fillWidth: true
}
Controls.LineSeparator {
Layout.fillWidth: true
}
Tumbler {
id: hoursTumbler
model: 24
delegate: tumblerComponent
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
}
Tumbler {
id: minutesTumbler
model: 60
delegate: tumblerComponent
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
}
Tumbler {
id: secondsTumbler
model: 60
delegate: tumblerComponent
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
}
}
Layout.fillWidth: true
}
}
RowLayout {
spacing: 20
Controls.OutlineButton {
text: qsTr("Read from board")
onClicked: BmsInterface.commands().sendTerminalCmd("checkUnixTime")
}
Controls.OutlineButton {
text: qsTr("Read from computer")
onClicked: {
const date = new Date()
yearTumbler.currentIndex = date.getFullYear() - 2000
monthTumbler.currentIndex = date.getMonth()
dayTumbler.currentIndex = date.getDate() - 1
hoursTumbler.currentIndex = date.getHours()
minutesTumbler.currentIndex = date.getMinutes()
secondsTumbler.currentIndex = date.getSeconds()
}
}
Controls.Button {
text: qsTr("Write to board")
onClicked: {
const date = new Date()
date.setFullYear(yearTumbler.model[yearTumbler.currentIndex])
date.setMonth(monthTumbler.currentIndex)
date.setDate(dayTumbler.currentIndex + 1)
date.setHours(hoursTumbler.currentIndex)
date.setMinutes(minutesTumbler.currentIndex)
date.setSeconds(secondsTumbler.currentIndex)
const localTimestamp = (Math.round(date / 1000) - date.getTimezoneOffset() * 60).toString(16)
BmsInterface.commands().sendTerminalCmd("setUnixTime " + localTimestamp)
Qt.callLater(BmsInterface.emitStatusMessage, qsTr("Time settings applied successfully"), true)
}
}
}
Component {
id: tumblerComponent
Controls.SubtitleLabel {
text: modelData
opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Connections {
target: BmsInterface.commands()
enabled: root.visible
onPrintReceived: {
const lines = str.split(/\r?\n/)
for (const line of lines) {
if (line.includes("Year")) {
const value = extractValue(line)
if (value.length === 0) contine
yearTumbler.currentIndex = parseInt(value)
} else if (line.includes("Month")) {
const value = extractValue(line)
if (value.length === 0) contine
monthTumbler.currentIndex = parseInt(value) - 1
} else if (line.includes("Day")) {
const value = extractValue(line)
if (value.length === 0) contine
dayTumbler.currentIndex = parseInt(value) - 1
} else if (line.includes("Hours")) {
const value = extractValue(line)
if (value.length === 0) contine
hoursTumbler.currentIndex = parseInt(value)
} else if (line.includes("Minutes")) {
const value = extractValue(line)
if (value.length === 0) contine
minutesTumbler.currentIndex = parseInt(value)
} else if (line.includes("Seconds")) {
const value = extractValue(line)
if (value.length === 0) contine
secondsTumbler.currentIndex = parseInt(value)
}
}
}
function extractValue(valueHolder) {
const values = valueHolder.split(":")
return values.length < 2 ? "" : values[1].trim()
}
}
function range(startAt, size) {
return [...Array(size).keys()].map(i => i + startAt);
}
onVisibleChanged: if (visible) {
BmsInterface.commands().sendTerminalCmd("checkUnixTime")
}
}

View File

@@ -0,0 +1,625 @@
import QtQuick 2.12
import QtQuick.Controls 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 {
id: root
spacing: 20
property real currentTime: 0
property var voltageData: []
property var currentData: []
property var batteryTemperatureData: []
property var bmsTemperatureData: []
property var cellVoltageData: []
property var cellListData: []
// https://htmlcolorcodes.com/color-chart/
property var chartColors: [
"#c62828", "#6a1b9a", "#283593", "#0277bd", "#00695c", "#558b2f", "#f9a825", "#ef6c00",
"#4e342e", "#37474f", "#ad1457", "#4527a0", "#1565c0", "#00838f", "#2e7d32", "#9e9d24",
"#ff8f00", "#d84315", "#424242", "#ef5350", "#ab47bc", "#5c6bc0", "#29b6f6", "#26a69a",
"#9ccc65", "#ffee58", "#ffa726", "#8d6e63", "#78909c", "#ec407a", "#7e57c2", "#42a5f5",
]
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.8
}
Controls.TabButton {
text: qsTr("Battery temperature")
width: bar.width / 6 * 1.3
}
Controls.TabButton {
text: qsTr("BMS temperature")
width: bar.width / 6 * 1.1
}
Controls.TabButton {
text: qsTr("Cell voltage")
width: bar.width / 6 * 1
}
Controls.TabButton {
text: qsTr("Cell list")
width: bar.width / 6 * 0.85
}
Layout.fillWidth: true
}
StackLayout {
width: parent.width
currentIndex: bar.currentIndex
Component {
id: legendDelegate
RowLayout {
width: ListView.view ? ListView.view.width : 200
height: 60
property Controls.ChartView chartItem: undefined
property color seriesColor: "black"
property bool horizontal: true
property bool selected: false
Controls.CheckBox {
id: checkSeries
checked: true
spacing: 10
onCheckedChanged: {
if (checked) {
chartItem.series(modelData).opacity = 1
} else {
chartItem.series(modelData).opacity = 0
}
}
onHoveredChanged: {
if (hovered) {
chartItem.series(modelData).style = Qt.DashLine
} else {
chartItem.series(modelData).style = Qt.SolidLine
}
}
Layout.fillWidth: !horizontal
}
Rectangle {
color: seriesColor
radius: width / 2
border.width: selected ? 2 : 0
border.color: "black"
Layout.preferredWidth: selected ? 21 : 18
Layout.preferredHeight: selected ? 21 : 18
Layout.rightMargin: 20
Layout.alignment: Qt.AlignCenter
MouseArea {
anchors.fill: parent
onClicked: if (!selected) selected = true
}
}
Component.onCompleted: {
chartItem = ListView.view ? ListView.view.chartItem : parent.chartItem
horizontal = !ListView.view
seriesColor = chartItem.series(modelData).color
checkSeries.text = Qt.binding(function(){ return chartItem.series(modelData).name })
selectedChanged.connect(function (){ if (selected) chartItem.selectedSeriesIndex = index })
chartItem.selectedSeriesIndexChanged.connect(function (){ if (typeof(selected) != "undefined") selected = chartItem.selectedSeriesIndex === index })
selected = chartItem.selectedSeriesIndex === index
}
}
}
Component {
id: chartComponent
RowLayout {
property string xLabel: ""
property string yLabel: ""
property string infoXLabel: ""
property string infoYLabel: ""
property Controls.ChartView chart: chartView
property int seriesCount: 0
property bool horizontalLegend: true
ColumnLayout {
spacing: -20
Controls.ContentLabel {
z: 1
text: yLabel
Layout.topMargin: 20
Layout.leftMargin: 30
Layout.alignment: Qt.AlignLeft
}
Controls.ChartView {
id: chartView
infoXMark: infoXLabel
infoYMark: infoYLabel
Layout.fillWidth: true
Layout.fillHeight: true
}
Controls.ContentLabel {
z: 1
text: xLabel
Layout.alignment: Qt.AlignRight
Layout.rightMargin: 30
Layout.bottomMargin: 10
}
RowLayout {
visible: horizontalLegend
spacing: 0
property Controls.ChartView chartItem: chart
Repeater {
model: seriesCount
delegate: legendDelegate
}
Layout.topMargin: 20
Layout.leftMargin: 20
}
Layout.fillWidth: true
Layout.fillHeight: true
}
ListView {
clip: true
model: seriesCount
delegate: legendDelegate
visible: !horizontalLegend
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: Controls.ScrollBar {}
property Controls.ChartView chartItem: chart
Layout.preferredWidth: 200
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") })
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
item.infoYLabel = Qt.binding(function() { return qsTr("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") })
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
item.infoYLabel = Qt.binding(function() { return qsTr("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") })
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
item.infoYLabel = Qt.binding(function() { return qsTr("°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") })
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
item.infoYLabel = Qt.binding(function() { return qsTr("°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") })
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
item.infoYLabel = Qt.binding(function() { return qsTr("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") })
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
item.infoYLabel = Qt.binding(function() { return qsTr("V") })
item.horizontalLegend = false
}
}
Layout.fillWidth: true
Layout.fillHeight: true
}
}
Layout.fillWidth: true
Layout.fillHeight: true
}
RowLayout {
spacing: 20
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
}
}
Controls.Button {
property string pauseText: qsTr("Pause data collection")
property string resumeText: qsTr("Resume data collection")
text: pauseText
onClicked: {
if (timer.running) {
text = resumeText
timer.stop()
} else {
text = pauseText
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
}
RowLayout {
spacing: 10
Controls.SubtitleLabel {
text: qsTr("Interval, s")
}
Controls.TextField {
id: intervalField
validator: DoubleValidator { bottom: 0.1; top: 100; decimals: 1; locale: "en-US" }
text: "1"
onEditingFinished: timer.interval = parseFloat(text) * 1000
Layout.preferredHeight: 44
}
Controls.ImageButton {
icon.source: "qrc:/Icons/check-indicator.svg"
icon.width: 32
icon.height: 32
Layout.preferredWidth: 42
Layout.preferredHeight: 42
}
}
}
Connections {
target: Translator
onCurrentLanguageChanged: {
for (var i = 0; i < cellListLoader.item.chart.count; ++i) {
cellListLoader.item.chart.series(i).name = qsTr("Cell #") + (i + 1).toString()
}
}
}
Connections {
target: BmsInterface.commands()
enabled: root.visible
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)
if (i < chartColors.length) {
cellListLoader.item.chart.series(i).color = chartColors[i]
}
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 = Math.round((timer.interval / 1000 + currentTime + Number.EPSILON) * 10) / 10
}
}
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.series(0).name = Qt.binding(function(){ return qsTr("Voltage indicator") })
voltageLoader.item.chart.series(0).color = "#fbc02d"
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.series(0).name = Qt.binding(function(){ return qsTr("Current indicator") })
currentLoader.item.chart.series(0).color = "#e64a19"
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.series(0).name = Qt.binding(function(){ return qsTr("Maximum temperature") })
batteryTemperatureLoader.item.chart.series(1).name = Qt.binding(function(){ return qsTr("Average temperature") })
batteryTemperatureLoader.item.chart.series(2).name = Qt.binding(function(){ return qsTr("Minimum temperature") })
batteryTemperatureLoader.item.chart.series(0).color = "#e64a19"
batteryTemperatureLoader.item.chart.series(1).color = "#fbc02d"
batteryTemperatureLoader.item.chart.series(2).color = "#388e3c"
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.series(0).name = Qt.binding(function(){ return qsTr("Maximum temperature") })
bmsTemperatureLoader.item.chart.series(1).name = Qt.binding(function(){ return qsTr("Average temperature") })
bmsTemperatureLoader.item.chart.series(2).name = Qt.binding(function(){ return qsTr("Minimum temperature") })
bmsTemperatureLoader.item.chart.series(0).color = "#e64a19"
bmsTemperatureLoader.item.chart.series(1).color = "#fbc02d"
bmsTemperatureLoader.item.chart.series(2).color = "#388e3c"
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.series(0).color = "#e64a19"
cellVoltageLoader.item.chart.series(1).color = "#fbc02d"
cellVoltageLoader.item.chart.series(2).color = "#388e3c"
cellVoltageLoader.item.chart.series(0).name = Qt.binding(function(){ return qsTr("Maximum voltage") })
cellVoltageLoader.item.chart.series(1).name = Qt.binding(function(){ return qsTr("Average voltage") })
cellVoltageLoader.item.chart.series(2).name = Qt.binding(function(){ return qsTr("Minimum voltage") })
cellVoltageLoader.item.chart.axes[0].max = 10
cellVoltageLoader.item.seriesCount = cellVoltageLoader.item.chart.count
}
}

17
qml/Screens/qmldir Normal file
View File

@@ -0,0 +1,17 @@
module Screens
AkbMonitorScreen 1.0 AkbMonitorScreen.qml
CellMonitorScreen 1.0 CellMonitorScreen.qml
BmsSettingsScreen 1.0 BmsSettingsScreen.qml
VisualizationScreen 1.0 VisualizationScreen.qml
BmsServiceScreen 1.0 BmsServiceScreen.qml
DebugInformationScreen 1.0 DebugInformationScreen.qml
ConnectionDialog 1.0 ConnectionDialog.qml
MessageDialog 1.0 MessageDialog.qml
StatusPopup 1.0 StatusPopup.qml
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
StatePopup 1.0 StatePopup.qml

9
qml/Utils/MathHelper.qml Normal file
View File

@@ -0,0 +1,9 @@
pragma Singleton
import QtQuick 2.12
QtObject {
function roundDouble(value, decimals = 2) {
var factor = Math.pow(10, decimals)
return Math.round((value + Number.EPSILON) * factor) / factor
}
}

30
qml/Utils/Palette.qml Normal file
View File

@@ -0,0 +1,30 @@
pragma Singleton
import QtQuick 2.12
QtObject {
property color textColor: "#000000"
property color selectedTextColor: "#009352"
property color contentTextColor: "#869098"
property color alternativeTextColor: "#FFFFFF"
property color tableHeaderTextColor: "#838D97"
property color backgroundColor: "#FFFFFF"
property color hoveredBackgroundColor: "#F0F1F4"
property color selectedBackgroundColor: "#CCE9DC"
property color alternativeBackgroundColor: "#009352"
property color screenBackgroundColor: "#F7F8FC"
property color tableHeaderBackgroundColor: "#F0F1F4"
property color selectedTextBackgroundColor: "#009150"
property color borderColor: "#DFE0EB"
property color buttonColor: "#009352"
property color outlineButtonColor: "#F7F8FC"
property color hoveredButtonColor: "#03AC61"
property color pressedButtonColor: "#057845"
property color informationColor: "#4C68ED"
property color invalidColor: "#A31C00"
property color goodColor: "#009352"
property color neutralColor: "#DFE0EB"
}

3
qml/Utils/qmldir Normal file
View File

@@ -0,0 +1,3 @@
module utils
singleton Palette 1.0 Palette.qml
singleton MathHelper 1.0 MathHelper.qml

28
qml/qml_icons.qrc Normal file
View File

@@ -0,0 +1,28 @@
<RCC>
<qresource prefix="/">
<file>Icons/akb-monitor.svg</file>
<file>Icons/bms-configuration.svg</file>
<file>Icons/bms-service.svg</file>
<file>Icons/cell-monitor.svg</file>
<file>Icons/cubo-logo.svg</file>
<file>Icons/exit.svg</file>
<file>Icons/hide-menu.svg</file>
<file>Icons/history.svg</file>
<file>Icons/visualization.svg</file>
<file>Icons/check-indicator.svg</file>
<file>Icons/connection.svg</file>
<file>Icons/close.svg</file>
<file>Icons/info.svg</file>
<file>Icons/warning.svg</file>
<file>Icons/english-flag.svg</file>
<file>Icons/italian-flag.svg</file>
<file>Icons/russian-flag.svg</file>
<file>Icons/refresh.svg</file>
<file>Icons/temperature.svg</file>
<file>Icons/error-state.svg</file>
<file>Icons/good-state.svg</file>
<file>Icons/info-state.svg</file>
<file>Icons/neutral-state.svg</file>
<file>Icons/warning-state.svg</file>
</qresource>
</RCC>

54
qml/qml_items.qrc Normal file
View File

@@ -0,0 +1,54 @@
<RCC>
<qresource prefix="/">
<file>MainWindow.qml</file>
<file>Screens/ConnectionDialog.qml</file>
<file>Screens/AkbMonitorScreen.qml</file>
<file>Screens/CellMonitorScreen.qml</file>
<file>Controls/ComboBox.qml</file>
<file>Utils/Palette.qml</file>
<file>Controls/qmldir</file>
<file>Screens/qmldir</file>
<file>Utils/qmldir</file>
<file>Controls/ScrollBar.qml</file>
<file>Controls/OutlineButton.qml</file>
<file>Controls/Button.qml</file>
<file>Controls/TextField.qml</file>
<file>Controls/Frame.qml</file>
<file>Controls/TitleLabel.qml</file>
<file>Controls/SubtitleLabel.qml</file>
<file>Controls/ContentLabel.qml</file>
<file>Controls/DotSeparator.qml</file>
<file>Controls/AvailabilityIndicator.qml</file>
<file>Screens/BmsSettingsScreen.qml</file>
<file>Controls/LabelWithBackground.qml</file>
<file>Controls/CheckBox.qml</file>
<file>Controls/LineSeparator.qml</file>
<file>Controls/LinkLabel.qml</file>
<file>Screens/VisualizationScreen.qml</file>
<file>Controls/TabButton.qml</file>
<file>Controls/TabBar.qml</file>
<file>Controls/ChartView.qml</file>
<file>Screens/BmsServiceScreen.qml</file>
<file>Controls/TextArea.qml</file>
<file>Screens/DebugInformationScreen.qml</file>
<file>Controls/DialogHeader.qml</file>
<file>Controls/DialogBackground.qml</file>
<file>Screens/MessageDialog.qml</file>
<file>Screens/StatusPopup.qml</file>
<file>Utils/MathHelper.qml</file>
<file>Controls/BusyIndicator.qml</file>
<file>Controls/MenuItemDelegate.qml</file>
<file>Controls/ScrollIndicator.qml</file>
<file>Controls/OutlineImageButton.qml</file>
<file>Controls/ImageButton.qml</file>
<file>Screens/TerminalScreen.qml</file>
<file>Screens/FirmwareUpdateScreen.qml</file>
<file>Controls/ProgressBar.qml</file>
<file>Screens/NetworkSettingsScreen.qml</file>
<file>Screens/TimeSettingsScreen.qml</file>
<file>Controls/RadioButton.qml</file>
<file>Screens/TemperatureMonitorScreen.qml</file>
<file>Screens/CanSettingsScreen.qml</file>
<file>Screens/StatePopup.qml</file>
</qresource>
</RCC>

View File

@@ -2486,6 +2486,186 @@ p, li { white-space: pre-wrap; }
<suffix>ms</suffix> <suffix>ms</suffix>
<vTx>5</vTx> <vTx>5</vTx>
</AUX1TurnOffDelay> </AUX1TurnOffDelay>
<chargeBatteryOutputChecked>
<longName>Charge Battery Output Checked</longName>
<type>5</type>
<transmittable>1</transmittable>
<description>Charge Battery Output Checked Description</description>
<cDefine>CHARGE_BATTERY_OUTPUT_CHECKED</cDefine>
<valInt>0</valInt>
</chargeBatteryOutputChecked>
<brushOrShuntOutputChecked>
<longName>Brush Or Shunt Output Checked</longName>
<type>5</type>
<transmittable>1</transmittable>
<description>Brush Or Shunt Output Checked Description</description>
<cDefine>BRUSH_OR_SHUNT_OUTPUT_CHECKED</cDefine>
<valInt>0</valInt>
</brushOrShuntOutputChecked>
<brushOrShuntMode>
<longName>Brush Or Shunt Mode</longName>
<type>5</type>
<transmittable>1</transmittable>
<description>Brush Or Shunt Mode Description</description>
<cDefine>BRUSH_OR_SHUNT_MODE</cDefine>
<valInt>1</valInt>
</brushOrShuntMode>
<brushUsageSocThreshold>
<longName>Brush Usage Soc Threshold</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>Brush Usage Soc Threshold Description</description>
<cDefine>BRUSH_USAGE_SOC_THRESHOLD</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>100</maxInt>
<minInt>0</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>10</valInt>
<suffix>°C</suffix>
<vTx>3</vTx>
</brushUsageSocThreshold>
<shuntChargingContactorDelay>
<longName>Shunt Charging Contactor Delay</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>Shunt Charging Contactor Delay Description</description>
<cDefine>SHUNT_CHARGING_CONTRACTOR_DELAY</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>65535</maxInt>
<minInt>0</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>10</valInt>
<suffix>Sec</suffix>
<vTx>3</vTx>
</shuntChargingContactorDelay>
<coolingOutputChecked>
<longName>Cooling Output Checked</longName>
<type>5</type>
<transmittable>1</transmittable>
<description>Cooling Output Checked Description</description>
<cDefine>COOLING_OUTPUT_CHECKED</cDefine>
<valInt>0</valInt>
</coolingOutputChecked>
<coolingStartThreshold>
<longName>Cooling Start Threshold</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>Cooling Start Threshold Description</description>
<cDefine>COOLING_START_THRESHOLD</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>32767</maxInt>
<minInt>-32768</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>50</valInt>
<suffix>°C</suffix>
<vTx>4</vTx>
</coolingStartThreshold>
<coolingStopThreshold>
<longName>Cooling Stop Threshold</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>Cooling Stop Threshold Description</description>
<cDefine>COOLING_STOP_THRESHOLD</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>32767</maxInt>
<minInt>-32768</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>40</valInt>
<suffix>°C</suffix>
<vTx>4</vTx>
</coolingStopThreshold>
<heatingOutputChecked>
<longName>Heating Output Checked</longName>
<type>5</type>
<transmittable>1</transmittable>
<description>Heating Output Checked Description</description>
<cDefine>HEATING_OUTPUT_CHECKED</cDefine>
<valInt>0</valInt>
</heatingOutputChecked>
<heatingStartThreshold>
<longName>Heating Start Threshold</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>Heating Start Threshold Description</description>
<cDefine>HEATING_START_THRESHOLD</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>32767</maxInt>
<minInt>-32768</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>0</valInt>
<suffix>°C</suffix>
<vTx>4</vTx>
</heatingStartThreshold>
<heatingStopThreshold>
<longName>Heating Stop Threshold</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>Heating Stop Threshold Description</description>
<cDefine>HEATING_STOP_THRESHOLD</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>32767</maxInt>
<minInt>-32768</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>20</valInt>
<suffix>°C</suffix>
<vTx>4</vTx>
</heatingStopThreshold>
<floatCurrentK1>
<longName>Current factor K1</longName>
<type>1</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'DejaVu Sans'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Current factor K1.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>FLOAT_CURRENT_K1</cDefine>
<editorDecimalsDouble>6</editorDecimalsDouble>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxDouble>1.17549e-38</maxDouble>
<minDouble>3.40282e+38</minDouble>
<showDisplay>0</showDisplay>
<stepDouble>0.05</stepDouble>
<valDouble>0</valDouble>
<vTxDoubleScale>100000</vTxDoubleScale>
<suffix></suffix>
<vTx>9</vTx>
</floatCurrentK1>
<floatCurrentK2>
<longName>Current factor K2</longName>
<type>1</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'DejaVu Sans'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Current factor K2.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>FLOAT_CURRENT_K1</cDefine>
<editorDecimalsDouble>6</editorDecimalsDouble>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxDouble>1.17549e-38</maxDouble>
<minDouble>3.40282e+38</minDouble>
<showDisplay>0</showDisplay>
<stepDouble>0.05</stepDouble>
<valDouble>0</valDouble>
<vTxDoubleScale>100000</vTxDoubleScale>
<suffix></suffix>
<vTx>9</vTx>
</floatCurrentK2>
</Params> </Params>
<SerOrder> <SerOrder>
<ser>noOfCellsSeries</ser> <ser>noOfCellsSeries</ser>
@@ -2582,5 +2762,18 @@ p, li { white-space: pre-wrap; }
<ser>chargeEnableState</ser> <ser>chargeEnableState</ser>
<ser>powerDownDelay</ser> <ser>powerDownDelay</ser>
<ser>humidityICType</ser> <ser>humidityICType</ser>
<ser>chargeBatteryOutputChecked</ser>
<ser>brushOrShuntOutputChecked</ser>
<ser>brushOrShuntMode</ser>
<ser>brushUsageSocThreshold</ser>
<ser>shuntChargingContactorDelay</ser>
<ser>coolingOutputChecked</ser>
<ser>coolingStartThreshold</ser>
<ser>coolingStopThreshold</ser>
<ser>heatingOutputChecked</ser>
<ser>heatingStartThreshold</ser>
<ser>heatingStopThreshold</ser>
<ser>floatCurrentK1</ser>
<ser>floatCurrentK2</ser>
</SerOrder> </SerOrder>
</ConfigParams> </ConfigParams>

BIN
translations/cubo_en.qm Normal file

Binary file not shown.

1415
translations/cubo_en.ts Normal file

File diff suppressed because it is too large Load Diff

BIN
translations/cubo_it.qm Normal file

Binary file not shown.

1415
translations/cubo_it.ts Normal file

File diff suppressed because it is too large Load Diff

BIN
translations/cubo_ru.qm Normal file

Binary file not shown.

1486
translations/cubo_ru.ts Normal file

File diff suppressed because it is too large Load Diff

BIN
translations/qt_en.qm Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More