Maker.io main logo

Raspberry Pi Retrofits Vintage Radio for Streaming

221

2025-03-14 | By Travis Foss

License: See Original Project Amplifiers Barrel Audio Connectors Raspberry Pi SBC

Last summer I purchased an antique radio from a local auction sale for only a few dollars. The β€Žradio is a Stewart Warner Model 205CK that I believe was made around 1941. After bringing home β€Žthe radio and evaluating its restoration potential, I had an idea: what if I retrofit it with a Raspberry β€ŽPi to turn it into an internet radio? I had a few different Raspberry Pis sitting around unused, so I β€Žthought this might be an interesting project. β€Ž

antique_1

The first idea I had was to carefully remove the internal electronics from the original build and β€Žthen see about placing the new electronics into the case. Prior to doing this, however, I β€Žremembered I had a small amplifier board, 1738-DFR0675-EN-ND, that I could pull from another β€Žproject to do some testing. The original speaker in the cabinet had an interesting set of β€Žconnections that I hadn’t seen before, I believe they are just referred to as spring clips.β€Ž

clips_2

These made it easy to evaluate to see if a small amplifier like this would provide enough power for β€Žthe speaker. After plugging in the amplifier and powering it with a 12V battery, the sound was β€Žpretty good, just not as loud as I thought it would be. To further investigate the project, I used my β€Žmultimeter to measure the speaker's impedance. I found that it was reading approximately 7 β€Žohms. While it may not be a perfect match for the amp, I believe it will likely work, as the amp has β€Žspecifications for both 4-ohm and 8-ohm speaker configurations. During the amplifier test, I β€Žnoticed how great the speaker sounded. The music, while not overly loud, filled the room with a β€Žwarm and pleasant tone that was enjoyable to listen to. I was truly impressed by this.β€Ž

amplifier_3

Now that I had the initial testing out of the way, I decided the next step was to figure out which β€ŽRaspberry Pi I wanted to use. I first started to think about the Raspberry Pi Zero 2 W that I hadn’t β€Žused in a project yet. I decided to create some test code to see if I could make it work.β€Ž

While I’ve done some programming with a Raspberry Pi, I thought this project would be an β€Žinteresting test case to see what using ChatGPT and Claude could do to help me speed up my β€Žcoding time. I should state that I did use the free version of each of these LLM’s to create this β€Žproject. β€Ž

To start, I went to Claude’s website and posted the following Prompt.β€Ž

You are an experienced Python programmer that rarely makes mistakes. I am working on creating an antique radio into an internet radio using a Raspberry Pi zero 2w, an β€ŽPimoroni Audio DAC, and a Hi-Fi Bluetooth radio receiver from DFRobot. Can you help me with the β€Žcode to get this up and running? I would like for it to be an internet radio along with an Airplay β€Žreceiver as well.

In my time looking at various prompt engineering videos, I’ve heard from several people that if you β€Žgive a role to the LLM, it will provide a better, more accurate output.β€Ž

For the initial test of the code, I decided to try to run the sound through my Bluetooth headphones β€Žconnected to the Pi instead of the speaker. I figured this would be an easy way to test the code β€Žprior to setting up all the hardware. β€Ž

After connecting my headphones to the Pi with Bluetooth, I copied and pasted the first batch of β€Žcode that Claude sent over. β€Ž

Copy Code
import subprocess

import os

import signal

import time

from threading import Thread

import vlc

class VintageRadio:β€Ž

β€Ž def init(self):β€Ž

β€Ž # Initialize audio componentsβ€Ž

β€Ž self.current_source = None

β€Ž self.player = None

β€Ž self.airplay_process = None

β€Ž self.radio_stations = {β€Ž

β€Ž '1': 'http://media-ice.musicradio.com/ClassicFMMP3',β€Ž

β€Ž '2': 'http://icecast.vrtcdn.be/radio1-high.mp3',β€Ž

β€Ž '3': 'http://stream.live.vc.bbcmedia.co.uk/bbc_radio_two'β€Ž

β€Ž }β€Ž

β€Ž β€Ž

β€Ž # Set up audio output to Pimoroni DAC

β€Ž os.environ['ALSA_CARD'] = 'sndrPihifiberry'β€Ž

β€Ž β€Ž

β€Ž def start_airplay(self):β€Ž

β€Ž """Start Shairport-sync for AirPlay receiving"""β€Ž

β€Ž if self.airplay_process is None:β€Ž

β€Ž try:β€Ž

