Vintage radios are irresistible. When you hear one spewing static, your natural response is to turn the dial and try to tune in a station. The anticipation! What will you hear? With this Haunted Radio project, you can decide for your guests or escape room attendees exactly what they'll hear, and you can even choose the frequency.

There isn't any pirate radio station involved here, either. Instead, the secret is a Feather microcontroller reading the dial position with a magnet sensor, and an attached Music Maker FeatherWing with amplifier to play back your pre-recorded message over the radio's speaker.

Parts & Materials

Here's what you'll need to make your Haunted Radio:


  • Soldering iron and solder
  • Wire cutters
  • Wire strippers
  • Pliers
  • Hot glue gun or tape

Let's take a look at how to prepare your vintage radio to be Haunted!

A lot can vary from radio to radio, so these won't be exact steps for yours, but a general method for reusing the case, dial, knob, and speaker when possible.

AC mains power is dangers! Be sure to unplug the radio from the wall first!!


Most vintage radios are accessed by removing a back panel. Go ahead and unscrew and remove yours.

Next, carefully pull of all knobs. These are often press-fit into place and can be removed with moderate force. Some may have a small set screw that must be loosened first.

Check the bottom for fasteners -- in this case small hex bolts -- are remove them.

The speaker will be connected to the radio electronics by two wires. Cut those right where they enter the board, leaving the full length of the wires connected to the speaker.

You can now remove the electronics from the radio. Look at those beautiful vacuum tubes.

Tuning Mechanism

You'll find a large wheel connected to the tuning knob shaft via a tensioned tuning cord. Try out the mechanism -- if you find that it is slipping you can apply some rosin to the cord, as the whole system relies on friction to turn the cord, which in turn moves the dial indicator.

Here we can see the tuning indicator that slides back and forth. It is to this that we'll be attaching the magnet later.

On/Off Reuse

Looking at the underside of the radio, you'll see a bunch of crusty old parts. Do not lick them.

If you want to have your Haunted Radio turn on and off via the original knob --this is often a dual-use on/off plus volume knob --  check for a pair of wires running to the knob. These are the on/off switches, vs. the set of three lugs that are for volume. You can clip all of these wires and then test continuity with a multimeter to confirm.

Solder two wires to the on/off lugs, about 8" each.

Soldering on your stranded wire is fun!

Here I've removed one of the vacuum tubes to use as a convenient through hole for running wires up to the top.

Battery Prep

Next, you'll splice the on/off switch wires into the battery cable. Start by cutting the black wire (or the red, the decision is yours!)

Strip all of the wire ends.

Use two butt splices to connect two pairs of green and black wires.

Squeeze down the connectors with a pair of pliers and you've now added the radio's on/off switch to your battery!

First, solder on the stacking female/male headers to your Feather Huzzah ESP8266. (You can use this guide as a reference.) Then, connect the Feather to the Terminal Block Breakout FeatherWing.

Solder the male headers onto the Music Maker FeatherWing, and then fit it on top of the Feather.

Before going any further, make sure you have a basic understanding of how to program and use an Arduino-compatible Feather microcontroller. Thankfully, we have a lot of great tutorials on how this whole thing works. Click here to get started with Arduino, and then come back to this guide to continue.

