Skip to main content

lgtv-companion-linux

CI Tests Coverage PyPI Python License: MIT SLSA 3 Ruff Buy Me a Coffee

Make your LG (webOS) TV turn on and off with your PC. When the computer boots the TV wakes up; when it sleeps or shuts down the TV powers off. It also blanks the TV when you're idle, switches HDMI inputs, wakes the TV over the network, and gives you a full command-line remote for everything else (picture, sound, inputs, buttons).

Built for Bazzite and other immutable/atomic distros — it never writes to /usr — but works on any Linux desktop. It's a Linux port of the excellent LGTV Companion for Windows by Jörgen Persson.

What it does

  • 🔌 TV follows your PC — on at boot, off at shutdown/suspend, back on at resume. A reboot leaves the TV on; a real shutdown turns it off.
  • 🛡️ Won't interrupt you — before powering the TV off it checks the active input. If you're watching another HDMI device (console, receiver) or a TV app, it leaves the TV alone.
  • 😴 Idle blanking — blanks (or powers off) the TV after you step away and wakes on mouse/keyboard/controller input. Won't blank while a video is playing full-screen.
  • 📺 HDMI switching — jump to your PC's input automatically on power-on.
  • ⚡ Wake-on-LAN — wake a TV that's fully off.
  • 🎮 Streaming-aware — turns the local TV off while you stream the desktop with Sunshine/Apollo (and Parsec, Moonlight, Chrome Remote Desktop, …).
  • 🏠 Home Assistant — optional MQTT bridge with auto-discovery.
  • 🕹️ Full CLI remote — picture, sound, inputs, luna settings, and 78 remote buttons, straight from the terminal or a script.
  • ✅ Works with the latest webOS — including the 2025 firmware pairing change (issue #351) that stops many older remote tools from connecting.

Install on Bazzite

The recommended setup for a couch/HTPC is system mode, so the TV comes on at boot before you even log in. Paste this into a terminal:

# 1. Install into a self-contained venv (nothing touches the system /usr)
sudo python3 -m venv /usr/local/lib/lgtv-companion
sudo /usr/local/lib/lgtv-companion/bin/pip install lgtvcompanion
sudo ln -s /usr/local/lib/lgtv-companion/bin/lgtvc{,-daemon,-agent} /usr/local/bin/

# 2. Generate the systemd services (they act on the TV as your user)
sudo lgtvc setup install --mode system --service-user $USER

# 3. Pair — approve the prompt that appears on the TV screen
sudo lgtvc setup pair --host <tv-ip>

# 4. Start everything
sudo systemctl enable --now lgtvc-daemon lgtvc-shutdown
systemctl --user enable --now lgtvc-agent

That's it — reboot and the TV should come on with the PC.

On a regular distro? Grab a package

Prefer your package manager? Every release ships .deb / .rpm / Arch packages (units included, only needs python3 ≥ 3.11):

sudo apt install ./lgtvcompanion_*_all.deb        # Debian/Ubuntu
sudo dnf install ./lgtvcompanion-*.noarch.rpm     # Fedora/RHEL
sudo pacman -U ./lgtvcompanion-*-any.pkg.tar.zst  # Arch

then pair + enable as in steps 3–4. The MQTT bridge is bundled; the tray GUI is too, but its Qt library (PySide6) is handled differently per distro:

  • Fedora / Arch — PySide6 is pulled automatically; the tray just works.
  • Ubuntu / Debian — these don't package PySide6, so add it once for the tray (everything else works without it):
    sudo python3 -m pip install --target /opt/lgtv-companion/lib PySide6
    
  • GNOME (any distro) removed the legacy tray — install + enable a tray extension for the icon to appear, e.g.:
    sudo dnf install gnome-shell-extension-appindicator          # Fedora
    sudo apt install gnome-shell-extension-appindicator          # Ubuntu/Debian
    # then enable "AppIndicator and KStatusNotifierItem Support" in Extensions
    

Full details: packaging/README.md. (On immutable distros like Bazzite, use the venv install above — nothing touches /usr.)

  • Want the tray icon + settings window or Home Assistant? Install lgtvcompanion[tray] or lgtvcompanion[mqtt] instead (line 2 above).
  • Prefer a no-root, user-only install, or pipx/uv? See the install guide.
  • Coming from Windows? lgtvc setup import-windows --file config.json brings your settings and pairing keys over — no re-pairing.

Everyday commands

lgtvc -poweron                        # turn on every TV
lgtvc -poweroff LivingRoom            # …one, by name
lgtvc -sethdmi 2                      # switch input
lgtvc -backlight 80 -mute             # several commands at once
lgtvc -picturemode filmMaker          # picture / sound / energy settings
lgtvc -button INFO                    # press a remote button
lgtvc status                          # what the daemon and TVs are doing

Same syntax as the Windows LGTVcli: commands are case-insensitive, you can chain several per line, and trailing words pick devices (none = all). Add --direct --host <tv-ip> to talk to a TV without the daemon.

How it compares to the Windows app

Full power sync, Wake-on-LAN, HDMI control, idle blanking with fullscreen/video vetoes, the complete settings CLI, and multi-TV support are all here. A few things are better on Linux (reboot-vs-shutdown is detected deterministically via systemd, not by matching localized text) and a few are extra (a first-party MQTT/Home Assistant bridge, version-update notifications). Windows-only bits like the MSI auto-updater and RDP detection don't apply.

See the full parity matrix for the item-by-item breakdown.

Under the hood (the moving parts)
Component Runs as Job
lgtvc-daemon system service Owns the TV websocket sessions and pairing keys; boot power-on, Wake-on-LAN, wake-on-input, idle blanking + vetoes, streaming/lock reactions, HDMI topology, and the IPC socket the CLI talks to.
lgtvc-agent user service The session-side "eyes" the confined system daemon can't have: input activity, media playback, fullscreen, screen-lock and streaming-process detection.
lgtvc CLI The full webOS command surface; also status / reload / events.
lgtvc-tray user service (optional) PySide6 tray + settings window ([tray] extra).
lgtvc-mqtt system service (optional) MQTT / Home Assistant bridge ([mqtt] extra).

Suspend/resume and shutdown are driven by short-lived lgtvc-sleep / lgtvc-shutdown systemd units rather than the daemon, which is how the reboot-vs-shutdown distinction stays reliable. On ostree/immutable systems the venv lives in /usr/local (/var/usrlocal), units in /etc/systemd/system, config in /etc/lgtv-companion/config.json, and pairing keys in /var/lib/lgtv-companion/keys/.

Documentation

Verifying a release (SLSA Level 3)

Every release is built by GitHub Actions and carries SLSA Build Level 3 provenance — non-forgeable, Sigstore-signed proof of exactly which workflow and commit produced each artifact, generated in an isolated slsa-github-generator workflow (the same trust boundary the upstream Windows app uses).

Grab the artifact you downloaded plus multiple.intoto.jsonl from the release, then verify with slsa-verifier (≥ v2.7.1):

slsa-verifier verify-artifact \
  --provenance-path multiple.intoto.jsonl \
  --source-uri github.com/moyoseph/lgtv-companion-linux \
  --source-tag "v0.2.3" \
  lgtvcompanion-0.2.3-py3-none-any.whl        # or the .tar.gz / .deb / .rpm / .pkg.tar.zst

A PASSED: SLSA verification passed line means the file is authentic and untampered. (PyPI installs are separately covered by PEP 740 attestations — pip verifies those automatically.)

Offline / privacy mode

Controlling the TV never needs the internet — the whole link (SSAP over wss://<tv-ip>:3001 + Wake-on-LAN) is LAN-only by design. The only things this app can send outward are the optional daily update check (GitHub) and the MQTT bridge if you point it at a cloud broker.

offline_mode is a master switch that guarantees the app makes zero internet connections: it disables the update check and refuses a non-LAN MQTT broker (a LAN Home Assistant broker still works).

lgtvc setup offline-mode on      # or: off  (no arg prints the current state)
systemctl --user restart lgtvc-agent   # takes effect on restart

Or tick "Offline mode (no internet)" in the tray's Settings dialog.

Honest caveats: this locks down this app, not your TV — LG webOS sets phone home on their own; block that at the router if you care. And the TLS to the TV intentionally skips certificate verification (TVs use self-signed certs; the threat model is your LAN).

Support

This is a free, open-source project maintained in my spare time. If it saved you some fiddling and you'd like to say thanks, you can buy me a coffee ☕ — entirely optional and always appreciated.

Buy Me A Coffee

License

MIT. Portions of the design and the command/button tables are derived from LGTV Companion, © Jörgen Persson, MIT.

Release files for lgtvcompanion 0.2.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lgtvcompanion 0.2.7
File Size Uploaded
lgtvcompanion-0.2.7.tar.gz 165.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lgtvcompanion 0.2.7
File Interpreter ABI Platform
lgtvcompanion-0.2.7-py3-none-any.whl Python 3 none any Details

Total release size: 264.3 kB

Release files / lgtvcompanion-0.2.7.tar.gz

Download URL lgtvcompanion-0.2.7.tar.gz
Size 165.6 kB
Tags Source
SHA-256 checksum
How to use checksums
04e09bd07c9b09d1a03640c4da6a254c4973797bde993bc998173cda9f8a8346
BLAKE2b-256 checksum
How to use checksums
b4c22627b0e6cabfa32558d7bc890c278b9b9eb12954bde4f0ac3b3ef4651597
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / lgtvcompanion-0.2.7-py3-none-any.whl

Download URL lgtvcompanion-0.2.7-py3-none-any.whl
Size 98.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
92f9ca2fe75b55b1f8fc0173598fd77be9797a88e3138ad328aa839d40d255ac
BLAKE2b-256 checksum
How to use checksums
a2c5c907483a31d8bc5642d10c72e19b3ba863324a88d04e835324989d5a8166
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.7 This release

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page