Philips Android TV component

after upgrading to 81.0 i got the error:

Update for media_player.tvbeneden fails
Traceback (most recent call last):
File “/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py”, line 221, in async_update_ha_state
await self.async_device_update()
File “/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py”, line 349, in async_device_update
await self.hass.async_add_executor_job(self.update)
File “/usr/local/lib/python3.6/concurrent/futures/thread.py”, line 56, in run
result = self.fn(*self.args, **self.kwargs)
File “/usr/local/lib/python3.6/site-packages/homeassistant/util/init.py”, line 324, in wrapper
result = method(*args, **kwargs)
File “/config/custom_components/media_player/philips_2016.py”, line 220, in update
self._tv.update()
File “/config/custom_components/media_player/philips_2016.py”, line 301, in update
self.getChannel()
File “/config/custom_components/media_player/philips_2016.py”, line 319, in getChannel
self.app_name = app[“label”]
KeyError: ‘label’

It is working by the way :wink:

@Emilio_Emile
do you already have the newest version?
I had a bug when your TV was in the Home Menu (Leanback Launcher) as no label is reported then
Pls check if you have the newest from GitHub:

I have the same issue and use the latest version. Actually, it was before I updated to 0.81.0.

2018-10-28 12:18:40 ERROR (MainThread) [homeassistant.helpers.entity] Update for media_player.philips_tv fails
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 221, in async_update_ha_state
    await self.async_device_update()
  File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 349, in async_device_update
    await self.hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.6/site-packages/homeassistant/util/__init__.py", line 324, in wrapper
    result = method(*args, **kwargs)
  File "/config/custom_components/media_player/philips_2016.py", line 220, in update
    self._tv.update()
  File "/config/custom_components/media_player/philips_2016.py", line 301, in update
    self.getChannel()
  File "/config/custom_components/media_player/philips_2016.py", line 319, in getChannel
    self.app_name = app["label"]
KeyError: 'label'
2018-10-28 12:18:47 ERROR (MainThread) [homeassistant.helpers.entity] Update for media_player.philips_tv fails
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 221, in async_update_ha_state
    await self.async_device_update()
  File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 349, in async_device_update
    await self.hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.6/site-packages/homeassistant/util/__init__.py", line 324, in wrapper
    result = method(*args, **kwargs)
  File "/config/custom_components/media_player/philips_2016.py", line 220, in update
    self._tv.update()
  File "/config/custom_components/media_player/philips_2016.py", line 301, in update
    self.getChannel()
  File "/config/custom_components/media_player/philips_2016.py", line 319, in getChannel
    self.app_name = app["label"]
KeyError: 'label'

quick fix:

    def getChannel(self):
    if self.on:
        rr = self._getReq('activities/current')
        if rr:
            if rr["component"]["packageName"] == "org.droidtv.zapster":
                r = self._getReq('activities/tv')
                self.channel_id = r.get("channel", {}).get("preset")
                self.channel_name = r.get("channel", {}).get("name")
                self.media_content_type_1 = "channel"
            else:
                self.media_content_type_1 = "app"
                pkgName = rr.get("component", {}).get("packageName")
                if pkgName == 'com.google.android.leanbacklauncher':
                    self.app_name = 'LeanbackLauncher'
                    self.channel_name = self.app_name
                else:
                    app = self.pkgNameToApp.get(pkgName, {})
                    self.app_name = app["label"]
                    self.channel_name = self.app_name

Is the syntax correct? I get errors when I try to replace the cod with this fix.

What kind of error do you get? I only added

if self.on:

You would need to add the correct spacing:

def getChannel(self):
  if self.on:
    rr = self._getReq('activities/current')
    ......

Thanks @JSON_v62 for the neat fix :slight_smile:

I will build some better handling of the ON/OFF state in the next version, also including your improvements @Molodax

Thank you. I’m looking forward to seeing the updated version since couldn’t implement the fix even with the correct spacing.

Hi, I’ve noticed a problem after I made the chromecast built in always available the TV doesn’t disconnect from the network. I’ve it connected via a LAN cable and now the component doesn’t detect the tv as online/powered on.

If I restart Home assistant with the TV powered on than the component detects that the TV is on and displays the correct source.

The on/off detection is flawed. The next iteration will improve this. @JSON_v62 did some awesome work on that and shared it with me. I will release the updated stuff this evening probably. Wanted to do some more tests with Wake-On-LAN (or WLAN) to see if I can get that to work for me.

2 Likes

Please post ideas or errors here, so we can make this better

Time for a new iteration/version (most new findings come from @JSON_v62):

  • Improve power state handling a lot thanks to the /powerstate command
  • Use wake-on-lan to wake the TV when in standby (for this to work: add mac to your config and enable WoWLAN, see below)
  • Fixed some app[‘label’] errors and other improvements and fixes

The handling of the powerstate is still not perfect and may not update very quickly for now. Please share if you encounter wrong behavior of the component.

