feat: make alarm music file configurable via env var and CLI arg
This commit is contained in:
@@ -27,11 +27,16 @@ This project uses Python 3 and `uv` for dependency management. To set up the env
|
|||||||
Please refer to the [arcade-button-wiring.md](arcade-button-wiring.md) file for detailed instructions on how to connect the arcade button and its LED to the Raspberry Pi's GPIO pins.
|
Please refer to the [arcade-button-wiring.md](arcade-button-wiring.md) file for detailed instructions on how to connect the arcade button and its LED to the Raspberry Pi's GPIO pins.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
1. Make sure your audio file (`Laid Back - Sunshine Reggae.mp3` or any other MP3 you prefer) is in the project directory.
|
1. Make sure your audio file (`Laid Back - Sunshine Reggae.mp3` or any other MP3 you prefer) is in the project directory, or set a custom path.
|
||||||
2. Run the alarm clock script manually:
|
2. Run the alarm clock script manually:
|
||||||
```bash
|
```bash
|
||||||
|
# Use the default music file or the MUSIC_FILE environment variable
|
||||||
python3 wecker.py
|
python3 wecker.py
|
||||||
|
|
||||||
|
# Or pass a custom music file directly
|
||||||
|
python3 wecker.py --music-file /path/to/your/alarm.mp3
|
||||||
```
|
```
|
||||||
|
The music file is resolved in this order: `--music-file` argument, `MUSIC_FILE` environment variable, default `Laid Back - Sunshine Reggae.mp3`.
|
||||||
|
|
||||||
## Automating and Managing Alarms (GraphQL API)
|
## Automating and Managing Alarms (GraphQL API)
|
||||||
|
|
||||||
|
|||||||
@@ -124,3 +124,15 @@ def test_blinking_updates_time_correctly(mock_time, mock_gpio, mock_pygame):
|
|||||||
|
|
||||||
assert clock.state == wecker.STATE_WAIT_FOR_INPUT
|
assert clock.state == wecker.STATE_WAIT_FOR_INPUT
|
||||||
assert clock.last_interaction_time == 200.0
|
assert clock.last_interaction_time == 200.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_uses_env_music_file(mock_gpio, mock_pygame, monkeypatch):
|
||||||
|
monkeypatch.setenv("MUSIC_FILE", "/custom/track.mp3")
|
||||||
|
wecker.setup()
|
||||||
|
mock_pygame.mixer.music.load.assert_called_with("/custom/track.mp3")
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_music_file_argument_overrides_env(mock_gpio, mock_pygame, monkeypatch):
|
||||||
|
monkeypatch.setenv("MUSIC_FILE", "/env/track.mp3")
|
||||||
|
wecker.setup(music_file="/arg/track.mp3")
|
||||||
|
mock_pygame.mixer.music.load.assert_called_with("/arg/track.mp3")
|
||||||
|
|||||||
@@ -63,8 +63,14 @@ BUTTON_PIN = 17
|
|||||||
LED_PIN = 27
|
LED_PIN = 27
|
||||||
|
|
||||||
|
|
||||||
def setup():
|
DEFAULT_MUSIC_FILE = "Laid Back - Sunshine Reggae.mp3"
|
||||||
|
|
||||||
|
|
||||||
|
def setup(music_file: str | None = None):
|
||||||
"""Initialize GPIO and audio hardware. Call once before running."""
|
"""Initialize GPIO and audio hardware. Call once before running."""
|
||||||
|
if music_file is None:
|
||||||
|
music_file = os.environ.get("MUSIC_FILE", DEFAULT_MUSIC_FILE)
|
||||||
|
|
||||||
GPIO.setmode(GPIO.BCM)
|
GPIO.setmode(GPIO.BCM)
|
||||||
GPIO.setup(LED_PIN, GPIO.OUT)
|
GPIO.setup(LED_PIN, GPIO.OUT)
|
||||||
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||||
@@ -74,7 +80,7 @@ def setup():
|
|||||||
pygame.mixer.init()
|
pygame.mixer.init()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pygame.mixer.music.load("Laid Back - Sunshine Reggae.mp3")
|
pygame.mixer.music.load(music_file)
|
||||||
pygame.mixer.music.set_volume(1.0)
|
pygame.mixer.music.set_volume(1.0)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error loading audio file: {e}")
|
logging.error(f"Error loading audio file: {e}")
|
||||||
@@ -200,8 +206,8 @@ class AlarmClock:
|
|||||||
return True # Keep running
|
return True # Keep running
|
||||||
|
|
||||||
|
|
||||||
def run_alarm(test_mode=False):
|
def run_alarm(test_mode=False, music_file: str | None = None):
|
||||||
setup()
|
setup(music_file=music_file)
|
||||||
logging.info("Alarm clock started. Music is playing in an endless loop.")
|
logging.info("Alarm clock started. Music is playing in an endless loop.")
|
||||||
if "pygame" in globals() and hasattr(pygame, "mixer") and pygame.mixer.get_init():
|
if "pygame" in globals() and hasattr(pygame, "mixer") and pygame.mixer.get_init():
|
||||||
pygame.mixer.music.play(-1)
|
pygame.mixer.music.play(-1)
|
||||||
@@ -231,9 +237,19 @@ def run_alarm(test_mode=False):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Raspberry Pi alarm clock.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--music-file",
|
||||||
|
default=os.environ.get("MUSIC_FILE", DEFAULT_MUSIC_FILE),
|
||||||
|
help="Path to the MP3 file to play (default: $MUSIC_FILE or default track).",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
ensure_single_instance()
|
ensure_single_instance()
|
||||||
try:
|
try:
|
||||||
run_alarm()
|
run_alarm(music_file=args.music_file)
|
||||||
finally:
|
finally:
|
||||||
pygame.mixer.quit()
|
pygame.mixer.quit()
|
||||||
GPIO.cleanup()
|
GPIO.cleanup()
|
||||||
|
|||||||
Reference in New Issue
Block a user