From 0956a94c383e59aff9558d858b9c8d89ee7f529c Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 22 Mar 2023 20:04:39 +0100 Subject: [PATCH] Improve code reability. --- components/truma_inetbox/TrumaEnums.h | 2 + components/truma_inetbox/TrumaStatusFrame.cpp | 92 ------ components/truma_inetbox/TrumaStatusFrame.h | 28 -- .../truma_inetbox/TrumaStatusFrameBuilder.h | 38 +++ .../TrumaStausFrameResponseStorage.h | 27 +- .../truma_inetbox/TrumaStausFrameStorage.h | 32 ++- components/truma_inetbox/TrumaStructs.h | 54 ++++ components/truma_inetbox/TrumaiNetBoxApp.cpp | 195 +++++-------- components/truma_inetbox/TrumaiNetBoxApp.h | 98 +------ .../TrumaiNetBoxAppAirconAuto.cpp | 23 ++ .../truma_inetbox/TrumaiNetBoxAppAirconAuto.h | 2 + .../TrumaiNetBoxAppAirconManual.cpp | 24 ++ .../TrumaiNetBoxAppAirconManual.h | 2 + .../truma_inetbox/TrumaiNetBoxAppClock.cpp | 66 +++++ .../truma_inetbox/TrumaiNetBoxAppClock.h | 22 +- .../truma_inetbox/TrumaiNetBoxAppConfig.cpp | 15 + .../truma_inetbox/TrumaiNetBoxAppConfig.h | 4 +- .../truma_inetbox/TrumaiNetBoxAppHeater.cpp | 168 +++++++++++ .../truma_inetbox/TrumaiNetBoxAppHeater.h | 11 +- .../truma_inetbox/TrumaiNetBoxAppTimer.cpp | 124 ++++++++ .../truma_inetbox/TrumaiNetBoxAppTimer.h | 8 + .../TrumaiNetBoxApp_automation.cpp | 270 ------------------ components/truma_inetbox/automation.h | 27 +- .../climate/TrumaRoomClimate.cpp | 14 +- .../climate/TrumaWaterClimate.cpp | 6 +- components/truma_inetbox/helpers.cpp | 2 - components/truma_inetbox/helpers.h | 3 +- .../number/TrumaHeaterNumber.cpp | 6 +- 28 files changed, 716 insertions(+), 647 deletions(-) delete mode 100644 components/truma_inetbox/TrumaStatusFrame.cpp delete mode 100644 components/truma_inetbox/TrumaStatusFrame.h create mode 100644 components/truma_inetbox/TrumaStatusFrameBuilder.h create mode 100644 components/truma_inetbox/TrumaiNetBoxAppClock.cpp create mode 100644 components/truma_inetbox/TrumaiNetBoxAppConfig.cpp delete mode 100644 components/truma_inetbox/TrumaiNetBoxApp_automation.cpp diff --git a/components/truma_inetbox/TrumaEnums.h b/components/truma_inetbox/TrumaEnums.h index fbad428..26ae40f 100644 --- a/components/truma_inetbox/TrumaEnums.h +++ b/components/truma_inetbox/TrumaEnums.h @@ -1,5 +1,7 @@ #pragma once +#include "esphome/core/helpers.h" + namespace esphome { namespace truma_inetbox { diff --git a/components/truma_inetbox/TrumaStatusFrame.cpp b/components/truma_inetbox/TrumaStatusFrame.cpp deleted file mode 100644 index 567326d..0000000 --- a/components/truma_inetbox/TrumaStatusFrame.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "TrumaStatusFrame.h" -#include "esphome/core/helpers.h" -#include "TrumaiNetBoxApp.h" -#include "helpers.h" - -namespace esphome { -namespace truma_inetbox { -void status_frame_create_empty(StatusFrame *response, u_int8_t message_type, u_int8_t message_length, - u_int8_t command_counter) { - response->inner.genericHeader.service_identifier = LIN_SID_READ_STATE_BUFFER | LIN_SID_RESPONSE; - // Copy header over for this message. - for (size_t i = 1; i < truma_message_header.size(); i++) { - response->raw[i] = truma_message_header[i]; - } - response->inner.genericHeader.header_2 = 'T'; - response->inner.genericHeader.header_3 = 0x01; - response->inner.genericHeader.message_type = message_type; - response->inner.genericHeader.message_length = message_length; - response->inner.genericHeader.command_counter = command_counter; -} - -void status_frame_calculate_checksum(StatusFrame *response) { - response->inner.genericHeader.checksum = 0x0; - response->inner.genericHeader.checksum = data_checksum(&response->raw[10], sizeof(StatusFrame) - 10, 0); -} - -void status_frame_create_init(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) { - status_frame_create_empty(response, STATUS_FRAME_RESPONSE_INIT_REQUEST, 0, command_counter); - - // Init frame is empty. - - status_frame_calculate_checksum(response); - (*response_len) = sizeof(StatusFrameHeader) + 0; -} - -void status_frame_create_update_clock(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter, - u_int8_t hour, u_int8_t minute, u_int8_t second, ClockMode clockMode) { - status_frame_create_empty(response, STATUS_FRAME_CLOCK_RESPONSE, sizeof(StatusFrameClock), command_counter); - - response->inner.clock.clock_hour = hour; - response->inner.clock.clock_minute = minute; - response->inner.clock.clock_second = second; - response->inner.clock.display_1 = 0x1; - response->inner.clock.display_2 = 0x1; - response->inner.clock.clock_mode = clockMode; - - status_frame_calculate_checksum(response); - (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameClock); -} - -void status_frame_create_update_timer(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter, - TimerActive active, u_int8_t start_hour, u_int8_t start_minute, - u_int8_t stop_hour, u_int8_t stop_minute, TargetTemp room, TargetTemp water, - HeatingMode mode, EnergyMix energy, ElectricPowerLevel elPower) { - status_frame_create_empty(response, STATUS_FRAME_TIMER_RESPONSE, sizeof(StatusFrameTimerResponse), command_counter); - - response->inner.timerResponse.timer_target_temp_room = room; - response->inner.timerResponse.timer_heating_mode = mode; - response->inner.timerResponse.timer_target_temp_water = water; - response->inner.timerResponse.timer_energy_mix_a = energy; - response->inner.timerResponse.timer_energy_mix_b = energy; - response->inner.timerResponse.timer_el_power_level_a = elPower; - response->inner.timerResponse.timer_el_power_level_b = elPower; - response->inner.timerResponse.timer_resp_active = active; - response->inner.timerResponse.timer_resp_start_hours = start_hour; - response->inner.timerResponse.timer_resp_start_minutes = start_minute; - response->inner.timerResponse.timer_resp_stop_hours = stop_hour; - response->inner.timerResponse.timer_resp_stop_minutes = stop_minute; - - status_frame_calculate_checksum(response); - (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameTimerResponse); -} - -void status_frame_create_update_heater(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter, - TargetTemp room, TargetTemp water, HeatingMode mode, EnergyMix energy, - ElectricPowerLevel elPower) { - status_frame_create_empty(response, STATUS_FRAME_HEATER_RESPONSE, sizeof(StatusFrameHeaterResponse), command_counter); - - response->inner.heaterResponse.target_temp_room = room; - response->inner.heaterResponse.heating_mode = mode; - response->inner.heaterResponse.target_temp_water = water; - response->inner.heaterResponse.energy_mix_a = energy; - response->inner.heaterResponse.energy_mix_b = energy; - response->inner.heaterResponse.el_power_level_a = elPower; - response->inner.heaterResponse.el_power_level_b = elPower; - - status_frame_calculate_checksum(response); - (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameHeaterResponse); -} - -} // namespace truma_inetbox -} // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaStatusFrame.h b/components/truma_inetbox/TrumaStatusFrame.h deleted file mode 100644 index b6f0c1d..0000000 --- a/components/truma_inetbox/TrumaStatusFrame.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "TrumaiNetBoxApp.h" - -namespace esphome { -namespace truma_inetbox { - -void status_frame_create_empty(StatusFrame *response, u_int8_t message_type, u_int8_t message_length, - u_int8_t command_counter); - -void status_frame_calculate_checksum(StatusFrame *response); - -void status_frame_create_init(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter); - -void status_frame_create_update_clock(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter, - u_int8_t hour, u_int8_t minute, u_int8_t second, ClockMode clockMode); - -void status_frame_create_update_timer(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter, - TimerActive active, u_int8_t start_hour, u_int8_t start_minute, - u_int8_t stop_hour, u_int8_t stop_minute, TargetTemp room, TargetTemp water, - HeatingMode mode, EnergyMix energy, ElectricPowerLevel elPower); - -void status_frame_create_update_heater(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter, - TargetTemp room, TargetTemp water, HeatingMode mode, EnergyMix energy, - ElectricPowerLevel elPower); - -} // namespace truma_inetbox -} // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaStatusFrameBuilder.h b/components/truma_inetbox/TrumaStatusFrameBuilder.h new file mode 100644 index 0000000..65d4a54 --- /dev/null +++ b/components/truma_inetbox/TrumaStatusFrameBuilder.h @@ -0,0 +1,38 @@ +#pragma once + +#include "TrumaStructs.h" +#include "helpers.h" + +namespace esphome { +namespace truma_inetbox { + +inline void status_frame_create_empty(StatusFrame *response, u_int8_t message_type, u_int8_t message_length, + u_int8_t command_counter) { + response->inner.genericHeader.service_identifier = LIN_SID_READ_STATE_BUFFER | LIN_SID_RESPONSE; + // Copy header over for this message. + for (size_t i = 1; i < truma_message_header.size(); i++) { + response->raw[i] = truma_message_header[i]; + } + response->inner.genericHeader.header_2 = 'T'; + response->inner.genericHeader.header_3 = 0x01; + response->inner.genericHeader.message_type = message_type; + response->inner.genericHeader.message_length = message_length; + response->inner.genericHeader.command_counter = command_counter; +} + +inline void status_frame_calculate_checksum(StatusFrame *response) { + response->inner.genericHeader.checksum = 0x0; + response->inner.genericHeader.checksum = data_checksum(&response->raw[10], sizeof(StatusFrame) - 10, 0); +} + +inline void status_frame_create_init(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) { + status_frame_create_empty(response, STATUS_FRAME_RESPONSE_INIT_REQUEST, 0, command_counter); + + // Init frame is empty. + + status_frame_calculate_checksum(response); + (*response_len) = sizeof(StatusFrameHeader) + 0; +} + +} // namespace truma_inetbox +} // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaStausFrameResponseStorage.h b/components/truma_inetbox/TrumaStausFrameResponseStorage.h index 2755c86..ba58024 100644 --- a/components/truma_inetbox/TrumaStausFrameResponseStorage.h +++ b/components/truma_inetbox/TrumaStausFrameResponseStorage.h @@ -1,16 +1,39 @@ #pragma once #include "TrumaStausFrameStorage.h" +#include "TrumaStructs.h" +#include "esphome/core/helpers.h" namespace esphome { namespace truma_inetbox { -template class TrumaStausFrameResponseStorage : public TrumaStausFrameStorage { +class TrumaiNetBoxApp; + +template +class TrumaStausFrameResponseStorage : public TrumaStausFrameStorage, public Parented { public: - void reset(); + void reset() override { + TrumaStausFrameStorage::reset(); + this->update_status_prepared_ = false; + this->update_status_unsubmitted_ = false; + this->update_status_stale_ = false; + } bool can_update() { return this->data_valid_; } virtual TResponse *update_prepare() = 0; void update_submit() { this->update_status_unsubmitted_ = true; } + const bool has_update() const { return this->update_status_unsubmitted_; } + void set_status(T val) override { + TrumaStausFrameStorage::set_status(val); + this->update_status_stale_ = false; + }; + virtual void create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) = 0; + + protected: + inline void update_submitted() { + this->update_status_prepared_ = false; + this->update_status_unsubmitted_ = false; + this->update_status_stale_ = true; + } // Prepared means `update_status_` was copied from `data_`. bool update_status_prepared_ = false; diff --git a/components/truma_inetbox/TrumaStausFrameStorage.h b/components/truma_inetbox/TrumaStausFrameStorage.h index f436674..a324573 100644 --- a/components/truma_inetbox/TrumaStausFrameStorage.h +++ b/components/truma_inetbox/TrumaStausFrameStorage.h @@ -7,19 +7,35 @@ namespace truma_inetbox { template class TrumaStausFrameStorage { public: + bool get_status_valid() { return this->data_valid_; }; + const T *get_status() { return &this->data_; }; + virtual void set_status(T val) { + this->data_ = val; + this->data_valid_ = true; + this->data_updated_ = true; + this->dump_data(); + }; + void update() { + if (this->data_updated_) { + this->state_callback_.call(&this->data_); + } + this->data_updated_ = false; + }; + virtual void reset() { + this->data_valid_ = false; + this->data_updated_ = false; + }; + void add_on_message_callback(std::function callback) { + this->state_callback_.add(std::move(callback)); + }; + virtual void dump_data() const = 0; + + protected: CallbackManager state_callback_{}; T data_; bool data_valid_ = false; // Value has changed notify listeners. bool data_updated_ = false; - - void add_on_message_callback(std::function callback) { - this->state_callback_.add(std::move(callback)); - } - bool get_status_valid() { return this->data_valid_; } - const T *get_status() { return &this->data_; } - void update(); - void reset(); }; } // namespace truma_inetbox diff --git a/components/truma_inetbox/TrumaStructs.h b/components/truma_inetbox/TrumaStructs.h index 21ee20e..c841e67 100644 --- a/components/truma_inetbox/TrumaStructs.h +++ b/components/truma_inetbox/TrumaStructs.h @@ -5,6 +5,37 @@ namespace esphome { namespace truma_inetbox { +#define LIN_SID_RESPONSE 0x40 +#define LIN_SID_READ_STATE_BUFFER 0xBA +#define LIN_SID_FIll_STATE_BUFFFER 0xBB + +// Response to init are the following frames: +// - 2 * STATUS_FRAME_DEVICES +// - STATUS_FRAME_HEATER +// - STATUS_FRAME_TIMER +// - STAUTS_FRAME_CONFIG +// - STATUS_FRAME_CLOCK +#define STATUS_FRAME_RESPONSE_INIT_REQUEST 0x0A +#define STATUS_FRAME_DEVICES 0x0B +#define STATUS_FRAME_RESPONSE_ACK 0x0D +#define STATUS_FRAME_CLOCK_RESPONSE (STATUS_FRAME_CLOCK - 1) +#define STATUS_FRAME_CLOCK 0x15 +// TODO: Documentation and testing of config response. +#define STAUTS_FRAME_CONFIG_RESPONSE (STAUTS_FRAME_CONFIG - 1) +#define STAUTS_FRAME_CONFIG 0x17 +#define STATUS_FRAME_HEATER_RESPONSE (STATUS_FRAME_HEATER - 1) +#define STATUS_FRAME_HEATER 0x33 +#define STATUS_FRAME_AIRCON_MANUAL_RESPONSE (STATUS_FRAME_AIRCON_MANUAL - 1) +#define STATUS_FRAME_AIRCON_MANUAL 0x35 +#define STATUS_FRAME_AIRCON_AUTO_RESPONSE (STATUS_FRAME_AIRCON_AUTO - 1) +#define STATUS_FRAME_AIRCON_AUTO 0x37 +#define STATUS_FRAME_TIMER_RESPONSE (STATUS_FRAME_TIMER - 1) +#define STATUS_FRAME_TIMER 0x3D +#define STATUS_FRAME_AIRCON_MANUAL_INIT_RESPONSE (STATUS_FRAME_AIRCON_MANUAL_INIT - 1) +#define STATUS_FRAME_AIRCON_MANUAL_INIT 0x3F +#define STATUS_FRAME_AIRCON_AUTO_INIT_RESPONSE (STATUS_FRAME_AIRCON_AUTO_INIT - 1) +#define STATUS_FRAME_AIRCON_AUTO_INIT 0x41 + struct StatusFrameHeader { // NOLINT(altera-struct-pack-align) // sid u_int8_t service_identifier; @@ -269,5 +300,28 @@ struct StatusFrameAirconAutoInit { // NOLINT(altera-struct-pack-align) u_int8_t unknown_20; // 0x00 } __attribute__((packed)); +union StatusFrame { // NOLINT(altera-struct-pack-align) + u_int8_t raw[41]; + struct inner { // NOLINT(altera-struct-pack-align) + StatusFrameHeader genericHeader; + union { // NOLINT(altera-struct-pack-align) + StatusFrameHeater heater; + StatusFrameHeaterResponse heaterResponse; + StatusFrameTimer timer; + StatusFrameTimerResponse timerResponse; + StatusFrameResponseAck responseAck; + StatusFrameClock clock; + StatusFrameConfig config; + StatusFrameDevice device; + StatusFrameAirconManual airconManual; + StatusFrameAirconManualResponse airconManualResponse; + StatusFrameAirconManualInit airconManualInit; + StatusFrameAirconAuto airconAuto; + StatusFrameAirconAutoResponse airconAutoResponse; + StatusFrameAirconAutoInit airconAutoInit; + } __attribute__((packed)); + } inner; +} __attribute__((packed)); + } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxApp.cpp b/components/truma_inetbox/TrumaiNetBoxApp.cpp index 4e96e8b..4ad0162 100644 --- a/components/truma_inetbox/TrumaiNetBoxApp.cpp +++ b/components/truma_inetbox/TrumaiNetBoxApp.cpp @@ -1,5 +1,5 @@ #include "TrumaiNetBoxApp.h" -#include "TrumaStatusFrame.h" +#include "TrumaStatusFrameBuilder.h" #include "esphome/core/log.h" #include "esphome/core/helpers.h" #include "helpers.h" @@ -9,15 +9,26 @@ namespace truma_inetbox { static const char *const TAG = "truma_inetbox.TrumaiNetBoxApp"; +TrumaiNetBoxApp::TrumaiNetBoxApp() { + this->airconAuto_.set_parent(this); + this->airconManual_.set_parent(this); + this->clock_.set_parent(this); + // this->config_.set_parent(this); + this->heater_.set_parent(this); + this->timer_.set_parent(this); +} + void TrumaiNetBoxApp::update() { // Call listeners in after method 'lin_multiframe_recieved' call. // Because 'lin_multiframe_recieved' is time critical an all these sensors can take some time. // Run through callbacks - heater_.update(); - timer_.update(); - clock_.update(); - config_.update(); + this->airconAuto_.update(); + this->airconManual_.update(); + this->clock_.update(); + this->config_.update(); + this->heater_.update(); + this->timer_.update(); LinBusProtocol::update(); @@ -29,19 +40,12 @@ void TrumaiNetBoxApp::update() { if (this->time_ != nullptr && !this->update_status_clock_done && this->init_recieved_ > 0) { if (micros() > ((30 * 1000 * 1000) + this->init_recieved_ /* 30 seconds after init recieved */)) { this->update_status_clock_done = true; - this->action_write_time(); + this->clock_.action_write_time(); } } #endif // USE_TIME } -template void TrumaStausFrameStorage::update() { - if (this->data_updated_) { - this->state_callback_.call(&this->data_); - } - this->data_updated_ = false; -} - const std::array TrumaiNetBoxApp::lin_identifier() { // Supplier Id: 0x4617 - Truma (Phone: +49 (0)89 4617-0) // Unknown: @@ -71,27 +75,16 @@ void TrumaiNetBoxApp::lin_reset_device() { this->device_registered_ = micros(); this->init_recieved_ = 0; - this->heater_.reset(); - this->timer_.reset(); + this->airconAuto_.reset(); this->airconManual_.reset(); this->clock_.reset(); this->config_.reset(); + this->heater_.reset(); + this->timer_.reset(); this->update_time_ = 0; } -template void TrumaStausFrameStorage::reset() { - this->data_valid_ = false; - this->data_updated_ = false; -} - -template void TrumaStausFrameResponseStorage::reset() { - TrumaStausFrameStorage::reset(); - this->update_status_prepared_ = false; - this->update_status_unsubmitted_ = false; - this->update_status_stale_ = false; -} - bool TrumaiNetBoxApp::answer_lin_order_(const u_int8_t pid) { // Alive message if (pid == LIN_PID_TRUMA_INET_BOX) { @@ -155,64 +148,31 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message ESP_LOGD(TAG, "Requested read: Sending init"); status_frame_create_init(response_frame, return_len, this->message_counter++); return response; - } else if (this->heater_.update_status_unsubmitted_) { + } else if (this->heater_.has_update()) { ESP_LOGD(TAG, "Requested read: Sending heater update"); - status_frame_create_update_heater( - response_frame, return_len, this->message_counter++, this->heater_.update_status_.target_temp_room, - this->heater_.update_status_.target_temp_water, this->heater_.update_status_.heating_mode, - this->heater_.update_status_.energy_mix_a, this->heater_.update_status_.el_power_level_a); - + this->heater_.create_update_data(response_frame, return_len, this->message_counter++); this->update_time_ = 0; - this->heater_.update_status_prepared_ = false; - this->heater_.update_status_unsubmitted_ = false; - this->heater_.update_status_stale_ = true; return response; - } else if (this->timer_.update_status_unsubmitted_) { + } else if (this->timer_.has_update()) { ESP_LOGD(TAG, "Requested read: Sending timer update"); - status_frame_create_update_timer( - response_frame, return_len, this->message_counter++, this->timer_.update_status_.timer_resp_active, - this->timer_.update_status_.timer_resp_start_hours, this->timer_.update_status_.timer_resp_start_minutes, - this->timer_.update_status_.timer_resp_stop_hours, this->timer_.update_status_.timer_resp_stop_minutes, - this->timer_.update_status_.timer_target_temp_room, this->timer_.update_status_.timer_target_temp_water, - this->timer_.update_status_.timer_heating_mode, this->timer_.update_status_.timer_energy_mix_a, - this->timer_.update_status_.timer_el_power_level_a); - + this->timer_.create_update_data(response_frame, return_len, this->message_counter++); this->update_time_ = 0; - this->timer_.update_status_prepared_ = false; - this->timer_.update_status_unsubmitted_ = false; - this->timer_.update_status_stale_ = true; return response; - } else if (this->airconManual_.update_status_unsubmitted_) { - ESP_LOGD(TAG, "Requested read: Sending aircon update"); - - status_frame_create_empty(response_frame, STATUS_FRAME_AIRCON_MANUAL_RESPONSE, sizeof(StatusFrameAirconManualResponse), - this->message_counter++); - - response_frame->inner.airconManualResponse.mode = this->airconManual_.update_status_.mode; - response_frame->inner.airconManualResponse.unknown_02 = this->airconManual_.update_status_.unknown_02; - response_frame->inner.airconManualResponse.operation = this->airconManual_.update_status_.operation; - response_frame->inner.airconManualResponse.energy_mix = this->airconManual_.update_status_.energy_mix; - response_frame->inner.airconManualResponse.target_temp_aircon = this->airconManual_.update_status_.target_temp_aircon; - - status_frame_calculate_checksum(response_frame); - (*return_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameAirconManualResponse); - + } else if (this->airconManual_.has_update()) { + ESP_LOGD(TAG, "Requested read: Sending aircon manual update"); + this->airconManual_.create_update_data(response_frame, return_len, this->message_counter++); + this->update_time_ = 0; + return response; + } else if (this->airconAuto_.has_update()) { + ESP_LOGD(TAG, "Requested read: Sending aircon auto update"); + this->airconAuto_.create_update_data(response_frame, return_len, this->message_counter++); this->update_time_ = 0; - this->airconManual_.update_status_prepared_ = false; - this->airconManual_.update_status_unsubmitted_ = false; - this->airconManual_.update_status_stale_ = true; return response; #ifdef USE_TIME - } else if (this->update_status_clock_unsubmitted_) { - if (this->time_ != nullptr) { - ESP_LOGD(TAG, "Requested read: Sending clock update"); - // read time live - auto now = this->time_->now(); - - status_frame_create_update_clock(response_frame, return_len, this->message_counter++, now.hour, now.minute, - now.second, this->clock_.data_.clock_mode); - } - this->update_status_clock_unsubmitted_ = false; + } else if (this->clock_.has_update()) { + ESP_LOGD(TAG, "Requested read: Sending clock update"); + this->clock_.create_update_data(response_frame, return_len, this->message_counter++); + this->update_time_ = 0; return response; #endif // USE_TIME } else { @@ -242,13 +202,10 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message // Example: // SID<---------PREAMBLE---------->|<---MSG_HEAD---->|tRoom|mo| |elecA|tWate|elecB|mi|mi|cWate|cRoom|st|err | | // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.14.33.00.12.00.00.00.00.00.00.00.00.00.00.01.01.CC.0B.6C.0B.00.00.00.00 - this->heater_.data_ = statusFrame->inner.heater; - this->heater_.data_valid_ = true; - this->heater_.data_updated_ = true; - - this->heater_.update_status_stale_ = false; + this->heater_.set_status(statusFrame->inner.heater); return response; - } else if (header->message_type == STATUS_FRAME_AIRCON_MANUAL && header->message_length == sizeof(StatusFrameAirconManual)) { + } else if (header->message_type == STATUS_FRAME_AIRCON_MANUAL && + header->message_length == sizeof(StatusFrameAirconManual)) { ESP_LOGI(TAG, "StatusFrameAirconManual"); // Example: // SID<---------PREAMBLE---------->|<---MSG_HEAD---->| @@ -269,11 +226,7 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.12.35.00.C2.04.00.71.01.D6.0B.00.00.88.0B.00.00.00.00.00.00.AA.0A // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.12.35.00.13.04.00.71.01.86.0B.00.00.88.0B.00.00.00.00.00.00.AA.0A // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.12.35.00.A8.00.00.71.01.00.00.00.00.88.0B.00.00.00.00.00.00.AA.0A - this->airconManual_.data_ = statusFrame->inner.airconManual; - this->airconManual_.data_valid_ = true; - this->airconManual_.data_updated_ = true; - - this->airconManual_.update_status_stale_ = false; + this->airconManual_.set_status(statusFrame->inner.airconManual); return response; } else if (header->message_type == STATUS_FRAME_AIRCON_MANUAL_INIT && header->message_length == sizeof(StatusFrameAirconManualInit)) { @@ -282,11 +235,13 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message // SID<---------PREAMBLE---------->|<---MSG_HEAD---->| // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.16.3F.00.E2.00.00.71.01.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00 return response; - } else if (header->message_type == STATUS_FRAME_AIRCON_AUTO && header->message_length == sizeof(StatusFrameAirconAuto)) { + } else if (header->message_type == STATUS_FRAME_AIRCON_AUTO && + header->message_length == sizeof(StatusFrameAirconAuto)) { ESP_LOGI(TAG, "StatusFrameAirconAuto"); // Example: // SID<---------PREAMBLE---------->|<---MSG_HEAD---->| // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.12.37.00.BF.01.00.01.00.00.00.00.00.00.00.00.00.00.00.49.0B.40.0B + this->airconAuto_.set_status(statusFrame->inner.airconAuto); return response; } else if (header->message_type == STATUS_FRAME_AIRCON_AUTO_INIT && header->message_length == sizeof(StatusFrameAirconAutoInit)) { @@ -301,18 +256,26 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message // SID<---------PREAMBLE---------->|<---MSG_HEAD---->|tRoom|mo|??|elecA|tWate|elecB|mi|mi|<--response-->|??|??|on|start|stop-| // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.18.3D.00.1D.18.0B.01.00.00.00.00.00.00.00.01.01.00.00.00.00.00.00.00.01.00.08.00.09 // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.18.3D.00.13.18.0B.0B.00.00.00.00.00.00.00.01.01.00.00.00.00.00.00.00.01.00.08.00.09 - this->timer_.data_ = statusFrame->inner.timer; - this->timer_.data_valid_ = true; - this->timer_.data_updated_ = true; - - this->timer_.update_status_stale_ = false; - - ESP_LOGD(TAG, "StatusFrameTimer target_temp_room: %f target_temp_water: %f %02u:%02u -> %02u:%02u %s", - temp_code_to_decimal(this->timer_.data_.timer_target_temp_room), - temp_code_to_decimal(this->timer_.data_.timer_target_temp_water), this->timer_.data_.timer_start_hours, - this->timer_.data_.timer_start_minutes, this->timer_.data_.timer_stop_hours, - this->timer_.data_.timer_stop_minutes, ((u_int8_t) this->timer_.data_.timer_active ? " ON" : " OFF")); + this->timer_.set_status(statusFrame->inner.timer); + return response; + } else if (header->message_type == STATUS_FRAME_CLOCK && header->message_length == sizeof(StatusFrameClock)) { + ESP_LOGI(TAG, "StatusFrameClock"); + // Example: + // SID<---------PREAMBLE---------->|<---MSG_HEAD---->| + // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.15.00.5B.0D.20.00.01.01.00.00.01.00.00 + // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.15.00.71.16.00.00.01.01.00.00.02.00.00 + // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.15.00.2B.16.1F.28.01.01.00.00.01.00.00 + this->clock_.set_status(statusFrame->inner.clock); + return response; + } else if (header->message_type == STAUTS_FRAME_CONFIG && header->message_length == sizeof(StatusFrameConfig)) { + ESP_LOGI(TAG, "StatusFrameConfig"); + // Example: + // SID<---------PREAMBLE---------->|<---MSG_HEAD---->| + // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.17.00.0F.06.01.B4.0A.AA.0A.00.00.00.00 + // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.17.00.41.06.01.B4.0A.78.0A.00.00.00.00 + // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.17.00.0F.06.01.B4.0A.AA.0A.00.00.00.00 + this->config_.set_status(statusFrame->inner.config); return response; } else if (header->message_type == STATUS_FRAME_RESPONSE_ACK && header->message_length == sizeof(StatusFrameResponseAck)) { @@ -335,35 +298,6 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message this->lin_reset_device(); } - return response; - } else if (header->message_type == STATUS_FRAME_CLOCK && header->message_length == sizeof(StatusFrameClock)) { - ESP_LOGI(TAG, "StatusFrameClock"); - // Example: - // SID<---------PREAMBLE---------->|<---MSG_HEAD---->| - // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.15.00.5B.0D.20.00.01.01.00.00.01.00.00 - // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.15.00.71.16.00.00.01.01.00.00.02.00.00 - // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.15.00.2B.16.1F.28.01.01.00.00.01.00.00 - this->clock_.data_ = statusFrame->inner.clock; - this->clock_.data_valid_ = true; - this->clock_.data_updated_ = true; - - ESP_LOGD(TAG, "StatusFrameClock %02d:%02d:%02d", this->clock_.data_.clock_hour, this->clock_.data_.clock_minute, - this->clock_.data_.clock_second); - - return response; - } else if (header->message_type == STAUTS_FRAME_CONFIG && header->message_length == sizeof(StatusFrameConfig)) { - ESP_LOGI(TAG, "StatusFrameConfig"); - // Example: - // SID<---------PREAMBLE---------->|<---MSG_HEAD---->| - // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.17.00.0F.06.01.B4.0A.AA.0A.00.00.00.00 - // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.17.00.41.06.01.B4.0A.78.0A.00.00.00.00 - // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0A.17.00.0F.06.01.B4.0A.AA.0A.00.00.00.00 - this->config_.data_ = statusFrame->inner.config; - this->config_.data_valid_ = true; - this->config_.data_updated_ = true; - - ESP_LOGD(TAG, "StatusFrameConfig Offset: %.1f", temp_code_to_decimal(this->config_.data_.temp_offset)); - return response; } else if (header->message_type == STATUS_FRAME_DEVICES && header->message_length == sizeof(StatusFrameDevice)) { ESP_LOGI(TAG, "StatusFrameDevice"); @@ -380,7 +314,6 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0C.0B.00.C7.03.00.01.00.50.00.00.04.03.00.60.10 // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0C.0B.00.71.03.01.01.00.10.03.02.06.00.02.00.00 // BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0C.0B.00.7C.03.02.01.00.01.0C.00.01.02.01.00.00 - auto device = statusFrame->inner.device; this->init_recieved_ = micros(); @@ -439,8 +372,8 @@ bool TrumaiNetBoxApp::has_update_to_submit_() { this->init_requested_ = micros(); return true; } - } else if (this->heater_.update_status_unsubmitted_ || this->timer_.update_status_unsubmitted_ || - this->update_status_clock_unsubmitted_ || this->airconManual_.update_status_unsubmitted_) { + } else if (this->airconAuto_.has_update() || this->airconManual_.has_update() || this->clock_.has_update() || + this->heater_.has_update() || this->timer_.has_update()) { if (this->update_time_ == 0) { // ESP_LOGD(TAG, "Notify CP Plus I got updates."); this->update_time_ = micros(); diff --git a/components/truma_inetbox/TrumaiNetBoxApp.h b/components/truma_inetbox/TrumaiNetBoxApp.h index 139a2df..fca977a 100644 --- a/components/truma_inetbox/TrumaiNetBoxApp.h +++ b/components/truma_inetbox/TrumaiNetBoxApp.h @@ -1,18 +1,13 @@ #pragma once -#include #include "LinBusProtocol.h" -#include "esphome/core/automation.h" -#include "TrumaEnums.h" +#include "TrumaStructs.h" #include "TrumaiNetBoxAppAirconAuto.h" #include "TrumaiNetBoxAppAirconManual.h" #include "TrumaiNetBoxAppClock.h" #include "TrumaiNetBoxAppConfig.h" #include "TrumaiNetBoxAppHeater.h" #include "TrumaiNetBoxAppTimer.h" -#include "TrumaStausFrameResponseStorage.h" -#include "TrumaStausFrameStorage.h" -#include "TrumaStructs.h" #ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" @@ -22,67 +17,19 @@ namespace esphome { namespace truma_inetbox { #define LIN_PID_TRUMA_INET_BOX 0x18 -#define LIN_SID_RESPONSE 0x40 -#define LIN_SID_READ_STATE_BUFFER 0xBA -#define LIN_SID_FIll_STATE_BUFFFER 0xBB - -// Response to init are the following frames: -// - 2 * STATUS_FRAME_DEVICES -// - STATUS_FRAME_HEATER -// - STATUS_FRAME_TIMER -// - STAUTS_FRAME_CONFIG -// - STATUS_FRAME_CLOCK -#define STATUS_FRAME_RESPONSE_INIT_REQUEST 0x0A -#define STATUS_FRAME_DEVICES 0x0B -#define STATUS_FRAME_RESPONSE_ACK 0x0D -#define STATUS_FRAME_CLOCK_RESPONSE (STATUS_FRAME_CLOCK - 1) -#define STATUS_FRAME_CLOCK 0x15 -// TODO: Documentation and testing of config response. -#define STAUTS_FRAME_CONFIG_RESPONSE (STAUTS_FRAME_CONFIG - 1) -#define STAUTS_FRAME_CONFIG 0x17 -#define STATUS_FRAME_HEATER_RESPONSE (STATUS_FRAME_HEATER - 1) -#define STATUS_FRAME_HEATER 0x33 -#define STATUS_FRAME_AIRCON_MANUAL_RESPONSE (STATUS_FRAME_AIRCON_MANUAL - 1) -#define STATUS_FRAME_AIRCON_MANUAL 0x35 -#define STATUS_FRAME_AIRCON_AUTO_RESPONSE (STATUS_FRAME_AIRCON_AUTO - 1) -#define STATUS_FRAME_AIRCON_AUTO 0x37 -#define STATUS_FRAME_TIMER_RESPONSE (STATUS_FRAME_TIMER - 1) -#define STATUS_FRAME_TIMER 0x3D -#define STATUS_FRAME_AIRCON_MANUAL_INIT_RESPONSE (STATUS_FRAME_AIRCON_MANUAL_INIT - 1) -#define STATUS_FRAME_AIRCON_MANUAL_INIT 0x3F -#define STATUS_FRAME_AIRCON_AUTO_INIT_RESPONSE (STATUS_FRAME_AIRCON_AUTO_INIT - 1) -#define STATUS_FRAME_AIRCON_AUTO_INIT 0x41 - -union StatusFrame { // NOLINT(altera-struct-pack-align) - u_int8_t raw[41]; - struct inner { // NOLINT(altera-struct-pack-align) - StatusFrameHeader genericHeader; - union { // NOLINT(altera-struct-pack-align) - StatusFrameHeater heater; - StatusFrameHeaterResponse heaterResponse; - StatusFrameTimer timer; - StatusFrameTimerResponse timerResponse; - StatusFrameResponseAck responseAck; - StatusFrameClock clock; - StatusFrameConfig config; - StatusFrameDevice device; - StatusFrameAirconManual airconManual; - StatusFrameAirconManualResponse airconManualResponse; - StatusFrameAirconManualInit airconManualInit; - StatusFrameAirconAuto airconAuto; - StatusFrameAirconAutoInit airconAutoInit; - } __attribute__((packed)); - } inner; -} __attribute__((packed)); class TrumaiNetBoxApp : public LinBusProtocol { public: + TrumaiNetBoxApp(); void update() override; const std::array lin_identifier() override; void lin_heartbeat() override; void lin_reset_device() override; + const TRUMA_DEVICE get_heater_device() const { return this->heater_device_; } + const TRUMA_DEVICE get_aircon_device() const { return this->aircon_device_; } + TrumaiNetBoxAppAirconAuto *get_aircon_auto() { return &this->airconAuto_; } TrumaiNetBoxAppAirconManual *get_aircon_manual() { return &this->airconManual_; } TrumaiNetBoxAppClock *get_clock() { return &this->clock_; } @@ -92,23 +39,9 @@ class TrumaiNetBoxApp : public LinBusProtocol { int64_t get_last_cp_plus_request() { return this->device_registered_; } - bool action_heater_room(u_int8_t temperature, HeatingMode mode = HeatingMode::HEATING_MODE_OFF); - bool action_heater_water(u_int8_t temperature); - bool action_heater_water(TargetTemp temperature); - bool action_heater_electric_power_level(u_int16_t value); - bool action_heater_energy_mix(EnergyMix energy_mix, - ElectricPowerLevel el_power_level = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0); - bool action_timer_disable(); - bool action_timer_activate(u_int16_t start, u_int16_t stop, u_int8_t room_temperature, - HeatingMode mode = HeatingMode::HEATING_MODE_OFF, u_int8_t water_temperature = 0, - EnergyMix energy_mix = EnergyMix::ENERGY_MIX_NONE, - ElectricPowerLevel el_power_level = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0); - #ifdef USE_TIME void set_time(time::RealTimeClock *time) { time_ = time; } - bool truma_clock_can_update() { return this->clock_.data_valid_; } - void update_clock_submit() { this->update_status_clock_unsubmitted_ = true; } - bool action_write_time(); + time::RealTimeClock *get_time() const { return time_; } #endif // USE_TIME protected: @@ -122,12 +55,12 @@ class TrumaiNetBoxApp : public LinBusProtocol { TRUMA_DEVICE heater_device_ = TRUMA_DEVICE::HEATER_COMBI4; TRUMA_DEVICE aircon_device_ = TRUMA_DEVICE::UNKNOWN; - TrumaiNetBoxAppAirconAuto airconAuto_{}; - TrumaiNetBoxAppAirconManual airconManual_{}; - TrumaiNetBoxAppClock clock_{}; - TrumaiNetBoxAppConfig config_{}; - TrumaiNetBoxAppHeater heater_{}; - TrumaiNetBoxAppTimer timer_{}; + TrumaiNetBoxAppAirconAuto airconAuto_; + TrumaiNetBoxAppAirconManual airconManual_; + TrumaiNetBoxAppClock clock_; + TrumaiNetBoxAppConfig config_; + TrumaiNetBoxAppHeater heater_; + TrumaiNetBoxAppTimer timer_; // last time CP plus was informed I got an update msg. uint32_t update_time_ = 0; @@ -135,15 +68,8 @@ class TrumaiNetBoxApp : public LinBusProtocol { #ifdef USE_TIME time::RealTimeClock *time_ = nullptr; - // The behaviour of `update_status_clock_unsubmitted_` is special. - // Just an update is marked. The actual package is prepared when CP Plus asks for the data in the - // `lin_multiframe_recieved` method. - bool update_status_clock_unsubmitted_ = false; - // Mark if the initial clock sync was done. bool update_status_clock_done = false; -#else - const bool update_status_clock_unsubmitted_ = false; #endif // USE_TIME bool answer_lin_order_(const u_int8_t pid) override; diff --git a/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.cpp b/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.cpp index ece4dfd..780c9a9 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.cpp +++ b/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.cpp @@ -1,8 +1,13 @@ #include "TrumaiNetBoxAppAirconAuto.h" +#include "TrumaStatusFrameBuilder.h" +#include "esphome/core/log.h" +#include "helpers.h" namespace esphome { namespace truma_inetbox { +static const char *const TAG = "truma_inetbox.TrumaiNetBoxAppAirconAuto"; + StatusFrameAirconAutoResponse *TrumaiNetBoxAppAirconAuto::update_prepare() { // An update is currently going on. if (this->update_status_prepared_ || this->update_status_stale_) { @@ -20,5 +25,23 @@ StatusFrameAirconAutoResponse *TrumaiNetBoxAppAirconAuto::update_prepare() { return &this->update_status_; } +void TrumaiNetBoxAppAirconAuto::create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter){ + + status_frame_create_empty(response, STATUS_FRAME_AIRCON_AUTO_RESPONSE, sizeof(StatusFrameAirconAutoResponse), + command_counter); + + // response->inner.airconAutoResponse.mode = this->update_status_.mode; + // response->inner.airconAutoResponse.unknown_02 = this->update_status_.unknown_02; + // response->inner.airconAutoResponse.operation = this->update_status_.operation; + // response->inner.airconAutoResponse.energy_mix = this->update_status_.energy_mix; + // response->inner.airconAutoResponse.target_temp_aircon = this->update_status_.target_temp_aircon; + + status_frame_calculate_checksum(response); + (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameAirconAutoResponse); + TrumaStausFrameResponseStorage::update_submitted(); +} + +void TrumaiNetBoxAppAirconAuto::dump_data() const {} + } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.h b/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.h index 538e705..9c1d1ff 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.h +++ b/components/truma_inetbox/TrumaiNetBoxAppAirconAuto.h @@ -10,6 +10,8 @@ class TrumaiNetBoxAppAirconAuto : public TrumaStausFrameResponseStorage { public: StatusFrameAirconAutoResponse *update_prepare() override; + void create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) override; + void dump_data() const override; }; } // namespace truma_inetbox diff --git a/components/truma_inetbox/TrumaiNetBoxAppAirconManual.cpp b/components/truma_inetbox/TrumaiNetBoxAppAirconManual.cpp index 0bc8577..d2a46ca 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppAirconManual.cpp +++ b/components/truma_inetbox/TrumaiNetBoxAppAirconManual.cpp @@ -1,8 +1,13 @@ #include "TrumaiNetBoxAppAirconManual.h" +#include "TrumaStatusFrameBuilder.h" +#include "esphome/core/log.h" +#include "helpers.h" namespace esphome { namespace truma_inetbox { +static const char *const TAG = "truma_inetbox.TrumaiNetBoxAppAirconManual"; + StatusFrameAirconManualResponse *TrumaiNetBoxAppAirconManual::update_prepare() { // An update is currently going on. if (this->update_status_prepared_ || this->update_status_stale_) { @@ -20,5 +25,24 @@ StatusFrameAirconManualResponse *TrumaiNetBoxAppAirconManual::update_prepare() { return &this->update_status_; } +void TrumaiNetBoxAppAirconManual::create_update_data(StatusFrame *response, u_int8_t *response_len, + u_int8_t command_counter) { + status_frame_create_empty(response, STATUS_FRAME_AIRCON_MANUAL_RESPONSE, sizeof(StatusFrameAirconManualResponse), + command_counter); + + response->inner.airconManualResponse.mode = this->update_status_.mode; + response->inner.airconManualResponse.unknown_02 = this->update_status_.unknown_02; + response->inner.airconManualResponse.operation = this->update_status_.operation; + response->inner.airconManualResponse.energy_mix = this->update_status_.energy_mix; + response->inner.airconManualResponse.target_temp_aircon = this->update_status_.target_temp_aircon; + + status_frame_calculate_checksum(response); + (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameAirconManualResponse); + + TrumaStausFrameResponseStorage::update_submitted(); +} + +void TrumaiNetBoxAppAirconManual::dump_data() const {} + } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppAirconManual.h b/components/truma_inetbox/TrumaiNetBoxAppAirconManual.h index 6cd0348..8a209cf 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppAirconManual.h +++ b/components/truma_inetbox/TrumaiNetBoxAppAirconManual.h @@ -10,6 +10,8 @@ class TrumaiNetBoxAppAirconManual : public TrumaStausFrameResponseStorage { public: StatusFrameAirconManualResponse *update_prepare() override; + void create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) override; + void dump_data() const override; }; } // namespace truma_inetbox diff --git a/components/truma_inetbox/TrumaiNetBoxAppClock.cpp b/components/truma_inetbox/TrumaiNetBoxAppClock.cpp new file mode 100644 index 0000000..cdfd71a --- /dev/null +++ b/components/truma_inetbox/TrumaiNetBoxAppClock.cpp @@ -0,0 +1,66 @@ +#include "TrumaiNetBoxAppClock.h" +#include "TrumaStatusFrameBuilder.h" +#include "esphome/core/log.h" +#include "helpers.h" +#include "TrumaiNetBoxApp.h" + +namespace esphome { +namespace truma_inetbox { + +static const char *const TAG = "truma_inetbox.TrumaiNetBoxAppClock"; + +void TrumaiNetBoxAppClock::dump_data() const { + ESP_LOGD(TAG, "StatusFrameClock %02d:%02d:%02d", this->data_.clock_hour, this->data_.clock_minute, + this->data_.clock_second); +} + +#ifdef USE_TIME +bool TrumaiNetBoxAppClock::action_write_time() { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + + if (this->parent_->get_time() == nullptr) { + ESP_LOGW(TAG, "Missing system time component."); + return false; + } + + auto now = this->parent_->get_time()->now(); + if (!now.is_valid()) { + ESP_LOGW(TAG, "Invalid system time, not syncing to CP Plus."); + return false; + } + + // The behaviour of this method is special. + // Just an update is marked. The actual package is prepared when CP Plus asks for the data in the + // `lin_multiframe_recieved` method. + this->update_submit(); + return true; +} + +void TrumaiNetBoxAppClock::create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) { + if (this->parent_->get_time() != nullptr) { + ESP_LOGD(TAG, "Requested read: Sending clock update"); + // read time live + auto now = this->parent_->get_time()->now(); + + status_frame_create_empty(response, STATUS_FRAME_CLOCK_RESPONSE, sizeof(StatusFrameClock), command_counter); + + response->inner.clock.clock_hour = now.hour; + response->inner.clock.clock_minute = now.minute; + response->inner.clock.clock_second = now.second; + response->inner.clock.display_1 = 0x1; + response->inner.clock.display_2 = 0x1; + response->inner.clock.clock_mode = this->data_.clock_mode; + + status_frame_calculate_checksum(response); + (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameClock); + } + this->update_status_unsubmitted_ = false; +} + +#endif // USE_TIME + +} // namespace truma_inetbox +} // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppClock.h b/components/truma_inetbox/TrumaiNetBoxAppClock.h index 6f44a63..b10c56e 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppClock.h +++ b/components/truma_inetbox/TrumaiNetBoxAppClock.h @@ -6,7 +6,27 @@ namespace esphome { namespace truma_inetbox { -class TrumaiNetBoxAppClock : public TrumaStausFrameStorage {}; +class TrumaiNetBoxApp; + +class TrumaiNetBoxAppClock : public TrumaStausFrameStorage, public Parented { + public: + void dump_data() const override; +#ifdef USE_TIME + bool can_update() { return this->data_valid_; } + void update_submit() { this->update_status_unsubmitted_ = true; } + const bool has_update() const { return this->update_status_unsubmitted_; } + bool action_write_time(); + void create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter); + + protected: + // The behaviour of `update_status_clock_unsubmitted_` is special. + // Just an update is marked. The actual package is prepared when CP Plus asks for the data in the + // `lin_multiframe_recieved` method. + bool update_status_unsubmitted_ = false; +#else + constexpr bool has_update() const { return false; } +#endif // USE_TIME +}; } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppConfig.cpp b/components/truma_inetbox/TrumaiNetBoxAppConfig.cpp new file mode 100644 index 0000000..6fc2be2 --- /dev/null +++ b/components/truma_inetbox/TrumaiNetBoxAppConfig.cpp @@ -0,0 +1,15 @@ +#include "TrumaiNetBoxAppConfig.h" +#include "esphome/core/log.h" +#include "helpers.h" + +namespace esphome { +namespace truma_inetbox { + +static const char *const TAG = "truma_inetbox.TrumaiNetBoxAppConfig"; + +void TrumaiNetBoxAppConfig::dump_data() const { + ESP_LOGD(TAG, "StatusFrameConfig Offset: %.1f", temp_code_to_decimal(this->config_.data_.temp_offset)); +} + +} // namespace truma_inetbox +} // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppConfig.h b/components/truma_inetbox/TrumaiNetBoxAppConfig.h index e697889..6c03204 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppConfig.h +++ b/components/truma_inetbox/TrumaiNetBoxAppConfig.h @@ -6,7 +6,9 @@ namespace esphome { namespace truma_inetbox { -class TrumaiNetBoxAppConfig : public TrumaStausFrameStorage {}; +class TrumaiNetBoxAppConfig : public TrumaStausFrameStorage { + void dump_data() const override; +}; } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppHeater.cpp b/components/truma_inetbox/TrumaiNetBoxAppHeater.cpp index e028c13..52ea65a 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppHeater.cpp +++ b/components/truma_inetbox/TrumaiNetBoxAppHeater.cpp @@ -1,8 +1,14 @@ #include "TrumaiNetBoxAppHeater.h" +#include "TrumaStatusFrameBuilder.h" +#include "esphome/core/log.h" +#include "helpers.h" +#include "TrumaiNetBoxApp.h" namespace esphome { namespace truma_inetbox { +static const char *const TAG = "truma_inetbox.TrumaiNetBoxAppHeater"; + StatusFrameHeaterResponse *TrumaiNetBoxAppHeater::update_prepare() { // An update is currently going on. if (this->update_status_prepared_ || this->update_status_stale_) { @@ -23,5 +29,167 @@ StatusFrameHeaterResponse *TrumaiNetBoxAppHeater::update_prepare() { return &this->update_status_; } +void TrumaiNetBoxAppHeater::create_update_data(StatusFrame *response, u_int8_t *response_len, + u_int8_t command_counter) { + status_frame_create_empty(response, STATUS_FRAME_HEATER_RESPONSE, sizeof(StatusFrameHeaterResponse), command_counter); + + response->inner.heaterResponse.target_temp_room = this->update_status_.target_temp_room; + response->inner.heaterResponse.heating_mode = this->update_status_.heating_mode; + response->inner.heaterResponse.target_temp_water = this->update_status_.target_temp_water; + response->inner.heaterResponse.energy_mix_a = this->update_status_.energy_mix_a; + response->inner.heaterResponse.energy_mix_b = this->update_status_.energy_mix_a; + response->inner.heaterResponse.el_power_level_a = this->update_status_.el_power_level_a; + response->inner.heaterResponse.el_power_level_b = this->update_status_.el_power_level_a; + + status_frame_calculate_checksum(response); + (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameHeaterResponse); + + TrumaStausFrameResponseStorage::update_submitted(); +} + +void TrumaiNetBoxAppHeater::dump_data() const {} + +bool TrumaiNetBoxAppHeater::action_heater_room(u_int8_t temperature, HeatingMode mode) { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + auto heater = this->update_prepare(); + + heater->target_temp_room = decimal_to_room_temp(temperature); + + // Ensure `heating_mode` and `energy_mix_a` is set. + if (heater->target_temp_room == TargetTemp::TARGET_TEMP_OFF) { + heater->heating_mode = HeatingMode::HEATING_MODE_OFF; + } else { + if (this->parent_->get_heater_device() == TRUMA_DEVICE::HEATER_VARIO) { + // If parameter `mode` contains a valid Heating mode use it or else use `AUTO`. + if (mode == HeatingMode::HEATING_MODE_VARIO_HEAT_NIGHT || mode == HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO || + mode == HeatingMode::HEATING_MODE_BOOST) { + heater->heating_mode = mode; + } else if (heater->heating_mode == HeatingMode::HEATING_MODE_OFF) { + heater->heating_mode = HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO; + } + } else { + // HEATER_COMBI + // If parameter `mode` contains a valid Heating mode use it or else use `ECO`. + if (mode == HeatingMode::HEATING_MODE_ECO || mode == HeatingMode::HEATING_MODE_HIGH || + mode == HeatingMode::HEATING_MODE_BOOST) { + heater->heating_mode = mode; + } else if (heater->heating_mode == HeatingMode::HEATING_MODE_OFF) { + heater->heating_mode = HeatingMode::HEATING_MODE_ECO; + } + } + } + if (heater->energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { + heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; + } + + this->update_submit(); + return true; +} + +bool TrumaiNetBoxAppHeater::action_heater_water(u_int8_t temperature) { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + auto heater = this->update_prepare(); + + heater->target_temp_water = decimal_to_water_temp(temperature); + + // Ensure `energy_mix_a` is set. + if (heater->target_temp_water != TargetTemp::TARGET_TEMP_OFF && heater->energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { + heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; + } + + this->update_submit(); + return true; +} + +bool TrumaiNetBoxAppHeater::action_heater_water(TargetTemp temperature) { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + auto heater = this->update_prepare(); + + // If parameter `temperature` contains a valid mode use it or else use `OFF`. + if (temperature == TargetTemp::TARGET_TEMP_WATER_ECO || temperature == TargetTemp::TARGET_TEMP_WATER_HIGH || + temperature == TargetTemp::TARGET_TEMP_WATER_BOOST) { + heater->target_temp_water = temperature; + } else { + heater->target_temp_water = TargetTemp::TARGET_TEMP_OFF; + } + + // Ensure `energy_mix_a` is set. + if (heater->target_temp_water != TargetTemp::TARGET_TEMP_OFF && heater->energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { + heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; + } + + this->update_submit(); + return true; +} + +bool TrumaiNetBoxAppHeater::action_heater_electric_power_level(u_int16_t value) { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + auto heater = this->update_prepare(); + + heater->el_power_level_a = decimal_to_el_power_level(value); + if (heater->el_power_level_a != ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { + if (heater->energy_mix_a != EnergyMix::ENERGY_MIX_MIX && + heater->energy_mix_a != EnergyMix::ENERGY_MIX_ELECTRICITY) { + heater->energy_mix_a = EnergyMix::ENERGY_MIX_MIX; + } + } else { + heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; + } + + this->update_submit(); + return true; +} + +bool TrumaiNetBoxAppHeater::action_heater_energy_mix(EnergyMix energy_mix, ElectricPowerLevel el_power_level) { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + auto heater = this->update_prepare(); + + // If parameter `el_power_level` contains a valid mode use it. + if (el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0 || + el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900 || + el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800) { + heater->el_power_level_a = el_power_level; + } + + if (energy_mix == EnergyMix::ENERGY_MIX_GAS) { + heater->energy_mix_a = energy_mix; + heater->el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0; + } else if (energy_mix == EnergyMix::ENERGY_MIX_MIX || energy_mix == EnergyMix::ENERGY_MIX_ELECTRICITY) { + heater->energy_mix_a = energy_mix; + // Electric energy is requested by user without a power level. Set it to minimum. + if (heater->el_power_level_a == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { + heater->el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900; + } + } + + // This last check is reached if invalid `energy_mix` parameter was submitted. + if (heater->el_power_level_a != ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { + if (heater->energy_mix_a != EnergyMix::ENERGY_MIX_MIX && + heater->energy_mix_a != EnergyMix::ENERGY_MIX_ELECTRICITY) { + heater->energy_mix_a = EnergyMix::ENERGY_MIX_MIX; + } + } else { + heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; + } + + this->update_submit(); + return true; +} + } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppHeater.h b/components/truma_inetbox/TrumaiNetBoxAppHeater.h index 4278546..478ed01 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppHeater.h +++ b/components/truma_inetbox/TrumaiNetBoxAppHeater.h @@ -8,7 +8,16 @@ namespace truma_inetbox { class TrumaiNetBoxAppHeater : public TrumaStausFrameResponseStorage { public: - StatusFrameHeaterResponse* update_prepare() override; + StatusFrameHeaterResponse *update_prepare() override; + void create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) override; + void dump_data() const override; + + bool action_heater_room(u_int8_t temperature, HeatingMode mode = HeatingMode::HEATING_MODE_OFF); + bool action_heater_water(u_int8_t temperature); + bool action_heater_water(TargetTemp temperature); + bool action_heater_electric_power_level(u_int16_t value); + bool action_heater_energy_mix(EnergyMix energy_mix, + ElectricPowerLevel el_power_level = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0); }; } // namespace truma_inetbox diff --git a/components/truma_inetbox/TrumaiNetBoxAppTimer.cpp b/components/truma_inetbox/TrumaiNetBoxAppTimer.cpp index 7deb741..a0e8162 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppTimer.cpp +++ b/components/truma_inetbox/TrumaiNetBoxAppTimer.cpp @@ -1,8 +1,14 @@ #include "TrumaiNetBoxAppTimer.h" +#include "TrumaStatusFrameBuilder.h" +#include "esphome/core/log.h" +#include "helpers.h" +#include "TrumaiNetBoxApp.h" namespace esphome { namespace truma_inetbox { +static const char *const TAG = "truma_inetbox.TrumaiNetBoxAppTimer"; + StatusFrameTimerResponse *TrumaiNetBoxAppTimer::update_prepare() { // An update is currently going on. if (this->update_status_prepared_ || this->update_status_stale_) { @@ -28,5 +34,123 @@ StatusFrameTimerResponse *TrumaiNetBoxAppTimer::update_prepare() { return &this->update_status_; } +void TrumaiNetBoxAppTimer::create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) { + status_frame_create_empty(response, STATUS_FRAME_TIMER_RESPONSE, sizeof(StatusFrameTimerResponse), command_counter); + + response->inner.timerResponse.timer_target_temp_room = this->update_status_.timer_target_temp_room; + response->inner.timerResponse.timer_heating_mode = this->update_status_.timer_heating_mode; + response->inner.timerResponse.timer_target_temp_water = this->update_status_.timer_target_temp_water; + response->inner.timerResponse.timer_energy_mix_a = this->update_status_.timer_energy_mix_a; + response->inner.timerResponse.timer_energy_mix_b = this->update_status_.timer_energy_mix_a; + response->inner.timerResponse.timer_el_power_level_a = this->update_status_.timer_el_power_level_a; + response->inner.timerResponse.timer_el_power_level_b = this->update_status_.timer_el_power_level_a; + response->inner.timerResponse.timer_resp_active = this->update_status_.timer_resp_active; + response->inner.timerResponse.timer_resp_start_hours = this->update_status_.timer_resp_start_hours; + response->inner.timerResponse.timer_resp_start_minutes = this->update_status_.timer_resp_start_minutes; + response->inner.timerResponse.timer_resp_stop_hours = this->update_status_.timer_resp_stop_hours; + response->inner.timerResponse.timer_resp_stop_minutes = this->update_status_.timer_resp_stop_minutes; + + status_frame_calculate_checksum(response); + (*response_len) = sizeof(StatusFrameHeader) + sizeof(StatusFrameTimerResponse); + + TrumaStausFrameResponseStorage::update_submitted(); +} + +void TrumaiNetBoxAppTimer::dump_data() const { + ESP_LOGD(TAG, "StatusFrameTimer target_temp_room: %f target_temp_water: %f %02u:%02u -> %02u:%02u %s", + temp_code_to_decimal(this->data_.timer_target_temp_room), + temp_code_to_decimal(this->data_.timer_target_temp_water), this->data_.timer_start_hours, + this->data_.timer_start_minutes, this->data_.timer_stop_hours, this->data_.timer_stop_minutes, + ((u_int8_t) this->data_.timer_active ? " ON" : " OFF")); +} + +bool TrumaiNetBoxAppTimer::action_timer_disable() { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + auto timer = this->update_prepare(); + + timer->timer_resp_active = TimerActive::TIMER_ACTIVE_OFF; + + this->update_submit(); + return true; +} + +bool TrumaiNetBoxAppTimer::action_timer_activate(u_int16_t start, u_int16_t stop, u_int8_t room_temperature, + HeatingMode mode, u_int8_t water_temperature, EnergyMix energy_mix, + ElectricPowerLevel el_power_level) { + if (!this->can_update()) { + ESP_LOGW(TAG, "Cannot update Truma."); + return false; + } + if (start > 1440 || stop > 1440) { + ESP_LOGW(TAG, "Invalid values start/stop submitted."); + return false; + } + + auto timer = this->update_prepare(); + + timer->timer_resp_active = TimerActive::TIMER_ACTIVE_ON; + timer->timer_resp_start_hours = start / 60; + timer->timer_resp_start_minutes = start % 60; + timer->timer_resp_stop_hours = stop / 60; + timer->timer_resp_stop_minutes = stop % 60; + timer->timer_target_temp_room = decimal_to_room_temp(room_temperature); + + // Ensure `timer_heating_mode` and `timer_energy_mix_a` is set. + if (timer->timer_target_temp_room == TargetTemp::TARGET_TEMP_OFF) { + timer->timer_heating_mode = HeatingMode::HEATING_MODE_OFF; + } else { + if (this->parent_->get_heater_device() == TRUMA_DEVICE::HEATER_VARIO) { + // If parameter `mode` contains a valid Heating mode use it or else use `AUTO`. + if (mode == HeatingMode::HEATING_MODE_VARIO_HEAT_NIGHT || mode == HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO || + mode == HeatingMode::HEATING_MODE_BOOST) { + timer->timer_heating_mode = mode; + } else if (timer->timer_heating_mode == HeatingMode::HEATING_MODE_OFF) { + timer->timer_heating_mode = HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO; + } + } else { + // HEATER_COMBI + // If parameter `mode` contains a valid Heating mode use it or else use `ECO`. + if (mode == HeatingMode::HEATING_MODE_ECO || mode == HeatingMode::HEATING_MODE_HIGH || + mode == HeatingMode::HEATING_MODE_BOOST) { + timer->timer_heating_mode = mode; + } else if (timer->timer_heating_mode == HeatingMode::HEATING_MODE_OFF) { + timer->timer_heating_mode = HeatingMode::HEATING_MODE_ECO; + } + } + } + + timer->timer_target_temp_water = decimal_to_water_temp(water_temperature); + + // If parameter `el_power_level` contains a valid mode use it. + if (el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0 || + el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900 || + el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800) { + timer->timer_el_power_level_a = el_power_level; + } + + // Ensure `timer_energy_mix_a` is set + if (timer->timer_energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { + timer->timer_energy_mix_a = EnergyMix::ENERGY_MIX_GAS; + } + + // User has supplied a `energy_mix` + if (energy_mix == EnergyMix::ENERGY_MIX_GAS) { + timer->timer_energy_mix_a = energy_mix; + timer->timer_el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0; + } else if (energy_mix == EnergyMix::ENERGY_MIX_MIX || energy_mix == EnergyMix::ENERGY_MIX_ELECTRICITY) { + timer->timer_energy_mix_a = energy_mix; + // Electric energy is requested by user without a power level. Set it to minimum. + if (timer->timer_el_power_level_a == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { + timer->timer_el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900; + } + } + + this->update_submit(); + return true; +} + } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/TrumaiNetBoxAppTimer.h b/components/truma_inetbox/TrumaiNetBoxAppTimer.h index 75c23ab..a6d0470 100644 --- a/components/truma_inetbox/TrumaiNetBoxAppTimer.h +++ b/components/truma_inetbox/TrumaiNetBoxAppTimer.h @@ -9,6 +9,14 @@ namespace truma_inetbox { class TrumaiNetBoxAppTimer : public TrumaStausFrameResponseStorage { public: StatusFrameTimerResponse *update_prepare() override; + void create_update_data(StatusFrame *response, u_int8_t *response_len, u_int8_t command_counter) override; + void dump_data() const override; + + bool action_timer_disable(); + bool action_timer_activate(u_int16_t start, u_int16_t stop, u_int8_t room_temperature, + HeatingMode mode = HeatingMode::HEATING_MODE_OFF, u_int8_t water_temperature = 0, + EnergyMix energy_mix = EnergyMix::ENERGY_MIX_NONE, + ElectricPowerLevel el_power_level = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0); }; } // namespace truma_inetbox diff --git a/components/truma_inetbox/TrumaiNetBoxApp_automation.cpp b/components/truma_inetbox/TrumaiNetBoxApp_automation.cpp deleted file mode 100644 index 7b7de9f..0000000 --- a/components/truma_inetbox/TrumaiNetBoxApp_automation.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "TrumaiNetBoxApp.h" -#include "TrumaStatusFrame.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" -#include "helpers.h" - -namespace esphome { -namespace truma_inetbox { - -static const char *const TAG = "truma_inetbox.TrumaiNetBoxApp"; - -bool TrumaiNetBoxApp::action_heater_room(u_int8_t temperature, HeatingMode mode) { - if (!this->heater_.can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - auto heater = this->heater_.update_prepare(); - - heater->target_temp_room = decimal_to_room_temp(temperature); - - // Ensure `heating_mode` and `energy_mix_a` is set. - if (heater->target_temp_room == TargetTemp::TARGET_TEMP_OFF) { - heater->heating_mode = HeatingMode::HEATING_MODE_OFF; - } else { - if (this->heater_device_ == TRUMA_DEVICE::HEATER_VARIO) { - // If parameter `mode` contains a valid Heating mode use it or else use `AUTO`. - if (mode == HeatingMode::HEATING_MODE_VARIO_HEAT_NIGHT || mode == HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO || - mode == HeatingMode::HEATING_MODE_BOOST) { - heater->heating_mode = mode; - } else if (heater->heating_mode == HeatingMode::HEATING_MODE_OFF) { - heater->heating_mode = HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO; - } - } else { - // HEATER_COMBI - // If parameter `mode` contains a valid Heating mode use it or else use `ECO`. - if (mode == HeatingMode::HEATING_MODE_ECO || mode == HeatingMode::HEATING_MODE_HIGH || - mode == HeatingMode::HEATING_MODE_BOOST) { - heater->heating_mode = mode; - } else if (heater->heating_mode == HeatingMode::HEATING_MODE_OFF) { - heater->heating_mode = HeatingMode::HEATING_MODE_ECO; - } - } - } - if (heater->energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { - heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; - } - - this->heater_.update_submit(); - return true; -} - -bool TrumaiNetBoxApp::action_heater_water(u_int8_t temperature) { - if (!this->heater_.can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - auto heater = this->heater_.update_prepare(); - - heater->target_temp_water = decimal_to_water_temp(temperature); - - // Ensure `energy_mix_a` is set. - if (heater->target_temp_water != TargetTemp::TARGET_TEMP_OFF && heater->energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { - heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; - } - - this->heater_.update_submit(); - return true; -} - -bool TrumaiNetBoxApp::action_heater_water(TargetTemp temperature) { - if (!this->heater_.can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - auto heater = this->heater_.update_prepare(); - - // If parameter `temperature` contains a valid mode use it or else use `OFF`. - if (temperature == TargetTemp::TARGET_TEMP_WATER_ECO || temperature == TargetTemp::TARGET_TEMP_WATER_HIGH || - temperature == TargetTemp::TARGET_TEMP_WATER_BOOST) { - heater->target_temp_water = temperature; - } else { - heater->target_temp_water = TargetTemp::TARGET_TEMP_OFF; - } - - // Ensure `energy_mix_a` is set. - if (heater->target_temp_water != TargetTemp::TARGET_TEMP_OFF && heater->energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { - heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; - } - - this->heater_.update_submit(); - return true; -} - -bool TrumaiNetBoxApp::action_heater_electric_power_level(u_int16_t value) { - if (!this->heater_.can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - auto heater = this->heater_.update_prepare(); - - heater->el_power_level_a = decimal_to_el_power_level(value); - if (heater->el_power_level_a != ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { - if (heater->energy_mix_a != EnergyMix::ENERGY_MIX_MIX && - heater->energy_mix_a != EnergyMix::ENERGY_MIX_ELECTRICITY) { - heater->energy_mix_a = EnergyMix::ENERGY_MIX_MIX; - } - } else { - heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; - } - - this->heater_.update_submit(); - return true; -} - -bool TrumaiNetBoxApp::action_heater_energy_mix(EnergyMix energy_mix, ElectricPowerLevel el_power_level) { - if (!this->heater_.can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - auto heater = this->heater_.update_prepare(); - - // If parameter `el_power_level` contains a valid mode use it. - if (el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0 || - el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900 || - el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800) { - heater->el_power_level_a = el_power_level; - } - - if (energy_mix == EnergyMix::ENERGY_MIX_GAS) { - heater->energy_mix_a = energy_mix; - heater->el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0; - } else if (energy_mix == EnergyMix::ENERGY_MIX_MIX || energy_mix == EnergyMix::ENERGY_MIX_ELECTRICITY) { - heater->energy_mix_a = energy_mix; - // Electric energy is requested by user without a power level. Set it to minimum. - if (heater->el_power_level_a == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { - heater->el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900; - } - } - - // This last check is reached if invalid `energy_mix` parameter was submitted. - if (heater->el_power_level_a != ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { - if (heater->energy_mix_a != EnergyMix::ENERGY_MIX_MIX && - heater->energy_mix_a != EnergyMix::ENERGY_MIX_ELECTRICITY) { - heater->energy_mix_a = EnergyMix::ENERGY_MIX_MIX; - } - } else { - heater->energy_mix_a = EnergyMix::ENERGY_MIX_GAS; - } - - this->heater_.update_submit(); - return true; -} - -bool TrumaiNetBoxApp::action_timer_disable() { - if (!this->timer_.can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - auto timer = this->timer_.update_prepare(); - - timer->timer_resp_active = TimerActive::TIMER_ACTIVE_OFF; - - this->timer_.update_submit(); - return true; -} - -bool TrumaiNetBoxApp::action_timer_activate(u_int16_t start, u_int16_t stop, u_int8_t room_temperature, - HeatingMode mode, u_int8_t water_temperature, EnergyMix energy_mix, - ElectricPowerLevel el_power_level) { - if (!this->timer_.can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - if (start > 1440 || stop > 1440) { - ESP_LOGW(TAG, "Invalid values start/stop submitted."); - return false; - } - - auto timer = this->timer_.update_prepare(); - - timer->timer_resp_active = TimerActive::TIMER_ACTIVE_ON; - timer->timer_resp_start_hours = start / 60; - timer->timer_resp_start_minutes = start % 60; - timer->timer_resp_stop_hours = stop / 60; - timer->timer_resp_stop_minutes = stop % 60; - timer->timer_target_temp_room = decimal_to_room_temp(room_temperature); - - // Ensure `timer_heating_mode` and `timer_energy_mix_a` is set. - if (timer->timer_target_temp_room == TargetTemp::TARGET_TEMP_OFF) { - timer->timer_heating_mode = HeatingMode::HEATING_MODE_OFF; - } else { - if (this->heater_device_ == TRUMA_DEVICE::HEATER_VARIO) { - // If parameter `mode` contains a valid Heating mode use it or else use `AUTO`. - if (mode == HeatingMode::HEATING_MODE_VARIO_HEAT_NIGHT || mode == HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO || - mode == HeatingMode::HEATING_MODE_BOOST) { - timer->timer_heating_mode = mode; - } else if (timer->timer_heating_mode == HeatingMode::HEATING_MODE_OFF) { - timer->timer_heating_mode = HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO; - } - } else { - // HEATER_COMBI - // If parameter `mode` contains a valid Heating mode use it or else use `ECO`. - if (mode == HeatingMode::HEATING_MODE_ECO || mode == HeatingMode::HEATING_MODE_HIGH || - mode == HeatingMode::HEATING_MODE_BOOST) { - timer->timer_heating_mode = mode; - } else if (timer->timer_heating_mode == HeatingMode::HEATING_MODE_OFF) { - timer->timer_heating_mode = HeatingMode::HEATING_MODE_ECO; - } - } - } - - timer->timer_target_temp_water = decimal_to_water_temp(water_temperature); - - // If parameter `el_power_level` contains a valid mode use it. - if (el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0 || - el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900 || - el_power_level == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800) { - timer->timer_el_power_level_a = el_power_level; - } - - // Ensure `timer_energy_mix_a` is set - if (timer->timer_energy_mix_a == EnergyMix::ENERGY_MIX_NONE) { - timer->timer_energy_mix_a = EnergyMix::ENERGY_MIX_GAS; - } - - // User has supplied a `energy_mix` - if (energy_mix == EnergyMix::ENERGY_MIX_GAS) { - timer->timer_energy_mix_a = energy_mix; - timer->timer_el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0; - } else if (energy_mix == EnergyMix::ENERGY_MIX_MIX || energy_mix == EnergyMix::ENERGY_MIX_ELECTRICITY) { - timer->timer_energy_mix_a = energy_mix; - // Electric energy is requested by user without a power level. Set it to minimum. - if (timer->timer_el_power_level_a == ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0) { - timer->timer_el_power_level_a = ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900; - } - } - - this->timer_.update_submit(); - return true; -} - -#ifdef USE_TIME -bool TrumaiNetBoxApp::action_write_time() { - if (!this->truma_clock_can_update()) { - ESP_LOGW(TAG, "Cannot update Truma."); - return false; - } - - if (this->time_ == nullptr) { - ESP_LOGW(TAG, "Missing system time component."); - return false; - } - - auto now = this->time_->now(); - if (!now.is_valid()) { - ESP_LOGW(TAG, "Invalid system time, not syncing to CP Plus."); - return false; - } - - // The behaviour of this method is special. - // Just an update is marked. The actual package is prepared when CP Plus asks for the data in the - // `lin_multiframe_recieved` method. - - this->update_clock_submit(); - return true; -} -#endif // USE_TIME - -} // namespace truma_inetbox -} // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/automation.h b/components/truma_inetbox/automation.h index cb13633..462dea6 100644 --- a/components/truma_inetbox/automation.h +++ b/components/truma_inetbox/automation.h @@ -12,8 +12,8 @@ template class HeaterRoomTempAction : public Action, publ TEMPLATABLE_VALUE(HeatingMode, heating_mode) void play(Ts... x) override { - this->parent_->action_heater_room(this->temperature_.value_or(x..., 0), - this->heating_mode_.value_or(x..., HeatingMode::HEATING_MODE_OFF)); + this->parent_->get_heater()->action_heater_room(this->temperature_.value_or(x..., 0), + this->heating_mode_.value_or(x..., HeatingMode::HEATING_MODE_OFF)); } }; @@ -21,7 +21,9 @@ template class HeaterWaterTempAction : public Action, pub public: TEMPLATABLE_VALUE(u_int8_t, temperature) - void play(Ts... x) override { this->parent_->action_heater_water(this->temperature_.value_or(x..., 0)); } + void play(Ts... x) override { + this->parent_->get_heater()->action_heater_water(this->temperature_.value_or(x..., 0)); + } }; template class HeaterWaterTempEnumAction : public Action, public Parented { @@ -29,7 +31,7 @@ template class HeaterWaterTempEnumAction : public Action, TEMPLATABLE_VALUE(TargetTemp, temperature) void play(Ts... x) override { - this->parent_->action_heater_water(this->temperature_.value_or(x..., TargetTemp::TARGET_TEMP_OFF)); + this->parent_->get_heater()->action_heater_water(this->temperature_.value_or(x..., TargetTemp::TARGET_TEMP_OFF)); } }; @@ -37,7 +39,9 @@ template class HeaterElecPowerLevelAction : public Action public: TEMPLATABLE_VALUE(u_int16_t, watt) - void play(Ts... x) override { this->parent_->action_heater_electric_power_level(this->watt_.value_or(x..., 0)); } + void play(Ts... x) override { + this->parent_->get_heater()->action_heater_electric_power_level(this->watt_.value_or(x..., 0)); + } }; template class HeaterEnergyMixAction : public Action, public Parented { @@ -46,14 +50,15 @@ template class HeaterEnergyMixAction : public Action, pub TEMPLATABLE_VALUE(ElectricPowerLevel, watt) void play(Ts... x) override { - this->parent_->action_heater_energy_mix(this->energy_mix_.value_or(x..., EnergyMix::ENERGY_MIX_GAS), - this->watt_.value_or(x..., ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0)); + this->parent_->get_heater()->action_heater_energy_mix( + this->energy_mix_.value_or(x..., EnergyMix::ENERGY_MIX_GAS), + this->watt_.value_or(x..., ElectricPowerLevel::ELECTRIC_POWER_LEVEL_0)); } }; template class TimerDisableAction : public Action, public Parented { public: - void play(Ts... x) override { this->parent_->action_timer_disable(); } + void play(Ts... x) override { this->parent_->get_timer()->action_timer_disable(); } }; template class TimerActivateAction : public Action, public Parented { @@ -67,7 +72,7 @@ template class TimerActivateAction : public Action, publi TEMPLATABLE_VALUE(ElectricPowerLevel, watt) void play(Ts... x) override { - this->parent_->action_timer_activate( + this->parent_->get_timer()->action_timer_activate( this->start_.value(x...), this->stop_.value(x...), this->room_temperature_.value(x...), this->heating_mode_.value_or(x..., HeatingMode::HEATING_MODE_OFF), this->water_temperature_.value_or(x..., 0), this->energy_mix_.value_or(x..., EnergyMix::ENERGY_MIX_NONE), @@ -78,9 +83,9 @@ template class TimerActivateAction : public Action, publi #ifdef USE_TIME template class WriteTimeAction : public Action, public Parented { public: - void play(Ts... x) override { this->parent_->action_write_time(); } + void play(Ts... x) override { this->parent_->get_clock()->action_write_time(); } }; -#endif // USE_TIME +#endif // USE_TIME class TrumaiNetBoxAppHeaterMessageTrigger : public Trigger { public: diff --git a/components/truma_inetbox/climate/TrumaRoomClimate.cpp b/components/truma_inetbox/climate/TrumaRoomClimate.cpp index 03e9f2f..f140cd6 100644 --- a/components/truma_inetbox/climate/TrumaRoomClimate.cpp +++ b/components/truma_inetbox/climate/TrumaRoomClimate.cpp @@ -37,7 +37,7 @@ void TrumaRoomClimate::dump_config() { LOG_CLIMATE(TAG, "Truma Room Climate", th void TrumaRoomClimate::control(const climate::ClimateCall &call) { if (call.get_target_temperature().has_value()) { float temp = *call.get_target_temperature(); - this->parent_->action_heater_room(static_cast(temp)); + this->parent_->get_heater()->action_heater_room(static_cast(temp)); } if (call.get_mode().has_value()) { @@ -47,11 +47,11 @@ void TrumaRoomClimate::control(const climate::ClimateCall &call) { switch (mode) { case climate::CLIMATE_MODE_HEAT: if (status_heater->target_temp_room == TargetTemp::TARGET_TEMP_OFF) { - this->parent_->action_heater_room(5); + this->parent_->get_heater()->action_heater_room(5); } break; default: - this->parent_->action_heater_room(0); + this->parent_->get_heater()->action_heater_room(0); break; } } @@ -65,16 +65,16 @@ void TrumaRoomClimate::control(const climate::ClimateCall &call) { } switch (pres) { case climate::CLIMATE_PRESET_ECO: - this->parent_->action_heater_room(current_target_temp, HeatingMode::HEATING_MODE_ECO); + this->parent_->get_heater()->action_heater_room(current_target_temp, HeatingMode::HEATING_MODE_ECO); break; case climate::CLIMATE_PRESET_COMFORT: - this->parent_->action_heater_room(current_target_temp, HeatingMode::HEATING_MODE_HIGH); + this->parent_->get_heater()->action_heater_room(current_target_temp, HeatingMode::HEATING_MODE_HIGH); break; case climate::CLIMATE_PRESET_BOOST: - this->parent_->action_heater_room(current_target_temp, HeatingMode::HEATING_MODE_BOOST); + this->parent_->get_heater()->action_heater_room(current_target_temp, HeatingMode::HEATING_MODE_BOOST); break; default: - this->parent_->action_heater_room(0); + this->parent_->get_heater()->action_heater_room(0); break; } } diff --git a/components/truma_inetbox/climate/TrumaWaterClimate.cpp b/components/truma_inetbox/climate/TrumaWaterClimate.cpp index 853752c..c8dd218 100644 --- a/components/truma_inetbox/climate/TrumaWaterClimate.cpp +++ b/components/truma_inetbox/climate/TrumaWaterClimate.cpp @@ -21,7 +21,7 @@ void TrumaWaterClimate::dump_config() { LOG_CLIMATE(TAG, "Truma Climate", this); void TrumaWaterClimate::control(const climate::ClimateCall &call) { if (call.get_target_temperature().has_value()) { float temp = *call.get_target_temperature(); - this->parent_->action_heater_water(static_cast(temp)); + this->parent_->get_heater()->action_heater_water(static_cast(temp)); } if (call.get_mode().has_value()) { @@ -30,11 +30,11 @@ void TrumaWaterClimate::control(const climate::ClimateCall &call) { switch (mode) { case climate::CLIMATE_MODE_HEAT: if (status_heater->target_temp_water == TargetTemp::TARGET_TEMP_OFF) { - this->parent_->action_heater_water(40); + this->parent_->get_heater()->action_heater_water(40); } break; default: - this->parent_->action_heater_water(0); + this->parent_->get_heater()->action_heater_water(0); break; } } diff --git a/components/truma_inetbox/helpers.cpp b/components/truma_inetbox/helpers.cpp index 9a73bbf..da37b07 100644 --- a/components/truma_inetbox/helpers.cpp +++ b/components/truma_inetbox/helpers.cpp @@ -1,6 +1,4 @@ #include "helpers.h" -#include "esphome/core/helpers.h" -#include "TrumaiNetBoxApp.h" namespace esphome { namespace truma_inetbox { diff --git a/components/truma_inetbox/helpers.h b/components/truma_inetbox/helpers.h index c968dae..e5bd704 100644 --- a/components/truma_inetbox/helpers.h +++ b/components/truma_inetbox/helpers.h @@ -1,6 +1,7 @@ #pragma once -#include "TrumaiNetBoxApp.h" +#include "TrumaEnums.h" +#include "esphome/core/helpers.h" namespace esphome { namespace truma_inetbox { diff --git a/components/truma_inetbox/number/TrumaHeaterNumber.cpp b/components/truma_inetbox/number/TrumaHeaterNumber.cpp index 8f02414..a9098eb 100644 --- a/components/truma_inetbox/number/TrumaHeaterNumber.cpp +++ b/components/truma_inetbox/number/TrumaHeaterNumber.cpp @@ -26,13 +26,13 @@ void TrumaHeaterNumber::setup() { void TrumaHeaterNumber::control(float value) { switch (this->type_) { case TRUMA_NUMBER_TYPE::TARGET_ROOM_TEMPERATURE: - this->parent_->action_heater_room(static_cast(value)); + this->parent_->get_heater()->action_heater_room(static_cast(value)); break; case TRUMA_NUMBER_TYPE::TARGET_WATER_TEMPERATURE: - this->parent_->action_heater_water(static_cast(value)); + this->parent_->get_heater()->action_heater_water(static_cast(value)); break; case TRUMA_NUMBER_TYPE::ELECTRIC_POWER_LEVEL: - this->parent_->action_heater_electric_power_level(static_cast(value)); + this->parent_->get_heater()->action_heater_electric_power_level(static_cast(value)); break; } }