Share your Lovelace Home Theater Remote Setup

Here is my simple one I pretty much just copied and pasted, but I have a question. Is it possible to have a repeating button press, with a long hold? I’m using MQTT to send the message from the button pressed on the home assistant screen, and then using node red to converted into the various infrared/network signals, but I wonder if it could be better.

Cheers!

That custom card let’s you do repeats. You can also set it up in a script and then add the script as the action.

type: custom:button-card
        hold_action:
          action: call-service
          repeat: 150
          service: switch.turn_on
          service_data:
            entity_id: switch.ir_tv_vol_dn
        

Sorry the formatting is probably off, was on mobile.

1 Like
      - type: custom:button-card
        label: Up
        icon: mdi:menu-up
        show_state: false
        show_name: false
        show_label: false
        styles:
          card:
            - height: 75px
            - border-radius: 15px
            - background-color: rgba(65, 65, 65,0.5)
          icon:
            - color: rgba(255, 255, 255, 1)
            - width: 80px
        tap_action:
          action: call-service
          service: mqtt.publish
          service_data:
            topic:  Lounge/Rumpus/SonyTV
            payload: up
         hold_action:
          action: call-service
          repeat: 150
          service: mqtt.publish
          service_data:
            topic:  Lounge/Rumpus/SonyTV
            payload: up

Thanks for that. Above is my amended code with your hold action bit, but it’s trying out configuration errors. I doublechecked the spacing, but they must be something I’m missing. Thanks for any help.

type: custom:button-card
label: Up
icon: mdi:menu-up
show_state: false
show_name: false
show_label: false
styles:
  card:
    - height: 75px
    - border-radius: 15px
    - background-color: rgba(65, 65, 65,0.5)
  icon:
    - color: rgba(255, 255, 255, 1)
    - width: 80px
tap_action:
  action: call-service
  service: mqtt.publish
  service_data:
    topic: Lounge/Rumpus/SonyTV
    payload: up
hold_action:
  action: call-service
  repeat: 150
  service: mqtt.publish
  service_data:
    topic: Lounge/Rumpus/SonyTV
    payload: up

That works for me in a manual card.
The initial - (dash) is usually for separation of multiple cards in a stack or similar

1 Like

Thank you, the initial dash was the problem, despite it being there when all the cards are combined, so there must’ve been a formatting error somewhere I can’t see.

So progress! However, I’m not getting multiple repeats in node red’s MQTT client. If I fire up MQTT Explorer, then they come through just fine, but I don’t even get one result if I hold down the buttom in node red. I know this is a Home Assistant forum, but if anyone has any ideas why they are being filtered in node red, that would be great to know!

Cheers!

Hmm not sure about nodered mqtt server. You could try setting up mqtt in homeassistant. It sort of sounds abit like a QoS or similar issue if it’s ignoring multiple close messages.

It certainly works over mqtt, it’s how I have it setup. The switch I use is a IR-mqtt switch in HA. Works for my volume control. I think my actual remote is in this thread already.

1 Like

my MQTT server is set up in home assistant, I’m just using node red to receive the messages. That way I can decide, depending on whether my input source on my receiver is TV/Netflix/pay TV et cetera, to send it to the proper device.

I’ll have a go tomorrow changing the QOS, but it’s weird that home assistant is sending it out properly, even if it’s just QOS=0, and that node red isn’t picking it up.

Thanks for your help again.

1 Like

First thing to try I suppose would changing the 150 milliseconds to 500 or even 1000. Then reduce it from a working amount of time.

I have qos1 set for my switches btw.

I actually did that! Yay initiative… :slight_smile:

I tried 1000, and even 5000 but it doesn’t even send it through once, well I should say it isn’t even received once. I I tried setting the qos: 1 with no improvement, and when you set the qos: 2, MQTT explorer shows qos: 0, while node red shows qos:1!

It’s bizarre.

