7 Commits

5 changed files with 74 additions and 61 deletions

View File

@@ -7,7 +7,7 @@ public:
typedef std::function<void(unsigned long, byte)> BeforeSendRequestCallback; typedef std::function<void(unsigned long, byte)> BeforeSendRequestCallback;
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback; typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback;
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {} CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {}
~CustomOpenTherm() {} ~CustomOpenTherm() {}
CustomOpenTherm* setDelayCallback(DelayCallback callback = nullptr) { CustomOpenTherm* setDelayCallback(DelayCallback callback = nullptr) {
@@ -28,8 +28,8 @@ public:
return this; return this;
} }
unsigned long sendRequest(unsigned long request, byte attempts = 5, byte _attempt = 0) { unsigned long sendRequest(unsigned long request) override {
_attempt++; this->sendRequestAttempt++;
while (!this->isReady()) { while (!this->isReady()) {
if (this->delayCallback) { if (this->delayCallback) {
@@ -40,15 +40,10 @@ public:
} }
if (this->beforeSendRequestCallback) { if (this->beforeSendRequestCallback) {
this->beforeSendRequestCallback(request, _attempt); this->beforeSendRequestCallback(request, this->sendRequestAttempt);
} }
unsigned long _response; if (this->sendRequestAsync(request)) {
OpenThermResponseStatus _responseStatus = OpenThermResponseStatus::NONE;
if (!this->sendRequestAsync(request)) {
_response = 0;
} else {
do { do {
if (this->delayCallback) { if (this->delayCallback) {
this->delayCallback(150); this->delayCallback(150);
@@ -56,42 +51,25 @@ public:
this->process(); this->process();
} while (this->status != OpenThermStatus::READY && this->status != OpenThermStatus::DELAY); } while (this->status != OpenThermStatus::READY && this->status != OpenThermStatus::DELAY);
_response = this->getLastResponse();
_responseStatus = this->getLastResponseStatus();
} }
if (this->afterSendRequestCallback) { if (this->afterSendRequestCallback) {
this->afterSendRequestCallback(request, _response, _responseStatus, _attempt); this->afterSendRequestCallback(request, this->response, this->responseStatus, this->sendRequestAttempt);
} }
if (_responseStatus == OpenThermResponseStatus::SUCCESS || _responseStatus == OpenThermResponseStatus::INVALID || _attempt >= attempts) { if (this->responseStatus == OpenThermResponseStatus::SUCCESS || this->responseStatus == OpenThermResponseStatus::INVALID) {
return _response; this->sendRequestAttempt = 0;
return this->response;
} else if (this->sendRequestAttempt >= this->sendRequestMaxAttempts) {
this->sendRequestAttempt = 0;
return this->response;
} else { } else {
return this->sendRequest(request, attempts, _attempt); return this->sendRequest(request);
} }
} }
unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2, bool summerWinterMode, bool dhwBlocking, uint8_t lb = 0) {
unsigned int data = enableCentralHeating
| (enableHotWater << 1)
| (enableCooling << 2)
| (enableOutsideTemperatureCompensation << 3)
| (enableCentralHeating2 << 4)
| (summerWinterMode << 5)
| (dhwBlocking << 6);
data <<= 8;
data |= lb;
return this->sendRequest(buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::Status,
data
));
}
bool sendBoilerReset() { bool sendBoilerReset() {
unsigned int data = 1; unsigned int data = 1;
data <<= 8; data <<= 8;
@@ -134,6 +112,27 @@ public:
return (byte)id == responseId; return (byte)id == responseId;
} }
static uint8_t getResponseMessageTypeId(unsigned long response) {
return (response << 1) >> 29;
}
static const char* getResponseMessageTypeString(unsigned long response) {
uint8_t msgType = getResponseMessageTypeId(response);
switch (msgType) {
case (uint8_t) OpenThermMessageType::READ_ACK:
case (uint8_t) OpenThermMessageType::WRITE_ACK:
case (uint8_t) OpenThermMessageType::DATA_INVALID:
case (uint8_t) OpenThermMessageType::UNKNOWN_DATA_ID:
return CustomOpenTherm::messageTypeToString(
static_cast<OpenThermMessageType>(msgType)
);
default:
return "UNKNOWN";
}
}
// converters // converters
template <class T> template <class T>
static unsigned int toFloat(const T val) { static unsigned int toFloat(const T val) {
@@ -145,6 +144,8 @@ public:
} }
protected: protected:
const uint8_t sendRequestMaxAttempts = 5;
uint8_t sendRequestAttempt = 0;
DelayCallback delayCallback; DelayCallback delayCallback;
BeforeSendRequestCallback beforeSendRequestCallback; BeforeSendRequestCallback beforeSendRequestCallback;
AfterSendRequestCallback afterSendRequestCallback; AfterSendRequestCallback afterSendRequestCallback;

View File

@@ -19,7 +19,7 @@ framework = arduino
lib_deps = lib_deps =
bblanchon/ArduinoJson@^7.3.0 bblanchon/ArduinoJson@^7.3.0
;ihormelnyk/OpenTherm Library@^1.1.5 ;ihormelnyk/OpenTherm Library@^1.1.5
https://github.com/ihormelnyk/opentherm_library#master https://github.com/Laxilef/opentherm_library#esp32_timer
arduino-libraries/ArduinoMqttClient@^0.1.8 arduino-libraries/ArduinoMqttClient@^0.1.8
lennarthennigs/ESP Telnet@^2.2 lennarthennigs/ESP Telnet@^2.2
gyverlibs/FileData@^1.0.2 gyverlibs/FileData@^1.0.2
@@ -84,7 +84,7 @@ board_build.ldscript = eagle.flash.4m1m.ld
;platform_packages = ;platform_packages =
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5 ; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip ; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
platform_packages = platform_packages =
board_build.partitions = esp32_partitions.csv board_build.partitions = esp32_partitions.csv
lib_deps = lib_deps =

View File

@@ -196,6 +196,7 @@ protected:
// critical heap // critical heap
if (!vars.states.restarting && (freeHeap < 2048 || maxFreeBlockHeap < 2048)) { if (!vars.states.restarting && (freeHeap < 2048 || maxFreeBlockHeap < 2048)) {
this->restartSignalReceivedTime = millis(); this->restartSignalReceivedTime = millis();
this->restartSignalReceived = true;
vars.states.restarting = true; vars.states.restarting = true;
} }

View File

@@ -93,8 +93,13 @@ protected:
this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) { this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) {
Log.sverboseln( Log.sverboseln(
FPSTR(L_OT), FPSTR(L_OT),
F("ID: %4d Request: %8lx Response: %8lx Attempt: %2d Status: %s"), F("ID: %4d Request: %8lx Response: %8lx Msg type: %s Attempt: %2d Status: %s"),
CustomOpenTherm::getDataID(request), request, response, attempt, CustomOpenTherm::statusToString(status) CustomOpenTherm::getDataID(request),
request,
response,
CustomOpenTherm::getResponseMessageTypeString(response),
attempt,
CustomOpenTherm::statusToString(status)
); );
if (status == OpenThermResponseStatus::SUCCESS) { if (status == OpenThermResponseStatus::SUCCESS) {
@@ -138,7 +143,12 @@ protected:
return; return;
} else if (this->instance->status == OpenThermStatus::NOT_INITIALIZED) { } else if (this->instance->status == OpenThermStatus::NOT_INITIALIZED) {
this->instance->begin(); if (!this->instance->begin()) {
Log.swarningln(FPSTR(L_OT), F("Failed begin"));
this->delay(5000);
return;
}
} }
// RX LED GPIO setup // RX LED GPIO setup
@@ -212,6 +222,20 @@ protected:
F("Failed receive boiler status: %s"), F("Failed receive boiler status: %s"),
CustomOpenTherm::statusToString(this->instance->getLastResponseStatus()) CustomOpenTherm::statusToString(this->instance->getLastResponseStatus())
); );
} else {
vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response);
vars.slave.dhw.active = settings.opentherm.options.dhwSupport ? CustomOpenTherm::isHotWaterActive(response) : false;
vars.slave.flame = CustomOpenTherm::isFlameOn(response);
vars.slave.cooling = CustomOpenTherm::isCoolingActive(response);
vars.slave.fault.active = CustomOpenTherm::isFault(response);
vars.slave.diag.active = CustomOpenTherm::isDiagnostic(response);
Log.snoticeln(
FPSTR(L_OT), F("Received boiler status. Heating: %hhu; DHW: %hhu; flame: %hhu; cooling: %hhu; fault: %hhu; diag: %hhu"),
vars.slave.heating.active, vars.slave.dhw.active,
vars.slave.flame, vars.slave.cooling, vars.slave.fault.active, vars.slave.diag.active
);
} }
// 5 request retries // 5 request retries
@@ -310,19 +334,6 @@ protected:
Log.sinfoln(FPSTR(L_OT_DHW), vars.master.dhw.enabled ? F("Enabled") : F("Disabled")); Log.sinfoln(FPSTR(L_OT_DHW), vars.master.dhw.enabled ? F("Enabled") : F("Disabled"));
} }
vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response);
vars.slave.dhw.active = settings.opentherm.options.dhwSupport ? CustomOpenTherm::isHotWaterActive(response) : false;
vars.slave.flame = CustomOpenTherm::isFlameOn(response);
vars.slave.cooling = CustomOpenTherm::isCoolingActive(response);
vars.slave.fault.active = CustomOpenTherm::isFault(response);
vars.slave.diag.active = CustomOpenTherm::isDiagnostic(response);
Log.snoticeln(
FPSTR(L_OT), F("Received boiler status. Heating: %hhu; DHW: %hhu; flame: %hhu; cooling: %hhu; fault: %hhu; diag: %hhu"),
vars.slave.heating.active, vars.slave.dhw.active,
vars.slave.flame, vars.slave.cooling, vars.slave.fault.active, vars.slave.diag.active
);
// These parameters will be updated every minute // These parameters will be updated every minute
if (millis() - this->prevUpdateNonEssentialVars > 60000) { if (millis() - this->prevUpdateNonEssentialVars > 60000) {
if (this->updateMinModulationLevel()) { if (this->updateMinModulationLevel()) {
@@ -1179,17 +1190,17 @@ protected:
bool needSetDhwTemp(const float target) { bool needSetDhwTemp(const float target) {
return millis() - this->dhwSetTempTime > this->dhwSetTempInterval return millis() - this->dhwSetTempTime > this->dhwSetTempInterval
|| fabsf(target - vars.slave.dhw.targetTemp) > 0.001f; || fabsf(target - vars.slave.dhw.targetTemp) > 0.05f;
} }
bool needSetHeatingTemp(const float target) { bool needSetHeatingTemp(const float target) {
return millis() - this->heatingSetTempTime > this->heatingSetTempInterval return millis() - this->heatingSetTempTime > this->heatingSetTempInterval
|| fabsf(target - vars.slave.heating.targetTemp) > 0.001f; || fabsf(target - vars.slave.heating.targetTemp) > 0.05f;
} }
bool needSetCh2Temp(const float target) { bool needSetCh2Temp(const float target) {
return millis() - this->ch2SetTempTime > this->ch2SetTempInterval return millis() - this->ch2SetTempTime > this->ch2SetTempInterval
|| fabsf(target - vars.slave.ch2.targetTemp) > 0.001f; || fabsf(target - vars.slave.ch2.targetTemp) > 0.05f;
} }
bool updateSlaveConfig() { bool updateSlaveConfig() {
@@ -1350,7 +1361,7 @@ protected:
return CustomOpenTherm::getUInt(response) == request; return CustomOpenTherm::getUInt(response) == request;
} }
bool setMaxHeatingTemp(const uint8_t temperature) { bool setMaxHeatingTemp(const float temperature) {
const unsigned int request = CustomOpenTherm::temperatureToData(temperature); const unsigned int request = CustomOpenTherm::temperatureToData(temperature);
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest( const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::WRITE_DATA, OpenThermMessageType::WRITE_DATA,

View File

@@ -60,11 +60,11 @@ protected:
this->hysteresis(); this->hysteresis();
vars.master.heating.targetTemp = settings.heating.target; vars.master.heating.targetTemp = settings.heating.target;
vars.master.heating.setpointTemp = constrain( vars.master.heating.setpointTemp = roundf(constrain(
this->getHeatingSetpointTemp(), this->getHeatingSetpointTemp(),
this->getHeatingMinSetpointTemp(), this->getHeatingMinSetpointTemp(),
this->getHeatingMaxSetpointTemp() this->getHeatingMaxSetpointTemp()
); ), 0);
Sensors::setValueByType( Sensors::setValueByType(
Sensors::Type::HEATING_SETPOINT_TEMP, vars.master.heating.setpointTemp, Sensors::Type::HEATING_SETPOINT_TEMP, vars.master.heating.setpointTemp,