Skip to main content

LG Horizon API Python Library

A Python library to interact with and control LG Horizon set-top boxes (Ziggo, Telenet, Virgin Media, UPC, BASE TV). Provides authentication, real-time device monitoring via MQTT, and remote control capabilities.

Supported Providers

Code Provider Country
nl Ziggo Netherlands
be-nl Telenet Belgium
be-basetv BASE TV Belgium
ch UPC Switzerland Switzerland
gb Virgin Media United Kingdom
ie Virgin Media Ireland
pl UPC Poland

Features

Authentication

  • Username/password and refresh token authentication
  • Automatic access token refreshing
  • Token refresh callback for persisting new tokens
  • Support for provider-specific auth flows

Device Management

  • Discover all set-top boxes on your account
  • Device info: manufacturer, model, platform type
  • Real-time availability monitoring (online/standby/offline)

Real-time Status via MQTT

  • Live device state changes via callback
  • Playback info: channel, show title, episode, season/episode numbers
  • Source types: linear TV, replay, VOD, nDVR, localDVR, review buffer, apps
  • Media types: channel, movie, episode, app
  • Playback position, duration, speed, paused state
  • Channel and program images
  • Automatic MQTT reconnection with exponential backoff

Channel Information

  • Full channel list with logos and stream images
  • Channel number, radio flag, linear products
  • Replay pre/post padding info
  • Profile-specific favorite channels

Recording Management

  • List all recordings (single, season, show)
  • Recording states: recorded, ongoing
  • Episode details for season/show recordings
  • Recording quota and usage percentage
  • Play recordings on a set-top box

Device Control

  • Power on/off
  • Play, pause, stop
  • Rewind, fast forward
  • Channel up/down and direct channel selection
  • Record current program
  • Set player position (seek)
  • Send any remote control key press
  • Display custom messages on the TV screen

Installation

pip install lghorizon

Requirements: Python 3.10+, aiohttp, paho-mqtt, backoff

Quick Start

Create a secrets.json file:

{
  "username": "your_username",
  "password": "your_password",
  "country": "nl",
  "timezone": "Europe/Amsterdam"
}

For providers with refresh token auth (Telenet, UPC CH, Virgin Media GB), use "refresh_token" instead of username/password.

Basic usage

import asyncio
import aiohttp
from lghorizon import LGHorizonApi, LGHorizonAuth

async def main():
    async with aiohttp.ClientSession() as session:
        auth = LGHorizonAuth(session, "nl", username="user", password="pass")
        api = LGHorizonApi(auth, profile_id=None)

        try:
            await api.initialize()
            devices = await api.get_devices()

            # Print all devices
            for device in devices.values():
                print(f"{device.device_friendly_name} ({device.manufacturer} {device.model})")
                print(f"  State: {device.device_state.state.value}")
                print(f"  Available: {device.is_available}")

            # Get channels
            channels = await api.get_profile_channels()
            for ch in channels.values():
                print(f"  {ch.channel_number} - {ch.title}")

            # Monitor state changes
            async def on_state_change(device_id: str):
                device = devices[device_id]
                s = device.device_state
                print(f"{device.device_friendly_name}: {s.channel_name} - {s.show_title}")
                print(f"  Source: {s.source_type.value}, Position: {s.position}/{s.duration}")

            for device in devices.values():
                await device.set_callback(on_state_change)

            # Keep running to receive MQTT updates
            await asyncio.Event().wait()

        finally:
            await api.disconnect()

asyncio.run(main())

Device control

device = devices["device-id"]

# Power
await device.turn_on()
await device.turn_off()

# Playback
await device.play()
await device.pause()
await device.stop()
await device.rewind()
await device.fast_forward()

# Channels
await device.next_channel()
await device.previous_channel()
await device.set_channel("NPO 1")

# Recording
await device.record()
await device.play_recording("recording-id")

# Position (milliseconds)
await device.set_player_position(60000)

# Display message on screen
await device.display_message("linear", "Hello from Python!")

Recordings & quota

if api.has_cloud_recording:
    # Quota
    quota = await api.get_recording_quota()
    print(f"Used: {quota.occupied}/{quota.quota} MB ({quota.percentage_used:.1f}%)")

    # All recordings
    recordings = await api.get_all_recordings()
    for rec in recordings.recordings:
        print(f"[{rec.type.value}] {rec.title} ({rec.recording_state.value})")

    # Episodes of a show recording
    episodes = await api.get_show_recording_episodes("show-recording-id")
    for ep in episodes.recordings:
        print(f"  S{ep.season_number}E{ep.episode_number}: {ep.episode_title}")

Token refresh callback

async def on_token_refresh(new_token: str):
    # Persist the new refresh token for next session
    save_to_storage(new_token)

await api.set_token_refresh_callback(on_token_refresh)

Device State Properties

When monitoring a device, device.device_state exposes:

