Skip to content

v1.0.6

Choose a tag to compare

@dennisadvani dennisadvani released this 04 Aug 08:44
· 35 commits to main since this release

Image Download Links Below

  • Instructions
  • IMG can be used for Raspberry Pi 3+
  • For Raspberry Pi 2, follow the manual installation instructions as Trixie 13 Lite 32-bit is required

Key Fixes

  • Fixed WiFi, Captive Portal and Access Point issues.

Change Log

[1.0.5-beta.5]

Added

  • Pi 2 / Ethernet-only supportis_wifi_hardware_present() check prevents the controller from attempting AP activation on devices without WiFi hardware; the controller stays in CLIENT_CONNECTED or CLIENT_DISCONNECTED based on Ethernet state and never retries AP
  • Stale AP cleanup on boot — the controller now kills any leftover hostapd instance on initialisation, preventing the captive portal from blocking the web dashboard after an unclean shutdown

Changed

  • AP startup delay eliminated — removed the daemon's forced ap_timeout_seconds wait on boot; the controller now owns all timing (immediate AP when no saved networks, 5‑minute grace period when saved WiFi exists)
  • Boot screen message timing — 10 s delay after slideshow start ensures the boot screen fade-out completes before welcome or PIN messages appear
  • Setup script prompts before install — channel and WiFi country questions are now asked before git is installed; answers flow through to Phase 1 via environment variables so the user is never re‑prompted
  • Beta channel pins to pre-release tags — the setup script now checks out the latest v*-beta.* tag on main for beta channel installs instead of tracking the dev branch, matching the OTA updater's behaviour

Fixed

  • Captive portal blocking dashboard after reboot — hostapd left running from a previous AP session is now stopped at controller init
[1.0.4-beta.4]

Added

  • WiFi connection failed popup — when the captive portal WiFi connection fails (wrong password, out of range, etc.), an error message now appears on the photo frame display with guidance to check the password or try a different network (30 s auto-dismiss)
  • WiFi connection profile fallback — if the one-shot nmcli device wifi connect fails with a "key-mgmt property is missing" error (common on routers with mixed WPA2/WPA3 or certain TP-Link/ASUS models), the code now creates an explicit connection profile with WPA2-PSK settings and retries automatically
  • Setup script channel prompt — asks for stable or beta channel before installing; stable pins to the latest non-prerelease v* tag, beta tracks the dev branch
  • Setup script WiFi country prompt — asks for the regulatory domain (e.g. AU, US, GB) upfront alongside the channel choice; both answers are written to config.json for the Web UI

Changed

  • Boot welcome delay eliminated — the network monitor no longer waits ap_timeout_seconds when a network is already connected at boot; the welcome message appears as soon as the slideshow is ready instead of 60+ seconds later
  • Captive portal error messaging — the WiFi failure popup on the frame display uses a single clean message instead of concatenating the raw nmcli error with boilerplate text

Fixed

  • Setup script CRLF line endings.gitattributes now enforces eol=lf for *.sh files; the setup script was renormalized so it runs correctly when downloaded from GitHub raw on a Pi
[1.0.3-beta.3]

Changed

  • Network Controller rewrittenNetworkPhase flag-based state machine replaced with NetworkState enum (CLIENT_CONNECTED, CLIENT_DISCONNECTED, AP_ACTIVE, AP_EXHAUSTED); all transitions go through a single _transition_to() method under lock; monitor loop drains a pending-actions queue instead of comparing phase snapshots. Ethernet connectivity is checked independently from WiFi and is always safe (different radio) — nmcli is never queried for WiFi while the AP is active, preventing hostapd beacon disruption.
  • WiFi connection deferred to background thread — the captive portal's /api/network/connect endpoint now returns a response immediately (before the AP is torn down) and spawns a background thread for the actual AP-stop + scan + nmcli-connect sequence. The phone receives the HTTP response while still associated with the AP.
  • WiFi scan delay after AP stopconnect_to_network() now performs a nmcli device wifi rescan and waits 5 s after stopping the AP before attempting the connection. Without a fresh scan wlan0 has no visible SSID list and nmcli fails with "No network with SSID 'X' found."
  • Controller connection guard — new begin_connection() / end_connection() methods prevent the monitor thread from treating an intentionally-stopped AP as "unexpectedly dead" during the scan gap
  • AP_EXHAUSTED sudo reduction_stop_ap() now guarded by is_ap_mode_active() check; no longer runs unnecessary sudo commands on every monitor tick when the AP is already down

