From 6e78c5bd1cc8f8fb643b3b7adb816b88998cb571 Mon Sep 17 00:00:00 2001 From: Bernhard Kirchen Date: Fri, 15 Dec 2023 10:59:07 +0100 Subject: [PATCH] Feature: JK BMS: export (more) data to live view and MQTT (#549) * add more values to web app live view. this should add all interesting values for the web app live view. those include important values and values that change frequently. * add more interesting JK BMS dummy messages: one has 0% SoC and an alarm (discharge undervoltage) set. the other has the undertemperature alarm set. * add alarms and warnings to live view * publish alarm and status bits through MQTT individually * publish cell voltages to MQTT broker * remove trailing spaces in BatteryStats class --- include/BatteryStats.h | 20 +++++- include/JkBmsDataPoints.h | 48 +++++++++++++ src/BatteryStats.cpp | 138 ++++++++++++++++++++++++++++++++++--- src/JkBmsController.cpp | 78 +++++++++++++++++++++ webapp/src/locales/de.json | 18 +++++ webapp/src/locales/en.json | 18 +++++ webapp/src/locales/fr.json | 27 +++++++- 7 files changed, 333 insertions(+), 14 deletions(-) diff --git a/include/BatteryStats.h b/include/BatteryStats.h index bef2e7d67..1ba3b7f79 100644 --- a/include/BatteryStats.h +++ b/include/BatteryStats.h @@ -89,15 +89,29 @@ class PylontechBatteryStats : public BatteryStats { class JkBmsBatteryStats : public BatteryStats { public: - void getLiveViewData(JsonVariant& root) const final; + void getLiveViewData(JsonVariant& root) const final { + getJsonData(root, false); + } + + void getInfoViewData(JsonVariant& root) const { + getJsonData(root, true); + } + void mqttPublish() const final; void updateFrom(JkBms::DataPointContainer const& dp); private: + void getJsonData(JsonVariant& root, bool verbose) const; + JkBms::DataPointContainer _dataPoints; mutable uint32_t _lastMqttPublish = 0; mutable uint32_t _lastFullMqttPublish = 0; + + uint16_t _cellMinMilliVolt = 0; + uint16_t _cellAvgMilliVolt = 0; + uint16_t _cellMaxMilliVolt = 0; + uint32_t _cellVoltageTimestamp = 0; }; class VictronSmartShuntStats : public BatteryStats { @@ -107,8 +121,8 @@ class VictronSmartShuntStats : public BatteryStats { void updateFrom(VeDirectShuntController::veShuntStruct const& shuntData); - private: - float _voltage; + private: + float _voltage; float _current; float _temperature; bool _tempPresent; diff --git a/include/JkBmsDataPoints.h b/include/JkBmsDataPoints.h index bf3a0f9bd..ccd136b75 100644 --- a/include/JkBmsDataPoints.h +++ b/include/JkBmsDataPoints.h @@ -9,6 +9,54 @@ namespace JkBms { +#define ALARM_BITS(fnc) \ + fnc(LowCapacity, (1<<0)) \ + fnc(BmsOvertemperature, (1<<1)) \ + fnc(ChargingOvervoltage, (1<<2)) \ + fnc(DischargeUndervoltage, (1<<3)) \ + fnc(BatteryOvertemperature, (1<<4)) \ + fnc(ChargingOvercurrent, (1<<5)) \ + fnc(DischargeOvercurrent, (1<<6)) \ + fnc(CellVoltageDifference, (1<<7)) \ + fnc(BatteryBoxOvertemperature, (1<<8)) \ + fnc(BatteryUndertemperature, (1<<9)) \ + fnc(CellOvervoltage, (1<<10)) \ + fnc(CellUndervoltage, (1<<11)) \ + fnc(AProtect, (1<<12)) \ + fnc(BProtect, (1<<13)) \ + fnc(Reserved1, (1<<14)) \ + fnc(Reserved2, (1<<15)) + +enum class AlarmBits : uint16_t { +#define ALARM_ENUM(name, value) name = value, + ALARM_BITS(ALARM_ENUM) +#undef ALARM_ENUM +}; + +static const std::map AlarmBitTexts = { +#define ALARM_TEXT(name, value) { AlarmBits::name, #name }, + ALARM_BITS(ALARM_TEXT) +#undef ALARM_TEXT +}; + +#define STATUS_BITS(fnc) \ + fnc(ChargingActive, (1<<0)) \ + fnc(DischargingActive, (1<<1)) \ + fnc(BalancingActive, (1<<2)) \ + fnc(BatteryOnline, (1<<3)) + +enum class StatusBits : uint16_t { +#define STATUS_ENUM(name, value) name = value, + STATUS_BITS(STATUS_ENUM) +#undef STATUS_ENUM +}; + +static const std::map StatusBitTexts = { +#define STATUS_TEXT(name, value) { StatusBits::name, #name }, + STATUS_BITS(STATUS_TEXT) +#undef STATUS_TEXT +}; + enum class DataPointLabel : uint8_t { CellsMilliVolt = 0x79, BmsTempCelsius = 0x80, diff --git a/src/BatteryStats.cpp b/src/BatteryStats.cpp index 912deeab3..4024bf2c7 100644 --- a/src/BatteryStats.cpp +++ b/src/BatteryStats.cpp @@ -84,7 +84,7 @@ void PylontechBatteryStats::getLiveViewData(JsonVariant& root) const addLiveViewAlarm(root, "bmsInternal", _alarmBmsInternal); } -void JkBmsBatteryStats::getLiveViewData(JsonVariant& root) const +void JkBmsBatteryStats::getJsonData(JsonVariant& root, bool verbose) const { BatteryStats::getLiveViewData(root); @@ -102,9 +102,80 @@ void JkBmsBatteryStats::getLiveViewData(JsonVariant& root) const static_cast(*oCurrent) / 1000, "A", 2); } - auto oTemperature = _dataPoints.get(); - if (oTemperature.has_value()) { - addLiveViewValue(root, "temperature", *oTemperature, "°C", 0); + if (oVoltage.has_value() && oCurrent.has_value()) { + auto current = static_cast(*oCurrent) / 1000; + auto voltage = static_cast(*oVoltage) / 1000; + addLiveViewValue(root, "power", current * voltage , "W", 2); + } + + if (verbose) { + auto oTemperatureOne = _dataPoints.get(); + if (oTemperatureOne.has_value()) { + addLiveViewValue(root, "batOneTemp", *oTemperatureOne, "°C", 0); + } + } + + if (verbose) { + auto oTemperatureTwo = _dataPoints.get(); + if (oTemperatureTwo.has_value()) { + addLiveViewValue(root, "batTwoTemp", *oTemperatureTwo, "°C", 0); + } + } + + auto oTemperatureBms = _dataPoints.get(); + if (oTemperatureBms.has_value()) { + addLiveViewValue(root, "bmsTemp", *oTemperatureBms, "°C", 0); + } + + if (_cellVoltageTimestamp > 0) { + if (verbose) { + addLiveViewValue(root, "cellMinVoltage", static_cast(_cellMinMilliVolt)/1000, "V", 3); + } + + addLiveViewValue(root, "cellAvgVoltage", static_cast(_cellAvgMilliVolt)/1000, "V", 3); + + if (verbose) { + addLiveViewValue(root, "cellMaxVoltage", static_cast(_cellMaxMilliVolt)/1000, "V", 3); + addLiveViewValue(root, "cellDiffVoltage", (_cellMaxMilliVolt - _cellMinMilliVolt), "mV", 0); + } + } + + // labels BatteryChargeEnabled, BatteryDischargeEnabled, and + // BalancingEnabled refer to the user setting. we want to show the + // actual MOSFETs' state which control whether charging and discharging + // is possible and whether the BMS is currently balancing cells. + auto oStatus = _dataPoints.get(); + if (oStatus.has_value()) { + using Bits = JkBms::StatusBits; + auto chargeEnabled = *oStatus & static_cast(Bits::ChargingActive); + addLiveViewText(root, "chargeEnabled", (chargeEnabled?"yes":"no")); + auto dischargeEnabled = *oStatus & static_cast(Bits::DischargingActive); + addLiveViewText(root, "dischargeEnabled", (dischargeEnabled?"yes":"no")); + auto balancingActive = *oStatus & static_cast(Bits::BalancingActive); + addLiveViewText(root, "balancingActive", (balancingActive?"yes":"no")); + } + + auto oAlarms = _dataPoints.get(); + if (oAlarms.has_value()) { +#define ISSUE(t, x) \ + auto x = *oAlarms & static_cast(JkBms::AlarmBits::x); \ + addLiveView##t(root, "JkBmsIssue"#x, x > 0); + + ISSUE(Warning, LowCapacity); + ISSUE(Alarm, BmsOvertemperature); + ISSUE(Alarm, ChargingOvervoltage); + ISSUE(Alarm, DischargeUndervoltage); + ISSUE(Alarm, BatteryOvertemperature); + ISSUE(Alarm, ChargingOvercurrent); + ISSUE(Alarm, DischargeOvercurrent); + ISSUE(Alarm, CellVoltageDifference); + ISSUE(Alarm, BatteryBoxOvertemperature); + ISSUE(Alarm, BatteryUndertemperature); + ISSUE(Alarm, CellOvervoltage); + ISSUE(Alarm, CellUndervoltage); + ISSUE(Alarm, AProtect); + ISSUE(Alarm, BProtect); +#undef ISSUE } } @@ -174,6 +245,43 @@ void JkBmsBatteryStats::mqttPublish() const MqttSettings.publish(topic, iter->second.getValueText().c_str()); } + auto oCellVoltages = _dataPoints.get(); + if (oCellVoltages.has_value() && (fullPublish || _cellVoltageTimestamp > _lastMqttPublish)) { + unsigned idx = 1; + for (auto iter = oCellVoltages->cbegin(); iter != oCellVoltages->cend(); ++iter) { + String topic("battery/Cell"); + topic += String(idx); + topic += "MilliVolt"; + + MqttSettings.publish(topic, String(iter->second)); + + ++idx; + } + + MqttSettings.publish("battery/CellMinMilliVolt", String(_cellMinMilliVolt)); + MqttSettings.publish("battery/CellAvgMilliVolt", String(_cellAvgMilliVolt)); + MqttSettings.publish("battery/CellMaxMilliVolt", String(_cellMaxMilliVolt)); + MqttSettings.publish("battery/CellDiffMilliVolt", String(_cellMaxMilliVolt - _cellMinMilliVolt)); + } + + auto oAlarms = _dataPoints.get(); + if (oAlarms.has_value()) { + for (auto iter = JkBms::AlarmBitTexts.begin(); iter != JkBms::AlarmBitTexts.end(); ++iter) { + auto bit = iter->first; + String value = (*oAlarms & static_cast(bit))?"1":"0"; + MqttSettings.publish(String("battery/alarms/") + iter->second.c_str(), value); + } + } + + auto oStatus = _dataPoints.get(); + if (oStatus.has_value()) { + for (auto iter = JkBms::StatusBitTexts.begin(); iter != JkBms::StatusBitTexts.end(); ++iter) { + auto bit = iter->first; + String value = (*oStatus & static_cast(bit))?"1":"0"; + MqttSettings.publish(String("battery/status/") + iter->second.c_str(), value); + } + } + _lastMqttPublish = millis(); if (fullPublish) { _lastFullMqttPublish = _lastMqttPublish; } } @@ -201,6 +309,20 @@ void JkBmsBatteryStats::updateFrom(JkBms::DataPointContainer const& dp) _dataPoints.updateFrom(dp); + auto oCellVoltages = _dataPoints.get(); + if (oCellVoltages.has_value()) { + for (auto iter = oCellVoltages->cbegin(); iter != oCellVoltages->cend(); ++iter) { + if (iter == oCellVoltages->cbegin()) { + _cellMinMilliVolt = _cellAvgMilliVolt = _cellMaxMilliVolt = iter->second; + continue; + } + _cellMinMilliVolt = std::min(_cellMinMilliVolt, iter->second); + _cellAvgMilliVolt = (_cellAvgMilliVolt + iter->second) / 2; + _cellMaxMilliVolt = std::max(_cellMaxMilliVolt, iter->second); + } + _cellVoltageTimestamp = millis(); + } + _lastUpdate = millis(); } @@ -216,7 +338,7 @@ void VictronSmartShuntStats::updateFrom(VeDirectShuntController::veShuntStruct c _manufacturer = "Victron " + _modelName; _temperature = shuntData.T; _tempPresent = shuntData.tempPresent; - + // shuntData.AR is a bitfield, so we need to check each bit individually _alarmLowVoltage = shuntData.AR & 1; _alarmHighVoltage = shuntData.AR & 2; @@ -233,19 +355,19 @@ void VictronSmartShuntStats::getLiveViewData(JsonVariant& root) const { // values go into the "Status" card of the web application addLiveViewValue(root, "voltage", _voltage, "V", 2); - addLiveViewValue(root, "current", _current, "A", 1); + addLiveViewValue(root, "current", _current, "A", 1); addLiveViewValue(root, "chargeCycles", _chargeCycles, "", 0); addLiveViewValue(root, "chargedEnergy", _chargedEnergy, "KWh", 1); addLiveViewValue(root, "dischargedEnergy", _dischargedEnergy, "KWh", 1); if (_tempPresent) { addLiveViewValue(root, "temperature", _temperature, "°C", 0); } - + addLiveViewAlarm(root, "lowVoltage", _alarmLowVoltage); addLiveViewAlarm(root, "highVoltage", _alarmHighVoltage); addLiveViewAlarm(root, "lowSOC", _alarmLowSOC); addLiveViewAlarm(root, "lowTemperature", _alarmLowTemperature); - addLiveViewAlarm(root, "highTemperature", _alarmHighTemperature); + addLiveViewAlarm(root, "highTemperature", _alarmHighTemperature); } void VictronSmartShuntStats::mqttPublish() const { diff --git a/src/JkBmsController.cpp b/src/JkBmsController.cpp index b6062dcf0..7e5ea0ac3 100644 --- a/src/JkBmsController.cpp +++ b/src/JkBmsController.cpp @@ -113,6 +113,84 @@ class DummySerial { 0x31, 0x41, 0x32, 0x34, 0x53, 0x31, 0x35, 0x50, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x4f, 0xc1 + }, + { + 0x4e, 0x57, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x01, 0x79, 0x30, 0x01, 0x0c, 0x13, + 0x02, 0x0c, 0x12, 0x03, 0x0c, 0x0f, 0x04, 0x0c, + 0x15, 0x05, 0x0c, 0x0d, 0x06, 0x0c, 0x13, 0x07, + 0x0c, 0x16, 0x08, 0x0c, 0x13, 0x09, 0x0b, 0xdb, + 0x0a, 0x0b, 0xf6, 0x0b, 0x0c, 0x17, 0x0c, 0x0b, + 0xf5, 0x0d, 0x0c, 0x16, 0x0e, 0x0c, 0x1a, 0x0f, + 0x0c, 0x1b, 0x10, 0x0c, 0x1c, 0x80, 0x00, 0x18, + 0x81, 0x00, 0x18, 0x82, 0x00, 0x18, 0x83, 0x13, + 0x49, 0x84, 0x00, 0x00, 0x85, 0x00, 0x86, 0x02, + 0x87, 0x00, 0x23, 0x89, 0x00, 0x00, 0x20, 0x14, + 0x8a, 0x00, 0x10, 0x8b, 0x00, 0x08, 0x8c, 0x00, + 0x05, 0x8e, 0x16, 0x80, 0x8f, 0x12, 0xc0, 0x90, + 0x0e, 0x10, 0x91, 0x0c, 0xda, 0x92, 0x00, 0x05, + 0x93, 0x0b, 0xb8, 0x94, 0x0c, 0x80, 0x95, 0x00, + 0x05, 0x96, 0x01, 0x2c, 0x97, 0x00, 0x28, 0x98, + 0x01, 0x2c, 0x99, 0x00, 0x28, 0x9a, 0x00, 0x1e, + 0x9b, 0x0b, 0xb8, 0x9c, 0x00, 0x0a, 0x9d, 0x01, + 0x9e, 0x00, 0x64, 0x9f, 0x00, 0x50, 0xa0, 0x00, + 0x64, 0xa1, 0x00, 0x64, 0xa2, 0x00, 0x14, 0xa3, + 0x00, 0x46, 0xa4, 0x00, 0x46, 0xa5, 0x00, 0x00, + 0xa6, 0x00, 0x02, 0xa7, 0xff, 0xec, 0xa8, 0xff, + 0xf6, 0xa9, 0x10, 0xaa, 0x00, 0x00, 0x00, 0xe6, + 0xab, 0x01, 0xac, 0x01, 0xad, 0x04, 0x4d, 0xae, + 0x01, 0xaf, 0x00, 0xb0, 0x00, 0x0a, 0xb1, 0x14, + 0xb2, 0x32, 0x32, 0x31, 0x31, 0x38, 0x37, 0x00, + 0x00, 0x00, 0x00, 0xb3, 0x00, 0xb4, 0x62, 0x65, + 0x6b, 0x69, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x32, + 0x33, 0x30, 0x36, 0xb6, 0x00, 0x02, 0x17, 0x10, + 0xb7, 0x31, 0x31, 0x2e, 0x58, 0x57, 0x5f, 0x53, + 0x31, 0x31, 0x2e, 0x32, 0x36, 0x32, 0x48, 0x5f, + 0xb8, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xe6, 0xba, + 0x62, 0x65, 0x6b, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4a, 0x4b, 0x5f, 0x42, + 0x31, 0x41, 0x32, 0x34, 0x53, 0x31, 0x35, 0x50, + 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x00, 0x45, 0xce + }, + { + 0x4e, 0x57, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x01, 0x79, 0x30, 0x01, 0x0c, 0x07, + 0x02, 0x0c, 0x0a, 0x03, 0x0c, 0x0b, 0x04, 0x0c, + 0x08, 0x05, 0x0c, 0x05, 0x06, 0x0c, 0x0b, 0x07, + 0x0c, 0x07, 0x08, 0x0c, 0x0a, 0x09, 0x0c, 0x08, + 0x0a, 0x0c, 0x06, 0x0b, 0x0c, 0x0a, 0x0c, 0x0c, + 0x05, 0x0d, 0x0c, 0x0a, 0x0e, 0x0c, 0x0a, 0x0f, + 0x0c, 0x0a, 0x10, 0x0c, 0x0a, 0x80, 0x00, 0x06, + 0x81, 0x00, 0x03, 0x82, 0x00, 0x03, 0x83, 0x13, + 0x40, 0x84, 0x00, 0x00, 0x85, 0x29, 0x86, 0x02, + 0x87, 0x00, 0x01, 0x89, 0x00, 0x00, 0x01, 0x0a, + 0x8a, 0x00, 0x10, 0x8b, 0x02, 0x00, 0x8c, 0x00, + 0x02, 0x8e, 0x16, 0x80, 0x8f, 0x10, 0x40, 0x90, + 0x0e, 0x10, 0x91, 0x0d, 0xde, 0x92, 0x00, 0x05, + 0x93, 0x0a, 0x28, 0x94, 0x0a, 0x5a, 0x95, 0x00, + 0x05, 0x96, 0x01, 0x2c, 0x97, 0x00, 0x28, 0x98, + 0x01, 0x2c, 0x99, 0x00, 0x28, 0x9a, 0x00, 0x1e, + 0x9b, 0x0b, 0xb8, 0x9c, 0x00, 0x0a, 0x9d, 0x01, + 0x9e, 0x00, 0x5a, 0x9f, 0x00, 0x50, 0xa0, 0x00, + 0x64, 0xa1, 0x00, 0x64, 0xa2, 0x00, 0x14, 0xa3, + 0x00, 0x37, 0xa4, 0x00, 0x37, 0xa5, 0x00, 0x03, + 0xa6, 0x00, 0x05, 0xa7, 0xff, 0xec, 0xa8, 0xff, + 0xf6, 0xa9, 0x10, 0xaa, 0x00, 0x00, 0x00, 0xe6, + 0xab, 0x01, 0xac, 0x01, 0xad, 0x04, 0x4d, 0xae, + 0x01, 0xaf, 0x00, 0xb0, 0x00, 0x0a, 0xb1, 0x14, + 0xb2, 0x32, 0x32, 0x31, 0x31, 0x38, 0x37, 0x00, + 0x00, 0x00, 0x00, 0xb3, 0x00, 0xb4, 0x62, 0x65, + 0x6b, 0x69, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x32, + 0x33, 0x30, 0x36, 0xb6, 0x00, 0x03, 0xb7, 0x2d, + 0xb7, 0x31, 0x31, 0x2e, 0x58, 0x57, 0x5f, 0x53, + 0x31, 0x31, 0x2e, 0x32, 0x36, 0x32, 0x48, 0x5f, + 0xb8, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xe6, 0xba, + 0x62, 0x65, 0x6b, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4a, 0x4b, 0x5f, 0x42, + 0x31, 0x41, 0x32, 0x34, 0x53, 0x31, 0x35, 0x50, + 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x00, 0x41, 0x7b } }; size_t _msg_idx = 0; diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 311f8dac5..843e044c9 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -804,19 +804,37 @@ "stateOfHealth": "Batteriezustand (SoH)", "voltage": "Spannung", "current": "Strom", + "power": "Leistung", "temperature": "Temperatur", + "bmsTemp": "BMS-Temperatur", "chargeVoltage": "Gewünschte Ladespannung (BMS)", "chargeCurrentLimitation": "Ladestromlimit", "dischargeCurrentLimitation": "Entladestromlimit", "chargeEnabled": "Laden ermöglicht", "dischargeEnabled": "Entladen ermöglicht", + "balancingActive": "Ausgleichen aktiv", "chargeImmediately": "Sofortiges Laden angefordert", + "cellAvgVoltage": "Durchschnittliche Zellspannung", "issues": "Meldungen", "noIssues": "Keine Meldungen", "issueName": "Bezeichnung", "issueType": "Art", "alarm": "Alarm", "warning": "Warnung", + "JkBmsIssueLowCapacity": "Niedrige Kapazität", + "JkBmsIssueBmsOvertemperature": "BMS Übertemperatur", + "JkBmsIssueChargingOvervoltage": "Überspannung (Akkupack)", + "JkBmsIssueDischargeUndervoltage": "Unterspannung (Akkupack)", + "JkBmsIssueBatteryOvertemperature": "Batterie Übertemperatur", + "JkBmsIssueChargingOvercurrent": "Überstrom (Laden)", + "JkBmsIssueDischargeOvercurrent": "Überstrom (Entladen)", + "JkBmsIssueCellVoltageDifference": "Zellspannungsdifferenz zu hoch", + "JkBmsIssueBatteryBoxOvertemperature": "Batterie (Box?) Übertemperatur", + "JkBmsIssueBatteryUndertemperature": "Batterie Untertemperatur", + "JkBmsIssueCellOvervoltage": "Überspannung (einzelne Zelle)", + "JkBmsIssueCellUndervoltage": "Unterspannung (einzelne Zelle)", + "JkBmsIssueAProtect": "AProtect (Bedeutung?)", + "JkBmsIssueBProtect": "BProtect (Bedeutung?)", "highCurrentDischarge": "Hoher Entladestrom", "overCurrentDischarge": "Überstrom (Entladen)", "highCurrentCharge": "Hoher Ladestrom", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index b71498e28..8aca39178 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -814,19 +814,37 @@ "stateOfHealth": "State of Health", "voltage": "Voltage", "current": "Current", + "power": "Power", "temperature": "Temperature", + "bmsTemp": "BMS temperature", "chargeVoltage": "Requested charge voltage", "chargeCurrentLimitation": "Charge current limit", "dischargeCurrentLimitation": "Discharge current limit", "chargeEnabled": "Charging possible", "dischargeEnabled": "Discharging possible", + "balancingActive": "Balancing active", "chargeImmediately": "Immediate charging requested", + "cellAvgVoltage": "Average cell voltage", "issues": "Issues", "noIssues": "No Issues", "issueName": "Name", "issueType": "Type", "alarm": "Alarm", "warning": "Warning", + "JkBmsIssueLowCapacity": "Low Capacity", + "JkBmsIssueBmsOvertemperature": "BMS overtemperature", + "JkBmsIssueChargingOvervoltage": "Overvoltage (sum of all cells)", + "JkBmsIssueDischargeUndervoltage": "Undervoltage (sum of all cells)", + "JkBmsIssueBatteryOvertemperature": "Battery overtemperature", + "JkBmsIssueChargingOvercurrent": "Overcurrent (Charging)", + "JkBmsIssueDischargeOvercurrent": "Overcurrent (Discharging)", + "JkBmsIssueCellVoltageDifference": "Cell voltage difference too high", + "JkBmsIssueBatteryBoxOvertemperature": "Battery (box?) overtemperature", + "JkBmsIssueBatteryUndertemperature": "Battery undertemperature", + "JkBmsIssueCellOvervoltage": "Overvoltage (single cell)", + "JkBmsIssueCellUndervoltage": "Undervoltage (single cell)", + "JkBmsIssueAProtect": "AProtect (meaning?)", + "JkBmsIssueBProtect": "BProtect (meaning?)", "highCurrentDischarge": "High current (discharge)", "overCurrentDischarge": "Overcurrent (discharge)", "highCurrentCharge": "High current (charge)", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index d8a493c16..6bebdc926 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -757,7 +757,7 @@ "Save": "@:dtuadmin.Save" }, "battery": { - "battery": "battery", + "battery": "Battery", "DataAge": "Data Age: ", "Seconds": " {val} seconds", "Status": "Status", @@ -766,20 +766,41 @@ "no": "@:base.No", "Value": "Value", "Unit": "Unit", - "SoC": "State of charge", - "stateOfHealth": "State of health", + "SoC": "State of Charge", + "stateOfHealth": "State of Health", "voltage": "Voltage", "current": "Current", + "power": "Power", "temperature": "Temperature", + "bmsTemp": "BMS temperature", "chargeVoltage": "Requested charge voltage", "chargeCurrentLimitation": "Charge current limit", "dischargeCurrentLimitation": "Discharge current limit", + "chargeEnabled": "Charging possible", + "dischargeEnabled": "Discharging possible", + "balancingActive": "Balancing active", + "chargeImmediately": "Immediate charging requested", + "cellAvgVoltage": "Average cell voltage", "issues": "Issues", "noIssues": "No Issues", "issueName": "Name", "issueType": "Type", "alarm": "Alarm", "warning": "Warning", + "JkBmsIssueLowCapacity": "Low Capacity", + "JkBmsIssueBmsOvertemperature": "BMS overtemperature", + "JkBmsIssueChargingOvervoltage": "Overvoltage (sum of all cells)", + "JkBmsIssueDischargeUndervoltage": "Undervoltage (sum of all cells)", + "JkBmsIssueBatteryOvertemperature": "Battery overtemperature", + "JkBmsIssueChargingOvercurrent": "Overcurrent (Charging)", + "JkBmsIssueDischargeOvercurrent": "Overcurrent (Discharging)", + "JkBmsIssueCellVoltageDifference": "Cell voltage difference too high", + "JkBmsIssueBatteryBoxOvertemperature": "Battery (box?) overtemperature", + "JkBmsIssueBatteryUndertemperature": "Battery undertemperature", + "JkBmsIssueCellOvervoltage": "Overvoltage (single cell)", + "JkBmsIssueCellUndervoltage": "Undervoltage (single cell)", + "JkBmsIssueAProtect": "AProtect (meaning?)", + "JkBmsIssueBProtect": "BProtect (meaning?)", "highCurrentDischarge": "High current (discharge)", "overCurrentDischarge": "Overcurrent (discharge)", "highCurrentCharge": "High current (charge)",