So you are using a “MQTT in” node in nodered correct? the mqtt in node should be qos 0 and the outgoing mqtt message from HA should be 0 or 1 . I think. I’m not aware of any reason otherwise why it would be getting filtered…

alternatively just change it to a switch in HA and pick it up in nodered as a “trigger: state” or “events: state” node.

Correct. The MQTT in node was set to qos: 1, but changing it to qos: 0 hasn’t helped unfortunately.

Thanks. I’ll have a look into that.

2 Likes

I haven’t set up long-press, but I did set up an input number to track the volume level of a soundbar that’s controlled by IR only. When the number is adjusted, it loops volume up/down commands every 500ms. There can be a bit of latency but I haven’t seen any commands dropped using it like this.

Also wanted to share my remote config, I really like the way paper-button-row and fold-entity-row look together

If anyone was interested in the buttons, I have them broken down into templates (in the generic sense, not the {{}} sense) that I can quickly copy into a new remote:

type: entities
entities:
  - type: section
    label: Directional
  - type: custom:paper-buttons-row
    style: ''
    base_config: null
    buttons:
      - icon: mdi:chevron-up
        name: false
        style:
          button:
            background-color: '#3B4252'
            border-radius: 50% 50% 0px 0px
            color: var(--primary-text-color)
            '--mdc-icon-size': 48px
            margin: 0px
            padding: 2px
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          background-color: '#3B4252'
          border-radius: 15px
          color: var(--primary-text-color)
          '--mdc-icon-size': 48px
          margin: 0px
          padding: 2px
    buttons:
      - icon: mdi:chevron-left
        style:
          button:
            border-radius: 50% 0px 0px 50%
            margin-left: auto
      - icon: mdi:keyboard-return
        style:
          button:
            border-radius: 0px
            '--mdc-icon-size': 40px
            padding: 6px
      - icon: mdi:chevron-right
        style:
          button:
            margin-right: auto
            border-radius: 0px 50% 50% 0px
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          '--mdc-icon-size': 35px
          border-radius: 15px
          color: var(--primary-text-color)
          background-color: '#00000000'
          margin: 0px
          padding: 2px
          margin-bottom: 20px
    buttons:
      - icon: mdi:arrow-left
        style:
          button:
            margin-right: 37px
            margin-left: auto
      - icon: mdi:chevron-down
        style:
          button:
            border-radius: 0px 0px 50% 50%
            '--mdc-icon-size': 48px
            background-color: '#3B4252'
      - icon: mdi:home
        style:
          button:
            margin-right: auto
            margin-left: 37px
  - type: section
    label: Numeric Pad
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 0px 10px 0px
          padding: 7px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          border-radius: 15px
          '--mdc-icon-size': 38px
    buttons:
      - icon: mdi:numeric-1
        style:
          button:
            margin-left: auto
            margin-right: 16px
      - icon: mdi:numeric-2
      - icon: mdi:numeric-3
        style:
          button:
            margin-right: auto
            margin-left: 16px
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 0px 10px 0px
          padding: 7px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          border-radius: 15px
          '--mdc-icon-size': 38px
    buttons:
      - icon: mdi:numeric-4
        style:
          button:
            margin-left: auto
            margin-right: 16px
      - icon: mdi:numeric-5
      - icon: mdi:numeric-6
        style:
          button:
            margin-right: auto
            margin-left: 16px
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 0px 10px 0px
          padding: 7px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          border-radius: 15px
          '--mdc-icon-size': 38px
    buttons:
      - icon: mdi:numeric-7
        style:
          button:
            margin-left: auto
            margin-right: 16px
      - icon: mdi:numeric-8
      - icon: mdi:numeric-9
        style:
          button:
            margin-right: auto
            margin-left: 16px
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 0px 10px 0px
          padding: 7px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          border-radius: 15px
          '--mdc-icon-size': 38px
    buttons:
      - icon: mdi:numeric-0
        style:
          button:
            margin-right: auto
            margin-left: auto
