Skip to content

Verification Request: homebridge-sonos-control-pro #1153

Description

@mathiashornbek

Plugin Name

homebridge-sonos-control-pro

Link To GitHub Repo

https://github.com/mathiashornbek/homebridge-sonos-control-pro

Plugin Icon (Optional)

https://raw.githubusercontent.com/mathiashornbek/homebridge-sonos-control-pro/main/docs/icon.png

The plugin does not offer the same nor less functionality than that of any existing verified plugin.

🟢 Yes

The plugin successfully installs and does not start unless it is configured.

🟢 Yes

The plugin does not require the user to run Homebridge in a TTY or with non-standard startup parameters, even for initial configuration.

🟢 Yes

The plugin does not contain any analytics or calls that enable you to track the user.

🟢 Yes

If the plugin needs to write files to disk (cache, keys, etc.), it stores them inside the Homebridge storage directory.

🟢 Yes

The plugin does not throw unhandled exceptions, the plugin must catch and log its own errors.

🟢 Yes

More Information

What it does
Sonos Control Pro turns a multi-room music scene into a single switch in Apple Home. Not a speaker — a scene: who leads, what plays, who joins, who is kept out, and the volume for each room, applied as one press.

The scene is built in a visual editor inside the Homebridge Plugin Settings GUI. Everything in that editor — speakers, favourites, playlists, radio stations, current volumes, current groups — is read live from the household over UPnP. There is not one UUID, IP address or room name for the user to type.

Why it is not another Sonos plugin
I looked at what is already verified before building this. The existing Sonos plugins model speakers: each room becomes an accessory with volume and play/pause, and a few can join or leave a group. That is a different product from this one, and this plugin does not replace it — you would install this one instead of hand-grouping in the Sonos app, not instead of a speaker accessory.

What is here that I could not find in a verified plugin:

  • One press composes the whole house. A single "Start music in a group" action picks the group leader, the source, who joins, who leaves and a volume per speaker, then executes it as an ordered plan: volumes land before anything makes a sound, then the source starts, then grouping, then play modes. A speaker left at 60 % last night cannot startle anyone.

  • "Everyone except…" that maintains itself. A scene is described by shape, not by a list of names. Buy a speaker next month and it is in that scene without the user editing anything. Rename a room in the Sonos app and every affected scene is flagged by name in the UI rather than silently doing less.

  • Targets with live filters. Every action takes a target — all speakers / chosen / all except / the group around X / the leader of X — and then a filter evaluated at press time: whatever they are doing, only those playing right now, only the silent ones, only group leaders. +5 %, only those playing turns up the kitchen without waking the bedroom. This is the piece I most wanted and could not find anywhere.

  • Scenes, not just actions. 30 actions across playback, volume, grouping, sound settings and sequencing (wait, remember state, restore state, run another scene), composed into a list, with an optional condition — is anything playing? is it between 22:00 and 06:00? is the kitchen above 30 %? — and a second branch for when it is not met. Switches can be momentary (runs and turns itself back off) or stateful, where turning it off runs a second list.

  • Templates and backups. Four starter scenes that hydrate themselves from the household on first press, so a new install is working in under a minute. Every save leaves a timestamped backup; the newest 20 are restorable from the UI, and the whole set exports and imports as JSON.

  • An activity log. Every run, step by step, with its duration and the speaker's own answer, so a slow or partial scene can be diagnosed without reading a log file.

Against the criteria
Dynamic platform. api.registerPlatform with configureAccessory; accessories are registered and unregistered as scenes are added and removed, so the switches in Apple Home follow the editor live.

Settings GUI. A custom UI (customUi: true) built on @homebridge/plugin-ui-utils — the only runtime dependency in the package. The Homebridge form itself shows two fields, name and language, because everything else belongs in the editor.

Node.js. engines declares Node 18/20/22/24 and Homebridge ^1.8.0 || ^2.0.0-beta.0. The suite is run on Node 22 and Node 24 in CI on every push.

Installs without configuration. No preinstall, install, postinstall or prepare script, no native module, no bin. With no platform block Homebridge never constructs the class; with a minimal one it starts, finds nothing and says so.

No TTY. Nothing reads process.stdin or process.argv. Initial setup is entirely in the settings GUI.

No analytics. No telemetry, no analytics, no outbound connection of any kind other than SSDP on the local network, port 1400 on the speakers themselves, and 127.0.0.1. The settings page loads no external script, font or stylesheet — everything is local to the plugin. There is no Sonos cloud account and no Sonos SDK: the protocol layer is hand-written and tested against a mock household that speaks real SOAP over real HTTP.

Files on disk. Everything lives under /sonos-control-pro/ — scenes.json, backups/, and a runtime.json holding the port and per-start token for the loopback control API (mode 0600). Nothing is written to config.json, the working directory, /tmp or the home directory, so a bad edit cannot take the bridge down. Writes are atomic and a corrupt file is quarantined rather than fatal.

Errors. Every scene run is wrapped and reported through the plugin's own result object; fan-out uses Promise.allSettled; every setInterval callback catches; the SSDP socket, the loopback server and the SOAP client all carry 'error' listeners; JSON.parse is always guarded. Failures are logged by the plugin, in the user's language, with the speaker's own answer attached.

Testing
npm test # 127 unit and integration tests
npm run test:ui # 100 checks driving the real settings UI in Chromium

Both run in CI on Node 22 and Node 24. The tests exercise the actual protocol rather than a stub: test/mock-sonos.js is a fake Sonos household that speaks real SOAP over real HTTP on loopback, with configurable latency, real queue update IDs, and speakers that can appear mid-run.

The suite is hermetic. It binds only to 127.0.0.1, on ports the operating system hands out, and the SSDP sweep is stubbed everywhere — so running npm test on a network that has real Sonos speakers on it neither finds them nor touches them. A test reads the test files and fails if any of them forgets.

Housekeeping

  • Published to npm as homebridge-sonos-control-pro.

  • Source on GitHub, issues enabled, with bug-report and feature-request templates.

  • MIT licensed.

  • A GitHub release with notes for each version, and a changelog that says what changed and why.

  • English and Danish throughout — the editor, every action, every help text and every line in the Homebridge log. No setting means "follow the machine", falling back to English.

Happy to make any changes the review asks for. Thank you for taking the time.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions