led-ticker-tennis
Live tennis scores — ATP, WTA, Challenger, ITF and juniors — for led-ticker. One tennis.scores widget cycles through every match in play (two players, sets, games, the point in progress, who is serving, break points) and falls back to the upcoming fixtures when nothing is on court.
Disclosure: this plugin is maintained by the vendor of its data source, the Live Tennis API. It uses the API's free tier (no card; 100 requests/day), and the plugin enforces a poll cadence that stays inside that quota.
Prerequisites
- A working led-ticker install (
led-ticker-core >= 4.16). - A Live Tennis API key — free at https://livetennisapi.com/subscribe/free. Put it in the environment as
LIVETENNIS_API_KEY(recommended) or in the widget config asapi_key. - Internet access on the Pi.
Without a key the widget does not crash or fetch anything: it shows Tennis: set LIVETENNIS_API_KEY (free key: …) on the panel until one is configured.
Install
This plugin auto-registers via the led_ticker.plugins entry point — once the package is installed, no [plugins] config change is needed.
Into a containerized led-ticker (recommended): add the package to your config/requirements-plugins.txt, pass the key through, and rebuild:
led-ticker-tennis
# compose override — hand the key to the container
services:
led-ticker:
environment:
LIVETENNIS_API_KEY: "ltapi_..."
docker compose up -d --build
Standalone (a venv that already has led-ticker):
pip install led-ticker-tennis
export LIVETENNIS_API_KEY=ltapi_...
Once installed, the tennis.scores widget is available automatically.
Widget: tennis.scores
Add a [[playlist.section.widget]] block inside a playlist section of your config/config.toml:
[[playlist.section.widget]]
type = "tennis.scores"
tours = ["atp", "wta"] # optional — omit for every tour
timezone = "America/New_York" # for fixture start times
No field is required (the key comes from LIVETENNIS_API_KEY). Everything below is optional tuning.
| Option | Type | Default | Description |
|---|---|---|---|
api_key |
string | "" |
Live Tennis API key. The environment variable LIVETENNIS_API_KEY takes precedence. Keep credentials out of config.toml. |
tours |
list of strings | [] (all) |
Any of "atp", "wta", "challenger", "itf", "juniors". Filtered client-side, so it never costs extra requests. |
draw |
string | "all" |
"all", "singles" or "doubles". Doubles teams show as CASH/GLASSPOOL. |
max_matches |
int | 8 |
Cap on matches per rotation (main tours first, then earliest start). |
layout |
string | "auto" |
"auto", "ticker" or "scoreboard" — see below. |
show_ranking |
bool | false |
Append the official singles ranking after each name on the ticker layouts, e.g. LEHECKA (21). |
timezone |
string | "America/New_York" |
IANA timezone for fixture start times (Today 3:00 PM). |
update_interval |
int | 900 |
Seconds between API polls. Floored at 900 (15 min) whatever you set — see Free-tier cadence. |
padding |
int | 6 |
Horizontal padding (logical px) after each story when scrolling. |
demo |
bool | false |
Render four fixture matches (break point, tiebreak, retirement, upcoming) with no key and no network — for docs and hardware checks. |
bg_color |
RGB list | none | Background fill. Scale-1 only — the scale>1 physical renderers paint their own palette. |
font_color |
RGB list / string / table | unset | Override all text color. Scale-1 only. |
font |
string | "6x12" |
Font for the scale-1 ticker line. |
small_font |
string | "5x8" |
Font for the scale-1 two-band scoreboard. |
Layouts
layout = "auto"(default) —tickeron a scale-1 sign (smallsign),scoreboardon scale>1 signs (bigsign, longboi).layout = "ticker"— one scrolling line per match in tennis notation, the serving player marked with*:LEHECKA* v FILS 4-6 3-4 (15-40) BP · SET 2 · R16 CINCINNATI OPEN. Finished:PAUL v VALLEJO 6-2 3-1 · RET · R32 …(winner green). Upcoming:ALCARAZ v SINNER · Tmrw 3:00 PM · QF …. Scale-1 renders it as a BDFSegmentMessage; scale>1 as a hi-res Inter crawl with the same words.layout = "scoreboard"— a held two-row board, player 1 over player 2:- a yellow serve dot left of the server's name;
- longboi (512 px): one column per set with that set's games, then the current-game points (
15/40/AD; tiebreak points as plain numbers); - bigsign (256 px): the compact form — sets won, current-set games, points;
- a red
BPbadge on the receiver's row at break point (never during a tiebreak); - a right-hand status column:
SET 2/SUSP(green) orFINAL/RET/W/O/DEF/ABD/CANC, then the round (orTBduring a tiebreak), then the tournament. Upcoming matches showToday/3:00 PMinstead. - On a scale-1 sign the same content renders as two 8-row BDF bands (
LEHECKA* 4 3 15 S2overFILS 6 4 40 BP R16).
Names are surnames (upper-case), shrink-to-fit on the physical board and truncated only when even the smallest size collides; both rows always share one name size. Nothing on the board is user-tunable (fixed Inter text and palette, like the other physical renderers in this repo).
How tennis is modelled (for the non-tennis reader)
A match is best-of-3 (or 5) sets; a set is first to 6 games (by two, or a tiebreak at 6-6); a game is scored in points 0 → 15 → 30 → 40 → game, with AD (advantage) after deuce (40-40). One player serves an entire game and is expected to win it, so a break point — the receiver one point from winning the server's game — is the moment that matters: receiver at AD, or receiver at 40 while the server is at 0, 15 or 30. Tiebreak points are counted 1, 2, 3… and have no break points. Matches end normally (FINAL), or early by retirement (RET), walkover (W/O), default (DEF) or abandonment; SUSP is a live match paused for rain/darkness.
Free-tier cadence
The free tier allows 100 requests per day. All tennis widgets in one process share a source for each API key. Every request waits at least 900 seconds after the previous request. This allows at most 96 requests per day during continuous operation. The smallest configured interval wins, with a 900-second floor. Listings and result lookups use the same request slots. There is no extra startup request. An empty live listing sends the next poll to the upcoming listing.
When a displayed match disappears, its last score and state stay visible with a STALE label beside them.
The source queues a free GET /matches/{matchId} lookup, alternating result lookups with live polls.
A completed response supplies the final score, outcome and winner. Finished matches stay in the rotation for two intervals, after any live matches. When max_matches is smaller than the live count, finished matches are left out.
A match that was looked up is not looked up again for four intervals, even if it briefly reappears. A 404 or 410 lookup keeps the last score as stale. It does not mark other matches stale or lengthen the backoff. A match that still reports live is never labelled final. Network failures retry after backoff. No winner is guessed from an unfinished score.
The shared cache is local to one process. Separate processes and restarts do not share its request budget. For three signs sharing a key, set every sign's interval to at least 2700 seconds. That totals 96 requests per day during continuous operation. Other clients share the same quota. Frequent restarts add requests, so leave headroom in the interval.
A failed request keeps the cached score and marks it STALE on the panel.
Backoff doubles from twice the interval, up to four hours. Authentication failures wait at least an hour, or longer when the interval requires it.
At the default interval, result lookups can extend the live listing cadence to 30 minutes.
This plugin keeps the same minimum interval for paid keys.
Sign checks
The examples directory has separate demo and live configs for smallsign, bigsign and longboi.
Use config.tennis-demo.<sign>.toml without a key, or config.tennis-live.<sign>.toml with LIVETENNIS_API_KEY in the environment.
Validate the chosen file with led-ticker validate <path> before starting the sign.
Check that BP, round labels and tournament names have separated letters. Check every score column stays inside the panel.
Data
Live Tennis API, base URL https://api.livetennisapi.com/api/public/v1, header X-API-Key. Score arrays are player-major (games = [[6, 3], [4, 4]] reads 6-4, 3-4). Docs: https://docs.livetennisapi.com. Not affiliated with the ATP, WTA or ITF.
Development
uv sync --extra dev # from the repo root
uv run pytest plugins/tennis --cov=plugins/tennis/src # tests
uv run ruff check plugins/tennis && uv run pyright plugins/tennis/src
tests/test_layout_scoreboard.py is the pixel-separation regression test for the physical board (CONTRIBUTING.md layout invariant): it spies on every hi-res hires() call on worst-case data and asserts a >= 6 px measured clearance between neighbours on both scale>1 geometries.
License
MIT — see LICENSE.
Metadata
Release files for led-ticker-tennis 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| led_ticker_tennis-0.1.0.tar.gz | 49.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| led_ticker_tennis-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 83.2 kB
Release files / led_ticker_tennis-0.1.0.tar.gz
| Download URL | led_ticker_tennis-0.1.0.tar.gz |
|---|---|
| Size | 49.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
eeef18a716f96e5c6f7ed3028e0c36dcf21c7adfd6013a0f33ade5c3b47988dc
|
|
BLAKE2b-256 checksum How to use checksums |
87b3f330a6db9ce40919772fa94c52baa9be9cf74a9dc7936715fb937224996b
|
| 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 Oct 6, 2026.
Transparency logRelease files / led_ticker_tennis-0.1.0-py3-none-any.whl
| Download URL | led_ticker_tennis-0.1.0-py3-none-any.whl |
|---|---|
| Size | 33.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
81673ef2f9d61b931e6063c780da706d5e5b6cfa0c8955fdc2d0e417e7256617
|
|
BLAKE2b-256 checksum How to use checksums |
faff8a5d9ec302e437cf6d8a09e9f9893fd86e8116622d3407451cb2b5e9c97f
|
| 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 Oct 6, 2026.
Transparency log