ποΈ Honor tradition with tech β This project plays the bugle calls Colors at 8:00 AM and Taps at sunset on a Sonos speaker automatically every day.
β
Play colors.mp3 at 0800 sharp every morning
π
Dynamically calculate sunset time to play taps.mp3
π Pause what's playing and restore it after the call
π Log every playback to /opt/flag/sonos_play.log
π‘ Serve your MP3s via a tiny HTTP server
βοΈ Customize everything via /opt/flag/config.json
π₯οΈ Scheduled via systemd timers β better logging, auto-retry, and Persistent=true boot resilience (critical for Raspberry Pi)
π΅ Extensible schedules β add any number of scheduled plays by editing config.json, no code changes needed
- π Python 3.8+
- πΆ Sonos speaker on the local network
- π₯οΈ Ubuntu/Debian VM, LXC container, or Raspberry Pi (systemd required)
- π§ Default
colors.mp3andtaps.mp3audio files are included; replace with your own if desired
Download and run the setup script from any directory (e.g., /root or /opt):
wget --no-cache https://raw.githubusercontent.com/agster27/flag/main/setup.sh -O setup.sh
chmod +x setup.sh
./setup.shYou will be prompted with a menu:
ββββββββββββββββββββββββββββββββββββββββββββ
β Honor Tradition with Tech β Setup β
β Version 2.1.0 β
β Status: β
Installed β
ββββββββββββββββββββββββββββββββββββββββββββ
Config: Sonos IP: 192.168.1.50 | 2 schedule(s) | Volume: 30
ββ Read-only ββββββββββββββββββββββββββ
1) List scheduled plays
2) Test Sonos playback
3) View logs
ββ Configuration ββββββββββββββββββββββ
4) Install (first-time setup)
5) Upgrade (update scripts, keep config)
6) Reconfigure (edit config.json interactively)
ββ Danger zone ββββββββββββββββββββββββ
7) Uninstall completely
8) Exit without doing anything
Install state detection: When
setup.shloads, it automatically checks for the Python virtual environment (/opt/flag/sonos-env), the config file (/opt/flag/config.json), and active systemd timers. If any component is missing, a warning is displayed above the menu with guidance on which option to select. On a fresh system, the "Install" option is marked withβ start hereand options that require a working installation are annotated with(requires install).
| Option | Action |
|---|---|
| 1 | List scheduled plays β shows all configured schedules, systemd timer status, and audio HTTP server status |
| 2 | Test Sonos playback β plays a test audio clip on your Sonos speaker |
| 3 | View logs β shows the last 20 lines of setup.log and sonos_play.log |
| 4 | Install (first-time setup) β installs system deps, downloads files, creates venv, runs config wizard, writes systemd timers |
| 5 | Upgrade β downloads latest scripts from GitHub and upgrades pip packages; preserves your existing config.json |
| 6 | Reconfigure β re-runs the config wizard to edit settings and regenerate timers |
| 7 | Uninstall β removes all files, systemd services, and timers |
| 8 | Exit without making any changes |
The script will automatically download all required files from GitHub using wget (no
git cloneneeded), create a Python virtual environment, install dependencies, and generate a defaultconfig.jsonif needed.
After setup, your /opt/flag/ folder should look like:
/opt/flag/
βββ sonos_play.py # Plays the MP3 on Sonos
βββ schedule_sonos.py # Calculates sunset and writes systemd timer unit files
βββ audio_check.py # Validates and converts audio files
βββ config.py # Central configuration loader
βββ README.md # Project readme (downloaded for reference)
βββ requirements.txt # Python requirements (downloaded for reference)
βββ sonos_play.log # π― Playback log file (created at runtime)
βββ setup.log # π§ Setup log file (created by setup.sh)
βββ config.json # π§ Settings (auto-generated if missing)
βββ sonos-env/ # π Virtual environment
βββ audio/
βββ colors.mp3 # πΆ Morning bugle call (default included; replace with your own)
βββ taps.mp3 # π
Evening taps (default included; replace with your own)
Systemd unit files (written by schedule_sonos.py to /etc/systemd/system/):
flag-colors.service / flag-colors.timer # Colors at 08:00
flag-taps.service / flag-taps.timer # Taps at sunset (updated daily)
flag-reschedule.service / flag-reschedule.timer # Daily 02:00 β recalculates sunset
flag-audio-http.service # HTTP audio file server
A systemd-managed HTTP server is set up to serve your audio files directly from /opt/flag/audio/.
You do not need to run git clone or start the server manually.
Your files will be available at:
Check the server status or restart it with:
sudo systemctl status flag-audio-http
sudo systemctl restart flag-audio-httpEdit /opt/flag/config.json to match your Sonos and preferences:
{
"sonos_ip": "192.168.1.50",
"port": 8000,
"volume": 30,
"default_wait_seconds": 60,
"skip_restore_if_idle": true,
"latitude": 42.1,
"longitude": -71.5,
"timezone": "America/New_York",
"sunset_offset_minutes": 0,
"schedules": [
{
"name": "colors",
"audio_url": "http://192.168.1.10:8000/colors.mp3",
"time": "08:00"
},
{
"name": "taps",
"audio_url": "http://192.168.1.10:8000/taps.mp3",
"time": "sunset"
}
]
}| Key | Description |
|---|---|
sonos_ip |
IP address of your Sonos speaker |
port |
Port the HTTP audio server listens on (default: 8000) |
volume |
Playback volume (0β100) |
default_wait_seconds |
Fallback wait time (seconds) if MP3 duration cannot be determined |
skip_restore_if_idle |
If true, do not restore prior playback when speaker was idle |
latitude / longitude |
Your coordinates, used to calculate local sunset time |
timezone |
IANA timezone name (e.g. "America/New_York") |
sunset_offset_minutes |
Optional offset in minutes from sunset (negative = before, positive = after). Defaults to 0 |
Each entry in schedules defines one scheduled audio play:
| Field | Description |
|---|---|
name |
Unique name used as the systemd unit suffix (flag-{name}.service / flag-{name}.timer). Must contain only letters, numbers, hyphens, and underscores. |
audio_url |
Full HTTP URL of the MP3 to play (served by the built-in audio HTTP server). |
time |
When to play: either "HH:MM" (24-hour local time) or the special value "sunset". |
Backward compatibility: If you have an older install that still uses the flat
colors_url/taps_url/colors_timekeys,schedule_sonos.pywill automatically synthesise a schedules list from them and print a deprecation warning. Re-runsetup.shβ option 6 (Reconfigure) to permanently migrate to the new format.
To add a new scheduled audio play (e.g., a 17:00 retreat call):
-
Add an audio file to
/opt/flag/audio/(e.g.,retreat.mp3) -
Edit
/opt/flag/config.jsonand add an entry to theschedulesarray:{ "name": "retreat", "audio_url": "http://192.168.1.10:8000/retreat.mp3", "time": "17:00" } -
Re-run setup.sh and choose option 6 (Reconfigure), or run:
sudo /opt/flag/sonos-env/bin/python /opt/flag/schedule_sonos.py
-
Verify the new timer is active:
systemctl list-timers --all | grep flag
After setup, you should test that all components work:
Check if your audio files are served correctly:
curl -I http://localhost:8000/colors.mp3
curl -I http://localhost:8000/taps.mp3You should see HTTP/1.0 200 OK in the response headers.
To test playback without waiting for the scheduled time, run:
/opt/flag/sonos-env/bin/python /opt/flag/sonos_play.py http://<your-pi-ip>:8000/colors.mp3or, for taps:
/opt/flag/sonos-env/bin/python /opt/flag/sonos_play.py http://<your-pi-ip>:8000/taps.mp3If it works, you'll hear the audio play on your Sonos and see log output in /opt/flag/sonos_play.log.
Verify all timers were installed and show their next fire times:
systemctl list-timers --all | grep flagYou should see entries for each schedule (flag-colors, flag-taps) and the daily reschedule (flag-reschedule).
Check journal logs for a specific timer/service:
journalctl -u flag-colors -n 50
journalctl -u flag-taps -n 50
journalctl -u flag-reschedule -n 20Review the playback log file for errors or confirmations:
cat /opt/flag/sonos_play.logThe setup log (written by setup.sh) is at:
cat /opt/flag/setup.log- Check audio server:
sudo systemctl status flag-audio-http - Check a specific timer status:
systemctl status flag-colors.timer
systemctl status flag-taps.timer - Check logs for a service:
journalctl -u flag-colors -n 50
journalctl -u flag-taps -n 50 - List all flag timers and their next fire time:
systemctl list-timers --all | grep flag - Check playback log:
cat /opt/flag/sonos_play.log - Check setup log:
cat /opt/flag/setup.log - Manually trigger a play (for testing):
sudo systemctl start flag-colors.service - Sunset timer shows the wrong time?
Theflag-rescheduletimer recalculates sunset at 02:00 each night. To recalculate immediately:
sudo /opt/flag/sonos-env/bin/python /opt/flag/schedule_sonos.py
Created by agster27.
Inspired by tradition, powered by Python and Sonos.