feat(settings): experimental HDMI-CEC display on/off#2886
Merged
Conversation
- Add `set_display_power(on)` + `cec_available()` to `lib/diagnostics`, mirroring the existing CEC-subprocess-with-timeout pattern. - Add `/settings/display/<on|off>/` Django POST handler that surfaces success / failure to the operator as a toast (issue #2575 asks for a visible feedback loop). - Add `POST /api/v2/display/<state>` mirroring reboot / shutdown; 200 on success, 502 on CEC failure, 400 on invalid state. - Render-time gate via `cec_available()`: section is hidden when neither `/dev/cec0` nor `/dev/vchiq` exists (covers most x86 PCs). - Mark the new section "Experimental" with an amber warning chip using the existing `--color-warning-soft` / `--color-warning-strong` tokens. - Tests: unit (diagnostics, Django view, v2 API) + Playwright integration (hidden state, visible state, error toast, success toast). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's `ruff format --check` flagged the five files added in the previous commit. No functional changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds an experimental HDMI-CEC “Display power” control to Anthias, exposed both via the Settings UI and a new v2 API endpoint, with render-time gating based on presence of common CEC device nodes.
Changes:
- Add synchronous
diagnostics.set_display_power()anddiagnostics.cec_available()helpers for HDMI-CEC power on/off. - Add Settings-page POST handler + UI section (with “Experimental” badge) for turning the display on/off.
- Add
POST /api/v2/display/<on|off>endpoint mirroring the Settings action, plus unit/integration test coverage.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_template_views.py | Adds POST view tests for the new settings display-power action. |
| tests/test_diagnostics.py | Adds unit tests for set_display_power() and cec_available(). |
| tests/test_app.py | Adds Playwright integration coverage for hidden/visible states and toast behavior. |
| src/anthias_server/lib/diagnostics.py | Implements CEC power set script, synchronous subprocess wrapper, and cec_available() gate. |
| src/anthias_server/app/views.py | Adds settings_display_power POST view that flashes success/error toasts. |
| src/anthias_server/app/urls.py | Registers the new settings route settings/display/<state>/. |
| src/anthias_server/app/templates/settings.html | Renders the new “Display power” section when cec_available is true. |
| src/anthias_server/app/static/sass/_styles.scss | Adds styling for the “Experimental” badge. |
| src/anthias_server/app/page_context.py | Adds cec_available to the settings page context. |
| src/anthias_server/api/views/v2.py | Exposes a v2 view class for display power. |
| src/anthias_server/api/views/mixins.py | Adds DisplayPowerViewMixin POST handler for /api/v2/display/<state>. |
| src/anthias_server/api/urls/v2.py | Registers the new v2 route v2/display/<state>. |
| src/anthias_server/api/tests/test_v2_endpoints.py | Adds API tests for success/failure/invalid state cases. |
| src/anthias_server/api/serializers/mixins.py | Adds an (empty) serializer mixin for schema consistency. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- views.py / mixins.py: short-circuit display-power POST/API on cec_available()=False so a stale form / direct curl can't burn a 10 s libcec subprocess on non-CEC hardware. API now returns 503. - diagnostics.set_display_power: when the subprocess emits neither the OK nor ERROR sentinel, fall back to the last stderr line (or the returncode) so the operator gets an actionable failure detail instead of a generic "unexpected CEC response." Message capped at ~240 chars to keep toasts / JSON responses sane. - tests/test_app.py: write screenshots to relative `test-artifacts/cec` instead of an absolute `/usr/src/app/...` path so local runs and alternative CI layouts pick them up via the same `--output test-artifacts` convention pytest-playwright already uses. - Tests updated to cover the new cec_available() guard (HTML + v2 API) and the new stderr / returncode fallbacks in set_display_power. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot follow-up on PR #2886. - `DisplayPowerViewSerializerMixin` was empty (matching the pattern the Reboot / Shutdown mixins use), but unlike those this endpoint *does* return a JSON body — `{message: ...}` on every status code. Add a read-only `message` field so drf-spectacular has a real shape to render. - Declare `responses={200, 400, 502, 503: ...}` on the view's `@extend_schema` so the generated OpenAPI document mirrors what clients will actually receive. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two Copilot follow-ups on PR #2886. - set_display_power: the ERROR: sentinel branch previously returned the raw remainder of stdout. A chatty libcec build could blow up the toast / JSON response with a multi-line / multi-kilobyte payload. Extract the cap + last-line trim into `_trim_cec_detail` and apply it to both the ERROR branch and the unexpected-output fallback. - settings.html: the "Display power" heading concatenated the title and the "Experimental" badge with no whitespace, so screen readers and copy/paste yielded "Display powerExperimental". Add a literal space + an explicit aria-label on the badge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
vpetersson
added a commit
that referenced
this pull request
May 13, 2026
Copilot follow-up on PR #2886. The `Upload integration test artifacts` step in test-runner.yml runs only on `if: failure()`, so the always-on screenshots are not surfaced on green CI runs. Reword the in-file comment (and the PR body) to set accurate expectations: they're for local-run review, not a CI deliverable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
vpetersson
added a commit
that referenced
this pull request
May 14, 2026
* chore(cec): tidy up follow-ups from PR #2886 Three small cleanups deferred from the CEC display-power PR: - Gate the Playwright screenshot captures behind a `PYTEST_CAPTURE_SCREENSHOTS=1` env var. They were useful for the one-time UX review but ran on every CI cycle for no reason: the test-runner.yml upload-artifact step is `if: failure()`, so the PNGs on green runs got written and immediately discarded. Default is now off; set the env var for local UX work. - Drop `test_display_power_success_toast_appearance`. It drove `Alpine.store('toasts').push('success', ...)` directly because the test container can't perform a real CEC success, so its only novel assertion was that the existing toast store accepts a 'success' kind — already exercised by every other toast in the app. It only existed to capture a success-state screenshot; with the screenshot motivation gone, the test goes too. - Declare `responses={200: None}` on RebootViewMixin / ShutdownViewMixin so the generated OpenAPI schema matches the empty response body those endpoints actually return. Aligns the pattern with DisplayPowerViewMixin (PR #2886) which declared its responses explicitly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(cec): parse PYTEST_CAPTURE_SCREENSHOTS as explicit truthy `bool(os.environ.get(...))` enables the gate for any non-empty value including '0' and 'false', which surprises anyone setting it to disable. Switch to an explicit allowlist ('1', 'true', 'yes', 'on', case-insensitive). Addresses Copilot review on #2887. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.



Issues Fixed
Closes #2575.
Description
Adds a manual Turn display on / Turn display off control to the Settings page, gated behind an Experimental badge per Viktor's note on the issue that CEC is unreliable in practice.
/dev/cec0nor/dev/vchiqis present (covers most x86 PCs).get_display_power()pattern) — short timeout, no Celery hop, so the success/failure surfaces immediately as a toast (the feedback loop the issue asks for).POST /api/v2/display/<on|off>mirroring how Reboot / Shutdown are dual-exposed.Test plan
pytest -m "not integration"— all pass.ruff check+ruff format --checkclean.Screenshots
Local Playwright runs write screenshots to
test-artifacts/cec/(gitignored). TheUpload integration test artifactsstep in.github/workflows/test-runner.ymlis gated onif: failure(), so these always-on captures are not surfaced by green CI runs — they're for the contributor's local review.🤖 Generated with Claude Code