Skip to content

kiosk: no panel, no browser; start on hotplug, stop on unplug - #60

Merged
ThinkOffApp merged 1 commit into
mainfrom
fix/kiosk-needs-a-panel
Sep 15, 2026
Merged

ThinkOffApp merged 1 commit into
mainfrom
fix/kiosk-needs-a-panel

Conversation

@ThinkOffApp

Copy link
Copy Markdown
Owner

petrus, 15 Sep 2026: the VTA's display had moved to the Pi and the kiosk kept drawing the dash for nobody: chrome + cage held one full core at 80 C for four hours. Pause test: 46 C with the kiosk stopped, 76 C ninety seconds after restarting it; every DRM connector reads disconnected.

  • carwatch-kiosk.sh: checks /sys/class/drm/card*-*/status before starting and exits 78 when nothing is connected; while the browser runs it re-checks every 5 s (CARWATCH_PANEL_POLL) and stops the browser when the panel goes away.
  • carwatch-kiosk.service: RestartPreventExitStatus=78 + SuccessExitStatus=78, so a no-panel exit stays down instead of a 3 s restart loop.
  • 90-carwatch-kiosk.rules (udev, both installers substitute the kiosk user): a DRM hotplug event wants the service, so plugging a panel in starts it without anyone enabling anything.
  • Tests (tests/test_kiosk_launcher.py, fake DRM tree): no panel -> exit 78 and no browser; panel unplugged mid-run -> browser stopped, exit 78; the three existing cases updated to declare a connected panel. 5/5 pass locally.

Deploy note for the VTA: the kiosk service there is currently disabled by hand (17:47Z); after merge, re-run scripts/kiosk/install-kiosk-ubuntu.sh once, which installs the rule and enables the unit, and it stays down until a panel appears.

Review before merge welcome, @codexmb.

🤖 Generated with Claude Code

petrus, 15 Sep 2026: the VTA's display had moved to the Pi and the kiosk
kept drawing the dash for nobody: chrome + cage one full core, 80 C, fans,
for four hours, measured by a pause test (46 C with the kiosk stopped,
76 C ninety seconds after restarting it; every DRM connector 'disconnected').

- carwatch-kiosk.sh checks /sys/class/drm/card*-*/status before starting
  and exits 78 when nothing is connected; while the browser runs it polls
  the panel every 5 s and stops the browser when it goes away.
- carwatch-kiosk.service: RestartPreventExitStatus=78 / SuccessExitStatus=78,
  so a no-panel exit stays down instead of a 3 s restart loop.
- 90-carwatch-kiosk.rules (udev, installed with the kiosk user substituted):
  a DRM hotplug event wants the service, so plugging the panel in starts it.
- tests: fake DRM tree; no panel -> exit 78 and no browser; panel unplugged
  while running -> browser stopped, exit 78. Poll default 5 s (1 s in tests).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
carwatch-dev Ready Ready Preview Sep 15, 2026 5:51pm UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-15T17:54:49.916061Z d6b1d6f Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d6b1d6fa3a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1,3 @@
# Start the CarWatch kiosk when a display is plugged in (DRM hotplug event).
# Installed by install-kiosk*.sh with the kiosk user substituted for KUSER.
SUBSYSTEM=="drm", ACTION=="change", ENV{HOTPLUG}=="1", TAG+="systemd", ENV{SYSTEMD_WANTS}+="carwatch-kiosk@KUSER.service"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Trigger the kiosk on every panel reconnection

After the kiosk exits on an unplug, the DRM device remains active and tagged, so reconnecting the same persistent connector produces another change event but no new device activation. The systemd.device(5) documentation states that SYSTEMD_WANTS dependencies are acted upon only when a device first becomes active; consequently, later reconnects will leave the kiosk stopped indefinitely. Toggle SYSTEMD_READY with the connection state or use a mechanism that explicitly starts the service on each connected hotplug.

Useful? React with 👍 / 👎.

@ThinkOffApp
ThinkOffApp merged commit 92178bb into main Sep 15, 2026
3 checks passed
ThinkOffApp added a commit that referenced this pull request Sep 15, 2026
…al logging

codexmb, #60 review: SYSTEMD_WANTS on a device unit fires once when the
device becomes active; card0 stays active across unplug/replug, so the
kiosk would not restart on the next plug. Now a udev RUN calls
carwatch-kiosk-hotplug.sh, which reset-fails and starts the unit
(--no-block).

Measured on the VTA while getting there: a rule keyed on any DRM change
event restarts the kiosk from its own start, because the VT switch of the
start emits a change event too: 517 starts in a minute. ENV{HOTPLUG}=="1"
is what separates a real plug (kernel drm_sysfs_hotplug_event) from that;
with it, three synthetic triggers plus a manual start produced exactly one
start. The unit's start-rate limit is raised (a plug can be a burst) so a
burst cannot leave the unit 'failed'. The launcher's no-panel and unplug
messages now also go to the journal via logger, since stderr under a
TTY-bound unit does not.

Verified: 5/5 launcher tests; on the VTA: launcher exit 78 with no panel,
rule listed by udevadm test, no feedback with the HOTPLUG guard. Not yet
verified: a real plug event (needs the panel on the VTA).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ThinkOffApp added a commit that referenced this pull request Sep 15, 2026
…le; comments corrected

codexmb, #59 review: Promise.race abandoned a still-running fn, so the test's
never-settling first call was alive when the second started and proved
nothing about overlap. Now each run gets an AbortController; poll, pollSteer
and pollVoice pass its signal into F (which links an outer signal to its own
abort timer); at CW_DEADLINE the signal is aborted and the run is awaited
until it settles, bounded by CW_SETTLE_GRACE for a fn that ignores its signal.
The test's stalled fn honours the signal like a real fetch and the harness
asserts the order call1, settle1, call2 and settled == 1; the previous
scheduler fails it (settled 0, overlapping calls).

Comments corrected: the timers were request waste, not the VTA's 80 C (that
was the kiosk drawing to no panel, #60); a hidden tab keeps the loop ticking
and skips the fetch, it does not stop polling outright.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant