top of page

The LG TV HA & WoL Caper

For most people in my household, the arrival of a shiny new TV meant a new, larger, more vivid screen to enjoy watching stuff on. And sure, going from a decade-old LCD to a modern OLED is a significant improvement, even before you consider UHD and HDR. But for me, a new device in the home means one thing above all else: How am I going to integrate it into Home Assistant?


Before I purchase anything these days, I check out the Home Assistant integrations list to check for device support. I tend to buy brands that are on the premium end of the scale as I expect a long service life and have had success with them in the past. With such brands you tend to get things like serial control ports, nowadays API access over a network, or perhaps apps that can be reverse engineered. Worst-case, IR remote control could be a fallback, but most devices offer a better solution. I would definitely think twice about making a major technology investment if it didn't have a reasonable way of integrating with Home Assistant.


My new TV is a C3 series model from LG. LG's recent TVs use their webOS Smart TV operating system, and of course, there's a Home Assistant integration for it. Great!


Home Assistant Integration


This was a piece of cake: Add the integration, enter the static IP address of the TV, click 'OK' on the TV when it asks if you want to allow control from a third-party, and presto!


By default, the integration adds a Media Player device to Home Assistant. You can then display a card for this on the GUI which displays the current input and volume. Tapping on this brings up the device details where you can change the volume and pick the input source from a dropdown. It works but the interaction is fiddly. Instead, I designed my own GUI with 'remote style' buttons.


I split this up into two sections:

  • Overall device control - power and input

  • Detailed control - navigation etc.


Overall Device


Navigation Control


Home Assistant Buttons

Each button calls a service on the Media Player device.


Power On

Not at all trivial and the reason for this whole blog post! See later on.


Power Off

Calls turn_off

- show_name: true
  show_icon: false
  name: Turn OFF
  type: button
  tap_action:
    action: call-service
    service: media_player.turn_off
    target:
      entity_id: media_player.sitting_room_tv

Source Selection

Calls select_source

- show_name: true
  show_icon: false
  name: Disney+
  type: button
  tap_action:
    action: call-service
    service: media_player.select_source
    target:
      entity_id: media_player.sitting_room_tv
    data:
      source: Disney+

The name of the source under data needs to match a source name configured in the integration. I ran into a frustration here because the TV has a propensity to rename its HDMI inputs depending on what it thinks is connected. I have an HDMI switch connected to HDMI1, so the device can change, and the TV will sometimes rename the input. The integration picks this up, fine, but because I have manually configured buttons to request a defined name, if the TV has renamed the "Sky Q" input to "Roku", obviously the input select fails. I have attempted to stop this behaviour by disabling HDMI-CEC on the TV and the devices, and turning off AirPlay on the TV. I also thought I could 'cheat' by scripting the 'HDMI1' button to send a request for each name the TV can pick for the input in the hope it manages to match at least one.


Navigation Buttons

Calls the webostv.button

- show_name: false
  show_icon: true
  type: button
  tap_action:
    action: call-service
    service: webostv.button
    target: {}
    data:
      entity_id: media_player.sitting_room_tv
      button: HOME
  name: HOME
  icon: mdi:home

By not using the Media Player card, I don't get access to the volume slider of the TV, but that's fine because I don't use this as I have an external sound bar. I did find I needed to add the TV's volume buttons, though, for when I have a bluetooth headset connected to the TV.


Sound Control

To partner with the C3 TV I also got the USC9S sound bar. This connects to the network via WiFi (wired is not available, sadly) to offer casting services. It also presents an API for LG's app, and the same API is driven by another Home Assistant integration. The integration doesn't list the USC9S as a compatible sound bar, but I took a chance that the API is the same. And it is - the integration works nicely.


I couldn't figure out a way to get the sound bar's volume control slider on the Home Assistant GUI, but practically I found that, most of the time, course volume adjustments are all I need so I created dedicated buttons for a handful of preset volumes. I also created buttons to switch between a few different sound modes after a process of trial-and-error to find the ones I felt were most applicable to my viewing habits:


Mute Button

