Skip to content

0.18.0

Choose a tag to compare

@github-actions github-actions released this 05 Sep 12:59
· 108 commits to main since this release

Board Support:

  • Add Waveshare ESP32-S3-Touch-LCD-3.5 (3.5' 320x480 ST7796 over SPI with LCD reset/CS on a PCA9554 IO expander, FT6336 touch, QMI8658 IMU, AXP2101 battery management); vendors the st7796 display driver and adds a PCA9554 expander driver
  • UNIHIKER K10: improve two-button navigation, correct camera preview orientation, and restore button input after camera operations
  • unix/macOS/web: compiler fallback to bytecode on architectures without a native emitter (e.g. macOS on Apple Silicon) instead of runtime-loaded apps using @micropython.native/@micropython.viper failing to import with SyntaxError 'invalid micropython decorator'
  • Waveshare ESP32-S3-Touch-LCD-3.5: ES8311 audio support (speaker output + microphone input over I2S, DAC volume default tuned by ear on hardware)

Builtin Apps:

  • AppStore and OSUpdate: defer boot service import and start by 120s and 90s respectively via delay_s in manifest intent_filter, moving their module imports out of the boot path
  • AppStore and OSUpdate: fix cooldown blocking the first update check for 60s after boot on ESP32 (ticks_ms counts from boot)
  • AppStore: add 'Scan QR' button that opens an app's detail screen from a scanned app link (https://badgehub.eu/page/project/APP_ID, micropythonos://app/APP_ID or mpos://app/APP_ID)
  • AppStore: fix insert_app_list_item not hiding items that don't match the selected category filter, causing remote-only apps to leak into the 'Installed' view
  • AppStore: guard against segfault when the activity leaves the foreground during an async download (e.g. back_screen() while the index is downloading)
  • AppStore: open a QR deep link's app detail screen immediately when the app is already known locally, instead of waiting for the index download

Frameworks:

  • AppManager: apps can declare URL handlers via 'urlPattern' in manifest intent_filters; patterns matching the official store host, mpos:// or micropythonos:// are reserved and rejected; multiple matching handlers open the chooser
  • AppManager: boot services can declare delay_s in their intent_filter; services with delay_s > 0 are imported and started asynchronously after the delay, keeping non-critical module imports out of the boot path
  • AudioManager: WAVStream on desktop and web now honors set_repeat()/repeat_count (was ESP32-only), so the MusicPlayer Repeat checkbox works across all platforms
  • AudioManager: WAVStream on ESP32 drains remaining I2S audio by wall-clock instead of a fixed sleep, fixing on_complete delays of up to 2s for low-sample-rate clips
  • Camera: after decoding a QR code in free-scan mode, show an 'Open in App Store' / 'Open link' chip when the code is an app link the OS can open
  • Camera: gracefully handle boards with no camera hardware (e.g. fri3d_2026) — show a 'No camera found' status instead of crashing on get_cameras()[0]
  • DeepLink: new mpos.content.deeplink module with strict app-link parsing (exact host allowlist, identity-only links) and URL dispatch
  • DNS (async_dns): single-flight lookups per name with a synchronous fallback when no worker thread can be spawned (e.g. boot-time thread pressure), so concurrent websocket/download connections no longer fail with 'can't create thread'
  • FileExplorer: pick mode with a path_pattern now lists only matching files (directories stay listed) — non-matching files could never be selected and taps on them were silently ignored, so listing them was pure clutter; browse mode still lists everything
  • focus_direction: skip stale widgets from inactive screens during navigation
  • FontManager: cache emoji codepoints for keyboard input by @fdb
  • FontManager: stop leaking an app's TTF and emoji fonts after the app closes by @fdb
  • fs_driver: widen callback exception handling from OSError to Exception, supporting non-seekable streams like DeflateIO
  • Nostr: surface NIP-47 (NWC) error replies through the error callback instead of silently discarding them. An UNAUTHORIZED reply (e.g. a retired wallet connection) previously left apps stuck on their connecting state forever, indistinguishable from a dead relay; identical repeated errors are forwarded once, and an error reply now also resets the relay silence watchdog since the wallet service is demonstrably answering
  • Screenshot: move the BMP encoder out of the web server into mpos.ui.testing.encode_bmp(), which both now share, and add save_screenshot_bmp() to capture the screen straight into a file
  • SharedPreferences: get_dict_item() and get_list_item_dict() now return copies, fixing silent write loss when mutating returned items
  • TaskManager: add create_supervised_task(restart_on_return=True) and use it for the aiorepl console, so it is restarted when it exits
  • TaskManager: create_task returns None when the task manager is disabled, preventing C-level crashes from asyncio.create_task on ESP32 when called from a disabled test runner context
  • topmenu: close_drawer() now accepts an animate parameter, matching the existing close_bar() API
  • topmenu: replace group.remove_all_objs() + rebuild with per-object lv.group_remove_obj() in _remove_focusables_from_group, avoiding DEFOCUSED event dispatch mid-cleanup and eliminating repeated linked-list node allocations that fragmented the LVGL heap
  • View: clear the shared default focus group before the screen is deleted to prevent dangling LVGL pointer accumulation across activity transitions

OS:

  • aiorepl: stop Ctrl-D in the non-raw REPL loop from shutting asyncio down; it now ends the line like Ctrl-C
  • aiorepl: survive stdin EOF (host disconnect) by polling for reconnection instead of exiting, so the serial console no longer dies permanently after mpremote/raw-REPL connection attempts
  • boot: disable the Ctrl-C interrupt character while mpos.main boots (restored on the REPL fallback paths), so hosts connecting over serial mid-boot (e.g. mpremote entering raw REPL) can no longer silently abort the boot scripts and leave the OS half-started at the REPL
  • builtin: compress the frozen /builtin filesystem archive (freezefs --compress), saving ~39 KB of firmware flash, and strip development junk (pycache, .DS_Store, backup files) from it during the build (#268)
  • lvgl_micropython: add general-punctuation glyphs to Montserrat fonts
  • lvgl_micropython: add native-decorator bytecode fallback for builds without a native emitter like the unix port on aarch64 (Apple Silicon macOS) and the wasm/web port
  • lvgl_micropython: compress Montserrat 10-18 fonts to save ~19 KB of flash space
  • main.py: skip the lib/ override when lib/mpos is from a different release than the frozen firmware, instead of letting a stale lib/ (as flashed by the web installer) shadow the new frozen modules after an OTA update and crash the launcher at boot (#239)
  • nostr: improve connection management, watchdog, error management
  • sdl_keyboard: CTRL-SHIFT-S (CMD-SHIFT-S on macOS) saves a timestamped BMP screenshot in the current directory, at the screen's own pixel size instead of the scaled SDL window

Testing:

  • howto_app: clear auto_start_app_early SharedPreferences in setUp so the 'Don't show again' checkbox reliably starts unchecked
  • mpos.ui.testing: simulate_click() now pumps simulated-indev reads during the hold, so LONG_PRESSED fires even when the scheduler is blocked
  • mpos_controller: click_button() now clicks the innermost clickable widget containing the text, instead of the outermost ancestor that sent clicks to the screen center
  • mpos_controller: write paste-mode payloads in chunks, draining echoed input between chunks to avoid PTY-buffer deadlock
  • on-device: increase timeouts for about_app (10→15s), launcher_splash dialog (8→15s), and fs_driver image loading (5→15s with upfront render wait) to account for device latency
  • on-device: relax timing thresholds for infinite_list (scroll drags, render waits, set_data) and navigation_leaks (32→2048 bytes/round) on ESP32 where the slower CPU exceeds desktop expectations
  • on-device: skip websocket (requires internet), nostr_local_relay (WebSocket on localhost unreliable), and scan_bluetooth simulation-mode detection (BLE-dependent)
  • test_battery_voltage: skip ADC/caching/voltage classes on boards that override BatteryManager to read the io_expander (no battery ADC, e.g. fri3d_2026)
  • test_calibration_check_bug: use the real IMU (auto-detected) instead of hardware mocks; save/restore calibration
  • test_runner/mpos_controller: self-check that unittest assertions aren't no-ops from an -O3 build; auto-repair from lib/unittest when possible, and fail loudly with a diagnostic when not — previously stripped assertions reported vacuously green
  • test_runner: catch subprocess timeout when a device freezes mid-test so the runner can retry (with --reset) instead of crashing
  • test_runner: disable notification sound on macOS/darwin in the settings because it causes a hang on headless CI runners
  • test_runner: save/restore asyncio.core globals around nested event loops, preventing segfaults when tests run inside the TaskManager's paste-mode event loop
  • test_runner: USB device unbind/rebind and automatic recovery when relay reset fails to bring the device back; also CDC PID polling (0x4001/0x1001) for ESP32-S3 USB enumeration

Merged branches

  • Revert "FontManager: free TTF and emoji fonts instead of leaking them per app" by @ThomasFarstrike in #254
  • FontManager: free an app's TTF and emoji fonts when the app quits by @fdb in #258
  • floodit: Tweaks, display "game ended" dialog and allow new game by @pavelmachek in #242
  • Fix UNIHIKER K10 two-button navigation by @leezisheng in #251
  • QR-code app deep links: scan a store link to install an app by @bitcoin3us in #249
  • main.py: skip stale lib/ override that bricks devices after OTA update by @bitcoin3us in #240
  • Fix runtime-loaded apps with native/viper decorators failing on desktop builds without a native emitter by @bitcoin3us in #237
  • Fix permanent serial console death from mpremote/raw-REPL connections by @bitcoin3us in #234
  • docs: add SECURITY.md vulnerability disclosure policy by @jnuyens in #225
  • Add CTRL-SHIFT-S screenshot hotkey to the desktop emulator by @fdb in #260
  • Cache emoji codepoints for keyboard input by @fdb in #264
  • Fix TaskManager finished tasks memory leak by @fdb in #266
  • builtin archive: strip dev junk and enable compression by @bitcoin3us in #270
  • AppStore: resolve QR deep links to local apps before the index download by @bitcoin3us in #269
  • Speedup boot by @ThomasFarstrike in #273
  • Show Battery app: reuse LVGL drawing objects by @fdb in #267
  • test tooling: fail loudly when unittest assertions are stripped by @bitcoin3us in #277
  • Fix test tooling: long-press simulation and click_button targeting by @bitcoin3us in #275
  • SharedPreferences: return copies from get_dict_item and get_list_item_dict by @bitcoin3us in #276
  • WAVStream: honor repeat_count in desktop and web playback by @bitcoin3us in #278
  • FileExplorer: list only path_pattern matches in pick mode by @bitcoin3us in #279
  • Add board support: Waveshare ESP32-S3-Touch-LCD-3.5 by @bitcoin3us in #280
  • Waveshare ESP32-S3-Touch-LCD-3.5: ES8311 audio support by @bitcoin3us in #281
  • WAVStream: drain queued I2S audio by wall-clock instead of a fixed ibuf sleep by @bitcoin3us in #282
  • Waveshare ESP32-S3-Touch-LCD-3.5: camera connector support (OV5640/OV2640) by @bitcoin3us in #285
  • Nostr: surface NIP-47 error replies instead of silently dropping them by @bitcoin3us in #288
  • tests: isolate the camera preview blit test on its own screen by @bitcoin3us in #291
  • build_mpos.sh: apply lvgl_micropython's SDL release-2.32.8 patch for unix/macOS builds by @bitcoin3us in #292
  • deeplink: fold query keys to lowercase; accept www.badgehub.eu by @bitcoin3us in #290
  • tests: use Lightning Piggy's current publisher name in the BadgeHub fixture by @bitcoin3us in #293
  • Nostr: keep the MessagePool across watchdog reconnects; count any NWC event as activity by @bitcoin3us in #295

New Contributors

Full Changelog: 0.17.3...0.18.0