Merge pull request #255 from madmartin:inverter_restart
Feature: add daily restart for the inverter
This commit is contained in:
commit
8298a0c36f
@ -150,6 +150,7 @@ struct CONFIG_T {
|
|||||||
float PowerLimiter_VoltageStartThreshold;
|
float PowerLimiter_VoltageStartThreshold;
|
||||||
float PowerLimiter_VoltageStopThreshold;
|
float PowerLimiter_VoltageStopThreshold;
|
||||||
float PowerLimiter_VoltageLoadCorrectionFactor;
|
float PowerLimiter_VoltageLoadCorrectionFactor;
|
||||||
|
int8_t PowerLimiter_RestartHour;
|
||||||
|
|
||||||
bool Battery_Enabled;
|
bool Battery_Enabled;
|
||||||
bool Huawei_Enabled;
|
bool Huawei_Enabled;
|
||||||
|
|||||||
@ -31,6 +31,7 @@ public:
|
|||||||
int32_t getLastRequestedPowewrLimit();
|
int32_t getLastRequestedPowewrLimit();
|
||||||
void setDisable(bool disable);
|
void setDisable(bool disable);
|
||||||
bool getDisable();
|
bool getDisable();
|
||||||
|
void calcNextInverterRestart();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t _lastLoop = 0;
|
uint32_t _lastLoop = 0;
|
||||||
@ -39,6 +40,8 @@ private:
|
|||||||
plStates _plState;
|
plStates _plState;
|
||||||
bool _disabled = false;
|
bool _disabled = false;
|
||||||
bool _batteryDischargeEnabled = false;
|
bool _batteryDischargeEnabled = false;
|
||||||
|
uint32_t _nextInverterRestart = 0; // Values: 0->not calculated / 1->no restart configured / >1->time of next inverter restart in millis()
|
||||||
|
uint32_t _nextCalculateCheck = 5000; // time in millis for next NTP check to calulate restart
|
||||||
|
|
||||||
float _powerMeter1Power;
|
float _powerMeter1Power;
|
||||||
float _powerMeter2Power;
|
float _powerMeter2Power;
|
||||||
|
|||||||
@ -122,6 +122,7 @@
|
|||||||
#define POWERLIMITER_VOLTAGE_START_THRESHOLD 50.0
|
#define POWERLIMITER_VOLTAGE_START_THRESHOLD 50.0
|
||||||
#define POWERLIMITER_VOLTAGE_STOP_THRESHOLD 49.0
|
#define POWERLIMITER_VOLTAGE_STOP_THRESHOLD 49.0
|
||||||
#define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001
|
#define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001
|
||||||
|
#define POWERLIMITER_RESTART_HOUR -1
|
||||||
|
|
||||||
#define BATTERY_ENABLED false
|
#define BATTERY_ENABLED false
|
||||||
|
|
||||||
|
|||||||
@ -163,6 +163,7 @@ bool ConfigurationClass::write()
|
|||||||
powerlimiter["voltage_start_threshold"] = config.PowerLimiter_VoltageStartThreshold;
|
powerlimiter["voltage_start_threshold"] = config.PowerLimiter_VoltageStartThreshold;
|
||||||
powerlimiter["voltage_stop_threshold"] = config.PowerLimiter_VoltageStopThreshold;
|
powerlimiter["voltage_stop_threshold"] = config.PowerLimiter_VoltageStopThreshold;
|
||||||
powerlimiter["voltage_load_correction_factor"] = config.PowerLimiter_VoltageLoadCorrectionFactor;
|
powerlimiter["voltage_load_correction_factor"] = config.PowerLimiter_VoltageLoadCorrectionFactor;
|
||||||
|
powerlimiter["inverter_restart_hour"] = config.PowerLimiter_RestartHour;
|
||||||
|
|
||||||
JsonObject battery = doc.createNestedObject("battery");
|
JsonObject battery = doc.createNestedObject("battery");
|
||||||
battery["enabled"] = config.Battery_Enabled;
|
battery["enabled"] = config.Battery_Enabled;
|
||||||
@ -360,6 +361,7 @@ bool ConfigurationClass::read()
|
|||||||
config.PowerLimiter_VoltageStartThreshold = powerlimiter["voltage_start_threshold"] | POWERLIMITER_VOLTAGE_START_THRESHOLD;
|
config.PowerLimiter_VoltageStartThreshold = powerlimiter["voltage_start_threshold"] | POWERLIMITER_VOLTAGE_START_THRESHOLD;
|
||||||
config.PowerLimiter_VoltageStopThreshold = powerlimiter["voltage_stop_threshold"] | POWERLIMITER_VOLTAGE_STOP_THRESHOLD;
|
config.PowerLimiter_VoltageStopThreshold = powerlimiter["voltage_stop_threshold"] | POWERLIMITER_VOLTAGE_STOP_THRESHOLD;
|
||||||
config.PowerLimiter_VoltageLoadCorrectionFactor = powerlimiter["voltage_load_correction_factor"] | POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR;
|
config.PowerLimiter_VoltageLoadCorrectionFactor = powerlimiter["voltage_load_correction_factor"] | POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR;
|
||||||
|
config.PowerLimiter_RestartHour = powerlimiter["inverter_restart_hour"] | POWERLIMITER_RESTART_HOUR;
|
||||||
|
|
||||||
JsonObject battery = doc["battery"];
|
JsonObject battery = doc["battery"];
|
||||||
config.Battery_Enabled = battery["enabled"] | BATTERY_ENABLED;
|
config.Battery_Enabled = battery["enabled"] | BATTERY_ENABLED;
|
||||||
|
|||||||
@ -53,6 +53,27 @@ void PowerLimiterClass::loop()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if next inverter restart time is reached
|
||||||
|
if ((_nextInverterRestart > 1) && (_nextInverterRestart <= millis())) {
|
||||||
|
MessageOutput.println("[PowerLimiterClass::loop] send inverter restart");
|
||||||
|
inverter->sendRestartControlRequest();
|
||||||
|
calcNextInverterRestart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if NTP time is set and next inverter restart not calculated yet
|
||||||
|
if ((config.PowerLimiter_RestartHour >= 0) && (_nextInverterRestart == 0) ) {
|
||||||
|
// check every 5 seconds
|
||||||
|
if (_nextCalculateCheck < millis()) {
|
||||||
|
struct tm timeinfo;
|
||||||
|
if (getLocalTime(&timeinfo, 5)) {
|
||||||
|
calcNextInverterRestart();
|
||||||
|
} else {
|
||||||
|
MessageOutput.println("[PowerLimiterClass::loop] inverter restart calculation: NTP not ready");
|
||||||
|
_nextCalculateCheck += 5000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure inverter is turned off if PL is disabled by user/MQTT
|
// Make sure inverter is turned off if PL is disabled by user/MQTT
|
||||||
if (((!config.PowerLimiter_Enabled || _disabled) && _plState != SHUTDOWN)) {
|
if (((!config.PowerLimiter_Enabled || _disabled) && _plState != SHUTDOWN)) {
|
||||||
if (inverter->isProducing()) {
|
if (inverter->isProducing()) {
|
||||||
@ -155,7 +176,7 @@ void PowerLimiterClass::loop()
|
|||||||
MessageOutput.printf("[PowerLimiterClass::loop] Status Batt: Ena: %i, SOC: %i, StartTH: %i, StopTH: %i, LastUpdate: %li\r\n",
|
MessageOutput.printf("[PowerLimiterClass::loop] Status Batt: Ena: %i, SOC: %i, StartTH: %i, StopTH: %i, LastUpdate: %li\r\n",
|
||||||
config.Battery_Enabled, Battery.stateOfCharge, config.PowerLimiter_BatterySocStartThreshold, config.PowerLimiter_BatterySocStopThreshold, millis() - Battery.stateOfChargeLastUpdate);
|
config.Battery_Enabled, Battery.stateOfCharge, config.PowerLimiter_BatterySocStartThreshold, config.PowerLimiter_BatterySocStopThreshold, millis() - Battery.stateOfChargeLastUpdate);
|
||||||
MessageOutput.printf("[PowerLimiterClass::loop] ******************* Leaving PL, PL set to: %i, SP: %i, Batt: %i, PM: %f\r\n", newPowerLimit, canUseDirectSolarPower(), _batteryDischargeEnabled, round(PowerMeter.getPowerTotal()));
|
MessageOutput.printf("[PowerLimiterClass::loop] ******************* Leaving PL, PL set to: %i, SP: %i, Batt: %i, PM: %f\r\n", newPowerLimit, canUseDirectSolarPower(), _batteryDischargeEnabled, round(PowerMeter.getPowerTotal()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t PowerLimiterClass::getPowerLimiterState() {
|
uint8_t PowerLimiterClass::getPowerLimiterState() {
|
||||||
@ -384,4 +405,44 @@ bool PowerLimiterClass::isStopThresholdReached(std::shared_ptr<InverterAbstract>
|
|||||||
|
|
||||||
float correctedDcVoltage = getLoadCorrectedVoltage(inverter);
|
float correctedDcVoltage = getLoadCorrectedVoltage(inverter);
|
||||||
return correctedDcVoltage <= config.PowerLimiter_VoltageStopThreshold;
|
return correctedDcVoltage <= config.PowerLimiter_VoltageStopThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief calculate next inverter restart in millis
|
||||||
|
void PowerLimiterClass::calcNextInverterRestart()
|
||||||
|
{
|
||||||
|
CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
|
// first check if restart is configured at all
|
||||||
|
if (config.PowerLimiter_RestartHour < 0) {
|
||||||
|
_nextInverterRestart = 1;
|
||||||
|
MessageOutput.println("[PowerLimiterClass::calcNextInverterRestart] _nextInverterRestart disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read time from timeserver, if time is not synced then return
|
||||||
|
struct tm timeinfo;
|
||||||
|
if (getLocalTime(&timeinfo, 5)) {
|
||||||
|
// calculation first step is offset to next restart in minutes
|
||||||
|
uint16_t dayMinutes = timeinfo.tm_hour * 60 + timeinfo.tm_min;
|
||||||
|
uint16_t targetMinutes = config.PowerLimiter_RestartHour * 60;
|
||||||
|
if (config.PowerLimiter_RestartHour > timeinfo.tm_hour) {
|
||||||
|
// next restart is on the same day
|
||||||
|
_nextInverterRestart = targetMinutes - dayMinutes;
|
||||||
|
} else {
|
||||||
|
// next restart is on next day
|
||||||
|
_nextInverterRestart = 1440 - dayMinutes + targetMinutes;
|
||||||
|
}
|
||||||
|
#ifdef POWER_LIMITER_DEBUG
|
||||||
|
MessageOutput.printf("[PowerLimiterClass::calcNextInverterRestart] Localtime read %d %d / configured RestartHour %d\r\n", timeinfo.tm_hour, timeinfo.tm_min, config.PowerLimiter_RestartHour);
|
||||||
|
MessageOutput.printf("[PowerLimiterClass::calcNextInverterRestart] dayMinutes %d / targetMinutes %d\r\n", dayMinutes, targetMinutes);
|
||||||
|
MessageOutput.printf("[PowerLimiterClass::calcNextInverterRestart] next inverter restart in %d minutes\r\n", _nextInverterRestart);
|
||||||
|
#endif
|
||||||
|
// then convert unit for next restart to milliseconds and add current uptime millis()
|
||||||
|
_nextInverterRestart *= 60000;
|
||||||
|
_nextInverterRestart += millis();
|
||||||
|
} else {
|
||||||
|
MessageOutput.println("[PowerLimiterClass::calcNextInverterRestart] getLocalTime not successful, no calculation");
|
||||||
|
_nextInverterRestart = 0;
|
||||||
|
}
|
||||||
|
MessageOutput.printf("[PowerLimiterClass::calcNextInverterRestart] _nextInverterRestart @ %d millis\r\n", _nextInverterRestart);
|
||||||
}
|
}
|
||||||
@ -52,6 +52,7 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request)
|
|||||||
root[F("voltage_start_threshold")] = static_cast<int>(config.PowerLimiter_VoltageStartThreshold * 100 +0.5) / 100.0;
|
root[F("voltage_start_threshold")] = static_cast<int>(config.PowerLimiter_VoltageStartThreshold * 100 +0.5) / 100.0;
|
||||||
root[F("voltage_stop_threshold")] = static_cast<int>(config.PowerLimiter_VoltageStopThreshold * 100 +0.5) / 100.0;;
|
root[F("voltage_stop_threshold")] = static_cast<int>(config.PowerLimiter_VoltageStopThreshold * 100 +0.5) / 100.0;;
|
||||||
root[F("voltage_load_correction_factor")] = config.PowerLimiter_VoltageLoadCorrectionFactor;
|
root[F("voltage_load_correction_factor")] = config.PowerLimiter_VoltageLoadCorrectionFactor;
|
||||||
|
root[F("inverter_restart_hour")] = config.PowerLimiter_RestartHour;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -136,8 +137,11 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request)
|
|||||||
config.PowerLimiter_VoltageStopThreshold = root[F("voltage_stop_threshold")].as<float>();
|
config.PowerLimiter_VoltageStopThreshold = root[F("voltage_stop_threshold")].as<float>();
|
||||||
config.PowerLimiter_VoltageStopThreshold = static_cast<int>(config.PowerLimiter_VoltageStopThreshold * 100) / 100.0;
|
config.PowerLimiter_VoltageStopThreshold = static_cast<int>(config.PowerLimiter_VoltageStopThreshold * 100) / 100.0;
|
||||||
config.PowerLimiter_VoltageLoadCorrectionFactor = root[F("voltage_load_correction_factor")].as<float>();
|
config.PowerLimiter_VoltageLoadCorrectionFactor = root[F("voltage_load_correction_factor")].as<float>();
|
||||||
|
config.PowerLimiter_RestartHour = root[F("inverter_restart_hour")].as<int8_t>();
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
|
PowerLimiter.calcNextInverterRestart();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg[F("type")] = F("success");
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg[F("message")] = F("Settings saved!");
|
||||||
|
|
||||||
|
|||||||
@ -549,6 +549,9 @@
|
|||||||
"InverterIsBehindPowerMeter": "Welchselrichter ist hinter Leistungsmesser",
|
"InverterIsBehindPowerMeter": "Welchselrichter ist hinter Leistungsmesser",
|
||||||
"Battery": "DC / Akku",
|
"Battery": "DC / Akku",
|
||||||
"VoltageLoadCorrectionInfo": "<b>Hinweis:</b> Wenn Leistung von der Batterie abgegeben wird, bricht normalerweise die Spannung etwas ein. Damit nicht vorzeitig der Wechelrichter ausgeschaltet wird sobald der \"Stop\"-Schwellenwert erreicht wird, wird der hier angegebene Korrekturfaktor mit einberechnet. Korrigierte Spannung = DC Spannung + (Aktuelle Leistung (W) + Korrekturfaktor).",
|
"VoltageLoadCorrectionInfo": "<b>Hinweis:</b> Wenn Leistung von der Batterie abgegeben wird, bricht normalerweise die Spannung etwas ein. Damit nicht vorzeitig der Wechelrichter ausgeschaltet wird sobald der \"Stop\"-Schwellenwert erreicht wird, wird der hier angegebene Korrekturfaktor mit einberechnet. Korrigierte Spannung = DC Spannung + (Aktuelle Leistung (W) + Korrekturfaktor).",
|
||||||
|
"InverterRestart": "Wechselrichter Neustart",
|
||||||
|
"InverterRestartHour": "Stunde für Neustart",
|
||||||
|
"InverterRestartHint": "Neustart des Wechselrichter einmal täglich um die \"Tagesertrag\" Werte wieder auf Null zu setzen.",
|
||||||
"Save": "@:dtuadmin.Save"
|
"Save": "@:dtuadmin.Save"
|
||||||
},
|
},
|
||||||
"batteryadmin": {
|
"batteryadmin": {
|
||||||
|
|||||||
@ -553,6 +553,9 @@
|
|||||||
"InverterIsBehindPowerMeter": "Inverter is behind Power meter",
|
"InverterIsBehindPowerMeter": "Inverter is behind Power meter",
|
||||||
"Battery": "DC / Battery",
|
"Battery": "DC / Battery",
|
||||||
"VoltageLoadCorrectionInfo": "<b>Hint:</b> When the power output is higher, the voltage is usually decreasing. In order to not stop the inverter too early (Stop treshold), a power factor can be specified here to correct this. Corrected voltage = DC Voltage + (Current power * correction factor).",
|
"VoltageLoadCorrectionInfo": "<b>Hint:</b> When the power output is higher, the voltage is usually decreasing. In order to not stop the inverter too early (Stop treshold), a power factor can be specified here to correct this. Corrected voltage = DC Voltage + (Current power * correction factor).",
|
||||||
|
"InverterRestart": "Inverter Restart",
|
||||||
|
"InverterRestartHour": "Restart Hour",
|
||||||
|
"InverterRestartHint": "Restart the Inverter once a day to reset the \"YieldDay\" values.",
|
||||||
"Save": "@:dtuadmin.Save"
|
"Save": "@:dtuadmin.Save"
|
||||||
},
|
},
|
||||||
"batteryadmin": {
|
"batteryadmin": {
|
||||||
|
|||||||
@ -14,4 +14,5 @@ export interface PowerLimiterConfig {
|
|||||||
voltage_start_threshold: number;
|
voltage_start_threshold: number;
|
||||||
voltage_stop_threshold: number;
|
voltage_stop_threshold: number;
|
||||||
voltage_load_correction_factor: number;
|
voltage_load_correction_factor: number;
|
||||||
|
inverter_restart_hour: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -193,6 +193,24 @@
|
|||||||
<div class="alert alert-secondary" role="alert" v-html="$t('powerlimiteradmin.VoltageLoadCorrectionInfo')"></div>
|
<div class="alert alert-secondary" role="alert" v-html="$t('powerlimiteradmin.VoltageLoadCorrectionInfo')"></div>
|
||||||
</CardElement>
|
</CardElement>
|
||||||
|
|
||||||
|
<CardElement :text="$t('powerlimiteradmin.InverterRestart')" textVariant="text-bg-primary" add-space
|
||||||
|
v-show="powerLimiterConfigList.enabled"
|
||||||
|
>
|
||||||
|
<div class="row mb-3" v-show="powerLimiterConfigList.enabled">
|
||||||
|
<label for="inputTimezone" class="col-sm-2 col-form-label">
|
||||||
|
{{ $t('powerlimiteradmin.InverterRestartHour') }}:
|
||||||
|
<BIconInfoCircle v-tooltip :title="$t('powerlimiteradmin.InverterRestartHint')" />
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-select" v-model="powerLimiterConfigList.inverter_restart_hour">
|
||||||
|
<option v-for="hour in restartHourList" :key="hour.key" :value="hour.key">
|
||||||
|
{{ hour.value }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardElement>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary mb-3">{{ $t('powerlimiteradmin.Save') }}</button>
|
<button type="submit" class="btn btn-primary mb-3">{{ $t('powerlimiteradmin.Save') }}</button>
|
||||||
</form>
|
</form>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
@ -243,6 +261,33 @@ export default defineComponent({
|
|||||||
{ key: 0, value: "powerlimiteradmin.BatteryDrainWhenFull"},
|
{ key: 0, value: "powerlimiteradmin.BatteryDrainWhenFull"},
|
||||||
{ key: 1, value: "powerlimiteradmin.BatteryDrainAtNight" },
|
{ key: 1, value: "powerlimiteradmin.BatteryDrainAtNight" },
|
||||||
],
|
],
|
||||||
|
restartHourList: [
|
||||||
|
{ key: -1, value: "- - - -" },
|
||||||
|
{ key: 0, value: "0:00" },
|
||||||
|
{ key: 1, value: "1:00" },
|
||||||
|
{ key: 2, value: "2:00" },
|
||||||
|
{ key: 3, value: "3:00" },
|
||||||
|
{ key: 4, value: "4:00" },
|
||||||
|
{ key: 5, value: "5:00" },
|
||||||
|
{ key: 6, value: "6:00" },
|
||||||
|
{ key: 7, value: "7:00" },
|
||||||
|
{ key: 8, value: "8:00" },
|
||||||
|
{ key: 9, value: "9:00" },
|
||||||
|
{ key: 10, value: "10:00" },
|
||||||
|
{ key: 11, value: "11:00" },
|
||||||
|
{ key: 12, value: "12:00" },
|
||||||
|
{ key: 13, value: "13:00" },
|
||||||
|
{ key: 14, value: "14:00" },
|
||||||
|
{ key: 15, value: "15:00" },
|
||||||
|
{ key: 16, value: "16:00" },
|
||||||
|
{ key: 17, value: "17:00" },
|
||||||
|
{ key: 18, value: "18:00" },
|
||||||
|
{ key: 19, value: "19:00" },
|
||||||
|
{ key: 20, value: "20:00" },
|
||||||
|
{ key: 21, value: "21:00" },
|
||||||
|
{ key: 22, value: "22:00" },
|
||||||
|
{ key: 23, value: "23:00" },
|
||||||
|
],
|
||||||
alertMessage: "",
|
alertMessage: "",
|
||||||
alertType: "info",
|
alertType: "info",
|
||||||
showAlert: false,
|
showAlert: false,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user