Yamaha MusicCast binding revival

Sleep function added.
DTO : added a model for Status.
You can test both of them, the compiled JAR is also uploaded

Development environment is updated to 2.5.9. Latest version of OH2 on which we will stay for a while.
New version is available built on 2.5.9
This one already incorporates changes to update channels automatically.
This is needed for

  • Detect amount of zones and create channels accordingly
  • Fetch presets and present them as a list. This avoids mapping to be created by you.
  • Create dropdown for devices for MC Link

Shortlist To Do

  • Add DTO for all API calls
  • Save Presets/Favorites in a prefilled mapping
  • Continue research to squeeze in MC Link
2 Likes

Also testing here, you can add WXA-050 to the Tested Devices list :wink:

Time for another update:

  • Presets are now automatically detected and saved. So no more mappings in sitemaps!
  • I have been playing around to see what I can do with OH for MusicCast.
    So I added a function which reads the API of your OH instance and shows the registerd Things, together with the zones. Now trying to use the button/switch to activate it.
    Example:

  • Cleaned up the code a bit to erase beginners mistakes :slight_smile:

As I donā€™t have 2 devices (yet), I need to keep on coding based on a drawing. Once something is available, I will post it so you can test it.

Shortlist To Do

  • Add DTO for all API calls
  • Continue working oon MC Link
  • Publish intermediate version as all changes are currently in the code only
2 Likes

After a few more days playing around, I have compiled and uploaded a new version on GitHub
This contains all the previous changes including fetching Presets.
But also contains a first draft of the MusicCast integration. So be advised: this is a Alpha version :slight_smile:

What can you expect/test?

  • Via the API your things are read, currently only the zone Main (1) is supported (hardcoded)
  • channelServer is the master
  • Only 1 slave is foreseen: channelClient1 (others will be added later)
  • Switch channelDistribution will activate the Music Cast link. Make sure you have selected a server and a client.
  • Unlinking is not yet possible.

This might work, it might explode. All feedback is welcome, the response of the devices is logged as INFO and needed to do some furter debugging.

Amazing progress! Iā€™ll have a play when I get home tonight.

Tested the musiccast link with RX-D485 as server and WXA-050 as client.
Can confirm this works.
As I turn on the distribution switch, the WXA-050 is switched on, and plays in link with the RX-D485.
:metal: :+1:

Eager to know your experience, then I know that the Proof Of Concept is working for at least 2 people.
Due to the nature of OH framework and my (perhaps limited) knowledge, I did not find a way to set a Virtual Zone as Input.
You need to decide for yourself which device will ā€œhostā€ the information regarding the MusicCast Link. In your exampel this can be Kitchen, Study or Outside.
There you need to set the server, client1 and the distribution switch.
Dropdowns will be filled, select the desired devices and click on the switch.

Shortlist To Do

  • Cleaning up the code: Add DTO for all API calls, coding guidelines (almost finished), ā€¦
  • Continue working on MC Link

@BeanzBE ive just tested the latest binding and its working as expected. I can select the lounge as the server and then I can send audio to another zone hitting the distribution switch!!! How quickly you are making progress is absolutely awesome!

Cool!
I will continue working on the integration of MusicCast.
@joedirt @jamesmelville @lampy @CobleS
I donā€™t want to make it too complicated. So how many Virtual Links do you need?
Each Virtual Link will support 10 devices (1 master + 9 slaves) and the binding will check if they are used or not (Item linked to channel)

1 Like

4 please, my goal is to split all of my combined zones once this binding is working properly with additional r-n303dā€™s Ill have a living/dining/kitchen/outdoor, kids rooms, guest bed/bathroom and an office/master bed/ensuite

OK, let me first get it finished and working for 9 clients.
Then I can expand it to 4 Virtual Links
That will almost be the maximum, I would think

Just tested also with 2 devices, the HTR-4068 (RX-V479) and Musiccast 20. Tested both as server as well as client.
The binding and distribution works good! :ok_hand:You can add them to the list with tested devices.
4 virtual links would be more than sufficient for my case. Donā€™t have that many devices yet, but I do expect more will come in the future.

