Skip to main content

Telnet (ANSI terminal) rendering backend for led-ticker — watch your sign in a terminal.

Project description

led-ticker-telnet

Watch your led-ticker sign live in any ANSI-capable terminal — the same content that drives your LED panels streams over TCP as true-color ANSI escape sequences.

Every client sees the current frame the moment swap() fires, at panel cadence. Open two terminals, disconnect one, start another — the sign keeps rendering without interruption.

Prerequisites

  • A working led-ticker install (core ≥ 2.2).
  • An ANSI-capable terminal (any modern terminal on macOS, Linux, or Windows Terminal). True-color support (24-bit) recommended; most terminals released after 2017 support it.
  • telnet or nc on the connecting machine (both are standard on macOS and most Linux distros).

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 and rebuild:

led-ticker-telnet
# in your led-ticker checkout
docker compose up -d --build

Standalone (a venv that already has led-ticker):

pip install led-ticker-telnet

See the led-ticker Plugins docs for the constraint-based install the Docker image uses.

Select the backend

In your config/config.toml, set the backend field under [display]:

[display]
backend = "telnet.telnet"
rows = 16
cols = 32
chain_length = 5
brightness = 80
default_scale = 1

The backend name is telnet.telnet — the first telnet is the plugin namespace (from the entry-point registration), and the second names the backend within that namespace.

All other [display] fields (rows, cols, chain_length, default_scale, etc.) work exactly as they do with the rgbmatrix backend. Your widgets, sections, and transitions config is unchanged.

Connect

Once led-ticker starts with the telnet backend, connect from any machine on the same network:

telnet <host> 2300  # default; see Configuration to change
nc <host> 2300  # default; see Configuration to change

Replace <host> with the hostname or IP of the machine running led-ticker. When connecting locally: telnet localhost 2300.

The terminal renders one text row per two canvas rows, using the Unicode UPPER HALF BLOCK character (▀) with the top pixel as the foreground color and the bottom pixel as the background color. This doubles the vertical pixel density in most terminals.

Disconnecting cleanly (Ctrl-C or closing the terminal window) is safe — led-ticker logs the departure and continues running.

Configuration via environment variables

The telnet backend reads two environment variables at startup:

Variable Default Description
LED_TICKER_TELNET_PORT 2300 TCP port to listen on
LED_TICKER_TELNET_HOST 0.0.0.0 Bind address (all interfaces)

Set them in your shell or in Docker Compose:

# shell
export LED_TICKER_TELNET_PORT=3000
# docker compose (compose.yaml)
environment:
  LED_TICKER_TELNET_PORT: "3000"
  # LED_TICKER_TELNET_HOST: "0.0.0.0"   # bind address; default is all interfaces

Known limitations

brightness is a no-op. The [display] brightness field is required by led-ticker's backend protocol but has no effect on ANSI output — adjust brightness/contrast in your terminal instead.

pixel_mapper_config is accepted but ignored. The telnet backend accepts the pixel_mapper_config argument (required by led-ticker's backend constructor convention) but does not apply any chain-folding or U-mapper remapping — it renders the logical canvas directly to the terminal. Physical-panel layout concerns (serpentine chains, rotation) are a hardware-level concern irrelevant to a terminal preview.

TOML [display] sub-keys are not readable by plugin backends today. The port and host are therefore environment-only — there is no port = 2300 or host = "0.0.0.0" key in the [display] block.

A future led-ticker-core [display.<backend>]from_config(cls, cfg) mechanism would close this: plugins could define their own sub-table and receive a typed config object at startup. Port and host would then be first-class TOML knobs alongside brightness, rows, and the rest. This is the key usability gap to resolve in a follow-up core change.

Behavior under error conditions

  • Bind failure (port in use, insufficient permissions): the backend logs a warning and continues without a server. The sign renders normally; clients simply cannot connect until the conflict is resolved and led-ticker restarts.
  • Slow or stalled client: swap() writes to the client without waiting for a drain, so the render loop never blocks. Bytes a client hasn't read accumulate in that connection's in-process write buffer; to keep a stalled client (suspended nc, terminal under Ctrl-S flow control, congested link) from growing that buffer without bound, swap() checks each client's write-buffer size and skips the write for any client over a ~4 MiB cap — that frame is dropped for that client, which recovers automatically once it starts reading again. The render loop and other clients are unaffected.
  • Client disconnect mid-session: detected on the next swap() write; the client is pruned and rendering continues.

Development

cd plugins/telnet
uv sync --extra dev      # resolves led-ticker-core from PyPI
uv run pytest -q
uv run ruff check src tests
uv run pyright src

The plugin imports only the public led_ticker.plugin surface — tests/test_import_purity.py enforces it.

Headless smoke / profiling image

Dockerfile.smoke runs led-ticker fully headless (no rgbmatrix, no hardware) with this backend and the bundled smoke config — handy for a quick visual check or profiling the render path on any machine:

cd plugins/telnet
make smoke-run            # build + run, then: telnet localhost 2300
make smoke-stop           # stop + remove the container

Profile a different engine/Python or change the port:

docker build -f Dockerfile.smoke --build-arg CORE_VERSION=2.3.0 -t led-ticker-telnet-smoke .
docker run -d -p 3000:3000 -e LED_TICKER_TELNET_PORT=3000 led-ticker-telnet-smoke

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

led_ticker_telnet-0.1.0.tar.gz (17.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

led_ticker_telnet-0.1.0-py3-none-any.whl (9.1 kB view details)

Uploaded Python 3

File details

Details for the file led_ticker_telnet-0.1.0.tar.gz.

File metadata

  • Download URL: led_ticker_telnet-0.1.0.tar.gz
  • Upload date:
  • Size: 17.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for led_ticker_telnet-0.1.0.tar.gz
Algorithm Hash digest
SHA256 454de3b62bf8300b56fdb26f081fa165c106531461174b2b4bedb810fd4e3336
MD5 4d520c0a85f89ace201a7b37ee52f28c
BLAKE2b-256 bde68a2f9faa2c7831c8ede587d1bfb6bee69d5803374ce242ccd01971bb8442

See more details on using hashes here.

Provenance

The following attestation bundles were made for led_ticker_telnet-0.1.0.tar.gz:

Publisher: publish.yml on JamesAwesome/led-ticker-plugins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file led_ticker_telnet-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for led_ticker_telnet-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 733281bacf23319b9a4ce1e0923ec075e13c1be89cadb947d25b70c9e55102d0
MD5 c66a3caa1c3421ea60e25a76a8539710
BLAKE2b-256 ddd9add5870daef54493d0c14c087aaca206b72600dddfa593dd03a250c5b356

See more details on using hashes here.

Provenance

The following attestation bundles were made for led_ticker_telnet-0.1.0-py3-none-any.whl:

Publisher: publish.yml on JamesAwesome/led-ticker-plugins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page