refactor: reworked the setting of the maximum modulation level, added the parameter of the maximum modulation level for DHW

This commit is contained in:
Yurii
2025-05-18 15:31:49 +03:00
parent 7c032ddc2f
commit 612b17b86f
8 changed files with 75 additions and 68 deletions

View File

@@ -342,13 +342,23 @@ protected:
vars.slave.modulation.min, vars.slave.power.max
);
if (settings.opentherm.maxModulation < vars.slave.modulation.min) {
settings.opentherm.maxModulation = vars.slave.modulation.min;
if (settings.heating.maxModulation < vars.slave.modulation.min) {
settings.heating.maxModulation = vars.slave.modulation.min;
fsSettings.update();
Log.swarningln(
FPSTR(L_SETTINGS_OT), F("Updated min modulation: %hhu%%"),
settings.opentherm.maxModulation
FPSTR(L_SETTINGS_HEATING), F("Updated min modulation: %hhu%%"),
settings.heating.maxModulation
);
}
if (settings.dhw.maxModulation < vars.slave.modulation.min) {
settings.dhw.maxModulation = vars.slave.modulation.min;
fsSettings.update();
Log.swarningln(
FPSTR(L_SETTINGS_DHW), F("Updated min modulation: %hhu%%"),
settings.dhw.maxModulation
);
}
@@ -367,29 +377,6 @@ protected:
Log.swarningln(FPSTR(L_OT), F("Failed receive min modulation and max power"));
}
if (!vars.master.heating.enabled && settings.opentherm.options.modulationSyncWithHeating) {
if (this->setMaxModulationLevel(0)) {
Log.snoticeln(FPSTR(L_OT), F("Set max modulation: 0% (response: %hhu%%)"), vars.slave.modulation.max);
} else {
Log.swarningln(FPSTR(L_OT), F("Failed set max modulation: 0% (response: %hhu%%)"), vars.slave.modulation.max);
}
} else {
if (this->setMaxModulationLevel(settings.opentherm.maxModulation)) {
Log.snoticeln(
FPSTR(L_OT), F("Set max modulation: %hhu%% (response: %hhu%%)"),
settings.opentherm.maxModulation, vars.slave.modulation.max
);
} else {
Log.swarningln(
FPSTR(L_OT), F("Failed set max modulation: %hhu%% (response: %hhu%%)"),
settings.opentherm.maxModulation, vars.slave.modulation.max
);
}
}
// Get DHW min/max temp (if necessary)
if (settings.opentherm.options.dhwSupport && settings.opentherm.options.getMinMaxTemp) {
@@ -517,6 +504,29 @@ protected:
this->prevUpdateNonEssentialVars = millis();
}
// Set max modulation level
uint8_t targetMaxModulation = vars.slave.modulation.max;
if (vars.slave.heating.active) {
targetMaxModulation = settings.heating.maxModulation;
} else if (vars.slave.dhw.active) {
targetMaxModulation = settings.dhw.maxModulation;
}
if (vars.slave.modulation.max != targetMaxModulation) {
if (this->setMaxModulationLevel(targetMaxModulation)) {
Log.snoticeln(
FPSTR(L_OT), F("Set max modulation: %hhu%% (response: %hhu%%)"),
targetMaxModulation, vars.slave.modulation.max
);
} else {
Log.swarningln(
FPSTR(L_OT), F("Failed set max modulation: %hhu%% (response: %hhu%%)"),
targetMaxModulation, vars.slave.modulation.max
);
}
}
// Update modulation level
if (

View File

@@ -59,7 +59,6 @@ struct Settings {
byte rxLedGpio = DEFAULT_OT_RX_LED_GPIO;
uint8_t memberId = 0;
uint8_t flags = 0;
uint8_t maxModulation = 100;
float minPower = 0.0f;
float maxPower = 0.0f;
@@ -72,7 +71,6 @@ struct Settings {
bool heatingToCh2 = false;
bool dhwToCh2 = false;
bool dhwBlocking = false;
bool modulationSyncWithHeating = false;
bool maxTempSyncWithTargetTemp = true;
bool getMinMaxTemp = true;
bool nativeHeatingControl = false;
@@ -104,6 +102,7 @@ struct Settings {
float turboFactor = 7.5f;
byte minTemp = DEFAULT_HEATING_MIN_TEMP;
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
uint8_t maxModulation = 100;
} heating;
struct {
@@ -111,6 +110,7 @@ struct Settings {
float target = DEFAULT_DHW_TARGET_TEMP;
byte minTemp = DEFAULT_DHW_MIN_TEMP;
byte maxTemp = DEFAULT_DHW_MAX_TEMP;
uint8_t maxModulation = 100;
} dhw;
struct {

View File

@@ -131,7 +131,6 @@ const char S_MIN_POWER[] PROGMEM = "minPower";
const char S_MIN_TEMP[] PROGMEM = "minTemp";
const char S_MODEL[] PROGMEM = "model";
const char S_MODULATION[] PROGMEM = "modulation";
const char S_MODULATION_SYNC_WITH_HEATING[] PROGMEM = "modulationSyncWithHeating";
const char S_MQTT[] PROGMEM = "mqtt";
const char S_NAME[] PROGMEM = "name";
const char S_NATIVE_HEATING_CONTROL[] PROGMEM = "nativeHeatingControl";

View File

@@ -449,7 +449,6 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
opentherm[FPSTR(S_RX_LED_GPIO)] = src.opentherm.rxLedGpio;
opentherm[FPSTR(S_MEMBER_ID)] = src.opentherm.memberId;
opentherm[FPSTR(S_FLAGS)] = src.opentherm.flags;
opentherm[FPSTR(S_MAX_MODULATION)] = src.opentherm.maxModulation;
opentherm[FPSTR(S_MIN_POWER)] = roundf(src.opentherm.minPower, 2);
opentherm[FPSTR(S_MAX_POWER)] = roundf(src.opentherm.maxPower, 2);
@@ -462,7 +461,6 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
otOptions[FPSTR(S_HEATING_TO_CH2)] = src.opentherm.options.heatingToCh2;
otOptions[FPSTR(S_DHW_TO_CH2)] = src.opentherm.options.dhwToCh2;
otOptions[FPSTR(S_DHW_BLOCKING)] = src.opentherm.options.dhwBlocking;
otOptions[FPSTR(S_MODULATION_SYNC_WITH_HEATING)] = src.opentherm.options.modulationSyncWithHeating;
otOptions[FPSTR(S_MAX_TEMP_SYNC_WITH_TARGET_TEMP)] = src.opentherm.options.maxTempSyncWithTargetTemp;
otOptions[FPSTR(S_GET_MIN_MAX_TEMP)] = src.opentherm.options.getMinMaxTemp;
otOptions[FPSTR(S_NATIVE_HEATING_CONTROL)] = src.opentherm.options.nativeHeatingControl;
@@ -491,12 +489,14 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
heating[FPSTR(S_TURBO_FACTOR)] = roundf(src.heating.turboFactor, 3);
heating[FPSTR(S_MIN_TEMP)] = src.heating.minTemp;
heating[FPSTR(S_MAX_TEMP)] = src.heating.maxTemp;
heating[FPSTR(S_MAX_MODULATION)] = src.heating.maxModulation;
auto dhw = dst[FPSTR(S_DHW)].to<JsonObject>();
dhw[FPSTR(S_ENABLED)] = src.dhw.enabled;
dhw[FPSTR(S_TARGET)] = roundf(src.dhw.target, 1);
dhw[FPSTR(S_MIN_TEMP)] = src.dhw.minTemp;
dhw[FPSTR(S_MAX_TEMP)] = src.dhw.maxTemp;
dhw[FPSTR(S_MAX_MODULATION)] = src.dhw.maxModulation;
auto equitherm = dst[FPSTR(S_EQUITHERM)].to<JsonObject>();
equitherm[FPSTR(S_ENABLED)] = src.equitherm.enabled;
@@ -811,15 +811,6 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
}
if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_MODULATION)].isNull()) {
unsigned char value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_MODULATION)].as<unsigned char>();
if (value > 0 && value <= 100 && value != dst.opentherm.maxModulation) {
dst.opentherm.maxModulation = value;
changed = true;
}
}
if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MIN_POWER)].isNull()) {
float value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MIN_POWER)].as<float>();
@@ -928,15 +919,6 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
}
if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MODULATION_SYNC_WITH_HEATING)].is<bool>()) {
bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MODULATION_SYNC_WITH_HEATING)].as<bool>();
if (value != dst.opentherm.options.modulationSyncWithHeating) {
dst.opentherm.options.modulationSyncWithHeating = value;
changed = true;
}
}
if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MAX_TEMP_SYNC_WITH_TARGET_TEMP)].is<bool>()) {
bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MAX_TEMP_SYNC_WITH_TARGET_TEMP)].as<bool>();
@@ -1301,6 +1283,16 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
if (!src[FPSTR(S_HEATING)][FPSTR(S_MAX_MODULATION)].isNull()) {
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MAX_MODULATION)].as<unsigned char>();
if (value > 0 && value <= 100 && value != dst.heating.maxModulation) {
dst.heating.maxModulation = value;
changed = true;
}
}
// dhw
if (src[FPSTR(S_DHW)][FPSTR(S_ENABLED)].is<bool>()) {
bool value = src[FPSTR(S_DHW)][FPSTR(S_ENABLED)].as<bool>();
@@ -1334,6 +1326,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
changed = true;
}
if (!src[FPSTR(S_DHW)][FPSTR(S_MAX_MODULATION)].isNull()) {
unsigned char value = src[FPSTR(S_DHW)][FPSTR(S_MAX_MODULATION)].as<unsigned char>();
if (value > 0 && value <= 100 && value != dst.dhw.maxModulation) {
dst.dhw.maxModulation = value;
changed = true;
}
}
if (!safe) {
// external pump

View File

@@ -292,6 +292,7 @@
"min": "Minimum temperature",
"max": "Maximum temperature"
},
"maxModulation": "Max modulation level",
"portal": {
"login": "Login",
@@ -375,7 +376,6 @@
"ledGpio": "RX LED GPIO",
"memberId": "Master member ID",
"flags": "Master flags",
"maxMod": "Max modulation level",
"minPower": {
"title": "Min boiler power <small>(kW)</small>",
"note": "This value is at 0-1% boiler modulation level. Typically found in the boiler specification as \"minimum useful heat output\"."
@@ -395,7 +395,6 @@
"heatingToCh2": "Duplicate heating to CH2",
"dhwToCh2": "Duplicate DHW to CH2",
"dhwBlocking": "DHW blocking",
"modulationSyncWithHeating": "Sync modulation with heating",
"maxTempSyncWithTargetTemp": "Sync max heating temp with target temp",
"getMinMaxTemp": "Get min/max temp from boiler",
"immergasFix": "Fix for Immergas boilers"

View File

@@ -292,6 +292,7 @@
"min": "Temperatura minima",
"max": "Temperatura massima"
},
"maxModulation": "Max livello modulazione",
"portal": {
"login": "Login",
@@ -375,7 +376,6 @@
"ledGpio": "RX LED GPIO",
"memberId": "Master member ID",
"flags": "Master flags",
"maxMod": "Max livello modulazione",
"minPower": {
"title": "Potenza minima caldaia <small>(kW)</small>",
"note": "Questo valore corrisponde allo livello 0-1% di modulazione della caldaia. Di solito si trova nelle specifiche delle caldaia come \"potenza minima disponibile\"."
@@ -395,7 +395,6 @@
"heatingToCh2": "Riproduci riscaldamento su CH2",
"dhwToCh2": "Riproduci ACS su CH2",
"dhwBlocking": "Bloccare ACS",
"modulationSyncWithHeating": "Sincronizzare modulazione con caldaia",
"maxTempSyncWithTargetTemp": "Sincronizza la temperatura massima di riscaldamento con la temperatura target",
"getMinMaxTemp": "Prendi temp min/max dalla caldaia",
"immergasFix": "Fix per caldiaie Immergas"

View File

@@ -292,6 +292,7 @@
"min": "Мин. температура",
"max": "Макс. температура"
},
"maxModulation": "Макс. уровень модуляции",
"portal": {
"login": "Логин",
@@ -375,7 +376,6 @@
"ledGpio": "RX LED GPIO",
"memberId": "Master member ID",
"flags": "Master flags",
"maxMod": "Макс. уровень модуляции",
"minPower": {
"title": "Мин. мощность котла <small>(кВт)</small>",
"note": "Это значение соответствует уровню модуляции котла 01%. Обычно можно найти в спецификации котла как \"минимальная полезная тепловая мощность\"."
@@ -395,7 +395,6 @@
"heatingToCh2": "Дублировать параметры отопления в канал 2",
"dhwToCh2": "Дублировать параметры ГВС в канал 2",
"dhwBlocking": "DHW blocking",
"modulationSyncWithHeating": "Синхронизировать модуляцию с отоплением",
"maxTempSyncWithTargetTemp": "Синхронизировать макс. темп. отопления с целевой темп.",
"getMinMaxTemp": "Получать мин. и макс. температуру от котла",
"immergasFix": "Фикс для котлов Immergas"

View File

@@ -202,6 +202,11 @@
</label>
</div>
<label>
<span data-i18n>settings.maxModulation</span>
<input type="number" inputmode="numeric" name="heating[maxModulation]" min="1" max="100" step="1" required>
</label>
<button type="submit" data-i18n>button.save</button>
</form>
</div>
@@ -226,6 +231,11 @@
</label>
</div>
<label>
<span data-i18n>settings.maxModulation</span>
<input type="number" inputmode="numeric" name="dhw[maxModulation]" min="1" max="100" step="1" required>
</label>
<button type="submit" data-i18n>button.save</button>
</form>
</div>
@@ -457,11 +467,6 @@
<span data-i18n>settings.ot.flags</span>
<input type="number" inputmode="numeric" name="opentherm[flags]" min="0" max="255" step="1" required>
</label>
<label>
<span data-i18n>settings.ot.maxMod</span>
<input type="number" inputmode="numeric" name="opentherm[maxModulation]" min="1" max="100" step="1" required>
</label>
</div>
<div class="grid">
@@ -521,11 +526,6 @@
<span data-i18n>settings.ot.options.dhwBlocking</span>
</label>
<label>
<input type="checkbox" name="opentherm[options][modulationSyncWithHeating]" value="true">
<span data-i18n>settings.ot.options.modulationSyncWithHeating</span>
</label>
<label>
<input type="checkbox" name="opentherm[options][maxTempSyncWithTargetTemp]" value="true">
<span data-i18n>settings.ot.options.maxTempSyncWithTargetTemp</span>
@@ -788,7 +788,6 @@
setInputValue("[name='opentherm[rxLedGpio]']", data.opentherm.rxLedGpio < 255 ? data.opentherm.rxLedGpio : '');
setInputValue("[name='opentherm[memberId]']", data.opentherm.memberId);
setInputValue("[name='opentherm[flags]']", data.opentherm.flags);
setInputValue("[name='opentherm[maxModulation]']", data.opentherm.maxModulation);
setInputValue("[name='opentherm[minPower]']", data.opentherm.minPower);
setInputValue("[name='opentherm[maxPower]']", data.opentherm.maxPower);
setCheckboxValue("[name='opentherm[options][dhwSupport]']", data.opentherm.options.dhwSupport);
@@ -799,7 +798,6 @@
setCheckboxValue("[name='opentherm[options][heatingToCh2]']", data.opentherm.options.heatingToCh2);
setCheckboxValue("[name='opentherm[options][dhwToCh2]']", data.opentherm.options.dhwToCh2);
setCheckboxValue("[name='opentherm[options][dhwBlocking]']", data.opentherm.options.dhwBlocking);
setCheckboxValue("[name='opentherm[options][modulationSyncWithHeating]']", data.opentherm.options.modulationSyncWithHeating);
setCheckboxValue("[name='opentherm[options][maxTempSyncWithTargetTemp]']", data.opentherm.options.maxTempSyncWithTargetTemp);
setCheckboxValue("[name='opentherm[options][getMinMaxTemp]']", data.opentherm.options.getMinMaxTemp);
setCheckboxValue("[name='opentherm[options][nativeHeatingControl]']", data.opentherm.options.nativeHeatingControl);
@@ -851,6 +849,7 @@
});
setInputValue("[name='heating[hysteresis]']", data.heating.hysteresis);
setInputValue("[name='heating[turboFactor]']", data.heating.turboFactor);
setInputValue("[name='heating[maxModulation]']", data.heating.maxModulation);
setBusy('#heating-settings-busy', '#heating-settings', false);
// DHW
@@ -862,6 +861,7 @@
"min": data.system.unitSystem == 0 ? 1 : 33,
"max": data.system.unitSystem == 0 ? 100 : 212
});
setInputValue("[name='dhw[maxModulation]']", data.dhw.maxModulation);
setBusy('#dhw-settings-busy', '#dhw-settings', false);
// Emergency mode