Feature: show BMS FW and HW version (JK BMS, SmartShunt)

This commit is contained in:
Bernhard Kirchen 2024-05-31 21:13:28 +02:00 committed by Bernhard Kirchen
parent 561f4be6d6
commit c22ae2bf8d
8 changed files with 52 additions and 6 deletions

View File

@ -58,6 +58,8 @@ class BatteryStats {
} }
String _manufacturer = "unknown"; String _manufacturer = "unknown";
String _hwversion = "";
String _fwversion = "";
uint32_t _lastUpdate = 0; uint32_t _lastUpdate = 0;
private: private:
@ -157,7 +159,6 @@ class VictronSmartShuntStats : public BatteryStats {
uint32_t _timeToGo; uint32_t _timeToGo;
float _chargedEnergy; float _chargedEnergy;
float _dischargedEnergy; float _dischargedEnergy;
String _modelName;
int32_t _instantaneousPower; int32_t _instantaneousPower;
float _midpointVoltage; float _midpointVoltage;
float _midpointDeviation; float _midpointDeviation;

View File

@ -158,18 +158,25 @@ uint32_t veStruct::getFwVersionAsInteger() const
String veStruct::getFwVersionFormatted() const String veStruct::getFwVersionFormatted() const
{ {
char const* strVersion = firmwareVer_FW; char const* strVersion = firmwareVer_FW;
char rc = 0;
// VE.Direct protocol manual states that the first char can be a non-digit, // VE.Direct protocol manual states that the first char can be a non-digit,
// in which case that char represents a release candidate version // in which case that char represents a release candidate version
if (strVersion[0] < '0' || strVersion[0] > '9') { ++strVersion; } if (strVersion[0] < '0' || strVersion[0] > '9') {
rc = strVersion[0];
++strVersion;
}
// SmartShunt firmware version is transmitted with leading zero(es)
while (strVersion[0] == '0') { ++strVersion; }
String res(strVersion[0]); String res(strVersion[0]);
res += "."; res += ".";
res += strVersion + 1; res += strVersion + 1;
if (strVersion > firmwareVer_FW) { if (rc != 0) {
res += "-rc-"; res += "-rc-";
res += firmwareVer_FW[0]; res += rc;
} }
return res; return res;

View File

@ -62,6 +62,12 @@ bool BatteryStats::updateAvailable(uint32_t since) const
void BatteryStats::getLiveViewData(JsonVariant& root) const void BatteryStats::getLiveViewData(JsonVariant& root) const
{ {
root["manufacturer"] = _manufacturer; root["manufacturer"] = _manufacturer;
if (!_fwversion.isEmpty()) {
root["fwversion"] = _fwversion;
}
if (!_hwversion.isEmpty()) {
root["hwversion"] = _hwversion;
}
root["data_age"] = getAgeSeconds(); root["data_age"] = getAgeSeconds();
addLiveViewValue(root, "SoC", _soc, "%", _socPrecision); addLiveViewValue(root, "SoC", _soc, "%", _socPrecision);
@ -375,20 +381,38 @@ void JkBmsBatteryStats::updateFrom(JkBms::DataPointContainer const& dp)
_cellVoltageTimestamp = millis(); _cellVoltageTimestamp = millis();
} }
auto oVersion = _dataPoints.get<Label::BmsSoftwareVersion>();
if (oVersion.has_value()) {
// raw: "11.XW_S11.262H_"
// => Hardware "V11.XW" (displayed in Android app)
// => Software "V11.262H" (displayed in Android app)
auto first = oVersion->find('_');
if (first != std::string::npos) {
_hwversion = oVersion->substr(0, first).c_str();
auto second = oVersion->find('_', first + 1);
// the 'S' seems to be merely an indicator for "software"?
if (oVersion->at(first + 1) == 'S') { first++; }
_fwversion = oVersion->substr(first + 1, second - first - 1).c_str();
}
}
_lastUpdate = millis(); _lastUpdate = millis();
} }
void VictronSmartShuntStats::updateFrom(VeDirectShuntController::data_t const& shuntData) { void VictronSmartShuntStats::updateFrom(VeDirectShuntController::data_t const& shuntData) {
BatteryStats::setVoltage(shuntData.batteryVoltage_V_mV / 1000.0, millis()); BatteryStats::setVoltage(shuntData.batteryVoltage_V_mV / 1000.0, millis());
BatteryStats::setSoC(static_cast<float>(shuntData.SOC) / 10, 1/*precision*/, millis()); BatteryStats::setSoC(static_cast<float>(shuntData.SOC) / 10, 1/*precision*/, millis());
_fwversion = shuntData.getFwVersionFormatted();
_current = static_cast<float>(shuntData.batteryCurrent_I_mA) / 1000; _current = static_cast<float>(shuntData.batteryCurrent_I_mA) / 1000;
_modelName = shuntData.getPidAsString().data();
_chargeCycles = shuntData.H4; _chargeCycles = shuntData.H4;
_timeToGo = shuntData.TTG / 60; _timeToGo = shuntData.TTG / 60;
_chargedEnergy = static_cast<float>(shuntData.H18) / 100; _chargedEnergy = static_cast<float>(shuntData.H18) / 100;
_dischargedEnergy = static_cast<float>(shuntData.H17) / 100; _dischargedEnergy = static_cast<float>(shuntData.H17) / 100;
_manufacturer = "Victron " + _modelName; _manufacturer = String("Victron ") + shuntData.getPidAsString().data();
_temperature = shuntData.T; _temperature = shuntData.T;
_tempPresent = shuntData.tempPresent; _tempPresent = shuntData.tempPresent;
_midpointVoltage = static_cast<float>(shuntData.VM) / 1000; _midpointVoltage = static_cast<float>(shuntData.VM) / 1000;

View File

@ -18,6 +18,12 @@
<div style="padding-right: 2em;"> <div style="padding-right: 2em;">
{{ $t('battery.battery') }}: {{ batteryData.manufacturer }} {{ $t('battery.battery') }}: {{ batteryData.manufacturer }}
</div> </div>
<div style="padding-right: 2em;" v-if="'fwversion' in batteryData">
{{ $t('battery.FwVersion') }}: {{ batteryData.fwversion }}
</div>
<div style="padding-right: 2em;" v-if="'hwversion' in batteryData">
{{ $t('battery.HwVersion') }}: {{ batteryData.hwversion }}
</div>
<div style="padding-right: 2em;"> <div style="padding-right: 2em;">
{{ $t('battery.DataAge') }} {{ $t('battery.Seconds', { 'val': batteryData.data_age }) }} {{ $t('battery.DataAge') }} {{ $t('battery.Seconds', { 'val': batteryData.data_age }) }}
</div> </div>

View File

@ -874,6 +874,8 @@
}, },
"battery": { "battery": {
"battery": "Batterie", "battery": "Batterie",
"FwVersion": "Firmware-Version",
"HwVersion": "Hardware-Version",
"DataAge": "letzte Aktualisierung: ", "DataAge": "letzte Aktualisierung: ",
"Seconds": "vor {val} Sekunden", "Seconds": "vor {val} Sekunden",
"status": "Status", "status": "Status",

View File

@ -881,6 +881,8 @@
}, },
"battery": { "battery": {
"battery": "Battery", "battery": "Battery",
"FwVersion": "Firmware Version",
"HwVersion": "Hardware Version",
"DataAge": "Data Age: ", "DataAge": "Data Age: ",
"Seconds": " {val} seconds", "Seconds": " {val} seconds",
"status": "Status", "status": "Status",

View File

@ -866,6 +866,8 @@
}, },
"battery": { "battery": {
"battery": "Battery", "battery": "Battery",
"FwVersion": "Firmware Version",
"HwVersion": "Hardware Version",
"DataAge": "Data Age: ", "DataAge": "Data Age: ",
"Seconds": " {val} seconds", "Seconds": " {val} seconds",
"status": "Status", "status": "Status",

View File

@ -4,6 +4,8 @@ type BatteryData = (ValueObject | string)[];
export interface Battery { export interface Battery {
manufacturer: string; manufacturer: string;
fwversion: string;
hwversion: string;
data_age: number; data_age: number;
values: BatteryData[]; values: BatteryData[];
issues: number[]; issues: number[];