#include #include class CustomOpenTherm : public OpenTherm { public: typedef std::function DelayCallback; typedef std::function BeforeSendRequestCallback; typedef std::function AfterSendRequestCallback; CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {} ~CustomOpenTherm() {} CustomOpenTherm* setDelayCallback(DelayCallback callback = nullptr) { this->delayCallback = callback; return this; } CustomOpenTherm* setBeforeSendRequestCallback(BeforeSendRequestCallback callback = nullptr) { this->beforeSendRequestCallback = callback; return this; } CustomOpenTherm* setAfterSendRequestCallback(AfterSendRequestCallback callback = nullptr) { this->afterSendRequestCallback = callback; return this; } unsigned long sendRequest(unsigned long request) override { this->sendRequestAttempt++; while (!this->isReady()) { if (this->delayCallback) { this->delayCallback(150); } this->process(); } if (this->beforeSendRequestCallback) { this->beforeSendRequestCallback(request, this->sendRequestAttempt); } if (this->sendRequestAsync(request)) { do { if (this->delayCallback) { this->delayCallback(150); } this->process(); } while (this->status != OpenThermStatus::READY && this->status != OpenThermStatus::DELAY); } if (this->afterSendRequestCallback) { this->afterSendRequestCallback(request, this->response, this->responseStatus, this->sendRequestAttempt); } if (this->responseStatus == OpenThermResponseStatus::SUCCESS || this->responseStatus == OpenThermResponseStatus::INVALID) { this->sendRequestAttempt = 0; return this->response; } else if (this->sendRequestAttempt >= this->sendRequestMaxAttempts) { this->sendRequestAttempt = 0; return this->response; } else { return this->sendRequest(request); } } inline auto sendBoilerReset() { return this->sendRequestCode(1); } inline auto sendServiceReset() { return this->sendRequestCode(10); } inline auto sendWaterFilling() { return this->sendRequestCode(2); } bool sendRequestCode(const uint8_t requestCode) { unsigned long response = this->sendRequest(buildRequest( OpenThermMessageType::WRITE_DATA, OpenThermMessageID::RemoteRequest, static_cast(requestCode) << 8 )); if (!isValidResponse(response) || !isValidResponseId(response, OpenThermMessageID::RemoteRequest)) { return false; } const uint8_t responseRequestCode = (response & 0xFFFF) >> 8; const uint8_t responseCode = response & 0xFF; if (responseRequestCode != requestCode || responseCode < 128) { return false; } // reset this->sendRequest(buildRequest( OpenThermMessageType::WRITE_DATA, OpenThermMessageID::RemoteRequest, 0u << 8 )); return true; } bool getStr(OpenThermMessageID id, char* buffer, uint16_t length = 50) { if (buffer == nullptr || length == 0) { return false; } unsigned long response; uint8_t index = 0; uint8_t maxIndex = 255; while (index <= maxIndex && index < length) { response = this->sendRequest(buildRequest( OpenThermMessageType::READ_DATA, id, static_cast(index) << 8 )); if (!isValidResponse(response) || !isValidResponseId(response, id)) { break; } const uint8_t character = response & 0xFF; if (character == 0) { break; } if (index == 0) { maxIndex = (response & 0xFFFF) >> 8; } buffer[index++] = static_cast(character); } buffer[index] = '\0'; return index > 0; } static bool isCh2Active(unsigned long response) { return response & 0x20; } static bool isValidResponseId(unsigned long response, OpenThermMessageID id) { const uint8_t responseId = (response >> 16) & 0xFF; return static_cast(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 static_cast(OpenThermMessageType::READ_ACK): case static_cast(OpenThermMessageType::WRITE_ACK): case static_cast(OpenThermMessageType::DATA_INVALID): case static_cast(OpenThermMessageType::UNKNOWN_DATA_ID): return CustomOpenTherm::messageTypeToString( static_cast(msgType) ); default: return "UNKNOWN"; } } // converters template static unsigned int toFloat(const T val) { return (unsigned int)(val * 256); } static short getInt(const unsigned long response) { return response & 0xffff; } protected: const uint8_t sendRequestMaxAttempts = 5; uint8_t sendRequestAttempt = 0; DelayCallback delayCallback; BeforeSendRequestCallback beforeSendRequestCallback; AfterSendRequestCallback afterSendRequestCallback; };