β€Ž self.stop_radio()β€Ž

β€Ž self.airplay_process = subprocess.Popen(β€Ž

β€Ž ['shairport-sync', '-o', 'alsa', '--name', 'Vintage Radio'],β€Ž

β€Ž stdout=subprocess.PIPE,β€Ž

β€Ž stderr=subprocess.PIPE

β€Ž )β€Ž

β€Ž self.current_source = 'airplay'β€Ž

β€Ž print("AirPlay receiver started")β€Ž

β€Ž except Exception as e:β€Ž

β€Ž print(f"Error starting AirPlay: {e}")β€Ž

β€Ž β€Ž

β€Ž def stop_airplay(self):β€Ž

β€Ž """Stop AirPlay receiver"""β€Ž

β€Ž if self.airplay_process:β€Ž

β€Ž self.airplay_process.terminate()β€Ž

β€Ž self.airplay_process = None

β€Ž self.current_source = None

β€Ž β€Ž

β€Ž def play_radio(self, station_number):β€Ž

β€Ž """Play internet radio station"""β€Ž

β€Ž if station_number in self.radio_stations:β€Ž

β€Ž try:β€Ž

β€Ž self.stop_airplay()β€Ž

β€Ž if self.player:β€Ž

β€Ž self.player.stop()β€Ž

β€Ž β€Ž

β€Ž # Create a new VLC instanceβ€Ž

β€Ž instance = vlc.Instance('--aout=alsa')β€Ž

β€Ž self.player = instance.media_player_new()β€Ž

β€Ž media = instance.media_new(self.radio_stations[station_number])β€Ž

β€Ž self.player.set_media(media)β€Ž

β€Ž self.player.play()β€Ž

β€Ž self.current_source = 'radio'β€Ž

β€Ž print(f"Playing radio station {station_number}")β€Ž

β€Ž except Exception as e:β€Ž

β€Ž print(f"Error playing radio: {e}")β€Ž

β€Ž β€Ž

β€Ž def stop_radio(self):β€Ž

β€Ž """Stop radio playback"""β€Ž

β€Ž if self.player:β€Ž

β€Ž self.player.stop()β€Ž

β€Ž self.player = None

β€Ž self.current_source = None

β€Ž β€Ž

β€Ž def setup_bluetooth(self):β€Ž

β€Ž """Initialize Bluetooth receiver"""β€Ž

β€Ž try:β€Ž

β€Ž # Enable Bluetooth audio sinkβ€Ž

β€Ž subprocess.run(['sudo', 'bluetoothctl', 'discoverable', 'on'])β€Ž

β€Ž subprocess.run(['sudo', 'bluetoothctl', 'pairable', 'on'])β€Ž

β€Ž subprocess.run(['sudo', 'bluetoothctl', 'agent', 'NoInputNoOutput'])β€Ž

β€Ž print("Bluetooth receiver ready")β€Ž

β€Ž except Exception as e:β€Ž

β€Ž print(f"Error setting up Bluetooth: {e}")β€Ž

β€Ž β€Ž

β€Ž def cleanup(self):β€Ž

β€Ž """Clean up all audio processes"""β€Ž

β€Ž self.stop_radio()β€Ž

β€Ž self.stop_airplay()β€Ž

β€Ž β€Ž

def main():β€Ž

β€Ž radio = VintageRadio()β€Ž

β€Ž radio.setup_bluetooth()β€Ž

β€Ž β€Ž

β€Ž while True:β€Ž

β€Ž print("\nVintage Radio Control")β€Ž

β€Ž print("1. Play Radio Station 1 (Classic FM)")β€Ž

β€Ž print("2. Play Radio Station 2 (Radio 1)")β€Ž

β€Ž print("3. Play Radio Station 3 (BBC Radio 2)")β€Ž

β€Ž print("4. Start AirPlay Receiver")β€Ž

β€Ž print("5. Stop All")β€Ž

β€Ž print("6. Exit")β€Ž

β€Ž β€Ž

β€Ž choice = input("Select an option: ")β€Ž

β€Ž β€Ž

β€Ž if choice in ['1', '2', '3']:β€Ž

β€Ž radio.play_radio(choice)β€Ž

β€Ž elif choice == '4':β€Ž

β€Ž radio.start_airplay()β€Ž

β€Ž elif choice == '5':β€Ž

β€Ž radio.cleanup()β€Ž

β€Ž elif choice == '6':β€Ž

β€Ž radio.cleanup()β€Ž

