Offload image prepare to executor, keep BLE transfer on the loop#54
Open
balloob wants to merge 1 commit into
Open
Offload image prepare to executor, keep BLE transfer on the loop#54balloob wants to merge 1 commit into
balloob wants to merge 1 commit into
Conversation
_async_send_image awaited device.upload_image(), which runs the library's _prepare_image synchronously on the event loop: rotate + fit + dither + encode + zlib on a full frame. Every upload_image/drawcustom call blocked the HA event loop for the whole CPU stage before any BLE I/O started. py-opendisplay 7.9.0 exposes the split deliberately: prepare_image() is the heavy CPU work and needs only the device config (no BLE), and device.upload_prepared_image() does the BLE transfer. Run prepare_image() in the executor via async_add_executor_job and pass the same dither/tone/fit/rotate options; then upload_prepared_image() on the loop. compress is gated on display.supports_zip to mirror upload_image() (which passes `compress and supports_compression` into _prepare_image); when the panel has no zip support prepare_image() returns compressed_data=None and upload_prepared_image() falls back to the uncompressed protocol, unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012g2e8mr132vcizx92WsgiR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
_async_send_image(the shared upload path behind both theupload_imageanddrawcustomservices) awaiteddevice.upload_image(...). Inside the library that call runs_prepare_imagesynchronously on the event loop: rotate + fit + dither + encode + zlib on a full frame. So every upload/drawcustom blocked the Home Assistant event loop for the entire CPU stage before any BLE I/O even started.Fix
py-opendisplay 7.9.0 exposes the split deliberately:
prepare_image(image, config=..., ...)— module-level, does the heavy CPU work (rotate/fit/dither/encode/compress) from the device config only, no BLE connection.device.upload_prepared_image(prepared, refresh_mode=...)— sends the pre-computed data over BLE._async_send_imagenow runsprepare_imagein the executor viahass.async_add_executor_job(passing the samedither_mode/tone/fit/rotateoptions previously handed toupload_image), then does onlyupload_prepared_imageon the loop inside_async_connect_and_run. The heavy CPU work is off the loop; only the BLE transfer stays on it.compressis gated ondisplay.supports_zip, mirroringupload_image()which passescompress and supports_compressioninto_prepare_image. When the panel has no zip support,prepare_image()returnscompressed_data=Noneandupload_prepared_image()falls back to the uncompressed protocol — identical behavior to before, just moved off-loop.Interaction with the per-MAC
ble_lock(#53)This is written so the two compose correctly. #53 wraps the whole
_async_connect_and_runconnection lifetime (async with entry.runtime_data.ble_lock, OpenDisplayDevice(...)) in the BLE lock. By moving theprepare_imageexecutor call before_async_connect_and_run(before the connection is opened), the CPU work runs outside the lock, and the lock is held only around theupload_prepared_imageBLE transfer — exactly the desired scoping (don't hold the per-tag BLE lock while burning CPU on dithering). #53 is not yet merged intofeat/clean-port; this branch is based on the currentfeat/clean-portstate and does not touch the lock itself, so it merges cleanly in either order.Testing
python -m py_compile custom_components/opendisplay/services.pypasses.prepare_imageis a module-level function exported fromopendisplay, deriving capabilities andpanel_ic_typefromconfigwhen not supplied (equivalent to a config-constructed device that skips interrogation);upload_prepared_image(prepared_data, refresh_mode=..., compress=True, ...)accepts the(uncompressed, compressed_or_None, processed_image)tupleprepare_imagereturns. Only args that exist at the pinned v7.9.0 are used.🤖 Generated with Claude Code
https://claude.ai/code/session_012g2e8mr132vcizx92WsgiR