Context aware Harmony remote setup

Here’s my recently finished (is anything ever finished?) Harmony setup, maybe it’ll inspire or assist someone.

My setup
I have a simple harmony setup, mainly TV, Soundbar and Playstation.

In TV mode I might be watching a smart TV App or casting to a chromecast in one of the HDMI sockets. Unlike the other TV in my house CEC doesn’t work so I can’t control the chromecast with the TV (pause etc.) or the TV from chromecast (power on).

In music mode the TV is off (as is the chromecast as it’s powered by the TV’s USB), the soundbar is on and a Google Home hub pairs over bluetooth.

My family are easily confused and can never remember whether (for example) they have to press pause on the harmony remote or say “ok Google, pause chromecast” / use their phones to pause. So, I want home assistant to provide them with a single, context aware, remote control. So when they press pause / play / stop etc. it does it no matter what the source is.

It’s designed to look best on the various phones my family have, but the screen shots are from a desktop. This makes it look like a bit of a space waster :slight_smile:

Basically, there’s a vertical-stack-in-card with one picture-elements card at the top for the activities and 3 conditional picture-elements cards which so up depending on what activity is selected. Check code comments for more detail on that.

The buttons are styled using a YAML anchor to reduce the repetition and enable changes for all buttons to be made in one place.

The activity buttons are switches which lets me toggle activities on and off.
Most of the other buttons just run the remote.send_command to send the relevant Harmony command.

The Play, Pause and Stop buttons update an input_text field. When the state of this changes it triggers a node-red flow which works out exactly what needs to be played, paused or stopped.

The config’s below - I split mine using includes to keep things simple. But I’ve put the name of the “master” file against each element for those that find it useful.

Harmony Switches (the icon templates are a hold-over from a different way of doing it and not required) (configuration.yaml)

  - platform: template
    switches:
        lounge_tv:
          friendly_name: Lounge TV
          value_template: "{{ is_state_attr('remote.lounge', 'current_activity', 'TV') }}"
          turn_on:
            service: remote.turn_on
            data:
              entity_id: remote.lounge
              activity: 'TV'
          turn_off:
            service: remote.turn_on
            data:
              entity_id: remote.lounge
              activity: 'PowerOff'
          icon_template: >-
            {% if is_state_attr('remote.lounge', 'current_activity', 'TV') %}
              mdi:television-classic
            {% else %}
              mdi:television-classic-off
            {% endif %}

        soundbar:
          friendly_name: Soundbar
          value_template: "{{ is_state_attr('remote.lounge', 'current_activity', 'Soundbar') }}"
          turn_on:
            service: remote.turn_on
            data:
              entity_id: remote.lounge
              activity: 'Soundbar'
          turn_off:
            service: remote.turn_on
            data:
              entity_id: remote.lounge
              activity: 'PowerOff'
          icon_template: >-
            {% if is_state_attr('remote.lounge', 'current_activity', 'Soundbar') %}
              mdi:music
            {% else %}
              mdi:music-off
            {% endif %}

        ps3:
          friendly_name: PS4
          value_template: "{{ is_state_attr('remote.lounge', 'current_activity', 'PS4') }}"
          turn_on:
            service: remote.turn_on
            data:
              entity_id: remote.lounge
              activity: 'PS4'
          turn_off:
            service: remote.turn_on
            data:
              entity_id: remote.lounge
              activity: 'PowerOff'
          icon_template: >-
            {% if is_state_attr('remote.lounge', 'current_activity', 'PS4') %}
              mdi:playstation
            {% else %}
              mdi:playstation
            {% endif %}

The text input thingy (configuration.yaml)

input_text:
  remote_command:
    name: Remote Command

The main remote control (ui-lovelace.yaml) - big but there’s a lot of repetitive bits so it’s really not complicated. There’s some comments to help as well.

# Harmony Remote Control

