From 0bc8f504439be98e5244de49bbec73b98079d8a9 Mon Sep 17 00:00:00 2001 From: barry Date: Fri, 10 Jan 2025 15:50:43 +0100 Subject: [PATCH] format --- .pre-commit-config.yaml | 4 +- spotiplayer_pi/api.py | 15 ++++--- spotiplayer_pi/lcdconfig.py | 50 ++++++++++++--------- spotiplayer_pi/lib.py | 88 +++++++++++++++++++++---------------- spotiplayer_pi/main.py | 86 +++++++++++++++++++++++++++--------- 5 files changed, 156 insertions(+), 87 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa4f1ef..dc8d09b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: rev: v0.9.0 # Use the desired version of ruff hooks: - id: ruff - files: spotiplayer_pi/ + args: ["--ignore=E711,E721"] # args: ["--fix"] # Automatically apply fixes where possible - id: ruff-format - files: spotiplayer_pi/ + args: ["--ignore=E711,E721"] diff --git a/spotiplayer_pi/api.py b/spotiplayer_pi/api.py index 574f371..6c9d8b4 100644 --- a/spotiplayer_pi/api.py +++ b/spotiplayer_pi/api.py @@ -1,4 +1,6 @@ import requests +import warnings + class Api: def __init__(self, refresh_token: str, base_64: str): @@ -13,11 +15,13 @@ class Api: "grant_type": "refresh_token", "refresh_token": self.refresh_token, } - req = requests.post(uri, data=data, headers={"Authorization": "Basic " + self.base_64}).json() + req = requests.post( + uri, data=data, headers={"Authorization": "Basic " + self.base_64} + ).json() self.access_token = req["access_token"] self.header = {"Authorization": f"Bearer {self.access_token}"} return req["expires_in"] - + def getPlaying(self): url = "https://api.spotify.com/v1/me/player/currently-playing" req = requests.get(url, headers=self.header) @@ -42,8 +46,7 @@ class Api: if img_urls: res["img_url"] = img_urls.pop()["url"] else: - warnings.warn(f"{res['track']} - {res['artists']}\nAlbum art can't be found\n{img_urls}") + warnings.warn( + f"{res['track']} - {res['artists']}\nAlbum art can't be found\n{img_urls}" + ) return res - - - diff --git a/spotiplayer_pi/lcdconfig.py b/spotiplayer_pi/lcdconfig.py index 8533e2b..b416042 100644 --- a/spotiplayer_pi/lcdconfig.py +++ b/spotiplayer_pi/lcdconfig.py @@ -27,31 +27,40 @@ # THE SOFTWARE. # -import os -import sys import time import spidev import logging import numpy as np + class RaspberryPi: - def __init__(self,spi_freq=40000000,rst=27,dc=25,bl=18,bl_freq=1000,i2c=None,i2c_freq=100000): + def __init__( + self, + spi_freq=40000000, + rst=27, + dc=25, + bl=18, + bl_freq=1000, + i2c=None, + i2c_freq=100000, + ): import RPi.GPIO + self.np = np - self.RST_PIN= rst + self.RST_PIN = rst self.DC_PIN = dc self.BL_PIN = bl - self.SPEED =spi_freq - self.BL_freq=bl_freq + self.SPEED = spi_freq + self.BL_freq = bl_freq self.GPIO = RPi.GPIO - #self.GPIO.cleanup() + # self.GPIO.cleanup() self.GPIO.setmode(self.GPIO.BCM) self.GPIO.setwarnings(False) - self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) - self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) - self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) - self.GPIO.output(self.BL_PIN, self.GPIO.HIGH) - #Initialize SPI + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) + self.GPIO.output(self.BL_PIN, self.GPIO.HIGH) + # Initialize SPI self.SPI = spidev.SpiDev() self.SPI.open(0, 0) self.SPI.max_speed_hz = spi_freq @@ -67,28 +76,29 @@ class RaspberryPi: time.sleep(delaytime / 1000.0) def spi_writebyte(self, data): - if self.SPI!=None : + if self.SPI != None: self.SPI.writebytes(data) + def bl_DutyCycle(self, duty): self._pwm.ChangeDutyCycle(duty) - def bl_Frequency(self,freq): + def bl_Frequency(self, freq): self._pwm.ChangeFrequency(freq) def module_init(self): self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) - self._pwm=self.GPIO.PWM(self.BL_PIN,self.BL_freq) + self._pwm = self.GPIO.PWM(self.BL_PIN, self.BL_freq) self._pwm.start(100) - if self.SPI!=None : + if self.SPI != None: self.SPI.max_speed_hz = self.SPEED self.SPI.mode = 0b00 return 0 def module_exit(self): logging.debug("spi end") - if self.SPI!=None : + if self.SPI != None: self.SPI.close() logging.debug("gpio cleanup...") @@ -97,15 +107,15 @@ class RaspberryPi: self._pwm.stop() time.sleep(0.001) self.GPIO.output(self.BL_PIN, 1) - #self.GPIO.cleanup() + # self.GPIO.cleanup() -''' +""" if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'): implementation = RaspberryPi() for func in [x for x in dir(implementation) if not x.startswith('_')]: setattr(sys.modules[__name__], func, getattr(implementation, func)) -''' +""" ### END OF FILE ### diff --git a/spotiplayer_pi/lib.py b/spotiplayer_pi/lib.py index 0cd216b..38439e6 100644 --- a/spotiplayer_pi/lib.py +++ b/spotiplayer_pi/lib.py @@ -3,9 +3,9 @@ import lcdconfig class LCD_2inch(lcdconfig.RaspberryPi): - width = 240 height = 320 + def command(self, cmd): self.digital_write(self.DC_PIN, self.GPIO.LOW) self.spi_writebyte([cmd]) @@ -13,13 +13,14 @@ class LCD_2inch(lcdconfig.RaspberryPi): def data(self, val): self.digital_write(self.DC_PIN, self.GPIO.HIGH) self.spi_writebyte([val]) + def reset(self): """Reset the display""" - self.GPIO.output(self.RST_PIN,self.GPIO.HIGH) + self.GPIO.output(self.RST_PIN, self.GPIO.HIGH) time.sleep(0.01) - self.GPIO.output(self.RST_PIN,self.GPIO.LOW) + self.GPIO.output(self.RST_PIN, self.GPIO.LOW) time.sleep(0.01) - self.GPIO.output(self.RST_PIN,self.GPIO.HIGH) + self.GPIO.output(self.RST_PIN, self.GPIO.HIGH) time.sleep(0.01) def Init(self): @@ -116,63 +117,74 @@ class LCD_2inch(lcdconfig.RaspberryPi): self.command(0x29) - def SetWindows(self, Xstart, Ystart, Xend, Yend): - #set the X coordinates + # set the X coordinates self.command(0x2A) - self.data(Xstart>>8) #Set the horizontal starting point to the high octet - self.data(Xstart & 0xff) #Set the horizontal starting point to the low octet - self.data(Xend>>8) #Set the horizontal end to the high octet - self.data((Xend - 1) & 0xff)#Set the horizontal end to the low octet + self.data(Xstart >> 8) # Set the horizontal starting point to the high octet + self.data(Xstart & 0xFF) # Set the horizontal starting point to the low octet + self.data(Xend >> 8) # Set the horizontal end to the high octet + self.data((Xend - 1) & 0xFF) # Set the horizontal end to the low octet - #set the Y coordinates + # set the Y coordinates self.command(0x2B) - self.data(Ystart>>8) - self.data((Ystart & 0xff)) - self.data(Yend>>8) - self.data((Yend - 1) & 0xff ) + self.data(Ystart >> 8) + self.data((Ystart & 0xFF)) + self.data(Yend >> 8) + self.data((Yend - 1) & 0xFF) self.command(0x2C) - def ShowImage(self,Image,Xstart=0,Ystart=0): + def ShowImage(self, Image, Xstart=0, Ystart=0): """Set buffer to value of Python Imaging Library image.""" """Write display buffer to physical display""" imwidth, imheight = Image.size - if imwidth == self.height and imheight == self.width: + if imwidth == self.height and imheight == self.width: img = self.np.asarray(Image) - pix = self.np.zeros((self.width, self.height,2), dtype = self.np.uint8) - #RGB888 >> RGB565 - pix[...,[0]] = self.np.add(self.np.bitwise_and(img[...,[0]],0xF8),self.np.right_shift(img[...,[1]],5)) - pix[...,[1]] = self.np.add(self.np.bitwise_and(self.np.left_shift(img[...,[1]],3),0xE0), self.np.right_shift(img[...,[2]],3)) + pix = self.np.zeros((self.width, self.height, 2), dtype=self.np.uint8) + # RGB888 >> RGB565 + pix[..., [0]] = self.np.add( + self.np.bitwise_and(img[..., [0]], 0xF8), + self.np.right_shift(img[..., [1]], 5), + ) + pix[..., [1]] = self.np.add( + self.np.bitwise_and(self.np.left_shift(img[..., [1]], 3), 0xE0), + self.np.right_shift(img[..., [2]], 3), + ) pix = pix.flatten().tolist() self.command(0x36) self.data(0x70) - self.SetWindows ( 0, 0, self.height,self.width) - self.digital_write(self.DC_PIN,self.GPIO.HIGH) - for i in range(0,len(pix),4096): - self.spi_writebyte(pix[i:i+4096]) + self.SetWindows(0, 0, self.height, self.width) + self.digital_write(self.DC_PIN, self.GPIO.HIGH) + for i in range(0, len(pix), 4096): + self.spi_writebyte(pix[i : i + 4096]) - else : + else: img = self.np.asarray(Image) - pix = self.np.zeros((imheight,imwidth , 2), dtype = self.np.uint8) + pix = self.np.zeros((imheight, imwidth, 2), dtype=self.np.uint8) - pix[...,[0]] = self.np.add(self.np.bitwise_and(img[...,[0]],0xF8),self.np.right_shift(img[...,[1]],5)) - pix[...,[1]] = self.np.add(self.np.bitwise_and(self.np.left_shift(img[...,[1]],3),0xE0), self.np.right_shift(img[...,[2]],3)) + pix[..., [0]] = self.np.add( + self.np.bitwise_and(img[..., [0]], 0xF8), + self.np.right_shift(img[..., [1]], 5), + ) + pix[..., [1]] = self.np.add( + self.np.bitwise_and(self.np.left_shift(img[..., [1]], 3), 0xE0), + self.np.right_shift(img[..., [2]], 3), + ) pix = pix.flatten().tolist() self.command(0x36) self.data(0x00) - self.SetWindows ( 0, 0, self.width, self.height) - self.digital_write(self.DC_PIN,self.GPIO.HIGH) - for i in range(0,len(pix),4096): - self.spi_writebyte(pix[i:i+4096]) + self.SetWindows(0, 0, self.width, self.height) + self.digital_write(self.DC_PIN, self.GPIO.HIGH) + for i in range(0, len(pix), 4096): + self.spi_writebyte(pix[i : i + 4096]) def clear(self): """Clear contents of image buffer""" - _buffer = [0xff]*(self.width * self.height * 2) - self.SetWindows ( 0, 0, self.height, self.width) - self.digital_write(self.DC_PIN,self.GPIO.HIGH) - for i in range(0,len(_buffer),4096): - self.spi_writebyte(_buffer[i:i+4096]) + _buffer = [0xFF] * (self.width * self.height * 2) + self.SetWindows(0, 0, self.height, self.width) + self.digital_write(self.DC_PIN, self.GPIO.HIGH) + for i in range(0, len(_buffer), 4096): + self.spi_writebyte(_buffer[i : i + 4096]) diff --git a/spotiplayer_pi/main.py b/spotiplayer_pi/main.py index 28a5762..6f429a0 100644 --- a/spotiplayer_pi/main.py +++ b/spotiplayer_pi/main.py @@ -27,7 +27,7 @@ def display_loop(api: Api, cfg: Dict): d.clear() bg = Image.new("RGB", (d.height, d.width), (0, 0, 0)) d.ShowImage(bg) - + Font0 = ImageFont.truetype("Font/Font00.ttf", 14) Font1 = ImageFont.truetype("Font/Font00.ttf", 18) Font2 = ImageFont.truetype("Font/Font00.ttf", 36) @@ -45,7 +45,12 @@ def display_loop(api: Api, cfg: Dict): not_playing_img.paste(spoti_logo, (0, 10)) not_playing_img.paste(qr, (120, 40)) draw = ImageDraw.Draw(not_playing_img) - draw.text((124, 10), "Connect to speakers", font=Font1, fill=cfg["color_theme"]["text"]) + draw.text( + (124, 10), + "Connect to speakers", + font=Font1, + fill=cfg["color_theme"]["text"], + ) del spoti_logo, qr, draw last_api_call = 0 @@ -59,12 +64,12 @@ def display_loop(api: Api, cfg: Dict): if time.time() - last_auth_refresh >= auth_interval: auth_interval = api.refreshAuth() - 120 last_auth_refresh = time.time() - print(f'Refreshed auth at {datetime.now().strftime("%d-%m %H:%M:%S")}') + print(f"Refreshed auth at {datetime.now().strftime('%d-%m %H:%M:%S')}") if time.time() - last_api_call >= cfg["api_interval"]: data = api.getPlaying() last_api_call = time.time() - + if data == None: warnings.warn("No data found") d.ShowImage(error_img) @@ -73,45 +78,85 @@ def display_loop(api: Api, cfg: Dict): draw = ImageDraw.Draw(not_playing_img) current_time = datetime.now().time() draw.rectangle([(00, 120), (119, 170)], fill=(0, 0, 0)) - draw.text((20, 120), f"{current_time.hour}:{current_time.minute:02d}", font=Font2, angle=0) + draw.text( + (20, 120), + f"{current_time.hour}:{current_time.minute:02d}", + font=Font2, + angle=0, + ) if current_mode != 0: current_mode = 0 print("Standby mode") d.ShowImage(not_playing_img) time.sleep(cfg["api_interval"]) - + elif type(data) == dict: current_track = data["track"] + data["artists"][0] + data["album"] if current_track != last_track: - print('updating track') + print("updating track") last_track = current_track img = None try: - img = requests.get(data["img_url"], timeout=cfg["refresh_interval"]/2) + img = requests.get( + data["img_url"], timeout=cfg["refresh_interval"] / 2 + ) img = Image.open(BytesIO(img.content)) except Exception as e: - warnings.warn(f"Failed to fetch album cover at: {data['img_url']}\n{e}") + warnings.warn( + f"Failed to fetch album cover at: {data['img_url']}\n{e}" + ) if img == None: img = unavailable_img img = img.resize((128, 128)) bg = Image.new("RGB", (320, 240), cfg["color_theme"]["background"]) bg.paste(img, (10, 30)) draw = ImageDraw.Draw(bg) - draw.text((150, 40), "\n".join(textwrap.wrap(", ".join(data["artists"]), width=16)), font=Font1, fill=cfg["color_theme"]["text"]) - draw.text((10, 160), "\n".join(textwrap.wrap(data["track"], width=32)), font=Font1, fill=cfg["color_theme"]["text"]) + draw.text( + (150, 40), + "\n".join(textwrap.wrap(", ".join(data["artists"]), width=16)), + font=Font1, + fill=cfg["color_theme"]["text"], + ) + draw.text( + (10, 160), + "\n".join(textwrap.wrap(data["track"], width=32)), + font=Font1, + fill=cfg["color_theme"]["text"], + ) w, h = bg.size w -= 92 - progress_time = data["progress_ms"] + int((time.time() - last_api_call) * 1000) - progress= progress_time / data["duration_ms"] + progress_time = data["progress_ms"] + int( + (time.time() - last_api_call) * 1000 + ) + progress = progress_time / data["duration_ms"] bar_width = int(w * progress) - draw.rectangle([(8, h - 22), (w + 2, h - 8)], outline=cfg["color_theme"]["bar_outline"]) - draw.rectangle([(10, h - 20), (w, h - 10)], fill=cfg["color_theme"]["background"]) - draw.rectangle([(10, h - 20), (bar_width, h - 10)], fill=cfg["color_theme"]["bar_inside"]) - f_current_time = "{:02.0f}:{:02.0f}".format(*divmod(progress_time // 1000, 60)) - f_total_time = "{:02d}:{:02d}".format(*divmod(data["duration_ms"]// 1000, 60)) - draw.rectangle([(234, 215), (310, 235)], fill=cfg["color_theme"]["background"]) - draw.text((235, 215), f"{f_current_time}/{f_total_time}", font=Font0, fill=cfg["color_theme"]["text"]) + draw.rectangle( + [(8, h - 22), (w + 2, h - 8)], + outline=cfg["color_theme"]["bar_outline"], + ) + draw.rectangle( + [(10, h - 20), (w, h - 10)], fill=cfg["color_theme"]["background"] + ) + draw.rectangle( + [(10, h - 20), (bar_width, h - 10)], + fill=cfg["color_theme"]["bar_inside"], + ) + f_current_time = "{:02.0f}:{:02.0f}".format( + *divmod(progress_time // 1000, 60) + ) + f_total_time = "{:02d}:{:02d}".format( + *divmod(data["duration_ms"] // 1000, 60) + ) + draw.rectangle( + [(234, 215), (310, 235)], fill=cfg["color_theme"]["background"] + ) + draw.text( + (235, 215), + f"{f_current_time}/{f_total_time}", + font=Font0, + fill=cfg["color_theme"]["text"], + ) d.ShowImage(bg) time.sleep(cfg["refresh_interval"]) @@ -125,4 +170,3 @@ if __name__ == "__main__": cfg = parse_config() api = Api(cfg["refresh_token"], cfg["base_64"]) display_loop(api, cfg) -