mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	bitpack api flags
This commit is contained in:
		| @@ -90,10 +90,10 @@ APIConnection::~APIConnection() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void APIConnection::loop() { | void APIConnection::loop() { | ||||||
|   if (this->next_close_) { |   if (this->flags_.next_close) { | ||||||
|     // requested a disconnect |     // requested a disconnect | ||||||
|     this->helper_->close(); |     this->helper_->close(); | ||||||
|     this->remove_ = true; |     this->flags_.remove = true; | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -134,15 +134,14 @@ void APIConnection::loop() { | |||||||
|         } else { |         } else { | ||||||
|           this->read_message(0, buffer.type, nullptr); |           this->read_message(0, buffer.type, nullptr); | ||||||
|         } |         } | ||||||
|         if (this->remove_) |         if (this->flags_.remove) | ||||||
|           return; |           return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Process deferred batch if scheduled |   // Process deferred batch if scheduled | ||||||
|   if (this->deferred_batch_.batch_scheduled && |   if (this->flags_.batch_scheduled && now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) { | ||||||
|       now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) { |  | ||||||
|     this->process_batch_(); |     this->process_batch_(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -152,7 +151,7 @@ void APIConnection::loop() { | |||||||
|     this->initial_state_iterator_.advance(); |     this->initial_state_iterator_.advance(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (this->sent_ping_) { |   if (this->flags_.sent_ping) { | ||||||
|     // Disconnect if not responded within 2.5*keepalive |     // Disconnect if not responded within 2.5*keepalive | ||||||
|     if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) { |     if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) { | ||||||
|       on_fatal_error(); |       on_fatal_error(); | ||||||
| @@ -160,13 +159,13 @@ void APIConnection::loop() { | |||||||
|     } |     } | ||||||
|   } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS) { |   } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS) { | ||||||
|     ESP_LOGVV(TAG, "Sending keepalive PING"); |     ESP_LOGVV(TAG, "Sending keepalive PING"); | ||||||
|     this->sent_ping_ = this->send_message(PingRequest()); |     this->flags_.sent_ping = this->send_message(PingRequest()); | ||||||
|     if (!this->sent_ping_) { |     if (!this->flags_.sent_ping) { | ||||||
|       // If we can't send the ping request directly (tx_buffer full), |       // If we can't send the ping request directly (tx_buffer full), | ||||||
|       // schedule it at the front of the batch so it will be sent with priority |       // schedule it at the front of the batch so it will be sent with priority | ||||||
|       ESP_LOGW(TAG, "Buffer full, ping queued"); |       ESP_LOGW(TAG, "Buffer full, ping queued"); | ||||||
|       this->schedule_message_front_(nullptr, &APIConnection::try_send_ping_request, PingRequest::MESSAGE_TYPE); |       this->schedule_message_front_(nullptr, &APIConnection::try_send_ping_request, PingRequest::MESSAGE_TYPE); | ||||||
|       this->sent_ping_ = true;  // Mark as sent to avoid scheduling multiple pings |       this->flags_.sent_ping = true;  // Mark as sent to avoid scheduling multiple pings | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -226,13 +225,13 @@ DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) { | |||||||
|   // 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->get_client_combined_info().c_str()); |   ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str()); | ||||||
|   this->next_close_ = true; |   this->flags_.next_close = true; | ||||||
|   DisconnectResponse resp; |   DisconnectResponse resp; | ||||||
|   return resp; |   return resp; | ||||||
| } | } | ||||||
| void APIConnection::on_disconnect_response(const DisconnectResponse &value) { | void APIConnection::on_disconnect_response(const DisconnectResponse &value) { | ||||||
|   this->helper_->close(); |   this->helper_->close(); | ||||||
|   this->remove_ = true; |   this->flags_.remove = true; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Encodes a message to the buffer and returns the total number of bytes used, | // Encodes a message to the buffer and returns the total number of bytes used, | ||||||
| @@ -1158,7 +1157,7 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) { | |||||||
|  |  | ||||||
| #ifdef USE_ESP32_CAMERA | #ifdef USE_ESP32_CAMERA | ||||||
| void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) { | void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) { | ||||||
|   if (!this->state_subscription_) |   if (!this->flags_.state_subscription) | ||||||
|     return; |     return; | ||||||
|   if (this->image_reader_.available()) |   if (this->image_reader_.available()) | ||||||
|     return; |     return; | ||||||
| @@ -1512,7 +1511,7 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) { | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| bool APIConnection::try_send_log_message(int level, const char *tag, const char *line) { | bool APIConnection::try_send_log_message(int level, const char *tag, const char *line) { | ||||||
|   if (this->log_subscription_ < level) |   if (this->flags_.log_subscription < level) | ||||||
|     return false; |     return false; | ||||||
|  |  | ||||||
|   // Pre-calculate message size to avoid reallocations |   // Pre-calculate message size to avoid reallocations | ||||||
| @@ -1552,7 +1551,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { | |||||||
|   resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; |   resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; | ||||||
|   resp.name = App.get_name(); |   resp.name = App.get_name(); | ||||||
|  |  | ||||||
|   this->connection_state_ = ConnectionState::CONNECTED; |   this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::CONNECTED); | ||||||
|   return resp; |   return resp; | ||||||
| } | } | ||||||
| ConnectResponse APIConnection::connect(const ConnectRequest &msg) { | ConnectResponse APIConnection::connect(const ConnectRequest &msg) { | ||||||
| @@ -1563,7 +1562,7 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) { | |||||||
|   resp.invalid_password = !correct; |   resp.invalid_password = !correct; | ||||||
|   if (correct) { |   if (correct) { | ||||||
|     ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str()); |     ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str()); | ||||||
|     this->connection_state_ = ConnectionState::AUTHENTICATED; |     this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED); | ||||||
|     this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->helper_->getpeername()); |     this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->helper_->getpeername()); | ||||||
| #ifdef USE_HOMEASSISTANT_TIME | #ifdef USE_HOMEASSISTANT_TIME | ||||||
|     if (homeassistant::global_homeassistant_time != nullptr) { |     if (homeassistant::global_homeassistant_time != nullptr) { | ||||||
| @@ -1677,7 +1676,7 @@ void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistant | |||||||
|   state_subs_at_ = 0; |   state_subs_at_ = 0; | ||||||
| } | } | ||||||
| bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { | bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { | ||||||
|   if (this->remove_) |   if (this->flags_.remove) | ||||||
|     return false; |     return false; | ||||||
|   if (this->helper_->can_write_without_blocking()) |   if (this->helper_->can_write_without_blocking()) | ||||||
|     return true; |     return true; | ||||||
| @@ -1727,7 +1726,7 @@ void APIConnection::on_no_setup_connection() { | |||||||
| } | } | ||||||
| void APIConnection::on_fatal_error() { | void APIConnection::on_fatal_error() { | ||||||
|   this->helper_->close(); |   this->helper_->close(); | ||||||
|   this->remove_ = true; |   this->flags_.remove = true; | ||||||
| } | } | ||||||
|  |  | ||||||
| void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type) { | void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type) { | ||||||
| @@ -1752,8 +1751,8 @@ void APIConnection::DeferredBatch::add_item_front(EntityBase *entity, MessageCre | |||||||
| } | } | ||||||
|  |  | ||||||
| bool APIConnection::schedule_batch_() { | bool APIConnection::schedule_batch_() { | ||||||
|   if (!this->deferred_batch_.batch_scheduled) { |   if (!this->flags_.batch_scheduled) { | ||||||
|     this->deferred_batch_.batch_scheduled = true; |     this->flags_.batch_scheduled = true; | ||||||
|     this->deferred_batch_.batch_start_time = App.get_loop_component_start_time(); |     this->deferred_batch_.batch_start_time = App.get_loop_component_start_time(); | ||||||
|   } |   } | ||||||
|   return true; |   return true; | ||||||
| @@ -1769,7 +1768,7 @@ ProtoWriteBuffer APIConnection::allocate_batch_message_buffer(uint16_t size) { | |||||||
|  |  | ||||||
| void APIConnection::process_batch_() { | void APIConnection::process_batch_() { | ||||||
|   if (this->deferred_batch_.empty()) { |   if (this->deferred_batch_.empty()) { | ||||||
|     this->deferred_batch_.batch_scheduled = false; |     this->flags_.batch_scheduled = false; | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -125,7 +125,7 @@ class APIConnection : public APIServerConnection { | |||||||
| #endif | #endif | ||||||
|   bool try_send_log_message(int level, const char *tag, const char *line); |   bool try_send_log_message(int level, const char *tag, const char *line); | ||||||
|   void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { |   void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { | ||||||
|     if (!this->service_call_subscription_) |     if (!this->flags_.service_call_subscription) | ||||||
|       return; |       return; | ||||||
|     this->send_message(call); |     this->send_message(call); | ||||||
|   } |   } | ||||||
| @@ -185,7 +185,7 @@ class APIConnection : public APIServerConnection { | |||||||
|   void on_disconnect_response(const DisconnectResponse &value) override; |   void on_disconnect_response(const DisconnectResponse &value) override; | ||||||
|   void on_ping_response(const PingResponse &value) override { |   void on_ping_response(const PingResponse &value) override { | ||||||
|     // we initiated ping |     // we initiated ping | ||||||
|     this->sent_ping_ = false; |     this->flags_.sent_ping = false; | ||||||
|   } |   } | ||||||
|   void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override; |   void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override; | ||||||
| #ifdef USE_HOMEASSISTANT_TIME | #ifdef USE_HOMEASSISTANT_TIME | ||||||
| @@ -198,16 +198,16 @@ class APIConnection : public APIServerConnection { | |||||||
|   DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override; |   DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override; | ||||||
|   void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } |   void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } | ||||||
|   void subscribe_states(const SubscribeStatesRequest &msg) override { |   void subscribe_states(const SubscribeStatesRequest &msg) override { | ||||||
|     this->state_subscription_ = true; |     this->flags_.state_subscription = true; | ||||||
|     this->initial_state_iterator_.begin(); |     this->initial_state_iterator_.begin(); | ||||||
|   } |   } | ||||||
|   void subscribe_logs(const SubscribeLogsRequest &msg) override { |   void subscribe_logs(const SubscribeLogsRequest &msg) override { | ||||||
|     this->log_subscription_ = msg.level; |     this->flags_.log_subscription = msg.level; | ||||||
|     if (msg.dump_config) |     if (msg.dump_config) | ||||||
|       App.schedule_dump_config(); |       App.schedule_dump_config(); | ||||||
|   } |   } | ||||||
|   void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override { |   void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override { | ||||||
|     this->service_call_subscription_ = true; |     this->flags_.service_call_subscription = true; | ||||||
|   } |   } | ||||||
|   void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override; |   void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override; | ||||||
|   GetTimeResponse get_time(const GetTimeRequest &msg) override { |   GetTimeResponse get_time(const GetTimeRequest &msg) override { | ||||||
| @@ -219,9 +219,12 @@ class APIConnection : public APIServerConnection { | |||||||
|   NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override; |   NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; } |   bool is_authenticated() override { | ||||||
|  |     return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::AUTHENTICATED; | ||||||
|  |   } | ||||||
|   bool is_connection_setup() override { |   bool is_connection_setup() override { | ||||||
|     return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated(); |     return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::CONNECTED || | ||||||
|  |            this->is_authenticated(); | ||||||
|   } |   } | ||||||
|   void on_fatal_error() override; |   void on_fatal_error() override; | ||||||
|   void on_unauthenticated_access() override; |   void on_unauthenticated_access() override; | ||||||
| @@ -460,19 +463,37 @@ class APIConnection : public APIServerConnection { | |||||||
|   uint16_t client_api_version_major_{0}; |   uint16_t client_api_version_major_{0}; | ||||||
|   uint16_t client_api_version_minor_{0}; |   uint16_t client_api_version_minor_{0}; | ||||||
|  |  | ||||||
|   // Group all 1-byte types together to minimize padding |   // Connection state enum | ||||||
|   enum class ConnectionState : uint8_t { |   enum class ConnectionState : uint8_t { | ||||||
|     WAITING_FOR_HELLO, |     WAITING_FOR_HELLO = 0, | ||||||
|     CONNECTED, |     CONNECTED = 1, | ||||||
|     AUTHENTICATED, |     AUTHENTICATED = 2, | ||||||
|   } connection_state_{ConnectionState::WAITING_FOR_HELLO}; |   }; | ||||||
|   uint8_t log_subscription_{ESPHOME_LOG_LEVEL_NONE}; |  | ||||||
|   bool remove_{false}; |   // Group all 1-byte types together to minimize padding | ||||||
|   bool state_subscription_{false}; |   struct APIFlags { | ||||||
|   bool sent_ping_{false}; |     uint8_t connection_state : 2;  // ConnectionState only needs 2 bits (3 states) | ||||||
|   bool service_call_subscription_{false}; |     uint8_t log_subscription : 3;  // Log levels 0-7 need 3 bits | ||||||
|   bool next_close_ = false; |     uint8_t remove : 1; | ||||||
|   // 7 bytes used, 1 byte padding |     uint8_t state_subscription : 1; | ||||||
|  |     uint8_t sent_ping : 1; | ||||||
|  |  | ||||||
|  |     uint8_t service_call_subscription : 1; | ||||||
|  |     uint8_t next_close : 1; | ||||||
|  |     uint8_t batch_scheduled : 1;  // Moved from DeferredBatch | ||||||
|  |     uint8_t reserved : 5;         // Reserved for future use | ||||||
|  |  | ||||||
|  |     APIFlags() | ||||||
|  |         : connection_state(0), | ||||||
|  |           log_subscription(ESPHOME_LOG_LEVEL_NONE), | ||||||
|  |           remove(0), | ||||||
|  |           state_subscription(0), | ||||||
|  |           sent_ping(0), | ||||||
|  |           service_call_subscription(0), | ||||||
|  |           next_close(0), | ||||||
|  |           batch_scheduled(0), | ||||||
|  |           reserved(0) {} | ||||||
|  |   } flags_;  // 2 bytes total instead of 7+ bytes | ||||||
|  |  | ||||||
|   // Larger objects at the end |   // Larger objects at the end | ||||||
|   InitialStateIterator initial_state_iterator_; |   InitialStateIterator initial_state_iterator_; | ||||||
| @@ -590,7 +611,6 @@ class APIConnection : public APIServerConnection { | |||||||
|  |  | ||||||
|     std::vector<BatchItem> items; |     std::vector<BatchItem> items; | ||||||
|     uint32_t batch_start_time{0}; |     uint32_t batch_start_time{0}; | ||||||
|     bool batch_scheduled{false}; |  | ||||||
|  |  | ||||||
|     DeferredBatch() { |     DeferredBatch() { | ||||||
|       // Pre-allocate capacity for typical batch sizes to avoid reallocation |       // Pre-allocate capacity for typical batch sizes to avoid reallocation | ||||||
| @@ -603,7 +623,6 @@ class APIConnection : public APIServerConnection { | |||||||
|     void add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type); |     void add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type); | ||||||
|     void clear() { |     void clear() { | ||||||
|       items.clear(); |       items.clear(); | ||||||
|       batch_scheduled = false; |  | ||||||
|       batch_start_time = 0; |       batch_start_time = 0; | ||||||
|     } |     } | ||||||
|     bool empty() const { return items.empty(); } |     bool empty() const { return items.empty(); } | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ void APIServer::setup() { | |||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       for (auto &c : this->clients_) { |       for (auto &c : this->clients_) { | ||||||
|         if (!c->remove_) |         if (!c->flags_.remove) | ||||||
|           c->try_send_log_message(level, tag, message); |           c->try_send_log_message(level, tag, message); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @@ -116,7 +116,7 @@ void APIServer::setup() { | |||||||
|     esp32_camera::global_esp32_camera->add_image_callback( |     esp32_camera::global_esp32_camera->add_image_callback( | ||||||
|         [this](const std::shared_ptr<esp32_camera::CameraImage> &image) { |         [this](const std::shared_ptr<esp32_camera::CameraImage> &image) { | ||||||
|           for (auto &c : this->clients_) { |           for (auto &c : this->clients_) { | ||||||
|             if (!c->remove_) |             if (!c->flags_.remove) | ||||||
|               c->set_camera_state(image); |               c->set_camera_state(image); | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
| @@ -176,7 +176,7 @@ void APIServer::loop() { | |||||||
|   while (client_index < this->clients_.size()) { |   while (client_index < this->clients_.size()) { | ||||||
|     auto &client = this->clients_[client_index]; |     auto &client = this->clients_[client_index]; | ||||||
|  |  | ||||||
|     if (!client->remove_) { |     if (!client->flags_.remove) { | ||||||
|       // Common case: process active client |       // Common case: process active client | ||||||
|       client->loop(); |       client->loop(); | ||||||
|       client_index++; |       client_index++; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user