Kef ls50 Wireless

Hi,

I have a pair of Kef ls50 wireless speakers that I want to integrate into my home assistant setup. As of June 2018, Kef released a firmware update with support for “third party developers”. After downloading their new app: Kef Control, I realized that they added the support for changing inputs and adjusting the volume etc.

I wanted to make automations which controls my Kef ls50 wireless speaker, so I connected by phone to my computer, and started to sniff some traffic. After a few hours, I could change the input of my speakers between usb input and optical input.

To changing to optical input, I send 0x5330811b00 (hex) to my speakers ip address on port 50001.

To change to usb input I send 0x5330811cf7

Currently, these are the only two commands I have identified. But It should not be hard to sniff out more commands. I’ll probably do this in the coming week.

I am considering to write an integration for these speakers into home-assistant, given that two criterias are met:

  • I want to know if other people can replicate what I did, so that it is universal. I do not yet understand how the protocol works

  • There has to be some people that want this integration. Otherwise, I’ll just write a small python file and build it to fulfill my purposes (which is changing input only).

To replicate my test run this in a bash terminal:


IP= #your speakers ip address

echo -ne "\x53\x30\x81\x1c\xf7" > /dev/tcp/${IP}/50001

echo -ne "\x53\x30\x81\x1b\x00" > /dev/tcp/${IP}/50001

3 Likes

I didn’t expect to get much when I Googled HA and LS50W but what do you know!

Brilliant sniffing, thanks man! I can confirm that those two values work for me on my LS50W, switching to PC and OPT.

I was planning on using a Xiaomi IR blaster (which I already bought unfortunately) to switch inputs but this is so much better.

I don’t suppose it’s possible to switch it on/off through the network too? Is it possible to set a specific volume or just up/down?

Thanks!!

Hi, nice to see that someone else also want these speakers to work with HA :slight_smile:

I don’t think you can turn on/off the speakers over the network, because it disconnects the network when turned off. I use IR for turning it on and off. It might be possible to set the volume to a specific number rather than sending “volume up” or “volume down” commands, since this can be done in the app. But, since I only need to change between PC and OPT inputs and there were no initial reaction from the community when I posted this, I haven’t made any further investigation/network sniffing.

Hey,

You’re right about turning on, that seems impossible. You can turn off from within Kef Control app though by clicking on the currently selected input.

I tried using Wireshark to try and complete some values (switching to Wireless input would be nice) but I don’t see anything!
I listened using my Macbook’s wireless interface to my iPhone’s IP. I then clicked some of the inputs, but Wireshark logged nothing. Any tips? :slight_smile:

Hi,

Nice that you are trying to get some messages. I can look at it during the weekend to see exactly how I did. But in general, I hooked up my iPhone to my mac with usb, and ran a script that enabled wireshark to listed to the usb interface that the iPhone was connected to.

Will check exactly how and reply to you here. Maybe I’ll try to get more message while I’m at it :slight_smile:

Love what you are doing.
Volume control would be cool too.

I agree. I don’t think real volume control is available though :frowning: Just up or down. Not setting of a value.

Hope this helps guys! Thanks for the Wireshark tips @Gronis :slight_smile:
Being able to turn it off rather than toggle is very interesting for me. As for volume, there must be a way to calculate what hex to use for a given input number but I have no idea how to go about doing that. So for the moment it’s pretty clunky.

0x5330819b0b this turns the LS50 off.
echo -ne “\x53\x30\x81\x9b\x0b” > /dev/tcp/{IP}/50001

This sets my volume to 60:
echo -ne “\x53\x25\x81\x3c\x94” > /dev/tcp/{IP}/50001

This sets my volume to 59:
echo -ne “\x53\x25\x81\x3b\x63” > /dev/tcp/{IP}/50001

This sets my volume to 55:
echo -ne “\x53\x25\x81\x37\xbb” > /dev/tcp/{IP}/50001

This sets my volume to 25:
echo -ne “\x53\x25\x81\x19\xaa” > /dev/tcp/{IP}/50001

This sets my volume to 15:
echo -ne “\x53\x25\x81\x0f\xf4” > /dev/tcp/{IP}/50001

This sets my volume to 0 (not mute):
echo -ne “\x53\x25\x81\x00\x1a” > /dev/tcp/{IP}/50001

Volume to 13:
echo -ne “\x53\x25\x81\x0d\x59” > /dev/tcp/{IP}/50001

29:
echo -ne “\x53\x25\x81\x1d\x6b” > /dev/tcp/{IP}/50001

58:
echo -ne “\x53\x25\x81\x3a\xf8” > /dev/tcp/{IP}/50001

Mute! (kind of, see post later on)
echo -ne “\x53\x25\x81\x8a\xa5” > /dev/tcp/{IP}/50001

Unmute! [Edit: This just changes the volume to 10. Haven’t found a true mute toggle yet] (see further below)
echo -ne “\x53\x25\x81\x0a\xae” > /dev/tcp/{IP}/50001

