Created
August 10, 2020 22:13
-
-
Save vsefer/0d524343c63677cc02f6e5786cc9a8d0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pi@scarlett:~ $ cat mopidy_display_ili9341.py | |
""" | |
This will show some Linux Statistics on the attached display. Be sure to adjust | |
to the display you have connected. Be sure to check the learn guides for more | |
usage information. | |
This example is for use on (Linux) computers that are using CPython with | |
Adafruit Blinka to support CircuitPython libraries. CircuitPython does | |
not support PIL/pillow (python imaging library)! | |
""" | |
import time | |
import sys | |
import os | |
import subprocess | |
import digitalio | |
import board | |
from PIL import Image, ImageDraw, ImageFont | |
from socket import error as socket_error | |
from datetime import datetime | |
import adafruit_rgb_display.ili9341 as ili9341 | |
import adafruit_rgb_display.st7789 as st7789 # pylint: disable=unused-import | |
import adafruit_rgb_display.hx8357 as hx8357 # pylint: disable=unused-import | |
import adafruit_rgb_display.st7735 as st7735 # pylint: disable=unused-import | |
import adafruit_rgb_display.ssd1351 as ssd1351 # pylint: disable=unused-import | |
import adafruit_rgb_display.ssd1331 as ssd1331 # pylint: disable=unused-import | |
# MPD Clint | |
from mpd import MPDClient, MPDError, CommandError, ConnectionError | |
#reload(sys) | |
#sys.setdefaultencoding('utf-8') | |
# Configuration for CS and DC pins (these are PiTFT defaults): | |
cs_pin = digitalio.DigitalInOut(board.CE0) | |
dc_pin = digitalio.DigitalInOut(board.D25) | |
reset_pin = digitalio.DigitalInOut(board.D24) | |
# Config for display baudrate (default max is 24mhz): | |
BAUDRATE = 24000000 | |
# Setup SPI bus using hardware SPI: | |
spi = board.SPI() | |
# pylint: disable=line-too-long | |
# Create the display: | |
# disp = st7789.ST7789(spi, rotation=90, # 2.0" ST7789 | |
# disp = st7789.ST7789(spi, height=240, y_offset=80, rotation=180, # 1.3", 1.54" ST7789 | |
# disp = st7789.ST7789(spi, rotation=90, width=135, height=240, x_offset=53, y_offset=40, # 1.14" ST7789 | |
# disp = hx8357.HX8357(spi, rotation=180, # 3.5" HX8357 | |
# disp = st7735.ST7735R(spi, rotation=90, # 1.8" ST7735R | |
# disp = st7735.ST7735R(spi, rotation=270, height=128, x_offset=2, y_offset=3, # 1.44" ST7735R | |
# disp = st7735.ST7735R(spi, rotation=90, bgr=True, # 0.96" MiniTFT ST7735R | |
# disp = ssd1351.SSD1351(spi, rotation=180, # 1.5" SSD1351 | |
# disp = ssd1351.SSD1351(spi, height=96, y_offset=32, rotation=180, # 1.27" SSD1351 | |
# disp = ssd1331.SSD1331(spi, rotation=180, # 0.96" SSD1331 | |
disp = ili9341.ILI9341( | |
spi, | |
rotation=90, # 2.2", 2.4", 2.8", 3.2" ILI9341 | |
cs=cs_pin, | |
dc=dc_pin, | |
rst=reset_pin, | |
baudrate=BAUDRATE, | |
) | |
# pylint: enable=line-too-long | |
# MPD Client | |
class MPDConnect(object): | |
def __init__(self, host='localhost', port=6600): | |
self._mpd_client = MPDClient() | |
self._mpd_client.timeout = 10 | |
self._mpd_connected = False | |
self._host = host | |
self._port = port | |
def connect(self): | |
if not self._mpd_connected: | |
try: | |
self._mpd_client.ping() | |
except(socket_error, ConnectionError): | |
try: | |
self._mpd_client.connect(self._host, self._port) | |
self._mpd_connected = True | |
except(socket_error, ConnectionError, CommandError): | |
self._mpd_connected = False | |
def disconnect(self): | |
self._mpd_client.close() | |
self._mpd_client.disconnect() | |
def _play_pause(self): | |
self._mpd_client.pause() | |
#return False | |
def _next_track(self): | |
self._mpd_client.next() | |
#return False | |
def _prev_track(self): | |
self._mpd_client.previous() | |
#return False | |
def fetch(self): | |
# MPD current song | |
song_info = self._mpd_client.currentsong() | |
# Artist Name | |
if 'artist' in song_info: | |
artist = song_info['artist'] | |
else: | |
artist = 'Unknown Artist' | |
# Song Name | |
if 'title' in song_info: | |
title = song_info['title'] | |
else: | |
title = 'Unknown Title' | |
# Album Name | |
if 'album' in song_info: | |
album = song_info['album'] | |
else: | |
album = 'Unknown Album' | |
# MPD Status | |
song_stats = self._mpd_client.status() | |
# State | |
state = song_stats['state'] | |
# Song time | |
if 'elapsed' in song_stats: | |
elapsed = song_stats['elapsed'] | |
m,s = divmod(float(elapsed), 60) | |
h,m = divmod(m, 60) | |
eltime = "%d:%02d:%02d" % (h, m, s) | |
else: | |
eltime ="0:00:00" | |
# Audio | |
if 'audio' in song_stats: | |
bit = song_stats['audio'].split(':')[1] | |
frequency = song_stats['audio'].split(':')[0] | |
z, f = divmod( int(frequency), 1000 ) | |
if ( f == 0 ): | |
frequency = str(z) | |
else: | |
frequency = str( float(frequency) / 1000 ) | |
bitrate = song_stats['bitrate'] | |
audio_info = bit + "bit " + frequency + "kHz " + bitrate + "kbps" | |
else: | |
audio_info = "" | |
# Bitrate | |
if 'bitrate' in song_stats: | |
bitrate = song_stats['bitrate'] | |
else: | |
bitrate = 'N/A' | |
# Volume | |
vol = song_stats['volume'] | |
return({'state':state, 'artist':artist, 'title':title, 'album':album, 'eltime':eltime, 'volume':int(vol), 'audio_info':audio_info, 'bitrate':bitrate}) | |
def main(): | |
# Create blank image for drawing. | |
# Make sure to create image with mode 'RGB' for full color. | |
if disp.rotation % 180 == 90: | |
height = disp.width # we swap height/width to rotate it to landscape! | |
width = disp.height | |
else: | |
width = disp.width # we swap height/width to rotate it to landscape! | |
height = disp.height | |
image = Image.new("RGB", (width, height)) | |
# Get drawing object to draw on image. | |
draw = ImageDraw.Draw(image) | |
# Draw a black filled box to clear the image. | |
draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0)) | |
disp.image(image) | |
# First define some constants to allow easy positioning of text. | |
#padding = -2 | |
#x = 0 | |
# Load a TTF font. Make sure the .ttf font file is in the | |
# same directory as the python script! | |
# Some other nice fonts to try: http://www.dafont.com/bitmap.php | |
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 12) | |
font_artist = ImageFont.truetype('/home/pi/MoodeAudio-OLED/Arial-Unicode-Bold.ttf', 48) | |
font_title = ImageFont.truetype('/home/pi/MoodeAudio-OLED/Arial-Unicode-Regular.ttf', 36) | |
font_album = ImageFont.truetype('/home/pi/MoodeAudio-OLED/Arial-Unicode-Regular.ttf', 24) | |
font_info = ImageFont.truetype('/home/pi/MoodeAudio-OLED/Verdana.ttf', 24) | |
font_time = ImageFont.truetype('/home/pi/MoodeAudio-OLED/Verdana.ttf', 36) | |
font_time_label = ImageFont.truetype('/home/pi/MoodeAudio-OLED/Verdana.ttf', 18) | |
font_timenow = ImageFont.truetype('/home/pi/MoodeAudio-OLED/Arial-Unicode-Bold.ttf', 120) | |
# MPD Connect | |
client = MPDConnect() | |
client.connect() | |
padding = 2 | |
shape_width = 20 | |
top = padding | |
bottom = height-padding | |
artoffset = 2 | |
titoffset = 2 | |
alboffset = 2 | |
animate = 20 | |
while True: | |
# Draw a black filled box to clear the image. | |
draw.rectangle((0, 0, width, height), outline=0, fill=0) | |
# Fetch data | |
info = client.fetch() | |
state = info['state'] | |
eltime = info['eltime'] | |
vol = info['volume'] | |
artist = info['artist'] | |
title = info['title'] | |
album = info['album'] | |
audio = info['audio_info'] | |
bitrate = info['bitrate'] | |
# Position text of Artist | |
artwd,artz = draw.textsize(str(artist), font=font_artist) | |
# Artist animate | |
if artwd < width: | |
artx = (width - artwd) / 2 | |
artoffset = padding | |
else: | |
artx = artoffset | |
artoffset -= animate | |
if (artwd - (width + abs(artx))) < -312: | |
artoffset = 320 | |
# Position text of Title | |
titwd,titz = draw.textsize(str(title), font=font_title) | |
# Title animate | |
if titwd < width: | |
titx = (width - titwd) / 2 | |
titoffset = padding | |
else: | |
titx = titoffset | |
titoffset -= animate | |
if (titwd - (width + abs(titx))) < -312: | |
titoffset = 320 | |
# Position text of Album | |
albwd,albz = draw.textsize(str(album), font=font_album) | |
# Album animate | |
if albwd < width: | |
albx = (width - albwd) / 2 | |
alboffset = padding | |
else: | |
albx = alboffset | |
alboffset -= animate | |
if (albwd - (width + abs(albx))) < -312: | |
alboffset = 320 | |
# Position text of audio infomation | |
audiox,audioy = draw.textsize(audio, font=font_info) | |
if audiox < 158: | |
audiox,audioy = divmod((65-audiox),2) | |
else: | |
audiox = 2 | |
if state == 'stop': | |
# Draw text | |
#draw.text((30,15), "Music Stop", font=font_title, fill="#FFFFFF") | |
#draw.text((padding,100), eltime, font=font_time, fill="#FFFFFF") | |
#draw.text((100,100), "vol: " + str(vol) , font=font_time, fill="#FFFFFF") | |
now = datetime.now() | |
current_time = now.strftime("%H:%M") | |
draw.text((5,15), current_time, font=font_timenow, fill="#FFFFFF") | |
else: | |
# Draw text. | |
draw.text((artx,1), str(artist), font=font_artist, fill="#00FFFF") | |
draw.text((titx,55), str(title), font=font_title, fill="#FFFFFF") | |
draw.text((albx,100), str(album), font=font_album, fill="YELLOW") | |
#draw.text((audiox,35), audio, font=font_info, fill="#FFFFFF") | |
draw.text((93,195), "kbit/s", font=font_time_label, fill="YELLOW") | |
draw.text((98,215), bitrate , font=font_info, fill="#00FFFF") | |
draw.text((86,140), eltime, font=font_time, fill="#FFFFFF") | |
draw.text((padding,215), str(vol) + "%" , font=font_info, fill="#00FFFF") | |
draw.text((padding,195), "input", font=font_time_label, fill="YELLOW") | |
#cmd = "amixer --card 1 get Headphone | grep dB | awk '{print $5}' | sort -u | tr -d '[]'" # pylint: disable=line-too-long | |
cmd = "amixer get Master | grep '%' | awk '{print $5}' | sort -u | tr -d '[]'" # pylint: disable=line-too-long | |
volume = subprocess.check_output(cmd, shell=True).decode("utf-8") | |
cmd = "cat /proc/asound/card1/pcm0p/sub0/hw_params | grep rate | awk '{print $2 / 1000}'" | |
freq = subprocess.check_output(cmd, shell=True).decode("utf-8") | |
draw.text((260,215), str(volume) , font=font_info, fill="#00FFFF") | |
draw.text((257,195), "output", font=font_time_label, fill="YELLOW") | |
draw.text((188,215), str(freq) , font=font_info, fill="#00FFFF") | |
draw.text((185,195), "kHz", font=font_time_label, fill="YELLOW") | |
#image_ratio = image.width / image.height | |
#screen_ratio = width / height | |
#if screen_ratio < image_ratio: | |
# scaled_width = image.width * height // image.height | |
# scaled_height = height | |
#else: | |
# scaled_width = width | |
# scaled_height = image.height * width // image.width | |
#image = image.resize((scaled_width, scaled_height), Image.BICUBIC) | |
cover = Image.open("/home/pi/pidi/current.jpg") | |
image = cover.resize((200, 200), Image.BICUBIC) | |
# Crop and center the image | |
#x = scaled_width // 32 - width // 32 | |
#y = scaled_height // 32 - height // 32 | |
#image = image.crop((x, y, x + width, y + height)) | |
# Draw the image buffer. | |
disp.image(image) | |
#disp.display() | |
# Pause briefly before drawing next frame. | |
time.sleep(1) | |
# Shell scripts for system monitoring from here: | |
# https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load | |
# cmd = "hostname -I | cut -d' ' -f1" | |
# IP = "IP: " + subprocess.check_output(cmd, shell=True).decode("utf-8") | |
# cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'" | |
# CPU = subprocess.check_output(cmd, shell=True).decode("utf-8") | |
# cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%s MB %.2f%%\", $3,$2,$3*100/$2 }'" | |
# MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8") | |
# cmd = 'df -h | awk \'$NF=="/"{printf "Disk: %d/%d GB %s", $3,$2,$5}\'' | |
# Disk = subprocess.check_output(cmd, shell=True).decode("utf-8") | |
# cmd = "cat /sys/class/thermal/thermal_zone0/temp | awk '{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}'" # pylint: disable=line-too-long | |
# Temp = subprocess.check_output(cmd, shell=True).decode("utf-8") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment