Files
wedding-phone/README.md
grabowski d07cb82772 Add USB backup system with CRC32 verification
**USB Backup Features:**
- Automatic backup to multiple USB drives
- CRC32 checksum verification for data integrity
- Configurable backup paths in config.json
- Backup on write (recordings and greeting uploads)
- Corrupted backups automatically deleted
- Web interface for monitoring and testing

**Configuration:**
- Added backup section to config.example.json
- enabled: Enable/disable USB backup
- usb_paths: Array of USB mount points
- verify_crc: Enable CRC32 verification
- backup_on_write: Backup immediately after file write

**CRC32 Implementation:**
- calculate_crc32(): Compute file checksum
- 64KB chunk reading for memory efficiency
- Source and destination file verification
- Automatic cleanup of failed copies

**Backup Functions:**
- backup_file_to_usb(): Backup with verification
- get_usb_backup_status(): Check drive status
- Mount detection, write test, free space check
- Preserves directory structure on USB

**Web Interface:**
- USB Backup card with drive status display
- Green/Yellow/Red status indicators
- Free space monitoring
- Test backup button
- Real-time status refresh
- Detailed error reporting

**Integration:**
- Recordings backed up after save
- Greetings backed up after upload
- Backup results logged to console
- Non-blocking backup execution

**API Endpoints:**
- GET /api/backup/status - Drive status
- POST /api/backup/test - Test backup

**Documentation:**
- Complete USB backup guide in README
- Mount instructions for USB drives
- CRC verification explanation
- Backup directory structure
- Web interface usage guide

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 16:28:32 +07:00

495 lines
15 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 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.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, greeting plays
2. **Recording starts**: After greeting finishes
3. **Guest presses button**: System detects GPIO signal (only works during recording)
4. **Sound plays**: Configured button sound plays through speaker
5. **Can be pressed multiple times**: Works throughout the recording phase
6. **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_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)
### USB Backup (Optional)
Automatically backup all recordings and greeting files to USB drives:
**Configuration** (`config.json`):
```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:**
1. Recording finishes or greeting uploaded
2. File saved to main storage
3. CRC32 checksum calculated for source file
4. File copied to each USB drive
5. CRC32 checksum verified on each copy
6. Corrupted copies deleted automatically
7. Success/failure logged to console
**Mount USB Drives:**
```bash
# Create mount points
sudo mkdir -p /media/usb0 /media/usb1
# Auto-mount in /etc/fstab (example)
UUID=XXXX-XXXX /media/usb0 vfat defaults,nofail 0 0
UUID=YYYY-YYYY /media/usb1 vfat defaults,nofail 0 0
# Or mount manually
sudo mount /dev/sda1 /media/usb0
sudo mount /dev/sdb1 /media/usb1
```
## 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
},
"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:
```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.