This changes to Wireless input:
echo -ne “\x53\x30\x81\x12\x82” > /dev/tcp/{IP}/50001

This changes to Bluetooth:
echo -ne “\x53\x30\x81\x19\xad” > /dev/tcp/{IP}/50001

This changes to Aux:
echo -ne “\x53\x30\x81\x1a\x9b” > /dev/tcp/{IP}/50001

1 Like

I just realised that for the volume the penultimate hex code is the volume level. E.g. 3c = 60. Not sure what the part after it means though. It would be nice if we could find a way to get the current volume level too.

OK I was just playing around and you can set the volume to anything you like by doing this command! I think the last hex code doesn’t really matter that much (this one was used to set the vol to 0 initially). Change “50” here to the vol value:
echo -ne "\x53\x25\x81\x$(echo "obase=16; 50" | bc)\x1a" > /dev/tcp/{IP}/50001

1 Like

OK I’m feeling pretty pleased with myself right now. Volume level!!

echo "ibase=16; $(echo -ne "\x47\x25\x80\x6c" | nc -w 1 192.168.1.49 50001 | hexdump -s 3 -n 1 -v -e '/1 "%02X "')" | bc

For info, we can figure out is_muted: it’s when volume is set to 160 (with the remote). (Kind of but not really, see below).

In Wireshark we can see that when we load up the Kef Control app the iPhone sends off a bunch of queries for the values in the app, and we can follow that TCP thread:

In this case I queried the second hex value (which I suspected was volume level after I saw 3c = 60, and I had volume at 60 in the app). The input hex is sent to netcat, which waits for a reply for 1sec then hexdump grabs the penultimate byte of the response and we ask bc to convert that back into decimal.

1 Like

Sorry about the flood of consciousness posts, but whatever.

So the way mute works is you add 128 to whatever your volume is. To unmute you subtract 128. So in fact any vol level value >= 128 is “mute”.

An interesting bug I found with these as I was testing this all out is that volume rolls over with the remote. If you go to 0, then click “-” on the remote, the volume rolls over to 255 and so your volume goes to max lol.

1 Like

Great find chimpy! With all this info, it would probably be quite easy to make a proper kef speaker integration with home assistant. Not sure if it is worth it though x). It’s a shame though that it is not possible to turn on the speakers with the app. Kef recently released a new pair of “smart speakers”: Kef LSX which also uses the same software stack, and I think this speaker has support for turning it on and off through the app. If it’s not a hardware issue, and we are lucky, it might be possible that kef releases a new firmware upgrade with support for this on the LS50W.

Are there any more features that is necessary for the media_player plugin that the kef LS50W is able to do through the app?

Most probably! I lack any sort of Python experience unfortunately. And yeah, I think that there are not that many of us haha. A proper component would be awesome though, specifically for volume level.

I’m converting what I found here into a pseudo component via the Universal Media Player component. I don’t think I’ll be able to get setting volume working though.

I saw that! I tried sending it a WOL packet just in case but no luck lol. I really wish they’d just open the API. That would be very cool.

Hey all. Thanks for finding these commands. I will try to develop a custom media_player component for the LS50. I have some basic python knowledge. I think it cannot be that hard. Likely it will not be perfect right away.

1 Like

That would be super cool! Let us know when you get around to drawing something up so we can help test!

Nice! Post a link to the repository so I can contribute as well :slightly_smiling_face: I’m well experienced with python :slightly_smiling_face:

1 Like

@Gronis: I could really use some help.
I am struggeling to sent any command to the LS50 using python.

The following code should be a replacement for

echo -ne “\x53\x30\x81\x1c\xf7” > /dev/tcp/192.168.178.52/50001

My code fragment is as follows. It would be cool if someone could help make it work:

from socket import *
from sys import *
import struct
import binascii

## Set the socket parameters
host = ‘192.168.178.52’
port = 50001

## Create socket
UDPSock = socket(AF_INET,SOCK_DGRAM)

## Send messages
MESSAGE = b’\x53\x30\x81\x1c\xf7’
ret = UDPSock.sendto( MESSAGE,(host,port))
print (“Number of bytes sent:” + str(ret))

## Close socket
UDPSock.close()

I dumped a few hours trying to sent a TCP command to the LS50. No success.

Once this works, one only needs to implement the MediaPlayerDevice interface. I found an easy example that can be used as a template:
https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/media_player/volumio.py

Ok. Finally, I am able to send basic commands to the LS50 using Python:

from socket import *

host = ‘192.168.178.52’
port = 50001

with socket(AF_INET, SOCK_STREAM) as s:
s.connect((host, port))
MESSAGE = bytes([0x53, 0x30, 0x81, 0x1c, 0xf7])
s.sendall(MESSAGE)

I managed to make a first (very early) proof of concept of the media_player integration of the LS50. I managed to read and set volume and have HA set volume.

I think I can have something useful in 7 days. Let’s see how much spare time I have this week.

1 Like