#!/usr/bin/env python # # Raspberry Pi Internet Radio Class # $Id: radio_class.py,v 1.246 2016/07/24 08:36:34 bob Exp $ # # # Author : Bob Rathbone # Site : http://www.bobrathbone.com # # This class uses Music Player Daemon 'mpd' and the python-mpd library # Use "apt-get install python-mpd" to install the library # Modified to use python-mpd2 library mpd.wikia.com # See http://mpd.wikia.com/wiki/Music_Player_Daemon_Wiki # # 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 sys import string import time,datetime import re import ConfigParser import SocketServer from time import strftime import pdb import pexpect from udp_server_class import UDPServer from udp_server_class import RequestHandler from log_class import Log from translate_class import Translate from config_class import Configuration from language_class import Language from mpd import MPDClient # System files ConfigFile = "/etc/radiod.conf" RadioLibDir = "/var/lib/radiod" PlaylistsDirectory = "/var/lib/mpd/playlists" MusicDirectory = "/var/lib/mpd/music" CurrentStationFile = RadioLibDir + "/current_station" CurrentPandoraFile = RadioLibDir + "/current_pandora" CurrentTrackFile = RadioLibDir + "/current_track" RandomSettingFile = RadioLibDir + "/random" VolumeFile = RadioLibDir + "/volume" TimerFile = RadioLibDir + "/timer" AlarmFile = RadioLibDir + "/alarm" StreamFile = RadioLibDir + "/streaming" BoardRevisionFile = RadioLibDir + "/boardrevision" VersionFile = "/usr/share/radio/version" log = Log() translate = Translate() config = Configuration() language = None server = None Mpd = "/usr/bin/mpd" # Music Player Daemon Mpc = "/usr/bin/mpc" # Music Player Client client = MPDClient() # Create the MPD client class Radio: # Input source RADIO = 0 PLAYER = 1 PANDORA = 2 # Rotary class ROTARY_STANDARD = config.STANDARD ROTARY_ALTERNATIVE = config.ALTERNATIVE # Player options RANDOM = 0 CONSUME = 1 REPEAT = 2 RELOADLIB = 3 TIMER = 4 ALARM = 5 ALARMSETHOURS = 6 ALARMSETMINS = 7 STREAMING = 8 SELECTCOLOR = 9 OPTION_LAST = STREAMING OPTION_ADA_LAST = SELECTCOLOR # Display Modes MODE_TIME = 0 MODE_SEARCH = 1 MODE_SOURCE = 2 MODE_OPTIONS = 3 MODE_RSS = 4 MODE_IP = 5 MODE_SLEEP = 6 # Sleep after timer or waiting for alarm MODE_SHUTDOWN = -1 # Alarm definitions ALARM_OFF = 0 ALARM_ON = 1 ALARM_REPEAT = 2 ALARM_WEEKDAYS = 3 ALARM_LAST = ALARM_WEEKDAYS # Other definitions OK = -1 UP = 0 DOWN = 1 LEFT = 2 RIGHT = 3 ONEDAYSECS = 86400 # Day in seconds ONEDAYMINS = 1440 # Day in minutes DECISION_SEC = 3 # 3 sekundy na potwierdzenie OK (pandora) WATCHDOG_SEC = 6 # 6 sekund na info z pandory version = "0.0" boardrevision = 2 # Raspberry board version type cores = 0 # number of processor cores udphost = 'localhost' # Remote IR listener UDP Host udpport = 5100 # Remote IR listener UDP port number mpdport = 6600 # MPD port number volume = 80 # Volume level 0 - 100% device_error_cnt = 0 # Device error causes an abort isMuted = False # Is radio state "pause" or "stop" isPandoraPaused = True playlist = [] # Play list (tracks or radio stations) current_id = 1 # Currently playing track or station current_pandora_id = 3 max_pandora_id = 0 pandora_stationList = [''] pandora_stationIDs = [''] pandora_decision = OK # jesli nie OK to zostal wcisniety kursor i czekamy na potwierdzenie decyzji (+, -, ban) przyciskiem OK, w czasie oczekiwania na potwierdzenie zmienna przyjmuje wartosc kierunku kursora pandora_decision_time = 0 # czas (godzina z zegara) po ktorym uplywa czekanie na decyzje pandora_watchdog_time = 0 # czas (godzina z zegara) o ktorej ostatnio przyszlo info z pandory source = RADIO # Source RADIO or Player reload = False # Reload radio stations or player playlists artist = "" # Artist (Search routines) error = False # Stream error handling errorStr = "" # Error string switch = 0 # Switch just pressed updateLib = False # Reload radio stations or player numevents = 0 # Number of events recieved for a rotary switch volumeChange = False # Volume change flag (external clients) interrupt = False # Was IR remote interrupt received stats = None # MPD Stats array currentsong = None # Current song / station state = 'play' # State (used if get state fails) getIdError = False # Prevent repeated display of ID error StationNamesSource = config.LIST # Use own names from playlist use_playlist_extensions = False # MPD 0.16 requires playlist. rotary_class = config.STANDARD # Rotary class standard all alternate mode_last = MODE_IP # Last mode a user can select option_last = OPTION_LAST # Last available option display_mode = MODE_TIME # Display mode display_artist = False # Display artist (or tracck) flag current_file = "" # Currently playing track or station option_changed = False # Option changed channelChanged = True # Used to display title configOK = False # Do we have a configuration file display_playlist_number = False # Display playlist number # MPD Options random = False # Random play repeat = False # Repeat play consume = False # Consume tracks # Pandora titles pandora_station_name = '' pandora_song_name = '' pandora_progress = '' # Metadata for icecast server streammetadata = '' # Clock and timer options timer = False # Timer on timerValue = 30 # Timer value in minutes timeTimer = 0 # The time when the Timer was activated in seconds volumetime = 0 # Last volume check time dateFormat = "%H:%M %d/%m/%Y" # Date format alarmType = ALARM_OFF # Alarm on alarmTime = "0:7:00" # Alarm time default type,hours,minutes alarmTriggered = False # Alarm fired stationName = '' # Radio station name stationTitle = '' # Radio station title option = RANDOM # Player option search_index = 0 # The current search index pandora_search_index = 0 loadnew = False # Load new track from search streaming = False # Streaming (Icecast) disabled ADAFRUIT = 1 # I2C backpack type AdaFruit PCF8574 = 2 # I2C backpack type PCF8574 i2c_backpack = ADAFRUIT i2c_address = 0x00 # Use default I2C address speech = False # Speech for visually impaired or blind persons # Configuration files ConfigFiles = { CurrentStationFile: 1, CurrentTrackFile: 1, CurrentPandoraFile: 0, VolumeFile: 75, TimerFile: 30, AlarmFile: "07:00:00", StreamFile: "off", RandomSettingFile: 0, } # Initialisation routine def __init__(self): log.init('radio') self.setupConfiguration() return # Set up configuration files def setupConfiguration(self): # Create directory if not os.path.isfile(CurrentStationFile): self.execCommand ("mkdir -p " + RadioLibDir ) # Get version from file self.version = self.readFromFile(VersionFile) # (Pecus) self.version = self.version.rstrip('\r\n') # Initialise configuration files from ConfigFiles list for file in self.ConfigFiles: value = self.ConfigFiles[file] if not os.path.isfile(file) or os.path.getsize(file) == 0: # self.execCommand ("echo " + str(value) + " > " + file) # (Pecus) self.writeToFile (file,str(value)) # (Pecus) # Create mount point for USB stick and link it to the music directory if not os.path.isfile("/media"): self.execCommand("mkdir -p /media") if not os.path.ismount("/media"): self.execCommand("chown pi:pi /media") self.execCommand("ln -f -s /media /var/lib/mpd/music") # Create mount point for networked music library (NAS) if not os.path.isfile("/share"): self.execCommand("mkdir -p /share") if not os.path.ismount("/share"): self.execCommand("chown pi:pi /share") self.execCommand("ln -f -s /share /var/lib/mpd/music") self.execCommand("chown -R pi:pi " + RadioLibDir) self.execCommand("chmod -R 777 " + RadioLibDir) self.current_file = CurrentPandoraFile self.current_pandora_id = self.getStoredID(self.current_file) self.current_file = CurrentStationFile self.current_id = self.getStoredID(self.current_file) self.search_index = self.current_id - 1 return # Call back routine for the IR remote def remoteCallback(self): global server key = server.getData() log.message("IR remoteCallback " + key, log.DEBUG) if key == 'KEY_MUTE': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) if self.muted(): self.unmute() else: self.mute() self.setInterrupt() elif key == 'KEY_VOLUMEUP': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.increaseVolume() self.setInterrupt() self.volumeChange = True elif key == 'KEY_VOLUMEDOWN': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.decreaseVolume() self.setInterrupt() self.volumeChange = True elif key == 'KEY_CHANNELUP': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.channelUp() self.setInterrupt() elif key == 'KEY_CHANNELDOWN': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.channelDown() self.setInterrupt() elif key == 'KEY_MENU' or key == 'KEY_OK': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) # jesli czekamy na potwierdzenie Pandory to wywolujemy odpowiednia procke if self.pandora_decision != self.OK: self.setPandoraDecision(self.pandora_decision) self.pandora_decision = self.OK time.sleep(0.5) # przydaloby sie tytul odswiezyc ale jak??? self.getPandoraData() self.setInterrupt() # to chyba dziala ale dlaczego??? else: self.cycleMenu() self.setInterrupt() elif key == 'KEY_LANGUAGE': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.toggleSpeech() self.setInterrupt() elif key == 'KEY_INFO': if self.display_mode != self.MODE_SLEEP: # no speak in sleep mode! (Pecus) self.speakInformation() self.setInterrupt() # These come from the Web CGI script elif key == 'MEDIA': self.loadMedia() self.setInterrupt() elif key == 'RADIO': self.loadStations() self.setInterrupt() elif key == 'STREAMING_TOGGLE': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.toggleStreaming() self.setInterrupt() elif key == 'STREAMING_ON': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.streamingOn() self.setInterrupt() elif key == 'STREAMING_OFF': if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.streamingOff() self.setInterrupt() elif key == 'KEY_MEDIA': # and remote dedicated button (Pecus) if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.setPlayerSource() # (Pecus) if self.getReload(): # (Pecus) display_mode = self.MODE_TIME # (Pecus) self.setInterrupt() # (Pecus) elif key == 'KEY_RADIO': # and remote dedicated button (Pecus) if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.setRadioSource() # (Pecus) if self.getReload(): # (Pecus) display_mode = self.MODE_TIME # (Pecus) self.setInterrupt() # (Pecus) elif key == 'KEY_PANDORA': # and remote dedicated button (Pecus) if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.setPandoraSource() # (Pecus) if self.getReload(): # (Pecus) display_mode = self.MODE_TIME # (Pecus) self.setInterrupt() # (Pecus) elif key == 'INTERRUPT': self.setInterrupt() # Sleep mode - forcing timer (Pecus) elif key == 'KEY_SLEEP': # (Pecus) if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) self.timerValue = 1 # (Pecus) self.timerOn() # (Pecus) now = int(time.time()) # (Pecus) self.timeTimer = now - self.timerValue * 60 # (Pecus) self.fireTimer() # (Pecus) time.sleep(0.5) # Zapobiega przewinieciu sie calego tytulu pandory na LCD przed wylaczeniem... dlaczego??? self.setInterrupt() # (Pecus) time.sleep(0.5) # Zapobiega przewinieciu sie calego tytulu pandory na LCD przed wylaczeniem... dlaczego??? self.setInterrupt() # (Pecus) # Wakeup from sleep - forcing menu and unmute (Pecus) elif key == 'KEY_WAKEUP': # (Pecus) self.unmute() # (Pecus) display_mode = self.MODE_TIME # (Pecus) self.setDisplayMode(display_mode) # (Pecus) self.setInterrupt() # (Pecus) self.streamingWakeup() elif key == 'KEY_TIME': # timer on/off (Pecus) if self.display_mode != self.MODE_SLEEP: # no in sleep mode! (Pecus) if self.getTimer(): self.timerOff() else: self.timerOn() self.setInterrupt() # (Pecus) # Handle left,right, up and down keys else: self.handle_key(key) self.setInterrupt() return # Set up radio configuration and start the MPD daemon def start(self): global server global language config.display() # Get Configuration parameters /etc/radiod.conf self.boardrevision = self.getBoardRevision() self.cores = self.getCores() self.mpdport = config.getMpdPort() self.udpport = config.getRemoteUdpPort() self.udphost = config.getRemoteListenHost() self.display_playlist_number = config.getDisplayPlaylistNumber() self.source = config.getSource() self.speech = config.getSpeech() self.stationNamesSource = config.getStationNamesSource() language = Language(self.speech) # language is a global self.use_playlist_extensions = config.getPlaylistExtensions() self.rotary_class = config.getRotaryClass() # Log OS version information OSrelease = self.execCommand("cat /etc/os-release | grep NAME") OSrelease = OSrelease.replace("PRETTY_NAME=", "OS release: ") OSrelease = OSrelease.replace('"', '') log.message(OSrelease, log.INFO) myos = self.execCommand('uname -a') log.message(myos, log.INFO) # Start the player daemon self.execCommand("service mpd start") # Connect to MPD self.connect(self.mpdport) client.clear() self.randomOff() self.consumeOff() self.repeatOff() self.current_id = self.getStoredID(self.current_file) log.message("radio.start current ID " + str(self.current_id), log.DEBUG) self.volume = self.getStoredVolume() self.setVolume(self.volume) self.execCommand ("killall pianobar") # Necessary after restart problems # Alarm and timer settings self.timeTimer = int(time.time()) self.timerValue = self.getStoredTimer() self.alarmTime = self.getStoredAlarm() sType,sHours,sMinutes = self.alarmTime.split(':') self.alarmType = int(sType) if self.alarmType > self.ALARM_OFF: self.alarmType = self.ALARM_OFF # Icecast Streaming settings self.streaming = self.getStoredStreaming() if self.streaming: self.streamingOn() else: self.streamingOff() # Start the remote control listener try: server = UDPServer((self.udphost,self.udpport),RequestHandler) msg = "UDP Server listening on " + self.udphost + " port " + str(self.udpport) log.message(msg, log.INFO) server.listen(server,self.remoteCallback) except: log.message("UDP server could not bind to " + self.udphost + " port " + str(self.udpport), log.ERROR) return # Connect to MPD def connect(self,port): global client connection = False retry = 2 while retry > 0: client = MPDClient() # Create the MPD client try: client.timeout = 10 client.idletimeout = None client.connect("localhost", port) log.message("Connected to MPD port " + str(port), log.INFO) connection = True retry = 0 except: log.message("Failed to connect to MPD on port " + str(port), log.ERROR) time.sleep(2.5) # Wait for interrupt in the case of a shutdown log.message("Restarting MPD",log.DEBUG) if retry < 2: self.execCommand("service mpd restart") else: self.execCommand("service mpd start") time.sleep(2) # Give MPD time to restart retry -= 1 return connection # Handle IR remote key def handle_key(self,key): if self.display_mode == self.MODE_TIME: # obsluga kursorow pilota na glownym ekranie if self.source == self.PANDORA: # Tylko dla Pandory specjalne funkcje kursorow na pilocie if key == 'KEY_RIGHT': # kursor w prawo w czasie odtwarzania pandory - nastepny utwor self.PandoraNextTrack() time.sleep(0.5) self.getPandoraData() self.pandora_decision = self.OK elif key == 'KEY_UP': self.pandora_decision = self.UP self.pandora_decision_time = int(time.time()) + self.DECISION_SEC # kursor w gore - lubie # ale czekamy sekunde na potwierdzenie OK # no i tu trzeba cos wykombinowac :) pass elif key == 'KEY_DOWN': self.pandora_decision = self.DOWN self.pandora_decision_time = int(time.time()) + self.DECISION_SEC elif key == 'KEY_LEFT': self.pandora_decision = self.LEFT self.pandora_decision_time = int(time.time()) + self.DECISION_SEC else: if self.display_mode == self.MODE_OPTIONS: self.handle_options(key) elif self.display_mode == self.MODE_SOURCE: self.handle_source(key) elif self.display_mode == self.MODE_SEARCH: self.handle_search(key) self.optionChangedTrue() return # Handle stepping through menu options and changing them def handle_options(self,key): direction = -1 if key == 'KEY_UP': direction = self.UP elif key == 'KEY_DOWN': direction = self.DOWN elif key == 'KEY_LEFT': direction = self.LEFT elif key == 'KEY_RIGHT': direction = self.RIGHT if direction == self.UP or direction == self.DOWN: self.cycleOptions(direction) elif direction == self.LEFT or direction == self.RIGHT: self.changeOption(direction) return # Handle stepping through menu options def cycleOptions(self,direction): option = self.getOption() log.message("radio.cycleOptions option=" + str(option) \ + " direction=" + str(direction), log.DEBUG) # Cycle through option if direction == self.UP: option += 1 elif direction == self.DOWN: option -= 1 # Skip reload if not in player mode if option == self.RELOADLIB and self.source != self.PLAYER: if direction == self.UP: option += 1 else: option -= 1 if option > self.option_last: option = self.RANDOM elif option < 0: option = self.option_last if option == self.RELOADLIB and self.source != self.PLAYER: option -= 1 self.setOption(option) return # Handle search (IR routine) def handle_search(self,key): direction = self.UP if key == 'KEY_LEFT' or key == 'KEY_DOWN': direction = self.DOWN if self.source == self.RADIO: self.getNext(direction) elif self.source == self.PLAYER: # Step through tracks if key == 'KEY_LEFT' or key == 'KEY_RIGHT': self.getNext(direction) else: # Step through artist self.findNextArtist(direction) elif self.source == self.PANDORA: #pass self.getPandoraNext(direction) return # Toggle speech def toggleSpeech(self): sVoice = language.getText('voice') if self.speech: sOff = language.getText('off') self.speak(sVoice + ' ' + sOff) self.speech = False else: self.speech = True sOn = language.getText('on') self.speak(sVoice + ' ' + sOn) return # Scroll up and down between stations/tracks def getNext(self,direction): playlist = self.getPlayList() index = self.getSearchIndex() # Artist displayed then don't increment track first time in if not self.displayArtist(): leng = len(playlist) if leng > 0: if direction == self.UP: index = index + 1 if index >= leng: index = 0 else: index = index - 1 if index < 0: index = leng - 1 self.setSearchIndex(index) self.setLoadNew(True) name = self.getStationName(index) if name.startswith("http:") and '#' in name: url,name = name.split('#') msg = "radio.getNext index " + str(index) + " "+ name log.message(msg, log.DEBUG) if self.speech: self.speak(language.getText('search') + " " + str(index+1) + " " + name) return # Scroll up and down between pandora stations def getPandoraNext(self,direction): index = self.pandora_search_index # Artist displayed then don't increment track first time in if not self.displayArtist(): leng = self.max_pandora_id if leng > 0: if direction == self.UP: index = index + 1 if index >= leng: index = 0 else: index = index - 1 if index < 0: index = leng - 1 self.pandora_search_index = index self.setLoadNew(True) name = self.getPandoraStationName(index) if name.startswith("http:") and '#' in name: url,name = name.split('#') msg = "radio.getPandoraNext index " + str(index) + " "+ name log.message(msg, log.DEBUG) if self.speech: self.speak(language.getText('search') + " " + str(index+1) + " " + name) return # Scroll through tracks by artist def findNextArtist(self,direction): self.setLoadNew(True) index = self.getSearchIndex() playlist = self.getPlayList() current_artist = self.getArtistName(index) found = False leng = len(playlist) count = leng while not found: if direction == self.UP: index = index + 1 if index >= leng: index = 0 else: index = index - 1 if index < 1: index = leng - 1 new_artist = self.getArtistName(index) if current_artist != new_artist: found = True count = count - 1 # Prevent everlasting loop if count < 1: found = True index = self.current_id # If a Backward Search find start of this list found = False if direction == self.DOWN: self.current_artist = new_artist while not found: index = index - 1 new_artist = self.getArtistName(index) if self.current_artist != new_artist: found = True index = index + 1 if index >= leng: index = leng-1 self.setSearchIndex(index) if self.speech: self.speak( str(index+1) + " " + new_artist) return # Change option (Used by remote control and non display radio only) def changeOption(self,direction): option = self.getOption() sOptions = language.getOptionText() sOption = sOptions[option] log.message("radio.changeOption " + str(option) + " " + sOption, log.DEBUG) if option == self.RANDOM: if self.getRandom(): self.randomOff() else: self.randomOn() elif option == self.CONSUME: if self.getConsume(): self.consumeOff() else: self.consumeOn() elif option == self.REPEAT: if self.getRepeat(): self.repeatOff() else: self.repeatOn() elif option == self.ALARM: self.alarmCycle(direction) elif option == self.STREAMING: self.toggleStreaming() elif option == self.RELOADLIB: if self.getUpdateLibrary(): self.setUpdateLibOff() else: self.setUpdateLibOn() elif option == self.TIMER: if self.getTimer(): if direction == self.RIGHT: self.incrementTimer(1) else: self.decrementTimer(1) else: self.timerOn() elif option == self.ALARMSETHOURS or option == self.ALARMSETMINS : value = 1 if option == self.ALARMSETHOURS: value = 60 if direction == self.RIGHT: self.incrementAlarm(value) else: self.decrementAlarm(value) self.optionChangedTrue() self.speakOption(option) return # Handle toggling of source def handle_source(self,key): if key == 'KEY_UP': self.toggleSource(self.UP) if key == 'KEY_DOWN': self.toggleSource(self.DOWN) return # Input Source RADIO, NETWORK or PLAYER def getSource(self): return self.source def setSource(self,source): self.source = source # Reload playlists flag def getReload(self): return self.reload def setReload(self,reload): log.message("radio.setReload " + str(reload), log.DEBUG) self.reload = reload # Reload music library flag def getUpdateLibrary(self): return self.updateLib def setUpdateLibOn(self): self.updateLib = True def setUpdateLibOff(self): self.updateLib = False # Load new track flag def loadNew(self): return self.loadnew def setLoadNew(self,loadnew): log.message("radio.setLoadNew " + str(loadnew), log.DEBUG) self.loadnew = loadnew return # Get the Raspberry pi board version from /proc/cpuinfo def getBoardRevision(self): revision = 1 with open("/proc/cpuinfo") as f: cpuinfo = f.read() rev_hex = re.search(r"(?<=\nRevision)[ |:|\t]*(\w+)", cpuinfo).group(1) rev_int = int(rev_hex,16) if rev_int > 3: revision = 2 self.boardrevision = revision log.message("Board revision " + str(self.boardrevision), log.INFO) return self.boardrevision # Get number of processor cores from /proc/cpuinfo def getCores(self): cores_text = self.execCommand("cat /proc/cpuinfo | grep -c 'processor[[:blank:]]:'") self.cores = int(cores_text) return self.cores # Get the MPD port number def getMpdPort(self): port = 6600 if os.path.isfile(MpdPortFile): try: # port = int(self.execCommand("cat " + MpdPortFile) ) # (Pecus) port = int(self.readFromFile(MpdPortFile) ) # (Pecus) except ValueError: port = 6600 else: log.message("Error reading " + MpdPortFile, log.ERROR) return port # Get options (synchronise with external mpd clients) def getOptions(self,stats): try: random = int(stats.get("random")) if random == 1: self.random = True else: self.random = False repeat = int(stats.get("repeat")) if repeat == 1: self.repeat = True else: self.repeat = False consume = int(stats.get("consume")) if consume == 1: self.consume = True else: self.consume = False except: log.message("radio.getOptions get error" + MpdPortFile, log.ERROR) return # Get volume and check if it has been changed by any MPD external client # Slug MPD calls to no more than per 0.5 second def getVolume(self): volume = 0 error = False try: now = time.time() if now > self.volumetime + 0.5: stats = self.getStats() volume = int(stats.get("volume")) self.volumetime = time.time() else: volume = self.volume except: log.message("radio.getVolume failed", log.ERROR) volume = 1 error = True if volume == str("None"): volume = -1 error = True if volume < 0: error = True if not error: if volume < config.getVolumeMin(): volume = config.getVolumeMin() if volume > config.getVolumeMax(): wolume = config.getVolumeMax() if volume != self.volume: if not error: self.device_error_cnt = 0 log.message("radio.getVolume external client changed volume " + str(volume),log.DEBUG) self.setVolume(volume) self.volumeChange = True else: self.device_error_cnt += 1 log.message("radio.getVolume audio device error " + str(volume), log.ERROR) if self.device_error_cnt > 10: msg = "Sound device error - exiting" log.message("radio._getVolume " + msg, log.ERROR) print msg sys.exit(1) return self.volume # Check for volume change def volumeChanged(self): volumeChange = self.volumeChange self.volumeChange = False return volumeChange # Set volume 0-100 def setVolume(self,volume): if self.muted(): self.unmute() else: if volume > config.getVolumeMax(): volume = config.getVolumeMax() elif volume < config.getVolumeMin(): volume = config.getVolumeMin() try: if volume != self.volume: log.message("radio.setVolume vol=" + str(volume),log.DEBUG) client.setvol(volume) self.volume = volume # Don't change stored volume (Needed for unmute function) if not self.muted(): self.storeVolume(self.volume) except: log.message("radio.setVolume error vol=" + str(self.volume),log.ERROR) return self.volume # Increase volume def increaseVolume(self): increment = config.getVolumeIncrement() volume = self.volume + increment log.message("radio.increaseVolume vol=" + str(volume),log.DEBUG) volume = self.setVolume(volume) return volume # Decrease volume def decreaseVolume(self): increment = config.getVolumeIncrement() volume = self.volume - increment log.message("radio.decreaseVolume vol=" + str(volume),log.DEBUG) volume = self.setVolume(volume) return volume # Mute sound functions (Also stops MPD if not streaming) def mute(self): log.message("radio.mute streaming=" + str(self.streaming),log.DEBUG) try: if self.source == self.RADIO: client.stop() # Disconnect from stream log.message("radio.mute radio stop",log.DEBUG) elif self.source == self.PLAYER: client.pause(1) # Pause playing track log.message("radio.mute player pause",log.DEBUG) elif self.source == self.PANDORA: try: if self.pianobar.isalive(): self.pianobar.send('p') self.isPandoraPaused = True log.message("radio.mute pandora pause",log.DEBUG) except: log.message("radio.mute pianobar pause error",log.DEBUG) self.isMuted = True except: log.message("radio.mute error",log.DEBUG) return # Unmute sound fuction, get stored volume def unmute(self): if self.muted(): self.volume = self.getStoredVolume() log.message("radio.unmute volume=" + str(self.volume),log.DEBUG) try: if self.source == self.RADIO or self.source == self.PLAYER: client.play() client.setvol(self.volume) log.message("radio.unmute radio or player play",log.DEBUG) elif self.source == self.PANDORA: try: if self.pianobar.isalive(): self.pianobar.send('P') self.isPandoraPaused = False else: self.setReload(True) #self.pandora_start() except: self.setReload(True) #self.pandora_start() log.message("radio.unmute pandora unpause or reload",log.DEBUG) self.isMuted = False except: log.message("radio.unmute error",log.ERROR) return self.volume def muted(self): return self.isMuted # Start MPD (Alarm mode) def startMPD(self): try: client.play() except: log.message("radio.startMPD error",log.ERROR) return # Stop MPD (Alarm mode) def stopMPD(self): try: client.stop() except: log.message("radio.stopMPD error",log.ERROR) return # Get the stored volume def getStoredVolume(self): volume = 75 if os.path.isfile(VolumeFile): try: # volume = int(self.execCommand("cat " + VolumeFile) ) # (Pecus) volume = int(self.readFromFile(VolumeFile) ) # (Pecus) except ValueError: volume = 75 else: log.message("Error reading " + VolumeFile, log.ERROR) return volume # Store volume in volume file def storeVolume(self,volume): # self.execCommand ("echo " + str(volume) + " > " + VolumeFile) # (Pecus) self.writeToFile (VolumeFile,str(volume)) # (Pecus) return # Random setting def getRandom(self): if self.source == self.PLAYER: self.random = self.getStoredRandomSetting() return self.random def randomOn(self): try: client.random(1) self.random = True if self.source == self.PLAYER: # self.execCommand ("echo " + str(1) + " > " + RandomSettingFile) # (Pecus) self.writeToFile (RandomSettingFile,str(1)) # (Pecus) except: log.message("radio.randomOn error",log.ERROR) return self.random def randomOff(self): try: client.random(0) self.random = False if self.source == self.PLAYER: # self.execCommand ("echo " + str(0) + " > " + RandomSettingFile) # (Pecus) self.writeToFile (RandomSettingFile,str(0)) # (Pecus) except: log.message("radio.randomOff error",log.ERROR) return self.random # Get the stored random setting 0=off 1=on def getStoredRandomSetting(self): random = 0 if os.path.isfile(RandomSettingFile): try: # random = int(self.execCommand("cat " + RandomSettingFile) ) # (Pecus) random = int(self.readFromFile(RandomSettingFile) ) # (Pecus) except ValueError: random = 0 else: log.message("Error reading " + RandomSettingFile, log.ERROR) if random is 1: self.random = True else: self.random = False return self.random # Repeat def getRepeat(self): return self.repeat def repeatOn(self): try: client.repeat(1) self.repeat = True except: log.message("radio.repeatOn error",log.ERROR) return def repeatOff(self): try: client.repeat(0) self.repeat = False except: log.message("radio.repeatOff error",log.ERROR) return # Consume def getConsume(self): return self.consume def consumeOn(self): try: client.consume(1) self.consume = True except: log.message("radio.consumeOn error",log.ERROR) return def consumeOff(self): try: client.consume(0) self.consume = False except: log.message("radio.consumeOff error",log.ERROR) return # Timer functions def getTimer(self): return self.timer def timerOn(self): self.timerValue = self.getStoredTimer() self.timeTimer = int(time.time()) self.timer = True return self.timer def timerOff(self): self.timer = False self.timerValue = 0 return self.timer def getTimerValue(self): return self.timerValue def fireTimer(self): fireTimer = False if self.timer and self.timerValue > 0: now = int(time.time()) if now > self.timeTimer + self.timerValue * 60: fireTimer = True # Store fired value # self.storeTimer(self.timerValue) self.timerOff() return fireTimer # Display the amount of time remaining def getTimerString(self): tstring = '' now = int(time.time()) value = self.timeTimer + self.timerValue * 60 - now if value > 0: minutes,seconds = divmod(value,60) hours,minutes = divmod(minutes,60) if hours > 0: tstring = '%d:%02d:%02d' % (hours,minutes,seconds) else: tstring = '%d:%02d' % (minutes,seconds) else: tstring = 'off' return tstring # Increment timer. def incrementTimer(self,inc): if self.timerValue >= 60: inc = 10 self.timerValue += inc if self.timerValue > self.ONEDAYMINS: self.timerValue = self.ONEDAYMINS self.timeTimer = int(time.time()) return self.timerValue def decrementTimer(self,dec): if self.timerValue > 60: dec = 10 self.timerValue -= dec if self.timerValue < 0: self.timerValue = 0 self.timer = False self.timeTimer = int(time.time()) return self.timerValue # Get the stored timer value def getStoredTimer(self): timerValue = 0 if os.path.isfile(TimerFile): try: # timerValue = int(self.execCommand("cat " + TimerFile) ) # (Pecus) timerValue = int(self.readFromFile(TimerFile) ) # (Pecus) except ValueError: timerValue = 30 else: log.message("Error reading " + TimerFile, log.ERROR) return timerValue # Store timer time in timer file def storeTimer(self,timerValue): # self.execCommand ("echo " + str(timerValue) + " > " + TimerFile) # (Pecus) self.writeToFile (TimerFile,str(timerValue)) # (Pecus) return # Radio Alarm Functions def alarmActive(self): alarmActive = False if self.alarmType != self.ALARM_OFF: alarmActive = True return alarmActive # Cycle through alarm types def alarmCycle(self,direction): if direction == self.UP: self.alarmType += 1 else: self.alarmType -= 1 if self.alarmType > self.ALARM_LAST: self.alarmType = self.ALARM_OFF elif self.alarmType < self.ALARM_OFF: self.alarmType = self.ALARM_LAST if self.alarmType > self.ALARM_OFF: self.alarmTime = self.getStoredAlarm() sType,sHours,sMinutes = self.alarmTime.split(':') hours = int(sHours) minutes = int(sMinutes) self.alarmTime = '%d:%d:%02d' % (self.alarmType,hours,minutes) self.storeAlarm(self.alarmTime) return self.alarmType # Switch off the alarm unless repeat or days of the week def alarmOff(self): if self.alarmType == self.ALARM_ON: self.alarmType = self.ALARM_OFF return self.alarmType # Increment alarm time def incrementAlarm(self,inc): sType,sHours,sMinutes = self.alarmTime.split(':') hours = int(sHours) minutes = int(sMinutes) + inc if minutes >= 60: minutes = minutes - 60 hours += 1 if hours >= 24: hours = 0 self.alarmTime = '%d:%d:%02d' % (self.alarmType,hours,minutes) self.storeAlarm(self.alarmTime) return '%d:%02d' % (hours,minutes) # Decrement alarm time def decrementAlarm(self,dec): sType,sHours,sMinutes = self.alarmTime.split(':') hours = int(sHours) minutes = int(sMinutes) - dec if minutes < 0: minutes = minutes + 60 hours -= 1 if hours < 0: hours = 23 self.alarmTime = '%d:%d:%02d' % (self.alarmType,hours,minutes) self.storeAlarm(self.alarmTime) return '%d:%02d' % (hours,minutes) # Fire alarm if current hours/mins matches time now def alarmFired(self): fireAlarm = False if self.alarmType > self.ALARM_OFF: sType,sHours,sMinutes = self.alarmTime.split(':') type = int(sType) hours = int(sHours) minutes = int(sMinutes) t1 = datetime.datetime.now() t2 = datetime.time(hours, minutes) weekday = t1.today().weekday() if t1.hour == t2.hour and t1.minute == t2.minute and not self.alarmTriggered: # Is this a weekday if type == self.ALARM_WEEKDAYS and weekday < 5: fireAlarm = True elif type < self.ALARM_WEEKDAYS: fireAlarm = True if fireAlarm: self.alarmTriggered = fireAlarm if type == self.ALARM_ON: self.alarmOff() log.message("radio.larmFired type " + str(type), log.DEBUG) else: self.alarmTriggered = False return fireAlarm # Get the stored alarm value def getStoredAlarm(self): alarmValue = '' if os.path.isfile(AlarmFile): try: # alarmValue = self.execCommand("cat " + AlarmFile) # (Pecus) alarmValue = self.readFromFile(AlarmFile) # (Pecus) except ValueError: alarmValue = "0:7:00" else: log.message("Error reading " + AlarmFile, log.ERROR) return alarmValue # Store alarm time in alarm file def storeAlarm(self,alarmString): # self.execCommand ("echo " + alarmString + " > " + AlarmFile) # (Pecus) self.writeToFile (AlarmFile,alarmString) # (Pecus) return # Get the actual alarm time def getAlarmTime(self): sType,sHours,sMinutes = self.alarmTime.split(':') hours = int(sHours) minutes = int(sMinutes) return '%d:%02d' % (hours,minutes) # Get the alarm type def getAlarmType(self): if self.alarmType > self.ALARM_LAST: self.alarmType = self.ALARM_OFF return self.alarmType # Get the date format def getDateFormat(self): return config.getDateFormat() # Get the stored streaming value def getStoredStreaming(self): streamValue = "off" streaming = False if os.path.isfile(StreamFile): try: # streamValue = self.execCommand("cat " + StreamFile) # (Pecus) streamValue = self.readFromFile(StreamFile) # (Pecus) except ValueError: streamValue = "off" else: log.message("Error reading " + StreamFile, log.ERROR) if streamValue == "on": streaming = True else: streaming = False return streaming # Toggle streaming on off # Stream number is 2 def toggleStreaming(self): if self.streamingAvailable(): if self.streaming: self.streamingOff() else: self.streamingOn() else: self.streaming = False self.storeStreaming("off") return self.streaming # Switch on Icecast2 streaming def streamingOn(self): if self.streamingAvailable(): output_id = 2 self.streaming = True self.execCommand("service icecast2 start") self.execCommand("service darkice start") self.execMpcCommand("enable " + str(output_id)) self.storeStreaming("on") self.streamingStatus() else: self.streaming = False self.storeStreaming("off") self.streammetadata = '' return self.streaming # Sleep Icecast2 streaming def streamingSleep(self): if self.streamingStat(): output_id = 2 self.execMpcCommand("disable " + str(output_id)) self.execCommand("service darkice stop") self.execCommand("service icecast2 stop") self.streamingStatus() self.streammetadata = '' return self.streaming # Wakeup Icecast2 streaming def streamingWakeup(self): if self.streaming and not self.streamingStat(): if self.streamingAvailable(): output_id = 2 self.execCommand("service icecast2 start") self.execCommand("service darkice start") self.execMpcCommand("enable " + str(output_id)) self.streamingStatus() self.streammetadata = '' return self.streaming # Switch off Icecast2 streaming def streamingOff(self): output_id = 2 self.streaming = False self.execMpcCommand("disable " + str(output_id)) self.execCommand("service darkice stop") self.execCommand("service icecast2 stop") self.storeStreaming("off") self.streamingStatus() self.streammetadata = '' return self.streaming # Check streaming status def streamingStat(self): status = self.execCommand("mpc outputs | grep -i 2\.*\enabled") stat = True if len(status)<1: stat = False return stat # Log streaming status def streamingStatus(self): status = "No Icecast streaming" if self.streamingStat(): status = "Icecast streaming enabled" log.message(status, log.INFO) return # Check if icecast streaming installed and pocessor has more than 1 core def streamingAvailable(self): fpath = "/usr/bin/icecast2" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) and ((self.cores>1) or config.getForceStreaming()) # Store stram on or off in streaming file def storeStreaming(self,onoff): # self.execCommand ("echo " + onoff + " > " + StreamFile) # (Pecus) self.writeToFile (StreamFile,onoff) # (Pecus) return # Get the streaming value def getStreaming(self): return self.streaming # Option changed def optionChanged(self): return self.option_changed def optionChangedTrue(self): #if self.speech and self.display_mode != self.MODE_SEARCH: # self.speakOption(self.option) self.option_changed = True return def optionChangedFalse(self): self.option_changed = False return # Set and get Display mode def getDisplayMode(self): return self.display_mode # Mode string for debugging def getDisplayModeString(self): sMode = ["MODE_TIME", "MODE_SEARCH", "MODE_SOURCE", "MODE_OPTIONS", "MODE_RSS", "MODE_IP", "MODE_SLEEP"] return sMode[self.display_mode] # Set display mode from menu button or IR remote def setDisplayMode(self,display_mode): if self.display_mode >= 0: log.message("radio.setDisplayMode " + str(display_mode), log.DEBUG) self.display_mode = display_mode if self.speech: self.speakMenu(display_mode) return # Speak menu def speakMenu(self,display_mode): # Speak menu sMenu = language.getMenuText() if display_mode != self.MODE_SLEEP: msg = sMenu[display_mode] self.speak(msg) if display_mode is self.MODE_OPTIONS: if not self.reload: self.speakOption(self.option) # Speak option def speakOption(self,option): sYes = language.getText("yes") sNo = language.getText("no") sOn = language.getText("on") sOff = language.getText("off") sParam = sOff sOptions = language.getOptionText() sOption = sOptions[option] if option == self.RANDOM: if self.getRandom(): sParam = sOn elif option == self.CONSUME: if self.getConsume(): sParam = sOn elif option == self.REPEAT: if self.getRepeat(): sParam = sOn #elif option == self.ALARM: elif option == self.STREAMING: if self.streaming: sParam = sOn elif option == self.RELOADLIB: if self.updateLib: sParam = sYes else: sParam = sNo elif option == self.TIMER: sOption = "Timer" sParam = self.getTimerString() sParam = sParam.replace(':', ' ') elif option == self.ALARM: sTypes = ['off', 'on', 'repeat', 'week days only'] type = self.getAlarmType() sOption = "Alarm" sParam = sTypes[type] elif option == self.ALARMSETHOURS or self.ALARMSETMINS: sType,sHours,sMinutes = self.alarmTime.split(':') hours = int(sHours) minutes = int(sMinutes) sOption = "Hours" if option == self.ALARMSETMINS: sOption = "Minutes" sParam = '%d %02d' % (hours,minutes) self.speak(sOption + ' ' + sParam) return # Cycle through the menu def cycleMenu(self): # If a reload has been issued return to TIME display if self.getReload(): display_mode = self.MODE_TIME elif self.search_index+1 != self.current_id: # zmiana kanalu radiowego lub utworu przez menu self.current_id = self.search_index+1 self.play(self.current_id) display_mode = self.MODE_TIME elif self.pandora_search_index+1 != self.current_pandora_id: # zmiana kanalu pandory przez menu self.current_pandora_id = self.pandora_search_index+1 self.setPandoraStation() display_mode = self.MODE_TIME else: display_mode = self.getDisplayMode() + 1 if display_mode > self.mode_last: display_mode = self.MODE_TIME if self.optionChanged(): display_mode = self.MODE_TIME self.optionChangedFalse() # If new time of Timer is set - Save it (only if longer than 4 minutes) if self.timerValue != self.getStoredTimer(): if self.timerValue > 4: self.storeTimer(self.timerValue) self.setDisplayMode(display_mode) self.pandora_watchdog_time = int(time.time()) + self.WATCHDOG_SEC return # Set any option you like here def getOption(self): return self.option def setOption(self,option): log.message("radio.setOption option " + str(option), log.DEBUG) self.option = option self.speakOption(self.option) return # Set the menu restriction for radios without a display (retro_radio.py) def setLastMode(self,mode_last): if mode_last >= self.MODE_OPTIONS and mode_last <= self.mode_last: self.mode_last = mode_last return self.mode_last # Set the options restriction for radios without a display (retro_radio.py) def setLastOption(self,option_last): if option_last >= self.REPEAT and option_last <= self.RELOADLIB: self.option_last = option_last return self.option_last # Execute system command def execCommand(self,cmd): p = os.popen(cmd) return p.readline().rstrip('\n') # Execute MPC comnmand via OS # Some commands are easier using mpc and don't have # an effect adverse on performance def execMpcCommand(self,cmd): return self.execCommand(Mpc + " " + cmd) def getPandoraStations(self): log.message("Receiving pandora station list...", log.DEBUG) names = [] ids = [] x = self.pianobar.expect(['Select station: ', pexpect.TIMEOUT], timeout=20) if x == 0: # tekst pojawil sie w ciagu 20s - O.K. # 'before' is now string of stations I believe # break up into separate lines a = self.pianobar.before.splitlines() # Parse each line for b in a[:-1]: # Skip last line (station select prompt) # Occasionally a queued up 'TIME: -XX:XX/XX:XX' string or # 'new playlist...' appears in the output. Station list # entries have a known format, so it's straightforward to # skip these bogus lines. ## print '\"{}\"'.format(b) if (b.find('playlist...') >= 0) or (b.find('Autostart') >= 0): continue ## if b[0:5].find(':') >= 0: continue ## if (b.find(':') >= 0) or (len(b) < 13): continue # Alternate strategy: must contain either 'QuickMix' or 'Radio': # Somehow the 'playlist' case would get through this check. Buh? if b.find('Radio') or b.find('QuickMix'): id = b[5:7].strip() name = b[13:].strip() # If 'QuickMix' found, always put at head of list if name == 'QuickMix': ids.insert(0, id) names.insert(0, name) else: ids.append(id) names.append(name) else: # po 20s nie mamy listy stacji - przekazujemy userowi ze cos jest nie tak self.pandora_station_name = '*** No station list ***' self.pandora_song_name = '---------------------' log.message("radio.getPandoraStations error - no station list from pianobar", log.ERROR) self.max_pandora_id = len(names) self.pandora_watchdog_time = int(time.time()) + self.WATCHDOG_SEC return names, ids # Pobranie co tam wyswietla aktualnie pianobar # i umieszczenie w odpowiednich zmiennych # na potrzeby innych procedur def getPandoraData(self): if self.pianobar.isalive(): pattern_list = self.pianobar.compile_pattern_list(['SONG: ', 'STATION: ', 'Receiving new playlist...', 'TIME: ', 'Error: ', pexpect.TIMEOUT]) # pattern_list = self.pianobar.compile_pattern_list(['SONG: ', 'STATION: ', 'Receiving new playlist...', pexpect.TIMEOUT]) end_of_texts = False # Process all pending pianobar output while not end_of_texts: try: x = self.pianobar.expect(pattern_list, timeout=0) if x == 0: # 'SONG: ' x = self.pianobar.expect(['\r\n', pexpect.TIMEOUT], timeout=0) if x == 0: # Artist - Title - from: "Album" self.pandora_song_name = self.pianobar.before self.setInterrupt() # A to dziala !!! elif x == 1: # 'STATION: ' x = self.pianobar.expect([' \| ', pexpect.TIMEOUT], timeout=0) if x == 0: self.pandora_station_name = self.pianobar.before elif x == 2: # wisi na odpytywaniu o kolejne utwory ??? # to sie pianobarowi przytrafia zbyt czesto # jak wisi, to trzeba ponownie odpalic stacje x = self.pianobar.expect(['Ok.', 'Error: ', pexpect.TIMEOUT], timeout=3) # czekamy 3s. na Ok, moze sie uda zaladowac, a moze komunikat bledu jest if x == 2: # nie udalo sie - restart self.pandora_stop() self.pandora_start() elif x == 1: # jakis blad komunikat zamiast nazwy stacji x = self.pianobar.expect(['\r\n', pexpect.TIMEOUT], timeout=0) if x == 0: self.pandora_station_name = '***' + self.pianobar.before + '***' self.pandora_song_name = '---------------------' elif x == 3: # Time doesn't include newline - prints over itself. x = self.pianobar.expect(['\r', pexpect.TIMEOUT], timeout=1) if x == 0: self.pandora_progress = self.pianobar.before self.pandora_watchdog_time = int(time.time()) + self.WATCHDOG_SEC if x == 4: # 'Error:' - gramy dalej cisze i zamiast nazwy stacji dajemy komunikat o bledzie x = self.pianobar.expect(['\r\n', pexpect.TIMEOUT], timeout=0) if x == 0: self.pandora_station_name = '***' + self.pianobar.before + '***' self.pandora_song_name = '---------------------' elif x == 5: # timeout jestesmy na koncu tekstow end_of_texts = True except: pass else: # pianobar "zmarl" trzeba powiadomic jakos usera #self.pandora_station_name = '*** pianobar dead ***' #self.pandora_song_name = '---------------------' self.pandora_song_name = '*** pianobar dead ***' return # Get the ID of the currently playing track or station ID def getCurrentID(self): try: currentsong = self.getCurrentSong() currentid = int(currentsong.get("pos")) + 1 # Only update if the Current ID has changed if self.current_id != currentid: log.message("radio.getCurrentID New ID " + str(currentid), log.DEBUG) self.current_id = currentid # Write to current ID file # self.execCommand ("echo " + str(currentid) + " > " + self.current_file) # (Pecus) self.writeToFile (self.current_file,str(currentid)) # (Pecus) self.getIdError = False except: if not self.getIdError: log.message("radio.getCurrentID failed", log.ERROR) self.getIdError = True return self.current_id # Check to see if an error occured def gotError(self): return self.error # Get the error string if a bad channel def getErrorString(self): self.error = False return self.errorStr # See if any error def checkStatus(self): try: status = client.status() self.errorStr = str(status.get("error")) if self.errorStr != "None": if not self.error: self.errorStr = (self.errorStr + " (Station " + str(self.current_id) + ")") log.message(self.errorStr, log.DEBUG) self.error = True else: # No error self.errorStr = "" except: log.message("checkStatus exception", log.ERROR) self.errorStr = "Status exception" return self.error # Get the progress of the currently playing track def getProgress(self): if self.source == self.RADIO or self.source == self.PLAYER: line = self.execMpcCommand("status | grep \"\[playing\]\" ") lineParts = line.split('/',1) if len(lineParts) >= 2: line = lineParts[1] while line.find(' ') > 0: line = line.replace(' ', ' ') lineParts = line.split(' ') progress = lineParts[1] # + ' ' + lineParts[2] # moze bez procentow ([2]), bo sie timer nie miesci # przerabiamy progres na taki jak w Pandorze (czas utwory odliczany do zera) line = lineParts[1].replace('/',':') # to zeby latwiej podzelic na liczby lineParts = line.split(':') # i mamy liste czterech liczb sektrwa = 60 * int(lineParts[0]) + int(lineParts[1]) # czas od poczatku utworu w sekundach sekcala = 60 * int(lineParts[2]) + int(lineParts[3]) # dlugosc utworu w sekundach sektrwa = sekcala - sektrwa # wyliczamy zamiast tego czas do konca utworu w sekundach # i skladamy to ponownie w string do kupy progress = "-" + '{:0>2}'.format(sektrwa/60) + ":" + '{:0>2}'.format(sektrwa%60) + "/" + '{:0>2}'.format(sekcala/60) + ":" + '{:0>2}'.format(sekcala%60) else: progress = '' if self.source == self.PANDORA: progress = 'xx/xx' if not self.isPandoraPaused: # zabezpieczamy sie przed tym zwisem na rozne sposoby..... try: self.getPandoraData() # odpalenie tego w tym momencie skutkuje zwisem.... moze wywoluje sie przed odpaleneniem stacji ??? except: pass progress = self.pandora_progress return progress # Set the new ID of the currently playing track or station (Also set search index) def setCurrentID(self,newid): log.message("radio.setCurrentID " + str(newid), log.DEBUG) self.current_id = newid # If an error (-1) reset to 1 if self.current_id <= 0: self.current_id = 1 log.message("radio.setCurrentID reset to " + str(self.current_id), log.DEBUG) # Don't allow an ID greater than the playlist length if self.current_id >= len(self.playlist): self.current_id = len(self.playlist) log.message("radio.setCurrentID reset to " + str(self.current_id), log.DEBUG) self.search_index = self.current_id - 1 log.message("radio.setCurrentID index= " + str(self.search_index), log.DEBUG) # self.execCommand ("echo " + str(self.current_id) + " > " + self.current_file) # (Pecus) self.writeToFile (self.current_file,str(self.current_id)) # (Pecus) name = self.getCurrentTitle() log.message("radio.setCurrentID (" + str(self.current_id) + ") " + name, log.INFO) return # Get stats array def getStats(self): try: stats = client.status() self.stats = stats # Only if above call works except: log.message("radio.getStats failed", log.ERROR) self.getOptions(self.stats) # Get options return self.stats # Get current state (play or pause or stop) if changed externally def getState(self): state = "play" try: stats = self.getStats() state = str(stats.get("state")) except: log.message("radio.getState failed", log.ERROR) self.connect(self.mpdport) state = self.state if self.source == self.RADIO or self.source == self.PLAYER: # Mute if pause or stop but not if there are no playlists if (state == "pause" or state == "stop") and self.current_id != 0: self.isMuted = True else: self.isMuted = False elif self.source == self.PANDORA: state = "play" self.isMuted = self.isPandoraPaused if self.isPandoraPaused: state = "pause" self.state = state return state # Get paused state (REDUNDANT) def paused(self): self.getState() return self.pause # Get current song information (Only for use within this module) def getCurrentSong(self): try: currentsong = client.currentsong() self.currentsong = currentsong except: # Try re-connect and status try: if self.connect(self.mpdport): currentsong = client.currentsong() self.currentsong = currentsong except: log.message("radio.getCurrentSong failed", log.ERROR) return self.currentsong # Get the currently playing radio station from mpd # This is usually from "name" but some stations use the "title" field def getRadioStation(self): if self.source == self.RADIO or self.source == self.PLAYER: currentsong = self.getCurrentSong() try: name = str(currentsong.get("name")) except: name = "No name" # If no name returned check that the file name is returned OK # and use name from the search index if name == "None": try: time.sleep(0.2) currentsong.get("file") name = self.getStationName(self.search_index) except: name = "Bad stream (" + str(self.current_id) + ")" if self.display_playlist_number: name = name + ' (' + str(self.current_id) + ')' self.stationName = translate.escape(name) # Use name from the playlist as the station name if self.stationNamesSource == config.LIST : self.stationName = self.getStationName(self.current_id -1) if self.source == self.PANDORA: self.stationName = 'no station information' self.getPandoraData() self.stationName = self.pandora_station_name return self.stationName # Get the title of the currently playing station or track from mpd def getCurrentTitle(self): if self.source == self.RADIO or self.source == self.PLAYER: try: currentsong = self.getCurrentSong() title = str(currentsong.get("title")) title = translate.escape(title) except: title = '' if title == 'None': title = '' try: genre = str(currentsong.get("genre")) except: genre = '' if genre == 'None': genre = '' # If the title contained the station name blank it out if title == self.stationName: title = '' if self.channelChanged: self.channelChanged = False if config.verbose(): if self.source == self.RADIO or self.source == self.PANDORA: sSource = "Station " else: sSource = "Track " if self.speech: self.speak(sSource + str(self.current_id) + ' ' + self.stationName) if title != self.stationTitle and len(title) > 0: log.message ("Title: " + str(title), log.DEBUG) self.stationTitle = title if self.source == self.PANDORA: title = 'no song information' self.getPandoraData() title = self.pandora_song_name return title # Get the currently playing radio station from mpd # Returns the same format as the mpc current command def getCurrentStation(self): name = self.getRadioStation() title = self.getCurrentTitle() if len(title) > 0: currentPlaying = name + ": " + title else: currentPlaying = name self.checkStatus() return currentPlaying # Get the name of the current artist mpd (Music librarry only) def getCurrentArtist(self): try: currentsong = self.getCurrentSong() title = str(currentsong.get("title")) title = translate.escape(title) artist = str(currentsong.get("artist")) if str(artist) == 'None': artist = "Unknown artist" self.artist = artist except: log.message ("radio.getCurrentArtist error", log.ERROR) return self.artist # Get bit rate - aways returns 0 in diagnostic mode def getBitRate(self): try: status = client.status() bitrate = int(status.get('bitrate')) except: bitrate = -1 return bitrate # Get the last ID stored in /var/lib/radiod def getStoredID(self,current_file): current_id = 0 if os.path.isfile(self.current_file): current_id = 1 try: # current_id = int(self.execCommand("cat " + self.current_file) ) # (Pecus) current_id = int(self.readFromFile(self.current_file) ) # (Pecus) except ValueError: current_id = 1 else: log.message("Error reading " + self.current_file, log.ERROR) if current_id <= 0: current_id = 1 return current_id # Po potwierdzeniu decyzji (+, -, ban) wyslanie odpowiedniego rozkazu do Pandory def setPandoraDecision(self, direction): if direction == self.UP: self.PandoraPress('+') # Like elif direction == self.DOWN: self.PandoraPress('-') # Don't like (ban) elif direction == self.LEFT: self.PandoraPress('t') # Tired (ban for 1 month) return # Nastepny utwor pandory def PandoraNextTrack(self): # dodatkowe zabezpieczenia sprawdzamy czy gra, a jak gra to czy faktycznie proces zyje if not self.isPandoraPaused: if self.pianobar.isalive(): self.pianobar.send('n') log.message('Pandora next track', log.DEBUG) return # Wyslanie do pianobar wcisniecia klawisza def PandoraPress(self,key): # dodatkowe zabezpieczenia sprawdzamy czy gra, a jak gra to czy faktycznie proces zyje if not self.isPandoraPaused: if self.pianobar.isalive(): self.pianobar.send(key) log.message('Pandora key: ' + key, log.DEBUG) return # Zmiana stacji pandory def setPandoraStation(self): # Entering station selection menu. Don't return to volume # select, regardless of outcome, just return to normal play. if self.pianobar.isalive(): self.pianobar.send('s') # Just keep the list we made at start-up # stationList, stationIDs = getStations() log.message('Selecting pandora station ' + self.pandora_stationIDs[self.current_pandora_id - 1], log.DEBUG) self.pianobar.sendline(self.pandora_stationIDs[self.current_pandora_id - 1]) self.pandora_search_index = self.current_pandora_id - 1 # zapis do pliku nie przez setCurrentID bo za duzo sprawdza a w pandorze ID moze sie np rownac 0 self.current_file = CurrentPandoraFile self.writeToFile (self.current_file,str(self.current_pandora_id)) # (Pecus) # self.setCurrentID(self.current_pandora_id) time.sleep(1) # nie wiedziec czemu ten sleep powoduje ze nazwy utworow i stacji po ich zmianie wyswietlaja sie szybko else: log.message('radio.setPandoraStation error - pianobar is dead?', log.ERROR) return # Change radio station up def channelUp(self): new_id = self.getCurrentID() if self.source == self.RADIO or self.source == self.PLAYER: new_id = self.getCurrentID() + 1 log.message("radio.channelUp " + str(new_id), log.DEBUG) if new_id > len(self.playlist): new_id = 1 self.play(new_id) else: try: client.next() except: log.message("radio.channelUp error", log.ERROR) new_id = self.getCurrentID() self.setCurrentID(new_id) # If any error MPD will skip to next channel self.checkStatus() self.channelChanged = True if self.source == self.PANDORA: self.current_pandora_id = self.current_pandora_id + 1 if self.current_pandora_id > self.max_pandora_id: self.current_pandora_id = 1 log.message("pandora.channelUp " + str(self.current_pandora_id), log.DEBUG) self.setPandoraStation() self.channelChanged = True return new_id # Change radio station down def channelDown(self): new_id = self.getCurrentID() if self.source == self.RADIO or self.source == self.PLAYER: new_id = self.getCurrentID() - 1 log.message("radio.channelDown " + str(new_id), log.DEBUG) if new_id <= 0: new_id = len(self.playlist) self.play(new_id) else: try: client.previous() except: log.message("radio.channelDown error", log.ERROR) new_id = self.getCurrentID() self.setCurrentID(new_id) # Check if error if so try next channel down if self.checkStatus(): new_id -= 1 if new_id <= 0: new_id = len(self.playlist) self.play(new_id) self.channelChanged = True if self.source == self.PANDORA: self.current_pandora_id = self.current_pandora_id - 1 if self.current_pandora_id < 1: self.current_pandora_id = self.max_pandora_id log.message("pandora.channelDown " + str(self.current_pandora_id), log.DEBUG) self.setPandoraStation() self.channelChanged = True return new_id # Toggle the input source (Reload is done when Reload requested) def toggleSource(self,direction): # Remember! RADIO=0, PLAYER=1, PANDORA=2 always! if direction == self.UP: self.source +=1 if self.source == self.PANDORA and (not config.getPandoraAvailable()): self.source +=1 elif direction == self.DOWN: self.source -=1 if self.source < self.RADIO: if config.getPandoraAvailable(): self.source = self.PANDORA else: self.source = self.PANDORA - 1 # PLAYER if self.source > self.PANDORA: self.source = self.RADIO self.setReload(True) if self.speech: self.speak(sSource) return self.source # Set the input source to radio (Reload is done when Reload requested) (Pecus) def setRadioSource(self): # (Pecus) if self.source != self.RADIO: # (Pecus) self.source = self.RADIO # (Pecus) sSource = language.getText('source_radio') # (Pecus) self.setReload(True) # (Pecus) if self.speech: # (Pecus) self.speak(sSource) # (Pecus) return self.source # (Pecus) # Set the input source to player (Reload is done when Reload requested) (Pecus) def setPlayerSource(self): # (Pecus) if self.source != self.PLAYER: # (Pecus) self.source = self.PLAYER # (Pecus) sSource = language.getText('source_media') # (Pecus) self.setReload(True) # (Pecus) if self.speech: # (Pecus) self.speak(sSource) # (Pecus) return self.source # (Pecus) # Set the input source to pandora (Reload is done when Reload requested) (Pecus) def setPandoraSource(self): # (Pecus) if config.getPandoraAvailable(): if self.source != self.PANDORA: # (Pecus) self.source = self.PANDORA # (Pecus) sSource = language.getText('source_pandora') # (Pecus) self.setReload(True) # (Pecus) if self.speech: # (Pecus) self.speak(sSource) # (Pecus) return self.source # (Pecus) def pandora_stop(self): log.message("radio.pandora_stop", log.DEBUG) try: if self.pianobar.isalive(): log.message("radio.pandora_stop terminate() pianobar process", log.DEBUG) self.pianobar.sendcontrol('c') # wysylamy Ctrl-C jakby akurat nie byl w trybie odtwarzania self.pianobar.send('q') # a teraz normalnie quit self.pianobar.terminate(True) # aa to nie wiem po co ale dla pewnosci :) except: pass self.isPandoraPaused = True #log.message("radio.pandora_stop kill pianobar proces", log.DEBUG) #self.execCommand ("killall pianobar") self.pandora_station_name = '' self.pandora_song_name = '' self.pandora_progress = '' return # Load radio stations def loadStations(self): self.pandora_stop() log.message("radio.loadStations", log.DEBUG) if self.speech: self.speak(language.getText('loading_radio')) try: client.clear() except: log.message("radio.loadStations mpc clear error", log.ERROR) dirList = os.listdir(PlaylistsDirectory) dirList.sort() for fname in dirList: fname = fname.rstrip() if fname is "share": continue if os.path.isdir(fname): continue # MPD version 0.19 plus does not require extions such as m3u, pls if not self.use_playlist_extensions: try: fname,ext = fname.split('.') except: log.message("radio.loadStations missing file extension in" + fname, log.ERROR) continue log.message("load " + fname, log.DEBUG) try: client.load(fname) except: log.message("radio.loadStations failed " + fname, log.ERROR) self.randomOff() self.consumeOff() self.repeatOn() self.playlist = self.createPlayList() self.current_file = CurrentStationFile self.current_id = self.getStoredID(self.current_file) self.play(self.current_id) self.search_index = self.current_id - 1 self.source = self.RADIO return # Load music library def loadMusic(self): self.pandora_stop() log.message("radio.loadMusic", log.DEBUG) if self.speech: self.speak(language.getText('loading_media')) self.execMpcCommand("stop") self.execMpcCommand("clear") directory = "/var/lib/mpd/music/" dirList=os.listdir(directory) dirList.sort() for fname in dirList: fname = fname.strip("\n") if os.path.isfile(directory+fname): continue path = directory + fname nfiles = len(os.listdir(path)) if nfiles > 0: cmd = "add \"" + fname + "\"" log.message("radio.loadMusic " + cmd,log.DEBUG) log.message(str(nfiles) + " files/directories found",log.DEBUG) try: self.execMpcCommand(cmd) except: log.message("Failed to load music directory " + fname, log.ERROR) else: log.message(path + " is empty", log.INFO) self.playlist = self.createPlayList() self.current_file = CurrentTrackFile self.current_id = self.getStoredID(self.current_file) # Old playlists may have been longer. length = len(self.playlist) if self.current_id > length: self.current_id = 1 log.message("radio.loadMusic ID " + str(self.current_id), log.DEBUG) # Important use mpc not python-mpd calls as these give problems if length > 0: log.message("radio.loadMusic play " + str(self.current_id), log.DEBUG) self.execMpcCommand("play " + str(self.current_id)) self.search_index = self.current_id - 1 self.execMpcCommand("random on") self.execMpcCommand("repeat off") self.execMpcCommand("consume off") self.random = True # Random play self.repeat = False # Repeat play self.consume = False # Consume tracks else: log.message("radio.loadMusic playlist length = " + str(length), log.ERROR) log.message("radio.loadMusic complete", log.DEBUG) return length def pandora_start(self): # kasujemy plik stanu, by pianobar startowal na czysto # jak jest ten plik, to od razu zaczyna grac - bez listy # stacji itp. I program glupieje self.execCommand ("rm /home/pi/.config/pianobar/state") log.message("radio.pandora_start", log.DEBUG) self.pandora_watchdog_time = int(time.time()) + self.WATCHDOG_SEC + 30 # + 30 dodatkowe na ewentualny czas startu #self.pandora_stop() # dla pewnosci self.pandora_decision = self.OK log.message("radio.pandora_start Spawning pianobar...", log.DEBUG) self.pianobar = pexpect.spawn('sudo -u pi pianobar') # Sprawdzmy bledy sieci czy logowania log.message("radio.pandora_start Wait for pianobar Login...", log.DEBUG) x = self.pianobar.expect(['Login... ', pexpect.TIMEOUT], timeout=10) if x == 0: # Jest Login - czekamy dalej log.message("radio.pandora_start Wait LF after Login...", log.DEBUG) x = self.pianobar.expect(['\r\n', pexpect.TIMEOUT], timeout=25) if x == 0: # nie wisi na login wiec sprawdzamy jaki komunikat pmessage = self.pianobar.before else: pmessage = "Login timeout error" # wisi na "Login..." ponad 25 s. log.message("radio.pandora_start kill pianobar proces", log.DEBUG) self.execCommand ("killall pianobar") # wisi wiec kilujemy else: # Przez 10s nie pojawilo sie "Login..." pmessage = "Connection timeout error" # wisi bez "Login..." ponad 10 s. log.message("radio.pandora_start kill pianobar proces", log.DEBUG) self.execCommand ("killall pianobar") # wisi wiec kilujemy #if not(self.pianobar.isalive()): # pmessage = 'Network error' log.message("radio.pandora_start Pianobar login message: " + pmessage, log.DEBUG) # jesli nie ma bledow logowania pojawi sie lista stacji if pmessage == 'Ok.': # czekamy 30s na info o pobraniu listy stacji log.message("radio.pandora_start Wait for pianobar stations list...", log.DEBUG) x = self.pianobar.expect(['Get stations... Ok.\r\n', pexpect.TIMEOUT], timeout=30) if x == 0: # lista pobrana odpalamy self.pandora_stationList, self.pandora_stationIDs = self.getPandoraStations() if self.current_pandora_id > self.max_pandora_id: self.current_pandora_id = 1 log.message('radio.pandora_start Selecting pandora station ' + self.pandora_stationIDs[self.current_pandora_id - 1], log.DEBUG) self.pianobar.sendline(self.pandora_stationIDs[self.current_pandora_id - 1]) self.pandora_search_index = self.current_pandora_id - 1 self.isPandoraPaused = False else: # przez 30s nie bylo Ok. przy pobieraniu listy stacji... self.pandora_station_name = '*** Station list error ***' self.pandora_song_name = '---------------------' self.isPandoraPaused = True else: # po logowaniu nie bylo Ok. a to co bylo wyswietlamy zamiast nazwy stacji self.pandora_station_name = '** ' + pmessage + ' **' self.pandora_song_name = '---------------------' self.isPandoraPaused = True self.pandora_watchdog_time = int(time.time()) + self.WATCHDOG_SEC return #Load Pandora def loadPandora(self): self.pandora_stop() log.message("radio.loadPandora", log.DEBUG) if self.speech: self.speak(language.getText('loading_pandora')) #stop MPD #client.pause(1) client.stop() log.message("radio.loadPandora MPD stopped", log.DEBUG) self.current_file = CurrentPandoraFile self.current_pandora_id = self.getStoredID(self.current_file) self.pandora_start() log.message("radio.loadPandora Pandora started", log.DEBUG) return # Update music library def updateLibrary(self): log.message("radio.updateLibrary", log.DEBUG) self.execMpcCommand("-w update") self.loadMusic() self.setUpdateLibOff() return # Play a new track using search index def playNew(self,index): self.setLoadNew(False) self.play(index + 1) return # Play a track number (Starts at 1) def play(self,number): log.message("radio.play " + str(number), log.DEBUG) log.message("radio.play Playlist len " + str(len(self.playlist)), log.DEBUG) if number > 0 and number <= len(self.playlist): self.current_id = number self.setCurrentID(self.current_id) else: log.message("play invalid station/track number "+ str(number), log.ERROR) self.setCurrentID(1) # Client play function starts at 0 not 1 log.message("play station/track number "+ str(self.current_id), log.DEBUG) try: client.play(self.current_id-1) self.checkStatus() except: log.message("radio.play error", log.ERROR) return # Clear streaming and other errors def clearError(self): log.message("radio.clearError", log.DEBUG) try: client.clearerror() self.errorStr = "" self.error = False except: log.message("radio.clearError failed", log.ERROR) return # Get list of tracks or stations def getPlayList(self): return self.playlist # Create list of tracks or stations def createPlayList(self): log.message("radio.createPlaylist", log.DEBUG) list = [] line = "" cmd = "playlist" p = os.popen(Mpc + " " + cmd) while True: line = p.readline().strip('\n') if line.__len__() < 1: break line = translate.escape(line) if line.startswith("http:") and '#' in line: url,line = line.split('#') list.append(line) self.playlist = list log.message("radio.createPlaylist length " + str(len(self.playlist)), log.DEBUG) return self.playlist # Get the length of the current list def getListLength(self): return len(self.playlist) # Display artist True or False def displayArtist(self): return self.display_artist def setDisplayArtist(self,dispArtist): self.display_artist = dispArtist # Set Search index def getSearchIndex(self): return self.search_index def setSearchIndex(self,index): self.search_index = index return # Get Pandora Radio station name by Index def getPandoraStationName(self,index): station = "" try: station = self.pandora_stationList[index] except: log.message("radio.getPandoraStationName bad index " + str(index), log.ERROR) station = "Station index error" return station # Get Radio station name by Index (Used in search routines) def getStationName(self,index): station = "" if self.source == self.RADIO: station = "No stations found" else: station = "No tracks found" try: if len(self.playlist) > 0: station = self.playlist[index] except: log.message("radio.getStationName bad index " + str(index), log.ERROR) return station # Get track name by Index def getTrackNameByIndex(self,index): if len(self.playlist) < 1: track = "No tracks" else: sections = self.playlist[index].split(' - ') leng = len(sections) if leng > 1: track = sections[1] else: track = "No track" track = translate.escape(track) if str(track) == 'None': track = "Unknown track" return track # Get artist name by Index def getArtistName(self,index): if len(self.playlist) < 1: artist = "No playlists" else: sections = self.playlist[index].split(' - ') leng = len(sections) if leng > 1: artist = sections[0] else: artist = "Unknown artist" artist = translate.escape(artist) return artist # Switch store and retrieval routines def setSwitch(self,switch): self.switch = switch return def getSwitch(self): return self.switch # Routines for storing rotary encoder events def incrementEvent(self): self.numevents += 1 return self.numevents def decrementEvent(self): self.numevents -= 1 if self.numevents < 0: self.numevents = 0 return self.numevents def getEvents(self): return self.numevents def resetEvents(self): self.numevents = 0 return self.numevents # Version number def getVersion(self): return self.version # Get the the backlight color number (option = bg_color etc) def getBackColor(self,option): return config.getBackColor(option) # Get the the backlight color number def getBackColorName(self,iColor): return config.getBackColorName(iColor) # Cycle colors def cycleColor(self,direction): return config.cycleColor(direction) # Get I2C backpack type def getBackPackType(self): self.i2c_backpack = config.getBackPackType() log.message("Backpack type " + str(self.i2c_backpack), log.DEBUG) return self.i2c_backpack # Get I2C address def getI2Caddress(self): self.i2c_address = config.getI2Caddress() log.message("I2C address " + hex(self.i2c_address), log.DEBUG) return self.i2c_address # Set an interrupt received def setInterrupt(self): self.interrupt = True return # See if interrupt received from IR remote control def getInterrupt(self): interrupt = self.interrupt self.interrupt = False return interrupt # Load media def loadMedia(self): self.unmountAll() self.mountUsb() self.mountShare() self.loadMusic() self.random = self.getStoredRandomSetting() return # Mount the USB stick def mountUsb(self): usbok = False if os.path.exists("/dev/sda1"): device = "/dev/sda1" usbok = True elif os.path.exists("/dev/sdb1"): device = "/dev/sdb1" usbok = True if usbok: self.execCommand("/bin/mount -o rw,uid=1000,gid=1000 "+ device + " /media") log.message(device + " mounted on /media", log.DEBUG) dirList=os.listdir(MusicDirectory) for fname in dirList: file = MusicDirectory + '/' + fname # Skip playlist files if os.path.isfile(file): continue log.message("Loading " + file, log.DEBUG) else: msg = "No USB stick found!" log.message(msg, log.WARNING) return # Mount any remote network drive def mountShare(self): if os.path.exists("/var/lib/radiod/share"): # myshare = self.execCommand("cat /var/lib/radiod/share") # (Pecus) myshare = self.readFromFile("/var/lib/radiod/share") # (Pecus) if myshare[:1] != '#': self.execCommand(myshare) log.message(myshare,log.DEBUG) return # Unmount all drives def unmountAll(self): self.execCommand("/bin/umount /dev/sda1 2>&1 >/dev/null") # Unmount USB stick self.execCommand("/bin/umount /dev/sdb1 2>&1 >/dev/null") # Unmount USB stick self.execCommand("/bin/umount /share 2>&1 >/dev/null") # Unmount network drive return # Speak a message def speak(self, msg): msg = msg.lstrip() if self.speech and len(msg) > 1: if msg[0] != '!': speech_volume = config.getSpeechVolume() volume = self.volume * speech_volume/100 if volume < 5: volume = 5 self.mute() language.speak(msg,volume) self.unmute() return # Speeak a message always (if speech os off too) (Pecus) def speakAlways(self, msg): # (Pecus) speech_volume = config.getSpeechVolume() # (Pecus) volume = self.volume * 2 * speech_volume/100 # (Pecus) self.mute() # (Pecus) language.speak(msg,volume) # (Pecus) self.unmute() # (Pecus) return # (Pecus) # Speak a message def speakInformation(self): log.message("radio.speakInformation" , log.DEBUG) msg = '' if self.source == self.RADIO: #current = "Station " + str(self.current_id ) # (Pecus) current = language.getText('Station') + " " + str(self.current_id ) # from language file :) (Pecus) name = self.getStationName(self.search_index) title = self.getCurrentTitle() elif self.source == self.PLAYER: #current = "Track " + str(self.current_id ) # (Pecus) current = language.getText('Track') + " " + str(self.current_id ) # from language file :) (Pecus) name = self.getCurrentArtist() title = self.getCurrentTitle() elif self.source == self.PANDORA: current = language.getText('Station') + " " + str(self.current_pandora_id ) # from language file :) (Pecus) name = self.pandora_station_name title = self.pandora_song_name # Can you speek hours in polish - Yes :) (Pecus) # It may by not be pretty, but it works ! #sTime = strftime("%H %M") # (Pecus) sMin = strftime("%M") # (Pecus) sHour = strftime("%H") # (Pecus) sTime = language.getText('h'+sHour) + " " + sMin # hour from language file (Pecus) time = language.getText('the_time') + " " + sTime #self.speak(time) # one command instead of 4 sounds better in player mode (Pecus) #self.speak(current) # (Pecus) #self.speak(name) # (Pecus) #self.speak(title) # (Pecus) self.speakAlways(time + ' , ' + current + ', ' + name + ', ' + title) # says even id excluded speaking in config file (Pecus) return # Is speech enabled def speechEnabled(self): return self.speech # Get language text def getLangText(self,label): return language.getText(label) # Get switch GPIO configuration def getSwitchGpio(self,label): return config.getSwitchGpio(label) # Get rotary class def getRotaryClass(self): return config.getRotaryClass() def dummy(self): log.message("dummy" , log.DEBUG) return # Write text to file (Pecus) def writeToFile(self,fname,text): # (Pecus) file = open(fname, "w") # (Pecus) file.write(text) # (Pecus) file.close() # (Pecus) return # (Pecus) # Read text line from file (Pecus) def readFromFile(self,fname): # (Pecus) file = open(fname, "r") # (Pecus) text = file.readline() # (Pecus) file.close() # (Pecus) return text # (Pecus) # End of Radio Class ### Test routine ### if __name__ == "__main__": print "Test radio_class.py" radio = Radio() radio.mountUsb() print "Version",radio.getVersion() print "Board revision", radio.getBoardRevision() iColor = radio.getBackColor('bg_color') colorName = radio.getBackColorName(iColor) print 'bg_color',colorName, iColor # Start radio and load the radio stations backpack = radio.getBackPackType() print "Backpack", backpack i2c_address = radio.getI2Caddress() print "I2C address", hex(i2c_address) radio.start() radio.loadStations() radio.play(1) current_id = radio.getCurrentID() index = current_id - 1 print "Current ID ", current_id print "Station",current_id,":", radio.getStationName(index) print "Bitrate", radio.getBitRate() # Test volume controls print "Stored volume", radio.getStoredVolume() radio.setVolume(15) radio.increaseVolume() radio.decreaseVolume() radio.getVolume() time.sleep(5) print "Mute" radio.mute() time.sleep(3) print "Unmute" radio.unmute() print "Volume", radio.getVolume() time.sleep(5) # Test channel functions current_id = radio.channelUp() print "Channel up" index = current_id - 1 print "Station",current_id,":", radio.getStationName(index) time.sleep(5) current_id = radio.channelDown() print "Channel down" index = current_id - 1 print "Station",current_id,":", radio.getStationName(index) # Check library load print "Load music library" radio.loadMusic() # Check state print "Paused " + str(radio.paused()) # Check timer print "Set Timer 1 minute" radio.timerValue = 1 radio.timerOn() while not radio.fireTimer(): time.sleep(1) print "Timer fired" # Exit sys.exit(0) # End of __main__ routine