Kef ls50 Wireless

Thanks! I reinstalled the module with HACS, and did the directory renaming, and the configuration change to match the new name.

The module doesn’t come up and throws this error in the log:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config.py", line 760, in async_process_component_config
    platform = p_integration.get_platform(domain)                             File "/usr/src/homeassistant/homeassistant/loader.py", line 265, in get_platform
    f"{self.pkg_path}.{platform_name}"
  File "/usr/local/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/config/custom_components/kef_custom/media_player.py", line 8, in <module>
    from custom_components.media_player.kef_custom.aiokef import AsyncKefSpeaker
ModuleNotFoundError: No module named 'custom_components.media_player'

Is there anything else that I need to rename?

Also here’s my config:

- platform: kef_custom                                                        host: 192.168.1.16
    type: LS50                                                                  
    name: KEF LS50W            
    standby_time: 60          
    # supports_on_off: False

Do I need to uncomment the last line?

I modified line 8 in kef_custom/media_player.py as follows, and then line 12 started to error out, I tried different things, the below fixed the error in the log:


"""Platform for the KEF Wireless Speakers."""                                                                                                           from datetime import timedelta
from functools import partial
import ipaddress     
import logging
                  
                       
from custom_components.kef_custom.aiokef import AsyncKefSpeaker
from getmac import get_mac_address
import voluptuous as vol

from homeassistant.components.media_player import (
    PLATFORM_SCHEMA,                                                            SUPPORT_SELECT_SOURCE,                                                      SUPPORT_TURN_OFF,                                                           SUPPORT_TURN_ON,
    SUPPORT_VOLUME_MUTE,
    SUPPORT_VOLUME_SET,
    SUPPORT_VOLUME_STEP,
    MediaPlayerDevice,
)

Now the kef component initialize, but behaves strangely. With the speakers off, Lovelace shows a bunch of errors in the log, like this one

 2020-01-18 12:51:20 ERROR (MainThread) [frontend.js.latest.202001080] http://192.168.1.5:8123/frontend_latest/chunk.ccd8efa7511bc7ce6031.js:2714:2342 Uncaught TypeError: Cannot read property 'entity_id' of undefined

And the kef card display doesn’t display as off

It looks like you somehow downloaded an old version…

With the current version on GitHub that error shouldn’t happen.

See the code here.

Also the config you posted isn’t correctly indented.

It should be

- platform: kef_custom                                                        host: 192.168.1.16
  type: LS50                                                                  
  name: KEF LS50W            
  standby_time: 60          
  supports_on_off: false

Thanks Bas. The indentation issues are just a fluke of copy/pasting with my android phone, it’s ok.

I took the code of the file and replaced media_player.oy in the custom component. The error in line 8 came back.

/config/custom_components/kef_custom/media_player.py", line 8, in <module>
    from custom_components.media_player.kef_custom.aiokef import AsyncKefSpeaker
ModuleNotFoundError: No module named 'custom_components.media_player'

Do I need to rename anything inside the manifest? I only renamed the component directory

Oh I am so sorry, I forgot to update the code. It is indeed wrong … sorry for wasting your time.

I will update it ASAP.

Ni worries at all and thanks again for the effort. Let me know when ready and I will copy/paste what’s needed inside the custom components files

I think this change should be sufficient:

Tested

Without the line

supports_on_off: false

The behavior is the same as before. When turning off the speaker, the component goes to “Unavailable”

Adding the config line above, the On/Off button in the lovelace card disappears, however after turning off (manually) the speakers, the state show is again Unavailable instead of off as shown below, so basically the same as before. Can you use a ping-type probe to determine on/off state? or remove the “Unavailable” state and replace with off?

image

Does the speaker become Unavailable both after turning them off with HA and manually?

Also, I updated the integration to not support turning off AND on. However, turning off might be supported?

Are there other issues?

With supports_on_off set to False, the card takes a few minutes (2? - some sort of timeout) after I manually to go from ON to Unavailable state

With supports_on_off set to True, if I press the power icon in HA while the KEFs are On, they turn off as expected, so powering off remotely works fine. The Card state behaves as above though: it keeps showing ON even if the KEFs are off, for a few minutes, and then it goes to Unavailable.