Property Type Description
state LGHorizonRunningState ONLINE_RUNNING, ONLINE_STANDBY, OFFLINE, etc.
ui_state_type LGHorizonUIStateType MAINUI, APPS, UNKNOWN
source_type LGHorizonSourceType LINEAR, VOD, NDVR, LOCALDVR, REPLAY, REVIEWBUFFER
media_type LGHorizonMediaType CHANNEL, MOVIE, EPISODE, APP
channel_id str | None Current channel ID
channel_name str | None Current channel name
show_title str | None Current show/movie/app title
episode_title str | None Current episode title
season_number int | None Season number
episode_number int | None Episode number
position int | None Playback position in seconds
duration int | None Content duration in seconds
start_time int | None Program start (Unix timestamp)
end_time int | None Program end (Unix timestamp)
speed int | None Playback speed (0 = paused, 1 = normal)
paused bool Whether playback is paused
image str | None Content/channel image URL
app_name str | None Active app name (when source is APPS)

Error Handling

from lghorizon import (
    LGHorizonApiError,              # Base exception
    LGHorizonApiConnectionError,    # Network/connection issues
    LGHorizonApiUnauthorizedError,  # Invalid credentials
    LGHorizonApiLockedError,        # Account locked
)

try:
    await api.initialize()
except LGHorizonApiLockedError:
    print("Account is locked, try again later")
except LGHorizonApiUnauthorizedError:
    print("Invalid credentials")
except LGHorizonApiConnectionError:
    print("Could not connect to the API")
except LGHorizonApiError as e:
    print(f"API error: {e}")

Development

Setup

git clone https://github.com/Sholofly/lghorizon-python.git
cd lghorizon-python
pip install -e .
pip install pytest pytest-asyncio

Running tests

python -m pytest tests/ -v

Running the demo script

  1. Create a secrets.json (see Quick Start)
  2. Run python main.py

The demo script prints all profiles, devices, channels, recordings, and then monitors live state changes with a visual progress bar. It also provides an interactive command prompt to control your set-top boxes (send messages, switch channels, etc.). Type help for a list of available commands.

Web-based Test UI

A browser-based interface for testing all library features interactively:

python web.py

Then open http://localhost:8080 in your browser.

Features:

  • Login with your provider credentials (username/password or refresh token, depending on provider)
  • Live dashboard showing all set-top boxes with real-time state updates via WebSocket
  • Full device control: power, playback, channel switching, message display, raw key input
  • Event log with timestamped state changes
  • Optional "Remember credentials" to save your provider and username between sessions (passwords are never stored)

Note: No additional dependencies are required — web.py uses the same aiohttp that the library already depends on.

License

MIT License

Release files for lghorizon 0.12.2

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

Source distribution (sdist)

Source distribution for lghorizon 0.12.2
File Size Uploaded
lghorizon-0.12.2.tar.gz 87.0 kB Details

Built distribution (wheel)

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

Total release size: 124.1 kB

Release files / lghorizon-0.12.2.tar.gz

Download URL lghorizon-0.12.2.tar.gz
Size 87.0 kB
Tags Source
SHA-256 checksum
How to use checksums
6675cc5338b7a8383f5e77551896e6c623e5d078cc69bb013b006990caa04464
BLAKE2b-256 checksum
How to use checksums
470e863082b84bfd830bdc2175787b051acb08c4132af593d1029bccd1576f10
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 26, 2026.

Transparency log

Release files / lghorizon-0.12.2-py3-none-any.whl

Download URL lghorizon-0.12.2-py3-none-any.whl
Size 37.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
edc973897d96e22d34dd3b65aa1899c6ad9445d206b688db928b10eb2fd19876
BLAKE2b-256 checksum
How to use checksums
e16cf142a2e5d8d60339e987c7278df520b7cc582f81683fe356dd03e0af5017
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.12.2 This release

2 release files

0.11.3

2 release files

0.11.2

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.7

2 release files

0.10.6

2 release files

0.10.5

2 release files

0.10.4

2 release files

0.10.3

2 release files

0.10.2

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.9.12

2 release files

0.9.9

2 release files

0.9.8

2 release files

0.9.7

2 release files

0.9.6

2 release files

0.9.5

2 release files

0.9.4

2 release files

0.9.3

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.7.5

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.13

2 release files

0.6.12

2 release files

0.6.11

2 release files

0.6.10

2 release files

0.6.9

2 release files

0.6.8

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.14

2 release files

0.5.13

2 release files

0.5.12

2 release files

0.5.11

2 release files

0.5.10

2 release files

0.5.9

2 release files

0.5.8

2 release files

0.5.7

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.0

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

1 release file

0.4.4

1 release file

0.4.3

1 release file

0.4.2

1 release file

0.4.0

1 release file

0.3.0

1 release file

0.2.1

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1

1 release file

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