- show_name: false
  show_icon: true
  type: button
  tap_action:
    action: call-service
    service: media_player.volume_mute
    target:
      entity_id: media_player.sitting_room_soundbar
    data:
      is_volume_muted: true
  name: MUTE
  icon: mdi:volume-mute

Once the sound bar is muted the integration seems unable to unmute it with the mute button. This might be a bug, actually, or perhaps a sign that the newer sound bar I'm using isn't totally compatible with the integration. I think the integration tracks the mute status and calls to 'mute' should toggle the status; if the status never reports as 'muted' it won't 'unmute'. I found that setting the volume will unmute the sound bar, though, which suffices for my needs.


Volume Button

- show_name: false
  show_icon: true
  type: button
  tap_action:
    action: call-service
    service: media_player.volume_set
    target:
      entity_id: media_player.sitting_room_soundbar
    data:
      volume_level: 0.15

Mode Button

- show_name: true
  show_icon: false
  type: button
  tap_action:
    action: call-service
    service: media_player.select_sound_mode
    target:
      entity_id: media_player.sitting_room_soundbar
    data:
      sound_mode: Standard

TV and Power On

Some devices keep their APIs running even when 'off". The LG TV is not one of them. If the TV is off the webOS integration can't control anything - so, how can it turn the TV on?


The integration's web page explains it needs a helper function, either HDMI-CEC or Wake on LAN (WoL). I can't immediately see how HDMI-CEC would work from Home Assistant, perhaps it would have to go via a connected device like a set-top box, but in any case I have disabled this in an attempt to stop the TV renaming inputs so it's not for me. So, Wake on LAN (WoL) it is.


What is Wake on LAN?

WoL is a venerable network protocol that is intended to allow devices to wake from a deep sleep when they receive a so-called 'magic packet' across the network. The device needs to keep its network interface running, but listening for a WoL 'magic packet' can be done by the interface electronics itself allowing the device to power all its higher-level functions (like the API) down. This is what the LG TV does.


To allow WoL to wake the TV, the TV needs to be configured to allow "waking from WiFi". Even, as is the case with me, I'm using wired Ethernet. There's a settings menu option for this. Once set, sending a 'magic packet' to the TV's MAC address does indeed turn the TV on - in fact it works really well!


Home Assistant and WoL

Home Assistant has a simple yet effective Wake on LAN integration. Firstly it has to be globally enabled in configuration.yaml:

# Example configuration.yaml entry
wake_on_lan:

There are examples of how to hook a WoL event into the Media Player's turn_on service, but I didn't bother, I just set up a dedicated button in the GUI to issue the WoL event directly.


For my "turn on" button I created a virtual Input Button Helper. This perhaps wasn't strictly necessary, because I could just call the wake_on_lan.send_magic_packet service from a GUI button, but having it as a virtual button felt neater to me.



Next I added an automation triggered off the Input Button. The automation triggers off a button event and calls the actual wake_on_lan.send_magic_packet service:

alias: Sitting Room TV On (WoL)
description: ""
trigger:
  - platform: state
    entity_id:
      - input_button.wol_tester
condition: []
action:
  - service: wake_on_lan.send_magic_packet
    data:
      broadcast_port: 9
      mac: 64:E4:CA:FE:CA:FE
      broadcast_address: 192.0.2.255
mode: single

And that's it!


WoL Service Configuration

The wake_on_lan.send_magic_packet service needs a few bits of configuration:

  • broadcast_port should be 9, because WoL uses UDP port 9 as standard (when in layer-3 mode, which is what Home Assistant supports).

  • mac is the MAC address of the TV's network interface, in my case the wired interface. This is sometimes printed on a label on the device but I got the information from my router's DHCP (dynamic IP) lease table.

  • broadcast_address is the IP address to which the WoL packet should be sent. WoL is a broadcast protocol so in most cases the IP address entered here should be the broadcast address of your subnet. This is the address one higher than the highest usable address and for most home cases the final octet of the address will be 255.


Full disclosure: The WoL in my system ended up rather more complicated than this, so much so that I have made a separate blog about it.


Conclusion

The LG webOS and sound bar integrations mean Home Assistant works very nicely with my LG setup, albeit with a bit of jumping through hoops to get the TV to turn on in the first place.


Comments


bottom of page