OH2 music player software stack advice

Hi all,

Been searching online but struggling to find a concise setup for setting up OH2 as a music controller.

For example, OH2 running on a RPi, from there what is the setup?

  • MPD
  • Bubble UPnP (for playlist sync between devices)
  • Openhome(for playlist sync between devices
  • Linn Kazoo (sexy interface)

This idea is to set up multi-room audio using RPi’s as renderers, and have the rooms available in OH2 in sync, and also to trigger music based on scenes etc…

Does anyone have a working setup of something similar to help get started? E.g. what media server software, what OH2 binding?.. How does it all hang together?

Here is a guide to something similar… http://tech.theswamp.in/post/2013/02/16/setting-up-a-raspberry-pi-powered-headless-media-server-and-nas/. Maybe someone has a similar setup?

Many thanks in advance

Hi,

I’m using squeezeserver to achive this.
Squeezeserver is running on my Synology NAS, but I’ve read somewhere it’s also available for RP. For each room I use either old android phones/cheapest tablets as clients(running Squeezeplayer android app), again client sw for RP should be available. All is accessed via OH/squeezebox addon. I set up a local TTS (real easy install howto in this forum) for voice output (e.g. “Welcome Home”, “Cooking timer finshed”). Once you set up a playlist(which i do with the web app comming with the Sqeezeserver), it is automagically available to all clients. In my sitemaps i make the player controls (Volume, Start, Stop) dynamically visible - e.g. if i press Stop, volume, title, artist and start items become invisible, only play remains. likewise if i press Play, stop, title, artist and volume appear. I plan on expanding this to next/prev and so on during the comming looong winter evenings :slight_smile:
starting/stopping playback for scenes, alarm clocks and so on can be achived using rules.
All in all i think there’s no cheaper way to get stereo multiroom audio.
Hope this gives you some ideas,
Regards,
-OLI

+1 on the above.

piCorePlayer is the client that runs on the Pi “renderers.” With this you’ll get analog outputs. If you need digital output, there are daughter boards available.

The Logitech Media Server Debian package also will run on a Pi.

Sound advice guys (excuse the pun)

I’m going to give this a try. Similar to @Oli above I’m going to run the server on a NAS (only on the Pi now since I’m away from home).

This will also be a great introduction to dynamic control, thanks for the idea :slight_smile:

So I will install Squeezeserver on the Pi for now. One thing… is Squeezeserver now Logitech Media Server? Are they the same thing?

Yeah it’s the same. Best of luck setting things up…

You might want to look at the still very active “official” forum for loads of information at http://forums.slimdevices.com/

You can get the latest builds from http://downloads.slimdevices.com/nightly/index.php?ver=7.9

(for Pi you will want the Debian All package… though I am not sure why the “All” version but that is what i had in my notes, so there would have been a reason at the time)

Installing Logitech Media Server

Just in case it is of any use (and while I have my notes up) here are my notes on installing LMS.

Note: that you should know what you are doing and I take no responsibility if anything goes wrong, use at your own risk.

First you download the file to your Pi. You can do this through the command line, first right click the file on the downloads page above and copy the link address. Or download on a different computer and copy it over with FTP.

Then on your Pi

wget http://downloads.slimdevices.com/nightly/7.9/thenwhateverthefilenameis.deb

To install

sudo dpkg -i logitechmediaserver_7.whateveryourversionnumberis_all.deb

To start/stop/restart/status the service

sudo service logitechmediaserver start
sudo service logitechmediaserver stop
sudo service logitechmediaserver restart
sudo service logitechmediaserver status

You can view the interface using port 9000 at your Pi ip address

e.g. http://192.168.1.123:9000

It does take a little while to load, use the status command above to check if it is running.

I should have my QNAP NAS set up in a week or so and then I’ll install Logitech Media Server on it and create renderers using piCorePlayer as mentioned by @mhilbush above. Alternatively I’ll use a dedicated Pi for the LMS and just use the NAS as network share to store the music, not sure what would be the easiest.

@sam, thank you for the step-by-step, it’s very useful :slight_smile: On the QNAP I think I’ll also use the Debian All package and see if it works. I’ll probably need to install the Linux Station to install it on, so if anyone has any experience with that please share. If I get it working I’ll post the steps up here in case it would be of interest to anyone.

Also, there is a Max2Play and Squeezeplug system that is available as an image. Does anyone have any experience with it?

The next cheeky thing to ask is if anyone would post a sample .items and .sitemap setup?

IMHO i would always install the LMS on the same box your music resides on. the LMS renders and streams the music to your devices on the fly; if the music is on a network share you could run into timing issues. As for examples, here are excellent starting points:



here is a great example if you would like to have one single place to control all your players:

i rather decided to have single controls for each room, so for each player i have one set of items:

# in openhab.cfg
squeeze:MotoG.id=MAC of device

squeeze.items:

Group    gPlayerPower
Group    gPlayerVolumeAll
//Group so all devices can be turned off in a rule
Group    gPlayerPowerAll
Group    gPlayerKueche <radio>
//Player Küche
Switch            squeezeKuechePower        "Stop"    <stop_playing>    (gPlayerKueche,gPlayerPowerAll)        { squeeze="MotoG:power",autoupdate="false" }
Switch            squeezeKuechePlay        "Play"    <play>            (gPlayerKueche)            { squeeze="MotoG:play",autoupdate="false" }
Rollershutter    squeezeKuecheVolume        "Vol [%.1f %%]"            <lautsprecher>    (gPlayerKueche,gPlayerVolumeAll)    { squeeze="MotoG:volume" }
String            squeezeKuecheTitle "Titel: [%s]"    <info>    (gPlayerKueche)                            { squeeze="MotoG:title" }
String            squeezeKuecheArtist "von: [%s]"        <info>    (gPlayerKueche)                            { squeeze="MotoG:artist" }
String            squeezeKuecheRadioTitle "Stream: [%s]"    <info>    (gPlayerKueche)                        { squeeze="MotoG:remotetitle" }


and in the sitemap:

Switch item=squeezeKuechePower    mappings=[OFF="Stop"]        visibility=[squeezeKuechePlay==ON]                
Switch item=squeezeKuechePlay    mappings=[ON="Play"]
Switch item=squeezeKuecheVolume visibility=[squeezeKuechePlay==ON]
Text item=squeezeKuecheTitle visibility=[squeezeKuechePlay==ON]
Text item=squeezeKuecheArtist visibility=[squeezeKuechePlay==ON]                
Text item=squeezeKuecheRadioTitle visibility=[squeezeKuechePlay==ON]

For other devices, you basically need to cut&paste the whole kid’ncaapoodle and remove “Kueche” with whatever “Livingroom” “Dungeon”…you get the idea :wink:
HTH,
-OLI

I will throw in to the thread in case it inspires, that I have previously ripped and uploaded all my music to Google Music and use that with LMS, no local music at all. Granted I am not an audiophile who loves everything in flac files, but for my use (be it streaming through the house, working at my desk or downstairs on the main amp) i cant tell the difference :slight_smile:

That’s a great idea.

If you are going to investigate I highly recommend setting up a separate Google account just for the music. It does misbehave when messing around with two factor auth custom password stuff

Here’s how I have mine set up – Items, Sitemap, and Rules

Items

Number Squeezebox_NJ_Living_Play_PlayList 	"Playlists"
Dimmer SBP_NJ_Living_Volume			"Volume [%d %%]"	{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:volume" }
Switch SBP_NJ_Living_Mute			"Mute"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:mute" }
Switch SBP_NJ_Living_Play			"Play"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:playPause" }
Switch SBP_NJ_Living_Stop			"Stop"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:stop" }
Switch SBP_NJ_Living_Next			"Next"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:next" }
Switch SBP_NJ_Living_Prev			"Previous"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:prev" }
Switch SBP_NJ_Living_Power			"Power"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:power" }
String SBP_NJ_Living_Album			"Album [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:album" }
String SBP_NJ_Living_Artist			"Artist [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:artist" }
String SBP_NJ_Living_Title			"Title [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420164526:title" }
Number Squeezebox_NJ_Family_Play_PlayList 	"Playlists"
Dimmer SBP_NJ_Family_Volume			"Volume [%d %%]"	{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:volume" }
Switch SBP_NJ_Family_Mute			"Mute"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:mute" }
Switch SBP_NJ_Family_Play			"Play"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:playPause" }
Switch SBP_NJ_Family_Stop			"Stop"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:stop" }
Switch SBP_NJ_Family_Next			"Next"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:next" }
Switch SBP_NJ_Family_Prev			"Previous"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:prev" }
Switch SBP_NJ_Family_Power			"Power"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:power" }
String SBP_NJ_Family_Album			"Album [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:album" }
String SBP_NJ_Family_Artist			"Artist [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:artist" }
String SBP_NJ_Family_Title			"Title [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:000420165ee2:title" }
Number Squeezebox_NJ_Master_Play_PlayList 	"Playlists"
Dimmer SBP_NJ_Master_Volume			"Volume [%d %%]"	{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:volume" }
Switch SBP_NJ_Master_Mute			"Mute"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:mute" }
Switch SBP_NJ_Master_Play			"Play"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:playPause" }
Switch SBP_NJ_Master_Stop			"Stop"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:stop" }
Switch SBP_NJ_Master_Next			"Next"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:next" }
Switch SBP_NJ_Master_Prev			"Previous"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:prev" }
Switch SBP_NJ_Master_Power			"Power"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:power" }
String SBP_NJ_Master_Album			"Album [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:album" }
String SBP_NJ_Master_Artist			"Artist [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:artist" }
String SBP_NJ_Master_Title			"Title [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:0004201e44d7:title" }
Number Squeezebox_NJ_Office_Play_PlayList 	"Playlists"
Dimmer SBP_NJ_Office_Volume			"Volume [%d %%]"	{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:volume" }
Switch SBP_NJ_Office_Mute			"Mute"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:mute" }
Switch SBP_NJ_Office_Play			"Play"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:playPause" }
Switch SBP_NJ_Office_Stop			"Stop"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:stop" }
Switch SBP_NJ_Office_Next			"Next"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:next" }
Switch SBP_NJ_Office_Prev			"Previous"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:prev" }
Switch SBP_NJ_Office_Power			"Power"			{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:power" }
String SBP_NJ_Office_Album			"Album [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:album" }
String SBP_NJ_Office_Artist			"Artist [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:artist" }
String SBP_NJ_Office_Title			"Title [%s]"		{ channel="squeezebox:squeezeboxplayer:13B79D32-2360-4A1D-85E7-1B6FE08D217F:b827eb163f1e:title" }