β€Ž break

β€Ž β€Ž

if name == "__main__":β€Ž

β€Ž main()β€Ž

Prior to running the code, Claude also mentioned that I needed to update the Pi as well as install β€Žsome other packages that weren’t included. β€Ž

These are the commands that it suggested

Copy Code
sudo apt-get update

sudo apt-get install python3-vlc shairport-sync bluetooth bluez-tools
Copy Code
β€Ž# Add this to /boot/config.txtβ€Ž
dtoverlay=hifiberry-dac
Copy Code
β€Ž# Edit /etc/bluetooth/main.confβ€Ž
β€Ž# Add or modify:β€Ž
Class = 0x200414β€Ž
Enable = Source,Sink,Media,Socket
Copy Code
chmod +x radio_script.py

After implementing all these changes, I tried testing out the code by running the Python script. It β€Žseemed like it was working correctly, however, I was unable to get any sound to play through my β€Žheadphones. β€Ž

The next prompt I sent to Claude was:β€Ž

I haven’t integrated the DFRobot Bluetooth amp or the Pimoroni DAC, could you rewrite the code β€Žso that I can test the radio over Bluetooth to some headphones.

After a few short moments, Claude gave me the next batch of code. I saved the new code and β€Žthen ran it again only to find out I was still having issues with the sound working. At that point, I β€Ždecided to do some testing on the Pi itself. I hooked up a screen and a keyboard and mouse to the β€ŽPi, however at this point I’m not exactly sure what I did but the Pi would no longer power up. After β€Žtrying several things, I resorted to changing to a Pi 4B instead of the Zero 2 W. I figured this would β€Žhelp in the long run as I would need fewer extra parts to get the radio up and running. The Pi 4B β€Žhad an Aux output on it, so I could directly connect between the Pi and the Bluetooth amp that I β€Žwas looking at using.β€Ž

After setting up the new PI, I first tried connecting my headphones via Bluetooth and tried playing β€Žsome YouTube videos. The sound came through the headphones loud and clear. β€Ž

Being that had worked, I went back to Claude and entered the following prompt:β€Ž

Can you remove all of the Bluetooth things from the code? In testing the Bluetooth portion of the Pi β€Žis working correctly already without modification.

Also, can you change the radio station dictionary to this '1': {'name': 'Lofi 1', 'url': β€Žβ€Ž'http://192.95.39.65:5607'}, '2': {'name': 'Lofi 2', 'url': 'https://cast.magicstreams.gr:9125'}, '3': β€Žβ€Ž{'name': 'Lofi 3', 'url': 'http://5.39.82.157:8054'}β€Ž

Claude gave me another rendition of the code.β€Ž

This new code worked perfectly. I was able to switch between stations as well as stop and restart β€Žthe radio by entering the numbers for each option in the terminal. β€Ž

After getting this part of the code working, I attempted to get an airplay function set up as well. β€ŽAlso, at this point, I had to switch from Claude to ChatGPT as I had hit my daily limit for requests. β€ŽI copied the code into ChatGPT and then asked if it could add the airplay receiver portion to the β€Žcode. After much frustration and effort in trying to get it to work, I decided to stop working on that β€Žportion of the code and try to get some other ideas working.β€Ž

The next idea I had for this build was to add a sound effect like an old-time radio tuning between β€Žstations each time the station was changed. I asked ChatGPT if it was possible to add some sort β€Žof sound effect between stations playing and it said that indeed it should be. It then instructed me β€Žto search the web for a royalty-free sound effect of β€œradio tuning noise” or β€œAM radio static”. After β€Žsearching the web, I was able to come across an MP3 that sounded very close to what I originally β€Žhad in mind. β€Ž

The next step that was given was to install pygame on the Pi by running this command

Copy Code
Pip install pygame

After downloading the .mp3 file onto the Pi, I then asked how I could go about adding a random 5-β€Žsecond clip of the .mp3 after a station had been selected. It then updated the code for me, and I β€Žsaved it to the Pi. The first few renditions of the code were close to what I was expecting but not β€Žquite right. The first kept playing the full one-minute plus .mp3 and the second rendition did play β€Žfor 5 seconds as I wanted, however, it didn’t fade in/out like I was hoping. I then asked if it would β€Žbe able to add a fade in/out sequence to the code. It added the correct fade out and in, but there β€Žwas a half-second dead spot between the two. I then asked if it was able to overlap the sound clip β€Žand the radio station a little bit so that it was more of a smooth transition. Once this prompt was β€Žsent, I received the code that would ultimately end up in the final build. It did everything I needed β€Žit to and faded in and out exactly like I wanted. After getting the code, I updated and added some β€Žnew stations to the station dictionary. β€Ž

