Information wants to be free...

Python Internet Radio Manager

In their infinite wisdom, the Norwegian government decided to shut down all FM boardcasts in favor of the even more obsolete and inferior DAB broadcast system this year. In response to their futile attempts, I have instead set up a Raspberry Pi 2 to function as an Internet radio and feed the audio into my existing radio equipment.

I only listen to the radio in the morning, so to avoid using the Internet connection at all times I needed some kind of manager. The result is a Python script which keeps track of the time of day and switches whatever is played on the audio output. This also gives the possibility to easily switch channels during the weekend.

Here is the script, where everything is just configured with my preferences within the script itself:

#!/usr/bin/python

import subprocess
import signal
import datetime
import time

events = (
  ("SUN", 15,  0, ["su", "root", "-c", "ntpdate 192.168.0.1"]),
  ("MON",  7, 45, ["mpg123", "http://nrk-mms-live.telenorcdn.net:80/nrk_radio_p1_rogaland_mp3_h"]),
  ("MON",  8, 30, ["./portal_looping_radio.sh"]),
  ("TUE",  7, 45, ["mpg123", "http://nrk-mms-live.telenorcdn.net:80/nrk_radio_p1_rogaland_mp3_h"]),
  ("TUE",  8, 30, ["./portal_looping_radio.sh"]),
  ("WED",  7, 45, ["mpg123", "http://nrk-mms-live.telenorcdn.net:80/nrk_radio_p1_rogaland_mp3_h"]),
  ("WED",  8, 30, ["./portal_looping_radio.sh"]),
  ("THU",  7, 45, ["mpg123", "http://nrk-mms-live.telenorcdn.net:80/nrk_radio_p1_rogaland_mp3_h"]),
  ("THU",  8, 30, ["./portal_looping_radio.sh"]),
  ("FRI",  7, 45, ["mpg123", "http://nrk-mms-live.telenorcdn.net:80/nrk_radio_p1_rogaland_mp3_h"]),
  ("FRI",  8, 30, ["./portal_looping_radio.sh"]),
  ("SAT",  7, 45, ["mpg123", "http://nrk-mms-live.telenorcdn.net:80/nrk_radio_jazz_mp3_h"]),
  ("SAT",  9, 30, ["./portal_looping_radio.sh"]),
  ("SUN",  7, 45, ["mpg123", "http://nrk-mms-live.telenorcdn.net:80/nrk_radio_jazz_mp3_h"]),
  ("SUN",  9, 30, ["./portal_looping_radio.sh"]),
)

default_event = ["./portal_looping_radio.sh"]

p = None

def alarm_handler(signum, frame):
    print "[RADIO] Got Alarm!"
    p.kill()

def event_to_secs(event):
    if event[0] == "MON":
        secs = 0
    elif event[0] == "TUE":
        secs = 86400
    elif event[0] == "WED":
        secs = 172800
    elif event[0] == "THU":
        secs = 259200
    elif event[0] == "FRI":
        secs = 345600
    elif event[0] == "SAT":
        secs = 432000
    elif event[0] == "SUN":
        secs = 518400

    secs += (event[1] * 3600)
    secs += (event[2] * 60)

    return secs

def get_next_event():
    now = datetime.datetime.now().timetuple()
    now_secs = (now.tm_wday * 86400) + (now.tm_hour * 3600) + (now.tm_min * 60) + now.tm_sec

    nearest_event_secs = 604801
    nearest_event = None
    first_event_secs = 604801
    first_event = None

    for event in events:
        event_secs = event_to_secs(event)
        if event_secs < first_event_secs:
            first_event_secs = event_secs
            first_event = event

        if event_secs > now_secs and event_secs < nearest_event_secs:
            nearest_event_secs = event_secs
            nearest_event = event

    if nearest_event == None:
        return (604800 + first_event_secs) - now_secs, first_event[3]
    else:
        return nearest_event_secs - now_secs, nearest_event[3]

if __name__ == "__main__":

    print "[RADIO] Starting"

    signal.signal(signal.SIGALRM, alarm_handler)
    p = subprocess.Popen(default_event)

    while True:
        timeleft, next_event = get_next_event()
        print "[RADIO] Time Left:", timeleft
        signal.alarm(timeleft)
        p.wait()
        print "[RADIO] Event:", next_event
        p = subprocess.Popen(next_event)
        time.sleep(30)
        p.poll()
        if p.returncode != None:
            print "[RADIO] Error, running default."
            p = subprocess.Popen(default_event)
            time.sleep(3)
            p.poll()
            if p.returncode != None:
                break

    print "[RADIO] Exit"
          


Topic: Scripts and Code, by Kjetil @ 16/12-2017, Article Link