card_mod:
  style: |
    #states div  {
      margin: 0px;
    }
type: entities
entities:
  - type: section
    label: Heading
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px
          margin-bottom: 0px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          padding: 0px
          '--mdc-icon-size': 34px
    buttons:
      - icon: mdi:google-chrome
        name: Google TV
        style:
          button:
            margin-left: auto
            margin-right: 22px
            background-color: none
            font-size: 1.2em
          icon:
            margin-left: '-4px'
      - icon: mdi:power
        tap_action:
          action: call-service
          service: media_player.toggle
          service_data:
            entity_id: media_player.loungeroom_soundbar
        style:
          button:
            background-color: '#434C5E'
            border-radius: 38px
            '--mdc-icon-size': 22px
            padding: 4px 14px
            margin-right: auto
            margin-left: 4px
  - type: section
    label: Four Small Buttons
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 8px 20px 8px
          padding: 6px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          border-radius: 50%
          '--mdc-icon-size': 22px
    buttons:
      - icon: mdi:alpha-a-circle-outline
        style:
          button:
            margin-left: auto
      - icon: mdi:alpha-b-circle-outline
      - icon: mdi:alpha-c-circle-outline
      - icon: mdi:alpha-d-circle-outline
        style:
          button:
            margin-right: auto
  - type: section
    label: Three Small Buttons
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 0px 10px 0px
          padding: 5px 14px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          border-radius: 15px
          '--mdc-icon-size': 20px
    buttons:
      - icon: mdi:rewind
        style:
          button:
            margin-left: auto
            margin-right: 22px
      - icon: mdi:pause
      - icon: mdi:fast-forward
        style:
          button:
            margin-right: auto
            margin-left: 22px
  - type: section
    label: Dual Button
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 0px 10px 0px
          padding: 8px 24px
          color: var(--primary-text-color)
          background-color: '#434C5E'
          border-radius: 15px
          '--mdc-icon-size': 28px
    buttons:
      - icon: mdi:youtube
        style:
          button:
            margin-left: auto
            margin-right: 20px
      - icon: mdi:jellyfish
        style:
          button:
            margin-right: auto
            margin-left: 20px
  - type: section
    label: Rocker
  - type: custom:paper-buttons-row
    base_config:
      style:
        button:
          margin: 0px 0px 10px 0px
          '--mdc-icon-size': 28px
          background-color: '#3B4252'
          color: var(--primary-text-color)
          padding: 8px 23px
    buttons:
      - icon: mdi:minus
        style:
          button:
            border-radius: 15px 0px 0px 15px
            margin-left: auto
      - entity: switch.sony_soundbar_mute
        name: false
        state_icons:
          'on': mdi:volume-off
          'off': mdi:volume-high
        style:
          button:
            border-radius: 0px
            padding: 8px 6px
      - icon: mdi:plus
        style:
          button:
            border-radius: 0px 15px 15px 0px
            margin-right: auto
card_mod:
  style: |
    #states div  {
      margin: 0px;
    }

11 Likes

Okay, progress. Using the “events: all” node with a filter of “call_service” the repeating MQTT message is displayed. I can then just use a switch filter with a property of: “msg.payload.event.service_data.payload” to find the message/MQTT payload I want.

My only concern is that it will be catching a lot of events, which might overload it somehow. But hopefully this will help someone else, even if it is a pretty dodgy workaround.

It would be nice to know why it isn’t working though. Come to think of it, EventGhost has the same problem with multiple MQTT messages in a row, so there must be something wrong, or an incompatibility somewhere…

events: state should be able to limit that

The Entity ID is ‘undefined’, so that makes it a bit tricky. I tried using an automation to toggle an input boolean, and then monitor that state change, but it didn’t work with the long press.

There is my mqtt switches if thats helpful. I can pull the entity into nodered with switch.family_tv_vol_dn etc.

