mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[remote_transmitter] Add non-blocking mode (#11524)
This commit is contained in:
		| @@ -1,3 +1,5 @@ | ||||
| import logging | ||||
|  | ||||
| from esphome import automation, pins | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import esp32, esp32_rmt, remote_base | ||||
| @@ -18,9 +20,12 @@ from esphome.const import ( | ||||
| ) | ||||
| from esphome.core import CORE | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| AUTO_LOAD = ["remote_base"] | ||||
|  | ||||
| CONF_EOT_LEVEL = "eot_level" | ||||
| CONF_NON_BLOCKING = "non_blocking" | ||||
| CONF_ON_TRANSMIT = "on_transmit" | ||||
| CONF_ON_COMPLETE = "on_complete" | ||||
| CONF_TRANSMITTER_ID = remote_base.CONF_TRANSMITTER_ID | ||||
| @@ -65,11 +70,25 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|             esp32_c6=48, | ||||
|             esp32_h2=48, | ||||
|         ): cv.All(cv.only_on_esp32, cv.int_range(min=2)), | ||||
|         cv.Optional(CONF_NON_BLOCKING): cv.All(cv.only_on_esp32, cv.boolean), | ||||
|         cv.Optional(CONF_ON_TRANSMIT): automation.validate_automation(single=True), | ||||
|         cv.Optional(CONF_ON_COMPLETE): automation.validate_automation(single=True), | ||||
|     } | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
|  | ||||
| def _validate_non_blocking(config): | ||||
|     if CORE.is_esp32 and CONF_NON_BLOCKING not in config: | ||||
|         _LOGGER.warning( | ||||
|             "'non_blocking' is not set for 'remote_transmitter' and will default to 'true'.\n" | ||||
|             "The default behavior changed in 2025.11.0; previously blocking mode was used.\n" | ||||
|             "To silence this warning, explicitly set 'non_blocking: true' (or 'false')." | ||||
|         ) | ||||
|         config[CONF_NON_BLOCKING] = True | ||||
|  | ||||
|  | ||||
| FINAL_VALIDATE_SCHEMA = _validate_non_blocking | ||||
|  | ||||
| DIGITAL_WRITE_ACTION_SCHEMA = cv.maybe_simple_value( | ||||
|     { | ||||
|         cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(RemoteTransmitterComponent), | ||||
| @@ -95,6 +114,7 @@ async def to_code(config): | ||||
|     if CORE.is_esp32: | ||||
|         var = cg.new_Pvariable(config[CONF_ID], pin) | ||||
|         cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS])) | ||||
|         cg.add(var.set_non_blocking(config[CONF_NON_BLOCKING])) | ||||
|         if CONF_CLOCK_RESOLUTION in config: | ||||
|             cg.add(var.set_clock_resolution(config[CONF_CLOCK_RESOLUTION])) | ||||
|         if CONF_USE_DMA in config: | ||||
|   | ||||
| @@ -54,6 +54,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, | ||||
| #if defined(USE_ESP32) | ||||
|   void set_with_dma(bool with_dma) { this->with_dma_ = with_dma; } | ||||
|   void set_eot_level(bool eot_level) { this->eot_level_ = eot_level; } | ||||
|   void set_non_blocking(bool non_blocking) { this->non_blocking_ = non_blocking; } | ||||
| #endif | ||||
|  | ||||
|   Trigger<> *get_transmit_trigger() const { return this->transmit_trigger_; }; | ||||
| @@ -74,6 +75,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|   void configure_rmt_(); | ||||
|   void wait_for_rmt_(); | ||||
|  | ||||
| #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1) | ||||
|   RemoteTransmitterComponentStore store_{}; | ||||
| @@ -90,6 +92,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, | ||||
|   esp_err_t error_code_{ESP_OK}; | ||||
|   std::string error_string_{""}; | ||||
|   bool inverted_{false}; | ||||
|   bool non_blocking_{false}; | ||||
| #endif | ||||
|   uint8_t carrier_duty_percent_; | ||||
|  | ||||
|   | ||||
| @@ -196,12 +196,29 @@ void RemoteTransmitterComponent::configure_rmt_() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void RemoteTransmitterComponent::wait_for_rmt_() { | ||||
|   esp_err_t error = rmt_tx_wait_all_done(this->channel_, -1); | ||||
|   if (error != ESP_OK) { | ||||
|     ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error)); | ||||
|     this->status_set_warning(); | ||||
|   } | ||||
|  | ||||
|   this->complete_trigger_->trigger(); | ||||
| } | ||||
|  | ||||
| #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1) | ||||
| void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { | ||||
|   uint64_t total_duration = 0; | ||||
|  | ||||
|   if (this->is_failed()) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // if the timeout was cancelled, block until the tx is complete | ||||
|   if (this->non_blocking_ && this->cancel_timeout("complete")) { | ||||
|     this->wait_for_rmt_(); | ||||
|   } | ||||
|  | ||||
|   if (this->current_carrier_frequency_ != this->temp_.get_carrier_frequency()) { | ||||
|     this->current_carrier_frequency_ = this->temp_.get_carrier_frequency(); | ||||
|     this->configure_rmt_(); | ||||
| @@ -212,6 +229,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen | ||||
|  | ||||
|   // encode any delay at the start of the buffer to simplify the encoder callback | ||||
|   // this will be skipped the first time around | ||||
|   total_duration += send_wait * (send_times - 1); | ||||
|   send_wait = this->from_microseconds_(static_cast<uint32_t>(send_wait)); | ||||
|   while (send_wait > 0) { | ||||
|     int32_t duration = std::min(send_wait, uint32_t(RMT_SYMBOL_DURATION_MAX)); | ||||
| @@ -229,6 +247,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen | ||||
|     if (!level) { | ||||
|       value = -value; | ||||
|     } | ||||
|     total_duration += value * send_times; | ||||
|     value = this->from_microseconds_(static_cast<uint32_t>(value)); | ||||
|     while (value > 0) { | ||||
|       int32_t duration = std::min(value, int32_t(RMT_SYMBOL_DURATION_MAX)); | ||||
| @@ -260,13 +279,12 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen | ||||
|   } else { | ||||
|     this->status_clear_warning(); | ||||
|   } | ||||
|   error = rmt_tx_wait_all_done(this->channel_, -1); | ||||
|   if (error != ESP_OK) { | ||||
|     ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error)); | ||||
|     this->status_set_warning(); | ||||
|   } | ||||
|  | ||||
|   this->complete_trigger_->trigger(); | ||||
|   if (this->non_blocking_) { | ||||
|     this->set_timeout("complete", total_duration / 1000, [this]() { this->wait_for_rmt_(); }); | ||||
|   } else { | ||||
|     this->wait_for_rmt_(); | ||||
|   } | ||||
| } | ||||
| #else | ||||
| void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { | ||||
|   | ||||
| @@ -2,6 +2,7 @@ remote_transmitter: | ||||
|   - id: xmitr | ||||
|     pin: ${pin} | ||||
|     carrier_duty_percent: 50% | ||||
|     non_blocking: true | ||||
|     clock_resolution: ${clock_resolution} | ||||
|     rmt_symbols: ${rmt_symbols} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user