Sitemap

Frame {
Text label=“Living Room Music” icon=“player” {
Frame label=“Now Playing” {
Text item=SBP_NJ_Living_Title
Text item=SBP_NJ_Living_Album
Text item=SBP_NJ_Living_Artist
}
Frame label=“Control Living Room Player” {
Slider item=SBP_NJ_Living_Volume icon="soundvolume"
Switch item=SBP_NJ_Living_Play label=“Play” mappings=[ON=“Play”, OFF=“Pause”]
Switch item=SBP_NJ_Living_Mute label=“Mute” mappings=[ON=“Mute”, OFF=“Unmute”]
Switch item=SBP_NJ_Living_Next label=“Next” mappings=[ON=“Next”]
}
Frame label=“Play a Playlist” {
Selection item=Squeezebox_NJ_Living_Play_PlayList label="Play a Playlist"
mappings=[0=“Playlist0”, 1=“Playlist1”, 2=“Playlist2”, 3=“Playlist3”, 4=“Playlist4”, 5=“Playlist5”]
}
}
Text label=“Office Music” icon=“player” {
Frame label=“Now Playing” {
Text item=SBP_NJ_Office_Title
Text item=SBP_NJ_Office_Album
Text item=SBP_NJ_Office_Artist
}
Frame label=“Control Office Player” {
Slider item=SBP_NJ_Office_Volume icon="soundvolume"
Switch item=SBP_NJ_Office_Play label=“Play” mappings=[ON=“Play”, OFF=“Pause”]
Switch item=SBP_NJ_Office_Mute label=“Mute” mappings=[ON=“Mute”, OFF=“Unmute”]
Switch item=SBP_NJ_Office_Next label=“Next” mappings=[ON=“Next”]
}
Frame label=“Play a Playlist” {
Selection item=Squeezebox_NJ_Office_Play_PlayList label="Play a Playlist"
mappings=[0=“Playlist0”, 1=“Playlist1”, 2=“Playlist2”, 3=“Playlist3”, 4=“Playlist4”, 5=“Playlist5”]
}
}
Text label=“Family Room Music” icon=“player” {
Frame label=“Now Playing” {
Text item=SBP_NJ_Family_Title
Text item=SBP_NJ_Family_Album
Text item=SBP_NJ_Family_Artist
}
Frame label=“Control Family Room Player” {
Slider item=SBP_NJ_Family_Volume icon="soundvolume"
Switch item=SBP_NJ_Family_Play label=“Play” mappings=[ON=“Play”, OFF=“Pause”]
Switch item=SBP_NJ_Family_Mute label=“Mute” mappings=[ON=“Mute”, OFF=“Unmute”]
Switch item=SBP_NJ_Family_Next label=“Next” mappings=[ON=“Next”]
}
Frame label=“Play a Playlist” {
Selection item=Squeezebox_NJ_Family_Play_PlayList label="Play a Playlist"
mappings=[0=“Playlist0”, 1=“Playlist1”, 2=“Playlist2”, 3=“Playlist3”, 4=“Playlist4”, 5=“Playlist5”]
}
}
Text label=“Master Bedroom Music” icon=“player” {
Frame label=“Now Playing” {
Text item=SBP_NJ_Master_Title
Text item=SBP_NJ_Master_Album
Text item=SBP_NJ_Master_Artist
}
Frame label=“Control Master Bedroom Player” {
Slider item=SBP_NJ_Master_Volume icon="soundvolume"
Switch item=SBP_NJ_Master_Play label=“Play” mappings=[ON=“Play”, OFF=“Pause”]
Switch item=SBP_NJ_Master_Mute label=“Mute” mappings=[ON=“Mute”, OFF=“Unmute”]
Switch item=SBP_NJ_Master_Next label=“Next” mappings=[ON=“Next”]
}
Frame label=“Play a Playlist” {
Selection item=Squeezebox_NJ_Master_Play_PlayList label="Play a Playlist"
mappings=[0=“Playlist0”, 1=“Playlist1”, 2=“Playlist2”, 3=“Playlist3”, 4=“Playlist4”, 5=“Playlist5”]
}
}
}