switch:
  - platform: mqtt
    name: "Family TV Power"
    command_topic: "cmnd/ESP-ir/IRSEND"
    availability_topic: "tele/ESP-ir/LWT"
    qos: 1
    payload_on: '{"Protocol":"NEC","Data":0x4ebbff00,"Bits":"32"}'
    payload_off: '{"Protocol":"nec","Data":0x4EBB708F,"Bits":"32"}'
    payload_available: "Online"
    payload_not_available: "Connection Lost"
    retain: false    
    
  - platform: mqtt
    name: "Family TV Vol Up"
    command_topic: "cmnd/ESP-ir/IRSEND"
    availability_topic: "tele/ESP-ir/LWT"
    qos: 1
    payload_on: '{"Protocol":"nec","Data":0x4EBB926D,"Bits":"32"}'
    payload_available: "Online"
    payload_not_available: "Connection Lost"
    retain: false 
    
  - platform: mqtt
    name: "Family TV Vol Dn"
    command_topic: "cmnd/ESP-ir/IRSEND"
    availability_topic: "tele/ESP-ir/LWT"
    qos: 1
    payload_on: '{"Protocol":"nec","Data":0x4EBBC23D,"Bits":"32"}'
    payload_available: "Online"
    payload_not_available: "Connection Lost"
    retain: false  
    
  - platform: mqtt
    name: "Family TV Vol Mute"
    command_topic: "cmnd/ESP-ir/IRSEND"
    availability_topic: "tele/ESP-ir/LWT"
    qos: 1
    payload_on: '{"Protocol":"nec","Data":0x4EBB58A7,"Bits":"32"}'
    payload_available: "Online"
    payload_not_available: "Connection Lost"
    retain: false   
1 Like

How did you manage to add the fold-entity-row to expand your paper-button-row ?

Both button rows and the mini media player can be used in an entities: list, either in the vanilla entities card or something like fold row. So it works exactly the same way you would for any other entity in a fold row :slight_smile: the button rows can be dropped into the fold row entities: list just like a regular entity, and from there I just have a couple of layers of nesting. I can share the full config if it helps, but it gets a bit convoluted, so I thought this snippet might make it clear:

- type: custom:fold-entity-row
  padding: 0
  open: false
  head:
    entity: media_player.loungeroom_tv
    type: custom:mini-media-player
    hide:
      volume: true
      controls: true
      power_state: false
    group: true
  entities:
    - type: custom:paper-buttons-row
      base_config:
        style:
          button:
            margin: 20px
            color: var(--primary-text-color)
            background-color: '#434C5E'
            padding: 0px
            '--mdc-icon-size': 34px
      buttons:
        - icon: mdi:television-classic
          name: Television
          style:
            button:
              margin-left: auto
              margin-right: 22px
              background-color: none
              font-size: 1.2em
            icon:
              margin-left: '-4px'
        - icon: mdi:power
          tap_action:
            action: call-service
            service: media_player.toggle
            service_data:
              entity_id: media_player.samsung_tv_power
          style:
            button:
              background-color: '#434C5E'
              border-radius: 38px
              '--mdc-icon-size': 22px
              padding: 4px 14px
              margin-right: auto
              margin-left: 4px
    - type: custom:paper-buttons-row
      base_config:
        style:
          button:
            margin: 0px 0px 10px 0px
            padding: 7px
            color: var(--primary-text-color)
            background-color: '#434C5E'
            border-radius: 15px
            '--mdc-icon-size': 38px
      buttons:
        - icon: mdi:numeric-1
          style:
            button:
              margin-left: auto
              margin-right: 16px
        - icon: mdi:numeric-2
        - icon: mdi:numeric-3
          style:
            button:
              margin-right: auto
              margin-left: 16px

I also overrode the fold row icon in the HACS files, so it’s the plus/minus symbol instead of the usual chevron

1 Like

Heres my remote for our theater room. I use a ipad to control it with homeassistant.

5 Likes

Please tell us your code :)))