Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4.5 KiB
LG TV Bridge — Decisions
Format: YYYY-MM-DD: <decision> — <why>
-
2026-06-01: Single bridge, single host — runs on steel141, pve173 retired. The bridge had been running on pve173 (always-on node) since 2026-03-23, SSHing to steel141 for every TV op. Consolidated everything onto steel141. Why: the WebOS pairing key (
/home/seth/.aiopylgtv.sqlite) lives only on steel141, sopower_offalways routes through it regardless of bridge host — pve173 added an SSH hop and a second host for no real availability gain (the TV is uncontrollable whenever steel141 is down anyway). One host, no SSH hop. -
2026-06-01: Cached-IP discovery, sweep only on miss. Persist last-known TV IP in
~/.cache/lgtv/last_ip; probe it directly (TCP :3000/:3001). Full /24 ping-sweep runs only on a cache miss, then re-caches. Why: the old code ping-swept all 254 hosts over SSH on every 30s HA state poll — slow, network spam, and racy (stale ARP) → the chronic "flaky state in HA" symptom. -
2026-06-01: Robust WoL — unicast + broadcast, ports 9/7, 3 bursts. Why: old code sent broadcast-only on ports 9/1235 once. Unreliable wakes. NOTE: the remaining wake failures are TV-side (Quick Start+ / Mobile TV On must be ON; wired Ethernet far more reliable than Wi-Fi for LG WoL) — not fixable in code.
-
2026-06-01: Deps via
pip --user --break-system-packagesforseth. paho- bscpylgtv live in
/home/seth/.local(PEP 668 box). Matches how bscpylgtv was already installed; the systemd unit runsUser=seth.
- bscpylgtv live in
-
2026-06-01: power_off must pass an absolute
key_file_path. bscpylgtv'sStorageSqliteDictdefaults the key DB toos.getcwd()/.aiopylgtv.sqlite(its$USER_HOMEfallback is not$HOME). The old pve173 setup worked only because it SSHed in as seth, landing CWD in/home/seth. Under systemd (cwd=/) it threwsqlite3.OperationalError: unable to open database file. Fix:WebOsClient.create(ip, key_file_path="~/.aiopylgtv.sqlite"). -
2026-06-01: power_off retries (2×, 10s apart). A TV woken seconds earlier answers TCP :3000 but refuses a WebSocket control session for ~20-30s, so an immediate OFF-after-ON can fail. Retry covers it; normal case (TV already up) succeeds first try in ~3s. Bounded under the bridge's 60s subprocess timeout.
-
2026-06-06: Google Home via the free manual
google_assistantintegration (not Nabu Casa). Exposed onlyswitch.big_tv_lg_tv. Linked end-to-end and verified. Three non-obvious requirements that were each a separate failure mode: account-linking Scopes must includeemail+name(blank → no login page); the "HTTP basic auth header" checkbox must be OFF (HA OAuth is secretless → checked =/auth/token401); and the Google Test must be activated by the same account used in the Home app (slingshooter08). The GCP OAuth consent screen is not part of smart-home linking — don't touch it (shared project runs WP Mail SMTP). Full detail + security-cleanup list in.claude/handoffs/2026-06-06-*.md. -
2026-10-22: HA VM 706 pinned to 192.168.0.146 twice over — Omada DHCP reservation (MAC BC:24:11:3F:DC:7B) AND HAOS static IPv4 (
ha network update enp0s18 --ipv4-method static) — HA had silently lost its IPv4 lease (~Aug 2026; IPv6-only, uptime 57d), cutting it off from MQTT/Caddy/Google: the "TV hasn't worked in months" outage. Static removes the DHCP dependency; reservation keeps the router from handing .146 to anyone else. -
2026-10-23: TV DHCP-reserved at 192.168.0.20 (Omada) — bscpylgtv keys pairings by IP, so every DHCP drift (7 IPs so far) re-triggered the on-TV auth prompt, and a missed prompt hung
offpast the 60s timeout. New IP seeded with the newest stored key (.31) so no re-prompt. Also: on_message now catches all exceptions — one escaping killed paho's thread while the poll loop kept the process alive (silent zombie).
Deferred / Rejected
- DHCP reservation for the TV (static IP): not done — Pi-hole doesn't run DHCP (router does), so it's Seth's action on the router. The cached-IP probe makes it unnecessary for correctness; a reservation would just let us drop the sweep-fallback entirely. Add if convenient.
- Unique per-instance MQTT client_id: rejected — keeping a fixed
lgtv-bridgeid means a duplicate instance is loud (reconnect war in broker logs) rather than silent. Single-instance discipline is the real guard. (A duplicate on 2026-06-01 during this very migration is what surfaced all this.)