Feature: know and use SoC precision
the Victron SmartShunt communicates the SoC value in permille. this should be displayed in the web UI accordingly. this is a good excuse to fully move ownership of the SoC value to the BatteryStats base class and add a precision indicator variable. this is required to be set each time a derived class (a battery provider) wants to update the SoC value. the precision is then used when populating the JSON data for the web UI (live view). related to #573.
This commit is contained in:
parent
7c069b1cc4
commit
6df358242c
@ -17,7 +17,7 @@ class BatteryStats {
|
||||
uint32_t getAgeSeconds() const { return (millis() - _lastUpdate) / 1000; }
|
||||
bool updateAvailable(uint32_t since) const { return _lastUpdate > since; }
|
||||
|
||||
uint8_t getSoC() const { return _SoC; }
|
||||
uint8_t getSoC() const { return _soc; }
|
||||
uint32_t getSoCAgeSeconds() const { return (millis() - _lastUpdateSoC) / 1000; }
|
||||
|
||||
float getVoltage() const { return _voltage; }
|
||||
@ -36,18 +36,26 @@ class BatteryStats {
|
||||
|
||||
protected:
|
||||
virtual void mqttPublish() const;
|
||||
|
||||
void setSoC(float soc, uint8_t precision, uint32_t timestamp) {
|
||||
_soc = soc;
|
||||
_socPrecision = precision;
|
||||
_lastUpdateSoC = timestamp;
|
||||
}
|
||||
|
||||
void setVoltage(float voltage, uint32_t timestamp) {
|
||||
_voltage = voltage;
|
||||
_lastUpdateVoltage = timestamp;
|
||||
}
|
||||
|
||||
String _manufacturer = "unknown";
|
||||
uint8_t _SoC = 0;
|
||||
uint32_t _lastUpdateSoC = 0;
|
||||
uint32_t _lastUpdate = 0;
|
||||
|
||||
private:
|
||||
uint32_t _lastMqttPublish = 0;
|
||||
float _soc = 0;
|
||||
uint8_t _socPrecision = 0; // decimal places
|
||||
uint32_t _lastUpdateSoC = 0;
|
||||
float _voltage = 0; // total battery pack voltage
|
||||
uint32_t _lastUpdateVoltage = 0;
|
||||
};
|
||||
@ -61,7 +69,6 @@ class PylontechBatteryStats : public BatteryStats {
|
||||
|
||||
private:
|
||||
void setManufacturer(String&& m) { _manufacturer = std::move(m); }
|
||||
void setSoC(uint8_t SoC) { _SoC = SoC; _lastUpdateSoC = millis(); }
|
||||
void setLastUpdate(uint32_t ts) { _lastUpdate = ts; }
|
||||
|
||||
float _chargeVoltage;
|
||||
@ -155,9 +162,7 @@ class MqttBatteryStats : public BatteryStats {
|
||||
// we do NOT publish the same data under a different topic.
|
||||
void mqttPublish() const final { }
|
||||
|
||||
// the SoC is the only interesting value in this case, which is already
|
||||
// displayed at the top of the live view. do not generate a card.
|
||||
// if the voltage is subscribed to at all, it alone does not warrant a
|
||||
// card in the live view, since the SoC is already displayed at the top
|
||||
void getLiveViewData(JsonVariant& root) const final { }
|
||||
|
||||
void setSoC(uint8_t SoC) { _SoC = SoC; _lastUpdateSoC = _lastUpdate = millis(); }
|
||||
};
|
||||
|
||||
@ -56,7 +56,7 @@ void BatteryStats::getLiveViewData(JsonVariant& root) const
|
||||
root[F("manufacturer")] = _manufacturer;
|
||||
root[F("data_age")] = getAgeSeconds();
|
||||
|
||||
addLiveViewValue(root, "SoC", _SoC, "%", 0);
|
||||
addLiveViewValue(root, "SoC", _soc, "%", _socPrecision);
|
||||
addLiveViewValue(root, "voltage", _voltage, "V", 2);
|
||||
}
|
||||
|
||||
@ -212,7 +212,7 @@ void BatteryStats::mqttPublish() const
|
||||
{
|
||||
MqttSettings.publish(F("battery/manufacturer"), _manufacturer);
|
||||
MqttSettings.publish(F("battery/dataAge"), String(getAgeSeconds()));
|
||||
MqttSettings.publish(F("battery/stateOfCharge"), String(_SoC));
|
||||
MqttSettings.publish(F("battery/stateOfCharge"), String(_soc));
|
||||
MqttSettings.publish(F("battery/voltage"), String(_voltage));
|
||||
}
|
||||
|
||||
@ -334,9 +334,9 @@ void JkBmsBatteryStats::updateFrom(JkBms::DataPointContainer const& dp)
|
||||
|
||||
auto oSoCValue = dp.get<Label::BatterySoCPercent>();
|
||||
if (oSoCValue.has_value()) {
|
||||
_SoC = *oSoCValue;
|
||||
auto oSoCDataPoint = dp.getDataPointFor<Label::BatterySoCPercent>();
|
||||
_lastUpdateSoC = oSoCDataPoint->getTimestamp();
|
||||
BatteryStats::setSoC(*oSoCValue, 0/*precision*/,
|
||||
oSoCDataPoint->getTimestamp());
|
||||
}
|
||||
|
||||
auto oVoltage = dp.get<Label::BatteryVoltageMilliVolt>();
|
||||
@ -367,8 +367,8 @@ void JkBmsBatteryStats::updateFrom(JkBms::DataPointContainer const& dp)
|
||||
|
||||
void VictronSmartShuntStats::updateFrom(VeDirectShuntController::veShuntStruct const& shuntData) {
|
||||
BatteryStats::setVoltage(shuntData.V, millis());
|
||||
BatteryStats::setSoC(static_cast<float>(shuntData.SOC) / 10, 1/*precision*/, millis());
|
||||
|
||||
_SoC = shuntData.SOC / 10;
|
||||
_current = shuntData.I;
|
||||
_modelName = shuntData.getPidAsString().data();
|
||||
_chargeCycles = shuntData.H4;
|
||||
@ -387,7 +387,6 @@ void VictronSmartShuntStats::updateFrom(VeDirectShuntController::veShuntStruct c
|
||||
_alarmHighTemperature = shuntData.AR & 64;
|
||||
|
||||
_lastUpdate = VeDirectShunt.getLastUpdate();
|
||||
_lastUpdateSoC = VeDirectShunt.getLastUpdate();
|
||||
}
|
||||
|
||||
void VictronSmartShuntStats::getLiveViewData(JsonVariant& root) const {
|
||||
|
||||
@ -82,7 +82,7 @@ void MqttBattery::onMqttMessageSoC(espMqttClientTypes::MessageProperties const&
|
||||
return;
|
||||
}
|
||||
|
||||
_stats->setSoC(static_cast<uint8_t>(*soc));
|
||||
_stats->setSoC(*soc, 0/*precision*/, millis());
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("MqttBattery: Updated SoC to %d from '%s'\r\n",
|
||||
|
||||
@ -136,7 +136,7 @@ void PylontechCanReceiver::loop()
|
||||
}
|
||||
|
||||
case 0x355: {
|
||||
_stats->setSoC(static_cast<uint8_t>(this->readUnsignedInt16(rx_message.data)));
|
||||
_stats->setSoC(static_cast<uint8_t>(this->readUnsignedInt16(rx_message.data)), 0/*precision*/, millis());
|
||||
_stats->_stateOfHealth = this->readUnsignedInt16(rx_message.data + 2);
|
||||
|
||||
if (_verboseLogging) {
|
||||
@ -282,7 +282,7 @@ void PylontechCanReceiver::dummyData()
|
||||
};
|
||||
|
||||
_stats->setManufacturer("Pylontech US3000C");
|
||||
_stats->setSoC(42);
|
||||
_stats->setSoC(42, 0/*precision*/, millis());
|
||||
_stats->_chargeVoltage = dummyFloat(50);
|
||||
_stats->_chargeCurrentLimitation = dummyFloat(33);
|
||||
_stats->_dischargeCurrentLimitation = dummyFloat(12);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user