In both cases, if I turn ON the KEFs manually, the card will take a few minutes to go from Unavailable to ON.

In no case the state is set to Off. It’s either ON or Unavailable.

All other features work very well. Setting the input, muting, changing volume, auto-off timer all works great.

The only issue I found is with Off state detection, not working well.

The following error appears in the Log:

2020-01-18 17:53:50 ERROR (MainThread) [aiokef.aiokef] Timeout in waiting for reply                                                                     2020-01-18 17:57:53 ERROR (MainThread) [homeassistant.helpers.entity] Update for media_player.kef_ls50w fails
Traceback (most recent call last):                                            File "/usr/local/lib/python3.7/site-packages/aiokef/aiokef.py", line 131, in open_connection
    task, timeout=_TIMEOUT                                                    File "/usr/local/lib/python3.7/asyncio/tasks.py", line 449, in wait_for       raise futures.TimeoutError()
concurrent.futures._base.TimeoutError                                                                                                                   The above exception was the direct cause of the following exception:
                                                                            Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/tenacity/_asyncio.py", line 57, in call
    result = yield from fn(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/aiokef/aiokef.py", line 197, in send_message
    await self.open_connection()
  File "/usr/local/lib/python3.7/site-packages/aiokef/aiokef.py", line 143,
in open_connection
    raise ConnectionRefusedError("Speaker is offline.") from e
ConnectionRefusedError: Speaker is offline.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):                                            File "/usr/local/lib/python3.7/site-packages/tenacity/_asyncio.py", line 5
7, in call
    result = yield from fn(*args, **kwargs)                                   File "/usr/local/lib/python3.7/site-packages/aiokef/aiokef.py", line 323,
in get_volume_and_is_muted
    volume = await self._comm.send_message(COMMANDS["get_volume"])            File "/usr/local/lib/python3.7/site-packages/tenacity/_asyncio.py", line 5
4, in call
    do = self.iter(retry_state=retry_state)
  File "/usr/local/lib/python3.7/site-packages/tenacity/__init__.py", line 351, in iter                                                                     six.raise_from(retry_exc, fut.exception())                                File "<string>", line 3, in raise_from                                    tenacity.RetryError: RetryError[<Future at 0x71757730 state=finished raised ConnectionRefusedError>]

The above exception was the direct cause of the following exception:
                                                                            Traceback (most recent call last):                                            File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 279, in async_update_ha_state                                                         await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 459, in async_device_update
    await self.async_update()                                                 File "/config/custom_components/kef_custom/media_player.py", line 186, in async_update
    ) = await self._speaker.get_volume_and_is_muted()                         File "/usr/local/lib/python3.7/site-packages/tenacity/_asyncio.py", line 54, in call
    do = self.iter(retry_state=retry_state)
  File "/usr/local/lib/python3.7/site-packages/tenacity/__init__.py", line 351, in iter
    six.raise_from(retry_exc, fut.exception())
  File "<string>", line 3, in raise_from                                    tenacity.RetryError: RetryError[<Future at 0x7181fa30 state=finished raised RetryError>]


OK thanks for letting me know!

I’ve changed the PR and the option will only be supports_on then :wink: (I didn’t update my custom_component yet).

The fact that it takes several minutes is a bit alarming, it should check if it can connect every 30 seconds.

The “Unavailable”, I am not sure how to solve. I will ask one of the Home Assistant core devs perhaps.

@ariel, is it possible to ping the speaker when it is off?

You can try ping 192.168.1.5 (change your speaker’s IP) in a terminal.

Yes, the Kef responds to pings when it’s on. And stops responding when off

$ ping 192.168.1.16
PING 192.168.1.16 (192.168.1.16): 56 data bytes
64 bytes from 192.168.1.16: seq=0 ttl=128 time=2.428 ms

Then it might not possible to distinguish between "off" and "Unavailable" in the case where supports_on=False .

See my post here.

