Hobby projects → LG TV inputs
WRITTEN 7 OCTOBER 2026 · HOME ASSISTANT 2026.9.4
Home Assistant · webOS · AV control

Switching LG TV inputs that actually sticks

Ask Home Assistant to put an LG webOS TV on HDMI 2 the obvious way and, some evenings, the TV opens a streaming app instead. This page explains why, gives the method that works — launching the input as the app it secretly is, repeatedly, until the state agrees — and ends with a full script that takes a games console from off to playing on screen, receiver included, and only ever reports what it has verified.

The trap

On webOS, every HDMI input is an application — com.webos.app.hdmi1, hdmi2 and so on — and the TV’s source list mixes those input-apps with the real apps. media_player.select_source matches against that mixed list, and depending on what the TV reports at that moment, “select HDMI 2” can resolve to launching whatever app the TV last fancied. The second trap is timing: a webOS TV that has just woken accepts commands before it will act on them, so a single switch sent once lands in the void. And the third is the cruellest: Home Assistant’s webOS integration returns success for service calls against a TV whose websocket has silently dropped — the call “worked” and nothing happened.

The rule that falls out: never use media_player.select_source for an HDMI input on an LG, and never trust a single fire-and-forget command. Launch the input as an app, in a loop, and let the entity’s own state decide when you are done.

The method, minimal

The whole trick in one small script: turn the TV on (harmless if it already is), then launch the HDMI app every two seconds until the TV reports itself on. Replace the entity id with your TV’s and the hdmi2 with the input you want.

A MINIMAL INPUT SWITCH · scripts.yaml
select_hdmi2:
  alias: Select HDMI 2
  mode: single
  sequence:
    - action: media_player.turn_on
      target:
        entity_id: media_player.lg_webos_tv
      continue_on_error: true
    - repeat:
        until:
          - condition: or
            conditions:
              - condition: state
                entity_id: media_player.lg_webos_tv
                state: "on"
              - "{{ repeat.index >= 15 }}"
        sequence:
          - action: media_player.turn_on
            target:
              entity_id: media_player.lg_webos_tv
            continue_on_error: true
          - delay:
              seconds: 2
    - action: webostv.command
      data:
        command: system.launcher/launch
        payload:
          id: com.webos.app.hdmi2
      target:
        entity_id: media_player.lg_webos_tv
      continue_on_error: true

Two details carry the weight. media_player.turn_on on a webOS entity sends Wake-on-LAN when the TV is off — so the loop doubles as the wake path, and re-sending it while the TV boots is exactly what a marginal first packet needs. And continue_on_error everywhere means a TV mid-boot never aborts the script; the loop simply tries again.

The full pattern: console, receiver, TV, verified

Real requests are “turn on the PlayStation”, which means three devices in concert: wake the console, wake the TV, put the AV receiver on the console’s input, put the TV on the receiver’s HDMI — and keep pressing all of it until the receiver reports the right input and the TV reports on, or a 50-second budget runs out. The script below is the production version from our own living room, exposed to a voice assistant; it returns a sentence to speak that never claims more than the states showed, in whichever of three languages the request came in. Swap the four entity ids and the input names for yours.