Copy Code
import pygame

import time

import random

import vlc

import subprocess

import logging

from threading import Thread

from tyPing import Optional, Dict

β€Ž# Set up logging with more detailed formatβ€Ž

logging.basicConfig(β€Ž

β€Ž level=logging.DEBUG,β€Ž

β€Ž format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'β€Ž

β€Ž)β€Ž

logger = logging.getLogger(__name__)β€Ž

class InternetRadio:β€Ž

β€Ž def init(self):β€Ž

β€Ž # Initialize pygame mixer with higher quality settingsβ€Ž

β€Ž pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=4096)β€Ž

β€Ž self.player: Optional[vlc.MediaPlayer] = None

β€Ž self.airplay_process: Optional[subprocess.Popen] = None

β€Ž self.current_source: Optional[str] = None

β€Ž self.current_station: Optional[str] = None

β€Ž self.vlc_volume = 0 # Track VLC player volume

β€Ž # Enhanced radio stations dictionary with metadataβ€Ž

β€Ž self.radio_stations: Dict[str, dict] = {β€Ž

β€Ž '1': {β€Ž

β€Ž 'name': 'Lofi 1',β€Ž

β€Ž 'url': 'http://192.95.39.65:5607',β€Ž

β€Ž 'description': 'Relaxing lofi beats'β€Ž

β€Ž },β€Ž

β€Ž '2': {β€Ž

β€Ž 'name': 'MPR News',β€Ž

β€Ž 'url': 'https://nis.stream.publicradio.org/nis.mp3',β€Ž

β€Ž 'description': 'Minnesota Public Radio News'β€Ž

β€Ž },β€Ž

β€Ž '3': {β€Ž

β€Ž 'name': 'Lofi 3',β€Ž

β€Ž 'url': 'http://5.39.82.157:8054',β€Ž

β€Ž 'description': 'Study beats and ambient sounds'β€Ž

β€Ž },β€Ž

β€Ž '4': {β€Ž

β€Ž 'name': 'Minnesota Jazz Tracks',β€Ž

β€Ž 'url': 'http://kbem-live.streamguys1.com/jazztracks_mp3',β€Ž

β€Ž 'description': 'The Jazz of 10,000 Lakes'β€Ž

β€Ž },β€Ž

β€Ž '5': {β€Ž

β€Ž 'name': 'Swing Street Radio',β€Ž

β€Ž 'url': 'http://s6.voscast.com:11312',β€Ž

β€Ž 'description': 'Swing Music'β€Ž

β€Ž },β€Ž

β€Ž '6': {β€Ž

β€Ž 'name': 'Swing City Radio',β€Ž

β€Ž 'url': 'http://bluford.torontocast.com:8006/stream',β€Ž

β€Ž 'description': 'Catch your favorites of the 20s 30s and 40s'β€Ž

β€Ž },β€Ž

β€Ž '7': {β€Ž

β€Ž 'name': 'Yesterday USA - Blue',β€Ž

β€Ž 'url': 'https://media.classicairwaves.com:8018/stream',β€Ž

β€Ž 'description': 'Welcome to Yesterday USA, where Old Time Radio Programs rule the day. β€ŽFor more than 37 years we have been playing classic old time radio shows hosted by volunteers β€Žwho are no>β€Ž

β€Ž },β€Ž

β€Ž }β€Ž

β€Ž def list_stations(self) -> None:β€Ž

β€Ž """Display all available radio stations with their descriptions"""β€Ž

β€Ž print("\n=== Available Radio Stations ===")β€Ž

β€Ž for number, station in self.radio_stations.items():β€Ž

β€Ž print(f"{number}. {station['name']} - {station['description']}")β€Ž

β€Ž print("=" * 30 + "\n")β€Ž

β€Ž def play_radio(self, station_number: str) -> None:β€Ž

β€Ž """β€Ž

β€Ž Play internet radio station with smooth transition effects

β€Ž """β€Ž

β€Ž if station_number not in self.radio_stations:β€Ž

β€Ž logger.error(f"Invalid station number: {station_number}")β€Ž

β€Ž print("Invalid station number. Please try again.")β€Ž

β€Ž return

β€Ž try:β€Ž

β€Ž self.stop_airplay()β€Ž

