mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 23:21:54 +00:00 
			
		
		
		
	Merge branch 'dev' into disable_ethernet_loop
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							| @@ -49,7 +49,7 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           python-version: "3.10" |           python-version: "3.10" | ||||||
|       - name: Set up Docker Buildx |       - name: Set up Docker Buildx | ||||||
|         uses: docker/setup-buildx-action@v3.11.0 |         uses: docker/setup-buildx-action@v3.11.1 | ||||||
|  |  | ||||||
|       - name: Set TAG |       - name: Set TAG | ||||||
|         run: | |         run: | | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -99,7 +99,7 @@ jobs: | |||||||
|           python-version: "3.10" |           python-version: "3.10" | ||||||
|  |  | ||||||
|       - name: Set up Docker Buildx |       - name: Set up Docker Buildx | ||||||
|         uses: docker/setup-buildx-action@v3.11.0 |         uses: docker/setup-buildx-action@v3.11.1 | ||||||
|  |  | ||||||
|       - name: Log in to docker hub |       - name: Log in to docker hub | ||||||
|         uses: docker/login-action@v3.4.0 |         uses: docker/login-action@v3.4.0 | ||||||
| @@ -178,7 +178,7 @@ jobs: | |||||||
|           merge-multiple: true |           merge-multiple: true | ||||||
|  |  | ||||||
|       - name: Set up Docker Buildx |       - name: Set up Docker Buildx | ||||||
|         uses: docker/setup-buildx-action@v3.11.0 |         uses: docker/setup-buildx-action@v3.11.1 | ||||||
|  |  | ||||||
|       - name: Log in to docker hub |       - name: Log in to docker hub | ||||||
|         if: matrix.registry == 'dockerhub' |         if: matrix.registry == 'dockerhub' | ||||||
|   | |||||||
| @@ -193,14 +193,13 @@ void AcDimmer::setup() { | |||||||
|   setTimer1Callback(&timer_interrupt); |   setTimer1Callback(&timer_interrupt); | ||||||
| #endif | #endif | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|   // 80 Divider -> 1 count=1µs |   // timer frequency of 1mhz | ||||||
|   dimmer_timer = timerBegin(0, 80, true); |   dimmer_timer = timerBegin(1000000); | ||||||
|   timerAttachInterrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr, true); |   timerAttachInterrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr); | ||||||
|   // For ESP32, we can't use dynamic interval calculation because the timerX functions |   // For ESP32, we can't use dynamic interval calculation because the timerX functions | ||||||
|   // are not callable from ISR (placed in flash storage). |   // are not callable from ISR (placed in flash storage). | ||||||
|   // Here we just use an interrupt firing every 50 µs. |   // Here we just use an interrupt firing every 50 µs. | ||||||
|   timerAlarmWrite(dimmer_timer, 50, true); |   timerAlarm(dimmer_timer, 50, true, 0); | ||||||
|   timerAlarmEnable(dimmer_timer); |  | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| void AcDimmer::write_state(float state) { | void AcDimmer::write_state(float state) { | ||||||
|   | |||||||
| @@ -61,8 +61,8 @@ void APIConnection::start() { | |||||||
|   APIError err = this->helper_->init(); |   APIError err = this->helper_->init(); | ||||||
|   if (err != APIError::OK) { |   if (err != APIError::OK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err), |     ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", this->get_client_combined_info().c_str(), | ||||||
|              errno); |              api_error_to_str(err), errno); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   this->client_info_ = helper_->getpeername(); |   this->client_info_ = helper_->getpeername(); | ||||||
| @@ -91,7 +91,7 @@ void APIConnection::loop() { | |||||||
|     // when network is disconnected force disconnect immediately |     // when network is disconnected force disconnect immediately | ||||||
|     // don't wait for timeout |     // don't wait for timeout | ||||||
|     this->on_fatal_error(); |     this->on_fatal_error(); | ||||||
|     ESP_LOGW(TAG, "%s: Network unavailable; disconnecting", this->client_combined_info_.c_str()); |     ESP_LOGW(TAG, "%s: Network unavailable; disconnecting", this->get_client_combined_info().c_str()); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   if (this->next_close_) { |   if (this->next_close_) { | ||||||
| @@ -104,7 +104,7 @@ void APIConnection::loop() { | |||||||
|   APIError err = this->helper_->loop(); |   APIError err = this->helper_->loop(); | ||||||
|   if (err != APIError::OK) { |   if (err != APIError::OK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(), |     ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->get_client_combined_info().c_str(), | ||||||
|              api_error_to_str(err), errno); |              api_error_to_str(err), errno); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| @@ -118,12 +118,12 @@ void APIConnection::loop() { | |||||||
|     } else if (err != APIError::OK) { |     } else if (err != APIError::OK) { | ||||||
|       on_fatal_error(); |       on_fatal_error(); | ||||||
|       if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) { |       if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) { | ||||||
|         ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str()); |         ESP_LOGW(TAG, "%s: Connection reset", this->get_client_combined_info().c_str()); | ||||||
|       } else if (err == APIError::CONNECTION_CLOSED) { |       } else if (err == APIError::CONNECTION_CLOSED) { | ||||||
|         ESP_LOGW(TAG, "%s: Connection closed", this->client_combined_info_.c_str()); |         ESP_LOGW(TAG, "%s: Connection closed", this->get_client_combined_info().c_str()); | ||||||
|       } else { |       } else { | ||||||
|         ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err), |         ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->get_client_combined_info().c_str(), | ||||||
|                  errno); |                  api_error_to_str(err), errno); | ||||||
|       } |       } | ||||||
|       return; |       return; | ||||||
|     } else { |     } else { | ||||||
| @@ -157,7 +157,7 @@ void APIConnection::loop() { | |||||||
|     // Disconnect if not responded within 2.5*keepalive |     // Disconnect if not responded within 2.5*keepalive | ||||||
|     if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) { |     if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) { | ||||||
|       on_fatal_error(); |       on_fatal_error(); | ||||||
|       ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->client_combined_info_.c_str()); |       ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->get_client_combined_info().c_str()); | ||||||
|     } |     } | ||||||
|   } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) { |   } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) { | ||||||
|     ESP_LOGVV(TAG, "Sending keepalive PING"); |     ESP_LOGVV(TAG, "Sending keepalive PING"); | ||||||
| @@ -166,7 +166,7 @@ void APIConnection::loop() { | |||||||
|       this->next_ping_retry_ = now + ping_retry_interval; |       this->next_ping_retry_ = now + ping_retry_interval; | ||||||
|       this->ping_retries_++; |       this->ping_retries_++; | ||||||
|       std::string warn_str = str_sprintf("%s: Sending keepalive failed %u time(s);", |       std::string warn_str = str_sprintf("%s: Sending keepalive failed %u time(s);", | ||||||
|                                          this->client_combined_info_.c_str(), this->ping_retries_); |                                          this->get_client_combined_info().c_str(), this->ping_retries_); | ||||||
|       if (this->ping_retries_ >= max_ping_retries) { |       if (this->ping_retries_ >= max_ping_retries) { | ||||||
|         on_fatal_error(); |         on_fatal_error(); | ||||||
|         ESP_LOGE(TAG, "%s disconnecting", warn_str.c_str()); |         ESP_LOGE(TAG, "%s disconnecting", warn_str.c_str()); | ||||||
| @@ -233,7 +233,7 @@ DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) { | |||||||
|   // remote initiated disconnect_client |   // remote initiated disconnect_client | ||||||
|   // don't close yet, we still need to send the disconnect response |   // don't close yet, we still need to send the disconnect response | ||||||
|   // close will happen on next loop |   // close will happen on next loop | ||||||
|   ESP_LOGD(TAG, "%s disconnected", this->client_combined_info_.c_str()); |   ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str()); | ||||||
|   this->next_close_ = true; |   this->next_close_ = true; | ||||||
|   DisconnectResponse resp; |   DisconnectResponse resp; | ||||||
|   return resp; |   return resp; | ||||||
| @@ -1544,8 +1544,7 @@ bool APIConnection::try_send_log_message(int level, const char *tag, const char | |||||||
| HelloResponse APIConnection::hello(const HelloRequest &msg) { | HelloResponse APIConnection::hello(const HelloRequest &msg) { | ||||||
|   this->client_info_ = msg.client_info; |   this->client_info_ = msg.client_info; | ||||||
|   this->client_peername_ = this->helper_->getpeername(); |   this->client_peername_ = this->helper_->getpeername(); | ||||||
|   this->client_combined_info_ = this->client_info_ + " (" + this->client_peername_ + ")"; |   this->helper_->set_log_info(this->get_client_combined_info()); | ||||||
|   this->helper_->set_log_info(this->client_combined_info_); |  | ||||||
|   this->client_api_version_major_ = msg.api_version_major; |   this->client_api_version_major_ = msg.api_version_major; | ||||||
|   this->client_api_version_minor_ = msg.api_version_minor; |   this->client_api_version_minor_ = msg.api_version_minor; | ||||||
|   ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(), |   ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(), | ||||||
| @@ -1567,7 +1566,7 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) { | |||||||
|   // bool invalid_password = 1; |   // bool invalid_password = 1; | ||||||
|   resp.invalid_password = !correct; |   resp.invalid_password = !correct; | ||||||
|   if (correct) { |   if (correct) { | ||||||
|     ESP_LOGD(TAG, "%s connected", this->client_combined_info_.c_str()); |     ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str()); | ||||||
|     this->connection_state_ = ConnectionState::AUTHENTICATED; |     this->connection_state_ = ConnectionState::AUTHENTICATED; | ||||||
|     this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_); |     this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_); | ||||||
| #ifdef USE_HOMEASSISTANT_TIME | #ifdef USE_HOMEASSISTANT_TIME | ||||||
| @@ -1673,7 +1672,7 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { | |||||||
|   APIError err = this->helper_->loop(); |   APIError err = this->helper_->loop(); | ||||||
|   if (err != APIError::OK) { |   if (err != APIError::OK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(), |     ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->get_client_combined_info().c_str(), | ||||||
|              api_error_to_str(err), errno); |              api_error_to_str(err), errno); | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| @@ -1695,10 +1694,10 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) | |||||||
|   if (err != APIError::OK) { |   if (err != APIError::OK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) { |     if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) { | ||||||
|       ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str()); |       ESP_LOGW(TAG, "%s: Connection reset", this->get_client_combined_info().c_str()); | ||||||
|     } else { |     } else { | ||||||
|       ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err), |       ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->get_client_combined_info().c_str(), | ||||||
|                errno); |                api_error_to_str(err), errno); | ||||||
|     } |     } | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| @@ -1707,11 +1706,11 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) | |||||||
| } | } | ||||||
| void APIConnection::on_unauthenticated_access() { | void APIConnection::on_unauthenticated_access() { | ||||||
|   this->on_fatal_error(); |   this->on_fatal_error(); | ||||||
|   ESP_LOGD(TAG, "%s requested access without authentication", this->client_combined_info_.c_str()); |   ESP_LOGD(TAG, "%s requested access without authentication", this->get_client_combined_info().c_str()); | ||||||
| } | } | ||||||
| void APIConnection::on_no_setup_connection() { | void APIConnection::on_no_setup_connection() { | ||||||
|   this->on_fatal_error(); |   this->on_fatal_error(); | ||||||
|   ESP_LOGD(TAG, "%s requested access without full connection", this->client_combined_info_.c_str()); |   ESP_LOGD(TAG, "%s requested access without full connection", this->get_client_combined_info().c_str()); | ||||||
| } | } | ||||||
| void APIConnection::on_fatal_error() { | void APIConnection::on_fatal_error() { | ||||||
|   this->helper_->close(); |   this->helper_->close(); | ||||||
| @@ -1860,10 +1859,10 @@ void APIConnection::process_batch_() { | |||||||
|   if (err != APIError::OK && err != APIError::WOULD_BLOCK) { |   if (err != APIError::OK && err != APIError::WOULD_BLOCK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) { |     if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) { | ||||||
|       ESP_LOGW(TAG, "%s: Connection reset during batch write", this->client_combined_info_.c_str()); |       ESP_LOGW(TAG, "%s: Connection reset during batch write", this->get_client_combined_info().c_str()); | ||||||
|     } else { |     } else { | ||||||
|       ESP_LOGW(TAG, "%s: Batch write failed %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err), |       ESP_LOGW(TAG, "%s: Batch write failed %s errno=%d", this->get_client_combined_info().c_str(), | ||||||
|                errno); |                api_error_to_str(err), errno); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -275,7 +275,13 @@ class APIConnection : public APIServerConnection { | |||||||
|   bool try_to_clear_buffer(bool log_out_of_space); |   bool try_to_clear_buffer(bool log_out_of_space); | ||||||
|   bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) override; |   bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) override; | ||||||
|  |  | ||||||
|   std::string get_client_combined_info() const { return this->client_combined_info_; } |   std::string get_client_combined_info() const { | ||||||
|  |     if (this->client_info_ == this->client_peername_) { | ||||||
|  |       // Before Hello message, both are the same (just IP:port) | ||||||
|  |       return this->client_info_; | ||||||
|  |     } | ||||||
|  |     return this->client_info_ + " (" + this->client_peername_ + ")"; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // Buffer allocator methods for batch processing |   // Buffer allocator methods for batch processing | ||||||
|   ProtoWriteBuffer allocate_single_message_buffer(uint16_t size); |   ProtoWriteBuffer allocate_single_message_buffer(uint16_t size); | ||||||
| @@ -432,37 +438,44 @@ class APIConnection : public APIServerConnection { | |||||||
|   // Helper function to get estimated message size for buffer pre-allocation |   // Helper function to get estimated message size for buffer pre-allocation | ||||||
|   static uint16_t get_estimated_message_size(uint16_t message_type); |   static uint16_t get_estimated_message_size(uint16_t message_type); | ||||||
|  |  | ||||||
|   enum class ConnectionState { |   // Pointers first (4 bytes each, naturally aligned) | ||||||
|  |   std::unique_ptr<APIFrameHelper> helper_; | ||||||
|  |   APIServer *parent_; | ||||||
|  |  | ||||||
|  |   // 4-byte aligned types | ||||||
|  |   uint32_t last_traffic_; | ||||||
|  |   uint32_t next_ping_retry_{0}; | ||||||
|  |   int state_subs_at_ = -1; | ||||||
|  |  | ||||||
|  |   // Strings (12 bytes each on 32-bit) | ||||||
|  |   std::string client_info_; | ||||||
|  |   std::string client_peername_; | ||||||
|  |  | ||||||
|  |   // 2-byte aligned types | ||||||
|  |   uint16_t client_api_version_major_{0}; | ||||||
|  |   uint16_t client_api_version_minor_{0}; | ||||||
|  |  | ||||||
|  |   // Group all 1-byte types together to minimize padding | ||||||
|  |   enum class ConnectionState : uint8_t { | ||||||
|     WAITING_FOR_HELLO, |     WAITING_FOR_HELLO, | ||||||
|     CONNECTED, |     CONNECTED, | ||||||
|     AUTHENTICATED, |     AUTHENTICATED, | ||||||
|   } connection_state_{ConnectionState::WAITING_FOR_HELLO}; |   } connection_state_{ConnectionState::WAITING_FOR_HELLO}; | ||||||
|  |   uint8_t log_subscription_{ESPHOME_LOG_LEVEL_NONE}; | ||||||
|   bool remove_{false}; |   bool remove_{false}; | ||||||
|  |  | ||||||
|   std::unique_ptr<APIFrameHelper> helper_; |  | ||||||
|  |  | ||||||
|   std::string client_info_; |  | ||||||
|   std::string client_peername_; |  | ||||||
|   std::string client_combined_info_; |  | ||||||
|   uint32_t client_api_version_major_{0}; |  | ||||||
|   uint32_t client_api_version_minor_{0}; |  | ||||||
| #ifdef USE_ESP32_CAMERA |  | ||||||
|   esp32_camera::CameraImageReader image_reader_; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|   bool state_subscription_{false}; |   bool state_subscription_{false}; | ||||||
|   int log_subscription_{ESPHOME_LOG_LEVEL_NONE}; |  | ||||||
|   uint32_t last_traffic_; |  | ||||||
|   uint32_t next_ping_retry_{0}; |  | ||||||
|   uint8_t ping_retries_{0}; |  | ||||||
|   bool sent_ping_{false}; |   bool sent_ping_{false}; | ||||||
|   bool service_call_subscription_{false}; |   bool service_call_subscription_{false}; | ||||||
|   bool next_close_ = false; |   bool next_close_ = false; | ||||||
|   APIServer *parent_; |   uint8_t ping_retries_{0}; | ||||||
|  |   // 8 bytes used, no padding needed | ||||||
|  |  | ||||||
|  |   // Larger objects at the end | ||||||
|   InitialStateIterator initial_state_iterator_; |   InitialStateIterator initial_state_iterator_; | ||||||
|   ListEntitiesIterator list_entities_iterator_; |   ListEntitiesIterator list_entities_iterator_; | ||||||
|   int state_subs_at_ = -1; | #ifdef USE_ESP32_CAMERA | ||||||
|  |   esp32_camera::CameraImageReader image_reader_; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   // Function pointer type for message encoding |   // Function pointer type for message encoding | ||||||
|   using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); |   using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); | ||||||
|   | |||||||
| @@ -125,38 +125,6 @@ class APIFrameHelper { | |||||||
|     const uint8_t *current_data() const { return data.data() + offset; } |     const uint8_t *current_data() const { return data.data() + offset; } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   // Queue of data buffers to be sent |  | ||||||
|   std::deque<SendBuffer> tx_buf_; |  | ||||||
|  |  | ||||||
|   // Common state enum for all frame helpers |  | ||||||
|   // Note: Not all states are used by all implementations |  | ||||||
|   // - INITIALIZE: Used by both Noise and Plaintext |  | ||||||
|   // - CLIENT_HELLO, SERVER_HELLO, HANDSHAKE: Only used by Noise protocol |  | ||||||
|   // - DATA: Used by both Noise and Plaintext |  | ||||||
|   // - CLOSED: Used by both Noise and Plaintext |  | ||||||
|   // - FAILED: Used by both Noise and Plaintext |  | ||||||
|   // - EXPLICIT_REJECT: Only used by Noise protocol |  | ||||||
|   enum class State { |  | ||||||
|     INITIALIZE = 1, |  | ||||||
|     CLIENT_HELLO = 2,  // Noise only |  | ||||||
|     SERVER_HELLO = 3,  // Noise only |  | ||||||
|     HANDSHAKE = 4,     // Noise only |  | ||||||
|     DATA = 5, |  | ||||||
|     CLOSED = 6, |  | ||||||
|     FAILED = 7, |  | ||||||
|     EXPLICIT_REJECT = 8,  // Noise only |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   // Current state of the frame helper |  | ||||||
|   State state_{State::INITIALIZE}; |  | ||||||
|  |  | ||||||
|   // Helper name for logging |  | ||||||
|   std::string info_; |  | ||||||
|  |  | ||||||
|   // Socket for communication |  | ||||||
|   socket::Socket *socket_{nullptr}; |  | ||||||
|   std::unique_ptr<socket::Socket> socket_owned_; |  | ||||||
|  |  | ||||||
|   // Common implementation for writing raw data to socket |   // Common implementation for writing raw data to socket | ||||||
|   APIError write_raw_(const struct iovec *iov, int iovcnt); |   APIError write_raw_(const struct iovec *iov, int iovcnt); | ||||||
|  |  | ||||||
| @@ -169,15 +137,41 @@ class APIFrameHelper { | |||||||
|   APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf, |   APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf, | ||||||
|                       const std::string &info, StateEnum &state, StateEnum failed_state); |                       const std::string &info, StateEnum &state, StateEnum failed_state); | ||||||
|  |  | ||||||
|  |   // Pointers first (4 bytes each) | ||||||
|  |   socket::Socket *socket_{nullptr}; | ||||||
|  |   std::unique_ptr<socket::Socket> socket_owned_; | ||||||
|  |  | ||||||
|  |   // Common state enum for all frame helpers | ||||||
|  |   // Note: Not all states are used by all implementations | ||||||
|  |   // - INITIALIZE: Used by both Noise and Plaintext | ||||||
|  |   // - CLIENT_HELLO, SERVER_HELLO, HANDSHAKE: Only used by Noise protocol | ||||||
|  |   // - DATA: Used by both Noise and Plaintext | ||||||
|  |   // - CLOSED: Used by both Noise and Plaintext | ||||||
|  |   // - FAILED: Used by both Noise and Plaintext | ||||||
|  |   // - EXPLICIT_REJECT: Only used by Noise protocol | ||||||
|  |   enum class State : uint8_t { | ||||||
|  |     INITIALIZE = 1, | ||||||
|  |     CLIENT_HELLO = 2,  // Noise only | ||||||
|  |     SERVER_HELLO = 3,  // Noise only | ||||||
|  |     HANDSHAKE = 4,     // Noise only | ||||||
|  |     DATA = 5, | ||||||
|  |     CLOSED = 6, | ||||||
|  |     FAILED = 7, | ||||||
|  |     EXPLICIT_REJECT = 8,  // Noise only | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   // Containers (size varies, but typically 12+ bytes on 32-bit) | ||||||
|  |   std::deque<SendBuffer> tx_buf_; | ||||||
|  |   std::string info_; | ||||||
|  |   std::vector<struct iovec> reusable_iovs_; | ||||||
|  |   std::vector<uint8_t> rx_buf_; | ||||||
|  |  | ||||||
|  |   // Group smaller types together | ||||||
|  |   uint16_t rx_buf_len_ = 0; | ||||||
|  |   State state_{State::INITIALIZE}; | ||||||
|   uint8_t frame_header_padding_{0}; |   uint8_t frame_header_padding_{0}; | ||||||
|   uint8_t frame_footer_size_{0}; |   uint8_t frame_footer_size_{0}; | ||||||
|  |   // 5 bytes total, 3 bytes padding | ||||||
|   // Reusable IOV array for write_protobuf_packets to avoid repeated allocations |  | ||||||
|   std::vector<struct iovec> reusable_iovs_; |  | ||||||
|  |  | ||||||
|   // Receive buffer for reading frame data |  | ||||||
|   std::vector<uint8_t> rx_buf_; |  | ||||||
|   uint16_t rx_buf_len_ = 0; |  | ||||||
|  |  | ||||||
|   // Common initialization for both plaintext and noise protocols |   // Common initialization for both plaintext and noise protocols | ||||||
|   APIError init_common_(); |   APIError init_common_(); | ||||||
| @@ -213,19 +207,28 @@ class APINoiseFrameHelper : public APIFrameHelper { | |||||||
|   APIError init_handshake_(); |   APIError init_handshake_(); | ||||||
|   APIError check_handshake_finished_(); |   APIError check_handshake_finished_(); | ||||||
|   void send_explicit_handshake_reject_(const std::string &reason); |   void send_explicit_handshake_reject_(const std::string &reason); | ||||||
|  |  | ||||||
|  |   // Pointers first (4 bytes each) | ||||||
|  |   NoiseHandshakeState *handshake_{nullptr}; | ||||||
|  |   NoiseCipherState *send_cipher_{nullptr}; | ||||||
|  |   NoiseCipherState *recv_cipher_{nullptr}; | ||||||
|  |  | ||||||
|  |   // Shared pointer (8 bytes on 32-bit = 4 bytes control block pointer + 4 bytes object pointer) | ||||||
|  |   std::shared_ptr<APINoiseContext> ctx_; | ||||||
|  |  | ||||||
|  |   // Vector (12 bytes on 32-bit) | ||||||
|  |   std::vector<uint8_t> prologue_; | ||||||
|  |  | ||||||
|  |   // NoiseProtocolId (size depends on implementation) | ||||||
|  |   NoiseProtocolId nid_; | ||||||
|  |  | ||||||
|  |   // Group small types together | ||||||
|   // Fixed-size header buffer for noise protocol: |   // Fixed-size header buffer for noise protocol: | ||||||
|   // 1 byte for indicator + 2 bytes for message size (16-bit value, not varint) |   // 1 byte for indicator + 2 bytes for message size (16-bit value, not varint) | ||||||
|   // Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase |   // Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase | ||||||
|   uint8_t rx_header_buf_[3]; |   uint8_t rx_header_buf_[3]; | ||||||
|   uint8_t rx_header_buf_len_ = 0; |   uint8_t rx_header_buf_len_ = 0; | ||||||
|  |   // 4 bytes total, no padding | ||||||
|   std::vector<uint8_t> prologue_; |  | ||||||
|  |  | ||||||
|   std::shared_ptr<APINoiseContext> ctx_; |  | ||||||
|   NoiseHandshakeState *handshake_{nullptr}; |  | ||||||
|   NoiseCipherState *send_cipher_{nullptr}; |  | ||||||
|   NoiseCipherState *recv_cipher_{nullptr}; |  | ||||||
|   NoiseProtocolId nid_; |  | ||||||
| }; | }; | ||||||
| #endif  // USE_API_NOISE | #endif  // USE_API_NOISE | ||||||
|  |  | ||||||
| @@ -252,6 +255,12 @@ class APIPlaintextFrameHelper : public APIFrameHelper { | |||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   APIError try_read_frame_(ParsedFrame *frame); |   APIError try_read_frame_(ParsedFrame *frame); | ||||||
|  |  | ||||||
|  |   // Group 2-byte aligned types | ||||||
|  |   uint16_t rx_header_parsed_type_ = 0; | ||||||
|  |   uint16_t rx_header_parsed_len_ = 0; | ||||||
|  |  | ||||||
|  |   // Group 1-byte types together | ||||||
|   // Fixed-size header buffer for plaintext protocol: |   // Fixed-size header buffer for plaintext protocol: | ||||||
|   // We now store the indicator byte + the two varints. |   // We now store the indicator byte + the two varints. | ||||||
|   // To match noise protocol's maximum message size (UINT16_MAX = 65535), we need: |   // To match noise protocol's maximum message size (UINT16_MAX = 65535), we need: | ||||||
| @@ -263,8 +272,7 @@ class APIPlaintextFrameHelper : public APIFrameHelper { | |||||||
|   uint8_t rx_header_buf_[6];  // 1 byte indicator + 5 bytes for varints (3 for size + 2 for type) |   uint8_t rx_header_buf_[6];  // 1 byte indicator + 5 bytes for varints (3 for size + 2 for type) | ||||||
|   uint8_t rx_header_buf_pos_ = 0; |   uint8_t rx_header_buf_pos_ = 0; | ||||||
|   bool rx_header_parsed_ = false; |   bool rx_header_parsed_ = false; | ||||||
|   uint16_t rx_header_parsed_type_ = 0; |   // 8 bytes total, no padding needed | ||||||
|   uint16_t rx_header_parsed_len_ = 0; |  | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -797,28 +797,18 @@ void ConnectResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void DisconnectRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void DisconnectRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void DisconnectRequest::dump_to(std::string &out) const { out.append("DisconnectRequest {}"); } | void DisconnectRequest::dump_to(std::string &out) const { out.append("DisconnectRequest {}"); } | ||||||
| #endif | #endif | ||||||
| void DisconnectResponse::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void DisconnectResponse::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void DisconnectResponse::dump_to(std::string &out) const { out.append("DisconnectResponse {}"); } | void DisconnectResponse::dump_to(std::string &out) const { out.append("DisconnectResponse {}"); } | ||||||
| #endif | #endif | ||||||
| void PingRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void PingRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void PingRequest::dump_to(std::string &out) const { out.append("PingRequest {}"); } | void PingRequest::dump_to(std::string &out) const { out.append("PingRequest {}"); } | ||||||
| #endif | #endif | ||||||
| void PingResponse::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void PingResponse::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void PingResponse::dump_to(std::string &out) const { out.append("PingResponse {}"); } | void PingResponse::dump_to(std::string &out) const { out.append("PingResponse {}"); } | ||||||
| #endif | #endif | ||||||
| void DeviceInfoRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void DeviceInfoRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void DeviceInfoRequest::dump_to(std::string &out) const { out.append("DeviceInfoRequest {}"); } | void DeviceInfoRequest::dump_to(std::string &out) const { out.append("DeviceInfoRequest {}"); } | ||||||
| #endif | #endif | ||||||
| @@ -1039,18 +1029,12 @@ void DeviceInfoResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void ListEntitiesRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void ListEntitiesRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void ListEntitiesRequest::dump_to(std::string &out) const { out.append("ListEntitiesRequest {}"); } | void ListEntitiesRequest::dump_to(std::string &out) const { out.append("ListEntitiesRequest {}"); } | ||||||
| #endif | #endif | ||||||
| void ListEntitiesDoneResponse::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void ListEntitiesDoneResponse::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void ListEntitiesDoneResponse::dump_to(std::string &out) const { out.append("ListEntitiesDoneResponse {}"); } | void ListEntitiesDoneResponse::dump_to(std::string &out) const { out.append("ListEntitiesDoneResponse {}"); } | ||||||
| #endif | #endif | ||||||
| void SubscribeStatesRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void SubscribeStatesRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void SubscribeStatesRequest::dump_to(std::string &out) const { out.append("SubscribeStatesRequest {}"); } | void SubscribeStatesRequest::dump_to(std::string &out) const { out.append("SubscribeStatesRequest {}"); } | ||||||
| #endif | #endif | ||||||
| @@ -3371,8 +3355,6 @@ void NoiseEncryptionSetKeyResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void SubscribeHomeassistantServicesRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void SubscribeHomeassistantServicesRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void SubscribeHomeassistantServicesRequest::dump_to(std::string &out) const { | void SubscribeHomeassistantServicesRequest::dump_to(std::string &out) const { | ||||||
|   out.append("SubscribeHomeassistantServicesRequest {}"); |   out.append("SubscribeHomeassistantServicesRequest {}"); | ||||||
| @@ -3498,8 +3480,6 @@ void HomeassistantServiceResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void SubscribeHomeAssistantStatesRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void SubscribeHomeAssistantStatesRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const { | void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const { | ||||||
|   out.append("SubscribeHomeAssistantStatesRequest {}"); |   out.append("SubscribeHomeAssistantStatesRequest {}"); | ||||||
| @@ -3603,8 +3583,6 @@ void HomeAssistantStateResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void GetTimeRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void GetTimeRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeRequest {}"); } | void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeRequest {}"); } | ||||||
| #endif | #endif | ||||||
| @@ -7499,8 +7477,6 @@ void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void SubscribeBluetoothConnectionsFreeRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void SubscribeBluetoothConnectionsFreeRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void SubscribeBluetoothConnectionsFreeRequest::dump_to(std::string &out) const { | void SubscribeBluetoothConnectionsFreeRequest::dump_to(std::string &out) const { | ||||||
|   out.append("SubscribeBluetoothConnectionsFreeRequest {}"); |   out.append("SubscribeBluetoothConnectionsFreeRequest {}"); | ||||||
| @@ -7784,8 +7760,6 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void UnsubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void UnsubscribeBluetoothLEAdvertisementsRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { | void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { | ||||||
|   out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}"); |   out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}"); | ||||||
| @@ -8451,8 +8425,6 @@ void VoiceAssistantWakeWord::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| void VoiceAssistantConfigurationRequest::encode(ProtoWriteBuffer buffer) const {} |  | ||||||
| void VoiceAssistantConfigurationRequest::calculate_size(uint32_t &total_size) const {} |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { | void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { | ||||||
|   out.append("VoiceAssistantConfigurationRequest {}"); |   out.append("VoiceAssistantConfigurationRequest {}"); | ||||||
|   | |||||||
| @@ -357,8 +357,6 @@ class DisconnectRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "disconnect_request"; } |   static constexpr const char *message_name() { return "disconnect_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -372,8 +370,6 @@ class DisconnectResponse : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "disconnect_response"; } |   static constexpr const char *message_name() { return "disconnect_response"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -387,8 +383,6 @@ class PingRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "ping_request"; } |   static constexpr const char *message_name() { return "ping_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -402,8 +396,6 @@ class PingResponse : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "ping_response"; } |   static constexpr const char *message_name() { return "ping_response"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -417,8 +409,6 @@ class DeviceInfoRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "device_info_request"; } |   static constexpr const char *message_name() { return "device_info_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -468,8 +458,6 @@ class ListEntitiesRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "list_entities_request"; } |   static constexpr const char *message_name() { return "list_entities_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -483,8 +471,6 @@ class ListEntitiesDoneResponse : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "list_entities_done_response"; } |   static constexpr const char *message_name() { return "list_entities_done_response"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -498,8 +484,6 @@ class SubscribeStatesRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "subscribe_states_request"; } |   static constexpr const char *message_name() { return "subscribe_states_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -1011,8 +995,6 @@ class SubscribeHomeassistantServicesRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "subscribe_homeassistant_services_request"; } |   static constexpr const char *message_name() { return "subscribe_homeassistant_services_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -1061,8 +1043,6 @@ class SubscribeHomeAssistantStatesRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "subscribe_home_assistant_states_request"; } |   static constexpr const char *message_name() { return "subscribe_home_assistant_states_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -1115,8 +1095,6 @@ class GetTimeRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "get_time_request"; } |   static constexpr const char *message_name() { return "get_time_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -2117,8 +2095,6 @@ class SubscribeBluetoothConnectionsFreeRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "subscribe_bluetooth_connections_free_request"; } |   static constexpr const char *message_name() { return "subscribe_bluetooth_connections_free_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -2244,8 +2220,6 @@ class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "unsubscribe_bluetooth_le_advertisements_request"; } |   static constexpr const char *message_name() { return "unsubscribe_bluetooth_le_advertisements_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
| @@ -2512,8 +2486,6 @@ class VoiceAssistantConfigurationRequest : public ProtoMessage { | |||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   static constexpr const char *message_name() { return "voice_assistant_configuration_request"; } |   static constexpr const char *message_name() { return "voice_assistant_configuration_request"; } | ||||||
| #endif | #endif | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |  | ||||||
|   void calculate_size(uint32_t &total_size) const override; |  | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -620,545 +620,301 @@ void APIServerConnection::on_ping_request(const PingRequest &msg) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| void APIServerConnection::on_device_info_request(const DeviceInfoRequest &msg) { | void APIServerConnection::on_device_info_request(const DeviceInfoRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_connection_setup_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     DeviceInfoResponse ret = this->device_info(msg); |     DeviceInfoResponse ret = this->device_info(msg); | ||||||
|     if (!this->send_message(ret)) { |     if (!this->send_message(ret)) { | ||||||
|       this->on_fatal_error(); |       this->on_fatal_error(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | } | ||||||
| void APIServerConnection::on_list_entities_request(const ListEntitiesRequest &msg) { | void APIServerConnection::on_list_entities_request(const ListEntitiesRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->list_entities(msg); |     this->list_entities(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| void APIServerConnection::on_subscribe_states_request(const SubscribeStatesRequest &msg) { | void APIServerConnection::on_subscribe_states_request(const SubscribeStatesRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->subscribe_states(msg); |     this->subscribe_states(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| void APIServerConnection::on_subscribe_logs_request(const SubscribeLogsRequest &msg) { | void APIServerConnection::on_subscribe_logs_request(const SubscribeLogsRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->subscribe_logs(msg); |     this->subscribe_logs(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| void APIServerConnection::on_subscribe_homeassistant_services_request( | void APIServerConnection::on_subscribe_homeassistant_services_request( | ||||||
|     const SubscribeHomeassistantServicesRequest &msg) { |     const SubscribeHomeassistantServicesRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->subscribe_homeassistant_services(msg); |     this->subscribe_homeassistant_services(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| void APIServerConnection::on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) { | void APIServerConnection::on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->subscribe_home_assistant_states(msg); |     this->subscribe_home_assistant_states(msg); | ||||||
|   } |   } | ||||||
| void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) { |  | ||||||
|   if (!this->is_connection_setup()) { |  | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
| } | } | ||||||
|  | void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) { | ||||||
|  |   if (this->check_connection_setup_()) { | ||||||
|     GetTimeResponse ret = this->get_time(msg); |     GetTimeResponse ret = this->get_time(msg); | ||||||
|     if (!this->send_message(ret)) { |     if (!this->send_message(ret)) { | ||||||
|       this->on_fatal_error(); |       this->on_fatal_error(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | } | ||||||
| void APIServerConnection::on_execute_service_request(const ExecuteServiceRequest &msg) { | void APIServerConnection::on_execute_service_request(const ExecuteServiceRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->execute_service(msg); |     this->execute_service(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #ifdef USE_API_NOISE | #ifdef USE_API_NOISE | ||||||
| void APIServerConnection::on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg) { | void APIServerConnection::on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     NoiseEncryptionSetKeyResponse ret = this->noise_encryption_set_key(msg); |     NoiseEncryptionSetKeyResponse ret = this->noise_encryption_set_key(msg); | ||||||
|     if (!this->send_message(ret)) { |     if (!this->send_message(ret)) { | ||||||
|       this->on_fatal_error(); |       this->on_fatal_error(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BUTTON | #ifdef USE_BUTTON | ||||||
| void APIServerConnection::on_button_command_request(const ButtonCommandRequest &msg) { | void APIServerConnection::on_button_command_request(const ButtonCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->button_command(msg); |     this->button_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_ESP32_CAMERA | #ifdef USE_ESP32_CAMERA | ||||||
| void APIServerConnection::on_camera_image_request(const CameraImageRequest &msg) { | void APIServerConnection::on_camera_image_request(const CameraImageRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->camera_image(msg); |     this->camera_image(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_CLIMATE | #ifdef USE_CLIMATE | ||||||
| void APIServerConnection::on_climate_command_request(const ClimateCommandRequest &msg) { | void APIServerConnection::on_climate_command_request(const ClimateCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->climate_command(msg); |     this->climate_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_COVER | #ifdef USE_COVER | ||||||
| void APIServerConnection::on_cover_command_request(const CoverCommandRequest &msg) { | void APIServerConnection::on_cover_command_request(const CoverCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->cover_command(msg); |     this->cover_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_DATETIME_DATE | #ifdef USE_DATETIME_DATE | ||||||
| void APIServerConnection::on_date_command_request(const DateCommandRequest &msg) { | void APIServerConnection::on_date_command_request(const DateCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->date_command(msg); |     this->date_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_DATETIME_DATETIME | #ifdef USE_DATETIME_DATETIME | ||||||
| void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequest &msg) { | void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->datetime_command(msg); |     this->datetime_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
| void APIServerConnection::on_fan_command_request(const FanCommandRequest &msg) { | void APIServerConnection::on_fan_command_request(const FanCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->fan_command(msg); |     this->fan_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
| void APIServerConnection::on_light_command_request(const LightCommandRequest &msg) { | void APIServerConnection::on_light_command_request(const LightCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->light_command(msg); |     this->light_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LOCK | #ifdef USE_LOCK | ||||||
| void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg) { | void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->lock_command(msg); |     this->lock_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_MEDIA_PLAYER | #ifdef USE_MEDIA_PLAYER | ||||||
| void APIServerConnection::on_media_player_command_request(const MediaPlayerCommandRequest &msg) { | void APIServerConnection::on_media_player_command_request(const MediaPlayerCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->media_player_command(msg); |     this->media_player_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_NUMBER | #ifdef USE_NUMBER | ||||||
| void APIServerConnection::on_number_command_request(const NumberCommandRequest &msg) { | void APIServerConnection::on_number_command_request(const NumberCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->number_command(msg); |     this->number_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
| void APIServerConnection::on_select_command_request(const SelectCommandRequest &msg) { | void APIServerConnection::on_select_command_request(const SelectCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->select_command(msg); |     this->select_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_SIREN | #ifdef USE_SIREN | ||||||
| void APIServerConnection::on_siren_command_request(const SirenCommandRequest &msg) { | void APIServerConnection::on_siren_command_request(const SirenCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->siren_command(msg); |     this->siren_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_SWITCH | #ifdef USE_SWITCH | ||||||
| void APIServerConnection::on_switch_command_request(const SwitchCommandRequest &msg) { | void APIServerConnection::on_switch_command_request(const SwitchCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->switch_command(msg); |     this->switch_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_TEXT | #ifdef USE_TEXT | ||||||
| void APIServerConnection::on_text_command_request(const TextCommandRequest &msg) { | void APIServerConnection::on_text_command_request(const TextCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->text_command(msg); |     this->text_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_DATETIME_TIME | #ifdef USE_DATETIME_TIME | ||||||
| void APIServerConnection::on_time_command_request(const TimeCommandRequest &msg) { | void APIServerConnection::on_time_command_request(const TimeCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->time_command(msg); |     this->time_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_UPDATE | #ifdef USE_UPDATE | ||||||
| void APIServerConnection::on_update_command_request(const UpdateCommandRequest &msg) { | void APIServerConnection::on_update_command_request(const UpdateCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->update_command(msg); |     this->update_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_VALVE | #ifdef USE_VALVE | ||||||
| void APIServerConnection::on_valve_command_request(const ValveCommandRequest &msg) { | void APIServerConnection::on_valve_command_request(const ValveCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->valve_command(msg); |     this->valve_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( | void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( | ||||||
|     const SubscribeBluetoothLEAdvertisementsRequest &msg) { |     const SubscribeBluetoothLEAdvertisementsRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->subscribe_bluetooth_le_advertisements(msg); |     this->subscribe_bluetooth_le_advertisements(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) { | void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_device_request(msg); |     this->bluetooth_device_request(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &msg) { | void APIServerConnection::on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_gatt_get_services(msg); |     this->bluetooth_gatt_get_services(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &msg) { | void APIServerConnection::on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_gatt_read(msg); |     this->bluetooth_gatt_read(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &msg) { | void APIServerConnection::on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_gatt_write(msg); |     this->bluetooth_gatt_write(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &msg) { | void APIServerConnection::on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_gatt_read_descriptor(msg); |     this->bluetooth_gatt_read_descriptor(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &msg) { | void APIServerConnection::on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_gatt_write_descriptor(msg); |     this->bluetooth_gatt_write_descriptor(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &msg) { | void APIServerConnection::on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_gatt_notify(msg); |     this->bluetooth_gatt_notify(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_subscribe_bluetooth_connections_free_request( | void APIServerConnection::on_subscribe_bluetooth_connections_free_request( | ||||||
|     const SubscribeBluetoothConnectionsFreeRequest &msg) { |     const SubscribeBluetoothConnectionsFreeRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     BluetoothConnectionsFreeResponse ret = this->subscribe_bluetooth_connections_free(msg); |     BluetoothConnectionsFreeResponse ret = this->subscribe_bluetooth_connections_free(msg); | ||||||
|     if (!this->send_message(ret)) { |     if (!this->send_message(ret)) { | ||||||
|       this->on_fatal_error(); |       this->on_fatal_error(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request( | void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request( | ||||||
|     const UnsubscribeBluetoothLEAdvertisementsRequest &msg) { |     const UnsubscribeBluetoothLEAdvertisementsRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->unsubscribe_bluetooth_le_advertisements(msg); |     this->unsubscribe_bluetooth_le_advertisements(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &msg) { | void APIServerConnection::on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->bluetooth_scanner_set_mode(msg); |     this->bluetooth_scanner_set_mode(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_VOICE_ASSISTANT | #ifdef USE_VOICE_ASSISTANT | ||||||
| void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) { | void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->subscribe_voice_assistant(msg); |     this->subscribe_voice_assistant(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_VOICE_ASSISTANT | #ifdef USE_VOICE_ASSISTANT | ||||||
| void APIServerConnection::on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) { | void APIServerConnection::on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     VoiceAssistantConfigurationResponse ret = this->voice_assistant_get_configuration(msg); |     VoiceAssistantConfigurationResponse ret = this->voice_assistant_get_configuration(msg); | ||||||
|     if (!this->send_message(ret)) { |     if (!this->send_message(ret)) { | ||||||
|       this->on_fatal_error(); |       this->on_fatal_error(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_VOICE_ASSISTANT | #ifdef USE_VOICE_ASSISTANT | ||||||
| void APIServerConnection::on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) { | void APIServerConnection::on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->voice_assistant_set_configuration(msg); |     this->voice_assistant_set_configuration(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_ALARM_CONTROL_PANEL | #ifdef USE_ALARM_CONTROL_PANEL | ||||||
| void APIServerConnection::on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) { | void APIServerConnection::on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (this->check_authenticated_()) { | ||||||
|     this->on_no_setup_connection(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (!this->is_authenticated()) { |  | ||||||
|     this->on_unauthenticated_access(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|     this->alarm_control_panel_command(msg); |     this->alarm_control_panel_command(msg); | ||||||
|   } |   } | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
|   | |||||||
| @@ -106,7 +106,7 @@ void APIServer::setup() { | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   this->last_connected_ = millis(); |   this->last_connected_ = App.get_loop_component_start_time(); | ||||||
|  |  | ||||||
| #ifdef USE_ESP32_CAMERA | #ifdef USE_ESP32_CAMERA | ||||||
|   if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) { |   if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) { | ||||||
| @@ -164,7 +164,7 @@ void APIServer::loop() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (this->reboot_timeout_ != 0) { |   if (this->reboot_timeout_ != 0) { | ||||||
|     const uint32_t now = millis(); |     const uint32_t now = App.get_loop_component_start_time(); | ||||||
|     if (!this->is_connected()) { |     if (!this->is_connected()) { | ||||||
|       if (now - this->last_connected_ > this->reboot_timeout_) { |       if (now - this->last_connected_ > this->reboot_timeout_) { | ||||||
|         ESP_LOGE(TAG, "No client connected; rebooting"); |         ESP_LOGE(TAG, "No client connected; rebooting"); | ||||||
|   | |||||||
| @@ -142,19 +142,27 @@ class APIServer : public Component, public Controller { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   bool shutting_down_ = false; |   // Pointers and pointer-like types first (4 bytes each) | ||||||
|   std::unique_ptr<socket::Socket> socket_ = nullptr; |   std::unique_ptr<socket::Socket> socket_ = nullptr; | ||||||
|   uint16_t port_{6053}; |   Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>(); | ||||||
|  |   Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>(); | ||||||
|  |  | ||||||
|  |   // 4-byte aligned types | ||||||
|   uint32_t reboot_timeout_{300000}; |   uint32_t reboot_timeout_{300000}; | ||||||
|   uint32_t batch_delay_{100}; |   uint32_t batch_delay_{100}; | ||||||
|   uint32_t last_connected_{0}; |   uint32_t last_connected_{0}; | ||||||
|  |  | ||||||
|  |   // Vectors and strings (12 bytes each on 32-bit) | ||||||
|   std::vector<std::unique_ptr<APIConnection>> clients_; |   std::vector<std::unique_ptr<APIConnection>> clients_; | ||||||
|   std::string password_; |   std::string password_; | ||||||
|   std::vector<uint8_t> shared_write_buffer_;  // Shared proto write buffer for all connections |   std::vector<uint8_t> shared_write_buffer_;  // Shared proto write buffer for all connections | ||||||
|   std::vector<HomeAssistantStateSubscription> state_subs_; |   std::vector<HomeAssistantStateSubscription> state_subs_; | ||||||
|   std::vector<UserServiceDescriptor *> user_services_; |   std::vector<UserServiceDescriptor *> user_services_; | ||||||
|   Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>(); |  | ||||||
|   Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>(); |   // Group smaller types together | ||||||
|  |   uint16_t port_{6053}; | ||||||
|  |   bool shutting_down_ = false; | ||||||
|  |   // 3 bytes used, 1 byte padding | ||||||
|  |  | ||||||
| #ifdef USE_API_NOISE | #ifdef USE_API_NOISE | ||||||
|   std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>(); |   std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>(); | ||||||
|   | |||||||
| @@ -327,9 +327,11 @@ class ProtoWriteBuffer { | |||||||
| class ProtoMessage { | class ProtoMessage { | ||||||
|  public: |  public: | ||||||
|   virtual ~ProtoMessage() = default; |   virtual ~ProtoMessage() = default; | ||||||
|   virtual void encode(ProtoWriteBuffer buffer) const = 0; |   // Default implementation for messages with no fields | ||||||
|  |   virtual void encode(ProtoWriteBuffer buffer) const {} | ||||||
|   void decode(const uint8_t *buffer, size_t length); |   void decode(const uint8_t *buffer, size_t length); | ||||||
|   virtual void calculate_size(uint32_t &total_size) const = 0; |   // Default implementation for messages with no fields | ||||||
|  |   virtual void calculate_size(uint32_t &total_size) const {} | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   std::string dump() const; |   std::string dump() const; | ||||||
|   virtual void dump_to(std::string &out) const = 0; |   virtual void dump_to(std::string &out) const = 0; | ||||||
| @@ -377,6 +379,26 @@ class ProtoService { | |||||||
|     // Send the buffer |     // Send the buffer | ||||||
|     return this->send_buffer(buffer, message_type); |     return this->send_buffer(buffer, message_type); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // Authentication helper methods | ||||||
|  |   bool check_connection_setup_() { | ||||||
|  |     if (!this->is_connection_setup()) { | ||||||
|  |       this->on_no_setup_connection(); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool check_authenticated_() { | ||||||
|  |     if (!this->check_connection_setup_()) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (!this->is_authenticated()) { | ||||||
|  |       this->on_unauthenticated_access(); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
|   | |||||||
| @@ -26,10 +26,17 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase { | |||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   friend class BluetoothProxy; |   friend class BluetoothProxy; | ||||||
|   bool seen_mtu_or_services_{false}; |  | ||||||
|  |  | ||||||
|   int16_t send_service_{-2}; |   // Memory optimized layout for 32-bit systems | ||||||
|  |   // Group 1: Pointers (4 bytes each, naturally aligned) | ||||||
|   BluetoothProxy *proxy_; |   BluetoothProxy *proxy_; | ||||||
|  |  | ||||||
|  |   // Group 2: 2-byte types | ||||||
|  |   int16_t send_service_{-2};  // Needs to handle negative values and service count | ||||||
|  |  | ||||||
|  |   // Group 3: 1-byte types | ||||||
|  |   bool seen_mtu_or_services_{false}; | ||||||
|  |   // 1 byte used, 1 byte padding | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace bluetooth_proxy | }  // namespace bluetooth_proxy | ||||||
|   | |||||||
| @@ -134,11 +134,17 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com | |||||||
|  |  | ||||||
|   BluetoothConnection *get_connection_(uint64_t address, bool reserve); |   BluetoothConnection *get_connection_(uint64_t address, bool reserve); | ||||||
|  |  | ||||||
|   bool active_; |   // Memory optimized layout for 32-bit systems | ||||||
|  |   // Group 1: Pointers (4 bytes each, naturally aligned) | ||||||
|   std::vector<BluetoothConnection *> connections_{}; |  | ||||||
|   api::APIConnection *api_connection_{nullptr}; |   api::APIConnection *api_connection_{nullptr}; | ||||||
|  |  | ||||||
|  |   // Group 2: Container types (typically 12 bytes on 32-bit) | ||||||
|  |   std::vector<BluetoothConnection *> connections_{}; | ||||||
|  |  | ||||||
|  |   // Group 3: 1-byte types grouped together | ||||||
|  |   bool active_; | ||||||
|   bool raw_advertisements_{false}; |   bool raw_advertisements_{false}; | ||||||
|  |   // 2 bytes used, 2 bytes padding | ||||||
| }; | }; | ||||||
|  |  | ||||||
| extern BluetoothProxy *global_bluetooth_proxy;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | extern BluetoothProxy *global_bluetooth_proxy;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ async def to_code(config): | |||||||
|  |  | ||||||
|     if CORE.using_arduino: |     if CORE.using_arduino: | ||||||
|         if CORE.is_esp32: |         if CORE.is_esp32: | ||||||
|  |             cg.add_library("ESP32 Async UDP", None) | ||||||
|             cg.add_library("DNSServer", None) |             cg.add_library("DNSServer", None) | ||||||
|             cg.add_library("WiFi", None) |             cg.add_library("WiFi", None) | ||||||
|         if CORE.is_esp8266: |         if CORE.is_esp8266: | ||||||
|   | |||||||
| @@ -132,6 +132,8 @@ def set_core_data(config): | |||||||
|         choices = CPU_FREQUENCIES[variant] |         choices = CPU_FREQUENCIES[variant] | ||||||
|         if "160MHZ" in choices: |         if "160MHZ" in choices: | ||||||
|             cpu_frequency = "160MHZ" |             cpu_frequency = "160MHZ" | ||||||
|  |         elif "360MHZ" in choices: | ||||||
|  |             cpu_frequency = "360MHZ" | ||||||
|         else: |         else: | ||||||
|             cpu_frequency = choices[-1] |             cpu_frequency = choices[-1] | ||||||
|         config[CONF_CPU_FREQUENCY] = cpu_frequency |         config[CONF_CPU_FREQUENCY] = cpu_frequency | ||||||
| @@ -289,11 +291,8 @@ def add_extra_build_file(filename: str, path: str) -> bool: | |||||||
|  |  | ||||||
| def _format_framework_arduino_version(ver: cv.Version) -> str: | def _format_framework_arduino_version(ver: cv.Version) -> str: | ||||||
|     # format the given arduino (https://github.com/espressif/arduino-esp32/releases) version to |     # format the given arduino (https://github.com/espressif/arduino-esp32/releases) version to | ||||||
|     # a PIO platformio/framework-arduinoespressif32 value |     # a PIO pioarduino/framework-arduinoespressif32 value | ||||||
|     # List of package versions: https://api.registry.platformio.org/v3/packages/platformio/tool/framework-arduinoespressif32 |     return f"pioarduino/framework-arduinoespressif32@https://github.com/espressif/arduino-esp32/releases/download/{str(ver)}/esp32-{str(ver)}.zip" | ||||||
|     if ver <= cv.Version(1, 0, 3): |  | ||||||
|         return f"~2.{ver.major}{ver.minor:02d}{ver.patch:02d}.0" |  | ||||||
|     return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def _format_framework_espidf_version( | def _format_framework_espidf_version( | ||||||
| @@ -317,12 +316,10 @@ def _format_framework_espidf_version( | |||||||
|  |  | ||||||
| # The default/recommended arduino framework version | # The default/recommended arduino framework version | ||||||
| #  - https://github.com/espressif/arduino-esp32/releases | #  - https://github.com/espressif/arduino-esp32/releases | ||||||
| #  - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-arduinoespressif32 | RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 1, 3) | ||||||
| RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(2, 0, 5) | # The platform-espressif32 version to use for arduino frameworks | ||||||
| # The platformio/espressif32 version to use for arduino frameworks | #  - https://github.com/pioarduino/platform-espressif32/releases | ||||||
| #  - https://github.com/platformio/platform-espressif32/releases | ARDUINO_PLATFORM_VERSION = cv.Version(53, 3, 13) | ||||||
| #  - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 |  | ||||||
| ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0) |  | ||||||
|  |  | ||||||
| # The default/recommended esp-idf framework version | # The default/recommended esp-idf framework version | ||||||
| #  - https://github.com/espressif/esp-idf/releases | #  - https://github.com/espressif/esp-idf/releases | ||||||
| @@ -365,8 +362,8 @@ SUPPORTED_PIOARDUINO_ESP_IDF_5X = [ | |||||||
| def _arduino_check_versions(value): | def _arduino_check_versions(value): | ||||||
|     value = value.copy() |     value = value.copy() | ||||||
|     lookups = { |     lookups = { | ||||||
|         "dev": (cv.Version(2, 1, 0), "https://github.com/espressif/arduino-esp32.git"), |         "dev": (cv.Version(3, 1, 3), "https://github.com/espressif/arduino-esp32.git"), | ||||||
|         "latest": (cv.Version(2, 0, 9), None), |         "latest": (cv.Version(3, 1, 3), None), | ||||||
|         "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), |         "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -388,6 +385,10 @@ def _arduino_check_versions(value): | |||||||
|         CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION)) |         CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION)) | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |     if value[CONF_SOURCE].startswith("http"): | ||||||
|  |         # prefix is necessary or platformio will complain with a cryptic error | ||||||
|  |         value[CONF_SOURCE] = f"framework-arduinoespressif32@{value[CONF_SOURCE]}" | ||||||
|  |  | ||||||
|     if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION: |     if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION: | ||||||
|         _LOGGER.warning( |         _LOGGER.warning( | ||||||
|             "The selected Arduino framework version is not the recommended one. " |             "The selected Arduino framework version is not the recommended one. " | ||||||
| @@ -829,10 +830,7 @@ async def to_code(config): | |||||||
|         cg.add_platformio_option("framework", "arduino") |         cg.add_platformio_option("framework", "arduino") | ||||||
|         cg.add_build_flag("-DUSE_ARDUINO") |         cg.add_build_flag("-DUSE_ARDUINO") | ||||||
|         cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ARDUINO") |         cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ARDUINO") | ||||||
|         cg.add_platformio_option( |         cg.add_platformio_option("platform_packages", [conf[CONF_SOURCE]]) | ||||||
|             "platform_packages", |  | ||||||
|             [f"platformio/framework-arduinoespressif32@{conf[CONF_SOURCE]}"], |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         if CONF_PARTITIONS in config: |         if CONF_PARTITIONS in config: | ||||||
|             cg.add_platformio_option("board_build.partitions", config[CONF_PARTITIONS]) |             cg.add_platformio_option("board_build.partitions", config[CONF_PARTITIONS]) | ||||||
|   | |||||||
| @@ -96,21 +96,34 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { | |||||||
|   void set_state(espbt::ClientState st) override; |   void set_state(espbt::ClientState st) override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   int gattc_if_; |   // Memory optimized layout for 32-bit systems | ||||||
|   esp_bd_addr_t remote_bda_; |   // Group 1: 8-byte types | ||||||
|   esp_ble_addr_type_t remote_addr_type_{BLE_ADDR_TYPE_PUBLIC}; |  | ||||||
|   uint16_t conn_id_{UNSET_CONN_ID}; |  | ||||||
|   uint64_t address_{0}; |   uint64_t address_{0}; | ||||||
|   bool auto_connect_{false}; |  | ||||||
|  |   // Group 2: Container types (grouped for memory optimization) | ||||||
|   std::string address_str_{}; |   std::string address_str_{}; | ||||||
|   uint8_t connection_index_; |  | ||||||
|   int16_t service_count_{0}; |  | ||||||
|   uint16_t mtu_{23}; |  | ||||||
|   bool paired_{false}; |  | ||||||
|   espbt::ConnectionType connection_type_{espbt::ConnectionType::V1}; |  | ||||||
|   std::vector<BLEService *> services_; |   std::vector<BLEService *> services_; | ||||||
|  |  | ||||||
|  |   // Group 3: 4-byte types | ||||||
|  |   int gattc_if_; | ||||||
|   esp_gatt_status_t status_{ESP_GATT_OK}; |   esp_gatt_status_t status_{ESP_GATT_OK}; | ||||||
|  |  | ||||||
|  |   // Group 4: Arrays (6 bytes) | ||||||
|  |   esp_bd_addr_t remote_bda_; | ||||||
|  |  | ||||||
|  |   // Group 5: 2-byte types | ||||||
|  |   uint16_t conn_id_{UNSET_CONN_ID}; | ||||||
|  |   uint16_t mtu_{23}; | ||||||
|  |  | ||||||
|  |   // Group 6: 1-byte types and small enums | ||||||
|  |   esp_ble_addr_type_t remote_addr_type_{BLE_ADDR_TYPE_PUBLIC}; | ||||||
|  |   espbt::ConnectionType connection_type_{espbt::ConnectionType::V1}; | ||||||
|  |   uint8_t connection_index_; | ||||||
|  |   uint8_t service_count_{0};  // ESP32 has max handles < 255, typical devices have < 50 services | ||||||
|  |   bool auto_connect_{false}; | ||||||
|  |   bool paired_{false}; | ||||||
|  |   // 6 bytes used, 2 bytes padding | ||||||
|  |  | ||||||
|   void log_event_(const char *name); |   void log_event_(const char *name); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -122,10 +122,10 @@ void ESP32BLETracker::loop() { | |||||||
|   // Consumer side: This runs in the main loop thread |   // Consumer side: This runs in the main loop thread | ||||||
|   if (this->scanner_state_ == ScannerState::RUNNING) { |   if (this->scanner_state_ == ScannerState::RUNNING) { | ||||||
|     // Load our own index with relaxed ordering (we're the only writer) |     // Load our own index with relaxed ordering (we're the only writer) | ||||||
|     size_t read_idx = this->ring_read_index_.load(std::memory_order_relaxed); |     uint8_t read_idx = this->ring_read_index_.load(std::memory_order_relaxed); | ||||||
|  |  | ||||||
|     // Load producer's index with acquire to see their latest writes |     // Load producer's index with acquire to see their latest writes | ||||||
|     size_t write_idx = this->ring_write_index_.load(std::memory_order_acquire); |     uint8_t write_idx = this->ring_write_index_.load(std::memory_order_acquire); | ||||||
|  |  | ||||||
|     while (read_idx != write_idx) { |     while (read_idx != write_idx) { | ||||||
|       // Process one result at a time directly from ring buffer |       // Process one result at a time directly from ring buffer | ||||||
| @@ -409,11 +409,11 @@ void ESP32BLETracker::gap_scan_event_handler(const BLEScanResult &scan_result) { | |||||||
|     // IMPORTANT: Only this thread writes to ring_write_index_ |     // IMPORTANT: Only this thread writes to ring_write_index_ | ||||||
|  |  | ||||||
|     // Load our own index with relaxed ordering (we're the only writer) |     // Load our own index with relaxed ordering (we're the only writer) | ||||||
|     size_t write_idx = this->ring_write_index_.load(std::memory_order_relaxed); |     uint8_t write_idx = this->ring_write_index_.load(std::memory_order_relaxed); | ||||||
|     size_t next_write_idx = (write_idx + 1) % SCAN_RESULT_BUFFER_SIZE; |     uint8_t next_write_idx = (write_idx + 1) % SCAN_RESULT_BUFFER_SIZE; | ||||||
|  |  | ||||||
|     // Load consumer's index with acquire to see their latest updates |     // Load consumer's index with acquire to see their latest updates | ||||||
|     size_t read_idx = this->ring_read_index_.load(std::memory_order_acquire); |     uint8_t read_idx = this->ring_read_index_.load(std::memory_order_acquire); | ||||||
|  |  | ||||||
|     // Check if buffer is full |     // Check if buffer is full | ||||||
|     if (next_write_idx != read_idx) { |     if (next_write_idx != read_idx) { | ||||||
|   | |||||||
| @@ -129,7 +129,7 @@ class ESPBTDeviceListener { | |||||||
|   ESP32BLETracker *parent_{nullptr}; |   ESP32BLETracker *parent_{nullptr}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum class ClientState { | enum class ClientState : uint8_t { | ||||||
|   // Connection is allocated |   // Connection is allocated | ||||||
|   INIT, |   INIT, | ||||||
|   // Client is disconnecting |   // Client is disconnecting | ||||||
| @@ -165,7 +165,7 @@ enum class ScannerState { | |||||||
|   STOPPED, |   STOPPED, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum class ConnectionType { | enum class ConnectionType : uint8_t { | ||||||
|   // The default connection type, we hold all the services in ram |   // The default connection type, we hold all the services in ram | ||||||
|   // for the duration of the connection. |   // for the duration of the connection. | ||||||
|   V1, |   V1, | ||||||
| @@ -193,15 +193,19 @@ class ESPBTClient : public ESPBTDeviceListener { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   ClientState state() const { return state_; } |   ClientState state() const { return state_; } | ||||||
|   int app_id; |  | ||||||
|  |   // Memory optimized layout | ||||||
|  |   uint8_t app_id;  // App IDs are small integers assigned sequentially | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|  |   // Group 1: 1-byte types | ||||||
|   ClientState state_{ClientState::INIT}; |   ClientState state_{ClientState::INIT}; | ||||||
|   // want_disconnect_ is set to true when a disconnect is requested |   // want_disconnect_ is set to true when a disconnect is requested | ||||||
|   // while the client is connecting. This is used to disconnect the |   // while the client is connecting. This is used to disconnect the | ||||||
|   // client as soon as we get the connection id (conn_id_) from the |   // client as soon as we get the connection id (conn_id_) from the | ||||||
|   // ESP_GATTC_OPEN_EVT event. |   // ESP_GATTC_OPEN_EVT event. | ||||||
|   bool want_disconnect_{false}; |   bool want_disconnect_{false}; | ||||||
|  |   // 2 bytes used, 2 bytes padding | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class ESP32BLETracker : public Component, | class ESP32BLETracker : public Component, | ||||||
| @@ -262,7 +266,7 @@ class ESP32BLETracker : public Component, | |||||||
|   /// Called to set the scanner state. Will also call callbacks to let listeners know when state is changed. |   /// Called to set the scanner state. Will also call callbacks to let listeners know when state is changed. | ||||||
|   void set_scanner_state_(ScannerState state); |   void set_scanner_state_(ScannerState state); | ||||||
|  |  | ||||||
|   int app_id_{0}; |   uint8_t app_id_{0}; | ||||||
|  |  | ||||||
|   /// Vector of addresses that have already been printed in print_bt_device_info |   /// Vector of addresses that have already been printed in print_bt_device_info | ||||||
|   std::vector<uint64_t> already_discovered_; |   std::vector<uint64_t> already_discovered_; | ||||||
| @@ -289,9 +293,9 @@ class ESP32BLETracker : public Component, | |||||||
|   // Consumer: ESPHome main loop (loop() method) |   // Consumer: ESPHome main loop (loop() method) | ||||||
|   // This design ensures zero blocking in the BT callback and prevents scan result loss |   // This design ensures zero blocking in the BT callback and prevents scan result loss | ||||||
|   BLEScanResult *scan_ring_buffer_; |   BLEScanResult *scan_ring_buffer_; | ||||||
|   std::atomic<size_t> ring_write_index_{0};      // Written only by BT callback (producer) |   std::atomic<uint8_t> ring_write_index_{0};       // Written only by BT callback (producer) | ||||||
|   std::atomic<size_t> ring_read_index_{0};       // Written only by main loop (consumer) |   std::atomic<uint8_t> ring_read_index_{0};        // Written only by main loop (consumer) | ||||||
|   std::atomic<size_t> scan_results_dropped_{0};  // Tracks buffer overflow events |   std::atomic<uint16_t> scan_results_dropped_{0};  // Tracks buffer overflow events | ||||||
|  |  | ||||||
|   esp_bt_status_t scan_start_failed_{ESP_BT_STATUS_SUCCESS}; |   esp_bt_status_t scan_start_failed_{ESP_BT_STATUS_SUCCESS}; | ||||||
|   esp_bt_status_t scan_set_param_failed_{ESP_BT_STATUS_SUCCESS}; |   esp_bt_status_t scan_set_param_failed_{ESP_BT_STATUS_SUCCESS}; | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ import esphome.config_validation as cv | |||||||
| from esphome.const import CONF_ID, CONF_MODE, CONF_PORT | from esphome.const import CONF_ID, CONF_MODE, CONF_PORT | ||||||
|  |  | ||||||
| CODEOWNERS = ["@ayufan"] | CODEOWNERS = ["@ayufan"] | ||||||
| DEPENDENCIES = ["esp32_camera"] | DEPENDENCIES = ["esp32_camera", "network"] | ||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
|  |  | ||||||
| esp32_camera_web_server_ns = cg.esphome_ns.namespace("esp32_camera_web_server") | esp32_camera_web_server_ns = cg.esphome_ns.namespace("esp32_camera_web_server") | ||||||
|   | |||||||
| @@ -1,48 +1,8 @@ | |||||||
| import esphome.codegen as cg |  | ||||||
| from esphome.components import esp32 | from esphome.components import esp32 | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import KEY_CORE, KEY_FRAMEWORK_VERSION |  | ||||||
| from esphome.core import CORE |  | ||||||
|  |  | ||||||
| CODEOWNERS = ["@jesserockz"] | CODEOWNERS = ["@jesserockz"] | ||||||
|  |  | ||||||
| RMT_TX_CHANNELS = { |  | ||||||
|     esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7], |  | ||||||
|     esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3], |  | ||||||
|     esp32.const.VARIANT_ESP32S3: [0, 1, 2, 3], |  | ||||||
|     esp32.const.VARIANT_ESP32C3: [0, 1], |  | ||||||
|     esp32.const.VARIANT_ESP32C6: [0, 1], |  | ||||||
|     esp32.const.VARIANT_ESP32H2: [0, 1], |  | ||||||
| } |  | ||||||
|  |  | ||||||
| RMT_RX_CHANNELS = { |  | ||||||
|     esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7], |  | ||||||
|     esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3], |  | ||||||
|     esp32.const.VARIANT_ESP32S3: [4, 5, 6, 7], |  | ||||||
|     esp32.const.VARIANT_ESP32C3: [2, 3], |  | ||||||
|     esp32.const.VARIANT_ESP32C6: [2, 3], |  | ||||||
|     esp32.const.VARIANT_ESP32H2: [2, 3], |  | ||||||
| } |  | ||||||
|  |  | ||||||
| rmt_channel_t = cg.global_ns.enum("rmt_channel_t") |  | ||||||
| RMT_CHANNEL_ENUMS = { |  | ||||||
|     0: rmt_channel_t.RMT_CHANNEL_0, |  | ||||||
|     1: rmt_channel_t.RMT_CHANNEL_1, |  | ||||||
|     2: rmt_channel_t.RMT_CHANNEL_2, |  | ||||||
|     3: rmt_channel_t.RMT_CHANNEL_3, |  | ||||||
|     4: rmt_channel_t.RMT_CHANNEL_4, |  | ||||||
|     5: rmt_channel_t.RMT_CHANNEL_5, |  | ||||||
|     6: rmt_channel_t.RMT_CHANNEL_6, |  | ||||||
|     7: rmt_channel_t.RMT_CHANNEL_7, |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def use_new_rmt_driver(): |  | ||||||
|     framework_version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] |  | ||||||
|     if CORE.using_esp_idf and framework_version >= cv.Version(5, 0, 0): |  | ||||||
|         return True |  | ||||||
|     return False |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_clock_resolution(): | def validate_clock_resolution(): | ||||||
|     def _validator(value): |     def _validator(value): | ||||||
| @@ -60,21 +20,3 @@ def validate_clock_resolution(): | |||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     return _validator |     return _validator | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_rmt_channel(*, tx: bool): |  | ||||||
|     rmt_channels = RMT_TX_CHANNELS if tx else RMT_RX_CHANNELS |  | ||||||
|  |  | ||||||
|     def _validator(value): |  | ||||||
|         cv.only_on_esp32(value) |  | ||||||
|         value = cv.int_(value) |  | ||||||
|         variant = esp32.get_esp32_variant() |  | ||||||
|         if variant not in rmt_channels: |  | ||||||
|             raise cv.Invalid(f"ESP32 variant {variant} does not support RMT.") |  | ||||||
|         if value not in rmt_channels[variant]: |  | ||||||
|             raise cv.Invalid( |  | ||||||
|                 f"RMT channel {value} does not support {'transmitting' if tx else 'receiving'} for ESP32 variant {variant}." |  | ||||||
|             ) |  | ||||||
|         return cv.enum(RMT_CHANNEL_ENUMS)(value) |  | ||||||
|  |  | ||||||
|     return _validator |  | ||||||
|   | |||||||
| @@ -42,7 +42,6 @@ void ESP32RMTLEDStripLightOutput::setup() { | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   RAMAllocator<rmt_symbol_word_t> rmt_allocator(this->use_psram_ ? 0 : RAMAllocator<rmt_symbol_word_t>::ALLOC_INTERNAL); |   RAMAllocator<rmt_symbol_word_t> rmt_allocator(this->use_psram_ ? 0 : RAMAllocator<rmt_symbol_word_t>::ALLOC_INTERNAL); | ||||||
|  |  | ||||||
|   // 8 bits per byte, 1 rmt_symbol_word_t per bit + 1 rmt_symbol_word_t for reset |   // 8 bits per byte, 1 rmt_symbol_word_t per bit + 1 rmt_symbol_word_t for reset | ||||||
| @@ -79,36 +78,6 @@ void ESP32RMTLEDStripLightOutput::setup() { | |||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| #else |  | ||||||
|   RAMAllocator<rmt_item32_t> rmt_allocator(this->use_psram_ ? 0 : RAMAllocator<rmt_item32_t>::ALLOC_INTERNAL); |  | ||||||
|  |  | ||||||
|   // 8 bits per byte, 1 rmt_item32_t per bit + 1 rmt_item32_t for reset |  | ||||||
|   this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + 1); |  | ||||||
|  |  | ||||||
|   rmt_config_t config; |  | ||||||
|   memset(&config, 0, sizeof(config)); |  | ||||||
|   config.channel = this->channel_; |  | ||||||
|   config.rmt_mode = RMT_MODE_TX; |  | ||||||
|   config.gpio_num = gpio_num_t(this->pin_); |  | ||||||
|   config.mem_block_num = 1; |  | ||||||
|   config.clk_div = RMT_CLK_DIV; |  | ||||||
|   config.tx_config.loop_en = false; |  | ||||||
|   config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; |  | ||||||
|   config.tx_config.carrier_en = false; |  | ||||||
|   config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; |  | ||||||
|   config.tx_config.idle_output_en = true; |  | ||||||
|  |  | ||||||
|   if (rmt_config(&config) != ESP_OK) { |  | ||||||
|     ESP_LOGE(TAG, "Cannot initialize RMT!"); |  | ||||||
|     this->mark_failed(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   if (rmt_driver_install(config.channel, 0, 0) != ESP_OK) { |  | ||||||
|     ESP_LOGE(TAG, "Cannot install RMT driver!"); |  | ||||||
|     this->mark_failed(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, | void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, | ||||||
| @@ -145,11 +114,7 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { | |||||||
|  |  | ||||||
|   ESP_LOGVV(TAG, "Writing RGB values to bus"); |   ESP_LOGVV(TAG, "Writing RGB values to bus"); | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   esp_err_t error = rmt_tx_wait_all_done(this->channel_, 1000); |   esp_err_t error = rmt_tx_wait_all_done(this->channel_, 1000); | ||||||
| #else |  | ||||||
|   esp_err_t error = rmt_wait_tx_done(this->channel_, pdMS_TO_TICKS(1000)); |  | ||||||
| #endif |  | ||||||
|   if (error != ESP_OK) { |   if (error != ESP_OK) { | ||||||
|     ESP_LOGE(TAG, "RMT TX timeout"); |     ESP_LOGE(TAG, "RMT TX timeout"); | ||||||
|     this->status_set_warning(); |     this->status_set_warning(); | ||||||
| @@ -162,11 +127,7 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { | |||||||
|   size_t size = 0; |   size_t size = 0; | ||||||
|   size_t len = 0; |   size_t len = 0; | ||||||
|   uint8_t *psrc = this->buf_; |   uint8_t *psrc = this->buf_; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   rmt_symbol_word_t *pdest = this->rmt_buf_; |   rmt_symbol_word_t *pdest = this->rmt_buf_; | ||||||
| #else |  | ||||||
|   rmt_item32_t *pdest = this->rmt_buf_; |  | ||||||
| #endif |  | ||||||
|   while (size < buffer_size) { |   while (size < buffer_size) { | ||||||
|     uint8_t b = *psrc; |     uint8_t b = *psrc; | ||||||
|     for (int i = 0; i < 8; i++) { |     for (int i = 0; i < 8; i++) { | ||||||
| @@ -184,15 +145,11 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { | |||||||
|     len++; |     len++; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   rmt_transmit_config_t config; |   rmt_transmit_config_t config; | ||||||
|   memset(&config, 0, sizeof(config)); |   memset(&config, 0, sizeof(config)); | ||||||
|   config.loop_count = 0; |   config.loop_count = 0; | ||||||
|   config.flags.eot_level = 0; |   config.flags.eot_level = 0; | ||||||
|   error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config); |   error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config); | ||||||
| #else |  | ||||||
|   error = rmt_write_items(this->channel_, this->rmt_buf_, len, false); |  | ||||||
| #endif |  | ||||||
|   if (error != ESP_OK) { |   if (error != ESP_OK) { | ||||||
|     ESP_LOGE(TAG, "RMT TX error"); |     ESP_LOGE(TAG, "RMT TX error"); | ||||||
|     this->status_set_warning(); |     this->status_set_warning(); | ||||||
| @@ -251,11 +208,7 @@ void ESP32RMTLEDStripLightOutput::dump_config() { | |||||||
|                 "ESP32 RMT LED Strip:\n" |                 "ESP32 RMT LED Strip:\n" | ||||||
|                 "  Pin: %u", |                 "  Pin: %u", | ||||||
|                 this->pin_); |                 this->pin_); | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   ESP_LOGCONFIG(TAG, "  RMT Symbols: %" PRIu32, this->rmt_symbols_); |   ESP_LOGCONFIG(TAG, "  RMT Symbols: %" PRIu32, this->rmt_symbols_); | ||||||
| #else |  | ||||||
|   ESP_LOGCONFIG(TAG, "  Channel: %u", this->channel_); |  | ||||||
| #endif |  | ||||||
|   const char *rgb_order; |   const char *rgb_order; | ||||||
|   switch (this->rgb_order_) { |   switch (this->rgb_order_) { | ||||||
|     case ORDER_RGB: |     case ORDER_RGB: | ||||||
|   | |||||||
| @@ -11,12 +11,7 @@ | |||||||
| #include <driver/gpio.h> | #include <driver/gpio.h> | ||||||
| #include <esp_err.h> | #include <esp_err.h> | ||||||
| #include <esp_idf_version.h> | #include <esp_idf_version.h> | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| #include <driver/rmt_tx.h> | #include <driver/rmt_tx.h> | ||||||
| #else |  | ||||||
| #include <driver/rmt.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace esp32_rmt_led_strip { | namespace esp32_rmt_led_strip { | ||||||
| @@ -61,11 +56,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { | |||||||
|                       uint32_t reset_time_high, uint32_t reset_time_low); |                       uint32_t reset_time_high, uint32_t reset_time_low); | ||||||
|  |  | ||||||
|   void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; } |   void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; } | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; } |   void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; } | ||||||
| #else |  | ||||||
|   void set_rmt_channel(rmt_channel_t channel) { this->channel_ = channel; } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|   void clear_effect_data() override { |   void clear_effect_data() override { | ||||||
|     for (int i = 0; i < this->size(); i++) |     for (int i = 0; i < this->size(); i++) | ||||||
| @@ -81,17 +72,11 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { | |||||||
|  |  | ||||||
|   uint8_t *buf_{nullptr}; |   uint8_t *buf_{nullptr}; | ||||||
|   uint8_t *effect_data_{nullptr}; |   uint8_t *effect_data_{nullptr}; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   rmt_channel_handle_t channel_{nullptr}; |   rmt_channel_handle_t channel_{nullptr}; | ||||||
|   rmt_encoder_handle_t encoder_{nullptr}; |   rmt_encoder_handle_t encoder_{nullptr}; | ||||||
|   rmt_symbol_word_t *rmt_buf_{nullptr}; |   rmt_symbol_word_t *rmt_buf_{nullptr}; | ||||||
|   rmt_symbol_word_t bit0_, bit1_, reset_; |   rmt_symbol_word_t bit0_, bit1_, reset_; | ||||||
|   uint32_t rmt_symbols_{48}; |   uint32_t rmt_symbols_{48}; | ||||||
| #else |  | ||||||
|   rmt_item32_t *rmt_buf_{nullptr}; |  | ||||||
|   rmt_item32_t bit0_, bit1_, reset_; |  | ||||||
|   rmt_channel_t channel_{RMT_CHANNEL_0}; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|   uint8_t pin_; |   uint8_t pin_; | ||||||
|   uint16_t num_leds_; |   uint16_t num_leds_; | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ import logging | |||||||
|  |  | ||||||
| from esphome import pins | from esphome import pins | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| from esphome.components import esp32, esp32_rmt, light | from esphome.components import esp32, light | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     CONF_CHIPSET, |     CONF_CHIPSET, | ||||||
| @@ -13,11 +13,9 @@ from esphome.const import ( | |||||||
|     CONF_OUTPUT_ID, |     CONF_OUTPUT_ID, | ||||||
|     CONF_PIN, |     CONF_PIN, | ||||||
|     CONF_RGB_ORDER, |     CONF_RGB_ORDER, | ||||||
|     CONF_RMT_CHANNEL, |  | ||||||
|     CONF_RMT_SYMBOLS, |     CONF_RMT_SYMBOLS, | ||||||
|     CONF_USE_DMA, |     CONF_USE_DMA, | ||||||
| ) | ) | ||||||
| from esphome.core import CORE |  | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
| @@ -69,53 +67,6 @@ CONF_RESET_HIGH = "reset_high" | |||||||
| CONF_RESET_LOW = "reset_low" | CONF_RESET_LOW = "reset_low" | ||||||
|  |  | ||||||
|  |  | ||||||
| class OptionalForIDF5(cv.SplitDefault): |  | ||||||
|     @property |  | ||||||
|     def default(self): |  | ||||||
|         if not esp32_rmt.use_new_rmt_driver(): |  | ||||||
|             return cv.UNDEFINED |  | ||||||
|         return super().default |  | ||||||
|  |  | ||||||
|     @default.setter |  | ||||||
|     def default(self, value): |  | ||||||
|         # Ignore default set from vol.Optional |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def only_with_new_rmt_driver(obj): |  | ||||||
|     if not esp32_rmt.use_new_rmt_driver(): |  | ||||||
|         raise cv.Invalid( |  | ||||||
|             "This feature is only available for the IDF framework version 5." |  | ||||||
|         ) |  | ||||||
|     return obj |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def not_with_new_rmt_driver(obj): |  | ||||||
|     if esp32_rmt.use_new_rmt_driver(): |  | ||||||
|         raise cv.Invalid( |  | ||||||
|             "This feature is not available for the IDF framework version 5." |  | ||||||
|         ) |  | ||||||
|     return obj |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def final_validation(config): |  | ||||||
|     if not esp32_rmt.use_new_rmt_driver(): |  | ||||||
|         if CONF_RMT_CHANNEL not in config: |  | ||||||
|             if CORE.using_esp_idf: |  | ||||||
|                 raise cv.Invalid( |  | ||||||
|                     "rmt_channel is a required option for IDF version < 5." |  | ||||||
|                 ) |  | ||||||
|             raise cv.Invalid( |  | ||||||
|                 "rmt_channel is a required option for the Arduino framework." |  | ||||||
|             ) |  | ||||||
|         _LOGGER.warning( |  | ||||||
|             "RMT_LED_STRIP support for IDF version < 5 is deprecated and will be removed soon." |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| FINAL_VALIDATE_SCHEMA = final_validation |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     light.ADDRESSABLE_LIGHT_SCHEMA.extend( |     light.ADDRESSABLE_LIGHT_SCHEMA.extend( | ||||||
|         { |         { | ||||||
| @@ -123,20 +74,17 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Required(CONF_PIN): pins.internal_gpio_output_pin_number, |             cv.Required(CONF_PIN): pins.internal_gpio_output_pin_number, | ||||||
|             cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, |             cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, | ||||||
|             cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True), |             cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True), | ||||||
|             cv.Optional(CONF_RMT_CHANNEL): cv.All( |             cv.SplitDefault( | ||||||
|                 not_with_new_rmt_driver, esp32_rmt.validate_rmt_channel(tx=True) |  | ||||||
|             ), |  | ||||||
|             OptionalForIDF5( |  | ||||||
|                 CONF_RMT_SYMBOLS, |                 CONF_RMT_SYMBOLS, | ||||||
|                 esp32_idf=192, |                 esp32=192, | ||||||
|                 esp32_s2_idf=192, |                 esp32_s2=192, | ||||||
|                 esp32_s3_idf=192, |                 esp32_s3=192, | ||||||
|                 esp32_p4_idf=192, |                 esp32_p4=192, | ||||||
|                 esp32_c3_idf=96, |                 esp32_c3=96, | ||||||
|                 esp32_c5_idf=96, |                 esp32_c5=96, | ||||||
|                 esp32_c6_idf=96, |                 esp32_c6=96, | ||||||
|                 esp32_h2_idf=96, |                 esp32_h2=96, | ||||||
|             ): cv.All(only_with_new_rmt_driver, cv.int_range(min=2)), |             ): cv.int_range(min=2), | ||||||
|             cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, |             cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, | ||||||
|             cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True), |             cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True), | ||||||
|             cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, |             cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, | ||||||
| @@ -145,7 +93,6 @@ CONFIG_SCHEMA = cv.All( | |||||||
|                 esp32.only_on_variant( |                 esp32.only_on_variant( | ||||||
|                     supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] |                     supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] | ||||||
|                 ), |                 ), | ||||||
|                 cv.only_with_esp_idf, |  | ||||||
|                 cv.boolean, |                 cv.boolean, | ||||||
|             ), |             ), | ||||||
|             cv.Optional(CONF_USE_PSRAM, default=True): cv.boolean, |             cv.Optional(CONF_USE_PSRAM, default=True): cv.boolean, | ||||||
| @@ -218,15 +165,6 @@ async def to_code(config): | |||||||
|     cg.add(var.set_is_rgbw(config[CONF_IS_RGBW])) |     cg.add(var.set_is_rgbw(config[CONF_IS_RGBW])) | ||||||
|     cg.add(var.set_is_wrgb(config[CONF_IS_WRGB])) |     cg.add(var.set_is_wrgb(config[CONF_IS_WRGB])) | ||||||
|     cg.add(var.set_use_psram(config[CONF_USE_PSRAM])) |     cg.add(var.set_use_psram(config[CONF_USE_PSRAM])) | ||||||
|  |  | ||||||
|     if esp32_rmt.use_new_rmt_driver(): |  | ||||||
|     cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS])) |     cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS])) | ||||||
|     if CONF_USE_DMA in config: |     if CONF_USE_DMA in config: | ||||||
|         cg.add(var.set_use_dma(config[CONF_USE_DMA])) |         cg.add(var.set_use_dma(config[CONF_USE_DMA])) | ||||||
|     else: |  | ||||||
|         rmt_channel_t = cg.global_ns.enum("rmt_channel_t") |  | ||||||
|         cg.add( |  | ||||||
|             var.set_rmt_channel( |  | ||||||
|                 getattr(rmt_channel_t, f"RMT_CHANNEL_{config[CONF_RMT_CHANNEL]}") |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
|   | |||||||
| @@ -26,19 +26,19 @@ void ESPHomeOTAComponent::setup() { | |||||||
|   ota::register_ota_platform(this); |   ota::register_ota_platform(this); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   server_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0);  // monitored for incoming connections |   this->server_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0);  // monitored for incoming connections | ||||||
|   if (server_ == nullptr) { |   if (this->server_ == nullptr) { | ||||||
|     ESP_LOGW(TAG, "Could not create socket"); |     ESP_LOGW(TAG, "Could not create socket"); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   int enable = 1; |   int enable = 1; | ||||||
|   int err = server_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); |   int err = this->server_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); | ||||||
|   if (err != 0) { |   if (err != 0) { | ||||||
|     ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err); |     ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err); | ||||||
|     // we can still continue |     // we can still continue | ||||||
|   } |   } | ||||||
|   err = server_->setblocking(false); |   err = this->server_->setblocking(false); | ||||||
|   if (err != 0) { |   if (err != 0) { | ||||||
|     ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err); |     ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
| @@ -54,14 +54,14 @@ void ESPHomeOTAComponent::setup() { | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   err = server_->bind((struct sockaddr *) &server, sizeof(server)); |   err = this->server_->bind((struct sockaddr *) &server, sizeof(server)); | ||||||
|   if (err != 0) { |   if (err != 0) { | ||||||
|     ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno); |     ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   err = server_->listen(4); |   err = this->server_->listen(4); | ||||||
|   if (err != 0) { |   if (err != 0) { | ||||||
|     ESP_LOGW(TAG, "Socket unable to listen: errno %d", errno); |     ESP_LOGW(TAG, "Socket unable to listen: errno %d", errno); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
| @@ -82,7 +82,14 @@ void ESPHomeOTAComponent::dump_config() { | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| void ESPHomeOTAComponent::loop() { this->handle_(); } | void ESPHomeOTAComponent::loop() { | ||||||
|  |   // Skip handle_() call if no client connected and no incoming connections | ||||||
|  |   // This optimization reduces idle loop overhead when OTA is not active | ||||||
|  |   // Note: No need to check server_ for null as the component is marked failed in setup() if server_ creation fails | ||||||
|  |   if (this->client_ != nullptr || this->server_->ready()) { | ||||||
|  |     this->handle_(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01; | static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01; | ||||||
|  |  | ||||||
| @@ -101,23 +108,21 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   size_t size_acknowledged = 0; |   size_t size_acknowledged = 0; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   if (client_ == nullptr) { |   if (this->client_ == nullptr) { | ||||||
|     // Check if the server socket is ready before accepting |     // We already checked server_->ready() in loop(), so we can accept directly | ||||||
|     if (this->server_->ready()) { |  | ||||||
|     struct sockaddr_storage source_addr; |     struct sockaddr_storage source_addr; | ||||||
|     socklen_t addr_len = sizeof(source_addr); |     socklen_t addr_len = sizeof(source_addr); | ||||||
|       client_ = server_->accept((struct sockaddr *) &source_addr, &addr_len); |     this->client_ = this->server_->accept((struct sockaddr *) &source_addr, &addr_len); | ||||||
|     } |     if (this->client_ == nullptr) | ||||||
|   } |  | ||||||
|   if (client_ == nullptr) |  | ||||||
|       return; |       return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   int enable = 1; |   int enable = 1; | ||||||
|   int err = client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(int)); |   int err = this->client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(int)); | ||||||
|   if (err != 0) { |   if (err != 0) { | ||||||
|     ESP_LOGW(TAG, "Socket could not enable TCP nodelay, errno %d", errno); |     ESP_LOGW(TAG, "Socket could not enable TCP nodelay, errno %d", errno); | ||||||
|     client_->close(); |     this->client_->close(); | ||||||
|     client_ = nullptr; |     this->client_ = nullptr; | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -106,7 +106,7 @@ void EthernetComponent::setup() { | |||||||
|       .post_cb = nullptr, |       .post_cb = nullptr, | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
| #if USE_ESP_IDF && (ESP_IDF_VERSION_MAJOR >= 5) | #if ESP_IDF_VERSION_MAJOR >= 5 | ||||||
|   eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg); |   eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg); | ||||||
| #else | #else | ||||||
|   spi_device_handle_t spi_handle = nullptr; |   spi_device_handle_t spi_handle = nullptr; | ||||||
|   | |||||||
| @@ -175,7 +175,7 @@ async def to_code(config): | |||||||
|                 not config.get(CONF_VERIFY_SSL), |                 not config.get(CONF_VERIFY_SSL), | ||||||
|             ) |             ) | ||||||
|         else: |         else: | ||||||
|             cg.add_library("WiFiClientSecure", None) |             cg.add_library("NetworkClientSecure", None) | ||||||
|             cg.add_library("HTTPClient", None) |             cg.add_library("HTTPClient", None) | ||||||
|     if CORE.is_esp8266: |     if CORE.is_esp8266: | ||||||
|         cg.add_library("ESP8266HTTPClient", None) |         cg.add_library("ESP8266HTTPClient", None) | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|  |  | ||||||
| #if defined(USE_ESP32) || defined(USE_RP2040) | #if defined(USE_ESP32) || defined(USE_RP2040) | ||||||
| #include <HTTPClient.h> | #include <HTTPClient.h> | ||||||
|  | #include <WiFiClient.h> | ||||||
| #endif | #endif | ||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
| #include <ESP8266HTTPClient.h> | #include <ESP8266HTTPClient.h> | ||||||
|   | |||||||
| @@ -125,7 +125,7 @@ ErrorCode ArduinoI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt) | |||||||
|   size_t to_request = 0; |   size_t to_request = 0; | ||||||
|   for (size_t i = 0; i < cnt; i++) |   for (size_t i = 0; i < cnt; i++) | ||||||
|     to_request += buffers[i].len; |     to_request += buffers[i].len; | ||||||
|   size_t ret = wire_->requestFrom((int) address, (int) to_request, 1); |   size_t ret = wire_->requestFrom(address, to_request, true); | ||||||
|   if (ret != to_request) { |   if (ret != to_request) { | ||||||
|     ESP_LOGVV(TAG, "RX %u from %02X failed with error %u", to_request, address, ret); |     ESP_LOGVV(TAG, "RX %u from %02X failed with error %u", to_request, address, ret); | ||||||
|     return ERROR_TIMEOUT; |     return ERROR_TIMEOUT; | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ namespace i2s_audio { | |||||||
|  |  | ||||||
| static const char *const TAG = "i2s_audio"; | static const char *const TAG = "i2s_audio"; | ||||||
|  |  | ||||||
| #if defined(USE_ESP_IDF) && (ESP_IDF_VERSION_MAJOR >= 5) | #if ESP_IDF_VERSION_MAJOR >= 5 | ||||||
| static const uint8_t I2S_NUM_MAX = SOC_I2S_NUM;  // because IDF 5+ took this away :( | static const uint8_t I2S_NUM_MAX = SOC_I2S_NUM;  // because IDF 5+ took this away :( | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -114,7 +114,7 @@ async def to_code(config): | |||||||
|         cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1)) |         cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1)) | ||||||
|         cg.add(var.set_i2s_comm_fmt_lsb(config[CONF_I2S_COMM_FMT] == "lsb")) |         cg.add(var.set_i2s_comm_fmt_lsb(config[CONF_I2S_COMM_FMT] == "lsb")) | ||||||
|  |  | ||||||
|     cg.add_library("WiFiClientSecure", None) |     cg.add_library("NetworkClientSecure", None) | ||||||
|     cg.add_library("HTTPClient", None) |     cg.add_library("HTTPClient", None) | ||||||
|     cg.add_library("esphome/ESP32-audioI2S", "2.3.0") |     cg.add_library("esphome/ESP32-audioI2S", "2.3.0") | ||||||
|     cg.add_build_flag("-DAUDIO_NO_SD_FS") |     cg.add_build_flag("-DAUDIO_NO_SD_FS") | ||||||
|   | |||||||
| @@ -3,28 +3,16 @@ | |||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO |  | ||||||
| #include <esp32-hal-ledc.h> |  | ||||||
| #endif |  | ||||||
| #include <driver/ledc.h> | #include <driver/ledc.h> | ||||||
|  |  | ||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
|  |  | ||||||
| #define CLOCK_FREQUENCY 80e6f | #define CLOCK_FREQUENCY 80e6f | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO |  | ||||||
| #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK |  | ||||||
| #undef CLOCK_FREQUENCY |  | ||||||
| // starting with ESP32 Arduino 2.0.2, the 40MHz crystal is used as clock by default if supported |  | ||||||
| #define CLOCK_FREQUENCY 40e6f |  | ||||||
| #endif |  | ||||||
| #else |  | ||||||
| #ifdef SOC_LEDC_SUPPORT_APB_CLOCK | #ifdef SOC_LEDC_SUPPORT_APB_CLOCK | ||||||
| #define DEFAULT_CLK LEDC_USE_APB_CLK | #define DEFAULT_CLK LEDC_USE_APB_CLK | ||||||
| #else | #else | ||||||
| #define DEFAULT_CLK LEDC_AUTO_CLK | #define DEFAULT_CLK LEDC_AUTO_CLK | ||||||
| #endif | #endif | ||||||
| #endif |  | ||||||
|  |  | ||||||
| static const uint8_t SETUP_ATTEMPT_COUNT_MAX = 5; | static const uint8_t SETUP_ATTEMPT_COUNT_MAX = 5; | ||||||
|  |  | ||||||
| @@ -34,7 +22,6 @@ namespace ledc { | |||||||
| static const char *const TAG = "ledc.output"; | static const char *const TAG = "ledc.output"; | ||||||
|  |  | ||||||
| static const int MAX_RES_BITS = LEDC_TIMER_BIT_MAX - 1; | static const int MAX_RES_BITS = LEDC_TIMER_BIT_MAX - 1; | ||||||
| #ifdef USE_ESP_IDF |  | ||||||
| #if SOC_LEDC_SUPPORT_HS_MODE | #if SOC_LEDC_SUPPORT_HS_MODE | ||||||
| // Only ESP32 has LEDC_HIGH_SPEED_MODE | // Only ESP32 has LEDC_HIGH_SPEED_MODE | ||||||
| inline ledc_mode_t get_speed_mode(uint8_t channel) { return channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE; } | inline ledc_mode_t get_speed_mode(uint8_t channel) { return channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE; } | ||||||
| @@ -44,7 +31,6 @@ inline ledc_mode_t get_speed_mode(uint8_t channel) { return channel < 8 ? LEDC_H | |||||||
| // https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/ledc.html#functionality-overview | // https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/ledc.html#functionality-overview | ||||||
| inline ledc_mode_t get_speed_mode(uint8_t) { return LEDC_LOW_SPEED_MODE; } | inline ledc_mode_t get_speed_mode(uint8_t) { return LEDC_LOW_SPEED_MODE; } | ||||||
| #endif | #endif | ||||||
| #endif |  | ||||||
|  |  | ||||||
| float ledc_max_frequency_for_bit_depth(uint8_t bit_depth) { | float ledc_max_frequency_for_bit_depth(uint8_t bit_depth) { | ||||||
|   return static_cast<float>(CLOCK_FREQUENCY) / static_cast<float>(1 << bit_depth); |   return static_cast<float>(CLOCK_FREQUENCY) / static_cast<float>(1 << bit_depth); | ||||||
| @@ -68,7 +54,6 @@ optional<uint8_t> ledc_bit_depth_for_frequency(float frequency) { | |||||||
|   return {}; |   return {}; | ||||||
| } | } | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF |  | ||||||
| esp_err_t configure_timer_frequency(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_channel_t chan_num, | esp_err_t configure_timer_frequency(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_channel_t chan_num, | ||||||
|                                     uint8_t channel, uint8_t &bit_depth, float frequency) { |                                     uint8_t channel, uint8_t &bit_depth, float frequency) { | ||||||
|   bit_depth = *ledc_bit_depth_for_frequency(frequency); |   bit_depth = *ledc_bit_depth_for_frequency(frequency); | ||||||
| @@ -98,13 +83,10 @@ esp_err_t configure_timer_frequency(ledc_mode_t speed_mode, ledc_timer_t timer_n | |||||||
|  |  | ||||||
|   return init_result; |   return init_result; | ||||||
| } | } | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF |  | ||||||
| constexpr int ledc_angle_to_htop(float angle, uint8_t bit_depth) { | constexpr int ledc_angle_to_htop(float angle, uint8_t bit_depth) { | ||||||
|   return static_cast<int>(angle * ((1U << bit_depth) - 1) / 360.0f); |   return static_cast<int>(angle * ((1U << bit_depth) - 1) / 360.0f); | ||||||
| } | } | ||||||
| #endif  // USE_ESP_IDF |  | ||||||
|  |  | ||||||
| void LEDCOutput::write_state(float state) { | void LEDCOutput::write_state(float state) { | ||||||
|   if (!this->initialized_) { |   if (!this->initialized_) { | ||||||
| @@ -120,10 +102,6 @@ void LEDCOutput::write_state(float state) { | |||||||
|   const float duty_rounded = roundf(state * max_duty); |   const float duty_rounded = roundf(state * max_duty); | ||||||
|   auto duty = static_cast<uint32_t>(duty_rounded); |   auto duty = static_cast<uint32_t>(duty_rounded); | ||||||
|   ESP_LOGV(TAG, "Setting duty: %" PRIu32 " on channel %u", duty, this->channel_); |   ESP_LOGV(TAG, "Setting duty: %" PRIu32 " on channel %u", duty, this->channel_); | ||||||
| #ifdef USE_ARDUINO |  | ||||||
|   ledcWrite(this->channel_, duty); |  | ||||||
| #endif |  | ||||||
| #ifdef USE_ESP_IDF |  | ||||||
|   auto speed_mode = get_speed_mode(this->channel_); |   auto speed_mode = get_speed_mode(this->channel_); | ||||||
|   auto chan_num = static_cast<ledc_channel_t>(this->channel_ % 8); |   auto chan_num = static_cast<ledc_channel_t>(this->channel_ % 8); | ||||||
|   int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); |   int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_); | ||||||
| @@ -135,18 +113,10 @@ void LEDCOutput::write_state(float state) { | |||||||
|     ledc_set_duty_with_hpoint(speed_mode, chan_num, duty, hpoint); |     ledc_set_duty_with_hpoint(speed_mode, chan_num, duty, hpoint); | ||||||
|     ledc_update_duty(speed_mode, chan_num); |     ledc_update_duty(speed_mode, chan_num); | ||||||
|   } |   } | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void LEDCOutput::setup() { | void LEDCOutput::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Running setup"); |   ESP_LOGCONFIG(TAG, "Running setup"); | ||||||
| #ifdef USE_ARDUINO |  | ||||||
|   this->update_frequency(this->frequency_); |  | ||||||
|   this->turn_off(); |  | ||||||
|   // Attach pin after setting default value |  | ||||||
|   ledcAttachPin(this->pin_->get_pin(), this->channel_); |  | ||||||
| #endif |  | ||||||
| #ifdef USE_ESP_IDF |  | ||||||
|   auto speed_mode = get_speed_mode(this->channel_); |   auto speed_mode = get_speed_mode(this->channel_); | ||||||
|   auto timer_num = static_cast<ledc_timer_t>((this->channel_ % 8) / 2); |   auto timer_num = static_cast<ledc_timer_t>((this->channel_ % 8) / 2); | ||||||
|   auto chan_num = static_cast<ledc_channel_t>(this->channel_ % 8); |   auto chan_num = static_cast<ledc_channel_t>(this->channel_ % 8); | ||||||
| @@ -175,7 +145,6 @@ void LEDCOutput::setup() { | |||||||
|   ledc_channel_config(&chan_conf); |   ledc_channel_config(&chan_conf); | ||||||
|   this->initialized_ = true; |   this->initialized_ = true; | ||||||
|   this->status_clear_error(); |   this->status_clear_error(); | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void LEDCOutput::dump_config() { | void LEDCOutput::dump_config() { | ||||||
| @@ -208,38 +177,7 @@ void LEDCOutput::update_frequency(float frequency) { | |||||||
|   } |   } | ||||||
|   this->bit_depth_ = bit_depth_opt.value_or(8); |   this->bit_depth_ = bit_depth_opt.value_or(8); | ||||||
|   this->frequency_ = frequency; |   this->frequency_ = frequency; | ||||||
| #ifdef USE_ARDUINO |  | ||||||
|   ESP_LOGV(TAG, "Using Arduino API - Trying to define channel, frequency and bit depth"); |  | ||||||
|   u_int32_t configured_frequency = 0; |  | ||||||
|  |  | ||||||
|   // Configure LEDC channel, frequency and bit depth with fallback |  | ||||||
|   int attempt_count_max = SETUP_ATTEMPT_COUNT_MAX; |  | ||||||
|   while (attempt_count_max > 0 && configured_frequency == 0) { |  | ||||||
|     ESP_LOGV(TAG, "Initializing channel %u with frequency %.1f and bit depth of %u", this->channel_, this->frequency_, |  | ||||||
|              this->bit_depth_); |  | ||||||
|     configured_frequency = ledcSetup(this->channel_, frequency, this->bit_depth_); |  | ||||||
|     if (configured_frequency != 0) { |  | ||||||
|       this->initialized_ = true; |  | ||||||
|       this->status_clear_error(); |  | ||||||
|       ESP_LOGV(TAG, "Configured frequency: %u with bit depth: %u", configured_frequency, this->bit_depth_); |  | ||||||
|     } else { |  | ||||||
|       ESP_LOGW(TAG, "Unable to initialize channel %u with frequency %.1f and bit depth of %u", this->channel_, |  | ||||||
|                this->frequency_, this->bit_depth_); |  | ||||||
|       // try again with a lower bit depth |  | ||||||
|       this->bit_depth_--; |  | ||||||
|     } |  | ||||||
|     attempt_count_max--; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (configured_frequency == 0) { |  | ||||||
|     ESP_LOGE(TAG, "Permanently failed to initialize channel %u with frequency %.1f and bit depth of %u", this->channel_, |  | ||||||
|              this->frequency_, this->bit_depth_); |  | ||||||
|     this->status_set_error(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| #endif  // USE_ARDUINO |  | ||||||
| #ifdef USE_ESP_IDF |  | ||||||
|   if (!this->initialized_) { |   if (!this->initialized_) { | ||||||
|     ESP_LOGW(TAG, "Not yet initialized"); |     ESP_LOGW(TAG, "Not yet initialized"); | ||||||
|     return; |     return; | ||||||
| @@ -259,7 +197,7 @@ void LEDCOutput::update_frequency(float frequency) { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   this->status_clear_error(); |   this->status_clear_error(); | ||||||
| #endif |  | ||||||
|   // re-apply duty |   // re-apply duty | ||||||
|   this->write_state(this->duty_); |   this->write_state(this->duty_); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -324,7 +324,10 @@ async def to_code(config): | |||||||
|     if CORE.using_arduino: |     if CORE.using_arduino: | ||||||
|         if config[CONF_HARDWARE_UART] == USB_CDC: |         if config[CONF_HARDWARE_UART] == USB_CDC: | ||||||
|             cg.add_build_flag("-DARDUINO_USB_CDC_ON_BOOT=1") |             cg.add_build_flag("-DARDUINO_USB_CDC_ON_BOOT=1") | ||||||
|             if CORE.is_esp32 and get_esp32_variant() == VARIANT_ESP32C3: |             if CORE.is_esp32 and get_esp32_variant() in ( | ||||||
|  |                 VARIANT_ESP32C3, | ||||||
|  |                 VARIANT_ESP32C6, | ||||||
|  |             ): | ||||||
|                 cg.add_build_flag("-DARDUINO_USB_MODE=1") |                 cg.add_build_flag("-DARDUINO_USB_MODE=1") | ||||||
|  |  | ||||||
|     if CORE.using_esp_idf: |     if CORE.using_esp_idf: | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace md5 { | namespace md5 { | ||||||
|  |  | ||||||
| #if defined(USE_ARDUINO) && !defined(USE_RP2040) | #if defined(USE_ARDUINO) && !defined(USE_RP2040) && !defined(USE_ESP32) | ||||||
| void MD5Digest::init() { | void MD5Digest::init() { | ||||||
|   memset(this->digest_, 0, 16); |   memset(this->digest_, 0, 16); | ||||||
|   MD5Init(&this->ctx_); |   MD5Init(&this->ctx_); | ||||||
| @@ -18,7 +18,7 @@ void MD5Digest::add(const uint8_t *data, size_t len) { MD5Update(&this->ctx_, da | |||||||
| void MD5Digest::calculate() { MD5Final(this->digest_, &this->ctx_); } | void MD5Digest::calculate() { MD5Final(this->digest_, &this->ctx_); } | ||||||
| #endif  // USE_ARDUINO && !USE_RP2040 | #endif  // USE_ARDUINO && !USE_RP2040 | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP32 | ||||||
| void MD5Digest::init() { | void MD5Digest::init() { | ||||||
|   memset(this->digest_, 0, 16); |   memset(this->digest_, 0, 16); | ||||||
|   esp_rom_md5_init(&this->ctx_); |   esp_rom_md5_init(&this->ctx_); | ||||||
| @@ -27,7 +27,7 @@ void MD5Digest::init() { | |||||||
| void MD5Digest::add(const uint8_t *data, size_t len) { esp_rom_md5_update(&this->ctx_, data, len); } | void MD5Digest::add(const uint8_t *data, size_t len) { esp_rom_md5_update(&this->ctx_, data, len); } | ||||||
|  |  | ||||||
| void MD5Digest::calculate() { esp_rom_md5_final(this->digest_, &this->ctx_); } | void MD5Digest::calculate() { esp_rom_md5_final(this->digest_, &this->ctx_); } | ||||||
| #endif  // USE_ESP_IDF | #endif  // USE_ESP32 | ||||||
|  |  | ||||||
| #ifdef USE_RP2040 | #ifdef USE_RP2040 | ||||||
| void MD5Digest::init() { | void MD5Digest::init() { | ||||||
|   | |||||||
| @@ -3,16 +3,11 @@ | |||||||
| #include "esphome/core/defines.h" | #include "esphome/core/defines.h" | ||||||
| #ifdef USE_MD5 | #ifdef USE_MD5 | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP32 | ||||||
| #include "esp_rom_md5.h" | #include "esp_rom_md5.h" | ||||||
| #define MD5_CTX_TYPE md5_context_t | #define MD5_CTX_TYPE md5_context_t | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(USE_ARDUINO) && defined(USE_ESP32) |  | ||||||
| #include "rom/md5_hash.h" |  | ||||||
| #define MD5_CTX_TYPE MD5Context |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(USE_ARDUINO) && defined(USE_ESP8266) | #if defined(USE_ARDUINO) && defined(USE_ESP8266) | ||||||
| #include <md5.h> | #include <md5.h> | ||||||
| #define MD5_CTX_TYPE md5_context_t | #define MD5_CTX_TYPE md5_context_t | ||||||
|   | |||||||
| @@ -215,4 +215,7 @@ async def to_code(config): | |||||||
|  |  | ||||||
|     # https://github.com/Makuna/NeoPixelBus/blob/master/library.json |     # https://github.com/Makuna/NeoPixelBus/blob/master/library.json | ||||||
|     # Version Listed Here: https://registry.platformio.org/libraries/makuna/NeoPixelBus/versions |     # Version Listed Here: https://registry.platformio.org/libraries/makuna/NeoPixelBus/versions | ||||||
|  |     if CORE.is_esp32: | ||||||
|  |         cg.add_library("makuna/NeoPixelBus", "2.8.0") | ||||||
|  |     else: | ||||||
|         cg.add_library("makuna/NeoPixelBus", "2.7.3") |         cg.add_library("makuna/NeoPixelBus", "2.7.3") | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO | #if defined(USE_ARDUINO) && !defined(CLANG_TIDY) | ||||||
|  |  | ||||||
| #include "esphome/core/color.h" | #include "esphome/core/color.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ import esphome.codegen as cg | |||||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | from esphome.components.esp32 import add_idf_sdkconfig_option | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT | from esphome.const import CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT | ||||||
| from esphome.core import CORE | from esphome.core import CORE, coroutine_with_priority | ||||||
|  |  | ||||||
| CODEOWNERS = ["@esphome/core"] | CODEOWNERS = ["@esphome/core"] | ||||||
| AUTO_LOAD = ["mdns"] | AUTO_LOAD = ["mdns"] | ||||||
| @@ -36,8 +36,11 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @coroutine_with_priority(201.0) | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     cg.add_define("USE_NETWORK") |     cg.add_define("USE_NETWORK") | ||||||
|  |     if CORE.using_arduino and CORE.is_esp32: | ||||||
|  |         cg.add_library("Networking", None) | ||||||
|     if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None: |     if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None: | ||||||
|         cg.add_define("USE_NETWORK_IPV6", enable_ipv6) |         cg.add_define("USE_NETWORK_IPV6", enable_ipv6) | ||||||
|         if enable_ipv6: |         if enable_ipv6: | ||||||
|   | |||||||
| @@ -56,6 +56,7 @@ struct IPAddress { | |||||||
|     IP_ADDR4(&ip_addr_, first, second, third, fourth); |     IP_ADDR4(&ip_addr_, first, second, third, fourth); | ||||||
|   } |   } | ||||||
|   IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); } |   IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); } | ||||||
|  |   IPAddress(const char *in_address) { ipaddr_aton(in_address, &ip_addr_); } | ||||||
|   IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); } |   IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); } | ||||||
|   IPAddress(ip4_addr_t *other_ip) { |   IPAddress(ip4_addr_t *other_ip) { | ||||||
|     memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t)); |     memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t)); | ||||||
|   | |||||||
| @@ -150,7 +150,7 @@ async def to_code(config): | |||||||
|         cg.add_define("USE_NEXTION_TFT_UPLOAD") |         cg.add_define("USE_NEXTION_TFT_UPLOAD") | ||||||
|         cg.add(var.set_tft_url(config[CONF_TFT_URL])) |         cg.add(var.set_tft_url(config[CONF_TFT_URL])) | ||||||
|         if CORE.is_esp32 and CORE.using_arduino: |         if CORE.is_esp32 and CORE.using_arduino: | ||||||
|             cg.add_library("WiFiClientSecure", None) |             cg.add_library("NetworkClientSecure", None) | ||||||
|             cg.add_library("HTTPClient", None) |             cg.add_library("HTTPClient", None) | ||||||
|         elif CORE.is_esp32 and CORE.using_esp_idf: |         elif CORE.is_esp32 and CORE.using_esp_idf: | ||||||
|             esp32.add_idf_sdkconfig_option("CONFIG_ESP_TLS_INSECURE", True) |             esp32.add_idf_sdkconfig_option("CONFIG_ESP_TLS_INSECURE", True) | ||||||
|   | |||||||
| @@ -224,7 +224,7 @@ void OnlineImage::loop() { | |||||||
|     this->height_ = buffer_height_; |     this->height_ = buffer_height_; | ||||||
|     ESP_LOGD(TAG, "Image fully downloaded, read %zu bytes, width/height = %d/%d", this->downloader_->get_bytes_read(), |     ESP_LOGD(TAG, "Image fully downloaded, read %zu bytes, width/height = %d/%d", this->downloader_->get_bytes_read(), | ||||||
|              this->width_, this->height_); |              this->width_, this->height_); | ||||||
|     ESP_LOGD(TAG, "Total time: %lds", ::time(nullptr) - this->start_time_); |     ESP_LOGD(TAG, "Total time: %" PRIu32 "s", (uint32_t) (::time(nullptr) - this->start_time_)); | ||||||
|     this->etag_ = this->downloader_->get_response_header(ETAG_HEADER_NAME); |     this->etag_ = this->downloader_->get_response_header(ETAG_HEADER_NAME); | ||||||
|     this->last_modified_ = this->downloader_->get_response_header(LAST_MODIFIED_HEADER_NAME); |     this->last_modified_ = this->downloader_->get_response_header(LAST_MODIFIED_HEADER_NAME); | ||||||
|     this->download_finished_callback_.call(false); |     this->download_finished_callback_.call(false); | ||||||
|   | |||||||
| @@ -8,27 +8,6 @@ namespace remote_base { | |||||||
|  |  | ||||||
| static const char *const TAG = "remote_base"; | static const char *const TAG = "remote_base"; | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 5 |  | ||||||
| RemoteRMTChannel::RemoteRMTChannel(uint8_t mem_block_num) : mem_block_num_(mem_block_num) { |  | ||||||
|   static rmt_channel_t next_rmt_channel = RMT_CHANNEL_0; |  | ||||||
|   this->channel_ = next_rmt_channel; |  | ||||||
|   next_rmt_channel = rmt_channel_t(int(next_rmt_channel) + mem_block_num); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| RemoteRMTChannel::RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num) |  | ||||||
|     : channel_(channel), mem_block_num_(mem_block_num) {} |  | ||||||
|  |  | ||||||
| void RemoteRMTChannel::config_rmt(rmt_config_t &rmt) { |  | ||||||
|   if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) > RMT_CHANNEL_MAX) { |  | ||||||
|     this->mem_block_num_ = int(RMT_CHANNEL_MAX) - int(this->channel_); |  | ||||||
|     ESP_LOGW(TAG, "Not enough RMT memory blocks available, reduced to %i blocks.", this->mem_block_num_); |  | ||||||
|   } |  | ||||||
|   rmt.channel = this->channel_; |  | ||||||
|   rmt.clk_div = this->clock_divider_; |  | ||||||
|   rmt.mem_block_num = this->mem_block_num_; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* RemoteReceiveData */ | /* RemoteReceiveData */ | ||||||
|  |  | ||||||
| bool RemoteReceiveData::peek_mark(uint32_t length, uint32_t offset) const { | bool RemoteReceiveData::peek_mark(uint32_t length, uint32_t offset) const { | ||||||
|   | |||||||
| @@ -8,10 +8,6 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 5 |  | ||||||
| #include <driver/rmt.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace remote_base { | namespace remote_base { | ||||||
|  |  | ||||||
| @@ -112,43 +108,21 @@ class RemoteComponentBase { | |||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| class RemoteRMTChannel { | class RemoteRMTChannel { | ||||||
|  public: |  public: | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   void set_clock_resolution(uint32_t clock_resolution) { this->clock_resolution_ = clock_resolution; } |   void set_clock_resolution(uint32_t clock_resolution) { this->clock_resolution_ = clock_resolution; } | ||||||
|   void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; } |   void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; } | ||||||
| #else |  | ||||||
|   explicit RemoteRMTChannel(uint8_t mem_block_num = 1); |  | ||||||
|   explicit RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num = 1); |  | ||||||
|  |  | ||||||
|   void config_rmt(rmt_config_t &rmt); |  | ||||||
|   void set_clock_divider(uint8_t clock_divider) { this->clock_divider_ = clock_divider; } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   uint32_t from_microseconds_(uint32_t us) { |   uint32_t from_microseconds_(uint32_t us) { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|     const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u; |     const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u; | ||||||
| #else |  | ||||||
|     const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u; |  | ||||||
| #endif |  | ||||||
|     return us * ticks_per_ten_us / 10; |     return us * ticks_per_ten_us / 10; | ||||||
|   } |   } | ||||||
|   uint32_t to_microseconds_(uint32_t ticks) { |   uint32_t to_microseconds_(uint32_t ticks) { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|     const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u; |     const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u; | ||||||
| #else |  | ||||||
|     const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u; |  | ||||||
| #endif |  | ||||||
|     return (ticks * 10) / ticks_per_ten_us; |     return (ticks * 10) / ticks_per_ten_us; | ||||||
|   } |   } | ||||||
|   RemoteComponentBase *remote_base_; |   RemoteComponentBase *remote_base_; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   uint32_t clock_resolution_{1000000}; |   uint32_t clock_resolution_{1000000}; | ||||||
|   uint32_t rmt_symbols_; |   uint32_t rmt_symbols_; | ||||||
| #else |  | ||||||
|   rmt_channel_t channel_{RMT_CHANNEL_0}; |  | ||||||
|   uint8_t mem_block_num_; |  | ||||||
|   uint8_t clock_divider_{80}; |  | ||||||
| #endif |  | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,15 +4,12 @@ from esphome.components import esp32, esp32_rmt, remote_base | |||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     CONF_BUFFER_SIZE, |     CONF_BUFFER_SIZE, | ||||||
|     CONF_CLOCK_DIVIDER, |  | ||||||
|     CONF_CLOCK_RESOLUTION, |     CONF_CLOCK_RESOLUTION, | ||||||
|     CONF_DUMP, |     CONF_DUMP, | ||||||
|     CONF_FILTER, |     CONF_FILTER, | ||||||
|     CONF_ID, |     CONF_ID, | ||||||
|     CONF_IDLE, |     CONF_IDLE, | ||||||
|     CONF_MEMORY_BLOCKS, |  | ||||||
|     CONF_PIN, |     CONF_PIN, | ||||||
|     CONF_RMT_CHANNEL, |  | ||||||
|     CONF_RMT_SYMBOLS, |     CONF_RMT_SYMBOLS, | ||||||
|     CONF_TOLERANCE, |     CONF_TOLERANCE, | ||||||
|     CONF_TYPE, |     CONF_TYPE, | ||||||
| @@ -103,49 +100,36 @@ CONFIG_SCHEMA = remote_base.validate_triggers( | |||||||
|                 cv.positive_time_period_microseconds, |                 cv.positive_time_period_microseconds, | ||||||
|                 cv.Range(max=TimePeriod(microseconds=4294967295)), |                 cv.Range(max=TimePeriod(microseconds=4294967295)), | ||||||
|             ), |             ), | ||||||
|             cv.SplitDefault(CONF_CLOCK_DIVIDER, esp32_arduino=80): cv.All( |  | ||||||
|                 cv.only_on_esp32, |  | ||||||
|                 cv.only_with_arduino, |  | ||||||
|                 cv.int_range(min=1, max=255), |  | ||||||
|             ), |  | ||||||
|             cv.Optional(CONF_CLOCK_RESOLUTION): cv.All( |             cv.Optional(CONF_CLOCK_RESOLUTION): cv.All( | ||||||
|                 cv.only_on_esp32, |                 cv.only_on_esp32, | ||||||
|                 cv.only_with_esp_idf, |  | ||||||
|                 esp32_rmt.validate_clock_resolution(), |                 esp32_rmt.validate_clock_resolution(), | ||||||
|             ), |             ), | ||||||
|             cv.Optional(CONF_IDLE, default="10ms"): cv.All( |             cv.Optional(CONF_IDLE, default="10ms"): cv.All( | ||||||
|                 cv.positive_time_period_microseconds, |                 cv.positive_time_period_microseconds, | ||||||
|                 cv.Range(max=TimePeriod(microseconds=4294967295)), |                 cv.Range(max=TimePeriod(microseconds=4294967295)), | ||||||
|             ), |             ), | ||||||
|             cv.SplitDefault(CONF_MEMORY_BLOCKS, esp32_arduino=3): cv.All( |  | ||||||
|                 cv.only_with_arduino, cv.int_range(min=1, max=8) |  | ||||||
|             ), |  | ||||||
|             cv.Optional(CONF_RMT_CHANNEL): cv.All( |  | ||||||
|                 cv.only_with_arduino, esp32_rmt.validate_rmt_channel(tx=False) |  | ||||||
|             ), |  | ||||||
|             cv.SplitDefault( |             cv.SplitDefault( | ||||||
|                 CONF_RMT_SYMBOLS, |                 CONF_RMT_SYMBOLS, | ||||||
|                 esp32_idf=192, |                 esp32=192, | ||||||
|                 esp32_s2_idf=192, |                 esp32_s2=192, | ||||||
|                 esp32_s3_idf=192, |                 esp32_s3=192, | ||||||
|                 esp32_p4_idf=192, |                 esp32_p4=192, | ||||||
|                 esp32_c3_idf=96, |                 esp32_c3=96, | ||||||
|                 esp32_c5_idf=96, |                 esp32_c5=96, | ||||||
|                 esp32_c6_idf=96, |                 esp32_c6=96, | ||||||
|                 esp32_h2_idf=96, |                 esp32_h2=96, | ||||||
|             ): cv.All(cv.only_with_esp_idf, cv.int_range(min=2)), |             ): cv.All(cv.only_on_esp32, cv.int_range(min=2)), | ||||||
|             cv.Optional(CONF_FILTER_SYMBOLS): cv.All( |             cv.Optional(CONF_FILTER_SYMBOLS): cv.All( | ||||||
|                 cv.only_with_esp_idf, cv.int_range(min=0) |                 cv.only_on_esp32, cv.int_range(min=0) | ||||||
|             ), |             ), | ||||||
|             cv.SplitDefault( |             cv.SplitDefault( | ||||||
|                 CONF_RECEIVE_SYMBOLS, |                 CONF_RECEIVE_SYMBOLS, | ||||||
|                 esp32_idf=192, |                 esp32=192, | ||||||
|             ): cv.All(cv.only_with_esp_idf, cv.int_range(min=2)), |             ): cv.All(cv.only_on_esp32, cv.int_range(min=2)), | ||||||
|             cv.Optional(CONF_USE_DMA): cv.All( |             cv.Optional(CONF_USE_DMA): cv.All( | ||||||
|                 esp32.only_on_variant( |                 esp32.only_on_variant( | ||||||
|                     supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] |                     supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] | ||||||
|                 ), |                 ), | ||||||
|                 cv.only_with_esp_idf, |  | ||||||
|                 cv.boolean, |                 cv.boolean, | ||||||
|             ), |             ), | ||||||
|         } |         } | ||||||
| @@ -156,7 +140,6 @@ CONFIG_SCHEMA = remote_base.validate_triggers( | |||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     pin = await cg.gpio_pin_expression(config[CONF_PIN]) |     pin = await cg.gpio_pin_expression(config[CONF_PIN]) | ||||||
|     if CORE.is_esp32: |     if CORE.is_esp32: | ||||||
|         if esp32_rmt.use_new_rmt_driver(): |  | ||||||
|         var = cg.new_Pvariable(config[CONF_ID], pin) |         var = cg.new_Pvariable(config[CONF_ID], pin) | ||||||
|         cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS])) |         cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS])) | ||||||
|         cg.add(var.set_receive_symbols(config[CONF_RECEIVE_SYMBOLS])) |         cg.add(var.set_receive_symbols(config[CONF_RECEIVE_SYMBOLS])) | ||||||
| @@ -166,14 +149,6 @@ async def to_code(config): | |||||||
|             cg.add(var.set_clock_resolution(config[CONF_CLOCK_RESOLUTION])) |             cg.add(var.set_clock_resolution(config[CONF_CLOCK_RESOLUTION])) | ||||||
|         if CONF_FILTER_SYMBOLS in config: |         if CONF_FILTER_SYMBOLS in config: | ||||||
|             cg.add(var.set_filter_symbols(config[CONF_FILTER_SYMBOLS])) |             cg.add(var.set_filter_symbols(config[CONF_FILTER_SYMBOLS])) | ||||||
|         else: |  | ||||||
|             if (rmt_channel := config.get(CONF_RMT_CHANNEL, None)) is not None: |  | ||||||
|                 var = cg.new_Pvariable( |  | ||||||
|                     config[CONF_ID], pin, rmt_channel, config[CONF_MEMORY_BLOCKS] |  | ||||||
|                 ) |  | ||||||
|             else: |  | ||||||
|                 var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS]) |  | ||||||
|             cg.add(var.set_clock_divider(config[CONF_CLOCK_DIVIDER])) |  | ||||||
|     else: |     else: | ||||||
|         var = cg.new_Pvariable(config[CONF_ID], pin) |         var = cg.new_Pvariable(config[CONF_ID], pin) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  |  | ||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR >= 5 | #if defined(USE_ESP32) | ||||||
| #include <driver/rmt_rx.h> | #include <driver/rmt_rx.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -29,7 +29,7 @@ struct RemoteReceiverComponentStore { | |||||||
|   uint32_t filter_us{10}; |   uint32_t filter_us{10}; | ||||||
|   ISRInternalGPIOPin pin; |   ISRInternalGPIOPin pin; | ||||||
| }; | }; | ||||||
| #elif defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR >= 5 | #elif defined(USE_ESP32) | ||||||
| struct RemoteReceiverComponentStore { | struct RemoteReceiverComponentStore { | ||||||
|   /// Stores RMT symbols and rx done event data |   /// Stores RMT symbols and rx done event data | ||||||
|   volatile uint8_t *buffer{nullptr}; |   volatile uint8_t *buffer{nullptr}; | ||||||
| @@ -55,21 +55,13 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, | |||||||
|  |  | ||||||
| { | { | ||||||
|  public: |  public: | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 5 |  | ||||||
|   RemoteReceiverComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1) |  | ||||||
|       : RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {} |  | ||||||
|  |  | ||||||
|   RemoteReceiverComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1) |  | ||||||
|       : RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {} |  | ||||||
| #else |  | ||||||
|   RemoteReceiverComponent(InternalGPIOPin *pin) : RemoteReceiverBase(pin) {} |   RemoteReceiverComponent(InternalGPIOPin *pin) : RemoteReceiverBase(pin) {} | ||||||
| #endif |  | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   void loop() override; |   void loop() override; | ||||||
|   float get_setup_priority() const override { return setup_priority::DATA; } |   float get_setup_priority() const override { return setup_priority::DATA; } | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR >= 5 | #ifdef USE_ESP32 | ||||||
|   void set_filter_symbols(uint32_t filter_symbols) { this->filter_symbols_ = filter_symbols; } |   void set_filter_symbols(uint32_t filter_symbols) { this->filter_symbols_ = filter_symbols; } | ||||||
|   void set_receive_symbols(uint32_t receive_symbols) { this->receive_symbols_ = receive_symbols; } |   void set_receive_symbols(uint32_t receive_symbols) { this->receive_symbols_ = receive_symbols; } | ||||||
|   void set_with_dma(bool with_dma) { this->with_dma_ = with_dma; } |   void set_with_dma(bool with_dma) { this->with_dma_ = with_dma; } | ||||||
| @@ -80,21 +72,16 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, | |||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   void decode_rmt_(rmt_symbol_word_t *item, size_t item_count); |   void decode_rmt_(rmt_symbol_word_t *item, size_t item_count); | ||||||
|   rmt_channel_handle_t channel_{NULL}; |   rmt_channel_handle_t channel_{NULL}; | ||||||
|   uint32_t filter_symbols_{0}; |   uint32_t filter_symbols_{0}; | ||||||
|   uint32_t receive_symbols_{0}; |   uint32_t receive_symbols_{0}; | ||||||
|   bool with_dma_{false}; |   bool with_dma_{false}; | ||||||
| #else |  | ||||||
|   void decode_rmt_(rmt_item32_t *item, size_t item_count); |  | ||||||
|   RingbufHandle_t ringbuf_; |  | ||||||
| #endif |  | ||||||
|   esp_err_t error_code_{ESP_OK}; |   esp_err_t error_code_{ESP_OK}; | ||||||
|   std::string error_string_{""}; |   std::string error_string_{""}; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(USE_ESP8266) || defined(USE_LIBRETINY) || (defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR >= 5) | #if defined(USE_ESP8266) || defined(USE_LIBRETINY) || defined(USE_ESP32) | ||||||
|   RemoteReceiverComponentStore store_; |   RemoteReceiverComponentStore store_; | ||||||
|   HighFrequencyLoopRequester high_freq_; |   HighFrequencyLoopRequester high_freq_; | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -14,7 +14,6 @@ static const uint32_t RMT_CLK_FREQ = 32000000; | |||||||
| static const uint32_t RMT_CLK_FREQ = 80000000; | static const uint32_t RMT_CLK_FREQ = 80000000; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| static bool IRAM_ATTR HOT rmt_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *event, void *arg) { | static bool IRAM_ATTR HOT rmt_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *event, void *arg) { | ||||||
|   RemoteReceiverComponentStore *store = (RemoteReceiverComponentStore *) arg; |   RemoteReceiverComponentStore *store = (RemoteReceiverComponentStore *) arg; | ||||||
|   rmt_rx_done_event_data_t *event_buffer = (rmt_rx_done_event_data_t *) (store->buffer + store->buffer_write); |   rmt_rx_done_event_data_t *event_buffer = (rmt_rx_done_event_data_t *) (store->buffer + store->buffer_write); | ||||||
| @@ -37,11 +36,9 @@ static bool IRAM_ATTR HOT rmt_callback(rmt_channel_handle_t channel, const rmt_r | |||||||
|   store->buffer_write = next_write; |   store->buffer_write = next_write; | ||||||
|   return false; |   return false; | ||||||
| } | } | ||||||
| #endif |  | ||||||
|  |  | ||||||
| void RemoteReceiverComponent::setup() { | void RemoteReceiverComponent::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Running setup"); |   ESP_LOGCONFIG(TAG, "Running setup"); | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   rmt_rx_channel_config_t channel; |   rmt_rx_channel_config_t channel; | ||||||
|   memset(&channel, 0, sizeof(channel)); |   memset(&channel, 0, sizeof(channel)); | ||||||
|   channel.clk_src = RMT_CLK_SRC_DEFAULT; |   channel.clk_src = RMT_CLK_SRC_DEFAULT; | ||||||
| @@ -105,62 +102,11 @@ void RemoteReceiverComponent::setup() { | |||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| #else |  | ||||||
|   this->pin_->setup(); |  | ||||||
|   rmt_config_t rmt{}; |  | ||||||
|   this->config_rmt(rmt); |  | ||||||
|   rmt.gpio_num = gpio_num_t(this->pin_->get_pin()); |  | ||||||
|   rmt.rmt_mode = RMT_MODE_RX; |  | ||||||
|   if (this->filter_us_ == 0) { |  | ||||||
|     rmt.rx_config.filter_en = false; |  | ||||||
|   } else { |  | ||||||
|     rmt.rx_config.filter_en = true; |  | ||||||
|     rmt.rx_config.filter_ticks_thresh = static_cast<uint8_t>( |  | ||||||
|         std::min(this->from_microseconds_(this->filter_us_) * this->clock_divider_, (uint32_t) 255)); |  | ||||||
|   } |  | ||||||
|   rmt.rx_config.idle_threshold = |  | ||||||
|       static_cast<uint16_t>(std::min(this->from_microseconds_(this->idle_us_), (uint32_t) 65535)); |  | ||||||
|  |  | ||||||
|   esp_err_t error = rmt_config(&rmt); |  | ||||||
|   if (error != ESP_OK) { |  | ||||||
|     this->error_code_ = error; |  | ||||||
|     this->error_string_ = "in rmt_config"; |  | ||||||
|     this->mark_failed(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   error = rmt_driver_install(this->channel_, this->buffer_size_, 0); |  | ||||||
|   if (error != ESP_OK) { |  | ||||||
|     this->error_code_ = error; |  | ||||||
|     if (error == ESP_ERR_INVALID_STATE) { |  | ||||||
|       this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); |  | ||||||
|     } else { |  | ||||||
|       this->error_string_ = "in rmt_driver_install"; |  | ||||||
|     } |  | ||||||
|     this->mark_failed(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   error = rmt_get_ringbuf_handle(this->channel_, &this->ringbuf_); |  | ||||||
|   if (error != ESP_OK) { |  | ||||||
|     this->error_code_ = error; |  | ||||||
|     this->error_string_ = "in rmt_get_ringbuf_handle"; |  | ||||||
|     this->mark_failed(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   error = rmt_rx_start(this->channel_, true); |  | ||||||
|   if (error != ESP_OK) { |  | ||||||
|     this->error_code_ = error; |  | ||||||
|     this->error_string_ = "in rmt_rx_start"; |  | ||||||
|     this->mark_failed(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void RemoteReceiverComponent::dump_config() { | void RemoteReceiverComponent::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "Remote Receiver:"); |   ESP_LOGCONFIG(TAG, "Remote Receiver:"); | ||||||
|   LOG_PIN("  Pin: ", this->pin_); |   LOG_PIN("  Pin: ", this->pin_); | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   ESP_LOGCONFIG(TAG, |   ESP_LOGCONFIG(TAG, | ||||||
|                 "  Clock resolution: %" PRIu32 " hz\n" |                 "  Clock resolution: %" PRIu32 " hz\n" | ||||||
|                 "  RMT symbols: %" PRIu32 "\n" |                 "  RMT symbols: %" PRIu32 "\n" | ||||||
| @@ -172,22 +118,6 @@ void RemoteReceiverComponent::dump_config() { | |||||||
|                 this->clock_resolution_, this->rmt_symbols_, this->filter_symbols_, this->receive_symbols_, |                 this->clock_resolution_, this->rmt_symbols_, this->filter_symbols_, this->receive_symbols_, | ||||||
|                 this->tolerance_, (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%", |                 this->tolerance_, (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%", | ||||||
|                 this->filter_us_, this->idle_us_); |                 this->filter_us_, this->idle_us_); | ||||||
| #else |  | ||||||
|   if (this->pin_->digital_read()) { |  | ||||||
|     ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " |  | ||||||
|                   "invert the signal using 'inverted: True' in the pin schema!"); |  | ||||||
|   } |  | ||||||
|   ESP_LOGCONFIG(TAG, |  | ||||||
|                 "  Channel: %d\n" |  | ||||||
|                 "  RMT memory blocks: %d\n" |  | ||||||
|                 "  Clock divider: %u\n" |  | ||||||
|                 "  Tolerance: %" PRIu32 "%s\n" |  | ||||||
|                 "  Filter out pulses shorter than: %" PRIu32 " us\n" |  | ||||||
|                 "  Signal is done after %" PRIu32 " us of no changes", |  | ||||||
|                 this->channel_, this->mem_block_num_, this->clock_divider_, this->tolerance_, |  | ||||||
|                 (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%", this->filter_us_, |  | ||||||
|                 this->idle_us_); |  | ||||||
| #endif |  | ||||||
|   if (this->is_failed()) { |   if (this->is_failed()) { | ||||||
|     ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_), |     ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_), | ||||||
|              this->error_string_.c_str()); |              this->error_string_.c_str()); | ||||||
| @@ -195,7 +125,6 @@ void RemoteReceiverComponent::dump_config() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void RemoteReceiverComponent::loop() { | void RemoteReceiverComponent::loop() { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   if (this->store_.error != ESP_OK) { |   if (this->store_.error != ESP_OK) { | ||||||
|     ESP_LOGE(TAG, "Receive error"); |     ESP_LOGE(TAG, "Receive error"); | ||||||
|     this->error_code_ = this->store_.error; |     this->error_code_ = this->store_.error; | ||||||
| @@ -221,25 +150,9 @@ void RemoteReceiverComponent::loop() { | |||||||
|       this->call_listeners_dumpers_(); |       this->call_listeners_dumpers_(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| #else |  | ||||||
|   size_t len = 0; |  | ||||||
|   auto *item = (rmt_item32_t *) xRingbufferReceive(this->ringbuf_, &len, 0); |  | ||||||
|   if (item != nullptr) { |  | ||||||
|     this->decode_rmt_(item, len / sizeof(rmt_item32_t)); |  | ||||||
|     vRingbufferReturnItem(this->ringbuf_, item); |  | ||||||
|  |  | ||||||
|     if (!this->temp_.empty()) { |  | ||||||
|       this->call_listeners_dumpers_(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| void RemoteReceiverComponent::decode_rmt_(rmt_symbol_word_t *item, size_t item_count) { | void RemoteReceiverComponent::decode_rmt_(rmt_symbol_word_t *item, size_t item_count) { | ||||||
| #else |  | ||||||
| void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t item_count) { |  | ||||||
| #endif |  | ||||||
|   bool prev_level = false; |   bool prev_level = false; | ||||||
|   bool idle_level = false; |   bool idle_level = false; | ||||||
|   uint32_t prev_length = 0; |   uint32_t prev_length = 0; | ||||||
|   | |||||||
| @@ -4,14 +4,12 @@ from esphome.components import esp32, esp32_rmt, remote_base | |||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     CONF_CARRIER_DUTY_PERCENT, |     CONF_CARRIER_DUTY_PERCENT, | ||||||
|     CONF_CLOCK_DIVIDER, |  | ||||||
|     CONF_CLOCK_RESOLUTION, |     CONF_CLOCK_RESOLUTION, | ||||||
|     CONF_ID, |     CONF_ID, | ||||||
|     CONF_INVERTED, |     CONF_INVERTED, | ||||||
|     CONF_MODE, |     CONF_MODE, | ||||||
|     CONF_OPEN_DRAIN, |     CONF_OPEN_DRAIN, | ||||||
|     CONF_PIN, |     CONF_PIN, | ||||||
|     CONF_RMT_CHANNEL, |  | ||||||
|     CONF_RMT_SYMBOLS, |     CONF_RMT_SYMBOLS, | ||||||
|     CONF_USE_DMA, |     CONF_USE_DMA, | ||||||
| ) | ) | ||||||
| @@ -38,34 +36,26 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
|         ), |         ), | ||||||
|         cv.Optional(CONF_CLOCK_RESOLUTION): cv.All( |         cv.Optional(CONF_CLOCK_RESOLUTION): cv.All( | ||||||
|             cv.only_on_esp32, |             cv.only_on_esp32, | ||||||
|             cv.only_with_esp_idf, |  | ||||||
|             esp32_rmt.validate_clock_resolution(), |             esp32_rmt.validate_clock_resolution(), | ||||||
|         ), |         ), | ||||||
|         cv.Optional(CONF_CLOCK_DIVIDER): cv.All( |         cv.Optional(CONF_EOT_LEVEL): cv.All(cv.only_on_esp32, cv.boolean), | ||||||
|             cv.only_on_esp32, cv.only_with_arduino, cv.int_range(min=1, max=255) |  | ||||||
|         ), |  | ||||||
|         cv.Optional(CONF_EOT_LEVEL): cv.All(cv.only_with_esp_idf, cv.boolean), |  | ||||||
|         cv.Optional(CONF_USE_DMA): cv.All( |         cv.Optional(CONF_USE_DMA): cv.All( | ||||||
|             esp32.only_on_variant( |             esp32.only_on_variant( | ||||||
|                 supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] |                 supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] | ||||||
|             ), |             ), | ||||||
|             cv.only_with_esp_idf, |  | ||||||
|             cv.boolean, |             cv.boolean, | ||||||
|         ), |         ), | ||||||
|         cv.SplitDefault( |         cv.SplitDefault( | ||||||
|             CONF_RMT_SYMBOLS, |             CONF_RMT_SYMBOLS, | ||||||
|             esp32_idf=64, |             esp32=64, | ||||||
|             esp32_s2_idf=64, |             esp32_s2=64, | ||||||
|             esp32_s3_idf=48, |             esp32_s3=48, | ||||||
|             esp32_p4_idf=48, |             esp32_p4=48, | ||||||
|             esp32_c3_idf=48, |             esp32_c3=48, | ||||||
|             esp32_c5_idf=48, |             esp32_c5=48, | ||||||
|             esp32_c6_idf=48, |             esp32_c6=48, | ||||||
|             esp32_h2_idf=48, |             esp32_h2=48, | ||||||
|         ): cv.All(cv.only_with_esp_idf, cv.int_range(min=2)), |         ): cv.All(cv.only_on_esp32, cv.int_range(min=2)), | ||||||
|         cv.Optional(CONF_RMT_CHANNEL): cv.All( |  | ||||||
|             cv.only_with_arduino, esp32_rmt.validate_rmt_channel(tx=True) |  | ||||||
|         ), |  | ||||||
|         cv.Optional(CONF_ON_TRANSMIT): automation.validate_automation(single=True), |         cv.Optional(CONF_ON_TRANSMIT): automation.validate_automation(single=True), | ||||||
|         cv.Optional(CONF_ON_COMPLETE): automation.validate_automation(single=True), |         cv.Optional(CONF_ON_COMPLETE): automation.validate_automation(single=True), | ||||||
|     } |     } | ||||||
| @@ -75,7 +65,6 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     pin = await cg.gpio_pin_expression(config[CONF_PIN]) |     pin = await cg.gpio_pin_expression(config[CONF_PIN]) | ||||||
|     if CORE.is_esp32: |     if CORE.is_esp32: | ||||||
|         if esp32_rmt.use_new_rmt_driver(): |  | ||||||
|         var = cg.new_Pvariable(config[CONF_ID], pin) |         var = cg.new_Pvariable(config[CONF_ID], pin) | ||||||
|         cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS])) |         cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS])) | ||||||
|         if CONF_CLOCK_RESOLUTION in config: |         if CONF_CLOCK_RESOLUTION in config: | ||||||
| @@ -91,14 +80,6 @@ async def to_code(config): | |||||||
|                     or config[CONF_PIN][CONF_INVERTED] |                     or config[CONF_PIN][CONF_INVERTED] | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
|         else: |  | ||||||
|             if (rmt_channel := config.get(CONF_RMT_CHANNEL, None)) is not None: |  | ||||||
|                 var = cg.new_Pvariable(config[CONF_ID], pin, rmt_channel) |  | ||||||
|             else: |  | ||||||
|                 var = cg.new_Pvariable(config[CONF_ID], pin) |  | ||||||
|             if CONF_CLOCK_DIVIDER in config: |  | ||||||
|                 cg.add(var.set_clock_divider(config[CONF_CLOCK_DIVIDER])) |  | ||||||
|  |  | ||||||
|     else: |     else: | ||||||
|         var = cg.new_Pvariable(config[CONF_ID], pin) |         var = cg.new_Pvariable(config[CONF_ID], pin) | ||||||
|     await cg.register_component(var, config) |     await cg.register_component(var, config) | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  |  | ||||||
| #include <vector> | #include <vector> | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR >= 5 | #if defined(USE_ESP32) | ||||||
| #include <driver/rmt_tx.h> | #include <driver/rmt_tx.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -20,15 +20,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, | |||||||
| #endif | #endif | ||||||
| { | { | ||||||
|  public: |  public: | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 5 |  | ||||||
|   RemoteTransmitterComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1) |  | ||||||
|       : remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {} |  | ||||||
|  |  | ||||||
|   RemoteTransmitterComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1) |  | ||||||
|       : remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {} |  | ||||||
| #else |  | ||||||
|   explicit RemoteTransmitterComponent(InternalGPIOPin *pin) : remote_base::RemoteTransmitterBase(pin) {} |   explicit RemoteTransmitterComponent(InternalGPIOPin *pin) : remote_base::RemoteTransmitterBase(pin) {} | ||||||
| #endif |  | ||||||
|   void setup() override; |   void setup() override; | ||||||
|  |  | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
| @@ -38,7 +30,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, | |||||||
|  |  | ||||||
|   void set_carrier_duty_percent(uint8_t carrier_duty_percent) { this->carrier_duty_percent_ = carrier_duty_percent; } |   void set_carrier_duty_percent(uint8_t carrier_duty_percent) { this->carrier_duty_percent_ = carrier_duty_percent; } | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR >= 5 | #if defined(USE_ESP32) | ||||||
|   void set_with_dma(bool with_dma) { this->with_dma_ = with_dma; } |   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_eot_level(bool eot_level) { this->eot_level_ = eot_level; } | ||||||
|   void digital_write(bool value); |   void digital_write(bool value); | ||||||
| @@ -65,15 +57,11 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, | |||||||
|  |  | ||||||
|   uint32_t current_carrier_frequency_{38000}; |   uint32_t current_carrier_frequency_{38000}; | ||||||
|   bool initialized_{false}; |   bool initialized_{false}; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   std::vector<rmt_symbol_word_t> rmt_temp_; |   std::vector<rmt_symbol_word_t> rmt_temp_; | ||||||
|   bool with_dma_{false}; |   bool with_dma_{false}; | ||||||
|   bool eot_level_{false}; |   bool eot_level_{false}; | ||||||
|   rmt_channel_handle_t channel_{NULL}; |   rmt_channel_handle_t channel_{NULL}; | ||||||
|   rmt_encoder_handle_t encoder_{NULL}; |   rmt_encoder_handle_t encoder_{NULL}; | ||||||
| #else |  | ||||||
|   std::vector<rmt_item32_t> rmt_temp_; |  | ||||||
| #endif |  | ||||||
|   esp_err_t error_code_{ESP_OK}; |   esp_err_t error_code_{ESP_OK}; | ||||||
|   std::string error_string_{""}; |   std::string error_string_{""}; | ||||||
|   bool inverted_{false}; |   bool inverted_{false}; | ||||||
|   | |||||||
| @@ -18,18 +18,10 @@ void RemoteTransmitterComponent::setup() { | |||||||
|  |  | ||||||
| void RemoteTransmitterComponent::dump_config() { | void RemoteTransmitterComponent::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "Remote Transmitter:"); |   ESP_LOGCONFIG(TAG, "Remote Transmitter:"); | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   ESP_LOGCONFIG(TAG, |   ESP_LOGCONFIG(TAG, | ||||||
|                 "  Clock resolution: %" PRIu32 " hz\n" |                 "  Clock resolution: %" PRIu32 " hz\n" | ||||||
|                 "  RMT symbols: %" PRIu32, |                 "  RMT symbols: %" PRIu32, | ||||||
|                 this->clock_resolution_, this->rmt_symbols_); |                 this->clock_resolution_, this->rmt_symbols_); | ||||||
| #else |  | ||||||
|   ESP_LOGCONFIG(TAG, |  | ||||||
|                 "  Channel: %d\n" |  | ||||||
|                 "  RMT memory blocks: %d\n" |  | ||||||
|                 "  Clock divider: %u", |  | ||||||
|                 this->channel_, this->mem_block_num_, this->clock_divider_); |  | ||||||
| #endif |  | ||||||
|   LOG_PIN("  Pin: ", this->pin_); |   LOG_PIN("  Pin: ", this->pin_); | ||||||
|  |  | ||||||
|   if (this->current_carrier_frequency_ != 0 && this->carrier_duty_percent_ != 100) { |   if (this->current_carrier_frequency_ != 0 && this->carrier_duty_percent_ != 100) { | ||||||
| @@ -42,7 +34,6 @@ void RemoteTransmitterComponent::dump_config() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| void RemoteTransmitterComponent::digital_write(bool value) { | void RemoteTransmitterComponent::digital_write(bool value) { | ||||||
|   rmt_symbol_word_t symbol = { |   rmt_symbol_word_t symbol = { | ||||||
|       .duration0 = 1, |       .duration0 = 1, | ||||||
| @@ -65,10 +56,8 @@ void RemoteTransmitterComponent::digital_write(bool value) { | |||||||
|     this->status_set_warning(); |     this->status_set_warning(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| #endif |  | ||||||
|  |  | ||||||
| void RemoteTransmitterComponent::configure_rmt_() { | void RemoteTransmitterComponent::configure_rmt_() { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   esp_err_t error; |   esp_err_t error; | ||||||
|  |  | ||||||
|   if (!this->initialized_) { |   if (!this->initialized_) { | ||||||
| @@ -140,54 +129,6 @@ void RemoteTransmitterComponent::configure_rmt_() { | |||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| #else |  | ||||||
|   rmt_config_t c{}; |  | ||||||
|  |  | ||||||
|   this->config_rmt(c); |  | ||||||
|   c.rmt_mode = RMT_MODE_TX; |  | ||||||
|   c.gpio_num = gpio_num_t(this->pin_->get_pin()); |  | ||||||
|   c.tx_config.loop_en = false; |  | ||||||
|  |  | ||||||
|   if (this->current_carrier_frequency_ == 0 || this->carrier_duty_percent_ == 100) { |  | ||||||
|     c.tx_config.carrier_en = false; |  | ||||||
|   } else { |  | ||||||
|     c.tx_config.carrier_en = true; |  | ||||||
|     c.tx_config.carrier_freq_hz = this->current_carrier_frequency_; |  | ||||||
|     c.tx_config.carrier_duty_percent = this->carrier_duty_percent_; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   c.tx_config.idle_output_en = true; |  | ||||||
|   if (!this->inverted_) { |  | ||||||
|     c.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH; |  | ||||||
|     c.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; |  | ||||||
|   } else { |  | ||||||
|     c.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; |  | ||||||
|     c.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   esp_err_t error = rmt_config(&c); |  | ||||||
|   if (error != ESP_OK) { |  | ||||||
|     this->error_code_ = error; |  | ||||||
|     this->error_string_ = "in rmt_config"; |  | ||||||
|     this->mark_failed(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (!this->initialized_) { |  | ||||||
|     error = rmt_driver_install(this->channel_, 0, 0); |  | ||||||
|     if (error != ESP_OK) { |  | ||||||
|       this->error_code_ = error; |  | ||||||
|       if (error == ESP_ERR_INVALID_STATE) { |  | ||||||
|         this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); |  | ||||||
|       } else { |  | ||||||
|         this->error_string_ = "in rmt_driver_install"; |  | ||||||
|       } |  | ||||||
|       this->mark_failed(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     this->initialized_ = true; |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { | void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { | ||||||
| @@ -202,11 +143,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen | |||||||
|   this->rmt_temp_.clear(); |   this->rmt_temp_.clear(); | ||||||
|   this->rmt_temp_.reserve((this->temp_.get_data().size() + 1) / 2); |   this->rmt_temp_.reserve((this->temp_.get_data().size() + 1) / 2); | ||||||
|   uint32_t rmt_i = 0; |   uint32_t rmt_i = 0; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   rmt_symbol_word_t rmt_item; |   rmt_symbol_word_t rmt_item; | ||||||
| #else |  | ||||||
|   rmt_item32_t rmt_item; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|   for (int32_t val : this->temp_.get_data()) { |   for (int32_t val : this->temp_.get_data()) { | ||||||
|     bool level = val >= 0; |     bool level = val >= 0; | ||||||
| @@ -241,7 +178,6 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   this->transmit_trigger_->trigger(); |   this->transmit_trigger_->trigger(); | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   for (uint32_t i = 0; i < send_times; i++) { |   for (uint32_t i = 0; i < send_times; i++) { | ||||||
|     rmt_transmit_config_t config; |     rmt_transmit_config_t config; | ||||||
|     memset(&config, 0, sizeof(config)); |     memset(&config, 0, sizeof(config)); | ||||||
| @@ -263,19 +199,6 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen | |||||||
|     if (i + 1 < send_times) |     if (i + 1 < send_times) | ||||||
|       delayMicroseconds(send_wait); |       delayMicroseconds(send_wait); | ||||||
|   } |   } | ||||||
| #else |  | ||||||
|   for (uint32_t i = 0; i < send_times; i++) { |  | ||||||
|     esp_err_t error = rmt_write_items(this->channel_, this->rmt_temp_.data(), this->rmt_temp_.size(), true); |  | ||||||
|     if (error != ESP_OK) { |  | ||||||
|       ESP_LOGW(TAG, "rmt_write_items failed: %s", esp_err_to_name(error)); |  | ||||||
|       this->status_set_warning(); |  | ||||||
|     } else { |  | ||||||
|       this->status_clear_warning(); |  | ||||||
|     } |  | ||||||
|     if (i + 1 < send_times) |  | ||||||
|       delayMicroseconds(send_wait); |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
|   this->complete_trigger_->trigger(); |   this->complete_trigger_->trigger(); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| #include "sntp_component.h" | #include "sntp_component.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP32 | ||||||
| #include "esp_sntp.h" | #include "esp_sntp.h" | ||||||
| #elif USE_ESP8266 | #elif USE_ESP8266 | ||||||
| #include "sntp.h" | #include "sntp.h" | ||||||
| @@ -16,7 +16,7 @@ static const char *const TAG = "sntp"; | |||||||
|  |  | ||||||
| void SNTPComponent::setup() { | void SNTPComponent::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Running setup"); |   ESP_LOGCONFIG(TAG, "Running setup"); | ||||||
| #if defined(USE_ESP_IDF) | #if defined(USE_ESP32) | ||||||
|   if (esp_sntp_enabled()) { |   if (esp_sntp_enabled()) { | ||||||
|     esp_sntp_stop(); |     esp_sntp_stop(); | ||||||
|   } |   } | ||||||
| @@ -46,7 +46,7 @@ void SNTPComponent::dump_config() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| void SNTPComponent::update() { | void SNTPComponent::update() { | ||||||
| #if !defined(USE_ESP_IDF) | #if !defined(USE_ESP32) | ||||||
|   // force resync |   // force resync | ||||||
|   if (sntp_enabled()) { |   if (sntp_enabled()) { | ||||||
|     sntp_stop(); |     sntp_stop(); | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <utility> | #include <utility> | ||||||
| #ifdef USE_WIFI_WPA2_EAP | #ifdef USE_WIFI_WPA2_EAP | ||||||
| #include <esp_wpa2.h> | #include <esp_eap_client.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef USE_WIFI_AP | #ifdef USE_WIFI_AP | ||||||
| @@ -228,43 +228,43 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { | |||||||
|   if (ap.get_eap().has_value()) { |   if (ap.get_eap().has_value()) { | ||||||
|     // note: all certificates and keys have to be null terminated. Lengths are appended by +1 to include \0. |     // note: all certificates and keys have to be null terminated. Lengths are appended by +1 to include \0. | ||||||
|     EAPAuth eap = ap.get_eap().value(); |     EAPAuth eap = ap.get_eap().value(); | ||||||
|     err = esp_wifi_sta_wpa2_ent_set_identity((uint8_t *) eap.identity.c_str(), eap.identity.length()); |     err = esp_eap_client_set_identity((uint8_t *) eap.identity.c_str(), eap.identity.length()); | ||||||
|     if (err != ESP_OK) { |     if (err != ESP_OK) { | ||||||
|       ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_identity failed! %d", err); |       ESP_LOGV(TAG, "esp_eap_client_set_identity failed! %d", err); | ||||||
|     } |     } | ||||||
|     int ca_cert_len = strlen(eap.ca_cert); |     int ca_cert_len = strlen(eap.ca_cert); | ||||||
|     int client_cert_len = strlen(eap.client_cert); |     int client_cert_len = strlen(eap.client_cert); | ||||||
|     int client_key_len = strlen(eap.client_key); |     int client_key_len = strlen(eap.client_key); | ||||||
|     if (ca_cert_len) { |     if (ca_cert_len) { | ||||||
|       err = esp_wifi_sta_wpa2_ent_set_ca_cert((uint8_t *) eap.ca_cert, ca_cert_len + 1); |       err = esp_eap_client_set_ca_cert((uint8_t *) eap.ca_cert, ca_cert_len + 1); | ||||||
|       if (err != ESP_OK) { |       if (err != ESP_OK) { | ||||||
|         ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_ca_cert failed! %d", err); |         ESP_LOGV(TAG, "esp_eap_client_set_ca_cert failed! %d", err); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     // workout what type of EAP this is |     // workout what type of EAP this is | ||||||
|     // validation is not required as the config tool has already validated it |     // validation is not required as the config tool has already validated it | ||||||
|     if (client_cert_len && client_key_len) { |     if (client_cert_len && client_key_len) { | ||||||
|       // if we have certs, this must be EAP-TLS |       // if we have certs, this must be EAP-TLS | ||||||
|       err = esp_wifi_sta_wpa2_ent_set_cert_key((uint8_t *) eap.client_cert, client_cert_len + 1, |       err = esp_eap_client_set_certificate_and_key((uint8_t *) eap.client_cert, client_cert_len + 1, | ||||||
|                                                    (uint8_t *) eap.client_key, client_key_len + 1, |                                                    (uint8_t *) eap.client_key, client_key_len + 1, | ||||||
|                                                    (uint8_t *) eap.password.c_str(), strlen(eap.password.c_str())); |                                                    (uint8_t *) eap.password.c_str(), strlen(eap.password.c_str())); | ||||||
|       if (err != ESP_OK) { |       if (err != ESP_OK) { | ||||||
|         ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_cert_key failed! %d", err); |         ESP_LOGV(TAG, "esp_eap_client_set_certificate_and_key failed! %d", err); | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       // in the absence of certs, assume this is username/password based |       // in the absence of certs, assume this is username/password based | ||||||
|       err = esp_wifi_sta_wpa2_ent_set_username((uint8_t *) eap.username.c_str(), eap.username.length()); |       err = esp_eap_client_set_username((uint8_t *) eap.username.c_str(), eap.username.length()); | ||||||
|       if (err != ESP_OK) { |       if (err != ESP_OK) { | ||||||
|         ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_username failed! %d", err); |         ESP_LOGV(TAG, "esp_eap_client_set_username failed! %d", err); | ||||||
|       } |       } | ||||||
|       err = esp_wifi_sta_wpa2_ent_set_password((uint8_t *) eap.password.c_str(), eap.password.length()); |       err = esp_eap_client_set_password((uint8_t *) eap.password.c_str(), eap.password.length()); | ||||||
|       if (err != ESP_OK) { |       if (err != ESP_OK) { | ||||||
|         ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_password failed! %d", err); |         ESP_LOGV(TAG, "esp_eap_client_set_password failed! %d", err); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     err = esp_wifi_sta_wpa2_ent_enable(); |     err = esp_wifi_sta_enterprise_enable(); | ||||||
|     if (err != ESP_OK) { |     if (err != ESP_OK) { | ||||||
|       ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_enable failed! %d", err); |       ESP_LOGV(TAG, "esp_wifi_sta_enterprise_enable failed! %d", err); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| #endif  // USE_WIFI_WPA2_EAP | #endif  // USE_WIFI_WPA2_EAP | ||||||
| @@ -552,7 +552,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ | |||||||
|       ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, |       ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, | ||||||
|                format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); |                format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); | ||||||
| #if USE_NETWORK_IPV6 | #if USE_NETWORK_IPV6 | ||||||
|       this->set_timeout(100, [] { WiFi.enableIpV6(); }); |       this->set_timeout(100, [] { WiFi.enableIPv6(); }); | ||||||
| #endif /* USE_NETWORK_IPV6 */ | #endif /* USE_NETWORK_IPV6 */ | ||||||
|  |  | ||||||
|       break; |       break; | ||||||
| @@ -662,12 +662,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ | |||||||
| } | } | ||||||
|  |  | ||||||
| WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() { | WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() { | ||||||
| #if USE_ARDUINO_VERSION_CODE < VERSION_CODE(3, 1, 0) |  | ||||||
|   const auto status = WiFiClass::status(); |  | ||||||
| #else |  | ||||||
|   const auto status = WiFi.status(); |   const auto status = WiFi.status(); | ||||||
| #endif |  | ||||||
|  |  | ||||||
|   if (status == WL_CONNECT_FAILED || status == WL_CONNECTION_LOST) { |   if (status == WL_CONNECT_FAILED || status == WL_CONNECTION_LOST) { | ||||||
|     return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED; |     return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -149,7 +149,7 @@ | |||||||
| #define USE_WIFI_11KV_SUPPORT | #define USE_WIFI_11KV_SUPPORT | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO | #ifdef USE_ARDUINO | ||||||
| #define USE_ARDUINO_VERSION_CODE VERSION_CODE(2, 0, 5) | #define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 1, 3) | ||||||
| #define USE_ETHERNET | #define USE_ETHERNET | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,7 +34,6 @@ build_flags = | |||||||
| [common] | [common] | ||||||
| lib_deps = | lib_deps = | ||||||
|     esphome/noise-c@0.1.4                  ; api |     esphome/noise-c@0.1.4                  ; api | ||||||
|     makuna/NeoPixelBus@2.7.3               ; neopixelbus |  | ||||||
|     improv/Improv@1.2.4                    ; improv_serial / esp32_improv |     improv/Improv@1.2.4                    ; improv_serial / esp32_improv | ||||||
|     bblanchon/ArduinoJson@6.18.5           ; json |     bblanchon/ArduinoJson@6.18.5           ; json | ||||||
|     wjtje/qr-code-generator-library@1.7.0  ; qr_code |     wjtje/qr-code-generator-library@1.7.0  ; qr_code | ||||||
| @@ -101,6 +100,7 @@ lib_deps = | |||||||
|     ESP8266WiFi                           ; wifi (Arduino built-in) |     ESP8266WiFi                           ; wifi (Arduino built-in) | ||||||
|     Update                                ; ota (Arduino built-in) |     Update                                ; ota (Arduino built-in) | ||||||
|     ESP32Async/ESPAsyncTCP@2.0.0          ; async_tcp |     ESP32Async/ESPAsyncTCP@2.0.0          ; async_tcp | ||||||
|  |     makuna/NeoPixelBus@2.7.3              ; neopixelbus | ||||||
|     ESP8266HTTPClient                     ; http_request (Arduino built-in) |     ESP8266HTTPClient                     ; http_request (Arduino built-in) | ||||||
|     ESP8266mDNS                           ; mdns (Arduino built-in) |     ESP8266mDNS                           ; mdns (Arduino built-in) | ||||||
|     DNSServer                             ; captive_portal (Arduino built-in) |     DNSServer                             ; captive_portal (Arduino built-in) | ||||||
| @@ -118,23 +118,26 @@ extra_scripts = post:esphome/components/esp8266/post_build.py.script | |||||||
| ; This are common settings for the ESP32 (all variants) using Arduino. | ; This are common settings for the ESP32 (all variants) using Arduino. | ||||||
| [common:esp32-arduino] | [common:esp32-arduino] | ||||||
| extends = common:arduino | extends = common:arduino | ||||||
| platform = platformio/espressif32@5.4.0 | platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip | ||||||
| platform_packages = | platform_packages = | ||||||
|     platformio/framework-arduinoespressif32@~3.20005.0 |     pioarduino/framework-arduinoespressif32@https://github.com/espressif/arduino-esp32/releases/download/3.1.3/esp32-3.1.3.zip | ||||||
|  |  | ||||||
| framework = arduino | framework = arduino | ||||||
| lib_deps = | lib_deps = | ||||||
|     ; order matters with lib-deps; some of the libs in common:arduino.lib_deps |     ; order matters with lib-deps; some of the libs in common:arduino.lib_deps | ||||||
|     ; don't declare built-in libraries as dependencies, so they have to be declared first |     ; don't declare built-in libraries as dependencies, so they have to be declared first | ||||||
|     FS                                   ; web_server_base (Arduino built-in) |     FS                                   ; web_server_base (Arduino built-in) | ||||||
|  |     Networking                           ; wifi,web_server_base,ethernet (Arduino built-in) | ||||||
|     WiFi                                 ; wifi,web_server_base,ethernet (Arduino built-in) |     WiFi                                 ; wifi,web_server_base,ethernet (Arduino built-in) | ||||||
|     Update                               ; ota,web_server_base (Arduino built-in) |     Update                               ; ota,web_server_base (Arduino built-in) | ||||||
|     ${common:arduino.lib_deps} |     ${common:arduino.lib_deps} | ||||||
|     ESP32Async/AsyncTCP@3.4.4            ; async_tcp |     ESP32Async/AsyncTCP@3.4.4            ; async_tcp | ||||||
|     WiFiClientSecure                     ; http_request,nextion (Arduino built-in) |     NetworkClientSecure                  ; http_request,nextion (Arduino built-in) | ||||||
|     HTTPClient                           ; http_request,nextion (Arduino built-in) |     HTTPClient                           ; http_request,nextion (Arduino built-in) | ||||||
|     ESPmDNS                              ; mdns (Arduino built-in) |     ESPmDNS                              ; mdns (Arduino built-in) | ||||||
|  |     ESP32 Async UDP                      ; captive_portal (Arduino built-in) | ||||||
|     DNSServer                            ; captive_portal (Arduino built-in) |     DNSServer                            ; captive_portal (Arduino built-in) | ||||||
|  |     makuna/NeoPixelBus@2.8.0             ; neopixelbus | ||||||
|     esphome/ESP32-audioI2S@2.3.0         ; i2s_audio |     esphome/ESP32-audioI2S@2.3.0         ; i2s_audio | ||||||
|     droscy/esp_wireguard@0.4.2           ; wireguard |     droscy/esp_wireguard@0.4.2           ; wireguard | ||||||
|     esphome/esp-audio-libs@1.1.4         ; audio |     esphome/esp-audio-libs@1.1.4         ; audio | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ platformio==6.1.18  # When updating platformio, also update /docker/Dockerfile | |||||||
| esptool==4.8.1 | esptool==4.8.1 | ||||||
| click==8.1.7 | click==8.1.7 | ||||||
| esphome-dashboard==20250514.0 | esphome-dashboard==20250514.0 | ||||||
| aioesphomeapi==32.2.3 | aioesphomeapi==32.2.4 | ||||||
| zeroconf==0.147.0 | zeroconf==0.147.0 | ||||||
| puremagic==1.29 | puremagic==1.29 | ||||||
| ruamel.yaml==0.18.14 # dashboard_import | ruamel.yaml==0.18.14 # dashboard_import | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ pyupgrade==3.20.0  # also change in .pre-commit-config.yaml when updating | |||||||
| pre-commit | pre-commit | ||||||
|  |  | ||||||
| # Unit tests | # Unit tests | ||||||
| pytest==8.4.0 | pytest==8.4.1 | ||||||
| pytest-cov==6.2.1 | pytest-cov==6.2.1 | ||||||
| pytest-mock==3.14.1 | pytest-mock==3.14.1 | ||||||
| pytest-asyncio==1.0.0 | pytest-asyncio==1.0.0 | ||||||
|   | |||||||
| @@ -959,8 +959,9 @@ def build_message_type( | |||||||
|         prot = "bool decode_64bit(uint32_t field_id, Proto64Bit value) override;" |         prot = "bool decode_64bit(uint32_t field_id, Proto64Bit value) override;" | ||||||
|         protected_content.insert(0, prot) |         protected_content.insert(0, prot) | ||||||
|  |  | ||||||
|     o = f"void {desc.name}::encode(ProtoWriteBuffer buffer) const {{" |     # Only generate encode method if there are fields to encode | ||||||
|     if encode: |     if encode: | ||||||
|  |         o = f"void {desc.name}::encode(ProtoWriteBuffer buffer) const {{" | ||||||
|         if len(encode) == 1 and len(encode[0]) + len(o) + 3 < 120: |         if len(encode) == 1 and len(encode[0]) + len(o) + 3 < 120: | ||||||
|             o += f" {encode[0]} " |             o += f" {encode[0]} " | ||||||
|         else: |         else: | ||||||
| @@ -970,25 +971,23 @@ def build_message_type( | |||||||
|         cpp += o |         cpp += o | ||||||
|         prot = "void encode(ProtoWriteBuffer buffer) const override;" |         prot = "void encode(ProtoWriteBuffer buffer) const override;" | ||||||
|         public_content.append(prot) |         public_content.append(prot) | ||||||
|  |     # If no fields to encode, the default implementation in ProtoMessage will be used | ||||||
|  |  | ||||||
|     # Add calculate_size method |     # Add calculate_size method only if there are fields | ||||||
|     o = f"void {desc.name}::calculate_size(uint32_t &total_size) const {{" |  | ||||||
|  |  | ||||||
|     # Add a check for empty/default objects to short-circuit the calculation |  | ||||||
|     # Only add this optimization if we have fields to check |  | ||||||
|     if size_calc: |     if size_calc: | ||||||
|  |         o = f"void {desc.name}::calculate_size(uint32_t &total_size) const {{" | ||||||
|         # For a single field, just inline it for simplicity |         # For a single field, just inline it for simplicity | ||||||
|         if len(size_calc) == 1 and len(size_calc[0]) + len(o) + 3 < 120: |         if len(size_calc) == 1 and len(size_calc[0]) + len(o) + 3 < 120: | ||||||
|             o += f" {size_calc[0]} " |             o += f" {size_calc[0]} " | ||||||
|         else: |         else: | ||||||
|             # For multiple fields, add a short-circuit check |             # For multiple fields | ||||||
|             o += "\n" |             o += "\n" | ||||||
|             # Performance optimization: add all the size calculations |  | ||||||
|             o += indent("\n".join(size_calc)) + "\n" |             o += indent("\n".join(size_calc)) + "\n" | ||||||
|         o += "}\n" |         o += "}\n" | ||||||
|         cpp += o |         cpp += o | ||||||
|         prot = "void calculate_size(uint32_t &total_size) const override;" |         prot = "void calculate_size(uint32_t &total_size) const override;" | ||||||
|         public_content.append(prot) |         public_content.append(prot) | ||||||
|  |     # If no fields to calculate size for, the default implementation in ProtoMessage will be used | ||||||
|  |  | ||||||
|     o = f"void {desc.name}::dump_to(std::string &out) const {{" |     o = f"void {desc.name}::dump_to(std::string &out) const {{" | ||||||
|     if dump: |     if dump: | ||||||
| @@ -1425,18 +1424,32 @@ def main() -> None: | |||||||
|         hpp_protected += f"  void {on_func}(const {inp} &msg) override;\n" |         hpp_protected += f"  void {on_func}(const {inp} &msg) override;\n" | ||||||
|         hpp += f"  virtual {ret} {func}(const {inp} &msg) = 0;\n" |         hpp += f"  virtual {ret} {func}(const {inp} &msg) = 0;\n" | ||||||
|         cpp += f"void {class_name}::{on_func}(const {inp} &msg) {{\n" |         cpp += f"void {class_name}::{on_func}(const {inp} &msg) {{\n" | ||||||
|         body = "" |  | ||||||
|         if needs_conn: |  | ||||||
|             body += "if (!this->is_connection_setup()) {\n" |  | ||||||
|             body += "  this->on_no_setup_connection();\n" |  | ||||||
|             body += "  return;\n" |  | ||||||
|             body += "}\n" |  | ||||||
|         if needs_auth: |  | ||||||
|             body += "if (!this->is_authenticated()) {\n" |  | ||||||
|             body += "  this->on_unauthenticated_access();\n" |  | ||||||
|             body += "  return;\n" |  | ||||||
|             body += "}\n" |  | ||||||
|  |  | ||||||
|  |         # Start with authentication/connection check if needed | ||||||
|  |         if needs_auth or needs_conn: | ||||||
|  |             # Determine which check to use | ||||||
|  |             if needs_auth: | ||||||
|  |                 check_func = "this->check_authenticated_()" | ||||||
|  |             else: | ||||||
|  |                 check_func = "this->check_connection_setup_()" | ||||||
|  |  | ||||||
|  |             body = f"if ({check_func}) {{\n" | ||||||
|  |  | ||||||
|  |             # Add the actual handler code, indented | ||||||
|  |             handler_body = "" | ||||||
|  |             if is_void: | ||||||
|  |                 handler_body = f"this->{func}(msg);\n" | ||||||
|  |             else: | ||||||
|  |                 handler_body = f"{ret} ret = this->{func}(msg);\n" | ||||||
|  |                 handler_body += "if (!this->send_message(ret)) {\n" | ||||||
|  |                 handler_body += "  this->on_fatal_error();\n" | ||||||
|  |                 handler_body += "}\n" | ||||||
|  |  | ||||||
|  |             body += indent(handler_body) + "\n" | ||||||
|  |             body += "}\n" | ||||||
|  |         else: | ||||||
|  |             # No auth check needed, just call the handler | ||||||
|  |             body = "" | ||||||
|             if is_void: |             if is_void: | ||||||
|                 body += f"this->{func}(msg);\n" |                 body += f"this->{func}(msg);\n" | ||||||
|             else: |             else: | ||||||
| @@ -1444,6 +1457,7 @@ def main() -> None: | |||||||
|                 body += "if (!this->send_message(ret)) {\n" |                 body += "if (!this->send_message(ret)) {\n" | ||||||
|                 body += "  this->on_fatal_error();\n" |                 body += "  this->on_fatal_error();\n" | ||||||
|                 body += "}\n" |                 body += "}\n" | ||||||
|  |  | ||||||
|         cpp += indent(body) + "\n" + "}\n" |         cpp += indent(body) + "\n" + "}\n" | ||||||
|  |  | ||||||
|         if ifdef is not None: |         if ifdef is not None: | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ light: | |||||||
|     rgb_order: GRB |     rgb_order: GRB | ||||||
|     num_leds: 256 |     num_leds: 256 | ||||||
|     pin: ${pin} |     pin: ${pin} | ||||||
|     rmt_channel: 0 |  | ||||||
|  |  | ||||||
| display: | display: | ||||||
|   - platform: addressable_light |   - platform: addressable_light | ||||||
|   | |||||||
| @@ -1,8 +0,0 @@ | |||||||
| <<: !include common.yaml |  | ||||||
|  |  | ||||||
| esp32_ble_tracker: |  | ||||||
|   max_connections: 3 |  | ||||||
|  |  | ||||||
| bluetooth_proxy: |  | ||||||
|   active: true |  | ||||||
|   connection_slots: 2 |  | ||||||
| @@ -8,7 +8,6 @@ light: | |||||||
|     rgb_order: GRB |     rgb_order: GRB | ||||||
|     num_leds: 256 |     num_leds: 256 | ||||||
|     pin: ${pin} |     pin: ${pin} | ||||||
|     rmt_channel: 0 |  | ||||||
|     effects: |     effects: | ||||||
|       - e131: |       - e131: | ||||||
|           universe: 1 |           universe: 1 | ||||||
|   | |||||||
| @@ -32,3 +32,7 @@ esp32_camera_web_server: | |||||||
|     mode: stream |     mode: stream | ||||||
|   - port: 8081 |   - port: 8081 | ||||||
|     mode: snapshot |     mode: snapshot | ||||||
|  |  | ||||||
|  | wifi: | ||||||
|  |   ssid: MySSID | ||||||
|  |   password: password1 | ||||||
|   | |||||||
| @@ -1,18 +0,0 @@ | |||||||
| light: |  | ||||||
|   - platform: esp32_rmt_led_strip |  | ||||||
|     id: led_strip1 |  | ||||||
|     pin: ${pin1} |  | ||||||
|     num_leds: 60 |  | ||||||
|     rmt_channel: 0 |  | ||||||
|     rgb_order: GRB |  | ||||||
|     chipset: ws2812 |  | ||||||
|   - platform: esp32_rmt_led_strip |  | ||||||
|     id: led_strip2 |  | ||||||
|     pin: ${pin2} |  | ||||||
|     num_leds: 60 |  | ||||||
|     rmt_channel: 1 |  | ||||||
|     rgb_order: RGB |  | ||||||
|     bit0_high: 100us |  | ||||||
|     bit0_low: 100us |  | ||||||
|     bit1_high: 100us |  | ||||||
|     bit1_low: 100us |  | ||||||
| @@ -3,4 +3,4 @@ substitutions: | |||||||
|   pin2: GPIO14 |   pin2: GPIO14 | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include common-ard.yaml |   common: !include common.yaml | ||||||
|   | |||||||
| @@ -3,4 +3,4 @@ substitutions: | |||||||
|   pin2: GPIO4 |   pin2: GPIO4 | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include common-ard.yaml |   common: !include common.yaml | ||||||
|   | |||||||
| @@ -3,4 +3,4 @@ substitutions: | |||||||
|   pin2: GPIO4 |   pin2: GPIO4 | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include common-idf.yaml |   common: !include common.yaml | ||||||
|   | |||||||
| @@ -3,4 +3,4 @@ substitutions: | |||||||
|   pin2: GPIO14 |   pin2: GPIO14 | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include common-idf.yaml |   common: !include common.yaml | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ substitutions: | |||||||
|   pin2: GPIO4 |   pin2: GPIO4 | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include common-idf.yaml |   common: !include common.yaml | ||||||
|  |  | ||||||
| light: | light: | ||||||
|   - id: !extend led_strip1 |   - id: !extend led_strip1 | ||||||
|   | |||||||
| @@ -1,5 +1 @@ | |||||||
| <<: !include common.yaml | <<: !include common.yaml | ||||||
|  |  | ||||||
| esp32: |  | ||||||
|   framework: |  | ||||||
|     version: 2.0.9 |  | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ light: | |||||||
|     chipset: ws2812 |     chipset: ws2812 | ||||||
|     num_leds: 256 |     num_leds: 256 | ||||||
|     rgb_order: GRB |     rgb_order: GRB | ||||||
|     rmt_channel: 1 |  | ||||||
|     pin: ${pin} |     pin: ${pin} | ||||||
|   - platform: partition |   - platform: partition | ||||||
|     name: Partition Light |     name: Partition Light | ||||||
|   | |||||||
| @@ -1,14 +0,0 @@ | |||||||
| remote_receiver: |  | ||||||
|   - id: rcvr |  | ||||||
|     pin: ${pin} |  | ||||||
|     rmt_channel: ${rmt_channel} |  | ||||||
|     dump: all |  | ||||||
|     tolerance: 25% |  | ||||||
|     <<: !include common-actions.yaml |  | ||||||
|  |  | ||||||
| binary_sensor: |  | ||||||
|   - platform: remote_receiver |  | ||||||
|     name: Panasonic Remote Input |  | ||||||
|     panasonic: |  | ||||||
|       address: 0x4004 |  | ||||||
|       command: 0x100BCBD |  | ||||||
| @@ -1,6 +1,9 @@ | |||||||
| substitutions: | substitutions: | ||||||
|   pin: GPIO2 |   pin: GPIO2 | ||||||
|   rmt_channel: "2" |   clock_resolution: "2000000" | ||||||
|  |   filter_symbols: "2" | ||||||
|  |   receive_symbols: "4" | ||||||
|  |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-ard.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -1,6 +1,9 @@ | |||||||
| substitutions: | substitutions: | ||||||
|   pin: GPIO2 |   pin: GPIO2 | ||||||
|   rmt_channel: "2" |   clock_resolution: "2000000" | ||||||
|  |   filter_symbols: "2" | ||||||
|  |   receive_symbols: "4" | ||||||
|  |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-ard.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -6,4 +6,4 @@ substitutions: | |||||||
|   rmt_symbols: "64" |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-idf.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -6,4 +6,4 @@ substitutions: | |||||||
|   rmt_symbols: "64" |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-idf.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ substitutions: | |||||||
|   rmt_symbols: "64" |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-idf.yaml |   common: !include esp32-common.yaml | ||||||
|  |  | ||||||
| remote_receiver: | remote_receiver: | ||||||
|   - id: !extend rcvr |   - id: !extend rcvr | ||||||
|   | |||||||
| @@ -1,8 +0,0 @@ | |||||||
| remote_transmitter: |  | ||||||
|   - id: xmitr |  | ||||||
|     pin: ${pin} |  | ||||||
|     rmt_channel: ${rmt_channel} |  | ||||||
|     carrier_duty_percent: 50% |  | ||||||
|  |  | ||||||
| packages: |  | ||||||
|   buttons: !include common-buttons.yaml |  | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| substitutions: | substitutions: | ||||||
|   pin: GPIO2 |   pin: GPIO2 | ||||||
|   rmt_channel: "2" |   clock_resolution: "2000000" | ||||||
|  |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-ard.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| substitutions: | substitutions: | ||||||
|   pin: GPIO2 |   pin: GPIO2 | ||||||
|   rmt_channel: "1" |   clock_resolution: "2000000" | ||||||
|  |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-ard.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -4,4 +4,4 @@ substitutions: | |||||||
|   rmt_symbols: "64" |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-idf.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -4,4 +4,4 @@ substitutions: | |||||||
|   rmt_symbols: "64" |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-idf.yaml |   common: !include esp32-common.yaml | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ substitutions: | |||||||
|   rmt_symbols: "64" |   rmt_symbols: "64" | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   common: !include esp32-common-idf.yaml |   common: !include esp32-common.yaml | ||||||
|  |  | ||||||
| remote_transmitter: | remote_transmitter: | ||||||
|   - id: !extend xmitr |   - id: !extend xmitr | ||||||
|   | |||||||
| @@ -12,6 +12,5 @@ light: | |||||||
|     rgb_order: GRB |     rgb_order: GRB | ||||||
|     num_leds: 256 |     num_leds: 256 | ||||||
|     pin: 2 |     pin: 2 | ||||||
|     rmt_channel: 0 |  | ||||||
|     effects: |     effects: | ||||||
|       - wled: |       - wled: | ||||||
|   | |||||||
| @@ -12,6 +12,5 @@ light: | |||||||
|     rgb_order: GRB |     rgb_order: GRB | ||||||
|     num_leds: 256 |     num_leds: 256 | ||||||
|     pin: 2 |     pin: 2 | ||||||
|     rmt_channel: 0 |  | ||||||
|     effects: |     effects: | ||||||
|       - wled: |       - wled: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user