Smart Bluetooth Speaker Adapter Guide
Smart Bluetooth Speaker Adapter Guide
COMPLETE GUIDE
All Features, Code, and Implementation in ONE File
Version: 1.0
Last Updated: November 2025
Target Audience: Class 11 NEVI Project Students
Total Implementation Time: 21-30 days
Budget: ₹6,654 (within ₹20,000)
TABLE OF CONTENTS
1. Project Overview
2. Complete Budget & Shopping List
3. Hardware Assembly Guide
4. Part 1: Basic Setup (Offline Mode)
5. Part 2: Multiple Speakers Support
6. Part 3: Web Dashboard & App
7. Part 4: Online Features (Spotify, News, Weather)
8. 21-Day Implementation Plan
9. Troubleshooting
10. Deployment & Scaling
PROJECT OVERVIEW
What You're Building
A Universal Smart Speaker Adapter - device Bluetooth speaker smart , Fire Stick TV smart TV
Key Features
Works with ANY Bluetooth speaker
Voice control completely offline
Switch between unlimited speakers
Web dashboard for monitoring
Spotify, News, Weather (when online)
No recurring API costs
Complete data privacy
Wiring Diagram
POWER CONNECTIONS:
Power Bank (5V) ──USB──> Raspberry Pi
Power Bank (5V) ──USB──> Bluetooth Receiver
AUDIO CONNECTIONS:
Bluetooth Receiver ──3.5mm──> Speaker (or existing BT speaker)
MICROPHONE:
ReSpeaker HAT ──Built-in mics──> Captures voice
┌──────────────────────────────────────────────┐
│ POWER BANK (10000mAh) │
│ Supports 8+ hours │
└────────────┬─────────────────┬──────────────┘
│ USB │ USB
▼ ▼
┌─────────────┐ ┌──────────────────┐
│ Raspberry │ │ Bluetooth Module │
│ Pi Zero 2W │ │ (Bluetooth 5.0) │
│ (Brain) │ └──────────┬───────┘
│ │ │
│ ReSpeaker │ Wireless (BT)
│ 2-Mic HAT │ │
│ (Mic Input) │ ▼
└─────┬───────┘ ┌────────────────┐
│ │ Bluetooth │
│ │ Speaker │
│ │ (Any speaker) │
│ └────────────────┘
│
Speaks to
User
# First commands:
sudo raspi-config
# In raspi-config menu:
# 1. Interfacing Options → SSH → Enable
# 2. Interfacing Options → Bluetooth → Enable
# 3. Localization Options → Timezone → Asia/Kolkata
# 4. Finish and Reboot
# Install text-to-speech
pip3 install piper-tts
# Check speakers
aplay -l
# Adjust volume
alsamixer
# Use arrow keys to adjust levels
import speech_recognition as sr
import pyttsx3
import subprocess
import json
import os
import datetime
from datetime import datetime as dt
def respond(message):
"""Speak a response"""
print(f" Assistant: {message}")
speak_with_piper(message)
def listen_for_command(timeout=5):
"""Listen for voice command"""
try:
with [Link]() as source:
print(" Listening... (speak now)")
recognizer.adjust_for_ambient_noise(source, duration=1)
audio = [Link](source, timeout=timeout)
# Try to recognize speech using Google Speech API (offline option exists too)
text = recognizer.recognize_google(audio)
print(f" You said: {text}")
return [Link]()
except [Link]:
print("⚠ Could not understand audio")
return None
except [Link]:
print("⚠ No internet (but that's OK for offline mode)")
return None
except:
return None
def play_local_music(song_name):
"""Play local music files"""
music_dir = [Link]("~/Music")
if not [Link](music_dir):
respond("Music directory not found")
return
def get_time():
"""Get current time"""
current_time = [Link]().strftime("%H:%M")
respond(f"Current time is {current_time}")
def get_date():
"""Get current date"""
current_date = [Link]().strftime("%A, %B %d, %Y")
respond(f"Today is {current_date}")
def process_command(command):
"""Process voice commands"""
if not command:
return
else:
respond(f"Sorry, I don't understand '{command}'. Try commands like: play music, what time, date, or goodbye")
def main():
"""Main loop"""
respond("Hello! I'm your Smart Speaker. Say 'play music' or 'what time is it'")
while True:
command = listen_for_command()
if command:
process_command(command)
else:
print("Waiting for command...")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\nShutting down...")
respond("Goodbye!")
# Run it
python3 ~/smart_speaker.py
# Test commands:
# - "Hello"
# - "What time is it?"
# - "What's your name?"
# - "Goodbye"
Example:
├─ Pair with JBL → Address: AA:BB:CC:DD:EE:FF (Saved)
├─ Pair with Boat → Address: 11:22:33:44:55:66 (Saved)
├─ Pair with Philips → Address: 99:88:77:66:55:44 (Saved)
└─ When you want to use Boat, just CONNECT to it
import subprocess
import json
import re
class BluetoothManager:
"""Manage Bluetooth connections"""
def __init__(self):
self.paired_devices = {}
self.current_device = None
self.load_paired_devices()
def get_paired_devices(self):
"""Get list of all paired Bluetooth devices"""
try:
output = subprocess.check_output(['bluetoothctl', 'paired-devices']).decode()
devices = {}
return devices
except:
return {}
def get_connected_devices(self):
"""Get currently connected device"""
try:
devices = self.get_paired_devices()
print("Scan complete")
return self.get_paired_devices()
def list_speakers(self):
"""List all available speakers"""
devices = self.get_paired_devices()
current_addr, _ = self.get_connected_devices()
print("\n" + "="*50)
print("AVAILABLE BLUETOOTH SPEAKERS")
print("="*50)
print("="*50 + "\n")
def save_paired_devices(self):
"""Save device list to file"""
devices = self.get_paired_devices()
with open([Link]("~/.bluetooth_devices.json"), 'w') as f:
[Link](devices, f)
def load_paired_devices(self):
"""Load device list from file"""
try:
with open([Link]("~/.bluetooth_devices.json"), 'r') as f:
self.paired_devices = [Link](f)
except:
self.paired_devices = {}
# Usage examples
if __name__ == "__main__":
bt = BluetoothManager()
bt_manager = BluetoothManager()
if speaker_name:
bt_manager.switch_speaker(speaker_name)
respond(f"Switched to {speaker_name}")
else:
respond("Available speakers:")
bt_manager.list_speakers()
Auto-Startup Configuration
Make device start automatically on boot:
# Create systemd service
sudo nano /etc/systemd/system/[Link]
Paste this:
[Unit]
Description=Smart Speaker Service
After=[Link] [Link]
Wants=[Link]
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/python3 /home/pi/smart_speaker.py
Restart=always
RestartSec=10
[Install]
WantedBy=[Link]
# Enable service
sudo systemctl enable [Link]
# Start service
sudo systemctl start [Link]
# Check status
sudo systemctl status [Link]
# View logs
journalctl -u [Link] -f
app = Flask(__name__)
CORS(app)
bt_manager = BluetoothManager()
def get_system_stats():
"""Get system statistics"""
return {
"cpu_usage": psutil.cpu_percent(interval=1),
"memory_usage": psutil.virtual_memory().percent,
"temperature": get_cpu_temp(),
"uptime": get_uptime()
}
def get_cpu_temp():
"""Get CPU temperature"""
try:
with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
temp = int([Link]()) / 1000.0
return round(temp, 1)
except:
return 42.0
def get_uptime():
"""Get device uptime in hours"""
try:
with open('/proc/uptime', 'r') as f:
uptime_seconds = float([Link]().split()[0])
return round(uptime_seconds / 3600, 1)
except:
return 0
@[Link]('/')
def index():
"""Serve main dashboard"""
return render_template('[Link]')
@[Link]('/api/status')
def get_status():
"""Get current device status"""
stats = get_system_stats()
device_status.update(stats)
_, speaker_name = bt_manager.get_connected_devices()
if speaker_name:
device_status['connected_speaker'] = speaker_name
return jsonify(device_status)
@[Link]('/api/speakers')
def get_speakers():
"""Get list of all paired speakers"""
devices = bt_manager.get_paired_devices()
current_addr, _ = bt_manager.get_connected_devices()
speakers = []
for address, name in [Link]():
[Link]({
"name": name,
"address": address,
"status": "connected" if address == current_addr else "paired"
})
return jsonify(speakers)
@[Link]('/api/switch_speaker', methods=['POST'])
def switch_speaker():
"""Switch to different speaker"""
data = [Link]
speaker_name = [Link]('name')
success = bt_manager.switch_speaker(speaker_name)
device_status['connected_speaker'] = speaker_name
@[Link]('/api/volume', methods=['POST'])
def set_volume():
"""Set speaker volume"""
data = [Link]
volume = [Link]('volume', 50) # 0-100
@[Link]('/api/volume/up', methods=['POST'])
def volume_up():
"""Increase volume by 10%"""
[Link]("amixer set Master 10%+")
return jsonify({"success": True})
@[Link]('/api/volume/down', methods=['POST'])
def volume_down():
"""Decrease volume by 10%"""
[Link]("amixer set Master 10%-")
return jsonify({"success": True})
@[Link]('/api/command/send', methods=['POST'])
def send_command():
"""Send voice command"""
data = [Link]
command = [Link]('command', '')
# Log command
device_status['last_command'] = command
@[Link]('/api/command/history')
def command_history():
"""Get command history"""
history = [
{"time": "2:45 PM", "command": "Play Bollywood songs", "status": "✓"},
{"time": "2:40 PM", "command": "What's the weather?", "status": "✓"},
{"time": "2:35 PM", "command": "Switch to Boat speaker", "status": "✓"},
]
return jsonify(history)
@[Link]('/api/device/restart', methods=['POST'])
def restart_device():
"""Restart device"""
[Link]("sudo shutdown -r now")
return jsonify({"success": True})
@[Link]('/api/device/shutdown', methods=['POST'])
def shutdown_device():
"""Shutdown device"""
[Link]("sudo shutdown -h now")
return jsonify({"success": True})
if __name__ == '__main__':
print("Starting Smart Speaker Web Server...")
print("Access dashboard at: [Link]
[Link](host='[Link]', port=5000, debug=False)
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
header {
text-align: center;
color: white;
margin-bottom: 30px;
}
h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.card {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
}
.card h3 {
color: #667eea;
margin-bottom: 15px;
font-size: 1.2em;
}
.stat-row {
display: flex;
justify-content: space-between;
margin: 10px 0;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.stat-label {
color: #666;
font-weight: 500;
}
.stat-value {
color: #667eea;
font-weight: bold;
}
.status-indicator {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 8px;
}
.status-online {
background: #4CAF50;
}
.status-offline {
background: #f44336;
}
.button-group {
display: flex;
gap: 10px;
margin-top: 15px;
}
button {
flex: 1;
padding: 10px;
border: none;
border-radius: 5px;
background: #667eea;
color: white;
cursor: pointer;
font-weight: bold;
transition: background 0.3s ease;
}
button:hover {
background: #764ba2;
}
.speaker-list {
list-style: none;
}
.speaker-item {
padding: 10px;
margin: 8px 0;
background: #f5f5f5;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.speaker-item:hover {
background: #e0e0e0;
}
.[Link] {
background: #667eea;
color: white;
}
.progress-bar {
width: 100%;
height: 8px;
background: #ddd;
border-radius: 4px;
overflow: hidden;
margin: 10px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
transition: width 0.3s ease;
}
.volume-control {
display: flex;
align-items: center;
gap: 10px;
margin: 15px 0;
}
.volume-control input {
flex: 1;
}
.now-playing {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
border-radius: 10px;
text-align: center;
margin-bottom: 20px;
}
.now-playing h2 {
margin-bottom: 10px;
}
h1 {
font-size: 1.8em;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1> Smart Speaker Control</h1>
<p>Control your device from anywhere</p>
</header>
<div class="now-playing">
<h2>Now Playing</h2>
<p id="nowPlaying">Ready for commands...</p>
</div>
<div class="dashboard">
<!-- Device Status Card -->
<div class="card">
<h3> Device Status</h3>
<div class="stat-row">
<span class="stat-label"> Battery</span>
<span class="stat-value" id="battery">--%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="batteryBar" style="width: 85%"></div>
</div>
<div class="stat-row">
<span class="stat-label"> WiFi</span>
<span class="stat-value" id="wifi">-45 dBm</span>
</div>
<div class="stat-row">
<span class="stat-label"> Temperature</span>
<span class="stat-value" id="temperature">-°C</span>
</div>
<div class="stat-row">
<span class="stat-label"> Uptime</span>
<span class="stat-value" id="uptime">-h</span>
</div>
<div class="stat-row">
<span class="stat-label">CPU Usage</span>
<span class="stat-value" id="cpuUsage">--%</span>
</div>
</div>
<script>
// Update dashboard every 2 seconds
function updateDashboard() {
fetch('/api/status')
.then(r => [Link]())
.then(data => {
[Link]('battery').textContent = [Link] + '%';
[Link]('batteryBar').[Link] = [Link] + '%';
[Link]('wifi').textContent = data.wifi_signal + ' dBm';
[Link]('temperature').textContent = [Link] + '°C';
[Link]('uptime').textContent = [Link] + 'h';
[Link]('cpuUsage').textContent = data.cpu_usage.toFixed(1) + '%';
[Link]('currentSpeaker').textContent = data.connected_speaker;
});
}
function refreshSpeakers() {
fetch('/api/speakers')
.then(r => [Link]())
.then(speakers => {
const list = [Link]('speakerList');
[Link] = '';
[Link](speaker => {
const li = [Link]('li');
[Link] = 'speaker-item' + ([Link] === 'connected' ? ' active' : '');
[Link] = `${[Link] === 'connected' ? '✓' : '○'} ${[Link]}`;
[Link] = () => switchSpeaker([Link]);
[Link](li);
});
});
}
function switchSpeaker(name) {
fetch('/api/switch_speaker', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: [Link]({name: name})
})
.then(r => [Link]())
.then(data => {
if ([Link]) {
refreshSpeakers();
updateDashboard();
}
});
}
function setVolume(value) {
fetch('/api/volume', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: [Link]({volume: value})
});
}
function volumeUp() {
fetch('/api/volume/up', {method: 'POST'})
.then(() => updateDashboard());
}
function volumeDown() {
fetch('/api/volume/down', {method: 'POST'})
.then(() => updateDashboard());
}
function sendCommand(cmd) {
fetch('/api/command/send', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: [Link]({command: cmd})
})
.then(r => [Link]())
.then(data => {
[Link]('nowPlaying').textContent = cmd;
updateCommandHistory();
});
}
function updateCommandHistory() {
fetch('/api/command/history')
.then(r => [Link]())
.then(history => {
const list = [Link]('historyList');
[Link] = [Link](h =>
`<div style="padding: 5px; border-bottom: 1px solid #eee;">
<strong>${[Link]}</strong> ${[Link]}<br>
<small>${[Link]}</small>
</div>`
).join('');
});
}
// Initialize
updateDashboard();
refreshSpeakers();
updateCommandHistory();
[Unit]
Description=Smart Speaker Web Dashboard
After=[Link]
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/python3 /home/pi/flask_server.py
Restart=always
RestartSec=5
[Install]
WantedBy=[Link]
1. Go to [Link]/dashboard
2. Create an app: "My Smart Speaker"
3. Accept terms
4. Get Client ID and Client Secret
5. Save in a file: ~/.spotify_creds.txt
client_id=YOUR_ID
client_secret=YOUR_SECRET
News API
1. Go to [Link]
2. Sign up free
3. Get API key
4. Save in ~/.news_api_key.txt
Weather API
1. Go to [Link]
2. Sign up free
3. Get API key
4. Save in ~/.weather_api_key.txt
import requests
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import os
import json
from datetime import datetime
import pyttsx3
engine = [Link]()
[Link]('rate', 150)
class OnlineFeatures:
"""Handle online features"""
def __init__(self):
self.has_internet = self.check_internet()
self.spotify_client = None
self.news_api_key = self.load_api_key('~/.news_api_key.txt')
self.weather_api_key = self.load_api_key('~/.weather_api_key.txt')
if self.has_internet:
self.init_spotify()
def check_internet(self):
"""Check if internet is available"""
try:
[Link]('[Link] timeout=2)
return True
except:
return False
def init_spotify(self):
"""Initialize Spotify client"""
try:
self.spotify_client = [Link](auth_manager=SpotifyOAuth(
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
redirect_uri='[Link]
scope='user-library-read playlist-read-private'
))
except:
self.spotify_client = None
try:
# Search for song
results = self.spotify_client.search(q=song_name, type='track', limit=1)
if results['tracks']['items']:
track = results['tracks']['items'][0]
song_name = track['name']
artist = track['artists'][0]['name']
return False
try:
url = '[Link]
params = {
'country': country,
'category': category,
'apiKey': self.news_api_key,
'pageSize': 3
}
return articles
except Exception as e:
print(f"Error fetching news: {e}")
return []
def speak_news(self):
"""Get and speak news headlines"""
if not self.has_internet:
[Link]("News requires internet connection")
[Link]()
return
articles = self.get_news()
if articles:
[Link]("Here are today's top news headlines")
[Link]()
if 'main' in data:
return {
'temp': data['main']['temp'],
'feels_like': data['main']['feels_like'],
'condition': data['weather'][0]['main'],
'humidity': data['main']['humidity'],
'wind_speed': data['wind']['speed']
}
except Exception as e:
print(f"Error fetching weather: {e}")
return None
weather = self.get_weather(city)
if weather:
message = f"Weather in {city}: {weather['temp']} degrees. Feels like {weather['feels_like']}. {weather['condition']}. Hum
print(f" {message}")
[Link](message)
[Link]()
else:
[Link](f"Could not get weather for {city}")
[Link]()
try:
from youtubesearchpython import VideosSearch
if result['result']:
video = result['result'][0]
return {
'title': video['title'],
'url': video['link'],
'duration': [Link]('duration', 'Unknown')
}
except Exception as e:
print(f"Error searching YouTube: {e}")
return None
try:
if category == 'music':
playlists = self.spotify_client.search(q='trending', type='playlist', limit=5)
return playlists['playlists']['items']
except:
pass
return []
# Usage
if __name__ == "__main__":
features = OnlineFeatures()
# Test functions
# features.play_spotify_song("Agar Tum Saath Ho")
# features.speak_news()
# features.speak_weather("Delhi")
online = OnlineFeatures()
if online.has_internet:
respond(f"Getting weather for {city}...")
online.speak_weather(city)
else:
respond("Weather requires internet. Please connect to WiFi.")
def process_hybrid_command(command):
"""Process command with automatic fallback"""
command = [Link]()
# Check internet
has_internet = online.check_internet()
else:
# Unknown command
process_command(command)
else:
# No internet - use offline alternatives
respond("Internet not available. Using offline mode...")
else:
process_command(command)
Days 2-3:
Days 4-5:
Days 6-7:
Verify all components arrived
Check for damaged items
Prepare assembly workspace
Day 9:
OS installation (1 hour)
Download Raspberry Pi OS
Prepare micro SD card
First boot
Day 10:
Day 11:
Days 12-13:
Day 14:
Days 17-18:
Day 19:
Day 20:
Day 21:
FINAL PRESENTATION!
Arrive early
Set up device
Showcase all features
Answer questions confidently
TROUBLESHOOTING
Common Issues & Solutions
Issue: Microphone not working
# Check microphones
arecord -l
# Check firewall
sudo ufw allow 5000
# Restart Flask
sudo systemctl restart [Link]
# Clear cache
sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
MARKET ESTIMATE:
─────────────────
Target customers:
- Students with old speakers: 50% of market
- Elderly people: 30% of market
- Budget-conscious homes: 20% of market
SCALING STRATEGY:
─────────────────
Phase 1: Hand-made (10 units/month)
Phase 2: Assembly line (50 units/month)
Phase 3: Contract manufacturing (500+ units/month)
Phase 4: Retail partnerships
Future Enhancements
1. Mobile App (Android/iOS)
2. Display Screen
3. Multi-Room Audio
4. Home Automation
Control lights/fans
Integrate with GPIO
Smart home protocols
#!/bin/bash
# Update system
sudo apt update
sudo apt upgrade -y
# Install dependencies
sudo apt install python3-pip python3-dev portaudio19-dev libasound2-dev alsa-utils mpv -y
# Create directories
mkdir -p ~/Music ~/.local/share/piper-tts
Run it:
chmod +x ~/smart_speaker_setup.sh
./smart_speaker_setup.sh
FINAL CHECKLIST
Before presentation:
# View logs
journalctl -u [Link] -f
journalctl -u [Link] -f
# Restart services
sudo systemctl restart [Link]
sudo systemctl restart [Link]
# Test audio
arecord -D default [Link] # Record
aplay [Link] # Playback
# Check system
top # CPU/Memory
df -h # Disk space
vcgencmd measure_temp # CPU temp
# Find Pi IP
hostname -I
# Access dashboard
# [Link]