β€Ž self.current_station = station_number

β€Ž # Create new VLC instance with initial volume at 0β€Ž

β€Ž instance = vlc.Instance('--verbose=2')β€Ž

β€Ž if self.player:β€Ž

β€Ž self.player.stop()β€Ž

β€Ž self.player = instance.media_player_new()β€Ž

β€Ž url = self.radio_stations[station_number]['url']β€Ž

β€Ž media = instance.media_new(url)β€Ž

β€Ž self.player.set_media(media)β€Ž

β€Ž # Start radio playback at 0 volumeβ€Ž

β€Ž self.player.audio_set_volume(0)β€Ž

β€Ž self.player.play()β€Ž

β€Ž # Start transition effect in a separate threadβ€Ž

β€Ž Thread(target=self._transition_audio).start()β€Ž

β€Ž except Exception as e:β€Ž

β€Ž logger.error(f"Error playing radio: {e}")β€Ž

β€Ž print(f"Error playing radio station. Please try again.")β€Ž

β€Ž def transitionaudio(self) -> None:β€Ž

β€Ž """β€Ž

β€Ž Handle the smooth transition between tuning noise and radio station

β€Ž """β€Ž

β€Ž try:β€Ž

β€Ž # Play tuning noiseβ€Ž

β€Ž pygame.mixer.music.load('radio_tuning.mp3')β€Ž

β€Ž pygame.mixer.music.play()β€Ž

β€Ž pygame.mixer.music.set_volume(1.0)β€Ž

β€Ž # Wait for a moment with full tuning noiseβ€Ž

β€Ž time.sleep(1.5)β€Ž

β€Ž # Crossfade between tuning noise and radioβ€Ž

β€Ž steps = 50 # More steps for smoother transition

β€Ž fade_duration = 3.0 # Longer fade for more vintage feel

β€Ž step_time = fade_duration / steps

β€Ž for i in range(steps + 1):β€Ž

β€Ž # Calculate volumes using sine wave for smooth transitionβ€Ž

β€Ž tuning_volume = cos_volume = (steps - i) / steps

β€Ž radio_volume = sin_volume = i / steps

β€Ž # Update volumesβ€Ž

β€Ž pygame.mixer.music.set_volume(tuning_volume)β€Ž

β€Ž self.player.audio_set_volume(int(radio_volume * 100))β€Ž

β€Ž time.sleep(step_time)β€Ž

β€Ž # Ensure tuning noise is fully stoppedβ€Ž

β€Ž pygame.mixer.music.stop()β€Ž

β€Ž except Exception as e:β€Ž

β€Ž logger.error(f"Error during audio transition: {e}")β€Ž

β€Ž def start_airplay(self) -> None:β€Ž

β€Ž """Start Shairport-sync for AirPlay receiving"""β€Ž

β€Ž if self.airplay_process is None:β€Ž

β€Ž try:β€Ž

β€Ž self.stop_radio()β€Ž

β€Ž self.airplay_process = subprocess.Popen(β€Ž

β€Ž ['shairport-sync', '-o', 'alsa', '--name', 'Vintage Radio'],β€Ž

β€Ž stdout=subprocess.PIPE,β€Ž

β€Ž stderr=subprocess.PIPE,β€Ž

β€Ž text=True

β€Ž )β€Ž

β€Ž self.current_source = 'airplay'β€Ž

β€Ž logger.info("AirPlay receiver started successfully")β€Ž

β€Ž print("AirPlay receiver is now active")β€Ž

β€Ž except Exception as e:β€Ž

β€Ž logger.error(f"Error starting AirPlay: {e}")β€Ž

β€Ž print("Failed to start AirPlay receiver. Please check if shairport-sync is installed.")β€Ž

β€Ž def stop_airplay(self) -> None:β€Ž

β€Ž """Stop AirPlay receiver"""β€Ž

β€Ž if self.airplay_process:β€Ž

β€Ž self.airplay_process.terminate()β€Ž

β€Ž self.airplay_process = None

β€Ž self.current_source = None

β€Ž logger.info("AirPlay receiver stopped")β€Ž

β€Ž print("AirPlay receiver stopped.")β€Ž

β€Ž def stop_radio(self) -> None:β€Ž

β€Ž """Stop radio playback with fade out effect"""β€Ž

β€Ž if self.player:β€Ž

β€Ž # Fade out radioβ€Ž

β€Ž current_volume = self.player.audio_get_volume()β€Ž

β€Ž steps = 20β€Ž

