Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ struct BATTERY_CONFIG_T {
float DischargeCurrentLimitBelowSoc;
float DischargeCurrentLimitBelowVoltage;
bool UseBatteryReportedDischargeCurrentLimit;
float NominalVoltage;
uint16_t NominalCapacity;
};
using BatteryConfig = struct BATTERY_CONFIG_T;

Expand Down
14 changes: 14 additions & 0 deletions include/battery/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class Stats {
float getChargeCurrentLimit() const { return _chargeCurrentLimit; };
uint32_t getChargeCurrentLimitAgeSeconds() const { return (millis() - _lastUpdateChargeCurrentLimit) / 1000; }

std::optional<uint16_t> getNominalCapacity() const;
std::optional<float> getNominalVoltage() const;

std::optional<float> getTemperature() const {
if (_lastUpdateTemperature > 0) {
return _temperature;
Expand Down Expand Up @@ -96,6 +99,14 @@ class Stats {
_lastUpdateChargeCurrentLimit = _lastUpdate = timestamp;
}

void setNominalCapacity(uint16_t nominalCapacity) {
_nominalCapacity = nominalCapacity;
}

void setNominalVoltage(float nominalVoltage) {
_nominalVoltage = nominalVoltage;
}

void setTemperature(float temperature, uint32_t timestamp) {
_temperature = temperature;
_lastUpdateTemperature = _lastUpdate = timestamp;
Expand Down Expand Up @@ -207,6 +218,9 @@ class Stats {

float _temperature = 0;
uint32_t _lastUpdateTemperature = 0;

uint16_t _nominalCapacity = 0; // the nominal capacity of the battery [Ah]
float _nominalVoltage = 0; // the nominal voltage of the battery [V]
};

} // namespace Batteries
1 change: 0 additions & 1 deletion include/battery/pytes/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ friend class Provider;
uint8_t _moduleCountBlockingCharge;
uint8_t _moduleCountBlockingDischarge;

float _totalCapacity;
float _availableCapacity;
uint8_t _capacityPrecision = 0; // decimal places

Expand Down
18 changes: 11 additions & 7 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,15 @@ void ConfigurationClass::serializePowerMeterUdpVictronConfig(PowerMeterUdpVictro

void ConfigurationClass::serializeBatteryConfig(BatteryConfig const& source, JsonObject& target)
{
target["enabled"] = config.Battery.Enabled;
target["provider"] = config.Battery.Provider;
target["enable_discharge_current_limit"] = config.Battery.EnableDischargeCurrentLimit;
target["discharge_current_limit"] = config.Battery.DischargeCurrentLimit;
target["discharge_current_limit_below_soc"] = config.Battery.DischargeCurrentLimitBelowSoc;
target["discharge_current_limit_below_voltage"] = config.Battery.DischargeCurrentLimitBelowVoltage;
target["use_battery_reported_discharge_current_limit"] = config.Battery.UseBatteryReportedDischargeCurrentLimit;
target["enabled"] = source.Enabled;
target["provider"] = source.Provider;
target["enable_discharge_current_limit"] = source.EnableDischargeCurrentLimit;
target["discharge_current_limit"] = source.DischargeCurrentLimit;
target["discharge_current_limit_below_soc"] = source.DischargeCurrentLimitBelowSoc;
target["discharge_current_limit_below_voltage"] = source.DischargeCurrentLimitBelowVoltage;
target["use_battery_reported_discharge_current_limit"] = source.UseBatteryReportedDischargeCurrentLimit;
target["nominal_voltage"] = source.NominalVoltage;
target["nominal_capacity"] = source.NominalCapacity;
}

void ConfigurationClass::serializeBatteryZendureConfig(BatteryZendureConfig const& source, JsonObject& target)
Expand Down Expand Up @@ -572,6 +574,8 @@ void ConfigurationClass::deserializeBatteryConfig(JsonObject const& source, Batt
target.DischargeCurrentLimitBelowSoc = source["discharge_current_limit_below_soc"] | BATTERY_DISCHARGE_CURRENT_LIMIT_BELOW_SOC;
target.DischargeCurrentLimitBelowVoltage = source["discharge_current_limit_below_voltage"] | BATTERY_DISCHARGE_CURRENT_LIMIT_BELOW_VOLTAGE;
target.UseBatteryReportedDischargeCurrentLimit = source["use_battery_reported_discharge_current_limit"] | BATTERY_USE_BATTERY_REPORTED_DISCHARGE_CURRENT_LIMIT;
target.NominalVoltage = source["nominal_voltage"] | 0.0f;
target.NominalCapacity = source["nominal_capacity"] | 0;
Comment thread
SW-Niko marked this conversation as resolved.
}

void ConfigurationClass::deserializeBatteryZendureConfig(JsonObject const& source, BatteryZendureConfig& target)
Expand Down
2 changes: 2 additions & 0 deletions src/battery/HassIntegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ void HassIntegration::publishSensors() const
publishSensor("State of Charge (SoC)", "mdi:battery-medium", "stateOfCharge", "battery", "measurement", "%");
publishSensor("Voltage", "mdi:battery-charging", "voltage", "voltage", "measurement", "V");
publishSensor("Current", "mdi:current-dc", "current", "current", "measurement", "A");
publishSensor("Nominal capacity", NULL, "nominalCapacity", "capacity", "measurement", "Ah");
publishSensor("Nominal voltage", NULL, "nominalVoltage", "voltage", "measurement", "V");
}

void HassIntegration::publishSensor(const char* caption, const char* icon,
Expand Down
46 changes: 46 additions & 0 deletions src/battery/Stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ void Stats::getLiveViewData(JsonVariant& root) const
addLiveViewValue(root, "chargeCurrentLimitation", _chargeCurrentLimit, "A", 1);
}

if (getNominalCapacity().has_value()) {
addLiveViewValue(root, "nominalCapacity", *getNominalCapacity(), "Ah", 0);
}

if (getNominalVoltage().has_value()) {
addLiveViewValue(root, "nominalVoltage", *getNominalVoltage(), "V", 2);
}

root["showIssues"] = supportsAlarmsAndWarnings();
}

Expand Down Expand Up @@ -119,6 +127,44 @@ void Stats::mqttPublish() const
if (isChargeCurrentLimitValid()) {
MqttSettings.publish("battery/settings/chargeCurrentLimitation", String(_chargeCurrentLimit));
}

if (getNominalCapacity().has_value()) {
MqttSettings.publish("battery/nominalCapacity", String(*getNominalCapacity()));
}

if (getNominalVoltage().has_value()) {
MqttSettings.publish("battery/nominalVoltage", String(*getNominalVoltage()));
}
}

/*
* Returns the nominal capacity of the battery, preferring a value reported by the battery itself (if available),
* but falling back to a user-configured value if not. If neither is available, returns std::nullopt.
*/
std::optional<uint16_t> Stats::getNominalCapacity() const {
std::optional<uint16_t> capacity = std::nullopt;

if (_nominalCapacity > 0) {
capacity = _nominalCapacity;
} else if (Configuration.get().Battery.NominalCapacity > 0) {
capacity = Configuration.get().Battery.NominalCapacity;
}
return capacity;
}

/*
* Returns the nominal voltage of the battery, preferring a value reported by the battery itself (if available),
* but falling back to a user-configured value if not. If neither is available, returns std::nullopt.
*/
std::optional<float> Stats::getNominalVoltage() const {
std::optional<float> voltage = std::nullopt;

if (_nominalVoltage > 0) {
voltage = _nominalVoltage;
} else if (Configuration.get().Battery.NominalVoltage > 0) {
voltage = Configuration.get().Battery.NominalVoltage;
}
return voltage;
}

} // namespace Batteries
1 change: 0 additions & 1 deletion src/battery/pytes/HassIntegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ void HassIntegration::publishSensors() const
publishSensor("Charged Energy", NULL, "chargedEnergy", "energy", "total_increasing", "kWh");
publishSensor("Discharged Energy", NULL, "dischargedEnergy", "energy", "total_increasing", "kWh");

