fix: power_off works under systemd — absolute key path + freshly-woken retry

Two OFF-path bugs found during live testing:
- bscpylgtv's key store defaulted to a CWD-relative ./.aiopylgtv.sqlite;
  under systemd (cwd=/) it couldn't open the pairing key db. Pass an
  absolute key_file_path (LGTV_KEY_FILE override, else ~/.aiopylgtv.sqlite).
- A TV woken seconds earlier answers TCP :3000 but rejects WebSocket control
  for ~20-30s. Retry power_off (2 attempts, 10s apart); common case still
  succeeds first try in ~3s. Kept under the bridge's 60s subprocess timeout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mortdecai
2026-06-01 20:16:20 -04:00
parent f310751281
commit 8f2bd2b015
+21 -2
View File
@@ -138,12 +138,23 @@ tv_off() {
exit 1 exit 1
fi fi
echo "TV at $ip — sending WebOS power_off..." echo "TV at $ip — sending WebOS power_off..."
TV_IP="$ip" python3 - <<'PY' # Retry a few times: a TV woken seconds ago answers TCP :3000 but isn't
# ready for a WebSocket control session for ~20-30s. The common case
# (TV already up) succeeds on the first try in ~3s.
local attempt
for attempt in 1 2; do
if TV_IP="$ip" python3 - <<'PY'
import asyncio, os import asyncio, os
from bscpylgtv import WebOsClient from bscpylgtv import WebOsClient
# Pass the key store path explicitly. bscpylgtv otherwise defaults to a
# CWD-relative ./.aiopylgtv.sqlite (and its $USER_HOME fallback isn't $HOME),
# so under systemd (cwd=/) it can't find the TV's pairing key. Absolute path
# = works regardless of cwd/env. Override with LGTV_KEY_FILE if needed.
KEY = os.environ.get('LGTV_KEY_FILE') or os.path.expanduser('~/.aiopylgtv.sqlite')
async def main(): async def main():
client = await WebOsClient.create(os.environ['TV_IP']) client = await WebOsClient.create(os.environ['TV_IP'], key_file_path=KEY)
await client.connect() await client.connect()
await client.power_off() await client.power_off()
await asyncio.sleep(1) await asyncio.sleep(1)
@@ -152,7 +163,15 @@ async def main():
asyncio.run(main()) asyncio.run(main())
print('power_off sent') print('power_off sent')
PY PY
then
echo "Done." echo "Done."
return 0
fi
echo " power_off attempt $attempt failed (TV may still be waking); retrying..."
sleep 10
done
echo "ERROR: power_off failed after 2 attempts"
exit 1
} }
tv_status() { tv_status() {