Initial commit: Paperwall, a standalone e-ink dashboard

Navidrome now-playing, clock, and weather for a Waveshare epd4in0e panel,
with a local web UI and install/uninstall scripts for the Pi.
This commit is contained in:
Honey committed 2026-07-21 22:29:45 +02:00
commit 66464291e1
33 files changed
+2215

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
"""Driver for the Waveshare epd4in0e (4", 6-color Spectra) panel.
Thin wrapper around the vendored `waveshare_epd.epd4in0e` module -- the exact
driver already proven working under the InkyPi install on this Pi. That
driver only exposes `Clear()` and `display()`, both of which do a full
`TurnOnDisplay()` flash cycle; there is no partial-refresh path for this
panel at the hardware/SDK level, confirmed by reading the driver itself.
"""
import logging
from display import Display
logger = logging.getLogger(__name__)
RESOLUTION = (400, 600)
class EPD4in0eDisplay(Display):
def __init__(self):
self.resolution = RESOLUTION
self._epd = None
def init(self) -> None:
from waveshare_epd import epd4in0e
self._epd = epd4in0e.EPD()
self._epd.init()
logger.info("epd4in0e initialized")
def show(self, image) -> None:
if self._epd is None:
self.init()
width, height = self.resolution
if image.size != (width, height):
raise ValueError(
f"Image size {image.size} does not match panel resolution {self.resolution}"
)
# Re-init: the panel goes to sleep after every show(), and needs a
# fresh init() before it will accept commands again.
self._epd.init()
# Clear first to avoid ghosting from the previous image -- also a
# full flash, there's no way around it on this panel.
self._epd.Clear()
self._epd.display(self._epd.getbuffer(image.convert("RGB")))
def sleep(self) -> None:
if self._epd is not None:
self._epd.sleep()
logger.info("epd4in0e put to sleep")