From 63da058f899963313b4eeb0c842fd763898f1b45 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 14 Nov 2023 22:25:26 -0500 Subject: [PATCH 01/24] update --- components/victron/victron.cpp | 88 +++++++++++++++++----------------- components/victron/victron.h | 1 + 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index c9c6bf9..e068f1c 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -93,61 +93,59 @@ void VictronComponent::loop() { ESP_LOGW(TAG, "Last transmission too long ago"); state_ = 0; } - if (!available()) return; last_transmission_ = now; - while (available()) { - uint8_t c; - read_byte(&c); - if (state_ == 0) { - if (c == '\r' || c == '\n') { - continue; - } - label_.clear(); - value_.clear(); - state_ = 1; + uint8_t c; + read_byte(&c); + if (state_ == 0) { + if (c == '\r' || c == '\n') { + return; } - if (state_ == 1) { - // Start of a ve.direct hex frame - if (c == ':') { - state_ = 3; - continue; - } - if (c == '\t') { - state_ = 2; - } else { - label_.push_back(c); - } - continue; + label_.clear(); + value_.clear(); + state_ = 1; + begin_frame_ = now; + } + if (state_ == 1) { + // Start of a ve.direct hex frame + if (c == ':') { + state_ = 3; + return; } - if (state_ == 2) { - if (label_ == "Checksum") { - state_ = 0; - // The checksum is used as end of frame indicator - if (now - this->last_publish_ >= this->throttle_) { - this->last_publish_ = now; - this->publishing_ = true; - } else { - this->publishing_ = false; - } - continue; - } - if (c == '\r' || c == '\n') { - if (this->publishing_) { - handle_value_(); - } - state_ = 0; + if (c == '\t') { + state_ = 2; + } else { + label_.push_back(c); + } + return; + } + if (state_ == 2) { + if (label_ == "Checksum") { + state_ = 0; + // The checksum is used as end of frame indicator + if (begin_frame_ - this->last_publish_ >= this->throttle_) { + this->last_publish_ = begin_frame_; + this->publishing_ = true; } else { - value_.push_back(c); + this->publishing_ = false; } + return; } - // Discard ve.direct hex frame - if (state_ == 3) { - if (c == '\r' || c == '\n') { - state_ = 0; + if (c == '\r' || c == '\n') { + if (this->publishing_) { + handle_value_(); } + state_ = 0; + } else { + value_.push_back(c); + } + } + // Discard ve.direct hex frame + if (state_ == 3) { + if (c == '\r' || c == '\n') { + state_ = 0; } } } diff --git a/components/victron/victron.h b/components/victron/victron.h index 9221006..fd74d7a 100644 --- a/components/victron/victron.h +++ b/components/victron/victron.h @@ -287,6 +287,7 @@ class VictronComponent : public uart::UARTDevice, public Component { int state_{0}; std::string label_; std::string value_; + uint32_t begin_frame_{0}; uint32_t last_transmission_{0}; uint32_t last_publish_{0}; uint32_t throttle_{0}; From 920d3a1f95065010cb4cc7cff9aff1ca919a01f9 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:06:31 -0500 Subject: [PATCH 02/24] calculate checksum --- components/victron/victron.cpp | 10 +++++++++- components/victron/victron.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index e068f1c..7cf3fc0 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -99,6 +99,7 @@ void VictronComponent::loop() { last_transmission_ = now; uint8_t c; read_byte(&c); + checksum_ += c; if (state_ == 0) { if (c == '\r' || c == '\n') { return; @@ -107,6 +108,7 @@ void VictronComponent::loop() { value_.clear(); state_ = 1; begin_frame_ = now; + return; } if (state_ == 1) { // Start of a ve.direct hex frame @@ -123,9 +125,14 @@ void VictronComponent::loop() { } if (state_ == 2) { if (label_ == "Checksum") { - state_ = 0; // The checksum is used as end of frame indicator if (begin_frame_ - this->last_publish_ >= this->throttle_) { + // check checksum + if (c != 0) { + // invalid checksum, drop frame + ESP_LOGW(TAG, "Received invalid checksum, dropping frame"); + return; + } this->last_publish_ = begin_frame_; this->publishing_ = true; } else { @@ -138,6 +145,7 @@ void VictronComponent::loop() { handle_value_(); } state_ = 0; + checksum_ = 0; } else { value_.push_back(c); } diff --git a/components/victron/victron.h b/components/victron/victron.h index fd74d7a..d30873f 100644 --- a/components/victron/victron.h +++ b/components/victron/victron.h @@ -291,6 +291,7 @@ class VictronComponent : public uart::UARTDevice, public Component { uint32_t last_transmission_{0}; uint32_t last_publish_{0}; uint32_t throttle_{0}; + uint8_t checksum_{0}; }; } // namespace victron From a4606d37dd94ad5a598f5121f85079a21cfe9a34 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:09:59 -0500 Subject: [PATCH 03/24] fix --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 7cf3fc0..18a4b40 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -120,8 +120,8 @@ void VictronComponent::loop() { state_ = 2; } else { label_.push_back(c); + return; } - return; } if (state_ == 2) { if (label_ == "Checksum") { From 55140853b60263e8363ac3173cb4b001a0e3f7a0 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:13:02 -0500 Subject: [PATCH 04/24] update --- components/victron/victron.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 18a4b40..a15bf66 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -99,17 +99,17 @@ void VictronComponent::loop() { last_transmission_ = now; uint8_t c; read_byte(&c); - checksum_ += c; if (state_ == 0) { if (c == '\r' || c == '\n') { return; } label_.clear(); value_.clear(); + checksum_ = 0; state_ = 1; begin_frame_ = now; - return; } + checksum_ += c; if (state_ == 1) { // Start of a ve.direct hex frame if (c == ':') { @@ -120,8 +120,8 @@ void VictronComponent::loop() { state_ = 2; } else { label_.push_back(c); - return; } + return; } if (state_ == 2) { if (label_ == "Checksum") { @@ -145,7 +145,6 @@ void VictronComponent::loop() { handle_value_(); } state_ = 0; - checksum_ = 0; } else { value_.push_back(c); } From ded7e3edfd08dd077265d8011ccdaa20e68a71a0 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:16:27 -0500 Subject: [PATCH 05/24] update --- components/victron/victron.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index a15bf66..d67c049 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -125,6 +125,7 @@ void VictronComponent::loop() { } if (state_ == 2) { if (label_ == "Checksum") { + state_ = 0; // The checksum is used as end of frame indicator if (begin_frame_ - this->last_publish_ >= this->throttle_) { // check checksum From 2e9de05c7297e6906acfec017d1a0dc36984c32e Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:19:47 -0500 Subject: [PATCH 06/24] check checksum --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index d67c049..1b69d06 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -129,7 +129,7 @@ void VictronComponent::loop() { // The checksum is used as end of frame indicator if (begin_frame_ - this->last_publish_ >= this->throttle_) { // check checksum - if (c != 0) { + if (checksum_ != 0) { // invalid checksum, drop frame ESP_LOGW(TAG, "Received invalid checksum, dropping frame"); return; From b9d64d392f8832d9a58505acd9eff3e4b84750ac Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:23:25 -0500 Subject: [PATCH 07/24] update --- components/victron/victron.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 1b69d06..982095d 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -99,17 +99,16 @@ void VictronComponent::loop() { last_transmission_ = now; uint8_t c; read_byte(&c); + checksum_ += c; if (state_ == 0) { if (c == '\r' || c == '\n') { return; } label_.clear(); value_.clear(); - checksum_ = 0; state_ = 1; begin_frame_ = now; } - checksum_ += c; if (state_ == 1) { // Start of a ve.direct hex frame if (c == ':') { @@ -146,6 +145,7 @@ void VictronComponent::loop() { handle_value_(); } state_ = 0; + checksum_ = 0; } else { value_.push_back(c); } @@ -154,6 +154,7 @@ void VictronComponent::loop() { if (state_ == 3) { if (c == '\r' || c == '\n') { state_ = 0; + checksum_ = 0; } } } From 1e4746055e8a46a70c6a850eeb36ad63f668cd9e Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:28:11 -0500 Subject: [PATCH 08/24] update --- components/victron/victron.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 982095d..f96454f 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -102,6 +102,7 @@ void VictronComponent::loop() { checksum_ += c; if (state_ == 0) { if (c == '\r' || c == '\n') { + checksum_ = c; return; } label_.clear(); @@ -130,7 +131,7 @@ void VictronComponent::loop() { // check checksum if (checksum_ != 0) { // invalid checksum, drop frame - ESP_LOGW(TAG, "Received invalid checksum, dropping frame"); + ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %s, calc %s", c, checksum_); return; } this->last_publish_ = begin_frame_; @@ -145,7 +146,7 @@ void VictronComponent::loop() { handle_value_(); } state_ = 0; - checksum_ = 0; + checksum_ = c; } else { value_.push_back(c); } @@ -154,7 +155,7 @@ void VictronComponent::loop() { if (state_ == 3) { if (c == '\r' || c == '\n') { state_ = 0; - checksum_ = 0; + checksum_ = c; } } } From 9bfae914615cf335a92439c3a7158c554f756644 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:29:15 -0500 Subject: [PATCH 09/24] update --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index f96454f..93da29f 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -131,7 +131,7 @@ void VictronComponent::loop() { // check checksum if (checksum_ != 0) { // invalid checksum, drop frame - ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %s, calc %s", c, checksum_); + ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %d, calc %d", c, checksum_); return; } this->last_publish_ = begin_frame_; From 5d8e42bbf9136714365200bd2d9f40c60aa407eb Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:34:56 -0500 Subject: [PATCH 10/24] checksum --- components/victron/victron.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 93da29f..2a7e9f3 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -102,7 +102,6 @@ void VictronComponent::loop() { checksum_ += c; if (state_ == 0) { if (c == '\r' || c == '\n') { - checksum_ = c; return; } label_.clear(); @@ -134,6 +133,7 @@ void VictronComponent::loop() { ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %d, calc %d", c, checksum_); return; } + checksum_ = 0; this->last_publish_ = begin_frame_; this->publishing_ = true; } else { @@ -146,7 +146,7 @@ void VictronComponent::loop() { handle_value_(); } state_ = 0; - checksum_ = c; + checksum_ = 0; } else { value_.push_back(c); } @@ -155,7 +155,7 @@ void VictronComponent::loop() { if (state_ == 3) { if (c == '\r' || c == '\n') { state_ = 0; - checksum_ = c; + checksum_ = 0; } } } From 21f6fcc297a5ea66f54a455a5840e9d8247441d1 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:39:40 -0500 Subject: [PATCH 11/24] update --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 2a7e9f3..c495169 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -131,9 +131,9 @@ void VictronComponent::loop() { if (checksum_ != 0) { // invalid checksum, drop frame ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %d, calc %d", c, checksum_); + checksum_ = 0; return; } - checksum_ = 0; this->last_publish_ = begin_frame_; this->publishing_ = true; } else { From 1102d03529b5a9f978dd129e3e37e9307b476355 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:43:43 -0500 Subject: [PATCH 12/24] update --- components/victron/victron.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index c495169..6ad2d43 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -138,6 +138,7 @@ void VictronComponent::loop() { this->publishing_ = true; } else { this->publishing_ = false; + checksum_ = 0; } return; } @@ -145,8 +146,6 @@ void VictronComponent::loop() { if (this->publishing_) { handle_value_(); } - state_ = 0; - checksum_ = 0; } else { value_.push_back(c); } From a9281541f6941945fa758584fa358beb932eb412 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 06:46:17 -0500 Subject: [PATCH 13/24] update --- components/victron/victron.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 6ad2d43..5ce84ac 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -146,6 +146,7 @@ void VictronComponent::loop() { if (this->publishing_) { handle_value_(); } + state_ = 0; } else { value_.push_back(c); } From 5c0ea4d219e709f1339e36433cc46dbcc7a4c132 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 07:34:00 -0500 Subject: [PATCH 14/24] update --- components/victron/victron.cpp | 282 +++++++++++++++++---------------- components/victron/victron.h | 6 +- 2 files changed, 150 insertions(+), 138 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 5ce84ac..ac6a935 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -107,7 +107,9 @@ void VictronComponent::loop() { label_.clear(); value_.clear(); state_ = 1; - begin_frame_ = now; + if (begin_frame_ == 0) { + begin_frame_ = now; + } } if (state_ == 1) { // Start of a ve.direct hex frame @@ -132,20 +134,27 @@ void VictronComponent::loop() { // invalid checksum, drop frame ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %d, calc %d", c, checksum_); checksum_ = 0; + for (std::pair element : recv_buffer_) { + ESP_LOGD(TAG, ">> %s: %s", element.first, element.second); + } + recv_buffer_.clear(); return; } this->last_publish_ = begin_frame_; - this->publishing_ = true; + for (std::pair element : recv_buffer_) { + handle_value_(element.first, element.second); + } + recv_buffer_.clear(); } else { - this->publishing_ = false; - checksum_ = 0; + ESP_LOGD(TAG, "recv throttled, drop frame"); } + // reset checksum + checksum_ = 0; + begin_frame_ = now; return; } if (c == '\r' || c == '\n') { - if (this->publishing_) { - handle_value_(); - } + recv_buffer_.push_back(std::make_pair(label_, value_)); state_ = 0; } else { value_.push_back(c); @@ -156,6 +165,7 @@ void VictronComponent::loop() { if (c == '\r' || c == '\n') { state_ = 0; checksum_ = 0; + recv_buffer_.clear(); } } } @@ -647,134 +657,134 @@ static std::string off_reason_text(uint32_t mask) { return value_list; } -void VictronComponent::handle_value_() { +void VictronComponent::handle_value_(std::string l, std::string v) { int value; - if (label_ == "V") { - this->publish_state_(battery_voltage_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + if (l == "V") { + this->publish_state_(battery_voltage_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "V2") { + if (l == "V2") { // mV to V - this->publish_state_(battery_voltage_2_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(battery_voltage_2_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "V3") { + if (l == "V3") { // mV to V - this->publish_state_(battery_voltage_3_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(battery_voltage_3_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "VS") { + if (l == "VS") { // mV to V - this->publish_state_(auxiliary_battery_voltage_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(auxiliary_battery_voltage_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "VM") { + if (l == "VM") { // mV to V this->publish_state_(midpoint_voltage_of_the_battery_bank_sensor_, - atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "DM") { + if (l == "DM") { // Per mill to % this->publish_state_(midpoint_deviation_of_the_battery_bank_sensor_, - atoi(value_.c_str()) * 0.10f); // NOLINT(cert-err34-c) + atoi(v.c_str()) * 0.10f); // NOLINT(cert-err34-c) return; } - if (label_ == "VPV") { + if (l == "VPV") { // mV to V - this->publish_state_(panel_voltage_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(panel_voltage_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "PPV") { - this->publish_state_(panel_power_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "PPV") { + this->publish_state_(panel_power_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "I") { + if (l == "I") { // mA to A - this->publish_state_(battery_current_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(battery_current_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "I2") { + if (l == "I2") { // mA to A - this->publish_state_(battery_current_2_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(battery_current_2_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "I3") { + if (l == "I3") { // mA to A - this->publish_state_(battery_current_3_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(battery_current_3_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "IL") { - this->publish_state_(load_current_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + if (l == "IL") { + this->publish_state_(load_current_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "LOAD") { - this->publish_state_(load_state_binary_sensor_, value_ == "ON" || value_ == "On"); + if (l == "LOAD") { + this->publish_state_(load_state_binary_sensor_, v == "ON" || v == "On"); return; } - if (label_ == "T") { - if (value_ == "---") { + if (l == "T") { + if (v == "---") { this->publish_state_(battery_temperature_sensor_, NAN); return; } - this->publish_state_(battery_temperature_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + this->publish_state_(battery_temperature_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "P") { - this->publish_state_(instantaneous_power_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "P") { + this->publish_state_(instantaneous_power_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "CE") { + if (l == "CE") { // mAh -> Ah - this->publish_state_(consumed_amp_hours_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(consumed_amp_hours_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "SOC") { + if (l == "SOC") { // Per mill to % - this->publish_state_(state_of_charge_sensor_, atoi(value_.c_str()) * 0.10f); // NOLINT(cert-err34-c) + this->publish_state_(state_of_charge_sensor_, atoi(v.c_str()) * 0.10f); // NOLINT(cert-err34-c) return; } - if (label_ == "TTG") { - this->publish_state_(time_to_go_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "TTG") { + this->publish_state_(time_to_go_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "Alarm") { - this->publish_state_(alarm_condition_active_text_sensor_, value_); + if (l == "Alarm") { + this->publish_state_(alarm_condition_active_text_sensor_, v); return; } - if (label_ == "Relay") { - this->publish_state_(relay_state_binary_sensor_, value_ == "ON" || value_ == "On"); + if (l == "Relay") { + this->publish_state_(relay_state_binary_sensor_, v == "ON" || v == "On"); return; } - if (label_ == "AR") { - this->publish_state_(alarm_reason_text_sensor_, error_code_text(atoi(value_.c_str()))); // NOLINT(cert-err34-c) + if (l == "AR") { + this->publish_state_(alarm_reason_text_sensor_, error_code_text(atoi(v.c_str()))); // NOLINT(cert-err34-c) return; } - if (label_ == "OR") { - auto off_reason_bitmask = parse_hex(value_.substr(2, value_.size() - 2)); + if (l == "OR") { + auto off_reason_bitmask = parse_hex(v.substr(2, v.size() - 2)); if (off_reason_bitmask) { this->publish_state_(off_reason_bitmask_sensor_, *off_reason_bitmask); this->publish_state_(off_reason_text_sensor_, off_reason_text(*off_reason_bitmask)); @@ -782,186 +792,186 @@ void VictronComponent::handle_value_() { return; } - if (label_ == "H1") { + if (l == "H1") { // mAh -> Ah this->publish_state_(depth_of_the_deepest_discharge_sensor_, - atoi(value_.c_str()) / 1000.0); // NOLINT(cert-err34-c) + atoi(v.c_str()) / 1000.0); // NOLINT(cert-err34-c) return; } - if (label_ == "H2") { + if (l == "H2") { // mAh -> Ah - this->publish_state_(depth_of_the_last_discharge_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(depth_of_the_last_discharge_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H3") { + if (l == "H3") { // mAh -> Ah this->publish_state_(depth_of_the_average_discharge_sensor_, - atoi(value_.c_str()) / 1000.0); // NOLINT(cert-err34-c) + atoi(v.c_str()) / 1000.0); // NOLINT(cert-err34-c) return; } - if (label_ == "H4") { - this->publish_state_(number_of_charge_cycles_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "H4") { + this->publish_state_(number_of_charge_cycles_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H5") { - this->publish_state_(number_of_full_discharges_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "H5") { + this->publish_state_(number_of_full_discharges_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H6") { - if (value_ == "---") { + if (l == "H6") { + if (v == "---") { this->publish_state_(cumulative_amp_hours_drawn_sensor_, NAN); return; } // mAh -> Ah - this->publish_state_(cumulative_amp_hours_drawn_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(cumulative_amp_hours_drawn_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H7") { + if (l == "H7") { // mV to V - this->publish_state_(min_battery_voltage_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(min_battery_voltage_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H8") { + if (l == "H8") { // mV to V - this->publish_state_(max_battery_voltage_sensor_, atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + this->publish_state_(max_battery_voltage_sensor_, atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H9") { - if (value_ == "---") { + if (l == "H9") { + if (v == "---") { this->publish_state_(last_full_charge_sensor_, NAN); return; } // sec -> min - this->publish_state_(last_full_charge_sensor_, (float) atoi(value_.c_str()) / 60.0f); // NOLINT(cert-err34-c) + this->publish_state_(last_full_charge_sensor_, (float) atoi(v.c_str()) / 60.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H10") { - if (value_ == "---") { + if (l == "H10") { + if (v == "---") { this->publish_state_(number_of_automatic_synchronizations_sensor_, NAN); return; } - this->publish_state_(number_of_automatic_synchronizations_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + this->publish_state_(number_of_automatic_synchronizations_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H11") { - this->publish_state_(number_of_low_main_voltage_alarms_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "H11") { + this->publish_state_(number_of_low_main_voltage_alarms_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H12") { - this->publish_state_(number_of_high_main_voltage_alarms_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "H12") { + this->publish_state_(number_of_high_main_voltage_alarms_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H13") { - this->publish_state_(number_of_low_auxiliary_voltage_alarms_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "H13") { + this->publish_state_(number_of_low_auxiliary_voltage_alarms_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H14") { + if (l == "H14") { this->publish_state_(number_of_high_auxiliary_voltage_alarms_sensor_, - atoi(value_.c_str())); // NOLINT(cert-err34-c) + atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H15") { + if (l == "H15") { // mV to V this->publish_state_(min_auxiliary_battery_voltage_sensor_, - atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H16") { + if (l == "H16") { // mV to V this->publish_state_(max_auxiliary_battery_voltage_sensor_, - atoi(value_.c_str()) / 1000.0f); // NOLINT(cert-err34-c) + atoi(v.c_str()) / 1000.0f); // NOLINT(cert-err34-c) return; } // "H17" 0.01 kWh Amount of discharged energy (BMV) / Amount of produced energy (DC monitor) - if (label_ == "H17") { + if (l == "H17") { // Wh - this->publish_state_(amount_of_discharged_energy_sensor_, atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + this->publish_state_(amount_of_discharged_energy_sensor_, atoi(v.c_str()) * 10.0f); // NOLINT(cert-err34-c) return; } // "H18" 0.01 kWh Amount of charged energy (BMV) / Amount of consumed energy (DC monitor) - if (label_ == "H18") { + if (l == "H18") { // Wh - this->publish_state_(amount_of_charged_energy_sensor_, atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + this->publish_state_(amount_of_charged_energy_sensor_, atoi(v.c_str()) * 10.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H19") { - this->publish_state_(yield_total_sensor_, atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + if (l == "H19") { + this->publish_state_(yield_total_sensor_, atoi(v.c_str()) * 10.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H20") { - this->publish_state_(yield_today_sensor_, atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + if (l == "H20") { + this->publish_state_(yield_today_sensor_, atoi(v.c_str()) * 10.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H21") { - this->publish_state_(max_power_today_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "H21") { + this->publish_state_(max_power_today_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "H22") { - this->publish_state_(yield_yesterday_sensor_, atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + if (l == "H22") { + this->publish_state_(yield_yesterday_sensor_, atoi(v.c_str()) * 10.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "H23") { - this->publish_state_(max_power_yesterday_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "H23") { + this->publish_state_(max_power_yesterday_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "ERR") { - value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + if (l == "ERR") { + value = atoi(v.c_str()); // NOLINT(cert-err34-c) this->publish_state_(error_code_sensor_, value); this->publish_state_(error_text_sensor_, error_code_text(value)); return; } - if (label_ == "CS") { - value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + if (l == "CS") { + value = atoi(v.c_str()); // NOLINT(cert-err34-c) this->publish_state_(charging_mode_id_sensor_, (float) value); this->publish_state_(charging_mode_text_sensor_, charging_mode_text(value)); return; } // "BMV" Model description (deprecated) - if (label_ == "BMV") { - this->publish_state_(model_description_text_sensor_, value_); + if (l == "BMV") { + this->publish_state_(model_description_text_sensor_, v); return; } - if (label_ == "FW") { - this->publish_state_once_(firmware_version_text_sensor_, value_.insert(value_.size() - 2, ".")); + if (l == "FW") { + this->publish_state_once_(firmware_version_text_sensor_, v.insert(v.size() - 2, ".")); return; } - if (label_ == "FWE") { + if (l == "FWE") { if (this->firmware_version_24bit_text_sensor_ == nullptr || this->firmware_version_24bit_text_sensor_->has_state()) return; - if (value_.size() > 4) { - std::string release_type = value_.substr(value_.size() - 2, 2); - std::string version_number = value_.substr(0, value_.size() - 2); + if (v.size() > 4) { + std::string release_type = v.substr(v.size() - 2, 2); + std::string version_number = v.substr(0, v.size() - 2); version_number = version_number.insert(version_number.size() - 2, "."); release_type = (release_type == "FF") ? "-official" : "-beta-" + release_type; @@ -969,69 +979,69 @@ void VictronComponent::handle_value_() { return; } - this->publish_state_once_(firmware_version_24bit_text_sensor_, value_); + this->publish_state_once_(firmware_version_24bit_text_sensor_, v); return; } - if (label_ == "PID") { - this->publish_state_once_(device_type_text_sensor_, device_type_text(strtol(value_.c_str(), nullptr, 0))); + if (l == "PID") { + this->publish_state_once_(device_type_text_sensor_, device_type_text(strtol(v.c_str(), nullptr, 0))); return; } - if (label_ == "SER#") { - this->publish_state_once_(serial_number_text_sensor_, value_); + if (l == "SER#") { + this->publish_state_once_(serial_number_text_sensor_, v); return; } - if (label_ == "HSDS") { - this->publish_state_(day_number_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "HSDS") { + this->publish_state_(day_number_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "MODE") { - value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + if (l == "MODE") { + value = atoi(v.c_str()); // NOLINT(cert-err34-c) this->publish_state_(device_mode_id_sensor_, (float) value); this->publish_state_(device_mode_text_sensor_, device_mode_text(value)); return; } - if (label_ == "AC_OUT_V") { - this->publish_state_(ac_out_voltage_sensor_, atoi(value_.c_str()) / 100.0f); // NOLINT(cert-err34-c) + if (l == "AC_OUT_V") { + this->publish_state_(ac_out_voltage_sensor_, atoi(v.c_str()) / 100.0f); // NOLINT(cert-err34-c) return; } - if (label_ == "AC_OUT_I") { - this->publish_state_(ac_out_current_sensor_, std::max(0.0f, atoi(value_.c_str()) / 10.0f)); // NOLINT(cert-err34-c) + if (l == "AC_OUT_I") { + this->publish_state_(ac_out_current_sensor_, std::max(0.0f, atoi(v.c_str()) / 10.0f)); // NOLINT(cert-err34-c) return; } - if (label_ == "AC_OUT_S") { - this->publish_state_(ac_out_apparent_power_sensor_, atoi(value_.c_str())); // NOLINT(cert-err34-c) + if (l == "AC_OUT_S") { + this->publish_state_(ac_out_apparent_power_sensor_, atoi(v.c_str())); // NOLINT(cert-err34-c) return; } - if (label_ == "WARN") { - value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + if (l == "WARN") { + value = atoi(v.c_str()); // NOLINT(cert-err34-c) this->publish_state_(warning_code_sensor_, value); this->publish_state_(warning_text_sensor_, warning_code_text(value)); return; } - if (label_ == "MPPT") { - value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + if (l == "MPPT") { + value = atoi(v.c_str()); // NOLINT(cert-err34-c) this->publish_state_(tracking_mode_id_sensor_, (float) value); this->publish_state_(tracking_mode_text_sensor_, tracking_mode_text(value)); return; } - if (label_ == "MON") { - value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + if (l == "MON") { + value = atoi(v.c_str()); // NOLINT(cert-err34-c) this->publish_state_(dc_monitor_mode_id_sensor_, (float) value); this->publish_state_(dc_monitor_mode_text_sensor_, dc_monitor_mode_text(value)); return; } - ESP_LOGD(TAG, "Unhandled property: %s %s", label_.c_str(), value_.c_str()); + ESP_LOGD(TAG, "Unhandled property: %s %s", l.c_str(), v.c_str()); } void VictronComponent::publish_state_(binary_sensor::BinarySensor *binary_sensor, const bool &state) { diff --git a/components/victron/victron.h b/components/victron/victron.h index d30873f..abe72eb 100644 --- a/components/victron/victron.h +++ b/components/victron/victron.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include "esphome/core/component.h" #include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/sensor/sensor.h" @@ -206,7 +208,7 @@ class VictronComponent : public uart::UARTDevice, public Component { float get_setup_priority() const override { return setup_priority::DATA; } protected: - void handle_value_(); + void handle_value_(std::string l, std::string v); void publish_state_(binary_sensor::BinarySensor *binary_sensor, const bool &state); void publish_state_(sensor::Sensor *sensor, float value); void publish_state_(text_sensor::TextSensor *text_sensor, const std::string &state); @@ -283,7 +285,6 @@ class VictronComponent : public uart::UARTDevice, public Component { text_sensor::TextSensor *alarm_reason_text_sensor_{nullptr}; text_sensor::TextSensor *model_description_text_sensor_{nullptr}; - bool publishing_{true}; int state_{0}; std::string label_; std::string value_; @@ -292,6 +293,7 @@ class VictronComponent : public uart::UARTDevice, public Component { uint32_t last_publish_{0}; uint32_t throttle_{0}; uint8_t checksum_{0}; + std::vector> recv_buffer_{}; }; } // namespace victron From 8238b1d4105ce364faa56dfbf6abfc9a5d9f5145 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 07:35:11 -0500 Subject: [PATCH 15/24] update --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index ac6a935..579dd4a 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -135,7 +135,7 @@ void VictronComponent::loop() { ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %d, calc %d", c, checksum_); checksum_ = 0; for (std::pair element : recv_buffer_) { - ESP_LOGD(TAG, ">> %s: %s", element.first, element.second); + ESP_LOGD(TAG, ">> %s: %s", element.first.c_str(), element.second.c_str()); } recv_buffer_.clear(); return; From 0f73a5fbbe4e3c339968df632abed7a90e3b2b2c Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 07:38:01 -0500 Subject: [PATCH 16/24] update --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 579dd4a..269c0e1 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -144,10 +144,10 @@ void VictronComponent::loop() { for (std::pair element : recv_buffer_) { handle_value_(element.first, element.second); } - recv_buffer_.clear(); } else { ESP_LOGD(TAG, "recv throttled, drop frame"); } + recv_buffer_.clear(); // reset checksum checksum_ = 0; begin_frame_ = now; From d2f16fc80db8f15893d9e5aba1ecb75aba9ae71a Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 07:51:13 -0500 Subject: [PATCH 17/24] update --- components/victron/victron.cpp | 14 +++++++++++++- components/victron/victron.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 269c0e1..430dd96 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -87,6 +87,15 @@ void VictronComponent::dump_config() { // NOLINT(google-readability-function-si } void VictronComponent::loop() { + if (publishing_) { + std::pair p = recv_buffer_.back(); + handle_value_(p.first, p.second); + recv_buffer_.pop_back(); + if (recv_buffer_.size() == 0) { + publishing_ = false; + } + return; + } const uint32_t now = millis(); if ((state_ > 0) && (now - last_transmission_ >= 200)) { // last transmission too long ago. Reset RX index. @@ -141,9 +150,12 @@ void VictronComponent::loop() { return; } this->last_publish_ = begin_frame_; + publishing_ = true; + /* for (std::pair element : recv_buffer_) { handle_value_(element.first, element.second); } + */ } else { ESP_LOGD(TAG, "recv throttled, drop frame"); } @@ -154,7 +166,7 @@ void VictronComponent::loop() { return; } if (c == '\r' || c == '\n') { - recv_buffer_.push_back(std::make_pair(label_, value_)); + recv_buffer_.insert(recv_buffer.begin(), std::make_pair(label_, value_)); state_ = 0; } else { value_.push_back(c); diff --git a/components/victron/victron.h b/components/victron/victron.h index abe72eb..20beaf7 100644 --- a/components/victron/victron.h +++ b/components/victron/victron.h @@ -286,6 +286,7 @@ class VictronComponent : public uart::UARTDevice, public Component { text_sensor::TextSensor *model_description_text_sensor_{nullptr}; int state_{0}; + bool publishing_{false}; std::string label_; std::string value_; uint32_t begin_frame_{0}; From d8547a3e8d098cb321ef88603f3b50961103e1fe Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 07:52:17 -0500 Subject: [PATCH 18/24] fix --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 430dd96..67ab28b 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -166,7 +166,7 @@ void VictronComponent::loop() { return; } if (c == '\r' || c == '\n') { - recv_buffer_.insert(recv_buffer.begin(), std::make_pair(label_, value_)); + recv_buffer_.insert(recv_buffer_.begin(), std::make_pair(label_, value_)); state_ = 0; } else { value_.push_back(c); From e1435b444f3fe7f45f806fd8a0029fd7233cbcc4 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 07:55:31 -0500 Subject: [PATCH 19/24] update --- components/victron/victron.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 67ab28b..5468849 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -87,7 +87,7 @@ void VictronComponent::dump_config() { // NOLINT(google-readability-function-si } void VictronComponent::loop() { - if (publishing_) { + if (publishing_ && recv_buffer_.size() > 0) { std::pair p = recv_buffer_.back(); handle_value_(p.first, p.second); recv_buffer_.pop_back(); @@ -96,6 +96,7 @@ void VictronComponent::loop() { } return; } + publishing_ = false; const uint32_t now = millis(); if ((state_ > 0) && (now - last_transmission_ >= 200)) { // last transmission too long ago. Reset RX index. From 4695794f62d8b61993df9deaf81dbc56d18332d2 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 07:58:43 -0500 Subject: [PATCH 20/24] update --- components/victron/victron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 5468849..f891939 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -159,8 +159,8 @@ void VictronComponent::loop() { */ } else { ESP_LOGD(TAG, "recv throttled, drop frame"); + recv_buffer_.clear(); } - recv_buffer_.clear(); // reset checksum checksum_ = 0; begin_frame_ = now; From d0d3a4ea6c12ea109695fc247302c7b0351baeef Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Nov 2023 08:56:52 -0500 Subject: [PATCH 21/24] comments --- components/victron/victron.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index f891939..6a915ef 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -87,6 +87,8 @@ void VictronComponent::dump_config() { // NOLINT(google-readability-function-si } void VictronComponent::loop() { + // publish one value at a time to yield to esphome between + // each value and avoid blocking too long if (publishing_ && recv_buffer_.size() > 0) { std::pair p = recv_buffer_.back(); handle_value_(p.first, p.second); @@ -96,6 +98,7 @@ void VictronComponent::loop() { } return; } + // reset publishing in case buffer is empty while publishing publishing_ = false; const uint32_t now = millis(); if ((state_ > 0) && (now - last_transmission_ >= 200)) { @@ -109,11 +112,14 @@ void VictronComponent::loop() { last_transmission_ = now; uint8_t c; read_byte(&c); + // checksum is calculated as the sum of all bytes in a frame + // the final checksum should be a multiple of 256 (0 in 8 bit value) checksum_ += c; if (state_ == 0) { if (c == '\r' || c == '\n') { return; } + // reset label/value label_.clear(); value_.clear(); state_ = 1; @@ -121,6 +127,7 @@ void VictronComponent::loop() { begin_frame_ = now; } } + // read label if (state_ == 1) { // Start of a ve.direct hex frame if (c == ':') { @@ -128,18 +135,21 @@ void VictronComponent::loop() { return; } if (c == '\t') { + // end of label received, start reading value state_ = 2; } else { + // update label label_.push_back(c); } return; } + // read value if (state_ == 2) { + // The checksum is used as end of frame indicator if (label_ == "Checksum") { state_ = 0; - // The checksum is used as end of frame indicator if (begin_frame_ - this->last_publish_ >= this->throttle_) { - // check checksum + // check that checksum value is accurate if (checksum_ != 0) { // invalid checksum, drop frame ESP_LOGW(TAG, "Received invalid checksum, dropping frame: recv %d, calc %d", c, checksum_); @@ -147,29 +157,30 @@ void VictronComponent::loop() { for (std::pair element : recv_buffer_) { ESP_LOGD(TAG, ">> %s: %s", element.first.c_str(), element.second.c_str()); } + // clear buffer with invalid data recv_buffer_.clear(); return; } this->last_publish_ = begin_frame_; + // full buffer received, with valid checksum + // set state to publishing to publish the values in the buffer publishing_ = true; - /* - for (std::pair element : recv_buffer_) { - handle_value_(element.first, element.second); - } - */ } else { + // frame is throttled, clear buffer and skip publishing ESP_LOGD(TAG, "recv throttled, drop frame"); recv_buffer_.clear(); } - // reset checksum + // reset checksum and frame checksum_ = 0; begin_frame_ = now; return; } if (c == '\r' || c == '\n') { + // end of value received, add label/value to buffer recv_buffer_.insert(recv_buffer_.begin(), std::make_pair(label_, value_)); state_ = 0; } else { + // update value value_.push_back(c); } } From d00f9ac3387ca27ddc7826c1d7c18b0cd13fc932 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 21 Nov 2023 06:38:01 -0500 Subject: [PATCH 22/24] add config option --- components/victron/__init__.py | 4 ++ components/victron/victron.cpp | 74 ++++++++++++++++++++++++++++++++++ components/victron/victron.h | 4 ++ 3 files changed, 82 insertions(+) diff --git a/components/victron/__init__.py b/components/victron/__init__.py index ca2e97a..8870049 100644 --- a/components/victron/__init__.py +++ b/components/victron/__init__.py @@ -11,6 +11,8 @@ MULTI_CONF = True +CONF_ASYNC_UART = 'async_uart' + victron_ns = cg.esphome_ns.namespace("victron") VictronComponent = victron_ns.class_("VictronComponent", uart.UARTDevice, cg.Component) @@ -20,6 +22,7 @@ { cv.GenerateID(): cv.declare_id(VictronComponent), cv.Optional(CONF_THROTTLE, default="1s"): cv.positive_time_period_milliseconds, + cv.Optional(CONF_ASYNC_UART, default=False): cv.boolean, } ) @@ -30,3 +33,4 @@ def to_code(config): yield uart.register_uart_device(var, config) cg.add(var.set_throttle(config[CONF_THROTTLE])) + cg.add(var.set_async_uart(config[CONF_ASYNC_UART])) diff --git a/components/victron/victron.cpp b/components/victron/victron.cpp index 6a915ef..6370165 100644 --- a/components/victron/victron.cpp +++ b/components/victron/victron.cpp @@ -87,6 +87,80 @@ void VictronComponent::dump_config() { // NOLINT(google-readability-function-si } void VictronComponent::loop() { + if (async_uart_) { + async_loop(); + } else { + blocking_loop(); + } +} + +void VictronComponent::blocking_loop() { + const uint32_t now = millis(); + if ((state_ > 0) && (now - last_transmission_ >= 200)) { + // last transmission too long ago. Reset RX index. + ESP_LOGW(TAG, "Last transmission too long ago"); + state_ = 0; + } + + if (!available()) + return; + + last_transmission_ = now; + while (available()) { + uint8_t c; + read_byte(&c); + if (state_ == 0) { + if (c == '\r' || c == '\n') { + continue; + } + label_.clear(); + value_.clear(); + state_ = 1; + } + if (state_ == 1) { + // Start of a ve.direct hex frame + if (c == ':') { + state_ = 3; + continue; + } + if (c == '\t') { + state_ = 2; + } else { + label_.push_back(c); + } + continue; + } + if (state_ == 2) { + if (label_ == "Checksum") { + state_ = 0; + // The checksum is used as end of frame indicator + if (now - this->last_publish_ >= this->throttle_) { + this->last_publish_ = now; + this->publishing_ = true; + } else { + this->publishing_ = false; + } + continue; + } + if (c == '\r' || c == '\n') { + if (this->publishing_) { + handle_value_(label_, value_); + } + state_ = 0; + } else { + value_.push_back(c); + } + } + // Discard ve.direct hex frame + if (state_ == 3) { + if (c == '\r' || c == '\n') { + state_ = 0; + } + } + } +} + +void VictronComponent::async_loop() { // publish one value at a time to yield to esphome between // each value and avoid blocking too long if (publishing_ && recv_buffer_.size() > 0) { diff --git a/components/victron/victron.h b/components/victron/victron.h index 20beaf7..b1289b0 100644 --- a/components/victron/victron.h +++ b/components/victron/victron.h @@ -14,6 +14,7 @@ namespace victron { class VictronComponent : public uart::UARTDevice, public Component { public: void set_throttle(uint32_t throttle) { this->throttle_ = throttle; } + void set_async_uart(bool async_uart) { this->async_uart_ = async_uart; } void set_load_state_binary_sensor(binary_sensor::BinarySensor *load_state_binary_sensor) { load_state_binary_sensor_ = load_state_binary_sensor; } @@ -204,6 +205,8 @@ class VictronComponent : public uart::UARTDevice, public Component { void dump_config() override; void loop() override; + void async_loop(); + void blocking_loop(); float get_setup_priority() const override { return setup_priority::DATA; } @@ -286,6 +289,7 @@ class VictronComponent : public uart::UARTDevice, public Component { text_sensor::TextSensor *model_description_text_sensor_{nullptr}; int state_{0}; + bool async_uart_{false}; bool publishing_{false}; std::string label_; std::string value_; From b25f8b8029e8ca403353dfbdfa59e1d94fc6ed73 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 21 Nov 2023 08:25:37 -0500 Subject: [PATCH 23/24] lint --- components/victron/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/victron/__init__.py b/components/victron/__init__.py index 8870049..cd86f27 100644 --- a/components/victron/__init__.py +++ b/components/victron/__init__.py @@ -11,7 +11,7 @@ MULTI_CONF = True -CONF_ASYNC_UART = 'async_uart' +CONF_ASYNC_UART = "async_uart" victron_ns = cg.esphome_ns.namespace("victron") VictronComponent = victron_ns.class_("VictronComponent", uart.UARTDevice, cg.Component) From 5a56486a1ee4a6a20996d3dd61ed81cd42dbdcee Mon Sep 17 00:00:00 2001 From: wozz Date: Fri, 22 Dec 2023 09:05:43 -0500 Subject: [PATCH 24/24] Update sensor.py --- components/victron/sensor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/victron/sensor.py b/components/victron/sensor.py index 6e46978..edb36a0 100644 --- a/components/victron/sensor.py +++ b/components/victron/sensor.py @@ -164,21 +164,21 @@ unit_of_measurement=UNIT_WATT_HOURS, icon=ICON_POWER, accuracy_decimals=0, - device_class=DEVICE_CLASS_POWER, + device_class=DEVICE_CLASS_ENERGY, state_class=STATE_CLASS_TOTAL_INCREASING, ), cv.Optional(CONF_YIELD_YESTERDAY): sensor.sensor_schema( unit_of_measurement=UNIT_WATT_HOURS, icon=ICON_POWER, accuracy_decimals=0, - device_class=DEVICE_CLASS_POWER, + device_class=DEVICE_CLASS_ENERGY, state_class=STATE_CLASS_TOTAL_INCREASING, ), cv.Optional(CONF_YIELD_TODAY): sensor.sensor_schema( unit_of_measurement=UNIT_WATT_HOURS, icon=ICON_POWER, accuracy_decimals=0, - device_class=DEVICE_CLASS_POWER, + device_class=DEVICE_CLASS_ENERGY, state_class=STATE_CLASS_TOTAL_INCREASING, ), cv.Optional(CONF_PANEL_VOLTAGE): sensor.sensor_schema(