Earlier this year, my parents bought a John Deere Ground Force Tractor and Trailer for my son Theodore and the other grandkids to play with at the cabin. For some inexplicable reason, in 2026, this tractor includes an FM radio (2xAA lithium batteries – not included). Putting the batteries in and turning it on, hits you with a blast of static noise, since Norway has transitioned most FM to DAB since 2017.
I could simply remove the batteries and leave it as a useless part, but
- It’s one of the selling points of the tractor
- Dials and buttons are fun to use, and even more so if they actually do something!
- I also think it’s a good learning that when you press stuff something happens
- It would be a lot more fun if it worked, and I do enjoy a pointless project where I might learn a thing or two
This led me to the thought: Would it be possible to broadcast a local FM signal and make my own radio channel?
Down the rabbit hole
After some quick searching I ended up finding fm_transmitter, a library to use the Raspberry Pi as a FM transmitter. I dug out a Raspberry Pi Zero 2 WH I had lying in a drawer, and quickly installed Raspberry Pi OS Lite (32-bit), and followed the installation instructions on the repository.
Next I grabbed a Dupont wire, connected it to GPIO4 on the Pi, and extended it by connecting a Wago clip with another wire to get a length of ~84.3cm, which is the recommended length for broadcasting on 89.0MHz. More details and an “Antenna Calculator” can be found on this page describing the full process in more detail.
Moment of truth, I ran the test command from the repository with an FM radio I had tuned to 89.0, and lo and behold the static changed into music!
I honestly couldn’t believe how easy it was to get up and running, and the whole thing I was expecting to spend multiple summer evenings on, took a total of maybe 30 minutes.
Creating a continuous feed
Now I was able to take any wav files that I had and broadcast them, and it would play the song from beginning to end, but then the process would terminate and the feed would stop, and go back to static. What I wanted was a folder songs/ which I could put a bunch of mp3s into, and it would just randomly play all of them over and over.
Play mp3s instead of wavs
fm_transmitter documents on their website how to use SoX to convert an mp3 and get it to play like this
| |
Unfortunately, I could not get this to work, even after installing the required libsox-fmt-mp3. Whenever I would pass it an mp3, it would spit back
sox FAIL formats: no handler for file extension `mp3'
I spent some time debugging and trying to understand what the issue was, but could not make it work regardless of what I tried. Eventually I figured out that the sox I was getting via apt was “compiled without libltdl dynamic-module support”, and therefore didn’t load any of the libsox-fmt-* files. I tried the workarounds using ffmpeg instead, but really didn’t feel like having to reencode each file to be able to play it. Just having a folder where I could drop an mp3 and play felt much easier.
Enter sox_ng, a “hard fork of sox-14.4.2 aiming to sanitize SoX”. I followed the steps for compiling it from source, which gave me a sox_ng binary, and this one accepted mp3s!
Non-stop music
With mp3s playing the next step was to create something which allowed me to just continuously loop through all files in my directory, and play them back to back without interruption. Using Claude, and quite a few back-and-forths, I created a bash script which allowed me to do just that. Now I actually had a local broadcast which played the songs I wanted, and I could easily add/remove songs as I needed.
Becoming a radio DJ
Since the initial setup and wiring went much faster than I had expected, I had some extra time to dive further into the project, and what does every radio station need? Jingles! Having used ElevenLabs in the past, I figured this could be a fun way to create some short jingles that would integrate nicely with the music.
I spent a bit of time coming up with a name for the station, then testing a few different voices and getting pronunciation right. This turned out to be more challenging since I was mixing English and Norwegian pronunciations in the same jingle. Thankfully there is native support for IPA pronunciation which made it possible.
Then Claude helped me change the script to support playing jingles, and it now plays a random jingle after every song.
Jingles
Here are some examples of jingles I created
“You’re listening to Radio Chateau HĂĄa”
“You’re still listening to Radio Chateau HĂĄa”
“Psst, here’s a message for Theodore: Mommy loves you! Radio Chateau HĂĄa”
Home Assistant
Now I could just leave this running 24/7, but since we’re not there most of the time, and the tractor isn’t always used, I figured it would make sense to have a way to start/stop the broadcast. With a robust Home Assistant setup already in place, this was a natural place to add it.
Claude helped me create a simple fm_mqtt_control.sh script which just listens and publishes state changes to MQTT, which is connected to Home Assistant as an mqtt switch:
| |
This gives a button I can use to start/stop the broadcast without needing to touch the Pi, and also lets me automatically shut down the broadcast when leaving, and enable it when the tractor is going to be used.
Finally I set up some systemd files for fm-radio.service and fm-radio-mqtt.service to ensure broadcast and MQTT listener run after reboot or crash.
Conclusion
All in all this turned out to be a lot easier than I was expecting, but it was quite fun and nostalgic to hear the music and jingles I selected be played on an FM radio!
Further improvements to look into would be slightly extending the range, since today it doesn’t fully cover the whole property, and when driving to the edges it abruptly cuts off. But then again, creates a bit of a “virtual boundary” so the kids don’t set off on too big of an adventure…
Resources
fm_shuffle.sh
| |
fm-radio.service
| |
fm_mqtt_control.sh
| |
fm-radio-mqtt.service
| |