Confirm that everything is working as expected by following the Music Maker guide here, connecting the Music Maker to a small speaker (or your radio's speaker) and running the Feather Player example.

There are a number of ways to read the position of the tuner indicator on an old radio. One versatile, but more involved way would be to read the capacitance of the tuner itself. Another would be to add a rotary encoder to the proceedings, or perhaps glue an encoder disk to the tuner's large wheel and read it optically.

Since we only need to measure a single position, and we don't need to know that state of the tuner (where it has been) we'll get away with using one of the most simple methods here: a hall effect sensor placed at the desired station number position that can read the presence of a magnet that travels with the indicator needle.

Need to read multiple station positions? Just add more Hall effect sensors -- as many as your microcontroller has available inputs!

This is our circuit diagram for the Haunted Radio -- the Hall effect sensor has three connections:

  1. power to 3v3 on the Feather
  2. ground to GND
  3. digital out to pin 4

You'll also run a 10k resistor between legs 1 and 3 of the sensor.

Build the sensor harness with three of the jumper wires. You'll plug the sensor legs into the female jumper connectors and do the same with the resistor.


A bit of tape can hold the ends together nicely.


Make sure you match the orientation so that leg one is on the left with the "front" of the sensor (the smaller face) toward you, and goes into the power (red) wire.


Trim the legs of the resistor and then push them in to contact the sensor legs 1 and 3.





Plug the red power wire into the 3v3 terminal block, then screw it down. 

Plug in and screw down the black wire to GND.

Lastly, plug the yellow wire into the pin 4 (marked SDA on the board) terminal.

Plug in Power

You can plug in the battery to the JST connector on the Feather board now -- check that the switch on the Terminal Block Breakout Board is in the "on" position. You'll turn on the whole system with the radio's on/off knob. 

Sensor Placement

Decide what frequency you'd like to use as your Haunted Radio's "cursed" frequency. Place the Hall effect sensor over this position (you may need to temporarily place the assembly back into the radio's case to determine the position).

Place the magnet on the dial -- we'll check for proper orientation later when we upload the code to the Feather. In case the dial isn't ferrous you can use tape or hot glue.

Tilt and bend the sensor legs so that the sensing face is nearest the magnet -- on many Hall sensors this is the larger face -- then affix the sensor to the radio with tape or hot glue.

The magnet should be easily read by the sensor at this distance, but you can fine tune it later.

Speaker Wiring

Strip the ends of the radio's speaker wires, then screw them into one of the output pairs (either Left or Right) on the Music Maker FeatherWing. 

Don't be tempted to wire the Left and Right outputs together -- it won't make things louder and could damage the amp!

Tidy Up

Neaten up the whole package by combining the Feather stack and the battery using zip ties or rubber bands. I've placed a small piece of felt between them to keep the exposed terminal points on the bottom from poking the heat shrink of the battery pack.

Before fully reassembling the radio, let's upload the code to the Feather!

Our code is fairly simple -- it really just does two things: play a looping static file, and then when the magnet is detected, play a different file.

You already got the Feather up and running in the Feather Prep section of the guide, so now we need to add code to read the Hall effect sensor and play the second track.

You'll needs two audio .mp3 files on the SD card. I've named my files STATIC.MP3 and TUNED.MP3. Load your files onto the card and then put the card in the FeatherWing's SD slot. You can find more info on loading music files here.

Copy this code below, paste it into a new Arduino sketch, save the sketch as hauntedRadio.ino in your Arduino sketches library, and then upload it to the Feather board which is plugged in via USB.

//Haunted Radio
//by John Park for Adafruit Industries
//based on feather_player by Limor Fried
//Uses hall sensor to detect magnet attached to radio tuner dial
//Plays static file and radio play files from Music Maker FeatherWing
//connected to Feather microcontroller
//MIT License

/*/////////// Hardware ////////////////////////////////

 Feather (of any variety, in this case ESP8266 Huzzah)
 Music Maker MP3 FeatherWing
 Hall sensor connected to digital input pin 4

Wiring is left (pin 1) to Vin, middle (2) to GND, right (3) to digital input
  -place 10K resistor between voltage in Pin 1 and voltage out Pin 3
 | |   | |
 | |   | |
  /  |  \
 |   |   |
 |   |   |
 |   |   |
 |   |   |
 +  GND  Output
 |   |   |
 |       |
 \-[|||]-/ 10k resistor


#include <SPI.h>
#include <SD.h>
#include <Adafruit_VS1053.h>

// These are the pins used
#define VS1053_RESET   -1     // VS1053 reset pin (not used!)

// Feather M0 or 32u4
#if defined(__AVR__) || defined(ARDUINO_SAMD_FEATHER_M0)
  #define VS1053_CS       6     // VS1053 chip select pin (output)
  #define VS1053_DCS     10     // VS1053 Data/command select pin (output)
  #define CARDCS          5     // Card chip select pin
  // DREQ should be an Int pin *if possible* (not possible on 32u4)
  #define VS1053_DREQ     9     // VS1053 Data request, ideally an Interrupt pin

// Feather ESP8266
#elif defined(ESP8266)
  #define VS1053_CS      16     // VS1053 chip select pin (output)
  #define VS1053_DCS     15     // VS1053 Data/command select pin (output)
  #define CARDCS          2     // Card chip select pin
  #define VS1053_DREQ     0     // VS1053 Data request, ideally an Interrupt pin

// Feather ESP32
#elif defined(ESP32)
  #define VS1053_CS      32     // VS1053 chip select pin (output)
  #define VS1053_DCS     33     // VS1053 Data/command select pin (output)
  #define CARDCS         14     // Card chip select pin
  #define VS1053_DREQ    15     // VS1053 Data request, ideally an Interrupt pin

// Feather Teensy3
#elif defined(TEENSYDUINO)
  #define VS1053_CS       3     // VS1053 chip select pin (output)
  #define VS1053_DCS     10     // VS1053 Data/command select pin (output)
  #define CARDCS          8     // Card chip select pin
  #define VS1053_DREQ     4     // VS1053 Data request, ideally an Interrupt pin

// WICED feather
#elif defined(ARDUINO_STM32_FEATHER)
  #define VS1053_CS       PC7     // VS1053 chip select pin (output)
  #define VS1053_DCS      PB4     // VS1053 Data/command select pin (output)
  #define CARDCS          PC5     // Card chip select pin
  #define VS1053_DREQ     PA15    // VS1053 Data request, ideally an Interrupt pin

#elif defined(ARDUINO_FEATHER52)
  #define VS1053_CS       30     // VS1053 chip select pin (output)
  #define VS1053_DCS      11     // VS1053 Data/command select pin (output)
  #define CARDCS          27     // Card chip select pin
  #define VS1053_DREQ     31     // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer = 
  Adafruit_VS1053_FilePlayer(VS1053_RESET, VS1053_CS, VS1053_DCS, VS1053_DREQ, CARDCS);

const int HALLPIN = 4;   // hall effect sensor pin (since we aren't using I2C)
int hallState = 0;       // variable for reading the hall sensor status

int staticOn = 1;  // variable to store state of static being played
int stationOn = 0; // variable to store state of station being selected

/////////////////////////// Setup /////////////////////////////////////////////

void setup() {

  pinMode(HALLPIN, INPUT_PULLUP); //so we can read the Hall sensor

  // if you're using Bluefruit or LoRa/RFM Feather, disable the BLE interface
  //pinMode(8, INPUT_PULLUP);

  // Wait for serial port to be opened, remove this line for 'standalone' operation
  //while (!Serial) { delay(1); }

  Serial.println("\n\nAdafruit Music Maker VS1053 Feather Haunted Radio");
  if (! musicPlayer.begin()) { // initialise the music player
     Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
     while (1);

  Serial.println(F("VS1053 found"));
  //musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working
  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  Serial.println("SD OK!");
  // Set volume for left, right channels. lower numbers == louder volume!
#if defined(__AVR_ATmega32U4__) 
  // Timer interrupts are not suggested, better to use DREQ interrupt!
  // but we don't have them on the 32u4 feather...
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); // timer int
#elif defined(ESP32)
  // no IRQ! doesn't work yet :/
  // If DREQ is on an interrupt pin we can do background
  // audio playing
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int


/////////////////////////  Loop  //////////////////////////////////////////////

void loop(){

  hallState = digitalRead(HALLPIN); // the magnet is on 1500AM, 
  //check to see if we're tuned in to this station

  if(staticOn == 1) {
    Serial.println("Playing STATIC.MP3.\n");
    staticOn = 0; //flip the flag so it doesn't start playing over again

  if (hallState == HIGH){ //this is HIGH when we don't sense a magnet
    Serial.println("No magnet.\n");

  else if(hallState == LOW){ //when this goes LOW, we're seeing the magnet
    Serial.println("\t Magnet has been sensed!");
      Serial.println("\t Playing file TUNED.MP3\n");

  if(musicPlayer.stopped()) {
    Serial.println("Player has stopped.\n");
    staticOn=1; //reset counter so static will start again
    //stationOn=0; //reset counter so station can be restarted when sensor is
    //over the magnet again, comment this line out if you don't want the station file to loop or play multiple times

Now, when you turn on the Haunted Radio it will begin immediately playing the static track. As you tune the dial and reach the cursed station, it will play back the second track!


Put your radio back together now, sliding it in place first, and then reconnecting the knobs.

Use It

It's time to unleash the mysterious powers of the Haunted Radio on your guests! You can make up a puzzle in a game or escape room that can only be solved by tuning the radio and listening to the message, or perhaps use it as an interactive prop while telling a ghost story...

This guide was first published on Jun 16, 2017. It was last updated on Jun 16, 2017.