Rules

val String njLivingPlayerMAC = "00:04:20:16:45:26"
val String njFamilyPlayerMAC = "00:04:20:16:5e:e2"
val String njMasterPlayerMAC = "00:04:20:1e:44:d7"
val String njOfficePlayerMAC = "b8:27:eb:16:3f:1e"
val org.eclipse.xtext.xbase.lib.Functions$Function2 squeezePlayPlaylist = [
    String player,
    String playlist |
	logInfo("squeezeplaylist.rules", "In squeezePlayPlaylist with player of " + player)
	var String station
	var String requestURL
	var boolean success = true
	switch(playlist) {
		case "0" : 
			station = "pandora%3A%2F%2F126109272201071737.mp3"
		case "1" : 
			station = "pandora%3A%2F%2F2739670749549530233.mp3"
		case "2" : 
			station = "pandora%3A%2F%2F3019846262429944953.mp3"
		case "3" :
			station = "pandora%3A%2F%2F79741376504106105.mp3"
		case "4" :
			station = "pandora%3A%2F%2F3230131829791886457.mp3"
		case "5" :
			station = "pandora%3A%2F%2F72031231602953337.mp3"
		default : {
			logError("squeezeplaylist.rules", "Received a request for an unknown playlist!")
			success = false
		}
	}
	if (success == true) {
		requestURL = "http://some.host:9000/status.html?p0=playlist&p1=play&p2=" + station + "&player=" + player
		logInfo("squeezeplaylist.rules", "Sending playlist request to server: " + requestURL)
		sendHttpGetRequest(requestURL)
	}
]
rule "Squeezebox_NJ_Living_PlayList"
when
	Item Squeezebox_NJ_Living_Play_PlayList received command
