@@ -87,6 +87,14 @@ void VictronComponent::dump_config() { // NOLINT(google-readability-function-si
87
87
}
88
88
89
89
void VictronComponent::loop () {
90
+ if (async_uart_) {
91
+ async_loop ();
92
+ } else {
93
+ blocking_loop ();
94
+ }
95
+ }
96
+
97
+ void VictronComponent::blocking_loop () {
90
98
const uint32_t now = millis ();
91
99
const uint8_t elapsed_time = now - last_transmission_;
92
100
if ((state_ > 0 ) && (elapsed_time >= 200 )) {
@@ -143,7 +151,7 @@ void VictronComponent::loop() {
143
151
ESP_LOGD (TAG, " v:%s" , value_.c_str ());
144
152
if (this ->publishing_ ) {
145
153
ESP_LOGD (TAG, " pub:%s" , label_.c_str ());
146
- handle_value_ ();
154
+ handle_value_ (label_, value_ );
147
155
}
148
156
state_ = 0 ;
149
157
} else {
@@ -163,6 +171,115 @@ void VictronComponent::loop() {
163
171
}
164
172
}
165
173
174
+
175
+ void VictronComponent::async_loop () {
176
+ // publish one value at a time to yield to esphome between
177
+ // each value and avoid blocking too long
178
+ if (publishing_ && recv_buffer_.size () > 0 ) {
179
+ std::pair<std::string, std::string> p = recv_buffer_.back ();
180
+ handle_value_ (p.first , p.second );
181
+ recv_buffer_.pop_back ();
182
+ if (recv_buffer_.size () == 0 ) {
183
+ publishing_ = false ;
184
+ }
185
+ return ;
186
+ }
187
+ // reset publishing in case buffer is empty while publishing
188
+ publishing_ = false ;
189
+ const uint32_t now = millis ();
190
+ if ((state_ > 0 ) && (now - last_transmission_ >= 200 )) {
191
+ // last transmission too long ago. Reset RX index.
192
+ ESP_LOGW (TAG, " Last transmission too long ago" );
193
+ state_ = 0 ;
194
+ }
195
+ if (!available ())
196
+ return ;
197
+
198
+ last_transmission_ = now;
199
+ uint8_t c;
200
+ read_byte (&c);
201
+ // checksum is calculated as the sum of all bytes in a frame
202
+ // the final checksum should be a multiple of 256 (0 in 8 bit value)
203
+ checksum_ += c;
204
+ if (state_ == 0 ) {
205
+ if (c == ' \r ' || c == ' \n ' ) {
206
+ return ;
207
+ }
208
+ // reset label/value
209
+ label_.clear ();
210
+ value_.clear ();
211
+ state_ = 1 ;
212
+ if (begin_frame_ == 0 ) {
213
+ begin_frame_ = now;
214
+ }
215
+ }
216
+ // read label
217
+ if (state_ == 1 ) {
218
+ // Start of a ve.direct hex frame
219
+ if (c == ' :' ) {
220
+ state_ = 3 ;
221
+ return ;
222
+ }
223
+ if (c == ' \t ' ) {
224
+ // end of label received, start reading value
225
+ state_ = 2 ;
226
+ } else {
227
+ // update label
228
+ label_.push_back (c);
229
+ }
230
+ return ;
231
+ }
232
+ // read value
233
+ if (state_ == 2 ) {
234
+ // The checksum is used as end of frame indicator
235
+ if (label_ == " Checksum" ) {
236
+ state_ = 0 ;
237
+ if (begin_frame_ - this ->last_publish_ >= this ->throttle_ ) {
238
+ // check that checksum value is accurate
239
+ if (checksum_ != 0 ) {
240
+ // invalid checksum, drop frame
241
+ ESP_LOGW (TAG, " Received invalid checksum, dropping frame: recv %d, calc %d" , c, checksum_);
242
+ checksum_ = 0 ;
243
+ for (std::pair<std::string, std::string> element : recv_buffer_) {
244
+ ESP_LOGD (TAG, " >> %s: %s" , element.first .c_str (), element.second .c_str ());
245
+ }
246
+ // clear buffer with invalid data
247
+ recv_buffer_.clear ();
248
+ return ;
249
+ }
250
+ this ->last_publish_ = begin_frame_;
251
+ // full buffer received, with valid checksum
252
+ // set state to publishing to publish the values in the buffer
253
+ publishing_ = true ;
254
+ } else {
255
+ // frame is throttled, clear buffer and skip publishing
256
+ ESP_LOGD (TAG, " recv throttled, drop frame" );
257
+ recv_buffer_.clear ();
258
+ }
259
+ // reset checksum and frame
260
+ checksum_ = 0 ;
261
+ begin_frame_ = now;
262
+ return ;
263
+ }
264
+ if (c == ' \r ' || c == ' \n ' ) {
265
+ // end of value received, add label/value to buffer
266
+ recv_buffer_.insert (recv_buffer_.begin (), std::make_pair (label_, value_));
267
+ state_ = 0 ;
268
+ } else {
269
+ // update value
270
+ value_.push_back (c);
271
+ }
272
+ }
273
+ // Discard ve.direct hex frame
274
+ if (state_ == 3 ) {
275
+ if (c == ' \r ' || c == ' \n ' ) {
276
+ state_ = 0 ;
277
+ checksum_ = 0 ;
278
+ recv_buffer_.clear ();
279
+ }
280
+ }
281
+ }
282
+
166
283
static std::string charging_mode_text (int value) {
167
284
switch (value) {
168
285
case 0 :
@@ -663,7 +780,7 @@ static std::string off_reason_text(uint32_t mask) {
663
780
return value_list;
664
781
}
665
782
666
- void VictronComponent::handle_value_ () {
783
+ void VictronComponent::handle_value_ (std::string label_, std::string value_ ) {
667
784
int value;
668
785
669
786
if (label_ == " V" ) {
0 commit comments