mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Tuya status gpio support (#3466)
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							fea05e9d33
						
					
				
				
					commit
					0665acd190
				
			| @@ -1,5 +1,6 @@ | |||||||
| from esphome.components import time | from esphome.components import time | ||||||
| from esphome import automation | from esphome import automation | ||||||
|  | from esphome import pins | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import uart | from esphome.components import uart | ||||||
| @@ -11,6 +12,7 @@ CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS = "ignore_mcu_update_on_datapoints" | |||||||
|  |  | ||||||
| CONF_ON_DATAPOINT_UPDATE = "on_datapoint_update" | CONF_ON_DATAPOINT_UPDATE = "on_datapoint_update" | ||||||
| CONF_DATAPOINT_TYPE = "datapoint_type" | CONF_DATAPOINT_TYPE = "datapoint_type" | ||||||
|  | CONF_STATUS_PIN = "status_pin" | ||||||
|  |  | ||||||
| tuya_ns = cg.esphome_ns.namespace("tuya") | tuya_ns = cg.esphome_ns.namespace("tuya") | ||||||
| Tuya = tuya_ns.class_("Tuya", cg.Component, uart.UARTDevice) | Tuya = tuya_ns.class_("Tuya", cg.Component, uart.UARTDevice) | ||||||
| @@ -88,6 +90,7 @@ CONFIG_SCHEMA = ( | |||||||
|             cv.Optional(CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS): cv.ensure_list( |             cv.Optional(CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS): cv.ensure_list( | ||||||
|                 cv.uint8_t |                 cv.uint8_t | ||||||
|             ), |             ), | ||||||
|  |             cv.Optional(CONF_STATUS_PIN): pins.gpio_output_pin_schema, | ||||||
|             cv.Optional(CONF_ON_DATAPOINT_UPDATE): automation.validate_automation( |             cv.Optional(CONF_ON_DATAPOINT_UPDATE): automation.validate_automation( | ||||||
|                 { |                 { | ||||||
|                     cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( |                     cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( | ||||||
| @@ -114,6 +117,9 @@ async def to_code(config): | |||||||
|     if CONF_TIME_ID in config: |     if CONF_TIME_ID in config: | ||||||
|         time_ = await cg.get_variable(config[CONF_TIME_ID]) |         time_ = await cg.get_variable(config[CONF_TIME_ID]) | ||||||
|         cg.add(var.set_time_id(time_)) |         cg.add(var.set_time_id(time_)) | ||||||
|  |     if CONF_STATUS_PIN in config: | ||||||
|  |         status_pin_ = await cg.gpio_pin_expression(config[CONF_STATUS_PIN]) | ||||||
|  |         cg.add(var.set_status_pin(status_pin_)) | ||||||
|     if CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS in config: |     if CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS in config: | ||||||
|         for dp in config[CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS]: |         for dp in config[CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS]: | ||||||
|             cg.add(var.add_ignore_mcu_update_on_datapoints(dp)) |             cg.add(var.add_ignore_mcu_update_on_datapoints(dp)) | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| #include "esphome/components/network/util.h" | #include "esphome/components/network/util.h" | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| #include "esphome/core/util.h" | #include "esphome/core/util.h" | ||||||
|  | #include "esphome/core/gpio.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace tuya { | namespace tuya { | ||||||
| @@ -13,6 +14,9 @@ static const int RECEIVE_TIMEOUT = 300; | |||||||
|  |  | ||||||
| void Tuya::setup() { | void Tuya::setup() { | ||||||
|   this->set_interval("heartbeat", 15000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); }); |   this->set_interval("heartbeat", 15000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); }); | ||||||
|  |   if (this->status_pin_.has_value()) { | ||||||
|  |     this->status_pin_.value()->digital_write(false); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void Tuya::loop() { | void Tuya::loop() { | ||||||
| @@ -49,9 +53,12 @@ void Tuya::dump_config() { | |||||||
|       ESP_LOGCONFIG(TAG, "  Datapoint %u: unknown", info.id); |       ESP_LOGCONFIG(TAG, "  Datapoint %u: unknown", info.id); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   if ((this->gpio_status_ != -1) || (this->gpio_reset_ != -1)) { |   if ((this->status_pin_reported_ != -1) || (this->reset_pin_reported_ != -1)) { | ||||||
|     ESP_LOGCONFIG(TAG, "  GPIO Configuration: status: pin %d, reset: pin %d (not supported)", this->gpio_status_, |     ESP_LOGCONFIG(TAG, "  GPIO Configuration: status: pin %d, reset: pin %d (not supported)", | ||||||
|                   this->gpio_reset_); |                   this->status_pin_reported_, this->reset_pin_reported_); | ||||||
|  |   } | ||||||
|  |   if (this->status_pin_.has_value()) { | ||||||
|  |     LOG_PIN("  Status Pin: ", this->status_pin_.value()); | ||||||
|   } |   } | ||||||
|   ESP_LOGCONFIG(TAG, "  Product: '%s'", this->product_.c_str()); |   ESP_LOGCONFIG(TAG, "  Product: '%s'", this->product_.c_str()); | ||||||
|   this->check_uart_settings(9600); |   this->check_uart_settings(9600); | ||||||
| @@ -164,16 +171,27 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff | |||||||
|     } |     } | ||||||
|     case TuyaCommandType::CONF_QUERY: { |     case TuyaCommandType::CONF_QUERY: { | ||||||
|       if (len >= 2) { |       if (len >= 2) { | ||||||
|         this->gpio_status_ = buffer[0]; |         this->status_pin_reported_ = buffer[0]; | ||||||
|         this->gpio_reset_ = buffer[1]; |         this->reset_pin_reported_ = buffer[1]; | ||||||
|       } |       } | ||||||
|       if (this->init_state_ == TuyaInitState::INIT_CONF) { |       if (this->init_state_ == TuyaInitState::INIT_CONF) { | ||||||
|         // If mcu returned status gpio, then we can omit sending wifi state |         // If mcu returned status gpio, then we can omit sending wifi state | ||||||
|         if (this->gpio_status_ != -1) { |         if (this->status_pin_reported_ != -1) { | ||||||
|           this->init_state_ = TuyaInitState::INIT_DATAPOINT; |           this->init_state_ = TuyaInitState::INIT_DATAPOINT; | ||||||
|           this->send_empty_command_(TuyaCommandType::DATAPOINT_QUERY); |           this->send_empty_command_(TuyaCommandType::DATAPOINT_QUERY); | ||||||
|  |           bool is_pin_equals = | ||||||
|  |               this->status_pin_.has_value() && this->status_pin_.value()->get_pin() == this->status_pin_reported_; | ||||||
|  |           // Configure status pin toggling (if reported and configured) or WIFI_STATE periodic send | ||||||
|  |           if (is_pin_equals) { | ||||||
|  |             ESP_LOGV(TAG, "Configured status pin %i", this->status_pin_reported_); | ||||||
|  |             this->set_interval("wifi", 1000, [this] { this->set_status_pin_(); }); | ||||||
|  |           } else { | ||||||
|  |             ESP_LOGW(TAG, "Supplied status_pin does not equals the reported pin %i. TuyaMcu will work in limited mode.", | ||||||
|  |                      this->status_pin_reported_); | ||||||
|  |           } | ||||||
|         } else { |         } else { | ||||||
|           this->init_state_ = TuyaInitState::INIT_WIFI; |           this->init_state_ = TuyaInitState::INIT_WIFI; | ||||||
|  |           ESP_LOGV(TAG, "Configured WIFI_STATE periodic send"); | ||||||
|           this->set_interval("wifi", 1000, [this] { this->send_wifi_status_(); }); |           this->set_interval("wifi", 1000, [this] { this->send_wifi_status_(); }); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -397,18 +415,21 @@ void Tuya::send_empty_command_(TuyaCommandType command) { | |||||||
|   send_command_(TuyaCommand{.cmd = command, .payload = std::vector<uint8_t>{}}); |   send_command_(TuyaCommand{.cmd = command, .payload = std::vector<uint8_t>{}}); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void Tuya::set_status_pin_() { | ||||||
|  |   bool is_network_ready = network::is_connected() && remote_is_connected(); | ||||||
|  |   this->status_pin_.value()->digital_write(is_network_ready); | ||||||
|  | } | ||||||
|  |  | ||||||
| void Tuya::send_wifi_status_() { | void Tuya::send_wifi_status_() { | ||||||
|   uint8_t status = 0x02; |   uint8_t status = 0x02; | ||||||
|   if (network::is_connected()) { |   if (network::is_connected()) { | ||||||
|     status = 0x03; |     status = 0x03; | ||||||
|  |  | ||||||
|     // Protocol version 3 also supports specifying when connected to "the cloud" |     // Protocol version 3 also supports specifying when connected to "the cloud" | ||||||
|     if (this->protocol_version_ >= 0x03) { |     if (this->protocol_version_ >= 0x03 && remote_is_connected()) { | ||||||
|       if (remote_is_connected()) { |  | ||||||
|       status = 0x04; |       status = 0x04; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (status == this->wifi_status_) { |   if (status == this->wifi_status_) { | ||||||
|     return; |     return; | ||||||
|   | |||||||
| @@ -79,6 +79,7 @@ class Tuya : public Component, public uart::UARTDevice { | |||||||
|   void set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value); |   void set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value); | ||||||
|   void set_boolean_datapoint_value(uint8_t datapoint_id, bool value); |   void set_boolean_datapoint_value(uint8_t datapoint_id, bool value); | ||||||
|   void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value); |   void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value); | ||||||
|  |   void set_status_pin(InternalGPIOPin *status_pin) { this->status_pin_ = status_pin; } | ||||||
|   void set_string_datapoint_value(uint8_t datapoint_id, const std::string &value); |   void set_string_datapoint_value(uint8_t datapoint_id, const std::string &value); | ||||||
|   void set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value); |   void set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value); | ||||||
|   void set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length); |   void set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length); | ||||||
| @@ -115,6 +116,7 @@ class Tuya : public Component, public uart::UARTDevice { | |||||||
|   void set_string_datapoint_value_(uint8_t datapoint_id, const std::string &value, bool forced); |   void set_string_datapoint_value_(uint8_t datapoint_id, const std::string &value, bool forced); | ||||||
|   void set_raw_datapoint_value_(uint8_t datapoint_id, const std::vector<uint8_t> &value, bool forced); |   void set_raw_datapoint_value_(uint8_t datapoint_id, const std::vector<uint8_t> &value, bool forced); | ||||||
|   void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data); |   void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data); | ||||||
|  |   void set_status_pin_(); | ||||||
|   void send_wifi_status_(); |   void send_wifi_status_(); | ||||||
|  |  | ||||||
| #ifdef USE_TIME | #ifdef USE_TIME | ||||||
| @@ -123,8 +125,9 @@ class Tuya : public Component, public uart::UARTDevice { | |||||||
| #endif | #endif | ||||||
|   TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT; |   TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT; | ||||||
|   uint8_t protocol_version_ = -1; |   uint8_t protocol_version_ = -1; | ||||||
|   int gpio_status_ = -1; |   optional<InternalGPIOPin *> status_pin_{}; | ||||||
|   int gpio_reset_ = -1; |   int status_pin_reported_ = -1; | ||||||
|  |   int reset_pin_reported_ = -1; | ||||||
|   uint32_t last_command_timestamp_ = 0; |   uint32_t last_command_timestamp_ = 0; | ||||||
|   uint32_t last_rx_char_timestamp_ = 0; |   uint32_t last_rx_char_timestamp_ = 0; | ||||||
|   std::string product_ = ""; |   std::string product_ = ""; | ||||||
|   | |||||||
| @@ -57,6 +57,9 @@ time: | |||||||
|  |  | ||||||
| tuya: | tuya: | ||||||
|   time_id: sntp_time |   time_id: sntp_time | ||||||
|  |   status_pin: | ||||||
|  |     number: 14 | ||||||
|  |     inverted: true | ||||||
|  |  | ||||||
| pipsolar: | pipsolar: | ||||||
|     id: inverter0 |     id: inverter0 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user