The ack polling loop has a tight timing requirement with
delay_microseconds_safe(1450) between iterations. Snapshotting
available() once could leave partial ack response bytes unread
until after the delay, potentially breaking cold boot timing
on some ld2420 units. Keep batch reads only in loop().
Replace byte-at-a-time read_byte() calls with batched read_array()
in loop(). Each read_byte() internally chains through
read_array(data, 1) -> check_read_timeout_(1) -> available(),
resulting in ~3 UART driver calls per byte. Batching into a 64-byte
stack buffer reduces this to ~3 calls per loop iteration regardless
of how many bytes are available.
Also uses vector insert() for bulk append instead of per-byte
push_back(), and caps reads to remaining buffer capacity upfront
to avoid over-reading from UART.
Replace byte-at-a-time read_byte() calls with batched read_array()
in loop(). Each read_byte() internally chains through
read_array(data, 1) -> check_read_timeout_(1) -> available(),
resulting in ~3 UART driver calls per byte. Batching into a 64-byte
stack buffer reduces this to ~3 calls per loop iteration regardless
of how many bytes are available.
Replace byte-at-a-time read() calls with batched read_array() in all
four UART read sites: receive_telegram_(), receive_encrypted_telegram_(),
and two drain loops. Each read() internally chains through
read_array(data, 1) -> check_read_timeout_(1) -> available(), resulting
in ~3 UART driver calls per byte. Batching into a 64-byte stack buffer
reduces this to ~3 calls per batch regardless of byte count.
Extract drain_rx_buffer_() helper to deduplicate the two drain sites
in ready_to_request_data_() and stop_requesting_data_().
Replace byte-at-a-time read_byte() calls with batched read_array()
in all three Seeed MR sensor components. Each read_byte() internally
chains through read_array(data, 1) -> check_read_timeout_(1) ->
available(), resulting in ~3 UART driver calls per byte. Batching
into a 64-byte stack buffer reduces this to ~3 calls per loop
iteration regardless of how many bytes are available.
Read all available bytes in batches via read_array() instead of
byte-at-a-time read() calls. Each read() internally chains through
read_byte -> read_array(1) -> check_read_timeout_ -> available(),
resulting in 3 UART calls per byte. Batching reduces this
significantly.
Read all available bytes in batches via read_array() instead of
byte-at-a-time read() calls. Each read() internally chains through
read_byte -> read_array(1) -> check_read_timeout_ -> available(),
resulting in 3 UART calls per byte. At 256000 baud with ~235 bytes
per loop iteration, this was ~706 UART operations per loop call.
Batching reduces this to ~12.
Measured 33% reduction in loop time (2348ms -> 1577ms per 60s).
Add _to() variants that write into a stack buffer and return StringRef,
avoiding heap allocation on every publish. Update publish_state() in
climate (11 allocations eliminated), fan (3), cover (2), and valve (1)
to use the new stack-based getters.
The allocating getters are retained for setup-time paths (subscribe,
send_discovery, dump_config) where the allocation is one-time.
The on_log callback was constructing a temporary MQTTMessage struct which
copied the log_message_ topic string and created a new std::string from
the message buffer on every log line. This is called frequently at runtime
and contributes to heap fragmentation.
Use the const char* publish overload directly to avoid both allocations.