# Vertical-stack-in-card makes a 'dynamic' remote control where the buttons change according to the activity
- type: custom:vertical-stack-in-card
  title: Lounge Entertainment
  cards:

  # Set Harmony Activity, this section always shows
  # Harmony Activities are configured as template switches
  - type: picture-elements
    image: /local/images/short-empty.png?v2.2
    elements:
      - type: image
        entity: switch.lounge_tv
        tap_action: 
          action: toggle
        image: /local/images/remote/tv.svg?v1
        state_filter: 
          "on": invert(.5) sepia(1) saturate(8) hue-rotate(10deg)
        style:
          top: 50%
          left: 20%
          # Reuse these values with <<: *style_anchor in the style section for each button
          <<: &style_anchor 
            width: 2em
            height: 2em
            padding: 15px
            background-color: var(--paper-item-icon-color)
            border-radius: 50%
            box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)
      - type: image
        entity: switch.soundbar
        tap_action: 
          action: toggle
        image: /local/images/remote/music.svg?v1
        state_filter: 
          "on": invert(.5) sepia(1) saturate(8) hue-rotate(10deg)
        style: 
          <<: *style_anchor
          top: 50%
          left: 50%    
      - type: image
        entity: switch.ps3
        tap_action: 
          action: toggle
        image: /local/images/remote/ps4.svg?v1
        state_filter: 
          "on": invert(.5) sepia(1) saturate(8) hue-rotate(10deg)
        style: 
          <<: *style_anchor
          top: 50%
          left: 80%

  # Display full remote when Harmony's TV Activity is on
  # Commands sent straight to Harmony with remote.send_command
  # Info, such as the Device ID come from config/harmony_XXXX.conf 
  - type: conditional
    conditions:
    - entity: switch.lounge_tv
      state: "on"
    card:
      type: picture-elements
      image: /local/images/empty.png?v2.4
      elements: 
      - type: image  # Menu
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: SmartHub
        image: /local/images/remote/menu.svg?v1
        style: 
          <<: *style_anchor
          top: 15%
          left: 20%
      - type: image  # Exit
        entity: media_player.lounge_chromecast
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: Exit
        image: /local/images/remote/cast.svg?v1 # using a cast image as exit only gets used to quit apps an watch cast content
        state_filter: # light up the button when chromecast is playing (as a nudge if the TV's sitting in an app)
          playing: invert(.5) sepia(1) saturate(8) hue-rotate(10deg)
          paused: invert(.5) sepia(1) saturate(8) hue-rotate(10deg)
        style:
          <<: *style_anchor
          top: 15%
          left: 50%
      - type: image  # Back
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: Return
        image: /local/images/remote/back.svg?v1
        style:
          <<: *style_anchor
          top: 15%
          left: 80%
      - type: image  # Up
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: DirectionUp
        image: /local/images/remote/up.svg?v1
        style:
          <<: *style_anchor
          top: 44%
          left: 50%
      - type: image  # Left
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: DirectionLeft
        image: /local/images/remote/left.svg?v1
        style:
          <<: *style_anchor
          top: 65%
          left: 32%
      - type: image  # OK
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: Select
        image: /local/images/remote/return.svg?v1
        style:
          <<: *style_anchor
          top: 65%
          left: 50%
      - type: image  # Right
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: DirectionRight
        image: /local/images/remote/right.svg?v1
        style:
          <<: *style_anchor
          top: 65%
          left: 68%
      - type: image  # Down
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: DirectionDown
        image: /local/images/remote/down.svg?v1
        style:
          <<: *style_anchor
          top: 86%
          left: 50%
  
  # Display Play / Pause / Stop when TV or Soundbar is active
  # These set the value of an input_text field which triggers a node-red flow which either:
  #  - sends harmony remote commands if watching TV app (TV is on / chromecast inactive)
  #  - controls chromecast if casting to it (TV is on / chromecast active)
  #  - controls google home if listening to music (TV is off / speaker is on)
  - type: conditional
    conditions:
    - entity: remote.lounge
      state: "on"
    - entity: switch.ps3
      state: "off"
    card:
      type: picture-elements
      image: /local/images/short-empty.png?v2.1
      elements: 
      - type: image  # Play
        tap_action:
          action: call-service
          service: input_text.set_value
          service_data:
            entity_id: input_text.remote_command
            value: play
        image: /local/images/remote/play.svg?v1
        style:
          <<: *style_anchor
          top: 50%
          left: 20%
      - type: image  # Pause
        tap_action:
          action: call-service
          service: input_text.set_value
          service_data:
            entity_id: input_text.remote_command
            value: pause
        image: /local/images/remote/pause.svg?v1
        style:
          <<: *style_anchor
          top: 50%
          left: 50%
      - type: image  # Stop
        entity: input_boolean.remote_stop
        tap_action:
          action: call-service
          service: input_text.set_value
          service_data:
            entity_id: input_text.remote_command
            value: stop
        image: /local/images/remote/stop.svg?v1
        style:
          <<: *style_anchor
          top: 50%
          left: 80% 

  # Display volume controls when any Activity is on
  - type: conditional
    conditions:
    - entity: remote.lounge
      state: "on"
    card:
      type: picture-elements
      image: /local/images/short-empty.png?v2.1
      elements: 
      - type: image  # Volume Up
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: VolumeUp
        image: /local/images/remote/volup.svg?v1
        style:
          <<: *style_anchor
          top: 40%
          left: 80%
      - type: image  # Mute
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: Mute
        image: /local/images/remote/mute.svg?v1
        style:
          <<: *style_anchor
          top: 40%
          left: 50%
      - type: image  # Volume Down
        tap_action:
          action: call-service
          service: remote.send_command
          service_data:
            entity_id: remote.lounge
            device: 29590173
            command: VolumeDown
        image: /local/images/remote/voldown.svg?v1
        style:
          <<: *style_anchor
          top: 40%
          left: 20%

