Skip to content

Commit

Permalink
perf: Complete new sonos2mqtt (#35)
Browse files Browse the repository at this point in the history
* perf: Complete new sonos2mqtt

BREAKING CHANGE: The bridge is completly rewritten.
Some functionality could no longer work, check before
use.

- This new version uses a different sonos library.
- Support for docker (figured out how to fix the network stuff).
- Text-to-speech, finally 🔔
- Much more stable
  • Loading branch information
svrooij committed Dec 22, 2019
1 parent 6a448aa commit bc497ce
Show file tree
Hide file tree
Showing 9 changed files with 6,670 additions and 5,381 deletions.
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
npm-debug.log
.editorconfig
.gitignore
.travis.yml
renovate.json
.github
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules/
node_modules/
.vscode
32 changes: 20 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
language: node_js
cache:
directories:
- ~/.npm
notifications:
email: false

node_js:
- '12'
- '10'
- '8'
after_success:
- npm run semantic-release
- 10
- 13

branches:
except:
- /^v\d+\.\d+\.\d+$/
only:
- "master"

jobs:
include:
# Define the release stage that runs semantic-release
- stage: release
node_js: lts/*
if: branch = master
# Advanced: optionally overwrite your default `script` step to skip the tests
# script: skip
deploy:
provider: script
skip_cleanup: true
script:
- npx semantic-release
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM node:current-alpine
ENV SONOS2MQTT_RUNNING_IN_CONTAINER=true
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 6326
CMD ["node", "./index.js"]
90 changes: 66 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
[![npm](https://img.shields.io/npm/v/sonos2mqtt.svg?style=flat-square)](https://www.npmjs.com/package/sonos2mqtt)
[![travis](https://img.shields.io/travis/svrooij/sonos2mqtt.svg?style=flat-square)](https://travis-ci.org/svrooij/sonos2mqtt)
[![mqtt-smarthome](https://img.shields.io/badge/mqtt-smarthome-blue.svg?style=flat-square)](https://github.com/mqtt-smarthome/mqtt-smarthome)
[![Support me on Patreon][badge_patreon]][patreon]
[![PayPal][badge_paypal_donate]][paypal-donations]
[![Support me on Github][badge_sponsor]][link_sponsor]
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release)

This node.js application is a bridge between the Sonos and a mqtt server. The status of all your sonos devices will be published to mqtt and you can control the sonos speakers over mqtt.
Expand All @@ -13,31 +12,52 @@ It's intended as a building block in heterogenous smart home environments where

Check out the other bridges in the [software list](https://github.com/mqtt-smarthome/mqtt-smarthome/blob/master/Software.md)

## Run in docker

You can run **sonos2mqtt** in docker, but you'll need to remember the following. This library depends on receiving events from your sonos speakers, the events are required. Every setting of this library can also be set with environment variables prefixed with `SONOS2MQTT_`.

1. Create an `.env` file with the following settings.
2. Set the required values.
3. Run `docker run --env-file .env -p 6329:6329 svrooij/sonos2mqtt`

```Shell
# Set the IP of one known sonos speaker (device discovery doesnt always work inside docker.)
SONOS2MQTT_DEVICE=192.168.x.x
# Set the mqtt connection string
SONOS2MQTT_MQTT=mqtt://ip_or_host_of_mqtt
# Set the IP of the docker host (so node-sonos-ts knows where the events should be send to)
SONOS_LISTENER_HOST=192.168.x.x
# Set text-to-speech endpoint (optional)
# SONOS_TTS_ENDPOINT=https://tts.server.com/api/generate
```

## Installation

Using sonos2mqtt is really easy, but it requires at least [Node.js](https://nodejs.org/) v8 or higher, because of it's async usage. (This app is tested against v8 and v9).
Using sonos2mqtt is really easy, but it requires at least [Node.js](https://nodejs.org/) v8 or higher, because of it's async usage. (This app is tested against v10 and v12).

`sudo npm install -g sonos2mqtt`

## Usage

```bash
sonos2mqtt 1.4.4
sonos2mqtt 0.0.0-development
A smarthome bridge between your sonos system and a mqtt server.

Usage: sonos2mqtt [options]

Options:
-v, --verbosity Verbosity level
[choices: "error", "warn", "info", "debug"] [default: "info"]
-n, --name instance name. used as mqtt client id and as prefix
-i, --name instance name. used as mqtt client id and as prefix
for connected topic [default: "sonos"]
-u, --url mqtt broker url. See
--mqtt mqtt broker url. See
https://github.com/mqttjs/MQTT.js#connect-using-a-url
[default: "mqtt://127.0.0.1"]
-d, --publish-distinct Publish distinct track states
[boolean] [default: false]
-h, --help Show help [boolean]
--tts-lang Default TTS language [default: "en-US"]
--device Start with one known IP instead of device discovery.
--version Show version number [boolean]
```

Expand Down Expand Up @@ -76,7 +96,7 @@ The status of each speaker will be published to `sonos/status/speaker_name/subto
* `name` The name of the speaker
* `ts` Timestamp of this message

By default you can subscribe to the following subtopics `state` (retained), `volume` (retained), `muted` (retaind) and `track` (not retained) but if you wish to have separate topics for the track values you can specify the `-d` or `--publish-distinct` parameter and you will get the `artist` `title` `album` and `albumart` topics.
By default you can subscribe to the following subtopics `state` (retained), `volume` (retained), `muted` (retaind) and `track`/`trackUri` (not retained) but if you wish to have separate topics for the track values you can specify the `-d` or `--publish-distinct` parameter and you will get the `artist`, `title`, `album`, `trackUri` and `albumart` topics.

### Controlling sonos

Expand All @@ -98,33 +118,57 @@ Speaker commands:
* `mute` - Mute the volume
* `unmute` - Unmute the volume
* `sleep` (payload requires number) - Set a sleeptimer for x amount of minutes (from payload)
* `notify` - Play a **notification** on this device :tada: (and revert to current state) see [parameters](https://github.com/bencevans/node-sonos/blob/master/docs/sonos.md#sonossonosplaynotificationoptions)
* `queue` - add a song to the queue, payload should be json string or uri. See [parameters](https://github.com/bencevans/node-sonos/blob/master/docs/sonos.md#sonossonosqueueoptions-positioninqueue)
* `setavtransporturi` - See [parameters](https://github.com/bencevans/node-sonos/blob/master/docs/sonos.md#sonossonossetavtransporturioptions)
* `notify` - Play a **notification** on this device :tada: (and revert to current state) see [notifications](#notifications)
* `speak` - Generate text-to-speech file and play as notification :tada: (and revert to current state) see [text-to-speech](#text-to-speech)
* `queue` - add a song to the queue, should be an (sonos supported) uri.
* `setavtransporturi` - Set the current playback uri.
* `joingroup` - Join a group by device name, payload should be a string with the name of the deivce to join.
* `leavegroup` - Leave a group.
* `playmode` - Set the playmode,payload should be *NORMAL*, *REPEAT_ALL*, *SHUFFLE* or *SHUFFLE_NOREPEAT*.
* `command` - One topic for all [commands](https://github.com/svrooij/sonos2mqtt/issues/21). Payload like `{"cmd":"volumeup"}` or `{"cmd":"volume", "val":10}` for commands that need a payload.
* `adv-command` - Same as `command` but sends the command to the Sonos library, see [commands](https://github.com/svrooij/node-sonos-ts#commands)

### Generic commands

There are also some genir commands not tied to a specific speaker. These generic commands should be send to `sonos/cmd/command` like `sonos/cmd/pauseall`.
There are also some generic commands not tied to a specific speaker. These generic commands should be send to `sonos/cmd/command` like `sonos/cmd/pauseall`.

Generic commands:

* `pauseall` - Pause all speakers know to the bridge.
* `pauseall` - Pause all speakers known to the bridge.
* `listalarms` - This will fetch all the current alarms and sends them to `sonos/alarms`.
* `setalarm` - This allows you to set/unset an alarm. Requires json object with `id` and `enabled`
* `notify` - Play a notification on all devices (and revert to current state) see [parameters](https://github.com/bencevans/node-sonos/blob/master/docs/sonos.md#sonossonosplaynotificationoptions)
* `notify` - Play a notification on all devices (and revert to current state) see [notifications](#notifications)

#### Notification sample
#### Notifications

To play a notification on all devices you send the following json string to `sonos/cmd/notify`

```json
{
"uri": "https://archive.org/download/Doorbell_1/doorbell.mp3",
"volume": 10
"trackUri": "https://cdn.smartersoft-group.com/various/pull-bell-short.mp3", // Can be any uri sonos understands
// trackUri: 'https://cdn.smartersoft-group.com/various/someone-at-the-door.mp3', // Cached text-to-speech file.
"onlyWhenPlaying": false, // make sure that it only plays when you're listening to music. So it won't play when you're sleeping.
"timeout": 10, // If the events don't work (to see when it stops playing) or if you turned on a stream, it will revert back after this amount of seconds.
"volume": 8
}
```

#### Text-to-speech

You can have your sonos speaker speak, which is a pretty cool feature. But you'll need some extra work. You'll need a text-to-speech endpoint as described [here](https://github.com/svrooij/node-sonos-ts#text-to-speech). You have two options either host your own [server](https://github.com/svrooij/node-sonos-tts-polly) or become a [sponsor][link_sponsor] and get access to my personal hosted TTS server.

Either way you'll have yourself a text-to-speech endpoint. This can be set in the environment as `SONOS_TTS_ENDPOINT` or you'll have to supply it with every request.

Have a speaker speak by sending the following to `sonos/set/device_name/speak`.

```json
{
"text": "Someone at the front-door", // The text you want spoken.
"endpoint": "https://your.tts.endpoint/api/generate", // Endpoint is required if not set in Environment
"lang": "en-US", // (optional) Specify the language, or set the default in the config.
"gender": "male", // (optional) Specify the gender (see supported voices of endpoint.)
"volume": 50, // (optional) If you want a different volume for the notification
"onlyWhenPlaying": false // (optional) make sure that it only plays when you're listening to music. So it won't play when you're sleeping.
}
```

Expand All @@ -137,19 +181,17 @@ If your want to test this library it's best to create a mqtt server just for tes

If everything works as expected, you should make the app run in the background automatically. Personally I use PM2 for this. And they have a great [guide for this](http://pm2.keymetrics.io/docs/usage/quick-start/).

## Node-sonos
## Node-sonos-ts

This library depends on [node-sonos](https://github.com/bencevans/node-sonos/) that I just completly promistified. All other libraries using node-sonos should also be able to implemented all the nice features included there. Like **notifications** which is the coolest new addition for **sonos2mqtt**!
This library depends on [node-sonos-ts](https://github.com/svrooij/node-sonos-ts/) which I also developed. All other libraries using node-sonos-ts should also be able to implemented all the nice features included there. Like **notifications** or **text-to-speech** which are the coolest new additions for **sonos2mqtt**!

## Beer
## Beer or Coffee

This bridge and [my work](https://github.com/bencevans/node-sonos/pull/195) on the sonos library took me quite some time, so I invite everyone using this bridge to [Buy me a beer](https://svrooij.nl/buy-me-a-beer/).
This bridge and the [sonos package](https://github.com/svrooij/node-sonos-ts) took me a lot of hours to build, so I invite everyone using it to at least have a look at my [Sponsor page](https://github.com/sponsors/svrooij). Even though the sponsoring tiers are montly you can also cancel anytime :wink:

## Special thanks

The latest version of this bridge is inspired on [hue2mqtt.js](https://github.com/hobbyquaker/hue2mqtt.js) by [Sabastian Raff](https://github.com/hobbyquaker). That was a great sample on how to create a globally installed, command-line, something2mqtt bridge.

[badge_paypal_donate]: https://svrooij.nl/badges/paypal_donate.svg
[badge_patreon]: https://svrooij.nl/badges/patreon.svg
[paypal-donations]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=T9XFJYUSPE4SG
[patreon]: https://www.patreon.com/svrooij
[badge_sponsor]: https://img.shields.io/badge/Sponsor-on%20Github-red
[link_sponsor]: https://github.com/sponsors/svrooij
Loading

0 comments on commit bc497ce

Please sign in to comment.