From 170682eed9bae481c3d5500000fdda7c31f77458 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Thu, 3 Sep 2026 22:40:06 -0400 Subject: [PATCH 1/2] feat(render_plugin): add --display-mode so multi-mode plugins can be rendered render_plugin.py always called plugin.display(force_clear=True) with no mode. A plugin that declares one display mode is fine, but the sports scoreboards declare three or more and keep their per-mode state on sub-managers; their no-argument path selects nothing and returns False, so the render came out blank with nothing to say why. Measured on nrl-scoreboard with identical seeded state: live.display() directly True, 1892 lit pixels plugin.display(display_mode="nrl_live") True, 1892 lit pixels plugin.display() False, 0 lit pixels --display-mode passes the requested mode through. It is only passed when asked for, so the many plugins whose display() takes no display_mode keep working untouched, and a plugin that declares modes but does not accept the argument degrades to its default screen with a warning rather than a TypeError. This is what lets the plugin READMEs show a scoreboard at all, and it also unblocks screens like birdnet_stats and the weather plugin's hourly, daily and almanac modes, which could previously only be described in prose. Co-Authored-By: Claude Opus 5 --- scripts/render_plugin.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/scripts/render_plugin.py b/scripts/render_plugin.py index 39dee61f..9e3baad8 100644 --- a/scripts/render_plugin.py +++ b/scripts/render_plugin.py @@ -52,6 +52,10 @@ def main() -> int: parser.add_argument('--height', type=int, default=32, help='Display height (default: 32)') parser.add_argument('--skip-update', action='store_true', help='Skip calling update() (render display only)') + parser.add_argument('--display-mode', default=None, + help='Display mode to render, for plugins that declare ' + 'more than one in their manifest (e.g. nrl_live). ' + 'Omitted, the plugin picks its own default.') args = parser.parse_args() @@ -141,8 +145,23 @@ def main() -> int: except Exception as e: logger.warning("update() raised: %s — continuing to display()", e) + # A plugin that declares several display modes usually renders nothing + # useful without being told which one to draw: the scoreboards keep their + # state on per-mode sub-managers and their no-argument path returns False. + # Only pass the argument when asked for, so the many plugins whose display() + # takes no display_mode keep working untouched. try: - plugin_instance.display(force_clear=True) + if args.display_mode: + try: + plugin_instance.display(display_mode=args.display_mode, + force_clear=True) + except TypeError: + logger.warning( + "%s.display() does not accept display_mode; rendering its " + "default screen instead", args.plugin) + plugin_instance.display(force_clear=True) + else: + plugin_instance.display(force_clear=True) logger.debug("display() completed") except Exception as e: logger.error("Error in display(): %s", e) From 3481701515f6b2b9a383585010321901cf988afd Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 21:09:50 +0000 Subject: [PATCH 2/2] Only fall back when plugin display rejects display_mode --- scripts/render_plugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/render_plugin.py b/scripts/render_plugin.py index 9e3baad8..6db85c1b 100644 --- a/scripts/render_plugin.py +++ b/scripts/render_plugin.py @@ -155,7 +155,10 @@ def main() -> int: try: plugin_instance.display(display_mode=args.display_mode, force_clear=True) - except TypeError: + except TypeError as error: + if ("unexpected keyword argument" not in str(error) + or "display_mode" not in str(error)): + raise logger.warning( "%s.display() does not accept display_mode; rendering its " "default screen instead", args.plugin)