Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional "load current" to live view, MQTT and HASS. #1367

Merged
merged 2 commits into from
Nov 3, 2024
Merged
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
10 changes: 8 additions & 2 deletions lib/VeDirectFrameHandler/VeDirectData.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ struct veMpptStruct : veStruct {
uint32_t panelVoltage_VPV_mV; // panel voltage in mV
uint32_t panelCurrent_mA; // panel current in mA (calculated)
int16_t batteryOutputPower_W; // battery output power in W (calculated, can be negative if load output is used)
uint32_t loadCurrent_IL_mA; // Load current in mA (Available only for models with a load output)
bool loadOutputState_LOAD; // virtual load output state (on if battery voltage reaches upper limit, off if battery reaches lower limit)
uint8_t currentState_CS; // current state of operation e.g. OFF or Bulk
uint8_t errorCode_ERR; // error code
uint32_t offReason_OR; // off reason
Expand All @@ -38,6 +36,14 @@ struct veMpptStruct : veStruct {
uint32_t yieldYesterday_H22_Wh; // yield yesterday Wh
uint16_t maxPowerYesterday_H23_W; // maximum power yesterday W

// these are optional values communicated through the TEXT protocol. the pair's first
// value is the timestamp the respective info was last received. if it is
// zero, the value is deemed invalid. the timestamp is reset if no current
// value could be retrieved.
std::pair<uint32_t, bool> loadOutputState_LOAD; // physical load output or virtual load output state (on if battery voltage
// reaches upper limit, off if battery reaches lower limit)
std::pair<uint32_t, uint32_t> loadCurrent_IL_mA; // Load current in mA (Available only for models with a physical load output)

// these are values communicated through the HEX protocol. the pair's first
// value is the timestamp the respective info was last received. if it is
// zero, the value is deemed invalid. the timestamp is reset if no current
Expand Down
20 changes: 13 additions & 7 deletions lib/VeDirectFrameHandler/VeDirectMpptController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ void VeDirectMpptController::init(int8_t rx, int8_t tx, Print* msgOut,
bool VeDirectMpptController::processTextDataDerived(std::string const& name, std::string const& value)
{
if (name == "IL") {
_tmpFrame.loadCurrent_IL_mA = atol(value.c_str());
_tmpFrame.loadCurrent_IL_mA.second = atol(value.c_str());
_tmpFrame.loadCurrent_IL_mA.first = millis();
return true;
}
if (name == "LOAD") {
_tmpFrame.loadOutputState_LOAD = (value == "ON");
_tmpFrame.loadOutputState_LOAD.second = (value == "ON");
_tmpFrame.loadOutputState_LOAD.first = millis();
return true;
}
if (name == "CS") {
Expand Down Expand Up @@ -97,7 +99,8 @@ void VeDirectMpptController::frameValidEvent() {
}

// calculation of the MPPT efficiency
float totalPower_W = (_tmpFrame.loadCurrent_IL_mA / 1000.0f + _tmpFrame.batteryCurrent_I_mA / 1000.0f) * _tmpFrame.batteryVoltage_V_mV /1000.0f;
float loadCurrent = (_tmpFrame.loadCurrent_IL_mA.first > 0) ? _tmpFrame.loadCurrent_IL_mA.second / 1000.0f : 0.0f;
float totalPower_W = (loadCurrent + _tmpFrame.batteryCurrent_I_mA / 1000.0f) * _tmpFrame.batteryVoltage_V_mV / 1000.0f;
if (_tmpFrame.panelPower_PPV_W > 0) {
_efficiency.addNumber(totalPower_W * 100.0f / _tmpFrame.panelPower_PPV_W);
_tmpFrame.mpptEfficiency_Percent = _efficiency.getAverage();
Expand All @@ -117,16 +120,19 @@ void VeDirectMpptController::loop()
// Second we read Text- and HEX-Messages
VeDirectFrameHandler::loop();

// Third we check if HEX-Data is outdated
// Note: Room for improvement, longer data valid time for slow changing values?
if (!isHexCommandPossible()) { return; }

auto resetTimestamp = [this](auto& pair) {
if (pair.first > 0 && (millis() - pair.first) > (10 * 1000)) {
pair.first = 0;
}
};

// Check if optional TEXT-Data is outdated
resetTimestamp(_tmpFrame.loadOutputState_LOAD);
resetTimestamp(_tmpFrame.loadCurrent_IL_mA);

// Third we check if HEX-Data is outdated
if (!isHexCommandPossible()) { return; }
resetTimestamp(_tmpFrame.MpptTemperatureMilliCelsius);
resetTimestamp(_tmpFrame.SmartBatterySenseTemperatureMilliCelsius);
resetTimestamp(_tmpFrame.NetworkTotalDcInputPowerMilliWatts);
Expand Down Expand Up @@ -337,4 +343,4 @@ void VeDirectMpptController::sendNextHexCommandFromQueue(void) {
prio = false; // second loop for low prio commands
}
}
}
}
3 changes: 2 additions & 1 deletion src/MqttHandleVedirect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ void MqttHandleVedirectClass::publish_mppt_data(const VeDirectMpptController::da
PUBLISH(productID_PID, "PID", currentData.getPidAsString().data());
PUBLISH(serialNr_SER, "SER", currentData.serialNr_SER);
PUBLISH(firmwareVer_FW, "FW", currentData.firmwareVer_FW);
PUBLISH(loadOutputState_LOAD, "LOAD", (currentData.loadOutputState_LOAD ? "ON" : "OFF"));
PUBLISH(currentState_CS, "CS", currentData.getCsAsString().data());
PUBLISH(errorCode_ERR, "ERR", currentData.getErrAsString().data());
PUBLISH(offReason_OR, "OR", currentData.getOrAsString().data());
Expand All @@ -136,6 +135,8 @@ void MqttHandleVedirectClass::publish_mppt_data(const VeDirectMpptController::da
MqttSettings.publish(topic + t, String(val)); \
}

PUBLISH_OPT(loadOutputState_LOAD, "LOAD", currentData.loadOutputState_LOAD.second ? "ON" : "OFF");
PUBLISH_OPT(loadCurrent_IL_mA, "IL", currentData.loadCurrent_IL_mA.second / 1000.0);
PUBLISH_OPT(NetworkTotalDcInputPowerMilliWatts, "NetworkTotalDcInputPower", currentData.NetworkTotalDcInputPowerMilliWatts.second / 1000.0);
PUBLISH_OPT(MpptTemperatureMilliCelsius, "MpptTemperature", currentData.MpptTemperatureMilliCelsius.second / 1000.0);
PUBLISH_OPT(BatteryAbsorptionMilliVolt, "BatteryAbsorption", currentData.BatteryAbsorptionMilliVolt.second / 1000.0);
Expand Down
9 changes: 8 additions & 1 deletion src/MqttHandleVedirectHass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ void MqttHandleVedirectHassClass::publishConfig()
auto optMpptData = VictronMppt.getData(idx);
if (!optMpptData.has_value()) { continue; }

publishBinarySensor("MPPT load output state", "mdi:export", "LOAD", "ON", "OFF", *optMpptData);
publishSensor("MPPT serial number", "mdi:counter", "SER", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT firmware number", "mdi:counter", "FW", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT state of operation", "mdi:wrench", "CS", nullptr, nullptr, nullptr, *optMpptData);
Expand All @@ -88,6 +87,14 @@ void MqttHandleVedirectHassClass::publishConfig()
publishSensor("Panel yield yesterday", NULL, "H22", "energy", "total", "kWh", *optMpptData);
publishSensor("Panel maximum power yesterday", NULL, "H23", "power", "measurement", "W", *optMpptData);

// optional info, provided only if the charge controller delivers the information
if (optMpptData->loadOutputState_LOAD.first != 0) {
publishBinarySensor("MPPT load output state", "mdi:export", "LOAD", "ON", "OFF", *optMpptData);
}
if (optMpptData->loadCurrent_IL_mA.first != 0) {
publishSensor("MPPT load current", NULL, "IL", "current", "measurement", "A", *optMpptData);
}

// optional info, provided only if TX is connected to charge controller
if (optMpptData->NetworkTotalDcInputPowerMilliWatts.first != 0) {
publishSensor("VE.Smart network total DC input power", "mdi:solar-power", "NetworkTotalDcInputPower", "power", "measurement", "W", *optMpptData);
Expand Down
15 changes: 14 additions & 1 deletion src/WebApi_ws_vedirect_live.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,20 @@ void WebApiWsVedirectLiveClass::populateJson(const JsonObject &root, const VeDir
const JsonObject values = root["values"].to<JsonObject>();

const JsonObject device = values["device"].to<JsonObject>();
device["LOAD"] = mpptData.loadOutputState_LOAD ? "ON" : "OFF";

// LOAD IL UI label result
// ------------------------------------
// false false Do not display LOAD and IL (device has no physical load output and virtual load is not configured)
// true false "VIRTLOAD" We display just LOAD (device has no physical load output and virtual load is configured)
// true true "LOAD" We display LOAD and IL (device has physical load output, regardless if virtual load is configured or not)
if (mpptData.loadOutputState_LOAD.first > 0) {
device[(mpptData.loadCurrent_IL_mA.first > 0) ? "LOAD" : "VIRTLOAD"] = mpptData.loadOutputState_LOAD.second ? "ON" : "OFF";
}
if (mpptData.loadCurrent_IL_mA.first > 0) {
device["IL"]["v"] = mpptData.loadCurrent_IL_mA.second / 1000.0;
device["IL"]["u"] = "A";
device["IL"]["d"] = 2;
}
device["CS"] = mpptData.getCsAsString();
device["MPPT"] = mpptData.getMpptAsString();
device["OR"] = mpptData.getOrAsString();
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@
"section_device": "Geräteinformation",
"device": {
"LOAD": "Status Lastausgang",
"VIRTLOAD": "Status virtueller Lastausgang",
"IL": "Laststrom",
"CS": "Betriebszustand",
"MPPT": "Betriebszustand des Trackers",
"OR": "Grund für das Ausschalten",
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@
"section_device": "Device Info",
"device": {
"LOAD": "Load output state",
"VIRTLOAD": "Virtual load output state",
"IL": "Load current",
"CS": "State of operation",
"MPPT": "Tracker operation mode",
"OR": "Off reason",
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@
"section_device": "Device Info",
"device": {
"LOAD": "Load output state",
"VIRTLOAD": "Virtual load output state",
"IL": "Load current",
"CS": "State of operation",
"MPPT": "Tracker operation mode",
"OR": "Off reason",
Expand Down