Self-hosting my alarm clock radio
I don’t like waking up, before going to sleep I tend to schdule many alarms and the next morning I turn off each one of them.
When I was younger I remember having an old radio alarm that would turn on at a scheduled time, I used it as an wake up alarm and I remember being effective.
Maybe because hearing people talking would be less numbing that hearing the same song every day, and it would motivate me more to not turn off the alarm, maybe, I don’t know.
But I wanted to try this.
Radio
The trivial solution would be to just buy a radio with an alarm, but I discarded this from the start because
- I don't like the radio static, and even less when I can listen to a live broadcast on the internet very clearly.
- I didn’t want to spend money
Mobile
My first attempt was downloading an app that would do this. As I’m already waking up with my cellphone I might as well continue using it.
I tried the RadioDroid app, it seems like it has the features I want, it connects to a radio URL and can be used as an alarm clock. But upon using a few nights I’ve noted that the alarm doesn’t always go off. I guess it might be because it’s trying to attempt an active connection and Android goes into idle mode after a while?
Besides I like to turn Wi-Fi off at night, and I realise that it lacks some other nice-to-haves, like adjusting the volume incrementally.
I tried others apps but this was the more promising, I don't want payware, and I surely didn’t feel like programming in Android, so it seemed like I would need another option.
Raspberry Pi
I have a couple of raspberry pis through the house, one of them I use it as a server for various services that are running all day long. So I thought about using it for this purpose as well.
I moved the raspi to the bedroom and connected to it some old PC speakers I had.
Having the interface of a whole computer now I had much more control, as I can program it however I want. All I had to do is play audio through the speakers at a certain time.
The player
The core of the schedule is to just to reproduce audio through the raspberry’s speakers, so I needed an audio player for it.
My priorities were that I needed a program that would be lightweight, CLI so I could run it directly on the terminal, and that could also play radio files.
I wasn’t going to install anything fancy like VLC or MPV just to play an audio file. So after searching around I found mpg123, which fullfilled my needs perfectly, it is extremely lightweight, is CLI, doesn’t have an interface and reproduces radio files directly from the URL.
The radio
As I said on the beginning, I wanted to hear people talking, so I searched for an AM radio. The most popular here regardless of political spectrum is Radio Mitre, which I don't find it entirely despicable, so it works for me.
I scrapped it’s web and found a link for a MP3 file that could be reproduced directly
http://27323.live.streamtheworld.com/AM790_56.mp3
And after executing the following on the raspberry pi.
$ mpg123 http://27323.live.streamtheworld.com/AM790_56.mp3
High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3
version 1.26.4; written and copyright by Michael Hipp and others
free software (LGPL) without any warranty but with best wishes
Directory: http://27323.live.streamtheworld.com/
Terminal control enabled, press 'h' for listing of keys and functions.
Playing MPEG stream 1 of 1: AM790_56.mp3 ...
ICY-NAME:
ICY-URL: https://radiomitre.com.ar/
MPEG 1.0 L III cbr96 44100 j-s
ICY-META: StreamTitle='SEP WHATSAPP MITRE -SMD';
It’s working! The live radio is coming out from the speakers.
Off button
Now that it works, I need a way to turn it off when I’m already awake.
As I was thinking about how I could attach a physical button to the raspi and having to attach wires and other electronical things and such. I thought to myself
”Wait, I’m a Node.js developer, I don’t need buttons, I can host a bloated express server just to listen for an action, and then send a HTTP request from my phone to trigger it.”
So I had all the elements to start programming.
Programming
I started with the core functionality, spawning the radio process.
const { spawn } = require('node:child_process');
const play = spawn('mpg123', ['http://27323.live.streamtheworld.com/AM790_56.mp3']);
And then handling the process killing on an express endpoint.
const express = require('express');
const app = express();
app
.get('/apagar', (_req, res) => {
try {
play.kill(9);
res.send('Apagado\n');
process.exit(0);
} catch (error) {
res.status(500).send(error);
process.exit(1);
}
})
.listen(3000);
On my phone, I created a termux shortcut script that does the HTTP request.
curl $RASPBERRY_IP:3000/apagar
From this I can turn the alarm off with a single tap on my phone.
And the core functionality is done!
Cron job
All I had to do now is set the alarm in motion each morning, which I simply added a cron job to execute it at a determined time. In this case at 08:30.
30 8 * * * cd radespertador && npm run start
Increasing volume and parametrizing
One last feature I’d like to have is to the volume being increasing slowly, I don’t want to get startled all of the sudden of my sleep.
I had to spawn another child process with a call to control the volume, and in intervals call the controller with smaller increments of the percentage for the volume.
const setVolume = volume => spawn('amixer', ['sset', "'Headphone'", `${volume}%`]);
setVolume(0);
let currentVolume = 0;
setInterval(() => {
setVolume(currentVolume > 99 ? currentVolume : ++currentVolume);
}, 2000);
And of course it would be a bad practice to leave all of this with literals and magic numbers, so I had everything parameterized, and the values can be tweaked on the config file.
You can see the final code here.
Final result
Here’s a recording of how it works, for demostration purpose the increment for the volume is way more frequent than it is in reality
Conclusion
Did it work? Kind of, I still struggle to wake up. But at least now I can listen to boomers say random things on the morning before turning off the alarm, and I can say that I build that.