β€Ž for i in range(steps):β€Ž

β€Ž volume = int(current_volume * (steps - i) / steps)β€Ž

β€Ž self.player.audio_set_volume(volume)β€Ž

β€Ž time.sleep(0.05)β€Ž

β€Ž self.player.stop()β€Ž

β€Ž self.player = None

β€Ž self.current_station = None

β€Ž logger.info("Radio playback stopped")β€Ž

β€Ž print("Radio playback stopped.")β€Ž

β€Ž def get_status(self) -> str:β€Ž

β€Ž """Get detailed current status of the radio"""β€Ž

β€Ž status = "\n=== Radio Status ===\n"β€Ž

β€Ž if self.current_source == 'airplay':β€Ž

β€Ž status += "Current mode: AirPlay\n"β€Ž

β€Ž elif self.current_station:β€Ž

β€Ž station = self.radio_stations[self.current_station]β€Ž

β€Ž status += f"Current mode: Radio\n"β€Ž

β€Ž status += f"Playing: {station['name']} - {station['description']}\n"β€Ž

β€Ž else:β€Ž

β€Ž status += "Current mode: Idle\n"β€Ž

β€Ž return status + "=" * 20 + "\n"β€Ž

def main():β€Ž

β€Ž radio = InternetRadio()β€Ž

β€Ž while True:β€Ž

β€Ž print("\n=== Vintage Internet Radio Control ===")β€Ž

β€Ž print("1. List Radio Stations")β€Ž

β€Ž print("2. Play Radio Station")β€Ž

β€Ž print("3. Start AirPlay Receiver")β€Ž

β€Ž print("4. Stop Playback")β€Ž

β€Ž print("5. Show Status")β€Ž

β€Ž print("6. Exit")β€Ž

β€Ž print("=" * 35)β€Ž

β€Ž try:β€Ž

β€Ž choice = input("\nSelect an option (1-6): ").strip()β€Ž

β€Ž if choice == '1':β€Ž

β€Ž radio.list_stations()β€Ž

β€Ž elif choice == '2':β€Ž

β€Ž radio.list_stations()β€Ž

β€Ž station = input("Enter station number to play: ").strip()β€Ž

β€Ž radio.play_radio(station)β€Ž

β€Ž elif choice == '3':β€Ž

β€Ž radio.start_airplay()β€Ž

β€Ž elif choice == '4':β€Ž

β€Ž radio.stop_radio()β€Ž

β€Ž radio.stop_airplay()β€Ž

β€Ž elif choice == '5':β€Ž

β€Ž print(radio.get_status())β€Ž

β€Ž elif choice == '6':β€Ž

β€Ž print("\nStopPing all playback...")β€Ž

β€Ž radio.stop_radio()β€Ž

β€Ž radio.stop_airplay()β€Ž

β€Ž print("Goodbye!")β€Ž

β€Ž break

β€Ž else:β€Ž

β€Ž print("Invalid option, please enter a number between 1 and 6.")β€Ž

β€Ž except KeyboardInterrupt:β€Ž

β€Ž print("\nShutting down gracefully...")β€Ž

β€Ž radio.stop_radio()β€Ž

β€Ž radio.stop_airplay()β€Ž

β€Ž break

β€Ž except Exception as e:β€Ž

β€Ž logger.error(f"Unexpected error: {e}")β€Ž

β€Ž print("An error occurred. Please try again.")β€Ž

if name == "__main__":β€Ž

β€Ž main()β€Ž

At this point, I had saved 8 different renditions of the code to the pi, so that I could revert to older β€Žones if I ran into issues. After getting the main controls working, the next task I asked ChatGPT β€Žwas if it could set up a local webpage that I would be able to control the Pi from. It then set off β€Žcreating a Flask page that would handle the controls. Prior to this build, I had never heard of Flask, β€Žso I had to do a bit of research to learn more about it. Luckily, we already have a few projects on β€ŽMaker.io related to Flask. After a short time, ChatGPT gave me the following bit of code.β€Ž

Copy Code
from flask import Flask, render_template, request, jsonify

import threading

from radio8_setup import InternetRadio # Ensure your existing script is named properly

app = Flask(__name__)β€Ž

radio = InternetRadio()β€Ž

@app.route('/')β€Ž

def index():β€Ž

β€Ž return render_template('index.html', stations=radio.radio_stations)β€Ž

@app.route('/play/<station_number>', methods=['POST'])β€Ž

def play_station(station_number):β€Ž