Node-Red flow - I’ll share if anyone’s interested but it might be kind of niche for my situation. I expect scripts / automations would also work but I’m too lazy to learn how to do them.

Enjoy, hope this helps someone.

17 Likes

Awsome work!!!
Do you mind sharing the svg icons that you have been using?
//Asif

thanks.

The SVG’s are all downloaded mdi icons. I’d have used the icons directly (and saved a lot of faff) but I got hit by this issue:
https://github.com/home-assistant/home-assistant-polymer/issues/2808

So, if you know how to work around that, or it gets fixed, you could use icon rather than image types.

Anyhow, the files are here …

2 Likes

Thank you so much! This is how my looks like.
I was able to use icons.
Short snippet of my template switches. Here i use images. But for rest, icons.
Note that I removed the “Width” and “height” in the style.

      - type: custom:vertical-stack-in-card
        cards:
        - type: picture-elements
          image: /local/images/remote/short-empty.png?v2.2
          elements:
            - type: image
              entity: switch.apple_tv
              tap_action: 
                action: toggle
              image: /local/images/remote/apple.svg?v1
              state_filter: 
                "on": invert(.5) sepia(1) saturate(8) hue-rotate(10deg)
                "off": invert(.90)
              style:
                top: 50%
                left: 15.5%
                # Reuse these values with <<: *style_anchor in the style section for each button
                <<: &style_anchor 
                  #width: 2em
                  #height: 2em
                  padding: 15px
                  background-color: var(--sidebar-background-color)
                  border-radius: 50%
                  box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)

Short snipped of Condition section using icons.

        - type: conditional
          conditions:
          - entity: switch.apple_tv
            state: "on"
          card:
            type: picture-elements
            image: /local/images/remote/empty.png?v2.4
            elements: 
            - type: icon  # Menu
              tap_action:
                action: call-service
                service: remote.send_command
                service_data:
                  entity_id: remote.harmony_hub
                  device: 43994817
                  command: Menu
              icon: mdi:menu
              style: 
                <<: *style_anchor
                top: 10%
                left: 20%

5 Likes

Nice, I like the media player view at the top. Sadly, icons at the standard size are too small for my liking, hence the width & height.

1 Like

This is great. I’m really looking forward to incorporating this into my setup. Thank you.

1 Like

This by far works best with my setup. Really appreciate it. The only problem I have is the touchable area of the icon is only a square in the middle, if you touch the edge of the icon/image, it doesn’t work. Any work around for that?

I hadn’t noticed, perhaps I have fat fingers :joy:

I took this screenshot while holding the ‘right’ button.

@eggman can you help with the node-red flow. I am stuck and cannot make it work.

Hi all,

i am trying to adapt the harmony remote to my system but it seems that the following css style option always breaks my lovelace config:

           <<: *style_anchor

Can anybody tell me what this used for and why it possibly breaks lovelace ?

For example:

      card:
        type: picture-elements
        image: /local/lovelace/icons_harmony_remote/empty.png?v2.4
        elements: 
        - type: icon  # Menu
          tap_action:
            action: call-service
            service: remote.send_command
            service_data:
              entity_id: remote.harmonyhub
              device: 54869661
              command: Menu
          # image: /local/lovelace/icons_harmony_remote/menu.svg?v1
          icon: mdi:menu
          style: 
            <<: *style_anchor
            top: 15%
            left: 20%

