WakeOnPi: A full rework

Posted on 26 Apr 2026 by Vithurshan Selvarajah 6 min

Introduction

I thought the first version of WakeOnPi was done. It worked, it woke the screen, and it streamed video. Job finished.

Then real usage happened.

I wanted this to be a proper Home Assistant wall display, not a side project that only worked when I babysat it. That meant better control, better observability, cleaner architecture, and fewer hardcoded assumptions. This update is the result of that rewrite.

The original goal is still the same: a Raspberry Pi dashboard that wakes quickly on motion, uses less power, and feels instant. The difference now is that the system is much more maintainable, configurable, and integration-friendly.

What Changed in This Update

These were the main upgrades in this release cycle:

  • Browser control from both the settings UI and MQTT.
  • Home Assistant integration improvements (state topics + discovery pattern).
  • Camera recording support, including record-on-motion.
  • Codebase breakup into clearer modules for maintainability.
  • Dynamic variable/setting updates at runtime.
  • Release workflow and versioning automation.
  • Logging rework and a settings-view log console.
  • A WebSocket-driven settings page for live status and controls.

1) WebSocket Settings Page: Why It Was Added

In the older flow, most settings and status interactions depended on traditional request/response behavior. That works, but it feels stale for an always-on device where multiple moving parts can change state every few seconds.

The updated settings page now uses a WebSocket connection (/ws) so the UI can receive live status without constant polling. It reflects motion state, display status, browser status, recording state, storage, system metrics, and active settings in near real time.

Why WebSocket instead of just REST polling?

  • Lower overhead for frequent updates.
  • More responsive UI for operational controls.
  • Cleaner model for push-style state changes from the backend.
  • Better UX when tuning motion/recording/display behavior live.

It also lets actions flow in the opposite direction through the same channel: display toggles, brightness updates, service restarts, recording toggles, and settings updates can all be sent as structured messages.

2) Browser Control: How It Works and Why It Is Designed This Way

One of the biggest practical upgrades was browser control. WakeOnPi now manages a Chromium kiosk process through a dedicated controller module and exposes control via both UI actions and MQTT commands.

What changed

  • Browser can be refreshed and navigated remotely.
  • Dashboard URL can be updated dynamically.
  • Current browser URL is tracked and published.
  • Browser control is available from local settings and automation flows.

Why this architecture was chosen

Directly launching browser commands from random app code quickly becomes fragile. A dedicated controller with a worker thread and command queue was chosen to keep process lifecycle changes serialized and predictable.

This avoids race conditions like:

  • Multiple restart requests colliding.
  • URL updates arriving during process transitions.
  • Out-of-sync UI state versus actual browser state.

The controller also uses Chromium remote debugging to observe the active tab URL, which is then published to MQTT. That closes the loop between what the Pi is actually showing and what Home Assistant or remote clients think it is showing.

3) Home Assistant and MQTT Integration Improvements

MQTT moved from being mostly an add-on to being a first-class control and state channel.

Control side

WakeOnPi now accepts MQTT commands for:

  • Screen power and brightness.
  • Screen control mode (auto, always_on, always_off).
  • Browser URL setting and refresh.
  • Recording toggle.
  • Runtime settings updates.

State side

WakeOnPi publishes state for motion, screen status, brightness, browser URL, recording state, storage, and system details. This makes dashboards and automations far easier to build because state is explicit and continuously available.

Why this mattered

For a wall display, local control alone is limiting. MQTT makes the system automation-native: Home Assistant can react to WakeOnPi state and WakeOnPi can react to broader home events.

4) Camera Recording and Record-on-Motion

Recording was added as a practical feature for real deployments, not just streaming demos.

New capabilities

  • Manual recording toggle.
  • Record-on-motion mode.
  • Post-motion timeout to avoid clipping events too aggressively.
  • Storage guardrails with configurable behavior when usage is high.

Complexity and tradeoffs

Recording cannot be treated like a fire-and-forget action in an always-on system. The implementation had to handle camera availability, storage pressure, and mode transitions without destabilizing the stream/motion pipeline.

A storage-aware policy was added so the system can either pause recording or overwrite oldest files once configured limits are reached.

5) Codebase Breakup for Maintainability

This update deliberately decomposed the app into clearer modules:

  • app.py for API/routes and orchestration.
  • motion.py for detection loop and wake/sleep logic.
  • camera.py for mode config and switching.
  • display.py for backlight and brightness control.
  • browser.py for kiosk process lifecycle.
  • mqtt.py for subscriptions, publish flow, and reconnect logic.
  • config.py for defaults and persistent runtime settings.

The reason is simple: hardware projects become hard to evolve when control logic, IO, and transport concerns are mixed together. Separating concerns made changes safer and debugging significantly easier.

6) Dynamic Variable Setting at Runtime

A major usability upgrade was moving from mostly static configuration to runtime-updatable settings.

Settings can now be updated through the UI or API without manual code edits, and many changes are applied immediately. Stream-specific changes can trigger camera reconfiguration, while sensitive fields keep placeholder semantics so credentials are not accidentally overwritten.

This made tuning possible in production-like conditions, where motion thresholds, timeouts, stream quality, and control behavior often need iterative adjustment.

7) Logging Rework and Log Viewing from Settings

The logging system was rebuilt to improve signal-to-noise and accessibility.

What changed

  • In-memory log buffering for quick diagnostics.
  • Filtering of noisy request paths to reduce clutter.
  • Level-based viewing from the settings page.

Why it matters

When this runs as an appliance-like service, logs must be available quickly without SSH-first workflows. The settings-side log viewer helps diagnose MQTT disconnects, camera issues, and service behavior directly from the control interface.

8) Release Workflow and Versioning

Release handling is now automated through GitHub Actions workflows, including beta and release pipelines.

What this improves

  • Consistent version tagging and release metadata.
  • Changelog generation from commit history.
  • Better beta/release separation.
  • Reduced manual release overhead.

Version information is also surfaced in runtime status and UI, which helps correlate field behavior with deployed builds.

Lessons from This Update

  • Fast features are good, controllable features are better.
  • Hardware-facing apps need robust process and state management, not just working code paths.
  • Real-time UI plus MQTT creates a stronger operational model than either one alone.
  • Maintainability work pays off quickly once feature count grows.

Closing Thoughts

This update was less about adding random features and more about making WakeOnPi reliable as a daily system.

It now behaves like a proper service: observable, remotely controllable, modular, and release-managed. The instant wake experience is still the core, but the surrounding platform is now strong enough to keep improving without turning into a maintenance nightmare.

If you are building something similar, the biggest takeaway is this: invest early in control surfaces (WebSocket, MQTT), observability (logs/status), and clean module boundaries. Those are the parts that make rapid iteration sustainable.

Learn More

WakeOnPi GitHub Repository