Kef ls50 Wireless

Could you perhaps check if it is what I mentioned in my last post?

I believe it only happens when standby_time: 20. It both happens in HA and with only using the app.

Hi @basnijholt, sorry, didn’t see your posting, just looked at the last one when responding to Renato.

Yes, I had 20 minutes set as timeout. Good (?) to see that I am not the only one having this problem. I will take the part talking to KEF as I already have a ticket with them open.

I will also see if I can do a network analysis to find some of the other codes. At least play/pause which would be handy to have.

Thx, Michael

Ok, here are 3 command sequences which work for play/pause, next track and prev track. There doesn’t seem to be individual play and pause commands, just a toggle. Also, the last byte can be 0x80 or 0x81 for the play/pause toggle. I don’t see a difference in behavior.
I have tested this with an earlier version of the KEF integration.

@basnijholt, should you add this to your implementation I can help test this. For completness, the WIFI firmware is p6.3001902221.105039422 on my speaker.

PLAY_PAUSE = bytes([0x53, 0x31, 0x81, 0x81]) # last byte 0x80 also seems to do the job
NEXT_TRACK = bytes([0x53, 0x31, 0x81, 0x82])
PREV_TRACK = bytes([0x53, 0x31, 0x81, 0x83])

Great work!

It seems to work for me too, I’ve added it to aiokef. I will add it to the KEF integration in HA too!

@mleiber, I have updated the KEF integration, see this PR :tada:

It works locally for me.

The only thing I am unsure about is whether the play, pause and next prev track are supported when playing over USB. I guess it’s not. Now I have implemented it such that the controls are only available when the source is either Bluetooth or Wifi.

Wow, that was quick :wink: . Re USB, don’t know either, I didn’t think about the source at all, just tried it with Wifi here. I will hook up my Macbook in the next days and check if it does any good to the USB source. I will use my ‘testbed’ as you wrote you already restricted the implementation to BT and Wifi/LAN.

I will continue make an attempt to figure out a way to detect the play/idle state of the player - I have some automations in mind where it would be handy to know the state and get triggers based on the state.

Thank you - I owe you something !

@basnijholt, I have temporarily copied your changes into a custom component and tested it - works nicely. Now only if one could figure out what the play state is so that e.g. the button in the media player UI shows the right thing!

1 Like

Unfortunately, dynamically changing the supported states isn’t allow, see this comment.

So no point in investigating whether it works with USB for now :stuck_out_tongue_winking_eye:

already done it ;-). play/pause, next/prev are non-operational on USB - as to be expected. I believe streaming thru USB is uni-directional only.

For those with the old hardware version that can’t be turned on via the App i.e. models where WiFi goes off when the unit is off, if you don’t want to see the “Unavailable” state in the UI and prefer On / Off, this can be done by tweaking media_player.py in this custom component.

modded in various places

import subprocess

....

#in the KEFMediaPlayer class:

    # inside  the init constructor
    ...
        """Initialize the media player."""
...
        self._host = host


    def pingDevice(self):
        """ping DEVICE - AR MOD"""
        cmd = ['ping', '-c1', '-W2', self._host ]
        response = subprocess.Popen(cmd, stdout=subprocess.PIPE)
        stdout, stderr = response.communicate()
        if response.returncode == 0:   
            return True
        else:
            return False

    @property
    def state(self):
        """Return the state of the device."""
        if not self.pingDevice():
            self._state = STATE_OFF
        return self._state

    @property
    def available(self):
        """Return if the speaker is reachable online."""
        # avoid 'unavailable' by returnining TRUE
        # and also set the state based on ping
        if not self.pingDevice():
            self._state = STATE_OFF
        return True

I could just add this to the actual integration itself.

I would just copy this logic.

@basnijholt that would be much better than my quick hack :slight_smile:
Note that to get this to behave in the expected way, you will need to tweak the available() method based on ping response, and you want to do this only for the old hardware (e.g. for people that disable the on/off control) that is not “always connected”. For the new hardware, your current logic makes sense.

Another exciting thing is coming!

I have added options to change all DSP settings for the KEF speakers! :tada:

See this PR, when it’s merged, we can change all settings that one can change in the KEF Control App.

1 Like

I seem to have lost my integration with the upgrade to 108. Anyone else?

2020-04-08 13:10:42 ERROR (MainThread) [homeassistant.components.media_player] Error while setting up kef platform for media_player
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 186, in _async_setup_platform
    await asyncio.gather(*pending)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 295, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 445, in _async_add_entity
    await entity.async_added_to_hass()
  File "/usr/src/homeassistant/homeassistant/components/kef/media_player.py", line 381, in async_added_to_hass
    self.hass, self.update_dsp, DSP_SCAN_INTERVAL
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 293, in async_track_time_interval
    remove = async_track_point_in_utc_time(hass, interval_listener, next_interval())
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 284, in next_interval
    return dt_util.utcnow() + interval
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and 'int'

That is correct! I made a mistake in the code, sorry.

I’ve already fixed it in this PR.

I also told balloob and he told me it will be in 0.108.1, which will be out very soon!

Ok, no worries. Thanks for the integration, it’s much better than using the KEF app. Much appreciated!

Not sure since when it happened, guess it came with the update to 0.108. I now see this frequently in the logs and given the function update_dsp() is mentioned it might have to do with the new feature to configure the KEF LS50 Wireless DSP.

async_track_point_in_utc_time.<locals>.point_in_time_listener(<Event time_c....008180+02:00>) at /usr/src/homeassistant/homeassistant/helpers/event.py:234
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 250, in point_in_time_listener
    hass.async_run_job(action, now)
  File "/usr/src/homeassistant/homeassistant/core.py", line 374, in async_run_job
    target(*args)
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 291, in interval_listener
    hass.async_run_job(action, now)
  File "/usr/src/homeassistant/homeassistant/core.py", line 376, in async_run_job
    self.async_add_job(target, *args)
  File "/usr/src/homeassistant/homeassistant/core.py", line 308, in async_add_job
    task = self.loop.create_task(target(*args))
TypeError: update_dsp() takes 1 positional argument but 2 were given

Thanks for reporting!

That definitely a bug!

Could you perhaps open an issue here?

will do this pm. Thx for the instant response.

Now that I’ve added all these services in the kef integration I can do:

Screen Recording 2020-06-15 at 16.42.46.mov

See this commit range to see the code that does this.

See my entire config at github/basnijholt/home-assistant-config.

2 Likes