publishSensor("Total Capacity", NULL, "capacity");
publishSensor("Available Capacity", NULL, "availableCapacity");

publishSensor("Cell Min Voltage", NULL, "CellMinMilliVolt", "voltage", "measurement", "mV");
Expand Down
12 changes: 7 additions & 5 deletions src/battery/pytes/Provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,10 @@ void Provider::onMessage(twai_message_t rx_message)
}

case 0x379: { // BatterySize: Installed Ah
_stats->_totalCapacity = this->readUnsignedInt16(rx_message.data);
auto capacity = this->readUnsignedInt16(rx_message.data);
_stats->setNominalCapacity(capacity);

DTU_LOGD("totalCapacity: %f Ah", _stats->_totalCapacity);
DTU_LOGD("totalCapacity: %u Ah", capacity);
break;
}

Expand Down Expand Up @@ -402,14 +403,15 @@ void Provider::onMessage(twai_message_t rx_message)
}

case 0x409: { // Pytes protocol: full mAh / remaining mAh
_stats->_totalCapacity = this->scaleValue(this->readUnsignedInt32(rx_message.data), 0.001);
auto capacity = this->scaleValue(this->readUnsignedInt32(rx_message.data), 0.001);
_stats->setNominalCapacity(capacity);
_stats->_availableCapacity = this->scaleValue(this->readUnsignedInt32(rx_message.data + 4), 0.001);
_stats->_capacityPrecision = 2;
float soc = 100.0 * _stats->_availableCapacity / _stats->_totalCapacity;
float soc = 100.0 * _stats->_availableCapacity / capacity;
_stats->setSoC(soc, 2/*precision*/, millis());

DTU_LOGD("soc: %.2f totalCapacity: %.2f Ah availableCapacity: %.2f Ah",
soc, _stats->_totalCapacity, _stats->_availableCapacity);
soc, capacity, _stats->_availableCapacity);
break;
}

