Skip to content

Use loop() to receive and send messages immediately, and set and process changed settings appropriately - #168

Open
kchen wants to merge 9 commits into
JanM321:mainfrom
kchen:handle-corrupted-messages
Open

Use loop() to receive and send messages immediately, and set and process changed settings appropriately #168
kchen wants to merge 9 commits into
JanM321:mainfrom
kchen:handle-corrupted-messages

Conversation

@kchen

@kchen kchen commented May 27, 2026

Copy link
Copy Markdown

The big thing this PR does is that it rearchitects the update() function, and moves much of the functionality to loop(). update() currently polls for new bytes to process and messages to send every 6 seconds. By using loop(), which is called regularly (and exits quickly if there is nothing to process), we can handle incoming bytes in approximately real-time.

The pre-existing code has a 15 second timeout if a message is incomplete. If a partial message is received, and many seconds later, a full 13-byte message is received, the pre-existing code will incorrectly drop the message because the first half of the full message will be considered the end of the partial message. The move to the real-time loop() and dropping the timeout to 150 milliseconds allows the code to quickly drop partial messages, allowing later full messages to be properly handled. (It takes 96 milliseconds for a byte to be received.)

Using loop() also allows outgoing messages to be sent right away, rather than waiting for the 6 second update() cycle. This rearchitecture of sending outgoing messages eliminates the tight loop of up to 500 milliseconds waiting for the data line to become available, which was previously blocking general ESP32 operation, and causing warnings to be logged.

This PR also includes improvements to protect against corrupted messages:

  • The mini-split unit often sends two copies of messages for redundancy, but the pre-existing code will ignore the second one if the first one is corrupted. However, in practice, generally at least one copy is properly received, and so it should not be ignored. This PR updates the code to not drop subsequent messages.
  • If a status message is invalid, the entire message is now ignored, rather than applying a partial update. Since the message is invalid, it is presumably corrupted, and with the change, no part of the status message causes a change on the microcontroller end.
  • The status message contains a settings changed bit. With this PR, settings changes in the status message from the LG unit are only accepted if the settings changed bit is set, or if there are settings changes without the bit set, the exact same message must be received twice.
  • Outgoing status messages from the microcontroller to the LG unit also now only set the settings changed bit when the settings have been changed, rather than always. (Presumably, this helps the LG unit from receiving invalid settings changes.)

There are also a few miscellaneous changes:

  • An outgoing settings message was always sent after every status message. This has been updated to only send the settings message if needed.
  • Floating point equality checks have been updated to use approximate comparisons. It seems like this might not actually be an issue for this project, but approximate comparisons seem generally safer.

This PR consists of several commits, and it may be worth reviewing the commits one by one, rather than the entire diff as a whole. I've tried to keep each commit reasonably self-contained, although there are a few things where it's not as clean as it could be.

kchen added 6 commits May 25, 2026 00:54
* Add loop() function to handle UART reading so that messages from the
  mini-split can be read and handled immediately.

* Drop messages that are incomplete after a 150 millisecond timeout.
  Since each byte takes about 96 milliseconds to transmit, this quick
  timeout allows incomplete messages to be dropped right away to
  prevent message framing problems.

* Remove had_error functionality to better handle messages with
  invalid checksums.  The mini-split system often sends two copies of
  the same message, and if the first copy is corrupted, the second
  copy should still be processed if not corrupted.
* Send messages immediately when the line is available, removing tight
  loops to avoid blocking.

* Verify sent messages 2 seconds after sending.
Rather than sending a settings message every time a status message is
sent every 20 seconds, only send the settings change as needed.
* To protect against mini-split units that often send corrupted
  messages, when processing status messages, only accept settings
  changes if the settings changed bit is set (or the status message is
  the first valid status message received).

* If the status message is invalid, ignore the entire message, and do
  not partially apply updates.

* Fix potential floating point comparison errors.
In outgoing status messages, rather than always setting the changed
settings bit, only set it when settings have changed.  This should
help protect against corrupted outgoing messages.
kchen and others added 2 commits July 17, 2026 20:02
Accept a status message if the identical message has arrived in
consecutive status messages, even if the changed settings bit is not
set.  This avoids getting stuck if the original status message with
the changed settings bit set was corrupted.
@kchen
kchen force-pushed the handle-corrupted-messages branch from 966ae61 to 176e5e5 Compare July 18, 2026 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant