From 25dbf687707216265386fce6f0e88f1cf47825f1 Mon Sep 17 00:00:00 2001 From: happyleaves Date: Tue, 16 Feb 2016 17:44:48 -0500 Subject: [PATCH] snapcast blog --- ...15-multi-room-audio-with-snapcast.markdown | 137 ++++++++++++++++++ .../images/blog/2016-02-snapcast/diagram.png | Bin 0 -> 24336 bytes 2 files changed, 137 insertions(+) create mode 100644 source/_posts/2016-02-15-multi-room-audio-with-snapcast.markdown create mode 100644 source/images/blog/2016-02-snapcast/diagram.png diff --git a/source/_posts/2016-02-15-multi-room-audio-with-snapcast.markdown b/source/_posts/2016-02-15-multi-room-audio-with-snapcast.markdown new file mode 100644 index 00000000000..ca8118aa481 --- /dev/null +++ b/source/_posts/2016-02-15-multi-room-audio-with-snapcast.markdown @@ -0,0 +1,137 @@ +--- +layout: post +title: "Multi-room audio with Snapcast, Mopidy, and Home Assistant" +date: 2016-02-15 17:10:56 -0500 +author: happyleavesaoc +comments: true +categories: How-To +--- + +Multi-room audio can be achieved by having a computer attached to speakers in every room. On each computer, services run to play and/or control the audio. With this DIY approach, the kind of computer and speakers is very much up to you. It could be your desktop computer with attached powered speakers, your HTPC hooked up to your TV and receiver, a Raspberry Pi with Amp or DAC, or even an Android device. + +You'll need two key software packages, besides Home Assistant. The first is [Mopidy](https://www.mopidy.com/), a music server that can play local files, or connect to streaming music services like Spotify. The second is [Snapcast](https://github.com/badaix/snapcast/), which enables synchronized audio streaming across your network. Both can be integrated into Home Assistant. Each room audio device will run an instance of the Snapcast client, and optionally a Mopidy instance. Your server will run a special instance of Mopidy and the Snapcast server. + +Finally, you also need a player to control Mopidy. Any MPD-compatible player will work, and there are several [Mopidy-only web-based options](https://docs.mopidy.com/en/latest/ext/web/#ext-web) available. On Android, [Remotedy](https://play.google.com/store/apps/details?id=se.anil.remotedy) is particularly nice since you can access multiple Mopidy instances in one place. + +Home Assistant will provide device status, and volume control for each room. If you want to play music in all your rooms (on all your clients), access the server instance of Mopidy. If you want to play music only in a specific room, access that specific Mopidy instance. If you're using a web UI for Mopidy, you can add links to each instance in Home Assistant with the [weblink] component. + +

+ +

+ + + +## Staging + +- [Install](https://www.mopidy.com/) Mopidy (2.0.0 or greater) +- [Download](https://github.com/badaix/snapcast/releases/) and [Install](https://github.com/badaix/snapcast/tree/v0.5.0-beta-1#installation) Snapcast (0.5.0 or greater) + +## Configure Mopidy + +Mopidy can be run with multiple configuration files, each extending the previous file. This is helpful when we're running multiple instances with varying functionality. + + +### core.conf +The core configuration is shared between all instances: + +```conf +[mpd] +hostname = :: + +[http] +hostname = :: + +[audio] +output = alsasink + +[spotify] +username = +password = +``` + +### local.conf +Add the local configuration on computers that have local media files: + +```conf +[local] +media_dir = +``` + +### snapcast.conf +Finally, the Mopidy instance that connects with Snapcast needs special configuration. Run on a different port to avoid conflicts if you have a second Mopidy instance running on your computer. The audio output is sent to a named pipe - Snapcast will read from there. Note that you may have to adjust the audio output attribute depending on your system and audio sources. + +```conf +[mpd] +hostname = :: +port = 6601 + +[http] +hostname = :: +port = 6681 + +[audio] +output = audioconvert ! audioresample ! audio/x-raw, rate=48000 ! filesink location=/tmp/snapfifo +``` + +## Run Mopidy + +To run a room-specific instance: + +```bash +$ mopidy --config $CONF_DIR/core.conf +``` + +To run a room-specific instance with local media: + +```bash +$ mopidy --config $CONF_DIR/core.conf:$CONF_DIR/local.conf +``` + +To run the special Snapcast-connected instance (with local media): + +```bash +$ mopidy --config $CONF_DIR/core.conf:$CONF_DIR/local.conf:$CONF_DIR/snapcast.conf +``` + +## Run Snapcast + +Start the `snapserver` on the same server running Mopidy with the snapcast configuration. + +```bash +$ snapserver # or use systemd +``` + +Start the `snapclient` on computers that will be playing audio. + +```bash +$ snapclient # or use systemd, add -h if necessary +``` + +## Configure Snapcast + +There are a number of snapcast configuration options, but the one relevant to Home Assistant is the client names. You can set them in the snapserver configuration file, by default located at `~/.config/Snapcast/settings.json`. Only edit this file while the `snapserver` is not running. Modify the `name` JSON value to your liking - this is how the client will be named in Home Assistant. + +## Configure Home Assistant + +Use the [mpd] and [snapcast] components. Optionally, use [weblink] to provide easy access to a Mopidy web UI. + +```yaml +media_player: +- platform: snapcast + host: xxxxx +- platform: mpd + server: xxxx + location: Multi-Room Controller +- platform: mpd + server: xxx + location: Room 1 + +weblink: + entities: + - name: Multi-Room Player + url: xxxx +``` + +[weblink]: /components/weblink/ +[snapcast]: /components/media_player.snapcast/ +[mpd]: /components/media_player.mpd/ diff --git a/source/images/blog/2016-02-snapcast/diagram.png b/source/images/blog/2016-02-snapcast/diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..fa894caae45861c8c6e2f6d3f30a6bc6eaaa5073 GIT binary patch literal 24336 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 literal 0 HcmV?d00001