Wednesday, February 18, 2026

Build a Low-Cost DIY USB Volume Knob with Digispark ATtiny85

This project turns a cheap Digispark ATtiny85 USB dongle and a KY-040 rotary encoder into a dedicated hardware volume knob. Rotate clockwise for volume up, counter-clockwise for volume down, press to mute. It enumerates as a standard USB HID Consumer Control device — no custom driver, no desktop app. Linux, Windows, and many Android devices recognise it out of the box.

Last updated: February 18, 2026

3D render of the DIY USB volume knob showing a Digispark ATtiny85 board connected to a KY-040 rotary encoder

3D render of the assembled volume knob — Digispark ATtiny85 USB board with KY-040 rotary encoder.

Finished DIY USB volume knob plugged into a USB port, showing the Digispark board with rotary encoder attached

The finished USB volume knob — plug in and it works immediately as a standard HID device.

Why Build This?

Keyboard shortcuts work, but a physical knob is better when you are:

  • Switching between headphones and speakers
  • On a call and need instant mute
  • Using a media PC or mini server with no easy keyboard access
  • Tired of digging into software mixer panels

For around 5–10 USD in parts you get a dedicated hardware control that is always there.

Parts

Parts required for the DIY USB volume knob: Digispark ATtiny85 board, KY-040 rotary encoder, and jumper wires

Everything needed: Digispark ATtiny85 USB board, KY-040 rotary encoder module, and jumper wires.

  • Digispark ATtiny85 USB board — ~2 USD
  • KY-040 rotary encoder module — ~1 USD
  • Jumper wires (female-to-female) — ~1 USD
  • Optional: 3D-printed case or aftermarket knob for a cleaner finish

Wiring

Wiring diagram showing connections between KY-040 rotary encoder and Digispark ATtiny85 board

Connection diagram: KY-040 rotary encoder wired to the Digispark ATtiny85 USB board.

Rotary Encoder Digispark ATtiny85
CLK P5 (PB5)
DT P2 (PB2)
SW P0 (PB0)
+ 5V
GND GND

ATtiny85 pin mapping used by this project:

                 +-\/-+
ENC_A (CLK) PB5  1|    |8  Vcc
USB D-      PB3  2|    |7  PB2  ENC_B (DT)
USB D+      PB4  3|    |6  PB1
            GND  4|    |5  PB0  ENC_SW (SW)
                 +----+

Note: PB5 is used as GPIO for encoder input in this design (RSTDISBL fuse context applies when programming bare chips). Digispark boards typically ship in a suitable configuration already.

Firmware

The firmware sends standard HID Consumer Control usages:

HID Usage Function
0xE9 Volume Increment
0xEA Volume Decrement
0xE2 Mute

Because these are standard HID usages, the host OS handles them natively — no custom driver needed.

Build and Flash

Clone the repository and build the firmware and uploader:

git clone https://github.com/hackboxguy/attiny85-hid-rotary-knob.git
cd attiny85-hid-rotary-knob
make all

This builds main.hex (firmware) and tools/micronucleus/micronucleus (uploader).

Flash via Micronucleus bootloader:

make upload

Tip: After running make upload, you will see "Waiting for device...". Plug in the Digispark within 60 seconds — the upload starts automatically once the bootloader is detected.

If your setup does not require sudo:

make upload SUDO=''

Note: Digispark boards come with the Micronucleus bootloader pre-installed — just plug in and upload. This blog assumes a board with a working bootloader. If you have a blank ATtiny85 chip without Micronucleus, flashing the bootloader requires an ISP programmer and is outside the scope of this guide.

Build prerequisites: Install gcc-avr, avr-libc, binutils-avr, libusb-1.0-0-dev, and pkg-config before running make.

Platform Compatibility

Linux

Works out of the box as a USB HID media control device. Desktop environments map it immediately to system volume and mute. Good fit for Ubuntu/Debian desktops, Arch with Wayland or X11, and Raspberry Pi media boxes.

Windows

Also works without drivers as a standard media-control device. If you briefly see "USB device not recognized" right after plugging in, that is the short Micronucleus bootloader window before the firmware enumerates. After handoff, the knob works normally.

Android

Works on Android devices that support USB OTG and HID media keys. You need a USB-C OTG adapter (or Micro-USB OTG on older phones) and OTG host support enabled on the device.

Android caveats: Behaviour can vary by OEM/ROM. Some devices only react when the screen is unlocked, and mute handling may differ across apps.

