grabowski ef0373e60b Add external configuration file system
Breaking Changes:
- Configuration now via config.json instead of editing Python code
- Remove all hardcoded paths (no more /home/berwn)
- Separate system config (config.json) from runtime config (user_config.json)

Features:
- config.example.json with all configurable options
- GPIO pin and state configuration
- Audio device index configuration
- Customizable paths (relative or absolute)
- Web port and upload size settings
- No code editing required for deployment

Configuration Structure:
- gpio: hook_pin, hook_pressed_state
- audio: device_index, chunk_size, channels, sample_rate, max_record_seconds
- paths: base_dir, recordings_dir, sounds_dir
- web: port, max_upload_size_mb
- system: active_greeting, default_volume

Script automatically:
- Checks for config.json on startup
- Provides helpful error if missing
- Uses relative paths by default
- Loads test_complete.py config from same file

Updated Documentation:
- Complete configuration guide in README
- Setup instructions without hardcoded paths
- Troubleshooting for config errors
- Device index discovery command

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 14:48:43 +07:00

Wedding Phone - Vintage Rotary Phone Audio System

A Raspberry Pi-based rotary phone system for weddings and events. Guests can pick up the handset to hear custom greeting messages and leave voice recordings. Features a modern web interface for managing messages and recordings.

Features

  • Vintage Phone Integration: Uses a real rotary phone with GPIO hook detection
  • Custom Greeting Messages: Upload multiple greeting messages and select which one plays
  • Voice Recording: Automatically records guest messages after the greeting
  • Web Interface: Beautiful, responsive web UI for managing the system
  • Audio Playback: Play recordings and greetings directly in the browser
  • Volume Control: Adjust playback volume with real-time slider (0-100%)
  • Multiple Message Support: Upload and manage multiple greeting messages
  • Active Message Selector: Choose which greeting plays when the phone is picked up
  • HiFiBerry Support: Optimized for HiFiBerry DAC+ADC Pro audio quality
  • Real-time Status: Monitor phone status (on-hook/off-hook/recording)
  • Auto-refresh: Status updates every 5 seconds

Hardware Requirements

  • Raspberry Pi (3/4/5 or Zero 2 W)
  • HiFiBerry DAC+ADC Pro (or similar audio interface)
  • Vintage rotary phone with hookswitch
  • Speaker (connected to HiFiBerry output)
  • Microphone (connected to HiFiBerry input, or use phone handset mic)

Software Requirements

  • Raspberry Pi OS (Bullseye or newer)
  • Python 3.7+
  • Required Python packages:
    • pyaudio
    • flask
    • numpy
    • RPi.GPIO
    • wave (built-in)

Installation

1. Clone the Repository

git clone https://git.b4l.co.th/grabowski/wedding-phone.git
cd wedding-phone

UV is a fast Python package installer and resolver. Install it:

curl -LsSf https://astral.sh/uv/install.sh | sh
# Or on Raspberry Pi with pip:
pip3 install uv

3. Install Dependencies

# Install system dependencies
sudo apt-get update
sudo apt-get install -y python3-pyaudio portaudio19-dev

# Install Python dependencies with UV
uv pip install -e .

Option B: Using pip

sudo apt-get update
sudo apt-get install -y python3-pip python3-pyaudio portaudio19-dev
pip3 install flask numpy RPi.GPIO

4. Configure HiFiBerry

Run the automatic configuration script:

chmod +x configure_hifiberry.sh
./configure_hifiberry.sh

Or follow the manual instructions in AUDIO_FIX.md.

5. Create Configuration File

Copy the example configuration and customize it:

cp config.example.json config.json
nano config.json  # or use your preferred editor

Important settings to configure:

{
  "gpio": {
    "hook_pin": 17,                    // GPIO pin for hookswitch
    "hook_pressed_state": "LOW"        // "LOW" or "HIGH"
  },
  "audio": {
    "device_index": 1,                 // HiFiBerry device index
    "sample_rate": 44100
  },
  "paths": {
    "base_dir": "./rotary_phone_data"  // Relative or absolute path
  },
  "web": {
    "port": 8080
  }
}

Finding your audio device index:

python3 -c "import pyaudio; p=pyaudio.PyAudio(); [print(f'{i}: {p.get_device_info_by_index(i)[\"name\"]}') for i in range(p.get_device_count())]"

6. Test Your Audio

python3 test_complete.py

This will test:

  • Speaker playback
  • Dial tone generation
  • Microphone recording

7. Run the System

python3 rotary_phone_web.py

The web interface will be available at:

  • http://localhost:8080
  • http://<raspberry-pi-ip>:8080

Usage

Web Interface

The web interface provides four main sections:

1. Phone Status

  • Shows current phone state (on-hook/off-hook/recording)
  • Displays active recording filename
  • Auto-refreshes every 5 seconds

2. Volume Control

  • Adjust Volume: Drag slider to set playback volume (0-100%)
  • Real-time visual feedback with percentage display
  • Changes apply immediately to greeting playback
  • Volume setting persists across restarts

3. Greeting Messages

  • Upload: Click "Choose WAV File(s)" to upload one or multiple greeting messages
  • Play: Click "▶️ Play" to preview any greeting in your browser
  • Set Active: Click " Set Active" to select which greeting plays when the phone is picked up
  • Delete: Remove unwanted greetings (cannot delete the active one)
  • Default Tone: Generate a classic telephone dial tone

4. Recordings

  • Play: Listen to recordings directly in the browser
  • Download: Save recordings to your computer
  • Delete: Remove unwanted recordings
  • Statistics: View total recordings, storage used, and total duration