FWIW there are many devices e.g. Kodi media players or wifi-enabled TVs behave like this with HA, where state is determined with keepalives, pings or HELLO-type messages and timeouts. I believe the Unavailable state is used for them only up until the device is first discovered by HA. Once it is discovered and included in the device registry for the first time, from that point onwards, a ping/HELLO timeout changes state to OFF, and Unavailable is never used again - and perhaps “unavailable” is actually never used for some devices, I don’t recall ever seeing it for my custom Kodi media player/server - whenever that machine auto-suspends HA shows it’s media-player card as Off.

Note that one of my Kodi media players/servers does NOT support wake-on-LAN so it’s pretty much the same use case as the KEFs. It can be turned off from HA but not ON. And state detection from HA works fine. Maybe that integration could serve for reference here?

Hi @basnijholt,

did you try to figure out the codes for play/pause for the KEF’s ? Also the codes for prev/next track which you can do in the control app? Last but not least a means to detect idle vs. playing state which right now is very difficult/impossible to get to. I have tried a few things creating a universal player also using a DLNA/Spotify player connected to the KEF and try to figure out state via those other media_player objects but it’s never complete.
Looks like there must be some way to get the proper state via the interface as the KEF control app can do it.

Anyway, if you haven’t looked for the codes for play/pause and prev/next track I will make an attempt to analyze network traffic to see if I can capture those codes (as a starting point for implementing them in the add-on). Maybe I can also find out if there is some communication going on that shows the idle/play state. Let me know if you already did some investigations.

On a separate note related to the on/off discussion above. I have a newer player with on/WOL support but have seen an interesting problem which I don’t fully understand yet but it might have to do with the HA integration. Normal behavior ist that after a power off the speaker turns off but the LAN port keeps being enabled for WOL functionality - you see it as the LEDs in the LAN connector keep blinking. I have now observed multiple times that all of a sudden the behavior changes such that on power off the LAN port also gets shut off completely (no blinking anymore) - thereby disabling WOL. This is then sticky over further on/off’s via the remote or keypad or even full power cycles (pull plug).
The only way I have found to be able to reenable WOL is by tinkering with the timeout period in the KEF control app. Switch it to different values a couple times and the WOL feature eventually comes back.
I have talked to KEF support, they are not aware of such a bug.
What I have done a few days ago now is to comment out the timeout period setting in the KEF integration. Since then I haven’t seen this problem anymore. It may be too early to say it has anything to do with this - so I will keep watching out for this issue. If it doesn’t come back I will revert the config change and see if it then happens again.

Thought I post this here in case someone else has seen similar behavior.

Other than that - great work and many thanks for making the KEF’s even more valuable (besides being fantastic speakers).

Looks like there must be some way to get the proper state via the interface as the KEF control app can do it.

I think there is no way of telling it from just the speakers. The way it happens (I assume) is that the speaker knows it’s playing e.g., Spotity, and then it queries its API for the state.

But I do have to say that I didn’t look for the codes really, so if you manage to figure it out, then I will definitely put it in the integration!

About your other problem, do you perhaps have a standby_time of 20 minutes? If so, I had a problem when I had to power cycle the speakers too when I had 20 minutes selected. It is a bug with the speakers itself, because it happens even with the app.

If you also experienced that problem, someone should probably notify KEF and I will disable that setting in the integration for the time being (or I can hack around it if I find the motivation).

The only way I have found to be able to reenable WOL is by tinkering with the timeout period in the KEF control app. Switch it to different values a couple times and the WOL feature eventually comes back.

Sir, I owe you a beer for this tip. Never been able to power the speakers from the app and it has been driving me insane since I got the speakers in September. It now seems to be working.
Thank you so much :pray:

Hi Renato. You are welcome. Glad my comments helped you to get the WOL feature going. I still have to fully understand a) the root cause of the issue and b) what exactly the remedy is. It’s a bit of trial and error right now. My current state is that I have the timeout disabled completely - and then have an HA automation that turns them off at least at night time. This seems to work reliably. Next is to set a timeout via the KEF Control App again and see how that goes. Last but not least re-enable the timeout setting in the KEF integration (again not sure if that really has an influence at all). If I 'm lucky I figure out the pattern to reproduce the issue.