Ich bastel gerade just 4 fun an einem Recode des Originals, in dem ich eigentlich keine starren Skin-Bilder nutzen möchte, eben weil die Skin-Bilder nur für eine Auflösung passen...
Auch wären ein paar Animationen nicht schlecht wie zB den Track-Titel - der auf so kleinen Displays selten vollständig dargestellt werden kann - von rechts nach links durch zu scrollen. Oder ein durchscrollen der Playlisten/Tracks wäre auch cool
Davon abgesehen hab ich im laufe des Umbau's noch ein paar andere Sachen geändert:
Bisheriges Changelog:
- Beta7:
- Allgemein den Code aufgeräumt und Einrückungen usw ausgebessert.
Mehr Features von pyGame verwendet (wie zB pygame.time.Clock()).
Allgemein so gut es geht auf 'subprocess' verzichtet. - Fehlermeldungen werden abgefangen und auf der Konsole ausgegeben. (Script läuft dadurch trotzdem weiter)
- Natives steuern des MPD's übers mpd2 Python Module, anstelle der subprocess mpc Shellbefehle... Dadurch wäre es nun auch möglich einen anderen MPD übers Netzwerk zu steuern.
Das senkt die CPU Belastung und macht die Bedienung auch bisschen flüssiger. Vorher waren nur 4-5 FPS möglich, aktuell bin ich bei ca. 9 FPS und kann evtl. noch was rauskitzeln - was nämlich nur an der update_screen() Funktion liegt. Würde man zB das ständige laden der Skin Bilder entfernen wärs noch mal 3 FPS schneller (und auch weniger CPU Last). - 'global' Variablen durch Dictionary's ersetzt...
Dadurch wird es flexibler, eindeutiger und man brauch nicht Variablen die man in einer Funktion ändern möchte extra 'global' setzen (und somit auch nicht vergessen dies zu tun), und es kommt auch zu keinem Konflikt. - CPU-Temperatur wird über /sys/class/thermal/thermal_zone0/temp ausgelesen...
Im Original wird vcgencmd genutzt was aber unnötige Last verursacht. - CPU Freq. im 2.Fenster eingefügt.
- RAM Werte im 2. Fenster eingefügt.
- Volume Wiederherstellung beim wiederholten drücken auf Mute.
Drückt man ein mal auf Mute wird der letzte Wert gespeichert. Drückt man erneut auf Mute wird die vorherige Lautstärke wieder aktiviert. - Pause und Resume auf dem 'pause' Knopf.
- Lauter/Leiser/Mute/Next/Prev ist auch über Tastatur möglich (m für Mute, das andere über die Pfeiltasten)
- Screensaver von Weiß auf Schwarz geändert - somit brennt sich nichts ein.
- IP wird nur ein mal beim ausführen des Scripts ausgelesen und dann in eine Variable gespeichert. Hat noch mals 1-2 FPS ausgemacht.
- Default Playlist die beim starten des Scripts abgespielt wird...
Lass ich das weg, musste ich bei mir jedes mal manuell über die Konsole eine add'en um was abspielen zu können - Falls Titel oder Station Name zu lang ist wird er abgeschnitten und mit "..." am Ende gekennzeichnet. Falls er aber nicht zu lang ist wird auch nichts abgeschnitten oder verpunktet
- Allgemein den Code aufgeräumt und Einrückungen usw ausgebessert.
- Beta8:
- update_screen() weiter optimiert und change_skin() ausgelagert.
Hat noch mals 3 FPS gebracht. - Station und Title auf utf-8 umgestellt (Umlaute).
- Durch einfügen von .convert() hinter jeder pygame.image.load() Zeile nochmals 2-4 FPS rausgekitzelt. (details dazu >hier< unter "Use surface.convert().")
Bis hier hin sind nun fast 16 FPS möglich, also mehr als das dreifache wie beim Original
"Dirty rect animation" bringt leider nichts da jedes mal das Skin Bild neu gerendert werden muss und somit +/-0 FPS dabei rauskommt (bzw sogar zZt 1-2fps langsamer)... Wen es trotzdem interessiert:"Dirty rect animation - update_screen()"
[code=php]# function to update screen
def update_screen():
dirtyrects=[]if dictionary['screensaver'] == True:
dirtyrects.append( screen.fill(black) )elif dictionary['screensaver'] == False:
current_time = time.strftime('%H:%M:%S %d.%m.%Y')
time_img = font.render(current_time, 1, (dictionary['font_color']))try:
PlayStatus = client.status()
PlayCurrent = client.currentsong()
except mpd.ConnectionError, e:
print('Connection Error: ' + str(e))
connected = reconnectMPD(client)if dictionary['menu'] == 1:
#reset for redraw
dirtyrects.append( screen.blit(dictionary['skin1'], (0, 0)) )try: station_name = PlayCurrent['name']
except: station_name = None
if not station_name:
try: station_name = PlayCurrent['album']
except: station_name = None
if not station_name:
station_img = font.render("Station: no data", 1, (dictionary['font_color']))
else:
if len(station_name) > 22:
station_name = station_name[:22] + '...'
station_img = font.render('Station: ' + station_name.decode('utf-8'), 1, (dictionary['font_color']))
dirtyrects.append( screen.blit(station_img, (23, 15)) )title_header = font.render("Now playing:", 1, (dictionary['font_color']))
try: title_name = PlayCurrent['title']
except: title_name = None
if not title_name:
title_img = font.render("no data! Try with PLAY!", 1, (dictionary['font_color']))
else:
dictionary['song_title'] = title_name
if len(title_name) > 30:
title_name = title_name[:30] + '...'
title_img = font.render(title_name.decode('utf-8'), 1, (dictionary['font_color']))
dirtyrects.append( screen.blit(title_header, (23, 40)) )
dirtyrects.append( screen.blit(title_img, (23, 60)) )vol = "{}%".format(int(PlayStatus['volume']))
volume_img = font.render("volume: " + vol, 1, (dictionary['font_color']))
dirtyrects.append( screen.blit(volume_img, (23, 90)) )
# display current time
dirtyrects.append( screen.blit(time_img, (150, 90)) )elif dictionary['menu'] == 2:
#reset for redraw
dirtyrects.append( screen.blit(dictionary['skin2'], (0, 0)) )# get and display ip
if not dictionary['IP']:
dictionary['IP'] = subprocess.check_output('hostname -I', shell=True).strip()
ip_img = font.render('IP: ' + dictionary['IP'], 1, (dictionary['font_color']))
dirtyrects.append( screen.blit(ip_img, (23, 15)) )# get and display cpu temp
cpu_temp = "%.2f'C" % get_temperature()
temp_img = font.render('cpu temp: ' + cpu_temp, 1, (dictionary['font_color']))
dirtyrects.append( screen.blit(temp_img, (23, 30)) )
#get and display cpu freq
freq = "%.0fMHz" % get_cpu_speed()
freq_img = font.render('freq: ' + freq, 1, (dictionary['font_color']))
dirtyrects.append( screen.blit(freq_img, (175, 30)) )#get and display RAM
ram_total, ram_free, ram_used, ram_usedPerc = getRAM()
ram = " {}MB {}MB {}MB {}" . format(ram_total/1024, ram_free/1024, ram_used/1024, ram_usedPerc)
ram_header = font.render('RAM Total Free Used Used%', 1, (dictionary['font_color']))
ram_img = font.render(ram, 1, (dictionary['font_color']))
dirtyrects.append( screen.blit(ram_header, (23, 48)) )
dirtyrects.append( screen.blit(ram_img, (23, 63)) )# display current time
dirtyrects.append( screen.blit(time_img, (90, 90)) )# Dirty rect animation. Only update changed stuff
pygame.display.update(dirtyrects)[/php]
- update_screen() weiter optimiert und change_skin() ausgelagert.
- Beta9:
- Erster Versuch automatisch den passenden Treiber herauszufinden und diesen entsprechen zu laden. Vorlage: http://www.karoltomala.com/blog/?p=679
Dabei versucht das Script erst 'fbcon' und danach 'directfb' zu laden und die Bildschirmauflösung automatisch zu ermitteln.
Auch erkennt das Script nun ob es tatsächlich Standalone gestartet wurde oder über zB X11-Forwarding und falls kann man die Fenstergröße ändern.. - Überprüfung ob die Skin Bilder geladen werden konnten...
- Lauftext zunächst auf lema67's Art geändert damit dieser nicht über den Skin-Rand drüber scrollt.
Wahlweise einstellbar ob überhaupt gescrollt werden soll. - ..Wusstet ihr eigentlich schon das man auch die Linux-System Fonts verwenden kann und somit keine extra font Dateien braucht? Nur muss man dann leider Abstände usw anpassen wenn man den Font verändert...
Default Font ist derzeit noch der pygame Standard Font "freesansbold" ... Aber ähnlich wie lema67 möchte auch ich später unterschiedliche Größen verwenden. - Screensaver in eigene Funktion ausgelagert um später einfacher Erweiterungen zu implementieren und nicht nur einen 'blank screen'
- Erster Versuch automatisch den passenden Treiber herauszufinden und diesen entsprechen zu laden. Vorlage: http://www.karoltomala.com/blog/?p=679
- Beta10
- Aktuelle Uhrzeit+Datum als Screensaver, was alle 10 Sekunden auf eine zufällige Position wechselt.
- ...und bestimmt auch noch ein paar andere Kleinigkeiten, woran ich mich aber jetzt nicht mehr erinnere...
Eine optimale FPS Einstellung die i.d.R. reicht sind übrigens 3 also 3 Updates innerhalb einer Sekunde. Auf 2fps ist die GUI dann schon merklich träge - verursacht dann aber auch nur noch ca. 15% CPU Last im Gegensatz zu ca. 27%.
Bei > 10 fps macht die Last zZt. kaum noch ein Unterschied und liegt bei ca. 45%.. Derzeit sind aber nicht mehr als ca. 10 FPS möglich da die update_screen() Funktion ausbremst, was ich statig versuche weiter zu optimieren.
Aus Testgründen hab ichs aber zZt auf 60 fps stehen (wegen des Lauftext's)
Nunja, jedenfalls möchte ich wie gesagt keine starren Skins verwenden sondern so ähnlich wie tuxerli >hier< einzelnen Bildern - allerdings will ich noch einen Schritt weiter gehen und das 'Sprite Sheets' Feature von pygame verwenden, wie es auch bei Spielen zum Einsatz kommt. Dabei kommt eine einzige Bilddatei zum Einsatz auf der alle benötigten Bilder angeordnet sind und über pygame kopiert man sich dann nur das jeweilige Abbild heraus. Das reduziert die Anzahl der Dateien und macht es auch etwas flexibler. Ein Beispiel hierfür kann man zB hier nachlesen: http://programarcadegames.com/python_examples/en/sprite_sheets/
Auch hatte Greengecko in seinem Thread die Idee das jeweilige Cover von local abgespielten MP3's darzustellen, was ich später auch noch einbauen möchte.
Ebenso wie weitere Informationen auf anderen "Fenstern", oder eben auch sowas wie "Verbleibende Zeit" des jeweiligen Tracks.
Also weitere Möglichkeiten gäb es denk ich viele - dank der TRON-Radio Vorlage hat man zumindest schon mal eine brauchbare Basis die man erweitern kann :thumbs1:
Builds:
29.04.2015 22:29 -> Beta7 http://slexy.org/view/s20w8YfFak
30.04.2015 23:31 -> Beta8 http://slexy.org/view/s21bipByjm
01.05.2015 20:28 -> Beta9 http://slexy.org/view/s2bWpjj9AC
Stay Tune!
PS: Minimalistisches Web-Interface: https://github.com/sn0opy/MPD-Webinterface oder https://github.com/notandy/ympd