Yamaha musiccast binding

Hey Guys,

see attached the Basic and the Advanced API documentation in the current revision. The Yamaha UK Support provided them to me and asked me to mention that it is only intended to be used by AV Professionals if i share it. DONE

I really hope that we get that ball rolling now. Using the API calls via HTTP Binding and parsing via JSONPATH works like a charm. However a centralised Binding would be way nicer especially when looking at the Advanced API.

YXC_API_Spec_Basic.pdf (987.4 KB)

YXC_API_Spec_Advanced.pdf (561.7 KB)

3 Likes

:heart_eyes: Excellent @Tomibeck ! and thanks also to @badsl

Ah nice something going forward here.
I wasnt in the community for some time now.
Thanks for sharing the advanced spec, that was missing in my documents.

I am really excited about the ongoing process.
If there is a well starting point on github i hope that i am able to help you out not only with testing. :slight_smile:

I work on Python implementation of Yamaha Extended Control API:

1 Like

Could you post your own implementations with the http binding in this Thread?
I am playing around with the http binding and jsonpath myself for my isx-80 radio, but when you already got some solutions it would be nice to share them.

Hey,

im in the process of renewing my whole installation so its actually not productive right now. I can give you two examples:

  Number  srt1500_volume  "Livingroom Volume"    (srt1500) {http="<[http://192.100.20.7:80/YamahaExtendedControl/v1/main/getStatus:60000:JSONPATH($.volume)]"}
String  srt1500_input  "Livingroom Input"    (srt1500) {http="<[http://192.100.20.7:80/YamahaExtendedControl/v1/main/getStatus:60000:JSONPATH($.input)]"}

Those are just two quick examples that had proved to be working.
Im actually thinking about doing it without the HTTP Binding and JSON Path. you can directly send http get and put from the rule as well

Ok i see, you ar as far as i am already^^

// Yamaha ISX-80 MusicCast Radio
Switch Yamaha_McRadio_Power	"Power [%s]" 			<switch>	(YamahaIsx80McRadio) { http=">[ON:GET:http://192.168.178.34/YamahaExtendedControl/v1/main/setPower?power=on] >[OFF:GET:http://192.168.178.34/YamahaExtendedControl/v1/main/setPower?power=standby]"}
Switch Yamaha_McRadio_Mute	"Mute [%s]" 			<soundvolume-0>	(YamahaIsx80McRadio) { http=">[ON:GET:http://192.168.178.34/YamahaExtendedControl/v1/main/setMute?enable=true] >[OFF:GET:http://192.168.178.34/YamahaExtendedControl/v1/main/setMute?enable=false]" }
String Yamaha_McRadio_Input 	"Eingang [MAP(yamaha.map):%s]" 	<receiver>	(YamahaIsx80McRadio) {http="<[yamIsx80McRadioStatus:10000:JSONPATH($.input)]"}
String Yamaha_McRadio_Volume	"Lautstärke [%s]"	        <soundvolume>	(YamahaIsx80McRadio) {http="<[yamIsx80McRadioStatus:10000:JSONPATH($.volume)]"}

Ofc all work in progress here too.
I am just playing a bit around since i still have exams to do which have a higher priority.

If someones interested, have collected some strings from the “getFeatures” api call and collected them for a mapping file:

net_radio=Net Radio
napster=Napster
spotify=Spotify
juke=Juke
airplay=Airplay
mc_link=MusicCast Link
server=Server
bluetooth=Bluetooth
tuner=Tuner
aux=Aux
power=Power
sleep=Sleep
volume=Volume
mute=Mute

I just want to cellect everythign here from scratch, to have as much background as possible when a possible binding development starts. :slight_smile:

Again something for the collection:

String Yamaha_McRadio_Cur_Track	 "Artist: [%s]"	<musical_note>	(YamahaIsx80McRadio)	
 {http=
  "<[http://IPADRESS/YamahaExtendedControl/v1/netusb/getPlayInfo:10000:JS(getIsxArtist.js)]"
 }

