**CHANGELOG.md Created:** - Complete version history from 1.0.0 to 1.2.0 - Detailed changelog with all features, changes, fixes - API endpoints documentation - Configuration changes documentation - Upgrade notes from 1.0.0 to 1.2.0 - Known issues and future enhancements **README.md Enhanced:** - Added Quick Start section at top - Added comprehensive Table of Contents - Updated Python version requirement (3.7 -> 3.8) - Added UV and Make to software requirements - Added new API endpoints (backup, delay) - Expanded Contributing section with guidelines - Added Version History section (current: v1.2.0) - Enhanced License section with clear permissions - Added Credits and Technologies Used sections - Added Support & Community section - Added proper closing with emoji - Updated file structure with CHANGELOG.md - Better file descriptions in structure **Documentation Improvements:** - Clear upgrade path from 1.0.0 to 1.2.0 - All new features documented - All configuration changes documented - Better organization with TOC - More professional presentation - Complete feature list - Development guidelines for contributors **Version Information:** - Current version: 1.2.0 - Major features: USB backup, systemd service, UV support - Breaking changes: Python 3.8+ required - New scripts: setup_usb.sh, install_service.sh - New commands: make start, make test, make sync **Key Highlights:** - ✅ Professional documentation structure - ✅ Easy to navigate with TOC - ✅ Quick Start for new users - ✅ Complete changelog for upgrading - ✅ Clear contribution guidelines - ✅ Proper version tracking 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
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.
Quick Start
# 1. Clone and enter directory
git clone https://git.b4l.co.th/grabowski/wedding-phone.git
cd wedding-phone
# 2. Install UV package manager
curl -LsSf https://astral.sh/uv/install.sh | sh
# 3. Create config from example
cp config.example.json config.json
nano config.json # Edit GPIO pins and audio device
# 4. Install dependencies
make sync
# 5. Configure HiFiBerry (if using)
./configure_hifiberry.sh
# 6. Test audio
make test
# 7. Run the system
make start
# 8. Optional: Install as service for auto-start
./install_service.sh
# 9. Optional: Setup USB backup
sudo ./setup_usb.sh
Web interface available at: http://<raspberry-pi-ip>:8080
Table of Contents
- Quick Start
- Features
- Hardware Requirements
- Software Requirements
- Installation
- Running the System
- Usage
- Configuration
- Systemd Service
- Troubleshooting
- API Endpoints
- File Structure
- Contributing
- License
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
- Extra Button Support: Optional GPIO button to play custom sounds during recording
- USB Backup: Automatic backup to multiple USB drives with CRC32 verification
- Data Integrity: Every file write is verified with CRC checksums
- 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.8+ (required for Flask 2.3+)
- UV package manager (recommended) or pip
- Make (for simplified commands)
- Required Python packages:
- flask>=2.3.0
- numpy>=1.21.0
- pyaudio>=0.2.13
- RPi.GPIO>=0.7.1
Installation
1. Clone the Repository
git clone https://git.b4l.co.th/grabowski/wedding-phone.git
cd wedding-phone
2. Install UV (Recommended)
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
Option A: Using UV (Recommended)
# Install system dependencies
sudo apt-get update
sudo apt-get install -y python3-pyaudio portaudio19-dev
# Install Python dependencies with UV
make sync
# Or manually:
# uv pip install flask numpy pyaudio RPi.GPIO
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"
"extra_button_enabled": true, // Enable extra button feature
"extra_button_pin": 27, // GPIO pin for extra button
"extra_button_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
Option A: Using Make (Recommended)
# Run the wedding phone system
make start
# Or run the audio test
make test
Option B: Using UV Directly
# Run the wedding phone system
uv run python rotary_phone_web.py
# Or run the audio test
uv run python test_complete.py
Option C: Run with Python
python3 rotary_phone_web.py
The web interface will be available at:
http://localhost:8080http://<raspberry-pi-ip>:8080
8. Install as System Service (Optional)
To run the wedding phone automatically on boot:
# Run the installer script
./install_service.sh
The installer will:
- Check dependencies
- Install the systemd service
- Configure for your user and project path
- Optionally enable and start the service
Manual service commands:
# Enable service to start on boot
sudo systemctl enable wedding-phone
# Start service now
sudo systemctl start wedding-phone
# Stop service
sudo systemctl stop wedding-phone
# Restart service
sudo systemctl restart wedding-phone
# View logs (live)
sudo journalctl -u wedding-phone -f
# View status
sudo systemctl status wedding-phone
# Disable service
sudo systemctl disable wedding-phone
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
- Set Button: Click "🔘 Set Button" to assign sound to extra button (if enabled)
- 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
- Guest picks up phone: System detects via GPIO
- Greeting plays: Active greeting message plays through speaker
- Recording starts: After greeting, system records guest message
- Guest hangs up: Recording stops and saves automatically
- Ready for next call: System returns to waiting state
Extra Button Operation (Optional)
If enabled in config.json:
- Guest picks up phone: Phone goes off-hook, greeting plays
- Recording starts: After greeting finishes
- Guest presses button: System detects GPIO signal (only works during recording)
- Sound plays: Configured button sound plays through speaker
- Can be pressed multiple times: Works throughout the recording phase
- Debounced: 0.5s delay prevents accidental double-presses
Note: Button only responds during the recording phase (not during greeting or when on-hook)
Greeting Delay (Optional)
Configure a delay before the greeting plays:
- Set
greeting_delay_secondsinconfig.json(0-10 seconds) - Useful for giving guests a moment after picking up
- Example: 2 second delay gives time to position the phone
- Default: 0 (greeting plays immediately)
USB Backup (Optional)
Automatically backup all recordings and greeting files to USB drives:
Configuration (config.json):
{
"backup": {
"enabled": true,
"usb_paths": [
"/media/usb0",
"/media/usb1"
],
"verify_crc": true,
"backup_on_write": true
}
}
Features:
- Multiple USB Drives: Backup to one or more USB drives simultaneously
- CRC32 Verification: Every backup is verified with CRC checksum
- Automatic Backup: Files are backed up immediately after recording/upload
- Integrity Check: Corrupted backups are automatically deleted
- Web Monitoring: View USB drive status, free space, and test backups
Web Interface:
- Monitor USB drive status (mounted, writable, free space)
- Test backup functionality with one click
- View real-time backup results
- Green = Ready, Yellow = Not Writable, Red = Not Mounted
Backup Structure:
/media/usb0/
└── wedding-phone-backup/
├── recordings/
│ ├── recording_20250124_143022.wav
│ └── recording_20250124_143145.wav
└── sounds/
├── dialtone.wav
└── greeting.wav
How It Works:
- Recording finishes or greeting uploaded
- File saved to main storage
- CRC32 checksum calculated for source file
- File copied to each USB drive
- CRC32 checksum verified on each copy
- Corrupted copies deleted automatically
- Success/failure logged to console
Mount USB Drives with Proper Permissions:
Automated Setup (Easiest):
# Run the USB setup script
sudo ./setup_usb.sh
This interactive script will:
- Detect your USB devices
- Mount them with proper user permissions
- Test write access
- Optionally add to /etc/fstab for auto-mounting
Option 1: Mount with user permissions (Recommended)
# Find your USB device
lsblk
# Create mount point
sudo mkdir -p /media/usb0
# Mount with user ownership (replace $USER with your username if needed)
sudo mount -o uid=$(id -u),gid=$(id -g) /dev/sda1 /media/usb0
# Verify it's writable
touch /media/usb0/test.txt && rm /media/usb0/test.txt
Option 2: Auto-mount in /etc/fstab with user permissions
# Get USB UUID
sudo blkid /dev/sda1
# Edit fstab
sudo nano /etc/fstab
# Add line (replace UUID and username):
UUID=XXXX-XXXX /media/usb0 vfat defaults,nofail,uid=1000,gid=1000 0 0
# Note: uid=1000 is usually the first user, check with: id -u
Option 3: Change ownership after mounting
# Mount normally
sudo mount /dev/sda1 /media/usb0
# Change ownership (replace with your username)
sudo chown -R $USER:$USER /media/usb0
Quick Setup Script:
#!/bin/bash
# setup_usb.sh - Mount USB drives with proper permissions
# Create mount points
sudo mkdir -p /media/usb0 /media/usb1
# Mount USB drives with user ownership
sudo mount -o uid=$(id -u),gid=$(id -g) /dev/sda1 /media/usb0
sudo mount -o uid=$(id -u),gid=$(id -g) /dev/sdb1 /media/usb1
echo "USB drives mounted!"
ls -la /media/usb0 /media/usb1
File Structure
wedding-phone/
├── rotary_phone_web.py # Main application (Flask + GPIO + Audio)
├── test_complete.py # Audio testing script
├── configure_hifiberry.sh # HiFiBerry DAC+ADC setup script
├── install_service.sh # Systemd service installer (interactive)
├── setup_usb.sh # USB drive setup with permissions (interactive)
├── wedding-phone.service # Systemd service file template
├── Makefile # Make commands (start, test, sync, clean)
├── config.example.json # Example configuration (copy to config.json)
├── pyproject.toml # Python package configuration
├── AUDIO_FIX.md # Audio troubleshooting guide
├── CHANGELOG.md # Version history and upgrade notes
├── README.md # This file (main documentation)
├── .gitignore # Git ignore rules
└── templates/ # Auto-generated on first run
└── index.html # Web interface (auto-generated from script)
Note: The templates/index.html file is automatically generated when you first run rotary_phone_web.py. If you update the script and want to regenerate the template with new features, simply delete the templates directory and restart the 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
"extra_button_enabled": true, // Enable optional extra button
"extra_button_pin": 27, // GPIO pin for extra button
"extra_button_pressed_state": "LOW" // Button pressed state
},
"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
},
"backup": {
"enabled": true, // Enable USB backup
"usb_paths": ["/media/usb0", "/media/usb1"], // USB mount points
"verify_crc": true, // Verify backups with CRC32
"backup_on_write": true // Backup immediately after write
},
"web": {
"port": 8080, // Web interface port
"max_upload_size_mb": 50 // Max upload file size
},
"system": {
"active_greeting": "dialtone.wav", // Default greeting
"extra_button_sound": "button_sound.wav", // Default button sound
"greeting_delay_seconds": 0, // Delay before greeting plays (0-10)
"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
-
Check HiFiBerry configuration:
aplay -l # List audio devices amixer -c 3 sset Digital 100% # Set volume (adjust card number) -
Test speaker directly:
speaker-test -D plughw:3,0 -c 1 -t wav -
Run the complete test:
python3 test_complete.py
Microphone Not Recording
- Check microphone is connected to HiFiBerry input
- Adjust input gain:
alsamixer -c 3 - Test recording:
arecord -D plughw:3,0 -f cd test.wav -d 5 aplay test.wav
GPIO Not Detecting Hookswitch
- Verify GPIO pin number in
config.json - Check if switch is normally open or closed
- Update
hook_pressed_stateinconfig.json("LOW" or "HIGH") - 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
- Check if Flask is running:
ps aux | grep python - Verify port in
config.jsonmatches URL - Check firewall:
sudo ufw allow 8080(or your configured port) - Check IP address:
hostname -I - Try localhost:
http://127.0.0.1:8080
Configuration Errors
If the script won't start:
- Ensure
config.jsonexists (copy fromconfig.example.json) - Validate JSON syntax:
python3 -m json.tool config.json - Check all paths exist or can be created
- Verify audio device index is correct
API Endpoints
The system provides REST API endpoints:
GET /- Web interfaceGET /api/status- Phone status JSONGET /api/recordings- List all recordingsGET /api/greetings- List all greeting messagesGET /api/volume- Get current volume settingPOST /api/volume- Set volume level (0-100)POST /upload_greeting- Upload new greetingPOST /set_active_greeting- Set active greetingPOST /delete_greeting/<filename>- Delete greetingGET /play_audio/<type>/<filename>- Stream audio fileGET /download/<filename>- Download recordingPOST /delete/<filename>- Delete recordingPOST /restore_default_sound- Generate default dial toneGET /api/backup/status- Get USB backup drive statusPOST /api/backup/test- Test backup to all USB drivesGET /api/greeting_delay- Get current greeting delayPOST /api/greeting_delay- Set greeting delay (0-10 seconds)
Contributing
Contributions are welcome! Here's how you can help:
- Report Bugs: Open an issue describing the bug and how to reproduce it
- Suggest Features: Open an issue describing your feature idea
- Submit Pull Requests: Fork the repo, make changes, and submit a PR
- Improve Documentation: Help make the docs clearer and more complete
- Share Your Experience: Post photos/videos of your wedding phone setup!
Development Guidelines
- Follow existing code style
- Test your changes thoroughly
- Update documentation for new features
- Add entries to CHANGELOG.md
- Use descriptive commit messages
Version History
See CHANGELOG.md for detailed version history and upgrade notes.
Current Version: 1.2.0
Major Updates:
- ✅ USB backup with CRC verification
- ✅ Systemd service support
- ✅ UV package manager integration
- ✅ Greeting delay control
- ✅ Extra button support
- ✅ Immediate hook detection
- ✅ Configurable everything (no hardcoded paths)
License
This project is open source and available for personal and commercial use.
License: MIT License
Feel free to:
- ✅ Use for personal projects
- ✅ Use for commercial events
- ✅ Modify and customize
- ✅ Redistribute with attribution
Credits
Created by: grabowski Purpose: Capture guest messages at weddings and events in a unique, nostalgic way Inspired by: Vintage telephone systems and the desire to preserve wedding memories
Technologies Used
- Python 3.8+
- Flask web framework
- PyAudio for audio handling
- RPi.GPIO for hardware control
- UV package manager
- HiFiBerry DAC+ADC Pro
- Systemd for service management
Support & Community
- Issues: GitHub Issues
- Documentation: This README and CHANGELOG.md
- Repository: https://git.b4l.co.th/grabowski/wedding-phone
Acknowledgments
Thanks to everyone who has contributed ideas, bug reports, and improvements to make this project better!
Made with ❤️ for preserving wedding memories 🎉📞💍