Universal Remote Card - Buttons, Touchpads, Sliders, and Keyboards for Multiple Platforms

Not sure what a TV hotbar is, but you’d have to figure out if this command is being sent via IR, RF, ADB, the remote API, or something Sony proprietary, and then figure out if it’s possible to call that from Home Assistant.

For creating new sources, see this thread: Android TV Remote - App Links/Deep Linking - Guide. I’m also not sure about 1:1 mouse control on Android TV. I know it’s possible on Windows using Unified Remote, but I don’t think the 1:1 mouse capability of that is possible on Home Assistant.

I’m not a Kodi user, but if there is a way to do it it would be in the Kodi JSON-RPC API documentation.

Thx to this project, very cool and handy to control my media devices.

Here an example of my popup control with a logitech harmony. It is based on the Rounded Theme which you can find here

type: custom:android-tv-card
remote_id: remote.wohnzimmer
slider_id: media_player.denon_avr_2113
button_style:
  width: 100px
  height: 100px
  border-radius: 20px
  background: var(--contrast3)
  '--size': 32px
touchpad_style:
  height: 200px
  background: url( '{{ state_attr("media_player.vu_wohnzimmer", "entity_picture") }}') center no-repeat
  background-color: var(--contrast3)
slider_style:
  '--border-radius': 12px
  height: 24px
  '--background-height': 12px
  '--color': var(--contrast18)
  '--background': var(--contrast3) 
rows:
  - - exit
    - home
    - power
  - - menu
    - channelup
    - channeldown  
  - - volume_slider    
  - - navigation_touchpad
  - - red
    - green
    - yellow
    - blue
custom_keys:
  power:
    icon: mdi:power
    service: select.select_option
    service_data:
      entity_id: select.wohnzimmer_activities 
      option: power_off
    style:
      color: |
        {% if is_state("select.wohnzimmer_activities", "Fernsehen") %}
          var(--black)          
        {% endif %}        
      background: |
        {% if is_state("select.wohnzimmer_activities", "Fernsehen") %}
          var(--red) 
        {% elif is_state("select.wohnzimmer_activities", "power_off") %}
          var(--green)                      
        {% endif %}  
  menu:
    icon: mdi:menu
    service: remote.send_command
    service_data:
      device: 26195962
      command: Menu   
      entity_id: remote.wohnzimmer     
  channelup: 
    icon: mdi:arrow-up-circle
    service: remote.send_command
    service_data:
      device: 26195962
      command: ChannelUp    
      entity_id: remote.wohnzimmer 
  channeldown: 
    icon: mdi:arrow-down-circle
    service: remote.send_command
    service_data:
      device: 26195962
      command: ChannelDown  
      entity_id: remote.wohnzimmer        
  yellow:
    entity: remote.wohnzimmer
    icon: mdi:circle
    service: remote.send_command
    service_data:  
      device: 26195962
      command: Yellow 
      entity_id: remote.wohnzimmer 
    style:       
      border-radius: 22px
      background: var(--contrast3)
      color: var(--yellow) 
      height: 40px  
      '--size': 25px     
      width: 75px          
  blue:
    entity: remote.wohnzimmer
    icon: mdi:circle
    service: remote.send_command
    service_data:  
      device: 26195962
      command: Blue 
      entity_id: remote.wohnzimmer 
    style:       
      border-radius: 22px
      background: var(--contrast3)
      color: var(--blue) 
      height: 40px
      '--size': 25px  
      width: 75px                        
  red:
    entity: remote.wohnzimmer
    icon: mdi:circle
    service: remote.send_command
    service_data:  
      device: 26195962
      command: Red
      entity_id: remote.wohnzimmer 
    style:       
      border-radius: 22px
      background: var(--contrast3)
      color: var(--red) 
      height: 40px       
      '--size': 25px   
      width: 75px                
  green:
    entity: remote.wohnzimmer
    icon: mdi:circle
    service: remote.send_command
    service_data:  
      device: 26195962
      command: Green
      entity_id: remote.wohnzimmer 
    style:       
      border-radius: 22px
      background: var(--contrast3)
      color: var(--green)    
      height: 40px    
      '--size': 25px  
      width: 75px                    
  up:
    icon: mdi:arrow-up-bold
    service: remote.send_command
    entity: remote.wohnzimmer
    service_data:    
      device: 26195962
      command: DirectionUp
      entity_id: remote.wohnzimmer
  right:
    icon: mdi:arrow-right-bold
    service: remote.send_command
    service_data:
      device: 26195962
      command: DirectionRight
      entity_id: remote.wohnzimmer
  left:
    icon: mdi:arrow-left-bold
    service: remote.send_command
    service_data:
      device: 26195962
      command: DirectionLeft
      entity_id: remote.wohnzimmer
  down:
    icon: mdi:arrow-down-bold
    service: remote.send_command
    service_data:
      device: 26195962
      command: DirectionDown   
      entity_id: remote.wohnzimmer
  center:
    icon: mdi:circle-outline
    service: remote.send_command
    service_data:
      device: 26195962
      command: OK       
      entity_id: remote.wohnzimmer
  exit:    
    icon: mdi:keyboard-return
    service: remote.send_command
    service_data:        
      device: 26195962
      command: Exit    
      entity_id: remote.wohnzimmer    
3 Likes

Not sure what a TV hotbar is

essentially on the Sony Bravia TV remote there’s a button (gear icon) that when pressed displays a small bar on the bottom of the TV with some pre-configured options (to quickly switch picture / audio modes, change brightness but also to just turn off the screen). I guess it’s just a collection of specific functions that are in the main settings as well, but just presented to you in an easier accessible way.

Unfortunately I’m out of my depth to even begin trying to find out how to figure out how that command is being sent to the TV

You should look into the Sony Bravia TV Home Assistant integration and see if it does what you need. If not you could also look into a smart IR remote like a Broadlink (which I personally use for TV and AV receiver controls) to learn and send IR and RF remote commands.

Right you are, in the log I found that “PictureOff” corresponds to the key command to turn off the screen. Tried it via Developer Tools → Service Calls → Remote:Send command and it works.

Now I’m trying to integrate into the custom card, but am struggling to correctly define th custom key. Could me out how to do it properly?

Here’s how the service call that works in developer tools looks like

service: remote.send_command
target:
  entity_id:
    - remote.sony_bravia_tv
  device_id: []
  area_id: []
data:
  command: PictureOff

trying to implement it like this in the custom card:

type: custom:android-tv-card
remote_id: remote.sony_xr_65a83j
slider_id: media_player.sony_bravia_tv
keyboard_id: remote.sony_xr_65a83j_adb
title: Fernseher
custom_keys:
  screen_off:
    icon: mdi:selection-remove
    service: remote.send_command
    target:
      entity_id:
        - remote.sony_bravia_tv
      data:
        command: PictureOff
rows:
  - - back
    - power
    - home
    - screen_off

but then I get the following error:
image

I tried to change the remote_id further up in the custom card, and then the command just works, but then I lose the functionality of the other commands you’ve programmed

Your data block is an indent level too deep.

type: custom:android-tv-card
remote_id: remote.sony_xr_65a83j
slider_id: media_player.sony_bravia_tv
keyboard_id: remote.sony_xr_65a83j_adb
title: Fernseher
custom_keys:
  screen_off:
    icon: mdi:selection-remove
    service: remote.send_command
    target:
      entity_id:
        - remote.sony_bravia_tv
    data:
      command: PictureOff
rows:
  - - back
    - power
    - home
    - screen_off

I also have my personal remote in popup controls using browser mod popup cards, card-mod, and layout-card media queries for horizontal and vertical layouts, which is opened via a regular Home Assistant button set to the remote entity.

type: custom:popup-card
card:
  type: custom:layout-card
  cards:
    - type: tile
      entity: media_player.lounge_tv
      icon_tap_action:
        action: toggle
      vertical: false
    - type: custom:android-tv-card
      remote_id: remote.lounge_google_tv
      adb_id: media_player.lounge_google_tv_adb
      custom_keys:
        volume_down:
          service: script.amplifier_volume_down
        volume_mute:
          service: script.amplifier_volume_mute
        volume_up:
          service: script.amplifier_volume_up
      alt_volume_icons: true
      rows:
        - - - - back
              - null
              - home
              - null
              - menu
            - - volume_down
              - null
              - volume_mute
              - null
              - volume_up
            - - rewind
              - null
              - play_pause
              - null
              - fast_forward
            - - netflix
              - disney
              - hulu
              - max
              - primevideo
            - - plex
              - vudu
              - youtube
              - spotify
          - - - keyboard
              - search
            - - navigation_touchpad
      touchpad_height: 325px
      view_layout:
        show:
          mediaquery: '(orientation: landscape)'
      card_mod:
        style: |
          ha-card {
            padding: 0 !important;
          }
    - type: custom:android-tv-card
      remote_id: remote.lounge_google_tv
      adb_id: media_player.lounge_google_tv_adb
      alt_volume_icons: true
      custom_keys:
        volume_down:
          service: script.amplifier_volume_down
        volume_mute:
          service: script.amplifier_volume_mute
        volume_up:
          service: script.amplifier_volume_up
      touchpad_height: 340px
      rows:
        - - back
          - home
          - play_pause
        - - keyboard
          - search
        - - volume_buttons
        - - navigation_touchpad
      view_layout:
        show:
          mediaquery: '(orientation: portrait)'
      card_mod:
        style: |
          ha-card {
            padding: 0 !important;
          }
  layout_type: custom:grid-layout
entity: remote.lounge_google_tv
size: fullscreen
dismissable: true
card_mod:
  style:
    .: |
      div.content {
        height: fit-content !important;
      }
    ha-dialog$: |
      .mdc-dialog__surface {
        border-radius: var(--ha-card-border-radius) !important;        
      }
      .mdc-dialog__container {
        flex-direction: column !important;
      }
      .mdc-dialog {
        --mdc-dialog-min-width: 95vw !important;
        --mdc-dialog-min-height: fit-content !important;
      }


2 Likes

Version 3.2.0 has just been released! This version changes custom action syntax to follow the Home Assistant actions format, and adds support for remappable double tap and hold actions for custom buttons. The following action types are now supported:

  • key
  • source
  • call-service
  • navigate
  • url

I’ve also refactored and improved how double taps, holds, and touchpad swipes are processed so they now work on all platforms! You can use them on any chromium based or Firefox desktop browser, and the Home Assistant apps on Android and iPhone.

This release does deprecate a few fields related to remapping touchpad actions and changes the format of custom actions (formerly custom keys and sources), but old configurations should continue to work and get internally upgraded to work with the refactored tap/double tap/hold action logic.

1 Like

Hi, I am looking to use the commands learned via Broadlink RM4 mini, however, it is not working. I have already tested the commands and they work via script. Is it possible to use this custom card together with the learned commands?

type: custom:android-tv-card
        title: TV Box
        custom_keys:
          power:
            service: remote.send_command
            target:
              entity_id: remote.control_universal_master
            data:
              device: TVBox_fision
              command:
                - power
          channel_up:
            service: remote.send_command
            target:
              entity_id: remote.control_universal_master
            data:
              device: TVBox_fision
              command:
                - channel_up
          channel_down:
            service: remote.send_command
            target:
              entity_id: remote.control_universal_master
            data:
              device: TVBox_fision
              command:
                - channel_down
          volume_up:
          volume_down:
          info:
          menu:
          back:
          guide:
        rows:
          - - power
          - - back
            - home
            - tv
            - netflix
          - - youtube
            - spotify
            - netflix
          - - touchpad
          - - slider
          - - channel_up
            - channel_down
            - info
          - - rewind
            - play
            - spotify
            - pause
            - fast_forward
1 Like

It should work the way you have it listed there yeah. I just tried it with some of my Broadlink IR commands and they worked fine when the service calls were defined in custom actions (I define all my IR remote actions in scripts and call those, which lets me run them in parallel mode with a max of 2 runs, which I’ve found works best for repeated IR commands speed and preventing overshooting too much). I’m not sure why it wouldn’t work for you. Are you seeing any errors in the Home Assistant logs?

1 Like

thanks for your quick response! i was able to solve it, the error was that i had forgotten to change the name of the entity, i was not calling it by its new name, but by the old one. :rofl: :joy:

2 Likes

Hey stop developing this further, you are now breaking all my old remote designs! :rofl: :rofl:

Just kidding man, this is all too awesome. Thanks for the great work! This totally rocks!

I think I will use your remote for things other than android TV! Like lights, fans, curtains etc.

1 Like

While you are joking, old remote configs should get internally upgraded and should continue to work. If you found that a new version does break old remote configs and there isn’t a breaking change section in the GitHub release notes, let me know for real!

2 Likes

Thanks for your great work! I was able to create a decent remote without too much hassle.
I was wondering if it’s possible to have a numpad (or buttons) to sent channel numbers. My dutch tv provider kpn is build on the Android tv and does accept channel numbers from Google Home (and some apps on playstore as well). Did i miss something or is it not possible?
Keep it up!

Have you tried using the default keys for the numbers and channel up/down keys?

type: custom:android-tv-card
rows:
  - - n7
    - n8
    - n9
  - - n4
    - n5
    - n6
  - - n1
    - n2
    - n3
  - - channel_up
    - channel_down

image

1 Like

I had the numbers without ‘n’ pasted from somewhere. Now it works perfectly. Thanks a lot, you’re great!
Screenshot of remote for KPN TV+ Android STB. Every button is working.

1 Like

Nice and can confirm, that did work!

now I just need the text entry keyboard figured out and then I can get to the actual visual design of the remote

Sorry super intelligent folks, I am about to ask a really stupid question after going through all the above conversation.

Tried using custom action by pasting the codes directly under the remote control yaml code in the dashboard. Didn’t work. Tried pasting that code in configuration.yaml, says custom action doesn’t exists. Searched under customer components section in Vs Code’s custom components section, couldn’t find any yaml file related to android TV card.

Kindly asking for your generous help.

Thank you

Hi all,

I realise I’m quite late to the (really cool) party - this extension was exactly what I was looking for, and really pleased that it’s being actively updated.

I’ve created a SkyQ remote - it’s not the prettiest, but I hope it will help someone… Underlying it is
https://github.com/RogerSelwyn/Home_Assistant_SkyQ_MediaPlayer

Here is a screenshot:

Obviously the volume buttons would need to be customised to your setup, but I hope someone will find it useful:

type: custom:android-tv-card
title: Sky
remote_id: media_player.skyq_living_room
button_style:
  width: 200%
  height: 64px
  border-radius: 100%
  background: gray
  '--size': 32px
  position: relative
  left: '-16px'
touchpad_style:
  height: 260px
  border-radius: 100%
  width: 260px
  flex-grow: 0
  background-color: gray
rows:
  - - power
    - sky
    - sky_search
  - - rewind
    - play_pause
    - fast_forward
  - - navigation_touchpad
  - - back
    - home
    - sidebar
  - - volume_up
    - volume_mute
    - info
    - channel_up
  - - volume_down
    - record
    - channel_down
  - - red
    - green
    - yellow
    - blue
  - - n1
    - n2
    - n3
  - - n4
    - n5
    - n6
  - - n7
    - n8
    - n9
  - - source
    - n0
    - question
custom_keys:
  power:
    icon: mdi:power
    service: select.select_option
    service_data:
      entity_id: select.wohnzimmer_activities
      option: power_off
  sky:
    icon: mdi:cloud
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: sky
    target:
      entity_id: media_player.skyq_living_room
  sky_search:
    icon: mdi:magnify
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: search
    target:
      entity_id: media_player.skyq_living_room
  rewind:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: rewind
    target:
      entity_id: media_player.skyq_living_room
  play_pause:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: play
    target:
      entity_id: media_player.skyq_living_room
  fast_forward:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: fastforward
    target:
      entity_id: media_player.skyq_living_room
  back:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: dismiss
    target:
      entity_id: media_player.skyq_living_room
  home:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: home
    target:
      entity_id: media_player.skyq_living_room
  sidebar:
    icon: mdi:dots-horizontal
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: sidebar
    target:
      entity_id: media_player.skyq_living_room
  volume_up:
    style: null
  volume_mute:
    style: null
  info:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: i
    target:
      entity_id: media_player.skyq_living_room
  channel_up:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: channelup
    target:
      entity_id: media_player.skyq_living_room
  volume_down:
    style: null
  record:
    icon: mdi:record-rec
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: record
    target:
      entity_id: media_player.skyq_living_room
  channel_down:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: channeldown
    target:
      entity_id: media_player.skyq_living_room
  red:
    icon: mdi:circle
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: red
    target:
      entity_id: media_player.skyq_living_room
    style:
      color: red
  green:
    icon: mdi:circle
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: green
    target:
      entity_id: media_player.skyq_living_room
    style:
      color: green
  yellow:
    icon: mdi:circle
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: yellow
    target:
      entity_id: media_player.skyq_living_room
    style:
      color: yellow
  blue:
    icon: mdi:circle
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: blue
    target:
      entity_id: media_player.skyq_living_room
    style:
      color: blue
  n0:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 0
    target:
      entity_id: media_player.skyq_living_room
  n1:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 1
    target:
      entity_id: media_player.skyq_living_room
  n2:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 2
    target:
      entity_id: media_player.skyq_living_room
  n3:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 3
    target:
      entity_id: media_player.skyq_living_room
  n4:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 4
    target:
      entity_id: media_player.skyq_living_room
  n5:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 5
    target:
      entity_id: media_player.skyq_living_room
  n6:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 6
    target:
      entity_id: media_player.skyq_living_room
  n7:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 7
    target:
      entity_id: media_player.skyq_living_room
  n8:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 8
    target:
      entity_id: media_player.skyq_living_room
  n9:
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: 9
    target:
      entity_id: media_player.skyq_living_room
  up:
    icon: mdi:arrow-up-bold
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: up
    target:
      entity_id: media_player.skyq_living_room
  right:
    icon: mdi:arrow-right-bold
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: right
    target:
      entity_id: media_player.skyq_living_room
  left:
    icon: mdi:arrow-left-bold
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: left
    target:
      entity_id: media_player.skyq_living_room
  down:
    icon: mdi:arrow-down-bold
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: down
    target:
      entity_id: media_player.skyq_living_room
  center:
    icon: mdi:circle-outline
    service: media_player.play_media
    data:
      media_content_type: skyq
      media_content_id: select
    target:
      entity_id: media_player.skyq_living_room

You’ll need to replace ‘media_player.skyq_living_room’ with whatever your SkyQ box is called.

The touchpad works exactly as you would expect. And many thanks to everyone who has contributed to this lovely repo.

Thanks!

3 Likes