β€Ž threading.Thread(target=radio.play_radio, args=(station_number,)).start()β€Ž

β€Ž return jsonify({"status": "playing", "station": station_number})β€Ž

@app.route('/stop', methods=['POST'])β€Ž

def stop_radio():β€Ž

β€Ž radio.stop_radio()β€Ž

β€Ž return jsonify({"status": "stopped"})β€Ž

@app.route('/volume', methods=['POST'])β€Ž

def set_volume():β€Ž

β€Ž volume = int(request.form['volume'])β€Ž

β€Ž if radio.player:β€Ž

β€Ž radio.player.audio_set_volume(volume)β€Ž

β€Ž return jsonify({"status": "volume_set", "volume": volume})β€Ž

if name == '__main__':β€Ž

β€Ž app.run(host='0.0.0.0', port=5000, debug=True)

β€ŽFor the Flask program to work, I also needed to have an index.html file put together. After β€Žprompting ChatGPT, here is the code that it gave me. I updated the background image to one I β€Žfound online.β€Ž

Copy Code
<!DOCTYPE html>β€Ž

β€Ž<html lang="en">β€Ž

β€Ž<head>β€Ž

β€Ž <meta charset="UTF-8">β€Ž

β€Ž <meta name="viewport" content="width=device-width, initial-scale=1.0">β€Ž

β€Ž <title>Antique Radio Controller</title>β€Ž

β€Ž <style>β€Ž

β€Ž body {β€Ž

β€Ž background-image: url('https://wallpapercave.com/wp/wp8461192.jpg');β€Ž

β€Ž background-size: cover;β€Ž

β€Ž text-align: center;β€Ž

β€Ž font-family: Arial, sans-serif;β€Ž

β€Ž color: white;β€Ž

β€Ž }β€Ž

β€Ž .button {β€Ž

β€Ž display: block;β€Ž

β€Ž width: 200px;β€Ž

β€Ž margin: 10px auto;β€Ž

β€Ž padding: 10px;β€Ž

β€Ž background-color: brown;β€Ž

β€Ž color: white;β€Ž

β€Ž border: none;β€Ž

β€Ž cursor: pointer;β€Ž

β€Ž }β€Ž

β€Ž .slider {β€Ž

β€Ž width: 50%;β€Ž

β€Ž margin: 20px auto;β€Ž

β€Ž }β€Ž

β€Ž </style>β€Ž

β€Ž</head>β€Ž

β€Ž<body>β€Ž

β€Ž <h1>Antique Radio Controller</h1>β€Ž

β€Ž {% for key, station in stations.items() %}β€Ž

β€Ž <button class="button" onclick="playStation('{{ key }}')">{{ station.name }}</button>β€Ž

β€Ž {% endfor %}β€Ž

β€Ž <br>β€Ž

β€Ž <input type="range" min="0" max="100" class="slider" oninput="setVolume(this.value)">β€Ž

β€Ž <br>β€Ž

β€Ž <button class="button" onclick="stopRadio()">Stop</button>β€Ž

β€Ž <script>β€Ž

β€Ž function playStation(station) {β€Ž

β€Ž fetch(`/play/${station}`, { method: 'POST' });β€Ž

β€Ž }β€Ž

β€Ž function stopRadio() {β€Ž

β€Ž fetch('/stop', { method: 'POST' });β€Ž

β€Ž }β€Ž

β€Ž function setVolume(volume) {β€Ž

β€Ž fetch('/volume', {β€Ž

β€Ž method: 'POST',β€Ž

β€Ž headers: {'Content-Type': 'application/x-www-form-urlencoded'},β€Ž

β€Ž body: volume=${volume}β€Ž

β€Ž });β€Ž

β€Ž }β€Ž

β€Ž </script>β€Ž

β€Ž</body>β€Ž

β€Ž</html>β€Ž

β€ŽNow that the Flask page was set up and the Python script was completed, the last task I had was β€Žto find out which parts I wanted to use in the final build. I started looking at the DigiKey website for β€Žanother audio amp that would be rather low-cost and possibly have a couple of different options β€Žfor how the media is delivered. I discovered a HiFi Bluetooth amplifier from DFRobot, part 1738-β€ŽDFR0803-ND, which had everything I was hoping to find. It had options for both Bluetooth and β€Žauxiliary inputs. This gave me the ability to connect to the radio over Bluetooth instead of Airplay β€Žor via the internet radio that I was building via the aux input. This was the perfect choice for this β€Žbuild. β€Ž

