Kef ls50 Wireless

Could you share the code base? I started with a simple python library (Hass requires all component integrations to have implementation details in an external library), but I couldn’t get your example to work for some reason. If we work on the same codebase, we won’t do the same work twice :slight_smile:

Prototype of external lib

Would be cool if you could work on this part. Then I could work on the HA part. Btw. My python is a bit rusty

1 Like

I made a repo here: https://github.com/Gronis/pykef
Used your initial work as a base for the current version. This version supports getting + setting volume, mute/unmute (with old volume retained when mute/unmute is toggled), setting input source, and turning it off. I guess what’s left is fetching input source from the speaker, add support for reconnecting when it turns off/on, and some kind of feedback if volume or input changes from other clients.

Any more ideas what could/should be implemented in the python lib?

1 Like

@Gronis: Thanks for your code. Looks very good to me. I wrote some comments in the repo.

On Wendsday I will start using your lib to implement the HA integration.

1 Like

Ok! I will do some updates today and tomorrow. I added you as a collaborator so that you can change things without a PR. I’m busy Thursday and Friday so I might not be able to help at that time if you run into integration trouble.

2 Likes

@chimpy: Do you think you could do some more wireshark magic to find out how to read the active input source from the LS50 box. I think this would be a key feature that we are still missing.

1 Like

It would also be nice to see what data is sent to a device when another device changes input or volume settings. Then it would be possible to setup listeners so that hass does not need to query for volume and input all the time.

1 Like

@ironhorse
That Wireshark screencap above contains the responses the LS50 makes to each query a client sends out when it wants to update its app UI.

@Gronis It does send a reply to the client when the command was successful but IIRC it was just something like “OK”.

I’m at work atm, but try this:
echo -ne "\x47\x30\x80\xd9" | nc -w 1 192.168.1.49 50001 | hexdump -s 3 -n 1 -v -e '/1 "%02X "'

In this command I’ve taken the first query (rendered in ASCII as G0..). I did this because the response from the LS50 contains 1c in the penultimate byte. We know it’s not volume (as that’s the second query), so I think it’s selected output.

1a 9b is Aux
1b 00 is Optical
1c f7 is USB
12 82 is Wireless
19 ad is Bluetooth

I’m not yet sure how LS50 distinguishes between some commands. Like set output to Bluetooth:
echo -ne "\x53\x30\x81\x19\xad"
And change volume to 25:
echo -ne "\x53\x30\x81\x19\xaa" (edit: this is wrong)

1 Like

I just realised that having an opened connection to the speakers prevents any new connection to the speakers. This means that listening on changes will not work and the plugin needs to poll for changes. It seams this is the way the app works as well, since it takes around 1-2 seconds for any change to be updated in the app GUI.

1 Like

@ironhorse I’ve published an update. See commit message/README for details. It works pretty good now, even though the code is a little bit of a mess.

2 Likes

@Gronis: Wow. Pretty cool update. Thanks for the documentation. That is a pretty good basis for the HA integration.

2 Likes

I’m so impressed with your work guys! Nice one! :smiley:

Please note that I tested the command I half-guessed at during work and it’s almost correct: Bluetooth is actually 1F.

That is, echo -ne "\x53\x30\x81\x19\xad" sets Bluetooth.
But when I run the command to get the source, the result back is “52 30 81 1F CF”. Or 1F. Maybe because I don’t have it paired to anything?

Also I realised the answer about how LS50 was not confusing volume and source values was staring me in the face:

Sources:
“\x53\x30\x81\x1a\x9b”
“\x53\x30\x81\x1b\x00”
“\x53\x30\x81\x1c\xf7”
“\x53\x30\x81\x12\x82” (wireless)
“\x53\x30\x81\x19\xad”

Volume:
“\x53\x25\x81\x12\x82” (sets vol to 18)
“\x53\x25\x81\x19\x82” (sets vol to 25)

x30 makes sure you’re changing outputs. x25 makes sure you’re changing volume.

Sources:
“\x53\ x30 \x81\ x1a \x9b”
“\x53\ x30 \x81\ x1b \x00”
"\x53\ x30 \x81\ x1c \xf7”
“\x53\ x30 \x81\ x12 \x82” (wireless)
“\x53\ x30 \x81\ x19 \xad”

Volume:
“\x53\ x25 \x81\ x12 \x82” (sets vol to 18)
“\x53\ x25 \x81\ x19 \x82” (sets vol to 25)

I tested this yesterday and I got the same behavior. I have implemented this in the python lib.

I uploaded the python lib to pypi, so now anyone can install it with:

pip3 install pykef

I have a first working version of the HA media_player integration of the KEF-LS50.

https://github.com/Gronis/pykef/tree/HA-01/kefwireless

You will find an install guide at the bottom of the README.md.

Hope it works for you. Have fun.

1 Like

I’ll test it and let you know!

@ironhorse @gronis It’s beautiful. Fantastic stuff thank you! Being able to set the volume is going to be awesome when I switch sources. I had no idea that each source had its own volume setting.

Only aesthetic thing I might mention is having the sources not capitalised, i.e. “Bluetooth” and “Opt” (or “Optical”) rather than as they are currently.

I have a volume limit set in the app as 60, which the speakers respect even if we set volume to 95 in HA. However the volume bar doesn’t “come back down” to 60 when I do that. That does happen in the app so I’m not sure why that doesn’t happen here.

Other than that I think you should definitely make a pull request!

Optional last finishing touch: Make turn_on possible by optionally configuring a parameter for a service call to turn it on?
service_call_on: { "entity_id": "remote.living_room_ir_remote", "command": "toggle_ls50", "num_repeats": 2, "delay_secs": 0 }

Happy that it works for you. I like it too. I will look into the issues you mentioned.
This was really good teamwork. I did only spent a day or so.

I have a first working version of the HA media_player integration of the KEF-LS50.

Nice, will try it out now.

@ironhorse: If we do a pull request, maybe we should use pip to install pykef? I thing that is how home-assistant wants the implementation specific libraries to be installed.

service_call_on: { "entity_id": "remote.living_room_ir_remote", "command": "toggle_ls50", "num_repeats": 2, "delay_secs": 0 }

I really like this idea. Then it’s very easy to turn on the speakers through IR commands.

This was really good teamwork.

I agree. The end product came out very good as well :slight_smile:

1 Like

For me, the reported state seems to be the input and the volume. Is that the same for you? I think it should just be On or Off. Also the input source is not displayed in the input source field. When changing input, it is displayed for a second, then it disappears.