mirror of
https://github.com/Threnklyn/esphome-dev.git
synced 2026-05-26 15:48:28 +02:00
Add support for Tuya MCU 0x1C (obtain local time) (#1344)
* Fix some Tuya devices not handling commands sent without delay * Also do not report WiFi status if MCU does not support it * Support Tuya MCU 0x1c command (obtain local time) * Use #ifdef USE_TIME to handle optional dependency on RTC * Rename Tuya clock config variable to time to be consistent with the codebase * Add tuya time configuration to test4
This commit is contained in:
@@ -6,9 +6,10 @@ namespace esphome {
|
||||
namespace tuya {
|
||||
|
||||
static const char *TAG = "tuya";
|
||||
static const int COMMAND_DELAY = 50;
|
||||
|
||||
void Tuya::setup() {
|
||||
this->set_interval("heartbeat", 1000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); });
|
||||
this->set_interval("heartbeat", 1000, [this] { this->schedule_empty_command_(TuyaCommandType::HEARTBEAT); });
|
||||
}
|
||||
|
||||
void Tuya::loop() {
|
||||
@@ -19,6 +20,15 @@ void Tuya::loop() {
|
||||
}
|
||||
}
|
||||
|
||||
void Tuya::schedule_empty_command_(TuyaCommandType command) {
|
||||
uint32_t delay = millis() - this->last_command_timestamp_;
|
||||
if (delay > COMMAND_DELAY) {
|
||||
send_empty_command_(command);
|
||||
} else {
|
||||
this->set_timeout(COMMAND_DELAY - delay, [this, command] { this->send_empty_command_(command); });
|
||||
}
|
||||
}
|
||||
|
||||
void Tuya::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Tuya:");
|
||||
if (this->init_state_ != TuyaInitState::INIT_DONE) {
|
||||
@@ -110,6 +120,7 @@ void Tuya::handle_char_(uint8_t c) {
|
||||
}
|
||||
|
||||
void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len) {
|
||||
this->last_command_timestamp_ = millis();
|
||||
switch ((TuyaCommandType) command) {
|
||||
case TuyaCommandType::HEARTBEAT:
|
||||
ESP_LOGV(TAG, "MCU Heartbeat (0x%02X)", buffer[0]);
|
||||
@@ -119,7 +130,7 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
|
||||
}
|
||||
if (this->init_state_ == TuyaInitState::INIT_HEARTBEAT) {
|
||||
this->init_state_ = TuyaInitState::INIT_PRODUCT;
|
||||
this->send_empty_command_(TuyaCommandType::PRODUCT_QUERY);
|
||||
this->schedule_empty_command_(TuyaCommandType::PRODUCT_QUERY);
|
||||
}
|
||||
break;
|
||||
case TuyaCommandType::PRODUCT_QUERY: {
|
||||
@@ -138,7 +149,7 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
|
||||
}
|
||||
if (this->init_state_ == TuyaInitState::INIT_PRODUCT) {
|
||||
this->init_state_ = TuyaInitState::INIT_CONF;
|
||||
this->send_empty_command_(TuyaCommandType::CONF_QUERY);
|
||||
this->schedule_empty_command_(TuyaCommandType::CONF_QUERY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -148,19 +159,27 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
|
||||
gpio_reset_ = buffer[1];
|
||||
}
|
||||
if (this->init_state_ == TuyaInitState::INIT_CONF) {
|
||||
// If we were following the spec to the letter we would send
|
||||
// state updates until connected to both WiFi and API/MQTT.
|
||||
// Instead we just claim to be connected immediately and move on.
|
||||
uint8_t c[] = {0x04};
|
||||
this->init_state_ = TuyaInitState::INIT_WIFI;
|
||||
this->send_command_(TuyaCommandType::WIFI_STATE, c, 1);
|
||||
// If mcu returned status gpio, then we can ommit sending wifi state
|
||||
if (this->gpio_status_ != 0) {
|
||||
this->init_state_ = TuyaInitState::INIT_DATAPOINT;
|
||||
this->schedule_empty_command_(TuyaCommandType::DATAPOINT_QUERY);
|
||||
} else {
|
||||
this->init_state_ = TuyaInitState::INIT_WIFI;
|
||||
this->set_timeout(COMMAND_DELAY, [this] {
|
||||
// If we were following the spec to the letter we would send
|
||||
// state updates until connected to both WiFi and API/MQTT.
|
||||
// Instead we just claim to be connected immediately and move on.
|
||||
uint8_t c[] = {0x04};
|
||||
this->send_command_(TuyaCommandType::WIFI_STATE, c, 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TuyaCommandType::WIFI_STATE:
|
||||
if (this->init_state_ == TuyaInitState::INIT_WIFI) {
|
||||
this->init_state_ = TuyaInitState::INIT_DATAPOINT;
|
||||
this->send_empty_command_(TuyaCommandType::DATAPOINT_QUERY);
|
||||
this->schedule_empty_command_(TuyaCommandType::DATAPOINT_QUERY);
|
||||
}
|
||||
break;
|
||||
case TuyaCommandType::WIFI_RESET:
|
||||
@@ -185,6 +204,44 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
|
||||
this->send_command_(TuyaCommandType::WIFI_TEST, c, 2);
|
||||
break;
|
||||
}
|
||||
case TuyaCommandType::LOCAL_TIME_QUERY: {
|
||||
#ifdef USE_TIME
|
||||
if (this->time_id_.has_value()) {
|
||||
auto time_id = *this->time_id_;
|
||||
auto now = time_id->now();
|
||||
|
||||
if (now.is_valid()) {
|
||||
this->set_timeout(COMMAND_DELAY, [this, now] {
|
||||
uint8_t year = now.year - 2000;
|
||||
uint8_t month = now.month;
|
||||
uint8_t day_of_month = now.day_of_month;
|
||||
uint8_t hour = now.hour;
|
||||
uint8_t minute = now.minute;
|
||||
uint8_t second = now.second;
|
||||
// Tuya days starts from Monday, esphome uses Sunday as day 1
|
||||
uint8_t day_of_week = now.day_of_week - 1;
|
||||
if (day_of_week == 0) {
|
||||
day_of_week = 7;
|
||||
}
|
||||
uint8_t c[] = {0x01, year, month, day_of_month, hour, minute, second, day_of_week};
|
||||
this->send_command_(TuyaCommandType::LOCAL_TIME_QUERY, c, 8);
|
||||
});
|
||||
} else {
|
||||
ESP_LOGW(TAG, "TUYA_CMD_LOCAL_TIME_QUERY is not handled because time is not valid");
|
||||
// By spec we need to notify MCU that the time was not obtained
|
||||
this->set_timeout(COMMAND_DELAY, [this] {
|
||||
uint8_t c[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
this->send_command_(TuyaCommandType::LOCAL_TIME_QUERY, c, 8);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "TUYA_CMD_LOCAL_TIME_QUERY is not handled because time is not configured");
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "LOCAL_TIME_QUERY is not handled");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(TAG, "invalid command (%02x) received", command);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user