Files
wedding-phone/README.md
grabowski 3b08c5f88b Fix greeting delay slider not appearing in web interface
- Delete old templates directory to force regeneration
- Templates are auto-generated on first run only
- Add note to README about regenerating templates
- Solution: Delete templates/ and restart script to get new features

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 15:39:17 +07:00

419 lines
12 KiB
Markdown

# 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
- **Extra Button Support**: Optional GPIO button to play custom sounds on demand
- **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
```bash
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:
```bash
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)
```bash
# 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
```bash
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:
```bash
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:
```bash
cp config.example.json config.json
nano config.json # or use your preferred editor
```
**Important settings to configure:**
```json
{
"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:**
```bash
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
```bash
python3 test_complete.py
```
This will test:
- Speaker playback
- Dial tone generation
- Microphone recording
### 7. Run the System
```bash
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
- **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
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
### Extra Button Operation (Optional)
If enabled in `config.json`:
1. **Guest picks up phone**: Phone goes off-hook
2. **Guest presses button**: System detects GPIO signal (only works when off-hook)
3. **Sound plays**: Configured button sound plays through speaker
4. **Can be pressed multiple times**: Works during greeting or recording
5. **Debounced**: 0.5s delay prevents accidental double-presses
**Note:** Button only responds when handset is off-hook (during active call)
### Greeting Delay (Optional)
Configure a delay before the greeting plays:
- Set `greeting_delay_seconds` in `config.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)
## 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)
```
**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:
```json
{
"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
},
"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:
```bash
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:
```bash
aplay -l # List audio devices
amixer -c 3 sset Digital 100% # Set volume (adjust card number)
```
2. Test speaker directly:
```bash
speaker-test -D plughw:3,0 -c 1 -t wav
```
3. Run the complete test:
```bash
python3 test_complete.py
```
### Microphone Not Recording
1. Check microphone is connected to HiFiBerry input
2. Adjust input gain:
```bash
alsamixer -c 3
```
3. Test recording:
```bash
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:
```python
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:
```bash
sudo nano /etc/systemd/system/wedding-phone.service
```
Add (replace `/path/to/wedding-phone` with your actual path):
```ini
[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:
```bash
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.