Troubleshooting

  • Build fails with missing AVR tools — Install the prerequisites listed in the Build and Flash section above.
  • Linux error -71 during USB enumeration — Reflash or repair the bootloader. See the repository troubleshooting section.
  • No response to rotation — Check CLK/DT wiring first (most common issue), then confirm the encoder module GND and 5V connections.

Going Further

The firmware is intentionally simple and stable, but the hardware supports extensions:

  • Multi-mode knob (volume / media transport / brightness)
  • Long-press and double-click actions
  • Mode indicator LED
  • Additional HID report descriptors

Start with a practical tool, then evolve it into a custom desktop controller.

Tuesday, February 17, 2026

VMBOX: Deliver Web Apps as Self-Contained Virtual Machines

VMBOX packages web applications and runtime dependencies into a self-contained VirtualBox VM. Teams can deliver internal tools as a portable OVA artifact with browser-first access, reducing per-app EXE/MSI/DEB installation work on managed endpoints.

Last updated: February 18, 2026

The Problem

If you've ever tried to deploy a custom tool on managed Windows laptops, you know the pain. Installing Python, setting up dependencies, dealing with Group Policy restrictions, getting IT approval for a new .msi — it all takes longer than writing the tool itself.

Container workflows can also solve packaging, but they often require Docker/Desktop approval, daemon operation, and additional endpoint permissions. In tightly managed enterprise environments, a VM artifact is often easier to deploy and support.

VMBOX takes a different approach. It wraps the full application stack — OS, runtime, dependencies, and web UI — into a single VirtualBox image. When VirtualBox is available, users can import an .ova, start the VM, and access the tool in a browser with predictable setup steps.

What is VMBOX?

VMBOX is a build system for generating minimal Alpine Linux-based VirtualBox images. Reference builds are lightweight (often around ~150MB compressed), boot quickly on modern hardware, and expose functionality through browser-accessible web interfaces without requiring a full desktop environment.

At its core, VMBOX provides:

  • Immutable root filesystem — SquashFS-based read-only rootfs with OverlayFS for runtime changes
  • Persistent data partition — Separate ext4 partition for user data and configurations
  • Optional APP partition — A dedicated read-only SquashFS partition for deploying custom web apps and services
  • Factory reset — One-click reset that restores the system to its original state without reimporting the OVA
  • System management dashboard — Built-in web UI for monitoring CPU, memory, disk, network, and managing applications
  • Cross-platform portability — Export as OVA for use on Windows, macOS, or Linux

System Architecture

VMBOX uses a multi-partition disk layout designed for reliability and easy updates:

VMBOX system architecture showing 4-partition layout: BOOT, ROOTFS, DATA, and APP partitions with OverlayFS merge

VMBOX disk layout: BOOT (FAT32) loads the kernel, ROOTFS (SquashFS) holds the immutable Alpine system, DATA (ext4) stores persistent state via OverlayFS, and APP (SquashFS) contains custom applications.

The BOOT partition contains the Syslinux bootloader, kernel, and initramfs. The ROOTFS partition is a read-only SquashFS image of Alpine Linux with all base services. The DATA partition provides persistent read-write storage — it holds the OverlayFS upper layer, user home directories, and application data. The optional APP partition is another read-only SquashFS image containing your custom web applications, mounted at /app.

During boot, the initramfs merges the read-only ROOTFS with the read-write DATA partition using OverlayFS. This means the system always has a clean base to fall back to — a factory reset simply wipes the overlay, and on the next reboot you're back to a pristine state.

App Delivery as a Single Artifact

The core idea behind VMBOX is that deploying a web application should not require each end user to install and maintain app-specific host runtimes. Compare a traditional rollout with VMBOX:

Traditional Deployment VMBOX Deployment
Install Python/Node runtime
Install dependencies
Configure environment
Deal with OS-specific issues
Navigate endpoint policy approvals
Write platform-specific installers
Import .ova file
Start VM
Open browser to localhost:8000
Done.

This works for any application that can be accessed through a browser: business dashboards, LLM-powered tools, internal APIs, operational utilities, and optional hardware-facing interfaces. Any web framework/runtime that fits your packaging flow can be delivered as a VMBOX image.

Compared with container-first distribution, VMBOX trades daemon/image orchestration for a portable VM artifact and browser-based access. The operating model is straightforward: import, start, and connect.

System Management Dashboard

Every VMBOX image ships with a built-in system management web UI at http://localhost:8000. After boot, sign in (reference builds use admin/brb0x) and change the password on first use. The dashboard provides real-time monitoring and control without requiring SSH for routine operations:

