feat(viewer): blank/unblank commands to turn the display off - #3065
Conversation
Adds a way to blank the screen on demand, parallel to the existing next/previous/stop/play viewer commands on the anthias.viewer Redis channel: * Wayland boards (x86/pi5/arm64): wlr-randr powers the connector off (true DPMS power-off) and back on. _wlr_output_names() gained an include_disabled flag so unblank can re-enable a connector that's currently Enabled: no. * eglfs/linuxfb boards (pi2/pi3/pi4): the Qt app owns the DRM master and can't be powered off externally, so the asset loop paints a new all-black BLACK_SCREEN image instead (same proven loadImage path as the standby screen). Backlight stays on; the screen goes black. blank_display() flips display_blanked + loop_is_stopped from the subscriber thread and runs the out-of-process wlr-randr call there; the webview repaint is deferred to the main loop thread (start_loop), which owns current_browser_url — mirroring the existing rotation-bounce threading discipline. Validated live on x86 (wayland): `blank` -> DP-1 Enabled: no, `unblank` -> Enabled: yes. eglfs black-paint reuses the standby loadImage path. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
There was a problem hiding this comment.
Pull request overview
Adds first-class “blank/unblank” viewer commands to support turning displays off (Wayland via wlr-randr) or blanking to black (eglfs/linuxfb via a black image) when the viewer owns DRM master, integrating with the existing Redis anthias.viewer command channel.
Changes:
- Introduces
blank/unblankcommands and supporting state (display_blanked) in the viewer. - Adds wlroots output-power toggling via
wlr-randrand extends_wlr_output_names()to optionally include disabled outputs. - Adds unit tests covering power targeting, platform no-ops, state transitions, and command registration.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/anthias_viewer/__init__.py |
Implements wlroots DPMS on/off, blank/unblank command handlers, state, and main-loop blank painting. |
src/anthias_viewer/constants.py |
Adds BLACK_SCREEN URL constant for eglfs/linuxfb blanking. |
tests/test_viewer.py |
Adds unit tests for wlroots power behavior and blank/unblank commands/state. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Import get_skip_event from anthias_viewer.utils in the test instead of via the viewer module, which doesn't explicitly re-export it (mypy attr-defined under --no-implicit-reexport). - start_loop: guard the black repaint on current_browser_url so it doesn't re-call view_image() — and re-log "Current url ..." at INFO — on every 0.1s tick while blanked (Copilot). - Route stop/play through module-level helpers that set the loop_is_stopped global start_loop actually reads; the prior setattr(__main__, ...) wrote a dead namespace under `python -m anthias_viewer` and never paused the loop. play now implies unblank when the display is blanked (Copilot). - Add tests for stop flag + play-implies-unblank. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
On-device eglfs validation — done. Built this branch's viewer+server as derived images on top of the
Viewer booted clean on the migrated config (no |
http is intentional — the viewer talks to the local anthias-server over plain HTTP (TLS is the opt-in Caddy sidecar's job), identical to the existing STANDBY_SCREEN / SPLASH_PAGE_URL. Annotate the line # NOSONAR, the repo's documented convention for Sonar false positives under Automatic Analysis (see sonar-project.properties; cf. test_csrf.py). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|



Motivation
There was no way to turn an Anthias display off. On a Wayland board you can run
wlr-randr --output X --offexternally, but on eglfs/Pi boards the Qt app owns the DRM master, so the display can't be powered off from outside the process at all (DPMS sysfs writes are rejected;vcgencmd display_poweris a no-op under vc4-KMS). This adds a first-class, cross-platform way to blank the screen.What it does
Two new viewer commands on the
anthias.viewerRedis channel, alongsidenext/previous/stop/play:blank— darken the screen and pause playback.wlr-randrpowers every connector off (true DPMS power-off, monitor sleeps).BLACK_SCREENimage (the same provenloadImagepath as the standby screen). Backlight stays on; the screen goes black.unblank— power the connector back on (Wayland) and resume playback._wlr_output_names()gained aninclude_disabledflag sounblankcan re-enable a connector that's currentlyEnabled: no.Threading
blank_display()/unblank_display()run on the subscriber thread: they flipdisplay_blanked+loop_is_stoppedand issue the out-of-processwlr-randrcall there, but defer the webview repaint to the main loop thread (start_loop), which ownscurrent_browser_url— mirroring the existing rotation-bounce discipline.view_image()no-ops once the URL is alreadyBLACK_SCREEN, so the paint costs oneloadImageand then idles.Testing
blank→Set output DP-1 --off,wlr-randrreportsEnabled: no;unblank→Set output DP-1 --on,Enabled: yes.loadImagepath the standby/splash screen already uses on Pi 4 (verified rendering there), andblack.pngserving was confirmed (200) after a server restart. Full on-device eglfs confirmation needs a Pi on a build that contains this change (the Pi 4 testbed is a few commits behind master); the screen is headless so the proof there is the webview fetching/static/img/black.png+ the loop pausing.Notes