HiFi Control

Date
2026-04-06
Status
Active — in active development
Source
github.com/richardsummerville/hifi-control

A native macOS menu-bar app written in Swift, zero dependencies, that talks directly to specific home AV hardware on the local network. No cloud, no IFTTT, no HomeKit bridge — just WebSocket, HTTP, ADB, SSDP, Wake-on-LAN, and mDNS aimed at five named devices.

It’s deliberately scoped as a personal project exploring what local-network device control feels like when you skip the smart-home middleware. It works for the specific stack listed below; the ROADMAP sketches the path to a configurable, distributable version.

Supported devices

DeviceProtocolOnOffStatus
Cambridge Audio CXN v2StreamMagic WebSocket (SMOIP)power cycleWebSocketlive polling
LG webOS TVSSAP WebSocket + WoLWake-on-LANSSAP turnOffWebSocket registration
NVIDIA ShieldADB over networkwake keyeventsleep keyeventdumpsys power
XboxSSDPunicast probe
Plex Media ServerHTTP APIactive session count

The protocol mix is the interesting part. Each device speaks something different, none of them speak HomeKit, and most are not designed to be controlled from a Mac at all. The app shims them into a single menu-bar surface where toggles and status rows behave consistently.

Features

  • Toggle rows for CXN, TV, and Shield with live state indicators
  • Status rows for Xbox (SSDP) and Plex server (active stream count)
  • Roon session toggle — power-cycles the CXN, launches and quits Roon in a single click
  • Plex session toggle — wakes the Shield and launches Plex on the TV
  • Shield app launcher — a Services submenu with brand icons for 16 streaming/media apps (Netflix, Disney+, Apple TV, Stremio, BBC iPlayer, etc.), launched via ADB intents
  • Plex library scans — Movies / TV / Music scans triggered from the menu
  • Configurable services list — settings sheet to show or hide apps in the Shield submenu
  • mDNS discovery — finds the CXN via Bonjour and resolves the TV’s IP from MAC via ARP, so device addresses survive DHCP changes
  • Launch at Login via the native SMAppService API
  • No dock icon (menu-bar only via LSUIElement)

Build and configuration

swiftc against AppKit and Foundation produces the binary; that gets dropped into a hand-rolled .app bundle. Requires macOS 13+, Swift 5, and adb (for the Shield).

brew install android-platform-tools
cd MenuBarApp
swiftc -o HiFiControl HiFiControl.swift \
  -framework AppKit -framework Foundation -swift-version 5
cp HiFiControl "HiFi Control.app/Contents/MacOS/HiFi Control"

Device IPs, the TV MAC, and the Plex token live in a gitignored config.local file at the project root — never committed, read at launch:

TV_MAC=AA:BB:CC:DD:EE:FF
CXN_IP=192.168.1.x
TV_IP=192.168.1.x
SHIELD_IP=192.168.1.x
XBOX_IP=192.168.1.x
PLEX_IP=192.168.1.x
PLEX_TOKEN=your_plex_token_here

Pairing notes

  • CXN v2 — no pairing; the StreamMagic API is open on the LAN
  • LG webOS TV — accept the prompt on the TV the first time. The app uses the same pairing key lgtv2 writes (~/Library/Preferences/lgtv2/), so a one-time Node helper handles the handshake
  • NVIDIA Shield — enable Network Debugging in Developer Options, accept the ADB authorisation prompt on first connection. After that the app talks to the Shield over TCP 5555

Why a single Swift file

The whole app is one HiFiControl.swift. No package manifest, no Xcode project, no SwiftUI — just NSStatusItem, NSMenu, URLSession, and the relevant network primitives. That decision pays off on a project like this: protocol exploration moves much faster when there’s nothing between you and the wire. Once the surface stabilises, the ROADMAP calls for a proper Swift Package Manager layout, an SwiftUI settings UI, and a configurable device registry — but the single-file shape was the right starting point.

Status

Experimental. It runs reliably for this hardware mix and has been on a daily-driver Mac for some months without rewrites — but device IDs are hard-coded, error handling is “log and shrug” in places, and the configuration model assumes you know your network. The scope question for the next phase is whether to make it a configurable end-user app, a library other people can build their own menus on top of, or a public reference for “how to talk to home AV devices on a local network without the cloud.”