VMBOX System Management Dashboard showing CPU, memory, disk gauges, network stats, applications panel, and log viewer

The System Management Dashboard: real-time CPU, memory, and disk monitoring, application status, log viewer, and system actions — all accessible from the browser.

The dashboard uses Server-Sent Events for 1-second live updates and includes:

  • CPU / Memory / Disk gauges with visual progress bars
  • Network statistics — real-time RX/TX traffic
  • Applications panel — status and control of all apps from the APP partition
  • Log viewer — search, filter, clear, and download logs
  • System actions — change password, reboot, factory reset

Optional: USB Passthrough for Embedded/Hardware Workflows

For embedded and hardware teams, VMBOX can optionally enable VirtualBox USB passthrough with automatic device filters. This allows selected USB devices to be forwarded to the VM for serial, ADB, or CAN workflows when host policy permits:

  • FTDI FT232/FT2232 (VID 0403) — common serial adapters
  • Silicon Labs CP210x (VID 10C4) — USB-to-UART bridges
  • WCH CH340/CH341 (VID 1A86) — budget serial adapters
  • Prolific PL2303 (VID 067B) — serial adapters
  • PCAN-USB (VID 0C72) — CAN bus adapters (optional)
  • Arduino boards (VID 2341) — development boards

When passthrough is enabled, a compatible USB adapter can appear inside the VM within seconds. Combined with a web-based terminal or device UI packaged in APP, teams can access hardware workflows through the browser without installing per-tool UI apps on each host.

Note: USB 2.0/3.0 passthrough requires the VirtualBox Extension Pack; USB 1.1 works without it.

Remote Collaboration via VPN

VMBOX can be paired with an approved VPN or internal network path (for example WireGuard, Tailscale, or enterprise VPN) to enable remote collaboration. Once the VM is reachable, colleagues can access web-based tools through a browser without local app installation.

This supports distributed teams and shared lab resources: one engineer can host the VM near equipment, while others access dashboards and tools remotely in scheduled sessions.

Getting Started

Building a VMBOX image requires a Linux host with standard tools (parted, squashfs-tools, syslinux, virtualbox). The example below builds a demo image with two bundled apps (hello-world and web-terminal):

  1. Clone the repository
    git clone https://github.com/hackboxguy/vmbox.git
    cd vmbox
  2. Build the base rootfs
    sudo ./build.sh --mode=base --output=/tmp/alpine-build --version=1.0.1
  3. Build the APP partition
    sudo ./scripts/build-app-partition.sh \
      --packages=configs/hello-web-terminal-package.txt \
      --output=/tmp/alpine-build/app \
      --rootfs=/tmp/alpine-build/rootfs
  4. Create disk image with APP partition
    sudo ./scripts/03-create-image.sh \
      --rootfs=/tmp/alpine-build/rootfs \
      --output=/tmp/alpine-build \
      --ospart=600M \
      --datapart=200M \
      --apppart=300M \
      --appdir=/tmp/alpine-build/app/app
  5. Fix ownership of build output
    sudo chown -R $(id -u):$(id -g) /tmp/alpine-build
  6. Convert to VirtualBox VM
    ./scripts/04-convert-to-vbox.sh \
      --input=/tmp/alpine-build/alpine-vbox.raw \
      --vmname=vmbox-hello-webterm-demo \
      --appdir=/tmp/alpine-build/app/app \
      --force \
      --memory=1024
  7. Start the VM on Linux
    VBoxManage startvm "vmbox-hello-webterm-demo" --type headless
  8. Or export as OVA for distribution
    VBoxManage export "vmbox-hello-webterm-demo" -o "vmbox-hello-webterm-demo.ova"

After boot completes (typically ~30-60 seconds depending on host resources), open http://localhost:8000 to access the System Management Dashboard.

Tip: Add --serial to step 6 to see boot messages in the terminal. To package your own apps, create a custom package list and pass it to build-app-partition.sh in step 3. See the repository README for the full build guide and the VM App Design Guide for creating custom web apps with the recommended structure and UI/UX style to integrate seamlessly with the VMBOX framework.

Use Cases

  • Internal tool distribution — Package web dashboards, APIs, and line-of-business tools as portable VMs
  • Enterprise self-hosted apps — Deliver browser-based workflows without per-user host dependency setup
  • LLM-powered applications — Deliver AI-driven tools as self-contained VMs that run locally without cloud dependencies
  • Lab equipment interfaces — Browser-based control panels for test setups shared across teams
  • Optional embedded/hardware workspaces — Web-based serial terminals, CAN tools, and device management where USB passthrough is enabled
  • Training and demos — Hand out OVA files that work identically on every machine

