mirror of
https://github.com/esphome/esphome.git
synced 2025-11-18 15:55:46 +00:00
[api][event] Send events immediately to prevent loss during rapid triggers (#11777)
This commit is contained in:
@@ -1295,7 +1295,7 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
|
|||||||
|
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
void APIConnection::send_event(event::Event *event, const char *event_type) {
|
void APIConnection::send_event(event::Event *event, const char *event_type) {
|
||||||
this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE,
|
this->send_message_smart_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE,
|
||||||
EventResponse::ESTIMATED_SIZE);
|
EventResponse::ESTIMATED_SIZE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_event_response(event::Event *event, const char *event_type, APIConnection *conn,
|
uint16_t APIConnection::try_send_event_response(event::Event *event, const char *event_type, APIConnection *conn,
|
||||||
|
|||||||
@@ -650,21 +650,30 @@ class APIConnection final : public APIServerConnection {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Helper method to send a message either immediately or via batching
|
// Helper to check if a message type should bypass batching
|
||||||
bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint8_t message_type,
|
// Returns true if:
|
||||||
uint8_t estimated_size) {
|
|
||||||
// Try to send immediately if:
|
|
||||||
// 1. It's an UpdateStateResponse (always send immediately to handle cases where
|
// 1. It's an UpdateStateResponse (always send immediately to handle cases where
|
||||||
// the main loop is blocked, e.g., during OTA updates)
|
// the main loop is blocked, e.g., during OTA updates)
|
||||||
// 2. OR: We should try to send immediately (should_try_send_immediately = true)
|
// 2. It's an EventResponse (events are edge-triggered - every occurrence matters)
|
||||||
// AND Batch delay is 0 (user has opted in to immediate sending)
|
// 3. OR: User has opted into immediate sending (should_try_send_immediately = true
|
||||||
// 3. AND: Buffer has space available
|
// AND batch_delay = 0)
|
||||||
if ((
|
inline bool should_send_immediately_(uint8_t message_type) const {
|
||||||
|
return (
|
||||||
#ifdef USE_UPDATE
|
#ifdef USE_UPDATE
|
||||||
message_type == UpdateStateResponse::MESSAGE_TYPE ||
|
message_type == UpdateStateResponse::MESSAGE_TYPE ||
|
||||||
#endif
|
#endif
|
||||||
(this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0)) &&
|
#ifdef USE_EVENT
|
||||||
this->helper_->can_write_without_blocking()) {
|
message_type == EventResponse::MESSAGE_TYPE ||
|
||||||
|
#endif
|
||||||
|
(this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to send a message either immediately or via batching
|
||||||
|
// Tries immediate send if should_send_immediately_() returns true and buffer has space
|
||||||
|
// Falls back to batching if immediate send fails or isn't applicable
|
||||||
|
bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint8_t message_type,
|
||||||
|
uint8_t estimated_size) {
|
||||||
|
if (this->should_send_immediately_(message_type) && this->helper_->can_write_without_blocking()) {
|
||||||
// Now actually encode and send
|
// Now actually encode and send
|
||||||
if (creator(entity, this, MAX_BATCH_PACKET_SIZE, true) &&
|
if (creator(entity, this, MAX_BATCH_PACKET_SIZE, true) &&
|
||||||
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
|
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
|
||||||
@@ -682,6 +691,27 @@ class APIConnection final : public APIServerConnection {
|
|||||||
return this->schedule_message_(entity, creator, message_type, estimated_size);
|
return this->schedule_message_(entity, creator, message_type, estimated_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overload for MessageCreator (used by events which need to capture event_type)
|
||||||
|
bool send_message_smart_(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) {
|
||||||
|
// Try to send immediately if message type should bypass batching and buffer has space
|
||||||
|
if (this->should_send_immediately_(message_type) && this->helper_->can_write_without_blocking()) {
|
||||||
|
// Now actually encode and send
|
||||||
|
if (creator(entity, this, MAX_BATCH_PACKET_SIZE, true, message_type) &&
|
||||||
|
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
// Log the message in verbose mode
|
||||||
|
this->log_proto_message_(entity, creator, message_type);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If immediate send failed, fall through to batching
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to scheduled batching
|
||||||
|
return this->schedule_message_(entity, std::move(creator), message_type, estimated_size);
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to schedule a deferred message with known message type
|
// Helper function to schedule a deferred message with known message type
|
||||||
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) {
|
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) {
|
||||||
this->deferred_batch_.add_item(entity, std::move(creator), message_type, estimated_size);
|
this->deferred_batch_.add_item(entity, std::move(creator), message_type, estimated_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user