mirror of
https://github.com/Pecusx/piradio-mini.git
synced 2026-05-20 22:33:44 +02:00
932 lines
26 KiB
Python
Executable File
932 lines
26 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Raspberry Pi Internet Radio
|
|
# using an HD44780 LCD display
|
|
# $Id: radio4.py,v 1.111 2016/08/07 13:33:49 bob Exp $
|
|
#
|
|
# Author : Bob Rathbone
|
|
# Site : http://www.bobrathbone.com
|
|
#
|
|
# This program uses Music Player Daemon 'mpd'and it's client 'mpc'
|
|
# See http://mpd.wikia.com/wiki/Music_Player_Daemon_Wiki
|
|
#
|
|
# 4 x 20 character LCD version
|
|
#
|
|
# License: GNU V3, See https://www.gnu.org/copyleft/gpl.html
|
|
#
|
|
# Disclaimer: Software is provided as is and absolutly no warranties are implied or given.
|
|
# The authors shall not be liable for any loss or damage however caused.
|
|
#
|
|
|
|
|
|
import os
|
|
import RPi.GPIO as GPIO
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import socket
|
|
import string
|
|
import datetime
|
|
from time import strftime
|
|
import shutil
|
|
import atexit
|
|
import traceback
|
|
import requests
|
|
|
|
# Class imports
|
|
from radio_daemon import Daemon
|
|
from radio_class import Radio
|
|
from lcd_class import Lcd
|
|
from log_class import Log
|
|
from rss_class import Rss
|
|
from config_class import Configuration # for configuration read (Pecus)
|
|
from translate_class import Translate
|
|
from display_model import ModelInfo
|
|
|
|
|
|
# To use GPIO 14 and 15 (Serial RX/TX)
|
|
# Remove references to /dev/ttyAMA0 from /boot/cmdline.txt and /etc/inittab
|
|
|
|
UP = 0
|
|
DOWN = 1
|
|
|
|
#CurrentStationFile = "/var/lib/radiod/current_station"
|
|
#CurrentTrackFile = "/var/lib/radiod/current_track"
|
|
#CurrentFile = CurrentStationFile
|
|
PlaylistsDirectory = "/var/lib/mpd/playlists/"
|
|
|
|
|
|
log = Log()
|
|
radio = Radio()
|
|
lcd = Lcd()
|
|
rss = Rss()
|
|
config = Configuration() # for configuration read (Pecus)
|
|
translate = Translate()
|
|
ModelInfo = ModelInfo()
|
|
|
|
# Signal SIGTERM handler
|
|
def signalHandler(signal,frame):
|
|
global lcd
|
|
global log
|
|
radio.execCommand("umount /media > /dev/null 2>&1")
|
|
radio.execCommand("umount /share > /dev/null 2>&1")
|
|
pid = os.getpid()
|
|
log.message("Radio stopped, PID " + str(pid), log.INFO)
|
|
lcd.line1(" Radio stopped") # center alignment (Pecus)
|
|
lcd.line2("")
|
|
lcd.line3("")
|
|
lcd.line4("")
|
|
lcd.setBright(False) # LCD backlight brightness to low (Pecus)
|
|
GPIO.cleanup()
|
|
sys.exit(0)
|
|
|
|
# Daemon class
|
|
class MyDaemon(Daemon):
|
|
|
|
def run(self):
|
|
#global CurrentFile
|
|
radio.execCommand("modprobe snd-aloop")
|
|
|
|
GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers
|
|
GPIO.setwarnings(False) # Ignore warnings
|
|
|
|
# Get switches configuration
|
|
up_switch = radio.getSwitchGpio("up_switch")
|
|
down_switch = radio.getSwitchGpio("down_switch")
|
|
|
|
left_switch = radio.getSwitchGpio("left_switch")
|
|
right_switch = radio.getSwitchGpio("right_switch")
|
|
menu_switch = radio.getSwitchGpio("menu_switch")
|
|
|
|
boardrevision = radio.getBoardRevision()
|
|
if boardrevision == 1:
|
|
# For rev 1 boards with no inbuilt pull-up/down resistors
|
|
# Wire the GPIO inputs to ground via a 10K resistor
|
|
GPIO.setup(menu_switch, GPIO.IN)
|
|
GPIO.setup(up_switch, GPIO.IN)
|
|
GPIO.setup(down_switch, GPIO.IN)
|
|
GPIO.setup(left_switch, GPIO.IN)
|
|
GPIO.setup(right_switch, GPIO.IN)
|
|
|
|
else:
|
|
# For rev 2 boards with inbuilt pull-up/down resistors
|
|
# there is no need to physically wire the 10k resistors
|
|
GPIO.setup(menu_switch, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
|
GPIO.setup(up_switch, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
|
GPIO.setup(down_switch, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
|
GPIO.setup(left_switch, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
|
GPIO.setup(right_switch, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
|
|
|
# Initialise radio
|
|
log.init('radio')
|
|
signal.signal(signal.SIGTERM,signalHandler)
|
|
|
|
progcall = str(sys.argv)
|
|
log.message('Radio running pid ' + str(os.getpid()), log.INFO)
|
|
log.message("Radio " + progcall + " daemon version " + radio.getVersion(), log.INFO)
|
|
log.message("GPIO version " + str(GPIO.VERSION), log.INFO)
|
|
|
|
lcd.init(boardrevision)
|
|
lcd.setWidth(20)
|
|
lcd.line1("Radio version " + radio.getVersion())
|
|
time.sleep(0.5)
|
|
|
|
# Display daemon pid on the LCD
|
|
message = "Radio pid " + str(os.getpid())
|
|
lcd.line2(message)
|
|
|
|
lcd.line3("Waiting for network")
|
|
IPwait = 10 # Wait max 10s. for network
|
|
while IPwait > 0:
|
|
IPwait = IPwait - 1
|
|
ipaddr = exec_cmd('hostname -I')
|
|
if ipaddr is "":
|
|
time.sleep(1)
|
|
else:
|
|
IPwait = 0
|
|
|
|
lcd.line4("IP " + ipaddr)
|
|
hostname = exec_cmd('hostname -s')
|
|
log.message("IP " + ipaddr, log.INFO)
|
|
|
|
lcd.line3("Starting MPD")
|
|
radio.start()
|
|
log.message("MPD started", log.INFO)
|
|
time.sleep(0.5)
|
|
|
|
if config.bright: # LCD brightnes to high only if on in config file (Pecus)
|
|
lcd.setBright(True) # LCD backlight brightness to high (Pecus)
|
|
|
|
#mpd_version = radio.execMpcCommand("version")
|
|
mpd_version = 'mpd version: ' + exec_cmd('mpd -V | grep Daemon | cut -c21-')
|
|
log.message(mpd_version, log.INFO)
|
|
lcd.line3(mpd_version)
|
|
lcd.line4("GPIO: " + str(GPIO.VERSION) + " cores:"+str(radio.cores))
|
|
time.sleep(2.0)
|
|
|
|
reload(lcd,radio)
|
|
#radio.play(get_stored_id(CurrentFile))
|
|
#log.message("Current ID = " + str(radio.getCurrentID()), log.INFO)
|
|
#lcd.line3("Radio Station " + str(radio.getCurrentID()))
|
|
|
|
# Set up switch event processing
|
|
GPIO.add_event_detect(menu_switch, GPIO.RISING, callback=switch_event, bouncetime=200)
|
|
GPIO.add_event_detect(left_switch, GPIO.RISING, callback=switch_event, bouncetime=200)
|
|
GPIO.add_event_detect(right_switch, GPIO.RISING, callback=switch_event, bouncetime=200)
|
|
GPIO.add_event_detect(up_switch, GPIO.RISING, callback=switch_event, bouncetime=200)
|
|
GPIO.add_event_detect(down_switch, GPIO.RISING, callback=switch_event, bouncetime=200)
|
|
|
|
# Main processing loop
|
|
count = 0
|
|
toggleScrolling = True # Toggle scrolling between Line 2 and 3
|
|
while True:
|
|
|
|
# See if we have had an interrupt
|
|
switch = radio.getSwitch()
|
|
if switch > 0:
|
|
get_switch_states(lcd,radio,rss)
|
|
radio.setSwitch(0)
|
|
|
|
display_mode = radio.getDisplayMode()
|
|
lcd.setScrollSpeed(0.3) # Scroll speed normal
|
|
dateFormat = radio.getDateFormat()
|
|
todaysdate = strftime(dateFormat)
|
|
ipaddr = exec_cmd('hostname -I')
|
|
|
|
# Shutdown command issued
|
|
if display_mode == radio.MODE_SHUTDOWN:
|
|
displayShutdown(lcd)
|
|
while True:
|
|
time.sleep(1)
|
|
|
|
elif ipaddr is "":
|
|
lcd.line3(" No IP network!")
|
|
|
|
elif display_mode == radio.MODE_TIME:
|
|
if config.bright: # LCD brightnes to high only if on in config file (Pecus)
|
|
lcd.setBright(True) # LCD backlight brightness to high (Pecus)
|
|
if radio.getReload():
|
|
log.message("Reload ", log.DEBUG)
|
|
reload(lcd,radio)
|
|
radio.setReload(False)
|
|
|
|
input_source = radio.getSource()
|
|
if input_source == radio.RADIO:
|
|
msg = "r"
|
|
elif input_source == radio.PLAYER:
|
|
msg = "m"
|
|
elif input_source == radio.PANDORA:
|
|
msg = "p"
|
|
# sprawdzamy czy minal czas na potwierdzenie z Pandory i jesli tak to zerujemy flage potwierdzenia
|
|
if radio.pandora_watchdog_time <= int(time.time()):
|
|
radio.setReload(True)
|
|
msg = msg + ' ' + todaysdate # extra space before time (Pecus)
|
|
if radio.getStreaming():
|
|
msg = msg + ' *'
|
|
lcd.line1(msg)
|
|
display_current(lcd,radio,toggleScrolling)
|
|
|
|
elif display_mode == radio.MODE_SEARCH:
|
|
display_search(lcd,radio)
|
|
|
|
elif display_mode == radio.MODE_SOURCE:
|
|
display_source_select(lcd,radio)
|
|
|
|
elif display_mode == radio.MODE_OPTIONS:
|
|
display_options(lcd,radio)
|
|
|
|
elif display_mode == radio.MODE_IP:
|
|
displayInfo(lcd,ipaddr,mpd_version)
|
|
|
|
elif display_mode == radio.MODE_RSS:
|
|
msg = todaysdate + ' RSS' # extra RSS mode info (Pecus)
|
|
lcd.line1(msg)
|
|
input_source = radio.getSource()
|
|
current_id = radio.getCurrentID()
|
|
if input_source == radio.RADIO or input_source == radio.PANDORA:
|
|
station = radio.getRadioStation()
|
|
lcd.line2(station)
|
|
else:
|
|
lcd.line2(radio.getCurrentArtist())
|
|
display_rss(lcd,rss)
|
|
|
|
elif display_mode == radio.MODE_SLEEP:
|
|
msg = ' ' + todaysdate # extra 2 spaces before time (Pecus)
|
|
lcd.line2(msg) # in sleep mode time and date in second line of LCD (Pecus)
|
|
display_sleep(lcd,radio)
|
|
if config.rss: # RSS in standby only if on in config file (Pecus)
|
|
display_rss(lcd,rss)
|
|
else:
|
|
lcd.line3('')
|
|
|
|
# Timer function
|
|
checkTimer(radio)
|
|
|
|
# Check state (pause or play)
|
|
checkState(radio)
|
|
|
|
# Alarm wakeup function
|
|
if display_mode == radio.MODE_SLEEP and radio.alarmFired():
|
|
log.message("Alarm fired", log.INFO)
|
|
radio.unmute()
|
|
displayWakeUpMessage(lcd)
|
|
radio.setDisplayMode(radio.MODE_TIME)
|
|
radio.streamingWakeup()
|
|
|
|
# Toggle line 2 & 3 scrolling
|
|
if toggleScrolling:
|
|
toggleScrolling = False
|
|
else:
|
|
toggleScrolling = True
|
|
|
|
if display_mode == radio.MODE_SLEEP:
|
|
if config.rss:
|
|
time.sleep(0.1)
|
|
else:
|
|
time.sleep(1)
|
|
else:
|
|
time.sleep(0.1)
|
|
|
|
# End of main processing loop
|
|
|
|
def status(self):
|
|
# Get the pid from the pidfile
|
|
try:
|
|
pf = file(self.pidfile,'r')
|
|
pid = int(pf.read().strip())
|
|
pf.close()
|
|
except IOError:
|
|
pid = None
|
|
|
|
if not pid:
|
|
message = "radiod status: not running"
|
|
log.message(message, log.INFO)
|
|
print message
|
|
else:
|
|
message = "radiod running pid " + str(pid)
|
|
log.message(message, log.INFO)
|
|
print message
|
|
return
|
|
|
|
# End of class overrides
|
|
|
|
# Scrolling LCD display interrupt routine
|
|
def interrupt():
|
|
global lcd
|
|
global radio
|
|
global rss
|
|
interrupt = False
|
|
switch = radio.getSwitch()
|
|
if switch > 0:
|
|
interrupt = get_switch_states(lcd,radio,rss)
|
|
radio.setSwitch(0)
|
|
|
|
# Rapid display of track play status
|
|
if radio.getDisplayMode() != radio.MODE_SLEEP and radio.getDisplayMode() != radio.MODE_IP:
|
|
if radio.getSource() == radio.PLAYER or radio.getSource() == radio.PANDORA:
|
|
if radio.volumeChanged():
|
|
displayVolume(lcd,radio)
|
|
time.sleep(0.5)
|
|
else:
|
|
displayProgress(lcd,radio)
|
|
elif (radio.getTimer() and not interrupt) or radio.volumeChanged():
|
|
displayVolume(lcd,radio)
|
|
interrupt = checkTimer(radio)
|
|
|
|
if not interrupt:
|
|
interrupt = checkState(radio) or radio.getInterrupt()
|
|
|
|
# sprawdzamy czy minal czas na potwierdzenie z Pandory i jesli tak to zerujemy flage potwierdzenia
|
|
if radio.pandora_decision_time <= int(time.time()):
|
|
radio.pandora_decision = radio.OK
|
|
if radio.getDisplayMode() == radio.MODE_IP and not interrupt: # ten manewr umozliwia przerwanie przewijania RSSa i przejscie do ekranu info bez czekania
|
|
interrupt = checkState(radio) or radio.getInterrupt()
|
|
return interrupt
|
|
|
|
def no_interrupt():
|
|
return False
|
|
|
|
# Call back routine called by switch events
|
|
def switch_event(switch):
|
|
global radio
|
|
radio.setSwitch(switch)
|
|
return
|
|
|
|
# Check switch states
|
|
def get_switch_states(lcd,radio,rss):
|
|
interrupt = False # Interrupt display
|
|
switch = radio.getSwitch()
|
|
display_mode = radio.getDisplayMode()
|
|
input_source = radio.getSource()
|
|
option = radio.getOption()
|
|
|
|
# Get switches configuration
|
|
up_switch = radio.getSwitchGpio("up_switch")
|
|
down_switch = radio.getSwitchGpio("down_switch")
|
|
left_switch = radio.getSwitchGpio("left_switch")
|
|
right_switch = radio.getSwitchGpio("right_switch")
|
|
menu_switch = radio.getSwitchGpio("menu_switch")
|
|
|
|
if switch == menu_switch:
|
|
log.message("MENU switch", log.DEBUG)
|
|
# Shutdown if menu button held for > 3 seconds
|
|
MenuSwitch = GPIO.input(menu_switch)
|
|
count = 15
|
|
while MenuSwitch:
|
|
time.sleep(0.2)
|
|
MenuSwitch = GPIO.input(menu_switch)
|
|
count = count - 1
|
|
if count < 0:
|
|
log.message("Shutdown", log.DEBUG)
|
|
MenuSwitch = False
|
|
radio.setDisplayMode(radio.MODE_SHUTDOWN)
|
|
|
|
if display_mode == radio.MODE_SLEEP:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_WAKEUP')
|
|
else:
|
|
if radio.muted():
|
|
unmuteRadio(lcd,radio)
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_OK')
|
|
|
|
elif switch == up_switch:
|
|
log.message("UP switch display_mode " + str(display_mode), log.DEBUG)
|
|
|
|
if display_mode != radio.MODE_SLEEP:
|
|
|
|
if display_mode == radio.MODE_TIME:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_CHANNELUP')
|
|
|
|
else:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_UP')
|
|
|
|
else:
|
|
DisplayExitMessage(lcd)
|
|
|
|
elif switch == down_switch:
|
|
log.message("DOWN switch display_mode " + str(display_mode), log.DEBUG)
|
|
|
|
if display_mode != radio.MODE_SLEEP:
|
|
|
|
if display_mode == radio.MODE_TIME:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_CHANNELDOWN')
|
|
|
|
else:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_DOWN')
|
|
|
|
else:
|
|
DisplayExitMessage(lcd)
|
|
|
|
elif switch == left_switch:
|
|
log.message("LEFT switch" ,log.DEBUG)
|
|
|
|
if display_mode != radio.MODE_SLEEP:
|
|
|
|
if display_mode == radio.MODE_TIME:
|
|
if GPIO.input(right_switch):
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_MUTE')
|
|
else:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_VOLUMEDOWN')
|
|
|
|
else:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_LEFT')
|
|
|
|
else:
|
|
DisplayExitMessage(lcd)
|
|
|
|
elif switch == right_switch:
|
|
log.message("RIGHT switch" ,log.DEBUG)
|
|
|
|
if display_mode != radio.MODE_SLEEP:
|
|
|
|
if display_mode == radio.MODE_TIME:
|
|
if GPIO.input(left_switch):
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_MUTE')
|
|
else:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_VOLUMEUP')
|
|
|
|
else:
|
|
# Send remote code (simulate IR remote key)
|
|
udpSend('KEY_RIGHT')
|
|
|
|
else:
|
|
DisplayExitMessage(lcd)
|
|
|
|
return interrupt
|
|
|
|
# Sleep exit message
|
|
def DisplayExitMessage(lcd):
|
|
lcd.line3("Press menu button to")
|
|
lcd.line4(" exit sleep mode")
|
|
time.sleep(1)
|
|
lcd.line3("")
|
|
lcd.line4("")
|
|
return
|
|
|
|
# Update music library
|
|
def update_library(lcd,radio):
|
|
log.message("Updating library", log.INFO)
|
|
lcd.line1("Updating library")
|
|
lcd.line2("Please wait")
|
|
radio.updateLibrary()
|
|
return
|
|
|
|
# Reload if new source selected (RADIO or PLAYER)
|
|
def reload(lcd,radio):
|
|
lcd.line1("Loading:")
|
|
lcd.line3("Wait...")
|
|
lcd.line4("")
|
|
|
|
source = radio.getSource()
|
|
if source == radio.RADIO:
|
|
lcd.line2("Radio Stations")
|
|
dirList=os.listdir(PlaylistsDirectory)
|
|
for fname in dirList:
|
|
if os.path.isfile(fname):
|
|
continue
|
|
log.message("Loading " + fname, log.DEBUG)
|
|
lcd.line2(fname)
|
|
time.sleep(0.1)
|
|
radio.loadStations()
|
|
|
|
elif source == radio.PLAYER:
|
|
lcd.line2("Media library")
|
|
radio.loadMedia()
|
|
current = radio.execMpcCommand("current")
|
|
if len(current) < 1 or radio.getUpdateLibrary() or config.media_update: # If uptade flags set, update library on source switch (Pecus)
|
|
update_library(lcd,radio)
|
|
|
|
elif source == radio.PANDORA:
|
|
lcd.line2("Pandora radio")
|
|
radio.loadPandora()
|
|
|
|
return
|
|
|
|
# Display the RSS feed
|
|
def display_rss(lcd,rss):
|
|
rss_line = rss.getFeed()
|
|
lcd.setScrollSpeed(0.2) # Scroll RSS a bit faster
|
|
lcd.scroll3(rss_line,interrupt)
|
|
return
|
|
|
|
# Display the currently playing station or track
|
|
def display_current(lcd,radio,toggleScrolling):
|
|
station = radio.getRadioStation()
|
|
title = radio.getCurrentTitle()
|
|
current_id = radio.getCurrentID()
|
|
source = radio.getSource()
|
|
streeamname = ''
|
|
|
|
# Display progress of the currently playing track
|
|
if radio.muted():
|
|
displayVolume(lcd,radio)
|
|
else:
|
|
if source == radio.PLAYER or source == radio.PANDORA:
|
|
displayProgress(lcd,radio)
|
|
else:
|
|
displayVolume(lcd,radio)
|
|
|
|
if source == radio.RADIO:
|
|
streamname = '[' + station + '] - ' + title
|
|
if len(title) < 1:
|
|
streamname = '[' + station + ']'
|
|
bitrate = radio.getBitRate()
|
|
if bitrate > 0:
|
|
title = "Station " + str(current_id) + ' ' + str(bitrate) +'k'
|
|
if current_id <= 0:
|
|
lcd.line2("No stations found")
|
|
else:
|
|
if toggleScrolling:
|
|
lcd.line3(title)
|
|
lcd.scroll2(station, interrupt)
|
|
else:
|
|
lcd.line2(station)
|
|
elif source == radio.PANDORA:
|
|
streamname = title
|
|
if toggleScrolling:
|
|
lcd.line3(title)
|
|
lcd.scroll2(station, interrupt)
|
|
else:
|
|
lcd.line2(station)
|
|
else:
|
|
index = radio.getSearchIndex()
|
|
playlist = radio.getPlayList()
|
|
current_artist = radio.getCurrentArtist()
|
|
lcd.line2(current_artist)
|
|
streamname = current_artist + ' - ' + title
|
|
|
|
# Send metadata to icecast server
|
|
if radio.streaming:
|
|
if radio.streammetadata != streamname:
|
|
radio.streammetadata = streamname
|
|
metadataFormatted = translate.toLCD(streamname)
|
|
metadataFormatted = metadataFormatted.replace("%","%25")
|
|
metadataFormatted = metadataFormatted.replace("&","%26")
|
|
metadataFormatted = metadataFormatted.replace("@","%40")
|
|
metadataFormatted = metadataFormatted.replace(" ","+") #add "+" instead of " " for icecast2
|
|
# metadataFormatted = "Test+characters+x"
|
|
try:
|
|
requestToSend = ("http://localhost:8001/admin/metadata?mount=/mpd&mode=updinfo&song=") +(metadataFormatted)
|
|
r = requests.get((requestToSend), auth=("admin","mympd"))
|
|
except:
|
|
log.message("Send metadata do icacast server problem - metadata: " + metadataFormatted, log.ERROR)
|
|
|
|
|
|
# Display stream error
|
|
if radio.gotError():
|
|
errorStr = radio.getErrorString()
|
|
lcd.scroll3(errorStr,interrupt)
|
|
radio.clearError()
|
|
else:
|
|
leng = len(title)
|
|
if leng > 20:
|
|
if toggleScrolling:
|
|
lcd.line3(title)
|
|
else:
|
|
lcd.scroll3(title[0:160],interrupt)
|
|
else:
|
|
lcd.line3(title)
|
|
|
|
return
|
|
|
|
# Display if in sleep
|
|
def display_sleep(lcd,radio):
|
|
message = '' # I don't like text "Sleep mode" in sleep mode (Pecus)
|
|
lcd.setBright(False) # LCD backlight brightness to low (Pecus)
|
|
lcd.line1('') # time is now in second line, therefore we clean first line (Pecus)
|
|
if radio.alarmActive():
|
|
message = "Alarm " + radio.getAlarmTime()
|
|
lcd.line4(message)
|
|
return
|
|
|
|
# Get the last ID stored in /var/lib/radiod
|
|
def get_stored_id(current_file):
|
|
current_id = 5
|
|
if os.path.isfile(current_file):
|
|
current_id = int(readFromFile(current_file) ) # (Pecus)
|
|
return current_id
|
|
|
|
# Execute system command
|
|
def exec_cmd(cmd):
|
|
p = os.popen(cmd)
|
|
result = p.readline().rstrip('\n')
|
|
return result
|
|
|
|
# Read text line from file (Pecus)
|
|
def readFromFile(fname): # (Pecus)
|
|
file = open(fname, "r") # (Pecus)
|
|
text = file.readline() # (Pecus)
|
|
file.close() # (Pecus)
|
|
return text # (Pecus)
|
|
|
|
# Get list of tracks or stations
|
|
def get_mpc_list(cmd):
|
|
list = []
|
|
line = ""
|
|
p = os.popen("/usr/bin/mpc " + cmd)
|
|
while True:
|
|
line = p.readline().strip('\n')
|
|
if line.__len__() < 1:
|
|
break
|
|
list.append(line)
|
|
|
|
return list
|
|
|
|
# Source selection display
|
|
def display_source_select(lcd,radio):
|
|
|
|
lcd.line1("Input Source:")
|
|
source = radio.getSource()
|
|
if source == radio.RADIO:
|
|
lcd.line2("Internet Radio")
|
|
|
|
elif source == radio.PLAYER:
|
|
lcd.line2("Music Player")
|
|
|
|
elif source == radio.PANDORA:
|
|
lcd.line2("Pandora Radio")
|
|
|
|
return
|
|
|
|
# Display search (Station or Track)
|
|
def display_search(lcd,radio):
|
|
index = radio.getSearchIndex()
|
|
source = radio.getSource()
|
|
current_id = radio.getCurrentID()
|
|
|
|
if source == radio.PLAYER:
|
|
lcd.line1("Search:" + str(index + 1))
|
|
current_artist = radio.getArtistName(index)
|
|
lcd.scroll2(current_artist[0:160],interrupt)
|
|
lcd.scroll3(radio.getTrackNameByIndex(index),interrupt)
|
|
lcd.line4(radio.getProgress())
|
|
elif source == radio.PANDORA:
|
|
lcd.line1("Search:" + str(radio.pandora_search_index + 1))
|
|
current_station = radio.getPandoraStationName(radio.pandora_search_index)
|
|
lcd.line3("Current station:" + str(radio.current_pandora_id))
|
|
lcd.scroll2(current_station[0:160],interrupt)
|
|
lcd.line4(radio.getProgress())
|
|
pass
|
|
else:
|
|
lcd.line1("Search:" + str(index + 1))
|
|
current_station = radio.getStationName(index)
|
|
lcd.line3("Current station:" + str(radio.getCurrentID()))
|
|
lcd.scroll2(current_station[0:160],interrupt)
|
|
return
|
|
|
|
# Unmute radio and get stored volume
|
|
def unmuteRadio(lcd,radio):
|
|
radio.unmute()
|
|
volume = radio.getVolume()
|
|
lcd.line4("Volume " + str(VolumeToDisplay(volume)))
|
|
# radio.setDisplayMode(radio.MODE_TIME)
|
|
return
|
|
|
|
# Options menu
|
|
def display_options(lcd,radio):
|
|
option = radio.getOption()
|
|
|
|
if option != radio.TIMER and option != radio.ALARM \
|
|
and option != radio.ALARMSETHOURS and option != radio.ALARMSETMINS :
|
|
lcd.line1("Menu selection:")
|
|
|
|
if option == radio.RANDOM:
|
|
if radio.getRandom():
|
|
lcd.line2("Random on")
|
|
else:
|
|
lcd.line2("Random off")
|
|
|
|
elif option == radio.CONSUME:
|
|
if radio.getConsume():
|
|
lcd.line2("Consume on")
|
|
else:
|
|
lcd.line2("Consume off")
|
|
|
|
elif option == radio.REPEAT:
|
|
if radio.getRepeat():
|
|
lcd.line2("Repeat on")
|
|
else:
|
|
lcd.line2("Repeat off")
|
|
|
|
elif option == radio.TIMER:
|
|
lcd.line1("Set timer function:")
|
|
if radio.getTimer():
|
|
lcd.line2("Timer " + radio.getTimerString())
|
|
else:
|
|
lcd.line2("Timer off")
|
|
|
|
elif option == radio.ALARM:
|
|
alarmString = "off"
|
|
lcd.line1("Set alarm function:")
|
|
alarmType = radio.getAlarmType()
|
|
|
|
if alarmType == radio.ALARM_ON:
|
|
alarmString = "on"
|
|
elif alarmType == radio.ALARM_REPEAT:
|
|
alarmString = "repeat"
|
|
elif alarmType == radio.ALARM_WEEKDAYS:
|
|
alarmString = "weekdays only"
|
|
lcd.line2("Alarm " + alarmString)
|
|
|
|
elif option == radio.ALARMSETHOURS:
|
|
lcd.line1("Set alarm time:")
|
|
lcd.line2("Alarm " + radio.getAlarmTime() + " hours")
|
|
|
|
elif option == radio.ALARMSETMINS:
|
|
lcd.line1("Set alarm time:")
|
|
lcd.line2("Alarm " + radio.getAlarmTime() + " mins")
|
|
|
|
elif option == radio.STREAMING:
|
|
if radio.getStreaming():
|
|
lcd.line2("Streaming on")
|
|
else:
|
|
lcd.line2("Streaming off")
|
|
|
|
elif option == radio.RELOADLIB:
|
|
if radio.getUpdateLibrary():
|
|
lcd.line2("Update playlist: Yes")
|
|
else:
|
|
lcd.line2("Update playlist: No")
|
|
|
|
if radio.getSource() == radio.PLAYER or radio.getSource() == radio.PANDORA:
|
|
lcd.line4(radio.getProgress())
|
|
|
|
return
|
|
|
|
# Display volume and timer
|
|
def displayVolume(lcd,radio):
|
|
if radio.muted():
|
|
msg = "Sound muted"
|
|
else:
|
|
msg = "Volume " + str(VolumeToDisplay(radio.getVolume()))
|
|
if radio.getTimer():
|
|
msg = msg + " " + radio.getTimerString()
|
|
if radio.alarmActive():
|
|
msg = msg + ' ' + radio.getAlarmTime()
|
|
lcd.line4(msg)
|
|
return
|
|
|
|
# Display progress and timer
|
|
def displayProgress(lcd,radio):
|
|
if radio.muted():
|
|
msg = "Sound muted"
|
|
else:
|
|
msg = str(radio.getProgress())
|
|
if radio.getTimer():
|
|
msg = msg + " " + radio.getTimerString()
|
|
if radio.alarmActive():
|
|
msg = msg + ' ' + radio.getAlarmTime()
|
|
if radio.getSource() == radio.PANDORA and radio.pandora_decision != radio.OK:
|
|
# jesli czekamy na potwierdzenie decyzji w Pandorze to zamiast progresu wyswietlamy rodzaj decyzji
|
|
if radio.pandora_decision == radio.UP:
|
|
msg = "Like this track. OK?"
|
|
elif radio.pandora_decision == radio.DOWN:
|
|
msg = "Ban this track. OK?"
|
|
elif radio.pandora_decision == radio.LEFT:
|
|
msg = "Tired this track.OK?"
|
|
lcd.line4(msg)
|
|
return
|
|
|
|
# Display wake up message
|
|
def displayWakeUpMessage(lcd):
|
|
message = 'Good day'
|
|
t = datetime.datetime.now()
|
|
if t.hour >= 0 and t.hour < 12:
|
|
message = 'Good morning'
|
|
if t.hour >= 12 and t.hour < 18:
|
|
message = 'Good afternoon'
|
|
if t.hour >= 16 and t.hour <= 23:
|
|
message = 'Good evening'
|
|
lcd.line4(message)
|
|
time.sleep(3)
|
|
return
|
|
|
|
def displayShutdown(lcd):
|
|
lcd.setBright(False) # LCD backlight brightness to low (Pecus)
|
|
lcd.line1(" Stopping radio")
|
|
radio.execCommand("service mpd stop")
|
|
radio.pandora_stop()
|
|
lcd.line2(" ")
|
|
lcd.line3(" ")
|
|
lcd.line4(" ")
|
|
radio.execCommand("shutdown -h now")
|
|
lcd.line2(" Shutdown issued")
|
|
time.sleep(3)
|
|
lcd.line1(" Radio stopped")
|
|
lcd.line2(" Power off radio")
|
|
return
|
|
|
|
def displayInfo(lcd,ipaddr,mpd_version):
|
|
lcd.line2("Radio version " + radio.getVersion())
|
|
lcd.line3(mpd_version)
|
|
if ipaddr is "":
|
|
lcd.line4(" No IP network!")
|
|
else:
|
|
lcd.line4("IP "+ ipaddr)
|
|
lcd.scroll1("Raspberry PI Model " + ModelInfo.model + " rev." + ModelInfo.revision + " (" + str(ModelInfo.ram_mb) + "MB RAM, cores:" + str(radio.cores) + ") manufactured by " + ModelInfo.maker + ". GPIO version " + GPIO.VERSION,interrupt)
|
|
return
|
|
|
|
def VolumeToDisplay(volume):
|
|
volume = (volume - config.getVolumeMin()) * 100
|
|
tym = (config.getVolumeMax() - config.getVolumeMin())
|
|
volume = volume / tym
|
|
return volume
|
|
|
|
# Check Timer fired
|
|
def checkTimer(radio):
|
|
interrupt = False
|
|
if radio.fireTimer():
|
|
log.message("Timer fired", log.INFO)
|
|
radio.mute()
|
|
if radio.getSource() == radio.PANDORA: # Jesli gra pandora to nie pauzujemy (mutujemy) tylko stopujemy
|
|
radio.pandora_stop()
|
|
radio.setDisplayMode(radio.MODE_SLEEP)
|
|
radio.streamingSleep()
|
|
interrupt = True
|
|
return interrupt
|
|
|
|
# Check state (pause or play)
|
|
# If external client such as mpc or MPDroid issue a pause or play command
|
|
# Returns paused True if paused
|
|
def checkState(radio):
|
|
paused = False
|
|
display_mode = radio.getDisplayMode()
|
|
state = radio.getState()
|
|
radio.getVolume()
|
|
|
|
if state == 'pause':
|
|
paused = True
|
|
if not radio.muted():
|
|
if radio.alarmActive() and not radio.getTimer():
|
|
radio.setDisplayMode(radio.MODE_SLEEP)
|
|
radio.mute()
|
|
elif state == 'play':
|
|
if radio.muted():
|
|
unmuteRadio(lcd,radio)
|
|
radio.setDisplayMode(radio.MODE_TIME)
|
|
return paused
|
|
|
|
# Send button data to radio program
|
|
def udpSend(button):
|
|
udpport = config.getRemoteUdpPort()
|
|
udphost = config.getRemoteUdpHost()
|
|
data = ''
|
|
log.message("radio4.udpSend " + button, log.DEBUG)
|
|
|
|
try:
|
|
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
clientsocket.settimeout(3)
|
|
clientsocket.sendto(button, (udphost, udpport))
|
|
data = clientsocket.recv(100).strip()
|
|
|
|
except socket.error, e:
|
|
err = e.args[0]
|
|
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
|
|
log.message("radio4.udpSend no data" + e, log.ERROR)
|
|
else:
|
|
# Errors such as timeout
|
|
log.message("radio4.udpSend " + str(e), log.ERROR)
|
|
|
|
if len(data) > 0:
|
|
log.message("radio4.udpSend server sent: " + data, log.DEBUG)
|
|
return data
|
|
|
|
|
|
### Main routine ###
|
|
if __name__ == "__main__":
|
|
daemon = MyDaemon('/var/run/radiod.pid')
|
|
if len(sys.argv) == 2:
|
|
if 'start' == sys.argv[1]:
|
|
daemon.start()
|
|
elif 'stop' == sys.argv[1]:
|
|
os.system("service mpd stop")
|
|
daemon.stop()
|
|
elif 'restart' == sys.argv[1]:
|
|
daemon.restart()
|
|
elif 'status' == sys.argv[1]:
|
|
daemon.status()
|
|
elif 'nodaemon' == sys.argv[1]:
|
|
daemon.nodaemon()
|
|
elif 'version' == sys.argv[1]:
|
|
print "Version " + radio.getVersion()
|
|
else:
|
|
print "Unknown command: " + sys.argv[1]
|
|
sys.exit(2)
|
|
sys.exit(0)
|
|
else:
|
|
print "usage: %s start|stop|restart|status|version|nodaemon" % sys.argv[0]
|
|
sys.exit(2)
|
|
|
|
# End of script
|