Fixed

  • WiFi connection failing after captive portal — the AP was torn down during the HTTP request, severing the client's TCP connection before the response arrived; the phone showed a network error instead of success
  • "WiFi Offline" popup flashing during WiFi connection — the monitor tick saw the AP was down during the scan delay and marked it as AP_EXHAUSTED, triggering an on-screen warning that was dismissed seconds later when the connection succeeded
  • Captive portal error messages removed — the password field no longer displays error text on failure; all feedback is shown on the photo frame display where it is always visible even after the phone disconnects from the AP

Removed

  • Legacy PIN state_pin_state module-level dict and all legacy PIN functions (generate_ap_pin, clear_ap_pin, validate_ap_pin, is_pin_required, get_active_pin) removed from network_manager.py; PIN management is now exclusively owned by NetworkController with proper thread safety
  • SCAN_CACHE_TTL constant and force_live parameter — scan cache is now served indefinitely while the AP is active; live scan toggle no longer exposed to the web API
  • Legacy PIN fallbacks in web routes — all is_pin_required() and validate_ap_pin() fallback paths removed; the controller is the sole source of truth
[1.0.2-beta.2]

Added

  • CPU temperature tile — sparkline graph on the System Status dashboard card using vcgencmd measure_temp; scaled 0–85°C in red
  • libopenblas0 added to setup script package list — resolves NumPy import failures on Pi 2 (32-bit) where the shared library was missing
  • Hardware documentation — separated Models table from RAM Requirements table in README; added 64‑bit vs 32‑bit image availability per model; Pi 4 promoted to Phase 1 (untested); Pi Zero 2 W marked as untested

Changed

  • Video transcode CPU limit default — reduced from 300 % to 200 %
  • Pause button — switched from Unicode characters (⏸/▶) to Material Symbols icons (pause / play_arrow) for consistent rendering
  • Progress bar colours — optimising images and transcoding bars now use var(--primary) (theme red), matching the scanning bar
  • WiFi Country Code — hint text repositioned below the input field using form-group--stack layout
  • Connected button — vertically centered in network list rows via display:inline-flex;align-items:center
  • Background processing bars — hidden when their respective feature is disabled (image optimisation off → hide optimising bar; video transcoding off → hide transcoding bar)
  • README — hardware section restructured with separate Supported Models and RAM Requirements tables; Pi 2 marked active (32-bit manual install); Pi 4 marked untested; Pi Zero 2 W marked untested

Fixed

  • Pipeline reset on sync changes — enabling/disabling local watch folders now triggers a full pipeline reset ("sync" re‑added to the config route trigger list)
  • Hardware docs consistencyCLAUDE.md, HARDWARE.md, ARCHITECTURE.md, GETTING_STARTED.md, INSTALLATION.md, and FEATURES.md updated to match README hardware tables (Pi 4 in Phase 1, Pi Zero 2 W untested, 32‑bit vs 64‑bit, manual install notes)
[1.0.1-beta.1]