Hey Lennert, great job! Itā€™s crazy youā€™ve managed (and bothered) to get this working without a second device to play with! The musiccast link seemed to work nicely for me as you described across a WX-030, ISX-80 and WX-010.

Iā€™m trying to understand further what youā€™re thinking in terms of ā€œvirtual linksā€. It seems curious to me that youā€™d attach them to the existing Thing for a physical device as you have now, Iā€™m not clear if thatā€™s just a stepping stone to getting it to work or part of your plan. For example, I can currently configure a zone, consisting of a server (device B) and a client (device C), as part of a completely unrelated Thing (e.g. device A), which could actually be in a completely different zone configured against another Thing.

I donā€™t have a ā€œcorrectā€ answer for this, nor am I sure there is one, but I wonder if it would make more sense to simply have a channel on each Thing (device), which tells that device which other Thing (server device) to stream from. The binding would then check if that other (server) device was already included in a zone, and either create a zone with that device as a server and the current device as client, or add the current device as a client to that existing zone. You could restrict the list of devices available to exclude those which are already clients, and present a null option to allow unlinking.

I donā€™t know if Yamaha impose some kind of constraint, but it seems strange to me to restrict to (e.g.) 4 zones if thereā€™s no limit in the hardware. (although 4 zones would be plenty for me :slight_smile:).

The alternatives I thought about was a different ThingType for a zone, which then had an on off switch and a server and list of clients. But Iā€™m not sure that adds much apart from maybe the option to have different pre-configured ā€œscenesā€, e.g. a logical ā€œpartyā€ zone which includes all your devices, and a ā€œfloor xā€ zone with just devices on that floor. Users would need to set up persistence to save pre-configured zones through power cycles, unless you actually made the server and list of clients part of the thing configuration, rather than channels on a thing. All in all itā€™s a trade off between whether people want on the fly zone configuration or pre-configured zones. Iā€™d be minded to go with my first suggestion, and people can pre-configure ā€œscenesā€ by creating a rule which sets the server each Thing (client) should follow on a group of Things.

Iā€™ve probably overthought this now, and completely missed some limitation of the API Iā€™m not aware of, but just my two cents! Let me know if you want me to try and articulate my thinking further.

That would be both for the moment. Currently it gives us the possibility to test the API and it is what I came up with during brainstorming.
I copied Virtual Link from the wordings of @joedirt as he mentioned it to be available under Input. But I donā€™t want to use Input as these are predefined values from Yamaha. Once you create the link, the Input changes to mc_link for the slaves.

It is not the nicest solution, if not correctly explained it causes confusion. However, Iā€™m going to finish it with the current setup to get some more experience and feedback.

Your suggestion to have a channel on each Thing (combined with the zone) is something which seems viable with the experience/new insights. For sake of simplicity, it also makes more sense. Something to think about.

For me, 1 master and 2 slaves (for now, may be up to 4 or 5 slaves in the future).
I donā€™t think I will need this, but do you think we can have letā€™s say 2 masters and 1 slave each? Just being curious :man_shrugging:

I have been re-reading the documentation again and it kinda confirmed what I already thought: the client has to join the server with all its zones.

On request of @jamesmelville, I have already added a new channel to select the server to stream from :wink:. It is called channelMCServer. I did a copy/paste of the code and made a few changes. The very first build is on GitHub. Again, this can work and this can explode. Main zone only!
(There are a few more small changes included as well, so perhaps good to backup the binding)
If that would work, then there is no limit on number rooms/links that you can create.

I can do the API calls and check the response. That gives me a direction if itā€™s OK or not. But I need volunteers :innocent: with multiple devices.

Anyway, used the dropdown myself and my AVR switches nicely to mc_link but nothing plays of course :sunglasses:

I finally compiled a OH3 version of this binding - and can confirm the link starts when I set the channelMCServer of the client to the server, the distribution starts immediately. So I was able to link 2 clients to the same server by sending a command to both clients. Good job :+1:

