Convert spectro.sh to Python#399
Conversation
Modernized 1:1 port of spectro.sh for current Raspberry Pi OS: - Drop Python 2 support (py2 is EOL; the original .sh remains for older systems) - Python modules install into the active venv via the standard sudo -E env PATH=$PATH invocation (no --break-system-packages) - Replace the deprecated /etc/rc.local autostart with a spectro.service systemd unit - Use get_boot_config() for the boot config path Tested end-to-end on a Pi 5 (Trixie): both select menus, mic and accel branches, config edits (selector.py FLAGS, config.txt hdmi_force_hotplug, alsa.conf, i2c), Spectro repo download, and the systemd service all verified, then reverted to baseline.
There was a problem hiding this comment.
Pull request overview
This PR replaces the legacy spectro.sh installer with a modern spectro.py installer targeting current Raspberry Pi OS, including a switch from rc.local autostart to a systemd unit and updated boot config handling.
Changes:
- Adds a new Python-based Spectro installer (
spectro.py) usingadafruit_shell. - Installs/overwrites a
spectro.servicesystemd unit to autostartselector.pyat boot. - Updates installation/config steps for current Raspberry Pi OS (e.g.,
get_boot_config()usage, optional mic/accelerometer branches).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| shell.write_text_file( | ||
| "/etc/systemd/system/spectro.service", | ||
| f"""[Unit] | ||
| Description=Adafruit Spectro display daemon | ||
| After=multi-user.target | ||
|
|
||
| [Service] | ||
| Type=simple | ||
| User=pi | ||
| WorkingDirectory={SPECTRO_DIR} | ||
| ExecStart=/usr/bin/python3 {SPECTRO_DIR}/selector.py | ||
| Restart=on-failure |
There was a problem hiding this comment.
Done — ExecStart now uses sys.executable (falling back to /usr/bin/python3) so the service runs the same interpreter/venv the installer used. Fixed in 73d97bc.
| print("Downloading Spectro software...") | ||
| shell.run_command( | ||
| "curl -L https://github.com/adafruit/Adafruit_Spectro_Pi/archive/master.zip " | ||
| "-o Adafruit_Spectro_Pi.zip" | ||
| ) | ||
| shell.run_command("unzip -q -o Adafruit_Spectro_Pi.zip") | ||
| shell.remove("Adafruit_Spectro_Pi.zip") | ||
| shell.run_command("mv Adafruit_Spectro_Pi-master Adafruit_Spectro_Pi") | ||
| shell.run_command("chown -R pi:pi Adafruit_Spectro_Pi") |
There was a problem hiding this comment.
Done — the installer now chdirs to ~pi, removes any existing SPECTRO_DIR first, and mvs/chowns into SPECTRO_DIR explicitly, so the unit path is correct regardless of CWD. Fixed in 73d97bc.
| # Make default GIFs directory | ||
| shell.run_command("mkdir /boot/gifs") | ||
|
|
||
| # Set up LED columns, rows and slowdown in selector.py script | ||
| flags = ( | ||
| f'FLAGS = ["--led-cols={MATRIX_WIDTHS[matrix_size]}", ' | ||
| f'"--led-rows={MATRIX_HEIGHTS[matrix_size]}", ' | ||
| f'"--led-slowdown-gpio={SLOWDOWN_OPTS[slowdown_gpio]}"]' | ||
| ) | ||
| shell.pattern_replace("./Adafruit_Spectro_Pi/selector.py", "^FLAGS.*$", flags) | ||
|
|
||
| # Force HDMI out so /dev/fb0 exists | ||
| config = shell.get_boot_config() | ||
| shell.reconfig(config, "^.*hdmi_force_hotplug.*$", "hdmi_force_hotplug=1") |
There was a problem hiding this comment.
Done — GIFs dir is now derived from get_boot_config() (/boot vs /boot/firmware), created with mkdir -p for idempotency, and the installer bails cleanly if no boot config is found. Fixed in 73d97bc.
| # Auto-start selector.py on boot via a systemd service | ||
| print("Installing spectro.service systemd unit...") | ||
| write_spectro_service() |
There was a problem hiding this comment.
Done — added a legacy /etc/rc.local cleanup that strips any selector.py autostart line, matching the retrogame.py pattern, so we don't double-launch alongside the systemd unit. Fixed in 73d97bc.
- ExecStart uses sys.executable so the service runs the same interpreter (and venv) the installer used, instead of hardcoded /usr/bin/python3. - Install the repo into SPECTRO_DIR explicitly (chdir ~pi, overwrite if present) so the systemd unit path is correct regardless of CWD. - Make the GIFs dir on the active boot partition via get_boot_config() (/boot vs /boot/firmware), mkdir -p for idempotency, bail if no config. - Clean up any legacy selector.py line in /etc/rc.local to avoid double-launching alongside the systemd unit (matches retrogame.py).
makermelissa
left a comment
There was a problem hiding this comment.
Thanks for the conversion.
Converts
spectro.shtospectro.py, modernized for current Raspberry Pi OS.Changes
.shremains in the repo for anyone on older systems.sudo -E env PATH=$PATH python3 spectro.pyinvocation — no--break-system-packages./etc/rc.localis deprecated on Bookworm/Trixie, soselector.pyis now auto-started from aspectro.servicesystemd unit instead of editing rc.local.get_boot_config()for the boot config path.Testing
Tested end-to-end on a Raspberry Pi 5 (Trixie):
pip3installs landed in the venv (psutil, RPi.GPIO, busdevice, lis3dh)selector.pyFLAGS line,config.txthdmi_force_hotplug=1,alsa.confcard remap (mic branch),i2cenabled (accel branch)/boot/gifscreatedspectro.serviceinstalled and enabledSystem was then reverted to baseline (config.txt md5 confirmed identical).