Phone Operation

  1. Guest picks up phone: System detects via GPIO
  2. Greeting plays: Active greeting message plays through speaker
  3. Recording starts: After greeting, system records guest message
  4. Guest hangs up: Recording stops and saves automatically
  5. Ready for next call: System returns to waiting state

File Structure

wedding-phone/
├── rotary_phone_web.py       # Main application
├── test_complete.py           # Audio testing script
├── configure_hifiberry.sh     # HiFiBerry setup script
├── config.example.json       # Example configuration (copy to config.json)
├── pyproject.toml            # UV/pip package configuration
├── AUDIO_FIX.md              # Audio configuration guide
├── README.md                  # This file
├── .gitignore                # Git ignore rules
└── templates/                 # Auto-generated on first run
    └── index.html            # Web interface (embedded in script)

Runtime Data (Auto-created)

rotary_phone_data/            # Default location (configurable)
├── recordings/               # Voice recordings from guests
├── sounds/                   # Greeting message WAV files
└── user_config.json         # Runtime settings (volume, active greeting)

Configuration

All configuration is done via the config.json file. No need to edit Python code!

Configuration File Structure

The config.json file contains all system settings:

{
  "gpio": {
    "hook_pin": 17,                        // GPIO pin number for hookswitch
    "hook_pressed_state": "LOW"            // "LOW" or "HIGH" depending on switch
  },
  "audio": {
    "device_index": 1,                     // Audio device index (run test to find)
    "chunk_size": 1024,                    // Audio buffer size
    "format": "paInt16",                   // Audio format (16-bit)
    "channels": 1,                         // Mono audio
    "sample_rate": 44100,                  // 44.1kHz sample rate
    "max_record_seconds": 300              // Max recording time (5 minutes)
  },
  "paths": {
    "base_dir": "./rotary_phone_data",     // Data directory (relative or absolute)
    "recordings_dir": "recordings",        // Subdirectory for recordings
    "sounds_dir": "sounds"                 // Subdirectory for greeting sounds
  },
  "web": {
    "port": 8080,                          // Web interface port
    "max_upload_size_mb": 50               // Max upload file size
  },
  "system": {
    "active_greeting": "dialtone.wav",     // Default greeting
    "volume": 70                           // Default volume (0-100)
  }
}

Finding Your Audio Device

To find your HiFiBerry or other audio device index:

python3 -c "import pyaudio; p=pyaudio.PyAudio(); [print(f'{i}: {p.get_device_info_by_index(i)[\"name\"]}') for i in range(p.get_device_count())]"

Look for your HiFiBerry device and note its index number, then set it in config.json.

Troubleshooting

No Sound from Speaker

  1. Check HiFiBerry configuration:

    aplay -l  # List audio devices
    amixer -c 3 sset Digital 100%  # Set volume (adjust card number)
    
  2. Test speaker directly:

    speaker-test -D plughw:3,0 -c 1 -t wav
    
  3. Run the complete test:

    python3 test_complete.py
    

Microphone Not Recording

  1. Check microphone is connected to HiFiBerry input
  2. Adjust input gain:
    alsamixer -c 3
    
  3. Test recording:
    arecord -D plughw:3,0 -f cd test.wav -d 5
    aplay test.wav
    

GPIO Not Detecting Hookswitch

  1. Verify GPIO pin number in config.json
  2. Check if switch is normally open or closed
  3. Update hook_pressed_state in config.json ("LOW" or "HIGH")
  4. Test with a simple script:
    import RPi.GPIO as GPIO
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    print(GPIO.input(17))  # Should change when switch toggles
    

Web Interface Not Accessible

  1. Check if Flask is running: ps aux | grep python
  2. Verify port in config.json matches URL
  3. Check firewall: sudo ufw allow 8080 (or your configured port)
  4. Check IP address: hostname -I
  5. Try localhost: http://127.0.0.1:8080

Configuration Errors

If the script won't start:

  1. Ensure config.json exists (copy from config.example.json)
  2. Validate JSON syntax: python3 -m json.tool config.json
  3. Check all paths exist or can be created
  4. Verify audio device index is correct

Auto-start on Boot

Create a systemd service:

sudo nano /etc/systemd/system/wedding-phone.service

Add (replace /path/to/wedding-phone with your actual path):

[Unit]
Description=Wedding Phone Service
After=network.target sound.target

[Service]
Type=simple
User=pi
WorkingDirectory=/path/to/wedding-phone
ExecStart=/usr/bin/python3 /path/to/wedding-phone/rotary_phone_web.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable wedding-phone.service
sudo systemctl start wedding-phone.service
sudo systemctl status wedding-phone.service

API Endpoints

The system provides REST API endpoints:

  • GET / - Web interface
  • GET /api/status - Phone status JSON
  • GET /api/recordings - List all recordings
  • GET /api/greetings - List all greeting messages
  • GET /api/volume - Get current volume setting
  • POST /api/volume - Set volume level (0-100)
  • POST /upload_greeting - Upload new greeting
  • POST /set_active_greeting - Set active greeting
  • POST /delete_greeting/<filename> - Delete greeting
  • GET /play_audio/<type>/<filename> - Stream audio file
  • GET /download/<filename> - Download recording
  • POST /delete/<filename> - Delete recording
  • POST /restore_default_sound - Generate default dial tone

Contributing

Feel free to open issues or submit pull requests for improvements.

License

This project is open source and available for personal and commercial use.

Credits

Created for wedding events to capture guest messages in a unique, nostalgic way.

Support

For issues or questions, please open an issue on the repository.

Description
No description provided
Readme 831 KiB
Languages
Python 88.1%
Shell 11.1%
Makefile 0.8%