smart tv less dumb

Quick Project: Making my Smart TV Less Dumb

This post may contain affiliate links. Please see the disclaimer for more information.

The word “smart” has become so loaded in these days of smart-this and smart-that. The question is what qualifies as “smart”? Surely the answer is some form of Internet connectivity? However, I’m not sure that goes far enough. I like to see some degree of interoperability with other systems before I call a device smart.

For me the other system in question is Home Assistant. I’m not going to call a device truly smart unless there is a way to make it integrate with HASS. Of course, HASS has a lot of integrations which should make it easy right?

Not so for my “smart” TV (a 2017 model Sony Bravia) which fits neatly into a chasm between Sony’s previous Bravia offerings and their Android TV line. As such the integration in HASS doesn’t work with it, because the service it relies on is not available on the TV and it’s not running the truly smart Android TV OS.

Sony just seem to have slapped Netflix, YouTube and a couple of other apps on the previous TV software, disabled the network control service (presumably because it didn’t work with those apps) and sold these as Smart. Seems pretty stupid to me. It’s a shame, because otherwise it’s a really nice TV. It’s high time I made this Smart TV less dumb.

Getting Smart

I’ve written previously about how I’ve integrated power switching for the TV into HASS via HDMI CEC and Node-RED. Well recently I’ve made a couple of improvements to this which have increased it’s utility and made my Smart TV slightly less dumb.

The first of these was to add a ping sensor to report on the power state of the TV. It seems like the TV has pretty rudimentary (but in my opinion good) power management, since it responds to pings when on and doesn’t when in standby.

Here’s the YAML for that sensor:

binary_sensor:
  - platform: ping
    name: "Living Room TV state"
    host: !secret living_room_tv_host
    count: 1
    scan_interval: 15

Basically this is just pinging once every 15s. I kept the repetitions this low in order to ping more frequently and still keep the network traffic low. If a ping is lost I’m not too worried since the next one happens pretty quickly. Also the TV is on a wired Ethernet connection, so packet loss is very low (as compared to wifi).

I’ve fused this with my existing power switch in order to overcome some reporting weirdness from the CEC switch. It seems to me that the TV doesn’t always report it’s power state, especially when turned off via the remote.

Here is the template switch that integrates the two:

switch:
  - platform: template
    switches:
      living_room_tv_fused:
        value_template: "{{ is_state('binary_sensor.living_room_tv_state', 'on') }}"
        turn_on:
          service: switch.turn_on
          data:
            entity_id: switch.living_room_tv
        turn_off:
          service: switch.turn_off
          data:
            entity_id: switch.living_room_tv

This switch becomes the primary means for controlling and displaying the TV power state in HASS. Now it’s really reliable, with the caveat that it may not update the state immediately, due to the ping interval. This is something which I can live with because it will now show the correct state most of the time. Previously it showed the incorrect state most of the time!

Detecting Netflix

As I was port scanning the TV (what? you mean it’s just me that scans every device that comes into my house?), I noticed an that port 9080 was open. Some investigation proved that this port is opened by the Netflix app on the TV and low and behold, if I exit Netflix the port is closed.

This gives us a nice way to detect if Netflix is running on the TV. This is useful, because despite my protestations people in my household seem to want to use the native app rather than Kodi (instability of the Kodi plugin is one reason for this). This is unfortunate in that I can’t see the state in HASS and therefore have had to disable my automation to turn off the TV when nothing is playing, lest it switch off five minutes into a Netflix stream.

I used the command line binary sensor to detect the open port (thanks to VDRainer on the HASS community forums for helping me with an issue here):

binary_sensor:
  - platform: command_line
    name: "Living Room Netflix"
    command: '/usr/bin/nmap -p9080 <insert ip address> | /bin/grep open > /dev/null && (echo ON) || (echo OFF)'
    device_class: connectivity

Here we run an nmap command which will detect the open port, grep for the answer and output ON or OFF depending on the state. By default this will be run every minute, which is good enough for me. Unfortunately, I haven’t found a way to use secrets with the command, so you’ll need to insert the IP of the TV manually if you want to use this.

smart tv less dumb
The Netflix Sensor

This doesn’t give us any information on whether or what Netflix is playing, just that the app is open. That information is probably available via this port, since it seems to be running some kind of web service for remote control. Someone would need to do the relevant investigation to work out what the endpoints are though.

Putting It All Together

Now I can update my TV power off automation:

  - alias: 'Turn off TV if idle for 5 minutes'
    trigger:
      - platform: state
        entity_id: media_player.living_room_kodi
        to: idle
        for:
          minutes: 5
      - platform: state
        entity_id: binary_sensor.living_room_netflix
        to: 'off'
        for:
          minutes: 5
    condition:
      condition: and
      conditions:
        - condition: state
          entity_id: media_player.living_room_kodi
          state: idle
        - condition: state
          entity_id: binary_sensor.living_room_netflix
          state: 'off'
        - condition: time
          after: '20:00:00'
          before: '07:00:00'
    action:
      - service: switch.turn_off
        data:
          entity_id: switch.living_room_tv_fused
      - condition: and
        conditions:
          - condition: state
            entity_id: light.living_room_spots
            state: 'on'
          - condition: template
            value_template: '{{ states.light.living_room_spots.attributes.rgb_color == [0, 0, 255] or states.light.living_room_spots.attributes.rgb_color == (0, 0, 255) }}'
      - service: light.turn_off
        data:
          entity_id: light.living_room_spots

Here I’m triggering the automation if either the local Kodi player or the Netflix sensor are idle/off for 5 minutes. I also check that both of these are in the desired state in the conditions. The extra time condition is to account for the use of the TV YouTube app, which I can’t detect. It only tends to be used before 8pm, so I restrict the time that this automation runs just in case.

Conclusion

That actually turned out to be quite a long post for a ‘quick’ project! I’m pretty happy with this approach and it’s allowed me to bring back an automation which has been disabled for ages. Hopefully this can start saving some power again, since people still leave the TV on. Now if only I could detect that pesky YouTube app! Then I really will have made my smart TV less dumb, but not yet truly smart (at least as far as I’m concerned).

If you liked this post and want to see more, please consider subscribing to the mailing list (below) or the RSS feed. You can also follow me on Twitter. If you want to show your appreciation, feel free to buy me a coffee.