Skip to content

Releases: sonn-audio/node-sonos

v0.3.0

Choose a tag to compare

@rudyberends rudyberends released this 06 Sep 08:06

The S1 backend no longer depends on @svrooij/sonos. It speaks UPnP itself, on top of @sonn-audio/node-upnp.

Why

That package's npm latest is 2.5.0, published in June 2022, and it pins fast-xml-parser 3.19.0 — a line carrying two unpatched advisories (prototype pollution via a tag or attribute name; XMLBuilder CDATA injection) whose fixes exist only in 4.x and 5.x. No range bump could reach them.

What we actually used of it was small: device identity, ZoneGroupState, GetPositionInfo/GetMediaInfo, nine events and six transport commands. All of it is plain UPnP.

What's new

  • Radio now-playing works. Read out of Sonos's own r:streamContent, where dc:title stays fixed on the station name. streamInfo used to always be undefined.
  • Group reshuffles arrive as ZoneGroupTopology events instead of waiting up to 30 s for the poll, which is now only a safety net.
  • Commands are addressed with the coordinator's own host and port from the topology, rather than the port the client was constructed with.
  • npm audit is clean.

Testing

There is no S1 hardware in this loop, so scripts/s1-probe.mjs drives the client against a fake speaker reproducing the wire format — device description, SOAP control, and GENA NOTIFYs carrying the double-escaped DIDL that real firmware sends. It found two real bugs during development. Run it with npm run build && npm run probe:s1.

Breaking changes

  • S1SonosGroup and S1SonosPlayer take (client, seed); the SonosDevice argument is gone.
  • Track metadata on the group's apply* methods is UpnpTrack (lowercase fields), not @svrooij/sonos's Track.

v0.2.4

Choose a tag to compare

@rudyberends rudyberends released this 11 Aug 22:49
fix(websocket): reconnect after the socket dies instead of wedging fo…

v0.2.3

Choose a tag to compare

@rudyberends rudyberends released this 28 Jun 19:02

Move to the @sonn-audio npm scope (formerly @lox-audioserver/node-sonos).

v0.2.2

Choose a tag to compare

@rudyberends rudyberends released this 07 Jun 14:15
fix(websocket): request Sonos subprotocol via ws protocols arg

The S2 WebSocket sent 'Sec-WebSocket-Protocol: v1.api.smartspeaker.audio'
as a raw header. ws only tracks a requested-protocol set when the
subprotocol is passed as the constructor's protocols argument; with the
header form that set is empty, so when Sonos echoes the subprotocol in its
101 response ws aborts with 'Server sent a subprotocol but none was
requested'. The handshake reached 101 but then errored — observed in the
field as 'Failed to connect (upgrade 101 Switching Protocols)', leaving
the state controller in an endless reconnect loop and no external events.

Pass the subprotocol as the protocols argument instead.

Bump 0.2.2.

v0.2.1

Choose a tag to compare

@rudyberends rudyberends released this 07 Jun 14:06
fix(discovery): disable TLS validation on S2 generation probe

detectGeneration probed https://host:1443 with plain undici fetch, which
rejects Sonos S2's self-signed cert (DEPTH_ZERO_SELF_SIGNED_CERT). The
probe then fell through to the S1 branch, and since S2 speakers also serve
the legacy UPnP device description on :1400, every S2 unit was
misclassified as S1 and routed to the SOAP backend instead of the
WebSocket event stream.

Pass the same rejectUnauthorized:false dispatcher that getDiscoveryInfo
and the WebSocket client already use; expose it as an override.

Bump 0.2.1.

v0.2.0

Choose a tag to compare

@rudyberends rudyberends released this 24 May 08:38
docs: update README for S1 support

Fixes the broken `@lox-audioserver/sonos` import example (was missing
the `node-` prefix), and documents the new S1 path: `S1Client`,
`detectGeneration`, the auto-detect pattern, S1-specific options, and
which features are S2-only.

v0.1.4

Choose a tag to compare

@rudyberends rudyberends released this 23 May 12:45
fix: refresh active group on every groups event

handleGroupsEvent only called player.checkActiveGroup() indirectly via
setupGroup for newly added groups. After updates or removals the cached
activeGroup went stale, so player.group could return a stale or null
group and follow-up commands (e.g. resume after pause) were silently
dropped by consumers.

Call checkActiveGroup() once after processing all adds/updates/removals.

Bump to 0.1.4.

v0.1.3

Choose a tag to compare

@rudyberends rudyberends released this 09 May 18:02
Surface WebSocket upgrade failures and discovery info

The WS connect path previously collapsed any handshake failure into a
generic "Failed to connect" error, hiding the HTTP status that the
player returned. Capture the unexpected-response event so the status
code, status message, headers, and body (first 512 bytes) end up in the
logs and in the resulting CannotConnect message. Also log the discovery
result (playerId, householdId, websocketUrl) on success and emit a warn
if the discovery HTTP call itself fails. Bump to 0.1.3.

v0.1.2

Choose a tag to compare

@rudyberends rudyberends released this 07 Jan 15:59
d4084b6
Rename project from lox-sonos-controller to node-sonos

v0.1.1

Choose a tag to compare

@rudyberends rudyberends released this 06 Jan 18:25
965158d
Bump version from 0.1.0 to 0.1.1