then
	logInfo("squeezeplaylist.rules", "Playing playlist on NJ Living Room player")
	squeezePlayPlaylist.apply(njLivingPlayerMAC, receivedCommand.toString)
end
rule "Squeezebox_NJ_Family_PlayList"
when
	Item Squeezebox_NJ_Family_Play_PlayList received command
then
	logInfo("squeezeplaylist.rules", "Playing playlist on NJ Family Room player")
	squeezePlayPlaylist.apply(njFamilyPlayerMAC, receivedCommand.toString)
end
rule "Squeezebox_NJ_Master_PlayList"
when
	Item Squeezebox_NJ_Master_Play_PlayList received command
then
	logInfo("squeezeplaylist.rules", "Playing playlist on NJ Master Bedroom player")
	squeezePlayPlaylist.apply(njMasterPlayerMAC, receivedCommand.toString)
end
rule "Squeezebox_NJ_Office_PlayList"
when
	Item Squeezebox_NJ_Office_Play_PlayList received command
then
	logInfo("squeezeplaylist.rules", "Playing playlist on NJ Office player with playlist ", receivedCommand.toString)
	squeezePlayPlaylist.apply(njOfficePlayerMAC, receivedCommand.toString)
end

totally valid point, I realise that now. Thanks for that, I think you’ve saved me many hours of troubleshooting!

@sam
Interesting approach. How is that on bandwidth? (I mean streaming your
music from the internet, do you use a few gigs each month?)

Being in South Africa that may be a limitation for me.

Thanks so far for some valuable input guys.

I couldn’t tell you how much the music uses, my broadband monthly usage is about a 1tb a month, but I am pretty sure the music is not a major factor.

I would guess that one HD film on Netflix, or a couple of episodes of The Great British Bake Off on BBC1 uses more bandwidth than the mp3s.

But if you have to watch your usage then it might be better to get a 300gb hard drive for £20… or just use your NAS :slight_smile:

Hey @sam ,

At last I’ve got some time to pick this up again.

For your Google Music integration to LMS, did you set it up via the Squeezebox-googlemusic plugin?

Urm, or some variation of that before that repo existed :slight_smile:

But as far as I know that is the current version to use