THE WORKED EXAMPLE · scripts.yaml
select_ps5:
  alias: Select PS5
  icon: mdi:sony-playstation
  mode: single
  description: >-
    Turns the PlayStation 5 ON for the living room, end to end: wakes the console
    (switch.living_room_ps5_pro), turns on the LG TV and the receiver, then switches
    the receiver to its PlayStation 5 input and the TV to HDMI 2, retrying every 2 s
    (re-sending wake-on-LAN to the TV while it is off) until the receiver reports the
    PlayStation 5 input AND the TV is on (at most ~50 s). Use this for "turn on the
    PS5", "switch to the PlayStation", "I want to play" and their translations.
    Never use the bare console switch for these requests: it wakes the console but
    leaves the TV and receiver untouched. Returns a sentence to speak verbatim; do
    not say the PlayStation is on unless it is the returned message.
  fields:
    language:
      name: Language
      description: "Language of the sentence to return: en, th or zh."
      selector:
        select:
          options:
            - en
            - th
            - zh
      default: en
  sequence:
    - action: switch.turn_on
      target:
        entity_id: switch.living_room_ps5_pro
      continue_on_error: true
    - action: media_player.turn_on
      target:
        entity_id: media_player.lg_webos_tv_oled77c1ptb
      continue_on_error: true
    - action: media_player.turn_on
      target:
        entity_id: media_player.living_room
      continue_on_error: true
    - repeat:
        until:
          - condition: or
            conditions:
              - condition: and
                conditions:
                  - condition: state
                    entity_id: media_player.living_room
                    attribute: source
                    state: PlayStation 5
                  - condition: state
                    entity_id: media_player.lg_webos_tv_oled77c1ptb
                    state: "on"
              - "{{ repeat.index >= 25 }}"
        sequence:
          - if:
              - condition: not
                conditions:
                  - condition: state
                    entity_id: media_player.lg_webos_tv_oled77c1ptb
                    state: "on"
            then:
              - action: media_player.turn_on
                target:
                  entity_id: media_player.lg_webos_tv_oled77c1ptb
                continue_on_error: true
          - action: media_player.select_source
            data:
              source: PlayStation 5
            target:
              entity_id: media_player.living_room
            continue_on_error: true
          - if:
              - condition: state
                entity_id: media_player.lg_webos_tv_oled77c1ptb
                state: "on"
            then:
              - action: webostv.command
                data:
                  command: system.launcher/launch
                  payload:
                    id: com.webos.app.hdmi2
                target:
                  entity_id: media_player.lg_webos_tv_oled77c1ptb
                continue_on_error: true
          - delay:
              seconds: 2
    - if:
        - condition: state
          entity_id: media_player.lg_webos_tv_oled77c1ptb
          state: "on"
      then:
        - action: webostv.command
          data:
            command: system.launcher/launch
            payload:
              id: com.webos.app.hdmi2
          target:
            entity_id: media_player.lg_webos_tv_oled77c1ptb
          continue_on_error: true
    - variables:
        avr_ok: "{{ is_state_attr('media_player.living_room', 'source', 'PlayStation 5') }}"
        ps5_on: "{{ is_state('switch.living_room_ps5_pro', 'on') }}"
        tv_on: "{{ is_state('media_player.lg_webos_tv_oled77c1ptb', 'on') }}"
        result:
          message: >-
            {% set lang = language | default('en') %}
            {% if avr_ok and ps5_on and tv_on %}{{ {'en': 'The PlayStation is on and the TV is set to it.',
              'th': 'เปิดเพลย์สเตชั่นแล้ว และตั้งทีวีไปที่เพลย์สเตชั่นเรียบร้อยครับ',
              'zh': 'PlayStation 已开机,电视已切换到它。'}[lang] }}
            {% elif ps5_on and avr_ok %}{{ {'en': 'The PlayStation and receiver are on, but the TV did not wake up. Press the TV power button.',
              'th': 'เพลย์สเตชั่นและรีซีฟเวอร์เปิดแล้ว แต่ทีวียังไม่ติด กรุณากดปุ่มเปิดทีวีครับ',
              'zh': 'PlayStation 和功放已开机,但电视没有唤醒。请按电视电源键。'}[lang] }}
            {% elif ps5_on %}{{ {'en': 'The PlayStation is awake, but the receiver did not switch to the PlayStation input. Try again or use the remote.',
              'th': 'เพลย์สเตชั่นเปิดแล้ว แต่รีซีฟเวอร์ยังไม่สลับไปที่ช่องเพลย์สเตชั่น ลองสั่งอีกครั้งหรือใช้รีโมทครับ',
              'zh': 'PlayStation 已唤醒,但功放没有切换到 PlayStation 输入。请再试一次或使用遥控器。'}[lang] }}
            {% else %}{{ {'en': 'The PlayStation did not wake up. Check it is plugged in and on the network.',
              'th': 'เพลย์สเตชั่นไม่ตื่นขึ้นมา กรุณาตรวจสอบว่าเสียบปลั๊กและเชื่อมต่อเครือข่ายอยู่ครับ',
              'zh': 'PlayStation 没有唤醒。请检查是否已插电并连接网络。'}[lang] }}
            {% endif %}
    - stop: Done
      response_variable: result

The receiver side uses media_player.select_source — on a network AV receiver that is the right call, because receivers report and switch named inputs faithfully; it is only the LG’s HDMI selection that needs the app-launch route. Note the structure of the ending: the script reads the three states after the loop and builds its answer from them, with a branch for every honest outcome. A voice assistant given this script can tell the truth — including “press the TV power button” on the rare evening the panel ignores every wake packet.

Wiring it to a voice assistant

Expose the script, not the devices. The long description in the example is doing real work: it tells a language-model assistant exactly when to call the script, which phrasings it covers, and — just as important — what not to do (“never use the bare console switch”). The language field plus response_variable gives the assistant a ready sentence to speak, so it cannot improvise a success the hardware never delivered. One script per destination (select_ps5, select_shield, select_appletv…) keeps each description short and each verdict honest.

Watch out for