Still no way to unlink though :wink: Iā€™m currently doing it by sending a setServerInfo with {"group_id":""} to the server and setClientInfo to {"group_id":""} to all clients too (though Iā€™m unsure if that really necessary).

Also I think it would be great to have support for that UDP event push feature that is barely documentedā€¦ having real time updates instead of polling would be awesome!
I just tried it for the first time with curl and netcat: apparently you just have to send these 2 X-AppName/X-AppPort headers with a request to the API every 10 minutes or less:
curl -v http://192.168.1.xxx/YamahaExtendedControl/v1/netusb/getPlayInfo -H 'X-AppName: MusicCast/1' -H 'X-AppPort: 41100'
and then if you listen to the UDP port youā€™ll see the updates appearing when something changes :smiley: :

$ nc -ul 41100

{"main":{"volume":86,"actual_volume":{"mode":"db","value":-37.5,"unit":"dB"}},"zone2":{"volume":0},"device_id":"..."}{"main":{"volume":95,"actual_volume":{"mode":"db","value":-33.0,"unit":"dB"}},"zone2":{"volume":0},"device_id":"..."}{"main":{"signal_info_updated":true},"netusb":{"play_info_updated":true},"device_id":"..."}{"main":{"signal_info_updated":true},"netusb":{"play_info_updated":true}```

Hi!
First of all - thank you very much for another useful binding!
As already confirmed in our conversation a day ago - it also works for my Yamaha WXC-50.

Maybe just hint from my side - I am using OH2 2.5.10 - on restart (shutdown as well as startup), the binding always shows an error message in the openhab.log:

2020-11-05 11:25:53.911 [INFO ] [cast.internal.YamahaMusiccastHandler] - YXC - Start initializing! - WXC-50
2020-11-05 11:25:53.917 [INFO ] [cast.internal.YamahaMusiccastHandler] - YXC - Start automatic refresh (60 seconds - WXC-50)
2020-11-05 11:25:53.919 [INFO ] [cast.internal.YamahaMusiccastHandler] - YXC - Finished initializing! - WXC-50
2020-11-05 11:25:53.997 [WARN ] [mmon.WrappedScheduledExecutorService] - Scheduled runnable ended with an exception:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $
at com.google.gson.Gson.fromJson(Gson.java:900) ~[?:?]
at com.google.gson.Gson.fromJson(Gson.java:853) ~[?:?]
at com.google.gson.Gson.fromJson(Gson.java:802) ~[?:?]
at com.google.gson.Gson.fromJson(Gson.java:774) ~[?:?]
at org.openhab.binding.yamahamusiccast.internal.YamahaMusiccastHandler.fetchOtherDevices(YamahaMusiccastHandler.java:589) ~[?:?]
at org.openhab.binding.yamahamusiccast.internal.YamahaMusiccastHandler.refreshProcess(YamahaMusiccastHandler.java:437) ~[?:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_222]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) ~[?:1.8.0_222]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) ~[?:1.8.0_222]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) ~[?:1.8.0_222]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_222]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_222]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_222]
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350) ~[?:?]
at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:70) ~[?:?]
at com.google.gson.Gson.fromJson(Gson.java:888) ~[?:?]
ā€¦ 12 more

It appears to be fully operational though.
Cheers,

Thank you for the feedback and compliments. Good to hear that the code works on OH3 as well.

There is still a lot to do:

  • Cleaning up the code to remove the first try for MusicCast Link. :heavy_check_mark:
  • Cleaning up the code: Add DTO for all API calls, coding guidelines, ā€¦ :heavy_check_mark:
  • Add unlink to break MusicCast link. Need to think of a good way to do this in the UI :heavy_check_mark:
  • Upgrade to JAVAV11 :heavy_check_mark:
  • Check the error message reported by @Endurofahrer (I have it too but not started verifying what it is) :heavy_check_mark:
  • Autodiscovery
  • UDP event push feature
  • Create a Pull Request for OH3
  • Add Play Info (Artist, track, ā€¦)
  • ā€¦

At least this keeps me of the street :innocent: