From 6f49f5465b61581d5f357c891e3c4aa134fec477 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 17 May 2022 01:15:02 -0700 Subject: [PATCH] Retry Tuya init commands (#3482) Co-authored-by: Samuel Sieb --- esphome/components/tuya/tuya.cpp | 30 ++++++++++++++++++++++++------ esphome/components/tuya/tuya.h | 2 ++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 1fbca7796d..78e9d9e568 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -1,7 +1,7 @@ #include "tuya.h" -#include "esphome/core/log.h" #include "esphome/components/network/util.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/core/util.h" namespace esphome { @@ -10,6 +10,7 @@ namespace tuya { static const char *const TAG = "tuya"; static const int COMMAND_DELAY = 10; static const int RECEIVE_TIMEOUT = 300; +static const int MAX_RETRIES = 5; void Tuya::setup() { this->set_interval("heartbeat", 15000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); }); @@ -27,8 +28,12 @@ void Tuya::loop() { void Tuya::dump_config() { ESP_LOGCONFIG(TAG, "Tuya:"); if (this->init_state_ != TuyaInitState::INIT_DONE) { - ESP_LOGCONFIG(TAG, " Configuration will be reported when setup is complete. Current init_state: %u", - static_cast(this->init_state_)); + if (this->init_failed_) { + ESP_LOGCONFIG(TAG, " Initialization failed. Current init_state: %u", static_cast(this->init_state_)); + } else { + ESP_LOGCONFIG(TAG, " Configuration will be reported when setup is complete. Current init_state: %u", + static_cast(this->init_state_)); + } ESP_LOGCONFIG(TAG, " If no further output is received, confirm that this is a supported Tuya device."); return; } @@ -127,6 +132,8 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff if (this->expected_response_.has_value() && this->expected_response_ == command_type) { this->expected_response_.reset(); + this->command_queue_.erase(command_queue_.begin()); + this->init_retries_ = 0; } switch (command_type) { @@ -332,8 +339,8 @@ void Tuya::handle_datapoints_(const uint8_t *buffer, size_t len) { } void Tuya::send_raw_command_(TuyaCommand command) { - uint8_t len_hi = (uint8_t)(command.payload.size() >> 8); - uint8_t len_lo = (uint8_t)(command.payload.size() & 0xFF); + uint8_t len_hi = (uint8_t) (command.payload.size() >> 8); + uint8_t len_lo = (uint8_t) (command.payload.size() & 0xFF); uint8_t version = 0; this->last_command_timestamp_ = millis(); @@ -378,13 +385,24 @@ void Tuya::process_command_queue_() { if (this->expected_response_.has_value() && delay > RECEIVE_TIMEOUT) { this->expected_response_.reset(); + if (init_state_ != TuyaInitState::INIT_DONE) { + if (++this->init_retries_ >= MAX_RETRIES) { + this->init_failed_ = true; + ESP_LOGE(TAG, "Initialization failed at init_state %u", static_cast(this->init_state_)); + this->command_queue_.erase(command_queue_.begin()); + this->init_retries_ = 0; + } + } else { + this->command_queue_.erase(command_queue_.begin()); + } } // Left check of delay since last command in case there's ever a command sent by calling send_raw_command_ directly if (delay > COMMAND_DELAY && !this->command_queue_.empty() && this->rx_message_.empty() && !this->expected_response_.has_value()) { this->send_raw_command_(command_queue_.front()); - this->command_queue_.erase(command_queue_.begin()); + if (!this->expected_response_.has_value()) + this->command_queue_.erase(command_queue_.begin()); } } diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index 3828c49b48..cdff523f90 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -122,6 +122,8 @@ class Tuya : public Component, public uart::UARTDevice { optional time_id_{}; #endif TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT; + bool init_failed_{false}; + int init_retries_{0}; uint8_t protocol_version_ = -1; int gpio_status_ = -1; int gpio_reset_ = -1;