The second issue i have is as soon as i add a second button the first one disappears without any error shown in lovelace…

Greetings

It’s a yaml anchor that enables you to define repetitive code once and reuse it.

You may have deleted the definition, it’s in the original code. You can alter it once and all the buttons will change.

It’s the bit that starts <<: &style_anchor

1 Like

Ah ok perfect i´ll take a look again! Thanks very much!

Tbh, although this works, there have been a few improvements since I did it. I think I’d use https://github.com/thomasloven/hass-lovelace_gen if I was starting again.

Strange thing do you happen to know why the icons are not in the middle ?

grafik

Cos you’ve not configured it right?

No idea unless you post your yaml,

Ah i did in my post above :slight_smile:

        type: picture-elements
        image: /local/lovelace/icons_harmony_remote/empty.png?v2.4
        elements: 
        - type: icon  # Menu
          tap_action:
            action: call-service
            service: remote.send_command
            service_data:
              entity_id: remote.harmonyhub
              device: 54869661
              command: Menu
          # image: /local/lovelace/icons_harmony_remote/menu.svg?v1
          icon: mdi:menu
          style: 
            #<<: *style_anchor
            top: 15%
            left: 20%
            <<: &style_anchor 
              width: 2em
              height: 2em
              padding: 15px
              background-color: grey #var(--paper-item-icon-color)
              border-radius: 50%
              box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)

I am quite sure i am missing something…

Solved it …my fault! As i use icons needed to remove width/height in style…

Is there a way to highlight the buttons on click (changing color or whatsoever)?

Here is mine so far:

So, as mentioned above, if I was doing this again I’d use lovelace_gen from Thomas Loven.

My configuration, just for the remote, had grown to over 500 rows, much of it repetitive, it’s now 157.

I’ve learned more about CSS styling and so was able to overcome the issues I’d previously had with using icons. So this is much neater, easier to modify and easier to maintain.

Buttons still appear when they’re relevant and disappear when not and it looks similar but is much easier to adapt for different styles as well. The application buttons at the bottom are new and result from me getting an NVidia Shield and using the Android TV component. Took a while to figure out the commands for some of the apps, whichever one’s active gets coloured in.


What it looks like on my phone.

# lovelace_gen

title: Remote
path: remote
icon: mdi:play-pause
background: center / cover no-repeat url("/local/images/backgrounds/remote.jpg") fixed rgba(170, 170, 170, 1)
panel: true
cards:
  - type: custom:layout-card
    layout: vertical
    cards:

    ############################################
    ##  Activities
    ############################################
    {% macro activity(entity, top, left) -%}
          - type: state-icon
            entity: {{ entity }}
            tap_action:
              action: toggle
            style:
              top: {{ top }}%
              left: {{ left }}%
              <<: &style_anchor
                transform: matrix(1.8, 0, 0, 1.8, -20, -20)
                background: rgb(105, 199, 252, .9)
                filter: drop-shadow(2px 2px 5px rgb(100, 100, 100, 1)
                border-radius: 100%
    {%- endmacro %}

      - type: picture-elements
        image: /local/images/short-empty.png
        elements: 
          {{ activity('switch.lounge_tv', 50, 12.5) }}
          {{ activity('switch.usbc', 50, 37.5) }}
          {{ activity('switch.ps3', 50, 62.5) }}
          {{ activity('switch.soundbar', 50, 87.5) }}

    ############################################
    ##  Conditional Activity Buttons
    ############################################
    {% macro button(device, command, icon, top, left) -%}
            - type: state-icon
              entity: remote.lounge
              tap_action:
                action: call-service
                service: remote.send_command
                service_data:
                  entity_id: remote.lounge
                  device: {{ device }}
                  command: {{ command }}
              icon: mdi:{{ icon }}
              style:
                <<: *style_anchor
                top: {{ top }}%
                left: {{ left }}%
    {%- endmacro %}

    {% macro nsbutton(device, command, icon, top, left) -%}
            - type: state-icon
              entity: remote.lounge
              tap_action:
                action: call-service
                service: remote.send_command
                service_data:
                  entity_id: remote.lounge
                  device: {{ device }}
                  command: {{ command }}
              icon: mdi:{{ icon }}
              style:
                transform: matrix(2.5, 0, 0, 2.5, -20, -20)
                top: {{ top }}%
                left: {{ left }}%
    {%- endmacro %}

    ############################################
    ##  Volume controls for all activities
    ############################################
      - type: conditional
        conditions:
          - entity: remote.lounge
            state: "on"
        card:
          type: picture-elements
          image: /local/images/short-empty.png
          elements:
            {{ button(29590185, 'VolumeDown', 'volume-minus', 50, 12.5) }}
            {{ button(29590185, 'VolumeUp', 'volume-plus', 50, 37.5) }}
            {{ button(29590185, 'Mute', 'volume-off', 50, 62.5) }}
            {{ button(29590185, 'PowerToggle', 'speaker', 50, 87.5) }}

    ############################################
    ##  Shield Remote
    ############################################
      - type: conditional
        conditions:
          - entity: switch.lounge_tv
            state: "on"
        card:
          type: picture-elements
          image: /local/images/empty.png
          elements:
            - type: image
              image: /local/images/remotecircle.png
              style:
                top: 50%
                left: 50%
                width: 60%
                opacity: 0.9
                filter: drop-shadow(2px 2px 5px rgb(100, 100, 100, 1)
                border-radius: 100%

            {{ button(64042126, 'Home', 'home-outline', 15, 12.5) }}
            {{ button(64042126, 'Back', 'undo-variant', 15, 87.5) }}
            {{ button(64042126, 'Select', 'keyboard-return', 50, 50) }}
                transform: matrix(2.2, 0, 0, 2.2, -20, -20)
            {{ nsbutton(64042126, 'DirectionUp', 'chevron-up', 22, 50) }}
            {{ nsbutton(64042126, 'DirectionDown', 'chevron-down', 78, 50) }}
            {{ nsbutton(64042126, 'DirectionLeft', 'chevron-left', 50, 27.5) }}
            {{ nsbutton(64042126, 'DirectionRight', 'chevron-right', 50, 72.5) }}
            {{ button(64042126, 'Pause', 'pause', 85, 12.5) }}
            {{ button(64042126, 'Play', 'play', 85, 87.5) }}
            
    ############################################
    ##  Applications
    ############################################
    {% macro activity(app, top, left, adbcommand) -%}
          - type: image
            entity: sensor.cur_shield_app
            tap_action:
              action: call-service
              service: script.launch_shield_app
              service_data:
                adbcommand: am start -a android.intent.action.VIEW -d -n {{ adbcommand }}
            image: /local/images/logos/{{app}}.png
            filter: grayscale(0.95) drop-shadow(2px 2px 5px rgb(100, 100, 100, 1) 
            state_filter:
              '{{app}}': drop-shadow(2px 2px 5px rgb(100, 100, 100, 1)
            style:
              background: transparent
              border-radius: 100%
              top: {{ top }}%
              left: {{ left }}%
              width: 72px
    {%- endmacro %}

      - type: picture-elements
        image: /local/images/medium-empty.png
        elements: 
          {{ activity('iPlayer', 27.5, 12.5, 'com.nvidia.bbciplayer/.MainPlayerActivity') }}
          {{ activity('PrimeVideo', 27.5, 37.5, 'com.amazon.amazonvideo.livingroom/com.amazon.ignition.IgnitionActivity') }}
          {{ activity('Netflix', 27.5, 62.5, 'com.netflix.ninja/.MainActivity') }}
          {{ activity('Kodi', 27.5, 87.5, 'org.xbmc.kodi/.Splash') }}
          {{ activity('YouTube', 72.5, 12.5, 'com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.ShellActivity') }}
          {{ activity('RedBullTV', 72.5, 37.5, 'com.nousguide.android.rbtv/com.redbull.launch.SplashActivity') }}
          {{ activity('ITVHub', 72.5, 62.5, 'air.ITVMobilePlayer/com.itv.tenft.itvhub.MainActivity') }}
          {{ activity('GooglePlayMusic', 72.5, 87.5, 'com.google.android.music/.tv.HomeActivity') }}

5 Likes

Hey eggman,

love you second attempt remote setup. I would like to use it in my setup, but I am not sure where to start and it this is there is other part to this that I should be looking at before making this decision. I would like to use this setup to control a LG TV/ Denon AVR/ PS4 and Nvidia shield. Is the other part to you config file that I would need to ask for and edit before I could get this to work? With no apparent scripts or automation references in your file, how does the control know what state the devices are constantly in? Would I be able to work something similar without having a main hub such as your harmony setup? I know that I am trying to jump into the deep end without first spending some time in the shallow end.