mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-11 18:54:28 +05:00
Compare commits
6 Commits
1.4.0-rc.2
...
1.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f245f37dfd | ||
|
|
a825412f37 | ||
|
|
935f8bd0a8 | ||
|
|
f78d2f38b8 | ||
|
|
ef083991e3 | ||
|
|
3c0f846335 |
@@ -136,6 +136,16 @@ public:
|
||||
return isValidResponse(response);
|
||||
}
|
||||
|
||||
bool setRoomSetpointCh2(float temperature) {
|
||||
unsigned long response = this->sendRequest(buildRequest(
|
||||
OpenThermMessageType::WRITE_DATA,
|
||||
OpenThermMessageID::TrSetCH2,
|
||||
temperatureToData(temperature)
|
||||
));
|
||||
|
||||
return isValidResponse(response);
|
||||
}
|
||||
|
||||
bool setRoomTemp(float temperature) {
|
||||
unsigned long response = this->sendRequest(buildRequest(
|
||||
OpenThermMessageType::WRITE_DATA,
|
||||
|
||||
@@ -27,6 +27,7 @@ lib_deps =
|
||||
laxilef/TinyLogger@^1.1.0
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||
;-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
-D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
|
||||
-mtext-section-literals
|
||||
-D MQTT_CLIENT_STD_FUNCTION_CALLBACK=1
|
||||
@@ -51,7 +52,7 @@ monitor_speed = 115200
|
||||
monitor_filters = direct
|
||||
board_build.flash_mode = dio
|
||||
board_build.filesystem = littlefs
|
||||
version = 1.4.0-rc.24
|
||||
version = 1.4.0
|
||||
|
||||
; Defaults
|
||||
[esp8266_defaults]
|
||||
@@ -68,7 +69,7 @@ board_build.ldscript = eagle.flash.4m1m.ld
|
||||
[esp32_defaults]
|
||||
platform = espressif32@^6.6
|
||||
platform_packages =
|
||||
platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32/archive/refs/tags/2.0.15.zip
|
||||
platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32/archive/refs/tags/2.0.15.zip
|
||||
board_build.partitions = esp32_partitions.csv
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
|
||||
@@ -30,6 +30,8 @@ protected:
|
||||
unsigned long dhwSetTempTime = 0;
|
||||
unsigned long heatingSetTempTime = 0;
|
||||
byte configuredRxLedGpio = GPIO_IS_NOT_CONFIGURED;
|
||||
byte configuredFaultStateGpio = GPIO_IS_NOT_CONFIGURED;
|
||||
bool faultState = false;
|
||||
|
||||
|
||||
const char* getTaskName() {
|
||||
@@ -116,6 +118,7 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
// RX LED GPIO setup
|
||||
if (settings.opentherm.rxLedGpio != this->configuredRxLedGpio) {
|
||||
if (this->configuredRxLedGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
digitalWrite(this->configuredRxLedGpio, LOW);
|
||||
@@ -131,6 +134,27 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
// Fault state setup
|
||||
if (settings.opentherm.faultStateGpio != this->configuredFaultStateGpio) {
|
||||
if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
digitalWrite(this->configuredFaultStateGpio, LOW);
|
||||
}
|
||||
|
||||
if (GPIO_IS_VALID(settings.opentherm.faultStateGpio)) {
|
||||
this->configuredFaultStateGpio = settings.opentherm.faultStateGpio;
|
||||
this->faultState = false ^ settings.opentherm.invertFaultState ? HIGH : LOW;
|
||||
|
||||
pinMode(this->configuredFaultStateGpio, OUTPUT);
|
||||
digitalWrite(
|
||||
this->configuredFaultStateGpio,
|
||||
this->faultState
|
||||
);
|
||||
|
||||
} else if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
this->configuredFaultStateGpio = GPIO_IS_NOT_CONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && this->pump && this->isReady();
|
||||
bool heatingCh2Enabled = settings.opentherm.heatingCh2Enabled;
|
||||
if (settings.opentherm.heatingCh1ToCh2) {
|
||||
@@ -144,7 +168,7 @@ protected:
|
||||
heatingEnabled,
|
||||
settings.opentherm.dhwPresent && settings.dhw.enable,
|
||||
false,
|
||||
false,
|
||||
settings.opentherm.nativeHeatingControl,
|
||||
heatingCh2Enabled,
|
||||
settings.opentherm.summerWinterMode,
|
||||
settings.opentherm.dhwBlocking
|
||||
@@ -174,6 +198,16 @@ protected:
|
||||
vars.states.fault = false;
|
||||
vars.states.diagnostic = false;
|
||||
|
||||
// Force fault state = on
|
||||
if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
bool fState = true ^ settings.opentherm.invertFaultState ? HIGH : LOW;
|
||||
|
||||
if (fState != this->faultState) {
|
||||
this->faultState = fState;
|
||||
digitalWrite(this->configuredFaultStateGpio, this->faultState);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -199,6 +233,16 @@ protected:
|
||||
vars.states.fault = CustomOpenTherm::isFault(response);
|
||||
vars.states.diagnostic = CustomOpenTherm::isDiagnostic(response);
|
||||
|
||||
// Fault state
|
||||
if (this->configuredFaultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
bool fState = vars.states.fault ^ settings.opentherm.invertFaultState ? HIGH : LOW;
|
||||
|
||||
if (fState != this->faultState) {
|
||||
this->faultState = fState;
|
||||
digitalWrite(this->configuredFaultStateGpio, this->faultState);
|
||||
}
|
||||
}
|
||||
|
||||
// These parameters will be updated every minute
|
||||
if (millis() - this->prevUpdateNonEssentialVars > 60000) {
|
||||
if (!heatingEnabled && settings.opentherm.modulationSyncWithHeating) {
|
||||
@@ -286,6 +330,9 @@ protected:
|
||||
// Get fault code (if necessary)
|
||||
if (vars.states.fault) {
|
||||
updateFaultCode();
|
||||
|
||||
} else if (vars.sensors.faultCode != 0) {
|
||||
vars.sensors.faultCode = 0;
|
||||
}
|
||||
|
||||
updatePressure();
|
||||
@@ -402,6 +449,13 @@ protected:
|
||||
} else {
|
||||
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set target indoor temp"));
|
||||
}
|
||||
|
||||
// Set target temp to CH2
|
||||
if (settings.opentherm.heatingCh1ToCh2) {
|
||||
if (!this->instance->setRoomSetpointCh2(convertedTemp)) {
|
||||
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set target indoor temp to CH2"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// force enable pump
|
||||
|
||||
@@ -512,6 +512,34 @@ protected:
|
||||
doc["system"]["maxFreeBlockHeap"] = getMaxFreeBlockHeap();
|
||||
doc["system"]["minMaxFreeBlockHeap"] = getMaxFreeBlockHeap(true);
|
||||
doc["system"]["resetReason"] = getResetReason();
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
doc["system"]["chipModel"] = esp_is_8285() ? "ESP8285" : "ESP8266";
|
||||
doc["system"]["chipRevision"] = 0;
|
||||
doc["system"]["chipCores"] = 1;
|
||||
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
||||
doc["system"]["coreVersion"] = ESP.getCoreVersion();
|
||||
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
||||
doc["system"]["flashRealSize"] = ESP.getFlashChipRealSize();
|
||||
#elif ARDUINO_ARCH_ESP32
|
||||
doc["system"]["chipModel"] = ESP.getChipModel();
|
||||
doc["system"]["chipRevision"] = ESP.getChipRevision();
|
||||
doc["system"]["chipCores"] = ESP.getChipCores();
|
||||
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
||||
doc["system"]["coreVersion"] = ESP.getSdkVersion();
|
||||
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
||||
doc["system"]["flashRealSize"] = doc["system"]["flashSize"];
|
||||
#else
|
||||
doc["system"]["chipModel"] = 0;
|
||||
doc["system"]["chipRevision"] = 0;
|
||||
doc["system"]["chipCores"] = 0;
|
||||
doc["system"]["cpuFreq"] = 0;
|
||||
doc["system"]["coreVersion"] = 0;
|
||||
doc["system"]["flashSize"] = 0;
|
||||
doc["system"]["flashRealSize"] = 0;
|
||||
#endif
|
||||
|
||||
|
||||
doc.shrinkToFit();
|
||||
|
||||
this->bufferedWebServer->send(200, "application/json", doc);
|
||||
|
||||
@@ -192,8 +192,15 @@ protected:
|
||||
}
|
||||
|
||||
if (vars.states.emergency) {
|
||||
etRegulator.Kt = 0;
|
||||
etRegulator.indoorTemp = 0;
|
||||
if (settings.sensors.indoor.type == SensorType::MANUAL) {
|
||||
etRegulator.Kt = 0;
|
||||
etRegulator.indoorTemp = 0;
|
||||
|
||||
} else {
|
||||
etRegulator.Kt = settings.equitherm.t_factor;
|
||||
etRegulator.indoorTemp = indoorTemp;
|
||||
}
|
||||
|
||||
etRegulator.outdoorTemp = outdoorTemp;
|
||||
|
||||
} else if (settings.pid.enable) {
|
||||
|
||||
@@ -65,7 +65,7 @@ protected:
|
||||
bool indoorTempUpdated = false;
|
||||
bool outdoorTempUpdated = false;
|
||||
|
||||
if (settings.sensors.outdoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.indoor.gpio)) {
|
||||
if (settings.sensors.outdoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.outdoor.gpio)) {
|
||||
outdoorTemperatureSensor();
|
||||
outdoorTempUpdated = true;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ struct Settings {
|
||||
byte inGpio = DEFAULT_OT_IN_GPIO;
|
||||
byte outGpio = DEFAULT_OT_OUT_GPIO;
|
||||
byte rxLedGpio = DEFAULT_OT_RX_LED_GPIO;
|
||||
byte faultStateGpio = DEFAULT_OT_FAULT_STATE_GPIO;
|
||||
byte invertFaultState = false;
|
||||
unsigned int memberIdCode = 0;
|
||||
bool dhwPresent = true;
|
||||
bool summerWinterMode = false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define PROJECT_NAME "OpenTherm Gateway"
|
||||
#define PROJECT_VERSION "1.4.0-rc.24"
|
||||
#define PROJECT_VERSION "1.4.0"
|
||||
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
|
||||
|
||||
#define MQTT_RECONNECT_INTERVAL 15000
|
||||
@@ -103,6 +103,10 @@
|
||||
#define DEFAULT_OT_RX_LED_GPIO GPIO_IS_NOT_CONFIGURED
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_OT_FAULT_STATE_GPIO
|
||||
#define DEFAULT_OT_FAULT_STATE_GPIO GPIO_IS_NOT_CONFIGURED
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SENSOR_OUTDOOR_GPIO
|
||||
#define DEFAULT_SENSOR_OUTDOOR_GPIO GPIO_IS_NOT_CONFIGURED
|
||||
#endif
|
||||
|
||||
36
src/utils.h
36
src/utils.h
@@ -342,6 +342,8 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
||||
dst["opentherm"]["inGpio"] = src.opentherm.inGpio;
|
||||
dst["opentherm"]["outGpio"] = src.opentherm.outGpio;
|
||||
dst["opentherm"]["rxLedGpio"] = src.opentherm.rxLedGpio;
|
||||
dst["opentherm"]["faultStateGpio"] = src.opentherm.faultStateGpio;
|
||||
dst["opentherm"]["invertFaultState"] = src.opentherm.invertFaultState;
|
||||
dst["opentherm"]["memberIdCode"] = src.opentherm.memberIdCode;
|
||||
dst["opentherm"]["dhwPresent"] = src.opentherm.dhwPresent;
|
||||
dst["opentherm"]["summerWinterMode"] = src.opentherm.summerWinterMode;
|
||||
@@ -642,6 +644,32 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
||||
}
|
||||
}
|
||||
|
||||
if (!src["opentherm"]["faultStateGpio"].isNull()) {
|
||||
if (src["opentherm"]["faultStateGpio"].is<JsonString>() && src["opentherm"]["faultStateGpio"].as<JsonString>().size() == 0) {
|
||||
if (dst.opentherm.faultStateGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||
dst.opentherm.faultStateGpio = GPIO_IS_NOT_CONFIGURED;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
unsigned char value = src["opentherm"]["faultStateGpio"].as<unsigned char>();
|
||||
|
||||
if (GPIO_IS_VALID(value) && value != dst.opentherm.faultStateGpio) {
|
||||
dst.opentherm.faultStateGpio = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (src["opentherm"]["invertFaultState"].is<bool>()) {
|
||||
bool value = src["opentherm"]["invertFaultState"].as<bool>();
|
||||
|
||||
if (value != dst.opentherm.invertFaultState) {
|
||||
dst.opentherm.invertFaultState = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!src["opentherm"]["memberIdCode"].isNull()) {
|
||||
unsigned int value = src["opentherm"]["memberIdCode"].as<unsigned int>();
|
||||
|
||||
@@ -652,8 +680,12 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
||||
}
|
||||
|
||||
if (src["opentherm"]["dhwPresent"].is<bool>()) {
|
||||
dst.opentherm.dhwPresent = src["opentherm"]["dhwPresent"].as<bool>();
|
||||
changed = true;
|
||||
bool value = src["opentherm"]["dhwPresent"].as<bool>();
|
||||
|
||||
if (value != dst.opentherm.dhwPresent) {
|
||||
dst.opentherm.dhwPresent = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (src["opentherm"]["summerWinterMode"].is<bool>()) {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Version:</th>
|
||||
<td><b id="version"></b></td>
|
||||
<td><b id="version"></b>, core/sdk: <b id="core-version"></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Build date:</th>
|
||||
@@ -101,6 +101,10 @@
|
||||
<th scope="row">Free memory:</th>
|
||||
<td><b id="free-heap"></b> of <b id="total-heap"></b> bytes (min: <b id="min-free-heap"></b> bytes)<br />max free block: <b id="max-free-block-heap"></b> bytes (min: <b id="min-max-free-block-heap"></b> bytes)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Board:</th>
|
||||
<td>Chip <b id="chip-model"></b> (rev. <span id="chip-revision"></span>)<br />Cores: <b id="chip-cores"></b>, frequency: <b id="cpu-freq"></b> mHz<br />Flash size: <b id="flash-size"></b> MB (real: <b id="flash-real-size"></b> MB)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Last reset reason:</th>
|
||||
<td><b id="reset-reason"></b></td>
|
||||
@@ -164,6 +168,15 @@
|
||||
setValue('#max-free-block-heap', result.system.maxFreeBlockHeap);
|
||||
setValue('#min-max-free-block-heap', result.system.minMaxFreeBlockHeap);
|
||||
setValue('#reset-reason', result.system.resetReason);
|
||||
|
||||
setValue('#chip-model', result.system.chipModel);
|
||||
setValue('#chip-revision', result.system.chipRevision);
|
||||
setValue('#chip-cores', result.system.chipCores);
|
||||
setValue('#cpu-freq', result.system.cpuFreq);
|
||||
setValue('#core-version', result.system.coreVersion);
|
||||
setValue('#flash-size', result.system.flashSize / 1024 / 1024);
|
||||
setValue('#flash-real-size', result.system.flashRealSize / 1024 / 1024);
|
||||
|
||||
setBusy('#system-busy', '#system-table', false);
|
||||
|
||||
} catch (error) {
|
||||
|
||||
@@ -435,6 +435,20 @@
|
||||
<input type="checkbox" id="opentherm-get-min-max-temp" name="opentherm[getMinMaxTemp]" value="true">
|
||||
Get min/max temp from boiler
|
||||
</label>
|
||||
|
||||
<hr />
|
||||
<fieldset>
|
||||
<label for="opentherm-fault-state-gpio">
|
||||
Fault state GPIO
|
||||
<input type="number" inputmode="numeric" id="opentherm-fault-state-gpio" name="opentherm[faultStateGpio]" min="0" max="254" step="1">
|
||||
<small>Can be useful to switch on another boiler <u>via relay</u>. Blank - not use.</small>
|
||||
</label>
|
||||
|
||||
<label for="opentherm-invert-fault-state">
|
||||
<input type="checkbox" id="opentherm-invert-fault-state" name="opentherm[invertFaultState]" value="true">
|
||||
Invert fault state
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<hr />
|
||||
<label for="opentherm-native-heating-control">
|
||||
@@ -680,6 +694,8 @@
|
||||
setInputValue('#opentherm-in-gpio', data.opentherm.inGpio < 255 ? data.opentherm.inGpio : '');
|
||||
setInputValue('#opentherm-out-gpio', data.opentherm.outGpio < 255 ? data.opentherm.outGpio : '');
|
||||
setInputValue('#opentherm-rx-led-gpio', data.opentherm.rxLedGpio < 255 ? data.opentherm.rxLedGpio : '');
|
||||
setInputValue('#opentherm-fault-state-gpio', data.opentherm.faultStateGpio < 255 ? data.opentherm.faultStateGpio : '');
|
||||
setCheckboxValue('#opentherm-invert-fault-state', data.opentherm.invertFaultState);
|
||||
setInputValue('#opentherm-member-id-code', data.opentherm.memberIdCode);
|
||||
setCheckboxValue('#opentherm-dhw-present', data.opentherm.dhwPresent);
|
||||
setCheckboxValue('#opentherm-sw-mode', data.opentherm.summerWinterMode);
|
||||
|
||||
Reference in New Issue
Block a user