SOURCE CODE

github.com/hackboxguy/vmbox — build system, rootfs overlay, system management UI, and example apps

Saturday, February 07, 2026

One Cable, Many Screens: A Self-Hosting PoE Raspberry Pi 4 Infotainment System

This is version 2 of my multi-screen Raspberry Pi infotainment project. The first version (DIY In-Car Infotainment) required a separate pocket router for DHCP, DNS, and DLNA. This version eliminates that dependency — one prebuilt SD card image works for all terminals, and the system configures itself automatically at boot.

Last updated: February 9, 2026

What's New in v2.1

  • Touch-friendly OSD controls — New "Sync" and "Stop All" buttons in Kodi's video player OSD. Tap the screen to show controls, tap Sync to synchronize all screens.
  • Master-only visibility — OSD sync buttons automatically hide on slave devices (only visible on master with USB mounted).
  • Keyboard shortcut — Press 'S' during video playback to trigger sync immediately.
  • No startup prompts — Pre-configured Addons database eliminates "Do you want to enable this addon?" popups.
  • Accurate device count — Fixed duplicate localhost counting (shows correct 3/3 instead of 4/4).
  • Minimal dual-screen setup — Just two Pi4s connected with a direct Ethernet cable — no PoE switch needed for small deployments.

v2.0 features: Self-hosted DHCP/DNS/NTP/DLNA on master Pi, automatic master election via USB detection, one SD card image for all terminals.

Minimal Dual-Screen Setup

For a quick two-screen deployment, you don't need a PoE switch — just connect two Pi4s directly with an Ethernet cable:

Minimal dual-screen setup: two Raspberry Pi 4 terminals connected directly with an Ethernet cable, master with USB storage

Minimal setup: Two Pi4s connected directly via Ethernet. The Pi with USB storage becomes master automatically.

What you need:

  • 2× Raspberry Pi 4 with touch displays
  • 2× MicroSD cards (same image on both)
  • 1× Ethernet cable (any length, crossover not required)
  • 1× USB storage with media files
  • 2× Power supplies (5V/3A each)

How it works:

  1. Download the pre-built SD card image (v2.1) and flash it to both cards using balenaEtcher or Rufus
  2. Connect the two Pi4s with a standard Ethernet cable
  3. Attach USB storage to one Pi (this becomes the master)
  4. Power on both — master provides DHCP, DLNA, and NTP to the slave
  5. Both terminals launch Kodi and show the DLNA media library

From here, use the touch-screen OSD controls to sync playback across both screens.

Scaling up? Add a PoE switch for 3+ screens — see Multi-Screen Setup (3+ Screens with PoE Switch) below.

Multi-Screen Setup (3+ Screens with PoE Switch)

Raspberry Pi 4 multi-screen infotainment system setup diagram showing PoE switch, master terminal with USB, and client terminals

System diagram: One master Pi (with USB media) provides DHCP, DNS, NTP, and DLNA to all client terminals via a PoE switch.

A typical deployment uses:

  • 1 master Pi4 terminal (with USB media attached)
  • 3 client Pi4 terminals
  • 1 PoE switch (5-port or larger)

The topology is a pure star connection: every terminal connects directly to the PoE switch via a single Ethernet cable that provides both power and network. No AV matrix or special head-end hardware required.

How It Works

  1. PoE switch powers on
  2. All Pi4 terminals boot from identical SD cards
  3. Each terminal checks for USB storage
  4. The terminal with USB media becomes the master automatically
  5. Master starts DHCP (192.168.8.100-200), DNS, NTP, and DLNA services
  6. Client terminals get their IP address, time sync, and media access from master
  7. All terminals launch Kodi and connect to the DLNA source
  8. Users choose Personal Mode or Sync Mode

Two Operating Modes

Personal Mode

Each user gets their own screen and audio path:

  • Analog headset via 3.5mm jack, or
  • Bluetooth headset

This feels similar to in-flight seatback entertainment. Each passenger independently browses the DLNA media library in Kodi and plays whatever they want.

Sync Mode

When shared viewing is needed, the master terminal can synchronize all clients using touch-screen OSD controls:

  1. Start playing a video on the master (the Pi with USB storage)
  2. Tap the screen (or press any key) to show the OSD
  3. Tap Sync — all screens open the same video at the same position
  4. Tap Stop All — stops playback on all screens simultaneously
