diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 9793565ee5..7b14c803b2 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -3493,7 +3493,7 @@ bool SubscribeLogsResponse::decode_length(uint32_t field_id, ProtoLengthDelimite } void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_enum(1, this->level); - buffer.encode_string(3, this->message); + buffer.encode_bytes(3, reinterpret_cast(this->message.data()), this->message.size()); buffer.encode_bool(4, this->send_failed); } void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const { @@ -3529,7 +3529,9 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD return false; } } -void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->key); } +void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_bytes(1, reinterpret_cast(this->key.data()), this->key.size()); +} void NoiseEncryptionSetKeyRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->key, false); } @@ -4266,7 +4268,7 @@ bool CameraImageResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { } void CameraImageResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_string(2, this->data); + buffer.encode_bytes(2, reinterpret_cast(this->data.data()), this->data.size()); buffer.encode_bool(3, this->done); } void CameraImageResponse::calculate_size(uint32_t &total_size) const { @@ -6784,7 +6786,7 @@ void BluetoothServiceData::encode(ProtoWriteBuffer buffer) const { for (auto &it : this->legacy_data) { buffer.encode_uint32(2, it, true); } - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothServiceData::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->uuid, false); @@ -6858,7 +6860,7 @@ bool BluetoothLEAdvertisementResponse::decode_length(uint32_t field_id, ProtoLen } void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); - buffer.encode_string(2, this->name); + buffer.encode_bytes(2, reinterpret_cast(this->name.data()), this->name.size()); buffer.encode_sint32(3, this->rssi); for (auto &it : this->service_uuids) { buffer.encode_string(4, it, true); @@ -6959,7 +6961,7 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_sint32(2, this->rssi); buffer.encode_uint32(3, this->address_type); - buffer.encode_string(4, this->data); + buffer.encode_bytes(4, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothLERawAdvertisement::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); @@ -7492,7 +7494,7 @@ bool BluetoothGATTReadResponse::decode_length(uint32_t field_id, ProtoLengthDeli void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTReadResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); @@ -7551,7 +7553,7 @@ void BluetoothGATTWriteRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); buffer.encode_bool(3, this->response); - buffer.encode_string(4, this->data); + buffer.encode_bytes(4, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTWriteRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); @@ -7648,7 +7650,7 @@ bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, Proto void BluetoothGATTWriteDescriptorRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTWriteDescriptorRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); @@ -7750,7 +7752,7 @@ bool BluetoothGATTNotifyDataResponse::decode_length(uint32_t field_id, ProtoLeng void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTNotifyDataResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); @@ -8480,7 +8482,7 @@ bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited } } void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->data); + buffer.encode_bytes(1, reinterpret_cast(this->data.data()), this->data.size()); buffer.encode_bool(2, this->end); } void VoiceAssistantAudio::calculate_size(uint32_t &total_size) const { diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.cpp b/esphome/components/esp32_rmt_led_strip/led_strip.cpp index dfdf50aa66..389c32882b 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.cpp +++ b/esphome/components/esp32_rmt_led_strip/led_strip.cpp @@ -21,6 +21,43 @@ static const uint32_t RMT_CLK_FREQ = 80000000; static const uint8_t RMT_CLK_DIV = 2; #endif +static const size_t RMT_SYMBOLS_PER_BYTE = 8; + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) +static size_t IRAM_ATTR HOT encoder_callback(const void *data, size_t size, size_t symbols_written, size_t symbols_free, + rmt_symbol_word_t *symbols, bool *done, void *arg) { + auto *params = static_cast(arg); + const auto *bytes = static_cast(data); + size_t index = symbols_written / RMT_SYMBOLS_PER_BYTE; + + // convert byte to symbols + if (index < size) { + if (symbols_free < RMT_SYMBOLS_PER_BYTE) { + return 0; + } + for (int32_t i = 0; i < RMT_SYMBOLS_PER_BYTE; i++) { + if (bytes[index] & (1 << (7 - i))) { + symbols[i] = params->bit1; + } else { + symbols[i] = params->bit0; + } + } + if ((index + 1) >= size && params->reset.duration0 == 0 && params->reset.duration1 == 0) { + *done = true; + } + return RMT_SYMBOLS_PER_BYTE; + } + + // send reset + if (symbols_free < 1) { + return 0; + } + symbols[0] = params->reset; + *done = true; + return 1; +} +#endif + void ESP32RMTLEDStripLightOutput::setup() { ESP_LOGCONFIG(TAG, "Running setup"); @@ -42,10 +79,15 @@ void ESP32RMTLEDStripLightOutput::setup() { return; } +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + // copy of the led buffer + this->rmt_buf_ = allocator.allocate(buffer_size); +#else RAMAllocator rmt_allocator(this->use_psram_ ? 0 : RAMAllocator::ALLOC_INTERNAL); // 8 bits per byte, 1 rmt_symbol_word_t per bit + 1 rmt_symbol_word_t for reset this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + 1); +#endif rmt_tx_channel_config_t channel; memset(&channel, 0, sizeof(channel)); @@ -65,6 +107,18 @@ void ESP32RMTLEDStripLightOutput::setup() { return; } +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + rmt_simple_encoder_config_t encoder; + memset(&encoder, 0, sizeof(encoder)); + encoder.callback = encoder_callback; + encoder.arg = &this->params_; + encoder.min_chunk_size = 8; + if (rmt_new_simple_encoder(&encoder, &this->encoder_) != ESP_OK) { + ESP_LOGE(TAG, "Encoder creation failed"); + this->mark_failed(); + return; + } +#else rmt_copy_encoder_config_t encoder; memset(&encoder, 0, sizeof(encoder)); if (rmt_new_copy_encoder(&encoder, &this->encoder_) != ESP_OK) { @@ -72,6 +126,7 @@ void ESP32RMTLEDStripLightOutput::setup() { this->mark_failed(); return; } +#endif if (rmt_enable(this->channel_) != ESP_OK) { ESP_LOGE(TAG, "Enabling channel failed"); @@ -85,20 +140,20 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f; // 0-bit - this->bit0_.duration0 = (uint32_t) (ratio * bit0_high); - this->bit0_.level0 = 1; - this->bit0_.duration1 = (uint32_t) (ratio * bit0_low); - this->bit0_.level1 = 0; + this->params_.bit0.duration0 = (uint32_t) (ratio * bit0_high); + this->params_.bit0.level0 = 1; + this->params_.bit0.duration1 = (uint32_t) (ratio * bit0_low); + this->params_.bit0.level1 = 0; // 1-bit - this->bit1_.duration0 = (uint32_t) (ratio * bit1_high); - this->bit1_.level0 = 1; - this->bit1_.duration1 = (uint32_t) (ratio * bit1_low); - this->bit1_.level1 = 0; + this->params_.bit1.duration0 = (uint32_t) (ratio * bit1_high); + this->params_.bit1.level0 = 1; + this->params_.bit1.duration1 = (uint32_t) (ratio * bit1_low); + this->params_.bit1.level1 = 0; // reset - this->reset_.duration0 = (uint32_t) (ratio * reset_time_high); - this->reset_.level0 = 1; - this->reset_.duration1 = (uint32_t) (ratio * reset_time_low); - this->reset_.level1 = 0; + this->params_.reset.duration0 = (uint32_t) (ratio * reset_time_high); + this->params_.reset.level0 = 1; + this->params_.reset.duration1 = (uint32_t) (ratio * reset_time_low); + this->params_.reset.level1 = 0; } void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { @@ -122,6 +177,9 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { } delayMicroseconds(50); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + memcpy(this->rmt_buf_, this->buf_, this->get_buffer_size_()); +#else size_t buffer_size = this->get_buffer_size_(); size_t size = 0; @@ -131,7 +189,7 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { while (size < buffer_size) { uint8_t b = *psrc; for (int i = 0; i < 8; i++) { - pdest->val = b & (1 << (7 - i)) ? this->bit1_.val : this->bit0_.val; + pdest->val = b & (1 << (7 - i)) ? this->params_.bit1.val : this->params_.bit0.val; pdest++; len++; } @@ -139,17 +197,20 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { psrc++; } - if (this->reset_.duration0 > 0 || this->reset_.duration1 > 0) { - pdest->val = this->reset_.val; + if (this->params_.reset.duration0 > 0 || this->params_.reset.duration1 > 0) { + pdest->val = this->params_.reset.val; pdest++; len++; } +#endif rmt_transmit_config_t config; memset(&config, 0, sizeof(config)); - config.loop_count = 0; - config.flags.eot_level = 0; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, this->get_buffer_size_(), &config); +#else error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config); +#endif if (error != ESP_OK) { ESP_LOGE(TAG, "RMT TX error"); this->status_set_warning(); diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.h b/esphome/components/esp32_rmt_led_strip/led_strip.h index c6a2b4bc9f..72ce659b4f 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.h +++ b/esphome/components/esp32_rmt_led_strip/led_strip.h @@ -25,6 +25,12 @@ enum RGBOrder : uint8_t { ORDER_BRG, }; +struct LedParams { + rmt_symbol_word_t bit0; + rmt_symbol_word_t bit1; + rmt_symbol_word_t reset; +}; + class ESP32RMTLEDStripLightOutput : public light::AddressableLight { public: void setup() override; @@ -72,12 +78,15 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { uint8_t *buf_{nullptr}; uint8_t *effect_data_{nullptr}; + LedParams params_; rmt_channel_handle_t channel_{nullptr}; rmt_encoder_handle_t encoder_{nullptr}; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + uint8_t *rmt_buf_{nullptr}; +#else rmt_symbol_word_t *rmt_buf_{nullptr}; - rmt_symbol_word_t bit0_, bit1_, reset_; +#endif uint32_t rmt_symbols_{48}; - uint8_t pin_; uint16_t num_leds_; bool is_rgbw_{false}; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index ad8e41ba5e..15313f48ee 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -526,9 +526,13 @@ class BytesType(TypeInfo): reference_type = "std::string &" const_reference_type = "const std::string &" decode_length = "value.as_string()" - encode_func = "encode_string" + encode_func = "encode_bytes" wire_type = WireType.LENGTH_DELIMITED # Uses wire type 2 + @property + def encode_content(self) -> str: + return f"buffer.encode_bytes({self.number}, reinterpret_cast(this->{self.field_name}.data()), this->{self.field_name}.size());" + def dump(self, name: str) -> str: o = f'out.append("\'").append({name}).append("\'");' return o