Expand Down
2 changes: 0 additions & 2 deletions src/battery/pytes/Stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ void Stats::getLiveViewData(JsonVariant& root) const
addLiveViewValue(root, "temperature", *oTemperature, "°C", 1);
}

addLiveViewValue(root, "capacity", _totalCapacity, "Ah", _capacityPrecision);
addLiveViewValue(root, "availableCapacity", _availableCapacity, "Ah", _capacityPrecision);

if (_chargedEnergy != -1) {
Expand Down Expand Up @@ -113,7 +112,6 @@ void Stats::mqttPublish() const
MqttSettings.publish("battery/dischargedEnergy", String(_dischargedEnergy));
}

MqttSettings.publish("battery/capacity", String(_totalCapacity));
MqttSettings.publish("battery/availableCapacity", String(_availableCapacity));

MqttSettings.publish("battery/CellMinMilliVolt", String(_cellMinMilliVolt));
Expand Down
8 changes: 7 additions & 1 deletion webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,11 @@
"JbdBmsConfiguration": "JBD BMS Einstellungen",
"PollingInterval": "Abfrageintervall",
"Seconds": "@:base.Seconds",
"BatteryDataConfiguration": "Generelle Daten",
"NominalVoltage": "Nennspannung",
"NominalVoltageInfo": "Die Nennspannung der Batterie. Dieser Wert wird unter anderem dazu verwendet, die Batteriekapazität in Wattstunden (Wh) zu berechnen. Achtung: Nicht mit der Ladeendspannung verwechseln!",
"NominalCapacity": "Nennkapazität",
"NominalCapacityInfo": "Die Nennkapazität der Batterie in Amperestunden (Ah).",
"DischargeCurrentLimitConfiguration": "Einstellungen Entladestromlimit",
"LimitDischargeCurrent": "Entladestrom limitieren",
"DischargeCurrentLimit": "max. Entladestrom",
Expand Down Expand Up @@ -1156,7 +1161,8 @@
"voltage": "Spannung",
"current": "Strom",
"power": "Leistung",
"capacity": "Gesamtkapazität",
"nominalCapacity": "Nennkapazität",
"nominalVoltage": "Nennspannung",
"availableCapacity": "Verfügbare Kapazität",
"temperature": "Temperatur",
"bmsTemp": "BMS-Temperatur",
Expand Down
8 changes: 7 additions & 1 deletion webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,11 @@
"JbdBmsConfiguration": "JBD BMS Settings",
"PollingInterval": "Polling Interval",
"Seconds": "@:base.Seconds",
"BatteryDataConfiguration": "General Data Settings",
"NominalVoltage": "Nominal Voltage",
"NominalVoltageInfo": "The nominal voltage of the battery. This value is used, among other things, to calculate the battery capacity in watt-hours (Wh). Note: Do not confuse with the charge end voltage.",
"NominalCapacity": "Nominal Capacity",
"NominalCapacityInfo": "The nominal capacity of the battery in ampere-hours (Ah).",
"DischargeCurrentLimitConfiguration": "Discharge Current Limit Settings",
"LimitDischargeCurrent": "Limit Discharge Current",
"DischargeCurrentLimit": "max. Discharge Current",
Expand Down Expand Up @@ -1160,7 +1165,8 @@
"voltage": "Voltage",
"current": "Current",
"power": "Power",
"capacity": "Total capacity",
"nominalCapacity": "Nominal capacity",
"nominalVoltage": "Nominal voltage",
"availableCapacity": "Available capacity",
"temperature": "Temperature",
"bmsTemp": "BMS temperature",
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/types/BatteryConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ export interface BatteryConfig {
discharge_current_limit_below_soc: number;
discharge_current_limit_below_voltage: number;
use_battery_reported_discharge_current_limit: boolean;
nominal_voltage: number;
nominal_capacity: number;
}
29 changes: 29 additions & 0 deletions webapp/src/views/BatteryAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,35 @@
</CardElement>
</template>

<template v-if="batteryConfigList.enabled">
<CardElement :text="$t('batteryadmin.BatteryDataConfiguration')" textVariant="text-bg-primary" addSpace>
<InputElement
:label="$t('batteryadmin.NominalVoltage')"
v-model="batteryConfigList.nominal_voltage"
type="number"
min="0"
max="100"
step="0.1"
postfix="V"
:tooltip="$t('batteryadmin.NominalVoltageInfo')"
wide
/>

<InputElement
v-if="batteryConfigList.provider != 4"
:label="$t('batteryadmin.NominalCapacity')"
v-model="batteryConfigList.nominal_capacity"
type="number"
min="0"
max="500"
step="1"
postfix="Ah"
:tooltip="$t('batteryadmin.NominalCapacityInfo')"
wide
/>
</CardElement>
</template>

<CardElement
:text="$t('batteryadmin.DischargeCurrentLimitConfiguration')"
textVariant="text-bg-primary"
Expand Down