At The Floow we have music playing in the office through some wall-mounted power speakers. We wanted our staff to be able to control what is playing, skip tracks, change volume, etc.
Initially we had Spotify running on a Mac Mini, using a home-made Rails website and some Apple Script commands to control skip, pause, play and volume change but naturally that was not very flexible, or reliable and created a maintenance burden when any new features needed adding.
Mopidy is essentially a music server which supports plugins to add functionality, for example music services like Spotify & Soundcloud but also for control through web interfaces.
We started running Mopidy on a Linux Server with the Music Box web client (of the Pi Musicbox project).
This has served us very well but is not the best use of a Dell server, so to minimise waste (and downtime should we need to tinker with the server) we are moving the Mopidy setup to a Raspberry Pi 2. This post outlines the steps to make that happen...
What You'll Need
- Raspberry Pi 2
- Micro SD Card (ideally 8 GB or larger)
- Another Computer (to download/copy the OS image and ssh)
- A way to read/write the micro SD card on the computer
- Powered Speakers?
I have heard that headphones are not a good way to test volume change etc
- If all goes well you shouldn't need a keyboard or mouse for the Pi!
This guide is based on running Linux on the computer used to prepare the SD card however there are many guides around the web on how to prepare the SD using Mac OS or Windows. Mac is fairly similar, most notably the devices are identified a little differently and you use
diskutil to find and unmount your device before using
Step 1 - Install Raspbian
First download Raspbian Jessie Lite from https://www.raspberrypi.org/downloads/raspbian/ and extract the img file within.
2015-11-21-raspbian-jessie-lite.zip paul@box [09:35:00] [~/Downloads] -> % unzip 2015-11-21-raspbian-jessie-lite.zip Archive: 2015-11-21-raspbian-jessie-lite.zip inflating: 2015-11-21-raspbian-jessie-lite.img
Then 'copy' the image to the SD card. This is done at the block level rather than the file level using the
dd command. This step (usually requiring sudo) is destructive so you need to be sure which device is your SD card - using fdisk one can check.
fdisk -l will list all disks, partitions, sizes. Again sudo is likely required.
fdisk will list entries that look similar to:
Disk /dev/sda: 894.3 GiB, 960197124096 bytes, 1875385008 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 62FB3A67-F01B-4A6A-903A-A5573C2A7E96 Device Start End Sectors Size Type /dev/sda1 2048 1050623 1048576 512M EFI System /dev/sda2 1050624 1808625663 1807575040 861.9G Linux filesystem /dev/sda3 1808625664 1875384319 66758656 31.9G Linux swap
So we can either look for a disk the same size as the SD card, in my case it's
/dev/sde (which already has two partitions in this case):
Disk /dev/sde: 59.5 GiB, 63864569856 bytes, 124735488 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xea0e7380 Device Boot Start End Sectors Size Id Type /dev/sde1 8192 131071 122880 60M c W95 FAT32 (LBA) /dev/sde2 131072 124735487 124604416 59.4G 83 Linux
Or we can check the device list before, and after inserting the device.
paul@box [09:41:17] [~/Downloads] -> % sudo fdisk -l | grep 'Disk /dev/' Disk /dev/sda: 894.3 GiB, 960197124096 bytes, 1875385008 sectors Disk /dev/sdb: 232.9 GiB, 250059350016 bytes, 488397168 sectors Disk /dev/sdc: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors Disk /dev/sdd: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors
paul@box [09:41:21] [~/Downloads] -> % sudo fdisk -l | grep 'Disk /dev/' Disk /dev/sda: 894.3 GiB, 960197124096 bytes, 1875385008 sectors Disk /dev/sdb: 232.9 GiB, 250059350016 bytes, 488397168 sectors Disk /dev/sdc: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors Disk /dev/sdd: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors Disk /dev/sde: 59.5 GiB, 63864569856 bytes, 124735488 sectors
It's quite likely it will come after the last used letter, for example if you last device is
/dev/sdc then it's likely to be
Now that we know the device, copying the data is simple -
paul@box [09:51:19] [~/Downloads] -> % sudo dd if=2015-11-21-raspbian-jessie-lite.img of=/dev/sde bs=1M 1391+0 records in 1391+0 records out 1458569216 bytes (1.5 GB) copied, 93.7754 s, 15.6 MB/s
Now the card should boot Raspbian in the Raspberry Pi 2.
Step 2 - SSH Access
When powering up the Pi with a monitor connected it should boot into Raspbian and tell you it's IP. The Lite version does not boot into a graphical (X) environment so you will be presented with a login prompt.
[TODO: Image Here]
Once you have the IP you should be able to manage it externally:
paul@box [04:54:04] [~] -> % ssh firstname.lastname@example.org The authenticity of host '192.168.1.57 (192.168.1.57)' can't be established. ECDSA key fingerprint is SHA256:2pI1YWSU6pjrr0Q15kriKfuFjgIL4GwnWmDtLY1eyCA. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.1.57' (ECDSA) to the list of known hosts. email@example.com's password: The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. pi@raspberrypi:~ $
The default username is
pi and password is
Step 3 - Configuration & Security
Set the hostname:
sudo vi /etc/hostname
I set it to
It will pick up after a reboot:
pi@musicbox:~ $ hostname musicbox
When running commands like sudo you may see:
sudo: unable to resolve host musicbox
If your hostname does not match a valid DNS entry you'll need to update the
/etc/hosts file. Note the last entry probably read
raspberrypi which I have changed to
127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters 127.0.1.1 musicbox
Add your management user:
pi@raspberrypi:~ $ sudo adduser paul Adding user `paul' ... Adding new group `paul' (1001) ... Adding new user `paul' (1001) with group `paul' ... Creating home directory `/home/paul' ... Copying files from `/etc/skel' ... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for paul Enter the new value, or press ENTER for the default Full Name : Paul Room Number : Work Phone : Home Phone : Other : Is the information correct? [Y/n]
Allow the new user sudo access:
sudo usermod -aG sudo paul
Login as the new user and remove the
paul@musicbox:~ $ sudo userdel pi
Step 4 - Install Mopidy
The steps here are based on the Official Install Guide for Debian.
paul@musicbox:~ $ wget -q -O - https://apt.mopidy.com/mopidy.gpg | sudo apt-key add - OK paul@musicbox:~ $ sudo wget -q -O /etc/apt/sources.list.d/mopidy.list https://apt.mopidy.com/jessie.list paul@musicbox:~ $ sudo apt-get update [ long output removed ] Fetched 9,299 kB in 20s (455 kB/s) Reading package lists... Done paul@musicbox:~ $ sudo apt-get install mopidy [ long output removed ] 0 upgraded, 145 newly installed, 0 to remove and 21 not upgraded. Need to get 39.3 MB of archives. After this operation, 130 MB of additional disk space will be used. Do you want to continue? [Y/n] y [ long output removed ] paul@musicbox:~ $
The install should only take a few minutes - though that depends in part on the speed of your internet connection.
Once complete, install the Spotify plug-in:
paul@musicbox:~ $ sudo apt-get install mopidy-spotify [ long output removed ] 0 upgraded, 7 newly installed, 0 to remove and 21 not upgraded. Need to get 1,141 kB of archives. After this operation, 3,551 kB of additional disk space will be used. Do you want to continue? [Y/n] [ long output removed ] paul@musicbox:~ $
And the last piece to install is the musicbox plug-in. The project's GitHub Page suggests using pip to install - which is generally easier and what I'd recommend:
paul@musicbox:~ $ sudo apt-get install python-pip [ long output removed ] paul@musicbox:~ $ sudo pip install Mopidy-MusicBox-Webclient [ long output removed ] paul@musicbox:~ $
Step 5 - Configuring Mopidy
If you run mopidy without any configuration (in the foreground) you'll likely get output that looks similar to this:
paul@musicbox:~ $ mopidy INFO Starting Mopidy 1.1.1 INFO Loading config from builtin defaults INFO Loading config from command line options INFO Creating dir /home/paul/.cache/mopidy INFO Creating dir /home/paul/.config/mopidy INFO Creating dir /home/paul/.local/share/mopidy INFO Loading config from builtin defaults INFO Loading config from command line options INFO Creating file /home/paul/.config/mopidy/mopidy.conf INFO Initialized /home/paul/.config/mopidy/mopidy.conf with default config INFO Enabled extensions: mpd, http, stream, m3u, softwaremixer, file, musicbox_webclient INFO Disabled extensions: spotify, local WARNING Found local configuration errors, the extension has been automatically disabled: WARNING local/media_dir must be set. WARNING Found spotify configuration errors, the extension has been automatically disabled: WARNING spotify/username must be set. WARNING spotify/password must be set. WARNING Please fix the extension configuration errors or disable the extensions to silence these messages. INFO Starting Mopidy mixer: SoftwareMixer INFO Starting Mopidy audio INFO Starting Mopidy backends: StreamBackend, M3UBackend, FileBackend INFO Creating dir /home/paul/.local/share/mopidy/m3u INFO Loaded 0 M3U playlists from /home/paul/.local/share/mopidy/m3u INFO Audio output set to "autoaudiosink" INFO Starting Mopidy core INFO Starting Mopidy frontends: MpdFrontend, HttpFrontend INFO MPD server running at [::ffff:127.0.0.1]:6600 INFO HTTP server running at [::ffff:127.0.0.1]:6680
The Warnings tell us that Spotify is not configured (and disabled) as is local media (which I'm not bothered about for now).
The configuration for mopidy is stored within
Add the following configuration:
[spotify] username = xxxxx password = xxxxx bitrate = 320 volume_normalization = true
The GitHub Page for the Spotify Plugin lists the configuration options available - as we pay for Premium we might as well have the highest bit rate!
Then we can test by running mopidy in the foreground again, to tell it to use the default config file we use the --config argument, and to avoid changing permissions on the config file it is run using sudo as by default only the mopidy user has access:
paul@musicbox:~ $ sudo mopidy --config /etc/mopidy/mopidy.conf INFO Starting Mopidy 1.1.1 INFO Loading config from builtin defaults INFO Loading config from /etc/mopidy/mopidy.conf INFO Loading config from command line options INFO Enabled extensions: spotify, mpd, http, stream, m3u, softwaremixer, file, musicbox_webclient, local INFO Disabled extensions: none INFO Starting Mopidy mixer: SoftwareMixer INFO Starting Mopidy audio INFO Starting Mopidy backends: SpotifyBackend, StreamBackend, M3UBackend, FileBackend, LocalBackend INFO Creating dir /var/cache/mopidy/spotify INFO Creating dir /var/lib/mopidy/spotify INFO Loaded 0 M3U playlists from /var/lib/mopidy/playlists INFO Audio output set to "autoaudiosink" INFO No local library metadata cache found at /var/lib/mopidy/local/library.json.gz. Please run `mopidy local scan` to index your local music library. If you do not have a local music collection, you can disable the local backend to hide this message. INFO Loaded 0 local tracks using json INFO Starting Mopidy core INFO Starting Mopidy frontends: MpdFrontend, HttpFrontend INFO MPD server running at [::ffff:127.0.0.1]:6600 INFO HTTP server running at [::ffff:127.0.0.1]:6680 INFO Logged in to Spotify in online mode
Now Spotify has logged in.
Note: If you specify bad credentials you will likely get an error like:
ERROR Spotify login error: <ErrorType.BAD_USERNAME_OR_PASSWORD: 6>
While Mopidy started you may have noticed two log entries of interest:
INFO MPD server running at [::ffff:127.0.0.1]:6600 INFO HTTP server running at [::ffff:127.0.0.1]:6680
The MPD server is Mopidy's own API (for which there are various clients).
The HTTP server is where the musicbox web plugin is mounted. As the log line suggests it is bound only to the loopback interface, which can be verified using
paul@musicbox:~ $ sudo lsof -i | grep 6680 mopidy 8993 root 20u IPv4 17770 0t0 TCP localhost:6680 (LISTEN)
This means that right now no clients on the same network as the Pi can access mopidy.
The HTTP Configuration of the Mopidy docs explains the config that can be specified - I changed to the following:
[http] enabled = true hostname = 0.0.0.0 port = 6680 zeroconf = Mopidy HTTP server on $hostname
The Port is unchanged (but I'd rather have it explicity in the config), and it now binds to all interfaces. On restarting Mopidy we should see:
INFO MPD server running at [::ffff:127.0.0.1]:6600 INFO HTTP server running at [::ffff:0.0.0.0]:6680
And if I browse to
http://192.168.1.57:6680/ from another computer on the nextwork I am redirected to
http://192.168.1.57:6680/mopidy/ which presents a page which in turn lets us navigate to MusicBox.
Now we can see if it works.
It doesn't. Upon trying to play a track there is no sound, and the following message shows in the log:
WARNING Element doesn't implement handling of this stream. Please file a bug.
It seems that by default the Pi sends audio out over HDMI, the following command forces it to use the Headphone Jack:
sudo amixer cset numid=3 1
The final argument in the above command is the output:
0=auto 1=analog 2=HDMI
TODO: sudo apt-get install mopidy-spotify mopidy-alsamixer
Additionally, OK AT FULL NOISY LOWER, KNOWN ISSUE - USB
[audio] mixer = alsamixer output = alsasink [alsamixer] card = 0 control = PCM [softwaremixer] enabled = false
Final for USB:
[spotify] username = xxx password = xxx bitrate = 320 volume_normalization = true [http] enabled = true hostname = 0.0.0.0 port = 6680 zeroconf = Mopidy HTTP server on $hostname [audio] mixer = alsamixer output = alsasink device=plughw:1,0 [alsamixer] card = 1 control = PCM [softwaremixer] enabled = false
Step 6 - Automation
Pre clean up (made as root)
sudo rm /var/log/mopidy/mopidy.log
START ON BOOT
sudo dpkg-reconfigure mopidy
Start on boot
- Reboot to test
Once booted you can tail the logs with
tail -f /var/log/mopidy/mopidy.log to check everything is working as expected.
We found at times the service got a bit stuck so we have a cron job to restart it at 7 PM which conveniently also stops the music should anyone forget.
The job is in root's crontab -
sudo nano crontab -e
0 19 * * * /etc/init.d/mopidy restart
Note: The Raspian Jessie Lite image seems to have NTP installed as default so the time syncs regularly.