Skip to content

fix: wake-on-input probes real TV power state; Steam Controller can wake the TV - #15

Merged
moyoseph merged 3 commits into
mainfrom
fix/wake-power-probe
Sep 25, 2026
Merged

moyoseph merged 3 commits into
mainfrom
fix/wake-power-probe

Conversation

@moyoseph

Copy link
Copy Markdown
Owner

Problem

With the box on and the TV powered off by its remote, no input (keyboard or controller) ever powered the TV back on.

Root causes

  1. The wake gate (wake.py) was a bare TCP connect to port 3001. QuickStart+ TVs (e.g. the 2025 B4) keep that port accepting in Active Standby, so the daemon always concluded "reachable ⇒ on" and returned without waking. (In standby the TV accepts TCP but rejects the SSAP register with close 1008 "Try Again Later".)
  2. The Steam Controller path deliberately sent key: false (unblank-only), so the controller could never wake an off TV even with the gate fixed.

Fix

  • DeviceSession.probe_power_state() replaces is_reachable(): live getPowerState when the session is connected, else a short-lived throwaway client (single attempt, no WoL, 3 s budget, closed in finally). Standby register-rejection and TCP refuse/timeout both map to "Unreachable" ⇒ wakeable.
  • WakeOnInput is now a pure debouncer (cooldown + single-flight). The decision moved to Daemon._wake_if_tv_off: probe all non-busy sessions concurrently, wake only those not Active — per-session, so a TV showing another input/app is never touched (a blanket power-on would have run set_hdmi_input on Active TVs in multi-TV setups).
  • KeyRejected never wakes — waking would loop on the rejected key, and each register attempt pops an on-screen pairing prompt. It logs a re-pair with lgtvc setup pair hint instead.
  • New steam_controller.wake (default on): controller input is reported as a key press so it can power on a fully-off TV. Caveat documented: the hidraw detector can't tell buttons from stick movement, so any genuine controller input wakes an off TV. Opt out via lgtvc setup steam-controller --wake off or the tray checkbox.

Notes

Tests

Daemon: Active → no wake; Active Standby → wakes (the QuickStart+ regression); Screen Off → wakes; KeyRejected → no wake; per-session (tv1 Active untouched, tv2 unreachable woken); busy skip; failure logged. DeviceSession vs FakeTv: connected live-state; connected error → closed + Unreachable; disconnected standby; close-on-register (the 1008 signature) → Unreachable; dead port; stale key → KeyRejected; throwaway never leaves the session connected. Agent: wake on/off → key true/false. CLI --wake + tray checkbox. 526 passed, ruff + mypy clean.

🤖 Generated with Claude Code

Mohamed Yosef and others added 3 commits September 25, 2026 14:04
raise of an unnarrowed Future.exception() and a list/set variable
redefinition — both pre-existing on main, tripped by the newer mypy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 4228129)
…e TV

The wake gate was a bare TCP probe of the API port. QuickStart+ TVs
(e.g. 2025 OLEDs) keep port 3001 accepting in Active Standby, so after a
remote power-off the daemon read 'reachable => on' and never woke the TV.

- DeviceSession.probe_power_state() replaces is_reachable(): a live
  getPowerState on the existing session, or a short-lived throwaway
  client (single attempt, no WoL, 3s budget, always closed). The standby
  register rejection (close 1008, normalized to ConnectionError) and TCP
  refuse/timeout both read as Unreachable => wakeable.
- WakeOnInput is now a pure debouncer (cooldown + single-flight); the
  decision lives in Daemon._wake_if_tv_off: probe all non-busy sessions
  concurrently, power on only those not Active — per-session, so a TV
  showing another input/app is never touched, even in multi-TV setups.
- KeyRejected never wakes (a WoL+connect would loop on the rejected key
  and every register pops an on-screen pairing prompt); it logs a
  re-pair hint instead.
- New steam_controller.wake (default ON): controller input is reported
  as a key press so it may power on a fully-off TV. lgtvc setup
  steam-controller --wake on|off + tray checkbox; wake=off restores the
  old unblank-only behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	CHANGELOG.md
@moyoseph
moyoseph merged commit f6c6c3e into main Sep 25, 2026
6 checks passed
@moyoseph
moyoseph deleted the fix/wake-power-probe branch September 25, 2026 11:44
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