To be able to turn your TV On from Standby you have to:

  • connect it to Wifi (That’s at least what worked for me, maybe there is a way to make it work for LAN)
  • enable WoWLAN under Settings->Wireless&Networks->Wired&Wifi->Switch on with Wi-Fi (WoWLAN)
  • add a line with the Wifi MAC address to your config, e.g.:
media_player:
  - platform: philips_2016
    name: TV
    host: 192.168.1.111
    mac: aa:aa:aa:aa:aa:aa
    username: xxxxx
    password: xxxxx

As always you can find the updated component here:

1 Like

Ideas to further improve this component:

  • Add full support to discovery, including generating user/pw and finding out Mac address
    It should be possible with only the IP to get system information. Then pair the TV. And then get the Mac address needed for WoWLAN using the /network/devices command.

  • Using the API it is currently not possible to check whether a video is playing or paused. A LOT of commands are possible through ADB (Android Debug Bridge), which is fairly easy to turn on. I already found some commands that could at give info about what app is currently playing
    adb shell dumpsys media_session for those curious
    This could actually be it’s own plugin, e.g. a component for controlling Android devices through ADB

@nstrelow Thank you for the quick reply and the quick relase. I just wanted to pin point this because the component was working great for 3 months.

Thank everyone who is working on this component it’s been a saver as I have replaced my Sony lcd with Philips Oled.

i tried the new component… but what i can see is… that when the TV is on and an App is loaded (like videoland)… it is not updating anymore:

Update for media_player.philips_tv fails
Traceback (most recent call last):
File “/usr/src/app/homeassistant/helpers/entity.py”, line 221, in async_update_ha_state
await self.async_device_update()
File “/usr/src/app/homeassistant/helpers/entity.py”, line 349, in async_device_update
await self.hass.async_add_executor_job(self.update)
File “/usr/local/lib/python3.6/concurrent/futures/thread.py”, line 56, in run
result = self.fn(*self.args, **self.kwargs)
File “/usr/src/app/homeassistant/util/init.py”, line 324, in wrapper
result = method(*args, **kwargs)
File “/config/custom_components/media_player/philips_2016.py”, line 226, in update
self._tv.update()
File “/config/custom_components/media_player/philips_2016.py”, line 309, in update
self.getChannel()
File “/config/custom_components/media_player/philips_2016.py”, line 331, in getChannel
self.app_name = app[“label”]
KeyError: ‘label’

Oh well, I was sure I fixed it, but forgot to upload it. FIXED IT NOW!
https://github.com/nstrelow/ha_philips_2016/blob/master/philips_2016.py (Haven’t test run it, as I am not home, should work, but no guarantees)

This essentially happens when an activity/app is displayed, which is not included in /applications.
Examples are “NA” or “LeanbackLauncher”. Somehow you trigger more examples, that’s why now if the app is not included in applications, just the packageName is displayed.

So:
If there is an app name, this name is displayed
If not, the packageName (com.android.google.youtube) or something else is displayed.
Please share what is displayed otherwise, I would love to know what other exceptions there are

Can this be something https://github.com/home-assistant/home-assistant/pull/16975 in regard to further improvements to check whether a video is playing or paused? It looks like it is still in progress, so maybe you @nstrelow could contribute to it so it would work with new Philips Tvs too?

sure I will check my apps and post the package name here…

I made some changes to the source because I think the powerstate is not function correct. And I can’t turn on the television etc.
I checked the older versions and I’m working now with the StateC.

from homeassistant.const import (CONF_HOST, CONF_MAC, CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
STATE_OFF, STATE_ON, STATE_IDLE, STATE_UNKNOWN, STATE_PLAYING, STATE_PAUSED)

def init
self._StateC = None

def StateC(self):
“”“Return the device name.”""
return self._StateC

def update(self):
self._StateC = self._tv.StateC
if self._StateC == ‘On’:
self._state = STATE_ON
elif self._StateC == ‘Standby’:
self._state = STATE_OFF
else:
self._state = STATE_OFF

def getStateC(self):
    r = self._getReq('powerstate')
    if r:
        self.StateC = r['powerstate']


def turn_on(self):
    """Turn on the device."""
    #self._tv.setPowerState('On')
    i = 0
    self.wol()
    self._tv.sendKey('Standby')
    self._state = STATE_ON

If you want my file just say it.

videoland: org.droidtv.nettvbrowser
RTL XL: org.droidtv.nettvbrowser
KIJK: org.droidtv.nettvbrowser
NPO: org.droidtv.nettvbrowser

1 Like

Renamed StateC to on, as I have no idea why it was called StateC
Also the new version is also using /powerstate, and setting the state in getState(). Exactly the same way you are doing it:

def getState(self):
        r = self._getReq('powerstate')
        if r:
            self.on = r['powerstate'] == 'On'
        else:
            self.on = False
...
if self._tv.on:
    if self._state == STATE_OFF or self._state == STATE_UNKNOWN:
        self._state = STATE_IDLE
else:
        self._state = STATE_OFF

Ahh this explains it. This is a different internal app, which does not have a label. How do you use this NetTV browser?
This is not just an app you get from the Play Store right? Is it a Philips TV specific app?