Added

  • first_frame_path and last_frame_path fields on MediaItem — backend-generated video frame caches referenced directly by the presentation engine
  • VideoProcessor._extract_video_frames() — extracts first frame (t=0) and last frame (sseof) during Phase 2 OPTIMISE; cached as .1.frame / .2.frame JPEGs
  • Image optimisation worker subprocess (worker.py) — PIL operations (load, transpose, resize, save) run in an isolated process with cpulimit -l 50 (hard 50 % CPU cap) and nice -n 19 (lowest priority); OS reclaims all memory on exit
  • Adaptive CPU throttling — sleep between image optimisations scales with 1‑minute load average (load1 × 0.2, capped at 1.0 s); folder watcher also yields between thumbnail generations when the optimiser is busy
  • Boot screen progress bar — red fill bar below the spinner showing optimisation progress (1/6 → 6/6); uses draw_image with 1×1 pixel textures to avoid pi3d colour-space issues
  • Per‑phase progress bars in the Web UI Background Processing card — separate persistent bars for scanning, image optimisation, and video transcoding; each retains its last position when the active phase switches
  • Frontend→backend slideshow‑started signalPOST /api/slideshow-started defers the network monitor's AP‑fallback countdown until the first slideshow items are ready, preventing CPU/I/O contention during initial processing
  • /api/config/processing-status endpoint — serves per‑phase progress data
  • FEATURES.md — comprehensive feature list linked from README
  • Per‑image processing time and per‑batch memory delta logging (DEBUG level)
  • Raspberry Pi 5 (2GB+) official Phase 1 support — runs the same Trixie image via cage + XWayland; now the recommended platform over Pi 3
  • Immich network connectivity gate — syncer checks is_connected() before attempting API calls, avoiding wasted time on doomed requests when offline
  • Network Controller (network_controller.py) — single-owner state machine for WiFi/AP management; eliminates race conditions between network monitor thread and Flask request threads via threading.Lock
  • WiFi AP grace period — 5‑minute silent retry of saved WiFi before activating the captive portal; handles transient router reboots without user intervention
  • WiFi AP exhaustion — AP auto‑stops after 10 minutes if no user connects; never reactivates until next reboot, preventing continuous AP cycling on permanent WiFi loss
  • WiFi AP crash detection — controller detects when hostapd dies unexpectedly and transitions to exhausted state rather than lying about the AP being active
  • WiFi regulatory domain — configurable country code in setup script and Web UI; persists via cfg80211.ieee80211_regdom module parameter
  • WiFi power management disabled — setup script writes NetworkManager config (wifi.powersave = 2), fixing Pi 3 WiFi unreliability
  • Pipeline reset on config change — changes to video, image, or display settings clear all queues and re‑scan; boot layer reactivates with spinner during rebuild instead of showing a black screen
  • Boot layer reactivationreactivate() method re‑shows logo + spinner on pipeline reset; reset mode skips 3 s minimum display and progress bar
  • Documentation overhaul — new GETTING_STARTED.md, WIFI_SETUP.md, INSTALLATION.md; README restructured with logo, showcase images, and two‑path quick‑start section
  • Contributing link — README Contributing section links to dev setup guide in INSTALLATION.md#path-c-development-setup-remote-via-samba
  • Cumulative progress tracking — image and video optimisation progress bars now show total backlog across all batches instead of resetting every 6 items
  • Folder watcher scanning progress — incremental scans (new files added to watch folders) now report progress to the Web UI bar, not just the initial scan