Kodi OSD showing custom Media-Mux Sync and Stop All buttons for synchronized multi-screen playback control

Kodi video player OSD on master device showing the custom Sync and Stop All buttons (highlighted). These buttons only appear on the master Pi.

Keyboard shortcut: Press 'S' during video playback to trigger sync immediately without showing the OSD.

Non-touch displays? Connect a mini 3-key USB keyboard to the master. Press KEY_1 to sync, KEY_2 to stop all. The OSD buttons are hidden on slave devices — only the master shows them.

Master audio can feed a central sound system (vehicle speakers, room PA, etc.) for group viewing.

Hardware List

For a 4-terminal setup:

Component Qty Notes
Raspberry Pi 4 (4GB) 4 2GB works but 4GB recommended
PoE HAT 4 Official or compatible 802.3af HAT
MicroSD card (32GB+) 4 Class 10 or faster
Full HD touch display 4 7" to 10" HDMI displays work well
PoE switch 1 5-port minimum, 802.3af/at
Ethernet cables 4 Up to 50m runs supported
USB storage 1 NTFS, FAT32, or ext4 formatted
3-key USB keyboard (optional) 1 Only needed for non-touch displays; touch screens use OSD buttons

Compared to v1, you no longer need the GL-MT300N-V2 pocket router — the master Pi handles all network services.

Real-World Use Cases

In-Car / Fleet Passenger Infotainment

Ideal for vehicles with multiple passengers:

  • Each passenger watches independent content with personal audio
  • One key press switches everyone to synchronized shared playback
  • Master audio routes to vehicle speakers for group viewing

Gives both freedom (personal playback) and coordination (sync playback) in one system.

Multi-Room Shared Viewing

Use case diagram showing multi-room shared viewing with synchronized screens in overflow rooms

Multi-room use case: synchronized playback across overflow rooms, halls, or training centers.

For venues where people are spread across rooms:

  • House of worship overflow rooms
  • Community halls
  • Training centers
  • Small campuses

A single PoE star network keeps wiring simple and operations predictable.

Quick Start

Option 1: Pre-built Image (Recommended)

  1. Download the pre-built SD card image (v2.1) (~1.2GB)
  2. Flash the image to all SD cards using balenaEtcher or Rufus
  3. Insert SD cards into Pi4 terminals
  4. Connect all terminals to PoE switch
  5. Insert USB media (NTFS, FAT32, or ext4) into one terminal
  6. Power on the PoE switch
  7. Wait for all terminals to boot into Kodi

Option 2: Manual Installation

On an existing Raspberry Pi OS Lite installation:

git clone https://github.com/hackboxguy/media-mux.git
cd media-mux
sudo ./setup.sh
# System reboots after base installation

# After reboot, login again and run:
cd media-mux
sudo ./setup-selfhosted.sh
sudo reboot

Troubleshooting

DLNA source shows "Couldn't connect to network server"

  • Check if master terminal has USB media attached
  • Verify minidlna is running: pgrep -f minidlnad
  • Check master log: cat /var/log/media-mux-selfhosted.log
  • Ensure USB is mounted: mount | grep /media/usb

Client terminal not getting IP address

  • Verify master booted first and has USB attached
  • Check dnsmasq is running on master: systemctl status dnsmasq
  • Try rebooting the client terminal

Time is wrong on client terminals

  • Wait a few minutes after boot for NTP sync
  • Check chrony status: chronyc sources
  • Verify master chrony is running: pgrep -f chronyd

Sync playback not working

  • Ensure you are triggering sync from the master (the Pi with USB storage)
  • Touch screen: Tap screen to show OSD, tap Sync button
  • Keyboard: Press 'S' during playback, or KEY_1 on 3-key keyboard
  • Check kodisync log on master: cat /var/log/kodisync.log
  • Verify all clients are on the same network (192.168.8.x)

OSD Sync/Stop buttons not visible

  • Buttons only appear on the master (Pi with USB storage attached)
  • Slave devices do not show these buttons by design
  • If master doesn't show buttons, verify USB is mounted: mount | grep /media/usb

USB media not detected

  • Supported formats: NTFS, FAT32, ext4
  • Check dmesg for USB detection: dmesg | grep -i usb
  • Try a different USB port or cable

Current Limitations

The system works reliably for practical deployments, but there are areas for future improvement:

  • No automatic master failover if master is disconnected
  • No web dashboard for status monitoring
  • Role is determined by USB presence (no manual pinning)

SOURCE CODE

github.com/hackboxguy/media-mux — pre-built images and release notes in Releases section