This commit is contained in:
barry 2025-10-01 19:11:46 +02:00
parent 2610d484e8
commit b7e2706b12
6 changed files with 163 additions and 24 deletions

106
poetry.lock generated
View File

@ -1,5 +1,25 @@
# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand.
[[package]]
name = "anyio"
version = "4.11.0"
description = "High-level concurrency and networking framework on top of asyncio or Trio"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"},
{file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"},
]
[package.dependencies]
idna = ">=2.8"
sniffio = ">=1.1"
typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
[package.extras]
trio = ["trio (>=0.31.0)"]
[[package]]
name = "certifi"
version = "2024.12.14"
@ -155,6 +175,65 @@ docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.
testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"]
typing = ["typing-extensions (>=4.12.2)"]
[[package]]
name = "h11"
version = "0.16.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"},
{file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"},
]
[[package]]
name = "httpcore"
version = "1.0.9"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"},
{file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"},
]
[package.dependencies]
certifi = "*"
h11 = ">=0.16"
[package.extras]
asyncio = ["anyio (>=4.0,<5.0)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
trio = ["trio (>=0.22.0,<1.0)"]
[[package]]
name = "httpx"
version = "0.28.1"
description = "The next generation HTTP client."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
{file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
]
[package.dependencies]
anyio = "*"
certifi = "*"
httpcore = "==1.*"
idna = "*"
[package.extras]
brotli = ["brotli", "brotlicffi"]
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "identify"
version = "2.6.5"
@ -531,6 +610,18 @@ files = [
{file = "ruff-0.9.0.tar.gz", hash = "sha256:143f68fa5560ecf10fc49878b73cee3eab98b777fcf43b0e62d43d42f5ef9d8b"},
]
[[package]]
name = "sniffio"
version = "1.3.1"
description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
[[package]]
name = "spidev"
version = "3.6"
@ -543,6 +634,19 @@ files = [
{file = "spidev-3.6.tar.gz", hash = "sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b"},
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
description = "Backported and Experimental Type Hints for Python 3.9+"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version < \"3.13\""
files = [
{file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"},
{file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"},
]
[[package]]
name = "urllib3"
version = "2.3.0"
@ -585,4 +689,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
[metadata]
lock-version = "2.1"
python-versions = "^3.11"
content-hash = "135cf9001d97689d659830abaa919636d20e76a494585757f9b59fbe9ca3adb5"
content-hash = "3e4bb3f59bdb90eac1180a026c9be37147b636f91f1f09cce2d7889b4c517f5e"

View File

@ -13,6 +13,7 @@ numpy = "^2.2.1"
pillow = "^11.1.0"
pyyaml = "^6.0.2"
psutil = "^6.1.1"
httpx = "^0.28.1"
[tool.poetry.group.dev.dependencies]

View File

@ -1,3 +1,6 @@
anyio==4.11.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc \
--hash=sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4
certifi==2024.12.14 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \
--hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db
@ -94,6 +97,15 @@ charset-normalizer==3.4.1 ; python_version >= "3.11" and python_version < "4.0"
--hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \
--hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \
--hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616
h11==0.16.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
httpcore==1.0.9 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
httpx==0.28.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
idna==3.10 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
@ -300,9 +312,15 @@ pyyaml==6.0.2 ; python_version >= "3.11" and python_version < "4.0" \
requests==2.32.3 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
sniffio==1.3.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
--hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
spidev==3.6 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b \
--hash=sha256:280abc00a1ef7780ef62c3f294f52a2527b6c47d8c269fea98664970bcaf6da5
typing-extensions==4.15.0 ; python_version >= "3.11" and python_version < "3.13" \
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
urllib3==2.3.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \
--hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d

View File

@ -1,5 +1,5 @@
import requests
import warnings
import httpx
class Api:
@ -8,23 +8,27 @@ class Api:
self.base_64 = base_64
self.access_token = None
self.header = None
self._client = httpx.AsyncClient(timeout=httpx.Timeout(5.0, connect=5.0))
def refreshAuth(self) -> None:
async def refreshAuth(self) -> None:
uri = "https://accounts.spotify.com/api/token"
data = {
"grant_type": "refresh_token",
"refresh_token": self.refresh_token,
}
req = requests.post(
uri, data=data, headers={"Authorization": "Basic " + self.base_64}
).json()
res = await self._client.post(
uri,
data=data,
headers={"Authorization": "Basic " + self.base_64},
)
req = res.json()
self.access_token = req["access_token"]
self.header = {"Authorization": f"Bearer {self.access_token}"}
return req["expires_in"]
def getPlaying(self):
async def getPlaying(self):
url = "https://api.spotify.com/v1/me/player/currently-playing"
req = requests.get(url, headers=self.header)
req = await self._client.get(url, headers=self.header)
if req.status_code == 204:
return "not-playing"
if req.status_code == 401:

View File

@ -56,10 +56,14 @@ class RaspberryPi:
# 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)
# 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)
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH)
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT, initial=self.GPIO.LOW)
self.GPIO.setup(self.BL_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH)
# Initialize SPI
self.SPI = spidev.SpiDev()
self.SPI.open(0, 0)
@ -86,9 +90,13 @@ class RaspberryPi:
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.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.setup(self.RST_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH)
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT, initial=self.GPIO.LOW)
self.GPIO.setup(self.BL_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH)
self._pwm = self.GPIO.PWM(self.BL_PIN, self.BL_freq)
self._pwm.start(100)
if self.SPI != None:

View File

@ -9,6 +9,7 @@ from datetime import datetime
import yaml
from typing import Dict
import subprocess
import asyncio
import numpy as np
import psutil
@ -62,7 +63,7 @@ def parse_config(path="spotiplayer_pi/config.yaml"):
return data
def display_loop(api: Api, cfg: Dict):
async def display_loop(api: Api, cfg: Dict):
try:
d = LCD_2inch()
d.Init()
@ -98,12 +99,12 @@ def display_loop(api: Api, cfg: Dict):
while True:
if time.time() - last_auth_refresh >= auth_interval:
auth_interval = api.refreshAuth() - 120
auth_interval = await api.refreshAuth() - 120
last_auth_refresh = time.time()
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()
data = await api.getPlaying()
last_api_call = time.time()
if data == None:
warnings.warn("No data found")
@ -129,7 +130,10 @@ def display_loop(api: Api, cfg: Dict):
idx = cpu_values_idxs[i]
val, prev_val = cpu_values[i], cpu_values[i - 1]
draw.rectangle(
[(idx, 200 - val), (idx - 1, 200 - prev_val)],
[
(min(idx - 1, idx), min(200 - prev_val, 200 - val)),
(max(idx - 1, idx), max(200 - prev_val, 200 - val)),
],
fill=(255, 253, 195),
)
draw.text(
@ -185,8 +189,8 @@ def display_loop(api: Api, cfg: Dict):
idx = len(binned_data) - idx_ - 1
draw.rectangle(
[
(321 - ((idx + 1) * 16), 240),
(319 - (idx * 16), 240 - bin_i // 65),
(321 - ((idx + 1) * 16), min(240, 240 - bin_i // 65)),
(319 - (idx * 16), max(240, 240 - bin_i // 65)),
],
fill=tuple(cmap2[idx]),
)
@ -293,10 +297,10 @@ def display_loop(api: Api, cfg: Dict):
fill=cfg["color_theme"]["text"],
)
d.ShowImage(bg)
time.sleep(cfg["refresh_interval"])
await asyncio.sleep(cfg["refresh_interval"])
except IOError as e:
raise e
print(f"IOError: {e}")
except KeyboardInterrupt:
d.module_exit()
@ -304,4 +308,4 @@ def display_loop(api: Api, cfg: Dict):
if __name__ == "__main__":
cfg = parse_config()
api = Api(cfg["refresh_token"], cfg["base_64"])
display_loop(api, cfg)
asyncio.run(display_loop(api, cfg))