Changed

  • Image processing moved to subprocessImageProcessor.process() spawns worker.py for cache misses; cache hits remain in‑process (fast path)
  • Throttle formula 4× more aggressiveload1 × 0.05load1 × 0.2
  • Batch sizes reduced — optimiser flush 12→6, folder watcher enqueue 24→6; items reach the slideshow ~4× faster after startup
  • Boot layer fades based on slideshow_ready signal from renderer (not playlist.json on disk) and waits for active GPU texture before signalling readiness — eliminates fade‑to‑black and jump‑cut regressions
  • _write_progress uses per‑phase format — scanning, optimising, and transcoding each track their own total/processed independently
  • Web UI Background Processing card replaced with three persistent progress bars using Material Symbols icons
  • is_ready_to_play now requires first_frame_path and last_frame_path for video items — videos without cached frames are excluded from the slideshow
  • Dev setup script: removed python3-pip and python3-pygame (dead deps)
  • Pi 5 moved from Phase 2 to Phase 1ARCHITECTURE.md, CLAUDE.md, README.md, and HARDWARE.md updated; Pi 5 (2GB+) now the recommended platform
  • Boot progress bar auto‑hides when slideshow queue reaches 6 items, preventing repeated 100 % cycling on cached restarts
  • Release scripts (release.ps1, release.sh): merge strategy changed from --ff-only to --no-ff for cleaner release history
  • Web UI scanning label updated to "Scanning folders and generating thumbnails"
  • WiFi AP state machine — daemon's _network_monitor_loop now delegates to NetworkController with phase‑based transitions (MONITORING, GRACE_PERIOD, AP_ACTIVE, AP_EXHAUSTED)
  • Video transcode CPU limit default — increased from 50 % to 300 % (3 full cores on Pi 5/3)
  • VLC playback messages — changed from INFO to DEBUG log level
  • Immich test connection — saves server URL and API key on successful test so Fetch Albums works immediately without a separate save step
  • Quiet boot hint — removed "Requires a reboot to take effect" from Web UI

Fixed

  • AP fallback falsely activated under CPU loadis_connected() now returns True on exception (nmcli timeout) instead of False
  • Worker JSON corrupted by cpulimit — cpulimit prints Process NNNN detected to stdout; parser now takes the first JSON line only
  • Duplicate throttle line — old ×0.05 formula overwrote new ×0.2 formula
  • Cache‑hit AttributeError — removed _build_item call, inlined MediaItem construction with _get_cached_dimensions()
  • Boot screen jump cutslideshow_ready now requires non‑None active GPU texture before signalling, preventing fade timer expiry during sync texture load
  • Slideshow‑started sent on empty queue — notification only fires when items are present; hot‑reload path also signals if initial load was empty
  • Progress bar jumping backward — uses batch size (6) as total instead of shrinking total_remaining
  • Progress bar disappearing — retains last‑known percentage when phase switches away from optimising_images
  • Boot layer duplicate docstring — removed dead duplicate of _read_progress_pct that shadowed the real implementation
  • WiFi captive portal not appearing on first bootstart_ap_mode() return value now checked; ap_was_active only set on success; wlan0 readiness polled (up to 30 s) before starting AP; hostapd no longer auto‑starts at boot
  • AP fallback retry deadlock — retry guard now checks is_ap_mode_active() as source of truth instead of a stale ap_was_active boolean
  • PIN validation race — PIN validated against cleared state (passed any input); now owned by NetworkController with threading.Lock; never passes when no PIN is active
  • Transparent PNG rendering — RGBA/PA images composited onto black background before RGB conversion; fixes white artifacts in transparent areas for both thumbnails and optimised images
  • Display power button state — Web UI button now reads actual display state from daemon via health endpoint instead of using a local toggle guess
  • Media library CPU spike — removed on‑the‑fly thumbnail generation from /api/media/list; relies on FolderWatcher‑generated thumbnails only
  • Log viewer follow mode — auto‑follow now jumps to last page when new entries arrive; scroll target corrected to #log-viewer container
  • On‑screen message spacing — Y‑position now accumulated from actual heights of preceding messages instead of index × current_height, eliminating gaps and overlaps between differently‑sized popups

Removed

  • All ffmpeg/ffprobe calls from PresentationEngine (engine.py): _extract_frame_array_cpu, _get_or_create_video_frame, _video_frame_cache_path, _video_frame_is_cached
  • contextlib import from frontend (no longer needed)
  • _count_playlist_items(), _PLAYLIST_PATH, and json import from boot layer
  • _resize_to_screen, _extract_exif, _build_item from ImageProcessor
  • ImageOps, UnidentifiedImageError imports from image.py