mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-05 23:05:10 +00:00
feat(plugins): request_on_demand() / end_on_demand() -- plugins ask for the screen in-process (#768)
* feat(plugins): request_on_demand() / end_on_demand() -- plugins ask for the screen in-process Four plugins (birdnet-go, mqtt-notifications, on-air, pomodoro-timer) take the screen by writing the display_on_demand_request mailbox, which the display reads once a second while the control socket is up and which stage 5 removes. This is the in-process way in that stage needed. - BasePlugin.request_on_demand(mode=None, duration=None, pinned=False) and end_on_demand(), safe from any thread, go through PluginManager to DisplayController.submit_plugin_on_demand, which only queues (at most 32) and wakes the render thread through ControlServer.wake(). The render thread applies them in _drain_control_commands, after socket commands, through _handle_on_demand_request, so they land within a frame; without a socket, on the next pending-changes pass. - A plugin's stop ends only its own session; a mailbox stop still ends any. - Both answer the request id, or None with no display in the process (web interface, check_plugin.py), a full queue, or a mock manager -- a plugin's cue to write the mailbox, which the display still reads. - docs/PLUGIN_API_REFERENCE.md documents the hasattr pattern for plugins that must keep working on older cores; IPC_CONTROL_SOCKET.md and the CHANGELOG are updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(display): wire the on-demand handler only on a manager that has it Tests and the golden traces stand in simpler plugin managers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+15
-1
@@ -772,8 +772,22 @@ class ControlServer:
|
||||
"""
|
||||
return self._pending.wait(timeout)
|
||||
|
||||
def wake(self) -> None:
|
||||
"""Wake the render thread as a queued command would, with nothing queued.
|
||||
|
||||
For work that reaches the display another way in the same process (a
|
||||
plugin's on-demand request, ``DisplayController.submit_plugin_on_demand``):
|
||||
the render thread returns from :meth:`wait_for_command` and drains,
|
||||
and reads the caller's own queue there. Safe from any thread.
|
||||
"""
|
||||
self._pending.set()
|
||||
|
||||
def drain(self) -> List[QueuedCommand]:
|
||||
"""Every queued command, oldest first. Called from the render thread."""
|
||||
"""Every queued command, oldest first. Called from the render thread.
|
||||
|
||||
Clears the wake flag first, so anything queued (or woken for) while
|
||||
this runs wakes the next wait again.
|
||||
"""
|
||||
commands: List[QueuedCommand] = []
|
||||
self._pending.clear()
|
||||
while True:
|
||||
|
||||
Reference in New Issue
Block a user