Python client library and CLI for the LED-Ticker BLE device
Project description
led_ticker — Python library & CLI for the LED Ticker
led_ticker speaks the same BLE service as the iOS app, so you can drive the
device — or build your own tools — from any machine with Bluetooth. The device
advertises as LED-Ticker-XXXX.
Install
pip install led-ticker # or: uv add led-ticker
This installs the importable led_ticker package and the led command.
From a checkout you can also run the CLI with no install via uv:
uv run tools/led.py <cmd> # uses ./src directly
Library
from led_ticker import LedTicker, scan
# Scan for available devices (returns DeviceInfo with name, address, rssi):
for d in scan():
print(d.name, d.address, d.rssi)
# Reuse one connection for several operations:
with LedTicker(pin="482913") as d:
d.set_tickers(["AAPL", "MSFT"])
d.set_status("BUSY", minutes=30)
print(d.get_version()) # -> "0.3.0"
s = d.get_status() # -> Status(text="BUSY", seconds=1800)
# Or a one-shot for a single call (opens and closes its own connection):
import led_ticker
led_ticker.set_mode(["stocks", "weather"])
LedTicker(select=None, address=None, name_prefix="LED-Ticker", scan_timeout=4.0, timeout=15.0, pin=None).
By default the first LED-Ticker-* in range is used; if several are in range it raises
AmbiguousDeviceError (whose .candidates is a list of DeviceInfo). Pass select= — a
name suffix (the XXXX in LED-Ticker-XXXX), full name, or address — to choose one, or
address= to target a known address directly (skips the scan). Methods raise
ValidationError, AuthError, DeviceNotFoundError, AmbiguousDeviceError, or
ProtocolError (all subclasses of LedTickerError).
Selecting a device
With more than one LED-Ticker in range, list them and target one explicitly:
uv run tools/led.py devices # list units: name, address, signal
uv run tools/led.py --device A1B2 status "BUSY" 30 # target by name suffix
--device matches a unit by its name suffix (the XXXX in LED-Ticker-XXXX),
its full name, or its Bluetooth address. If you run a command with several units
in range and no --device, an interactive terminal prompts you to choose; in a
script (no TTY) it lists the candidates and exits non-zero so you can re-run with
--device.
CLI
# Sign mode
uv run tools/led.py status "BUSY" 30 # show for 30 min, then auto-clear
uv run tools/led.py status "ON AIR" # indefinite
uv run tools/led.py status clear
# Timer mode (countdown sign — random animation at zero, then resumes ambient)
uv run tools/led.py timer 10 # 10-minute countdown
uv run tools/led.py timer cancel
# Ambient mode (subset of stocks/weather/clock, 'all', or 'none' for sign-only)
uv run tools/led.py mode stocks weather
uv run tools/led.py mode clock
uv run tools/led.py mode all
uv run tools/led.py mode none
# Power (volatile — power cycle returns to on)
uv run tools/led.py power on
uv run tools/led.py power off
# Display settings (persisted on the device)
uv run tools/led.py display # show current brightness + scroll speed
uv run tools/led.py display brightness 8 # brightness 0-15
uv run tools/led.py display speed 50 # scroll ms/step 20-500 (lower = faster)
uv run tools/led.py display 8 50 # both at once
# Timezone (persisted; POSIX TZ string — the iOS app has a friendly picker)
uv run tools/led.py timezone # show current
uv run tools/led.py timezone "EST5EDT,M3.2.0,M11.1.0" # US Eastern
# Data
uv run tools/led.py tickers AAPL TSLA NVDA SPY
uv run tools/led.py locations "47.61,-122.33,Seattle" # lat,lon,label (look up coords online)
uv run tools/led.py apikey your-finnhub-key
uv run tools/led.py wifi My Network Name password
# Inspect
uv run tools/led.py get version # firmware version on the device
uv run tools/led.py get wifi|apikey|tickers|status|locations|mode|power|display|timezone|version # read other settings
# Auth
uv run tools/led.py pin 482913 # save the device's PIN locally (~/.config/led-ticker/pin)
uv run tools/led.py pin clear # forget the saved PIN
uv run tools/led.py pin-enforce on # device: require PIN for writes (default after a fresh flash)
uv run tools/led.py pin-enforce off # device: stop requiring PIN (escape hatch)
# Maintenance
uv run tools/led.py reload # force stock refresh
uv run tools/led.py reset # wipe NVS, rotate PIN, revert to config.h defaults
Stale-PIN safety: every write probes the device after sending the PIN and exits with a clear error if the PIN was rotated by a factory reset — a write never fails silently because of an out-of-date local PIN.
License
Apache-2.0 © 2026 Sunil Sayala — free to use, including commercially, with attribution. (The firmware in the parent repo is also Apache-2.0; the hardware design files are CC BY 4.0 — see the repo root.)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file led_ticker-0.3.0.tar.gz.
File metadata
- Download URL: led_ticker-0.3.0.tar.gz
- Upload date:
- Size: 21.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b58578d144a415943a13830feb8ecad60b7f944ace77811f7f8b6595ed2c6549
|
|
| MD5 |
0a953e08042724cd377ad945ee7e7119
|
|
| BLAKE2b-256 |
60c1d2d41461739f2fe5d3f563a02dfe95b281e842bc62b63f55a01aa164b986
|
Provenance
The following attestation bundles were made for led_ticker-0.3.0.tar.gz:
Publisher:
publish.yml on ssayala/esp32-led-simple
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
led_ticker-0.3.0.tar.gz -
Subject digest:
b58578d144a415943a13830feb8ecad60b7f944ace77811f7f8b6595ed2c6549 - Sigstore transparency entry: 1904738811
- Sigstore integration time:
-
Permalink:
ssayala/esp32-led-simple@8ae1fa4ddd6575d32b2ba360648d10e1f058d1b1 -
Branch / Tag:
refs/tags/led-ticker-v0.3.0 - Owner: https://github.com/ssayala
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8ae1fa4ddd6575d32b2ba360648d10e1f058d1b1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file led_ticker-0.3.0-py3-none-any.whl.
File metadata
- Download URL: led_ticker-0.3.0-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8051ea16edb2f7db5cafcd86b9307bfba0338a6ec5d466fe75139ab3803516b5
|
|
| MD5 |
52a5a000a9a434169ee7afe49c1a5f50
|
|
| BLAKE2b-256 |
caf3bab6ce2b7081c4fa78e7fb01966d4eb5b463d1bf461767eeb28d30678655
|
Provenance
The following attestation bundles were made for led_ticker-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on ssayala/esp32-led-simple
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
led_ticker-0.3.0-py3-none-any.whl -
Subject digest:
8051ea16edb2f7db5cafcd86b9307bfba0338a6ec5d466fe75139ab3803516b5 - Sigstore transparency entry: 1904738975
- Sigstore integration time:
-
Permalink:
ssayala/esp32-led-simple@8ae1fa4ddd6575d32b2ba360648d10e1f058d1b1 -
Branch / Tag:
refs/tags/led-ticker-v0.3.0 - Owner: https://github.com/ssayala
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8ae1fa4ddd6575d32b2ba360648d10e1f058d1b1 -
Trigger Event:
push
-
Statement type: