Files
portal/examples/panel_text.py
Jimmy d5cab2efdf Add multi-panel Pico UDP firmware and Python LED control.
Pico panels get static IPs on 10.1.1.10–14 with per-panel LED counts, Makefile deploy targets, and Python examples for animations, sync tests, and direct Pi SPI control.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-28 22:46:08 +12:00

102 lines
3.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""Display text on Pico panel(s) over UDP."""
from __future__ import annotations
import argparse
import socket
import subprocess
import sys
import time
from leds.panel_udp import (
HeadlessMatrix,
add_panel_args,
format_panel_targets,
panel_targets_from_args,
send_frame,
)
from leds.text import draw_text, draw_text_centered
DEFAULT_NAME = "JIMMY"
def _default_name() -> str:
try:
out = subprocess.run(
["git", "config", "user.name"],
capture_output=True,
text=True,
check=False,
)
name = out.stdout.strip()
if name:
return name.upper()
except OSError:
pass
return DEFAULT_NAME
def main() -> int:
parser = argparse.ArgumentParser(description="Display text on LED panel(s)")
parser.add_argument("text", nargs="?", default=None)
add_panel_args(parser)
parser.add_argument("--color", default="255,200,80", metavar="R,G,B")
parser.add_argument("--hold", type=float, default=0.0, help="0 = show until Ctrl+C")
parser.add_argument("--scroll", action="store_true")
args = parser.parse_args()
text = (args.text or _default_name()).upper()
parts = [int(p.strip()) for p in args.color.split(",")]
if len(parts) != 3:
print("Error: --color must be R,G,B", file=sys.stderr)
return 1
color = (parts[0], parts[1], parts[2])
targets = panel_targets_from_args(args)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print(f"Displaying '{text}' on {format_panel_targets(targets, args.port)}")
try:
matrices = [
(target, HeadlessMatrix(target.width, target.height, brightness=args.brightness))
for target in targets
]
if args.scroll:
start = time.monotonic()
offsets = {target.index: matrix.width for target, matrix in matrices}
while True:
for target, matrix in matrices:
matrix.clear()
draw_text(matrix, text, offsets[target.index], 1, color)
send_frame(sock, target.host, args.port, matrix.rgb_bytes(), args.panel_id)
offsets[target.index] -= 1
if offsets[target.index] < -len(text) * 6:
offsets[target.index] = matrix.width
time.sleep(0.08)
if args.hold > 0 and time.monotonic() - start >= args.hold:
break
else:
for target, matrix in matrices:
matrix.clear()
draw_text_centered(matrix, text, color)
send_frame(sock, target.host, args.port, matrix.rgb_bytes(), args.panel_id)
if args.hold <= 0:
print("Showing (Ctrl+C to clear)")
while True:
time.sleep(1)
else:
time.sleep(args.hold)
except KeyboardInterrupt:
print("\nClearing.")
finally:
for target, matrix in matrices:
matrix.clear()
send_frame(sock, target.host, args.port, matrix.rgb_bytes(), args.panel_id)
sock.close()
return 0
if __name__ == "__main__":
raise SystemExit(main())