After selecting the amplifier, I wanted to use, I looked for a short audio plug-to-plug (aux cable) to β€Žconnect the Raspberry Pi to the amplifier. I found part number TL1621-ND, which is 1 foot long.β€Ž

After getting these parts, I then dove into the build itself. My original thought was to take out the β€Žoriginal internals to the radio, but after seeing what I would need to get this to work, I decided that β€ŽI would keep the radio as original as possible with the internals intact. I figured that way if β€Žsomeone later wanted to restore the radio, everything was still in its original place.β€Ž

To start the hardware installation, I first looked for a Raspberry Pi 4 case suitable for a VESA mount β€Žon Printables and began 3D printing it. Next, I found a case for the amplifier, which was listed as β€Žthe Wuzhi ZK-502C case, also on Printables. I then took that file and added a few mounting tabs in β€Žthe slicer software I was using. My plan was to mount the case to the bottom of the shelf below β€Žthe Raspberry Pi, as I thought this would be the simplest solution. After getting both pieces β€Žprinted, I dove into the assembly. There was already a passthrough hole drilled into the wooden β€Žshelf at the back of the radio, so I decided to screw the Raspberry Pi case into the shelf next to β€Žthis hole. Directly beneath it, I mounted the Hi-Fi amplifier close enough for the short aux cable I β€Žfound to reach. From there I ran the speaker wire from the amp down to the speaker and β€Žconnected both positive and negative wires to their respective terminals. Lastly, I ran the power β€Žsupplies for both the amp and the Pi down to the bottom of the cabinet. From there I attached β€Žboth power supplies to a dual connection extension cord so that I would only have to plug the one β€Žcord into the wall to power both devices. β€Ž

At this stage, the complete build was assembled and sounded fantastic. However, I felt that β€Žsomething was still missing from the front. While the project looked impressive overall, the β€Ždisplay seemed to lack adequate backlighting. Initially, I considered using an LED strip for the β€Žbacklighting, but after assessing the limited space available, I decided to explore other options. I β€Žremembered that Adafruit had flexible LED filaments that they refer to NOODS. I found part 1528-β€Žβ€Ž5504-ND which I thought would look pretty good. I connected the setup to my benchtop power β€Žsupply to determine the appropriate resistor size for achieving the desired level of backlighting. β€ŽAfter conducting a series of tests, including positioning the filament within the radio below the β€Ždisplay, I discovered that a 4.5-ohm resistor provided the perfect color I was aiming for at 3.3V. β€ŽThe reason I wanted to adjust it for that voltage is so I could directly connect it to the 3.3V pin on β€Žthe Raspberry Pi for power. After getting the LED filament wired and put into place, I realized I β€Žneeded something to hold it there. Instead of using glue to adhere it, I resorted to 3D printing a β€Žlong rectangular piece that would just wedge it in place. That way it could be easily removed if β€Žneeded.β€Ž

radio_4

I should mention that I downloaded an app called Wuzhi Audio on my phone. This app allows me β€Žto easily switch between Bluetooth and Aux input for the amplifier. This feature makes it even β€Žeasier than I imagined to play songs from my phone on the radio.β€Ž

Here is the reveal of the final product and how it turned out.β€Ž

final_5

interface_6

This is how the web control interface looks:β€Ž

controller_7

And here is a short video of it in action:β€Ž

 

β€Ž

Overall, this build was a lot of fun, and I was able to test the viability of using LLM’s to help with β€Žmy coding. I would say that looking back on this project, LLM’s are great at getting the groundwork β€Žof a project. It helped get the project 80% of the way completed and it needed guidance along the β€Žway to get it there, but it for sure helped speed up my coding.

Mfr Part # DFR0675-EN
STEREOBLUETOOTHAMPLIFIERBOARD
DFRobot
Mfr Part # DFR0803
HIFI DIGITAL BLUETOOTH AMPLIFIER
DFRobot
$130.89
View More Details
Mfr Part # P312-001
ADAPT 3.5MM PLUG TO 3.5MM PLUG
Eaton Tripp Lite
Mfr Part # 5504
LED MOD WARM WHT LINEAR STRIP
Adafruit Industries LLC
Mfr Part # SC1176
SBC 1.0GHZ 4 CORE 512MB RAM
Raspberry Pi
$123.48
View More Details
Mfr Part # SC0194(9)
SBC 1.5GHZ 4 CORE 4GB RAM
Raspberry Pi
$484.86
View More Details
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.