String Yamaha_McRadio_Cur_Artist "Track: [%s]"	<musical_note>	(YamahaIsx80McRadio)	
 {http=
  "<[http://IPADRESS/YamahaExtendedControl/v1/netusb/getPlayInfo:10000:JS(getIsxTrack.js)]"
 }

Switch Yamaha_McRadio_prev_next	 "Play ->"	<musical_note>	(YamahaIsx80McRadio)	
 {http=
  ">[ON:GET:http://IPADRESS/YamahaExtendedControl/v1/netusb/setPlayback?playback=previous]
  >[OFF:GET:http://IPADRESS/YamahaExtendedControl/v1/netusb/setPlayback?playback=next]",
  autoupdate="false"
 }

The Switch is set to autoupdate=false, to use it with two pushbuttons for previous and next track on my playlist.

Switch item=Yamaha_McRadio_prev_next label="Play ->" mappings=[ON="Previous", OFF="Next"]

The Strings are used as a current playing information.
getIsxArtist.js:

(function(i) {
    if(JSON.parse(i).input == "net_radio"){
    	var trackDataArray = JSON.parse(i).track.split(" - ");
    	
    	if(trackDataArray.length == 2){
    		return trackDataArray[trackDataArray.length - 2];
    	}
    	return trackDataArray[trackDataArray.length - 1];
	}
	else{
		return JSON.parse(i).artist;
	}
})(input)

I have separated “net_radio” input, because in this mode the artist element in the json response is for the radio station.
In most stations that i have listened to, the complete song information is stored in the track element with Artist - Track

Works fine for me for some time now.
getIsxTrack.js is doing nearly the same with different json elements.

And i decided to update my power button too, since the current power state was not set correct all the time.

Switch Yamaha_McRadio_Power	 "Power [%s]" <switch>	(YamahaIsx80McRadio) 
 {http=
  ">[ON:GET:http://IPADRESS/YamahaExtendedControl/v1/main/setPower?power=on]
  >[OFF:GET:http://IPADRESS/YamahaExtendedControl/v1/main/setPower?power=standby]
  <[yamIsx80McRadioStatus:10000:JS(getIsxPowerStatus.js)]"
 }

getIsxPowerStatus.js

(function(i) {
    if(JSON.parse(i).power == "standby"){
		return "OFF";
	}
	else{
		return "ON";
	}
})(input)

Yamaha distinguishes between on and standby, so i mapped the state to a OH-switch conform way.
Maybe there is an easier way, but i was dealing with many js files anyway and continued it that way. :smiley:

Edit for clarity:
yamIsx80McRadioStatus is just a cached url in my http.cfg

Hi guys,

just put the calls from you listetd here (Power ON, Standby and Volume) in a very very draft binding. So feel free to test on your side. Actual push only, so if ou switch of the MusicCast manually it will be not reflected in the Binding. Also no discovery, you have to put in the IP Adress.

Yamaha MusicCast Binding

Feel free to play with it. When have more time, i will work on it, feedback welcome

Best Frank

Hey Frank,

Power and Volume work fine for my ISX-80 Radio.
Will test the AV-Receiver this week. :slight_smile:

Do you have the source files hosted anywhere?
I am no Java Pro, but maybe i can help out with some simple things already.

Anyway thanks for giving this a start.

Hi Frank,

Power works fine with the WX-10 speaker.
Volume will be tested tomorrow

Thanks a lot!

Hi Frank,

works fine with Yamaha WX-030 :wink:
Do you share the source file please ;(

Hey everybody,

Is there a way to configure one of the speakers as “Default Sink” like the Sonos speakers ?

Best regards

I would say not at the current state.

I dont know the exact behaviour, but technically you need to turn in the speaker, set the Input and play the Audio Stream.

The current Binding Supports only Power and mute.

I feared. I have already tried to find he appropriate code site from the Sonos binding , but I have not found so far. Anyone some ideas?

Hi,

sorry for delay, I’m blocked a little bit with other task. I try to work on the Binding, but not yet something to show

Here is the Source Code

BEst Frank

Yamaha Binding SRC

I’ve no experience with this type of binding and how to use it in openhab, is it similar in application to another binding that i can look at the wiki for instructions? or if not maybe someone can show how 1 of the above functions can be configured so i can work out the rest?

Very excited to test this so i can stop trying to create rules and multiple items just to turn on my soundbar 8)

Thanks in advance.

ps. i have wx-010 , isx-18D , and YAS-306.

You just have to install the Binding manually for using it in this early state.
That means you have to download the jar file that frank has linked and put it in the addons folder of your openhab installtion.

Edit:
In my case (Openhabian installed on a raspberry the addons folder is located under

/usr/share/openhab2/addons

Anyone developed a method for finding the MusicCast services, I know they advertise as an http sink but there’s got to be a more specific way of identifying them, sorry if I’ve overlooked something! Thanks Ed

Ha! Didn’t know they released the API docs for MusicCast!

I figured a few things out by reverse engineering (sniffing the HTTP traffic from the official app) a year or so ago, when I was an openHAB noob :slight_smile:

Here’s my setup in case someone is interested.
My items:

Switch MusicCast_Salon "Salon (ampli) [%s]" <switch> {http="<[http://192.168.1.XXX/YamahaExtendedControl/v1/main/getStatus:20000:JS(musiccast_power.js)] >[ON:GET:http://192.168.1.XXX/YamahaExtendedControl/v1/main/setPower?power=on] >[OFF:GET:http://192.168.1.XXX/YamahaExtendedControl/v1/main/setPower?power=standby]"}
Switch MusicCast_Chambre "Chambre (réveil) [%s]" <switch> {http="<[http://192.168.1.YYY/YamahaExtendedControl/v1/main/getStatus:20000:JS(musiccast_power.js)] >[ON:GET:http://192.168.1.YYY/YamahaExtendedControl/v1/main/setPower?power=on] >[OFF:GET:http://192.168.1.YYY/YamahaExtendedControl/v1/main/setPower?power=standby]"}
Switch MusicCast_Bureau "Bureau (enceinte) [%s]" <switch> {http="<[http://192.168.1.ZZZ/YamahaExtendedControl/v1/main/getStatus:20000:JS(musiccast_power.js)] >[ON:GET:http://192.168.1.ZZZ/YamahaExtendedControl/v1/main/setPower?power=on] >[OFF:GET:http://192.168.1.ZZZ/YamahaExtendedControl/v1/main/setPower?power=standby]"}

Number MusicCast_Salon_Volume "Volume Salon [%d]" <soundvolume> {http="<[http://192.168.1.XXX/YamahaExtendedControl/v1/main/getStatus:20000:JSONPATH($.volume)] >[*:GET:http://192.168.1.XXX/YamahaExtendedControl/v1/main/setVolume?volume=%2$s]"}
Number MusicCast_Chambre_Volume "Volume Chambre [%d]" <soundvolume> {http="<[http://192.168.1.YYY/YamahaExtendedControl/v1/main/getStatus:20000:JSONPATH($.volume)] >[*:GET:http://192.168.1.YYY/YamahaExtendedControl/v1/main/setVolume?volume=%2$s]"}
Number MusicCast_Bureau_Volume "Volume Bureau [%d]" <soundvolume> {http="<[http://192.168.1.ZZZ/YamahaExtendedControl/v1/main/getStatus:20000:JSONPATH($.volume)] >[*:GET:http://192.168.1.ZZZ/YamahaExtendedControl/v1/main/setVolume?volume=%2$s]"}

String MusicCast_Artist "Artiste [%s]" <parents_1_1> {http="<[http://192.168.1.XXX/YamahaExtendedControl/v1/netusb/getPlayInfo:20000:JSONPATH($.artist)]"}
String MusicCast_Track "Track [%s]" <microphone> {http="<[http://192.168.1.XXX/YamahaExtendedControl/v1/netusb/getPlayInfo:20000:JSONPATH($.track)]"}

Number MusicCast_Link "MusicCast Link" <network>

transform/musiccast_power.js is simply:

(JSON.parse(input).power == 'on') ? "ON" : "OFF"

I also wanted to link the main AV receiver to the other rooms easily - I always use the AV receiver as the link master so I control the music using the Yamaha receiver binding.
Here’s how I did it:

rule "MusicCast unlink"
  when
    Item MusicCast_Link received update 0
  then
    logInfo("MusicCast", "Unlinking MusicCast rooms")
    sendHttpPostRequest("http://192.168.1.XXX/YamahaExtendedControl/v1/dist/setServerInfo", "application/json", '{ "group_id": "" }')
    sendHttpPostRequest("http://192.168.1.YYY/YamahaExtendedControl/v1/dist/setClientInfo", "application/json", '{ "group_id": "" }')
    sendHttpPostRequest("http://192.168.1.ZZZ/YamahaExtendedControl/v1/dist/setClientInfo", "application/json", '{ "group_id": "" }')
end


rule "MusicCast link Chambre to Salon"
  when
    Item MusicCast_Link received update 1
  then
    logInfo("MusicCast", "Linking MusicCast room Chambre to Salon")
    sendHttpGetRequest("http://192.168.1.YYY/YamahaExtendedControl/v1/main/setPower?power=on")
    sendHttpPostRequest("http://192.168.1.XXX/YamahaExtendedControl/v1/dist/setServerInfo", "application/json", '{"group_id":"a89b0f9f2d334b63bab6bcc48a0587f0","type":"add","client_list":["192.168.1.YYY"]}')
    sendHttpPostRequest("http://192.168.1.YYY/YamahaExtendedControl/v1/dist/setClientInfo", "application/json", '{"group_id":"a89b0f9f2d334b63bab6bcc48a0587f0","zone":["main"],"server_ip_address":"192.168.1.XXX"}')
    sendHttpGetRequest("http://192.168.1.XXX/YamahaExtendedControl/v1/dist/startDistribution?num=0")
    sendHttpPostRequest("http://192.168.1.XXX/YamahaExtendedControl/v1/dist/setGroupName", "application/json", '{"name": "Salon+Chambre"}')
end

rule "MusicCast link Bureau to Salon"
  when
    Item MusicCast_Link received update 2
  then
    logInfo("MusicCast", "Linking MusicCast room Bureau to Salon")
    sendHttpGetRequest("http://192.168.1.ZZZ/YamahaExtendedControl/v1/main/setPower?power=on")
    sendHttpPostRequest("http://192.168.1.XXX/YamahaExtendedControl/v1/dist/setServerInfo", "application/json", '{"group_id":"a89b0f9f2d334b63bab6bcc48a0587f0","type":"add","client_list":["192.168.1.ZZZ"]}')
    sendHttpPostRequest("http://192.168.1.ZZZ/YamahaExtendedControl/v1/dist/setClientInfo", "application/json", '{"group_id":"a89b0f9f2d334b63bab6bcc48a0587f0","zone":["main"],"server_ip_address":"192.168.1.XXX"}')
    sendHttpGetRequest("http://192.168.1.XXX/YamahaExtendedControl/v1/dist/startDistribution?num=0")
    sendHttpPostRequest("http://192.168.1.XXX/YamahaExtendedControl/v1/dist/setGroupName", "application/json", '{"name": "Salon+Bureau"}')
end

I believe the order of the calls is important.
IIRC any random string will do for the group_id and I could also choose the name - the Yamaha app will still display e.g. “Salon +1 room” but the group name you chose will appear in some places like Spotify which is actually better than what the app does :wink:

Incidentally, if you control the volume of a receiver using the yamahareceiver binding and it’s a link master, the volumes of the additional rooms will be adjusted as well.

Hope that helps.

I’d be very interested in that as well!

3 Likes