Presto Music Library
MicroPython app for the Pimoroni Presto that connects to the Music Library API. It runs full-resolution on the 480x480 touch display and lets you search the collection or browse records released on a selected date.
What It Does
- Home screen with Search Collection and Today's Records
- Month calendar with day navigation and today's date highlighted
- Day list with cover art, title, artists, format, and release year
- Search input with on-screen keyboard and scrollable results
- Record detail page with larger cover art, genres, metadata, purchase date, and optional Last.fm scrobble button
- Display sleep after 1 minute of inactivity, with wake-on-touch
- WiFi reconnect, NTP sync, and simple network error states
Requirements
- Pimoroni Presto running stock firmware with MicroPython, PicoGraphics, touch,
urequests,ntptime, and usuallyjpegdec - WiFi with internet access
- Music Library API token
Setup
Create secrets.py from the template:
cp config.example.py secrets.py
Fill in:
WIFI_SSID = "your-wifi-ssid"
WIFI_PASSWORD = "your-wifi-password"
API_TOKEN = "your-api-token"
secrets.py is git-ignored and must not be committed.
Deploy
First-time deployment needs both the app and credentials on the device:
mpremote fs cp main.py :main.py
mpremote fs cp secrets.py :secrets.py
mpremote reset
After secrets.py has been copied once, use the project task:
mise run presto
That task copies main.py to :main.py and resets the Presto. It does not copy secrets.py.
The Presto runs main.py on boot, connects to WiFi, syncs time, then opens the home screen.
An equivalent Elm-style implementation is available in music_library.py. It
uses messages, model updates, and effects for the application runtime while
providing the same Music Library screens and API interactions. Deploy it as
the device entrypoint with:
mise run music_library
This task copies music_library.py to :main.py on the device and resets it.
Usage
Home: tap Search Collection to search by text, or Today's Records to open the current month with today highlighted.
Month view: use the arrow buttons to change month, tap a day to load records released on that date, or tap H to return home.
Day view: drag vertically to scroll long lists. During drag scrolling, covers are drawn as placeholders and restored when the drag ends. Tap a row to open its detail page.
Search: type with the on-screen keyboard and tap OK. Results use the same row and detail views as the day list. Back from results returns to the search input with the query preserved.
Record detail: shows title, artists, medium cover, genres, record type, format, release year, and purchase date. Records with selected_release_id show a Scrobble button; successful scrobbles show Done until you leave the detail page.
Display sleep: after 1 minute without touch input, the backlight turns off. The first touch wakes the display and is consumed so it does not also press a button or start a scroll.
Testing
Run the headless smoke tests from this directory:
mise run test
The tests use pimoroni-emulator mock MicroPython modules, import both
main.py and music_library.py without starting their event loops, and block
accidental network calls. They render all screen states and save screenshots
to tests/fixtures/ for manual inspection. Additional runtime tests cover the
message/effect boundary in music_library.py.
For a syntax-only check without creating __pycache__:
python3 -c "import py_compile; py_compile.compile('main.py', cfile='/tmp/main.pyc', doraise=True)"
python3 -c "import py_compile; py_compile.compile('music_library.py', cfile='/tmp/music_library.pyc', doraise=True)"
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
secrets.py not found |
Credentials are missing on the device | Copy secrets.py to the Presto root |
WIFI_SSID not set or API_TOKEN not set |
Required value is blank | Check secrets.py |
WiFi connection failed |
Wrong credentials or network unavailable | Verify SSID, password, and network |
Could not reach server |
API token invalid, server down, or network lost | Check API_TOKEN and server status |
| Grey cover placeholders | JPEG decoder unavailable or image URL failed | Check firmware and internet access |
| Black display after idle | Display sleep is active | Touch once to wake |
API Contract
All requests use:
Authorization: Bearer <API_TOKEN>
The app calls:
GET /api/v1/collection/on_this_day?date=YYYY-MM-DD
GET /api/v1/collection?q=QUERY&limit=20
POST /api/v1/collection/:record_id/scrobble
Both GET endpoints return { "records": [...] }. Fields used by the client:
idselected_release_idtitleartistsformatrelease_dategenresrecord_typepurchased_atcovers.smallcovers.medium
The day and search lists use covers.small as an 80x80 row thumbnail. Detail pages use covers.medium in a 400x400 cover area. The app expects display-ready JPEGs and does not resize covers on the device.
License
This application is part of the Music Library project.