Homebridge plugin for Sonos ZonePlayer
Copyright © 2016-2019 Erik Baauw. All rights reserved.
- Automatic discovery of Sonos zones, taking into account stereo pairs and home theatre setup;
- Support for Sonos groups, created through the Sonos app;
- Control from HomeKit of play/pause, volume, and mute per Sonos group;
- Optional control from HomeKit of volume, mute, bass, treble, and loudness per Sonos zone;
- Optional control from HomeKit for Sonos zones leaving Sonos groups, and for Sonos zones creating/joining one Sonos group;
- Real-time monitoring from HomeKit of play/pause state, volume, mute, current track, and coordinator per Sonos Group; and, optionally, of volume, mute, bass, treble, loudness per Sonos zone. Like the Sonos app, homebridge-zp subscribes to ZonePlayer events to receive notifications;
- Optional control from HomeKit for the status LED. Note that Sonos doesn't support events for the status LED, so homebridge-zp cannot provide real-time monitoring for this;
You need a server to run homebridge. This can be anything running Node.js: from a Raspberri Pi, a NAS system, or an always-on PC running Linux, macOS, or Windows. See the homebridge Wiki for details. I use a Mac mini server, and, occasionally, a Raspberri Pi 3 model B.
To interact with HomeKit, you need Siri or a HomeKit app on an iPhone, Apple Watch, iPad, iPod Touch, or Apple TV (4th generation or later). I recommend to use the latest released versions of iOS, watchOS, and tvOS. Please note that Siri and even Apple's Home app still provide only limited HomeKit support. To use the full features of homebridge-zp, you might want to check out some other HomeKit apps, like Elgato's Eve app (free) or Matthias Hochgatterer's Home app (paid). For HomeKit automation, you need to setup an Apple TV (4th generation or later) or iPad as Home Hub.
The homebridge-zp plugin creates an accessory per Sonos zone, named after the zone, e.g. Living Room Sonos for the Living Room zone. By default, this accessory contains a single
Switch service, with the same name as the accessory. In addition to the standard
Power State characteristic for play/pause control, additional characteristics are provided for
Current Track (read-only) and
Sonos Group (read-only). Note that
Current Track and
Sonos Group are custom characteristics. They might not be supported by all HomeKit apps, see Caveats.
Note that neither Siri nor the Apple's Home app support
Mute, even thought these are standard HomeKit characteristics. Because of this, the type of the service, as well as the type of characteristic used for volume can be changed from
config.json, see Configuration and issue #10.
When multiple Sonos zones, e.g. Living Room and Kitchen, are grouped into one Sonos group, the Sonos app shows them as a single room, e.g. Living Room + 1, with shared control for play/pause, music source, and (group) volume and mute. When this group is broken, each zone forms a separate standalone group, containing only that zone. The Sonos app shows each standalone group as a separate room, with separate control per room for play/pause, music source, and (zone) volume and mute.
If we would mimic this behaviour in homebridge-zp, dynamically creating and deleting accessories for groups, HomeKit would lose the assignment to HomeKit rooms, scenes and triggers, every time an accessory is deleted. Consequently, you would have to reconfigure HomeKit each time you group or ungroup Sonos zones.
To overcome this, homebridge-zp creates an accessory and corresponding service for each Sonos zone. This service actually controls the Sonos group the zone is in rather than the zone. When separated, the Living Room Sonos service controls the standalone Living Room group, consisting of only the Living Room zone; and the Kitchen Sonos service controls the standalone Kitchen group, consisting of only the Kitchen zone. When grouped, both the Living Room Sonos service and the Kitchen Sonos service control the multi-zone Living Room + 1 group, containing both the Living Room and Kitchen zones. The
Sonos Group characteristic shows which group the zone belongs to, or rather: the name of the group coordinator zone, in this example: Living Room.
So when grouped, changing the Living Room Sonos
Volume changes the volume of both the Living Room zone and the Kitchen zone. So does changing the Kitchen Sonos
Volume. When ungrouped, changing the Living Room Sonos
Volume only changes the volume of the Living Room zone; and changing the Kitchen Sonos
Volume only changes the volume of the Kitchen zone.
Changing in HomeKit the volume of an individual zones in a multi-zone group requires an additional
Volume characteristic for the zone, next to the
Volume characteristic for the group. As HomeKit doesn't support multiple characteristics of the same type per service, it actually requires an additional service. By specifying
"speakers": true in
config.json, homebridge-zp creates an additional Speakers service for each zone accessory, to control the individual zone. This service is named after the zone as well, in our example: Living Room Speakers.
Like the Sonos service, the type of the Speakers service can be changed in
config.json from the default
Switch. The Speakers service
Power On characteristic is used to create, join, or leave a Sonos group. Additional characteristics for
Loudness control the corresponding zone attributes.
Loudness are custom characteristics. They might not be supported by all HomeKit apps, see Caveats below.
When grouping zones from the Sonos app, homebridge-zp sets the Speakers
On characteristic for a zone in a multi-zone group and clears it for a zone in a standalone group. When setting the Speakers
On from HomeKit, that zone will join the (first) existing multi-zone Sonos group. When no multi-zone Sonos group yet exists, the zone is designated as coordinator for a future multi-zone group. When
On is cleared from HomeKit, the zone leaves its current group, forming a standalone group. Note that when the coordinator leaves the group, the music to the other zones in that group is briefly interrupted, as the new coordinator assumes its role.
The homebridge-zp plugin obviously needs homebridge, which, in turn needs Node.js. I've followed these steps to set it up on my macOS server:
- Install the latest v10 LTS version of Node.js. On a Raspberry Pi, use the 10.x Debian package. On other platforms, download the 10.x.x LTS installer. Both installations include the
- On macOS, make sure
/usr/local/binis in your
npm, and, later,
homebridgeinstall there. On a Raspberry Pi, these install to
- You might want to update
sudo npm -g update npm@latest;
- Install homebridge through
sudo npm -g install homebridge --unsafe-perm. Follow the instructions on GitHub to create a
~/.homebridge, as described;
- Install the homebridge-zp plugin through
sudo npm -g install homebridge-zp;
~/.homebridge/config.jsonand add the
ZPplatform provided by homebridge-zp, see Configuration.
Once homebridge is up and running with the homebridge-zp plugin, you might want to daemonise it and start it automatically on login or system boot. See the homebridge Wiki for more info how to do that on MacOS or on a Raspberri Pi.
config.json you need to specify a platform for homebridge-zp:
The following optional parameters can be added to modify homebridge-zp's behaviour:
||Flag whether to expose an additional service per Sonos alarm.|
||Flag whether to expose volume as
||Flag whether to expose an additional Lightbulb service per zone for the status LED.|
||(discovered)||The hostname or IP address for the web server homebridge-zp creates to receive notifications from Sonos ZonePlayers. This must be the hostname or IP address of the server running homebridge-zp, reachable by the ZonePlayers. You might need to set this on a multi-homed server, if homebridge-zp binds to the wrong network interface.|
||The port for the web server homebridge-zp creates to receive notifications from Sonos ZonePlayers.|
||The timeout (in seconds) to wait for a response when searching for Sonos Zoneplayers.|
||Defines what type of service and volume characteristic homebridge-zp uses. Possible values are:
||Flag whether to expose a second Speakers service per zone, in addition to the standard Sonos service, see Speakers. You might want to set this if you're using Sonos groups in a configuration of multiple Sonos zones.|
||The duration (in minutes) of the subscriptions homebridge-zp creates with each ZonePlayer.|
||The name scheme for the HomeKit accessories.
Below is an example
config.json that exposes the Sonos and Speakers service as a HomeKit
Speaker and volume as
Brightness, so it can be controlled from Siri:
If you run into issues, please run homebridge with only the homebridge-zp plugin enabled in
config.json. This way, you can determine whether the issue is related to the homebridge-zp plugin itself, or to the interaction of multiple homebridge plugins in your setup. Note that disabling the other plugins from your existing homebridge setup will remove their accessories from HomeKit. You will need to re-assign these accessories to any HomeKit rooms, groups, scenes, and rules after re-enabling their plugins. Alternatively, you can start a different instance of homebridge just for homebridge-zp, on a different system, or from a different directory (specified by the
-U flag). Make sure to use a different homebridge
username, and (if running on the same system)
port in the
config.json for each instance.
The homebridge-zp plugin outputs an info message for each HomeKit characteristic value it sets and for each HomeKit characteristic value change notification it receives. When homebridge is started with
-D, homebridge-zp outputs a debug message for each request it makes to a Sonos ZonePlayer and for each ZonePlayer notification event it receives. To capture these messages into a logfile, start homebridge as
homebridge -D > logfile 2>&1.
For each zone found, the homebridge-zp plugin logs a debug message with the zone name and the type, ID and IP address and port of the corresponding ZonePlayer, e.g.
[2018-9-28 12:35:47] [ZP] Living Room: setup ZPS9 v9.1 player RINCON_5CAAFDxxxxxx01400 at 192.168.76.71:1400
Like the Sonos app, homebridge-zp subscribes to the ZonePlayer events to be notified in real-time of changes. It creates a web server to receive these notifications. The IP address and port number for this listener are logged in a debug message, e.g.
[2018-9-28 12:36:02] [ZP] listening on http://192.168.xxx.xxx:xxxxx/notify
To check whether the listener is reachable from the network, open this URL in your web browser. You should get a reply like:
homebridge-zp v0.2.34, node v8.12.0, homebridge v0.4.45
To make sure homebridge-zp unsubscribes from the ZonePlayers when homebridge exits, it installs a handler for uncaught exceptions, that would otherwise cause homebridge (or rather NodeJS) to crash. The handler displays a message and sends the SIGTERM signal to homebridge, so it can exit cleanly. Note that the uncaught exception is not caused by homebridge-zp, it only handles it. In the example below, the exception is caused by homebridge itself (it cannot start its server, because another instance of homebridge is already running):
[2018-9-28 12:51:42] [ZP] uncaught exception Error: listen EADDRINUSE :::51826 at Server.setupListenHandle [as _listen2] (net.js:1360:14) at listenInCluster (net.js:1401:12) at Server.listen (net.js:1485:7) at EventedHTTPServer.listen (/usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/util/eventedhttp.js:60:19) at HAPServer.listen (/usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/HAPServer.js:158:20) at Bridge.Accessory.publish (/usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/Accessory.js:607:16) at Server._publish (/usr/local/lib/node_modules/homebridge/lib/server.js:128:16) at Server.<anonymous> (/usr/local/lib/node_modules/homebridge/lib/server.js:404:14) at /usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/util/once.js:16:19 at listen (/Users/ebaauw/GitHub/homebridge-zp/lib/ZpPlatform.js:183:14) [2018-9-28 12:51:42] Got SIGTERM, shutting down Homebridge... [2018-9-28 12:51:42] [ZP] cleaning up...
If you need help, please open an issue on GitHub. Please attach a copy of your full
config.json (masking any sensitive info) and the debug logfile.
For questions, you can also post a message to the #homebridge-zp channel of the homebridge workspace on Slack.
The homebridge-zp plugin is a hobby project of mine, provided as-is, with no warranty whatsoever. I've been running it successfully at my home for years, but your mileage might vary. Please report any issues on GitHub.
Homebridge is a great platform, but not really intended for consumers, as it requires command-line interaction.
HomeKit is still relatively new, and Apple's Home app provides only limited support. You might want to check out some other HomeKit apps, like Elgato's Eve (free), Matthias Hochgatterer's Home (paid), or, if you use
Xcode, Apple's HMCatalog example app.
The HomeKit terminology needs some getting used to. An accessory more or less corresponds to a physical device, accessible from your iOS device over WiFi or Bluetooth. A bridge (like homebridge) provides access to multiple bridged accessories. An accessory might provide multiple services. Each service corresponds to a virtual device (like a lightbulb, switch, motion sensor, ...). There is also an accessory information service. Siri interacts with services, not with accessories. A service contains one or more characteristics. A characteristic is like a service attribute, which might be read or written by HomeKit apps. You might want to checkout Apple's HomeKit Accessory Simulator, which is distributed as an additional tool for
The Sonos terminology needs some getting used to. A zone corresponds to a physical room. It consists of a single ZonePlayer, two ZonePlayers configured as a stereo pair, or a home theatre setup (e.g. a PlayBar with separate surround speakers). Typically, zone setup is static; you would only change it when physically re-arranging your ZonePlayers between rooms. A group is a collection of one or more zones, playing the same music in sync. A group is controlled by its coordinator zone. Typically, groups are dynamic, you add and/or remove zones to/from a group when listening to your music. Controls for play/pause and music source act on a group. Controls for volume and mute act on a group or on a zone. Controls for bass, treble, and loudness act on a zone. Note that Sonos uses the term room ambiguously: on the Sonos app main screen it corresponds to a group, but in the Room Settings it corresponds to a zone.