Remote Control Widget

Hello,
I created a Remote Control Widget that I use with OH3 to control my TV and Satellite receiver via the
Broadlink Binding

I don’t know if it can be also used in other scenarios, but I thought I’ll share it anyways :wink:

So to use the widget, you need to have an item that receives the commands and you need to set the commands to send with the buttons. You can also set a label that will be displayed on top of the remote, e.g. TV, Sat, Amp etc.

In my scenario, I have all codes in a .map file, so the screenshot just shows the key to the codes in the .map file, like “TV_PHILIPS_POWER”

Thanks to @d0t and @Christopher_Hemmings , who shared the code of their remotes. This helped me to understand how to create a remote control widget!

edit:
I created a variant with slightly different layout and some extra buttons. See UniversalRemote2.txt
edit2:
Added some more remotes, specific for my equipment. But maybe they can serve as template for someone.

NubertSubwooferRemote

Here is the .yaml of the widget:
UniversalRemote.txt (21.6 KB)
UniversalRemote2.txt (22.3 KB)
PhilipsTvRemote.txt (19.8 KB)
DenonAmpRemote.txt (29.6 KB)
NubertSubwooferRemote.txt (4.2 KB)

11 Likes

Thanks for sharing this remote! Good work!

I think, i will try to adapt it soon to my LG TV with WebOS. If someone already did it before, it would also be great if it could be shared.

That is one extremely cool looking widget!
Awesome job!!! :+1:

Really looks nice.

I wonder what creates these text files?
Is this hand-coded?
Or is there a tool creating these files? Which one?

I use only the widget editor in OH3. Don’t know if there are other tools.

Hello. thank you for the remote control.I have a question! I installed your widget and configured the broadlink remote.when I send commands through the widget the LED on the remote flashes 5 times.The widget sends the command 5 times.This is not convenient.how to make the widget send a command 1 time

Hello, I just checked that my broadlink flashes only once when I press a button on the widget.
There is no special logic in the widget that sends the command multiple times. It just sends what you have configured for the button.

thank you for this wonderful widget…

I don’t use it but it gave me a ton of information what one is able to achive with layout-options on yaml… I will use it as a reference for building own widget stuff…
I wasn’t aware of the ability to use all this css stuff - nice!

really great! love it :wink:

1 Like

Great remote widget.
I changed it and added more buttons and also removed the props for the button commands as I only wanted to use it for my TV.
I have a broadlink RM4 clone and I created an item and a rule to control the TV.

I made the rule to use the same name as the actionCommand to be the name of the remote control command.

I also installed this software to run the broadlink to MQTT

EXAMPLE:
To record the command source
mosquitto_pub -h 192.168.0.164 -t broadlink/tv/sony/source -m “record”
to run the command source:
mosquitto_pub -h 192.168.0.164 -t broadlink/tv/sony/source -m “replay”

The source button on the remote has the actionCommand source

Here is the rule:

//need below to log to openhab.log file
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
//below is if you are going to use the ececute command
var Exec = Java.type("org.openhab.core.model.script.actions.Exec");
//below is also needed for the execute command
var Duration = Java.type("java.time.Duration");

//var HttpUtil = Java.type("org.openhab.core.io.net.http.HttpUtil");
//var HttpGet = Java.type("org.openhab.core.model.script.actions.HTTP");

var TOPIC = "broadlink/tv/sony/"

var stateof = event.itemState.toString() ;
//logger.info("results = " + stateof);

result = Exec.executeCommandLine(Duration.ofSeconds(5), "/usr/bin/mosquitto_pub","\-h","192.168.0.164","\-t","" + TOPIC + stateof,"\-m","replay");
logger.info('The script ran the command '  + TOPIC + stateof);

image

Here is the widget code:

uid: Remote Sony TV
tags: []
props:
  parameters:
    - context: item
      description: The item to send the command to
      label: Item
      name: item
      required: false
      type: TEXT
    - description: Type label to display on top of the remote (TV, Sat, Amp etc.)
      label: Device Type
      name: devicetype
      required: false
      type: TEXT
timestamp: Jul 3, 2021, 4:04:34 PM
component: f7-card
config:
  style:
    box-shadow: 2px 3px rgb(150,150,150)
    background-color: rgb(192, 192, 192)
    --f7-card-margin-horizontal: 0px
    border-radius: 30px
    width: 15rem
    height: 46rem
slots:
  default:
    - component: oh-button
      config:
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 20px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        iconF7: power
        iconSize: 25
        action: command
        actionCommand: power
        actionItem: =props.item
    - component: oh-link
      config:
        color: black
        style:
          font-size: 25px
          position: absolute
          left: 90px
          top: 20px
          width: 60px
          height: 40px
          display: flex
        text: '=(props.devicetype) ? props.devicetype : "TV"'
    - component: oh-button
      config:
        bgColor: black
        style:
          position: absolute
          left: 160px
          top: 20px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        iconF7: speaker_slash
        iconSize: 25
        action: command
        actionCommand: volumemute
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 80px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 1
        action: command
        actionCommand: one
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 90px
          top: 80px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 2
        action: command
        actionCommand: two
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 160px
          top: 80px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 3
        action: command
        actionCommand: three
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 130px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 4
        action: command
        actionCommand: four
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 90px
          top: 130px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 5
        action: command
        actionCommand: five
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 160px
          top: 130px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 6
        action: command
        actionCommand: six
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 180px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 7
        action: command
        actionCommand: seven
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 90px
          top: 180px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 8
        action: command
        actionCommand: eight
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 160px
          top: 180px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: 9
        action: command
        actionCommand: nine
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 230px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
        iconF7: house
        iconSize: 25
        action: command
        actionCommand: home
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 90px
          top: 230px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: "0"
        action: command
        actionCommand: zero
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 160px
          top: 230px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
        iconF7: arrow_uturn_left
        iconSize: 25
        action: command
        actionCommand: return
        actionItem: =props.item
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 40px
          top: 290px
          width: 160px
          height: 160px
          transform: rotate(45deg)
          border-radius: 30%
          z-index: 1
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          font-size: 25px
          position: absolute
          left: 80px
          top: 330px
          width: 80px
          height: 80px
          border-radius: 50%
          border: gray solid 1px
          display: flex
          z-index: 2
        text: OK
        action: command
        actionCommand: ok
        actionItem: =props.item
    - component: oh-button
      config:
        color: black
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 285px
          width: 50px
          height: 40px
          border-radius: 20%
          z-index: 1
          transform: skew(-45deg)
        action: command
        actionCommand: volumeup
        actionItem: =props.item
    - component: oh-link
      config:
        color: white
        style:
          position: absolute
          left: 35px
          top: 290px
          display: flex
          z-index: 2
        iconF7: speaker_3
        iconSize: 25
        action: command
        actionCommand: volumeup
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 100px
          top: 285px
          width: 40px
          height: 40px
          display: flex
          z-index: 2
        iconF7: arrowtriangle_up
        iconSize: 35
        action: command
        actionCommand: up
        actionItem: =props.item
    - component: oh-button
      config:
        color: black
        bgColor: black
        style:
          position: absolute
          left: 170px
          top: 285px
          width: 50px
          height: 40px
          border-radius: 20%
          z-index: 1
          transform: skew(45deg)
        action: command
        actionCommand: channelup
        actionItem: =props.item
    - component: oh-link
      config:
        color: white
        style:
          font-size: 20px
          position: absolute
          left: 180px
          top: 290px
          display: flex
          z-index: 2
        text: CH+
        action: command
        actionCommand: channelup
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 35px
          top: 350px
          width: 40px
          height: 40px
          display: flex
          z-index: 2
        iconF7: arrowtriangle_left
        iconSize: 35
        action: command
        actionCommand: left
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 165px
          top: 350px
          width: 40px
          height: 40px
          display: flex
          z-index: 2
        iconF7: arrowtriangle_right
        iconSize: 35
        action: command
        actionCommand: right
        actionItem: =props.item
    - component: oh-button
      config:
        color: black
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 415px
          width: 50px
          height: 40px
          border-radius: 20%
          z-index: 1
          transform: skew(45deg)
        action: command
        actionCommand: volumedown
        actionItem: =props.item
    - component: oh-link
      config:
        color: white
        style:
          position: absolute
          left: 35px
          top: 425px
          display: flex
          z-index: 2
        iconF7: speaker_1
        iconSize: 25
        action: command
        actionCommand: volumedown
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 100px
          top: 415px
          width: 40px
          height: 40px
          display: flex
          z-index: 2
        iconF7: arrowtriangle_down
        iconSize: 35
        action: command
        actionCommand: down
        actionItem: =props.item
    - component: oh-button
      config:
        color: black
        bgColor: black
        style:
          position: absolute
          left: 170px
          top: 415px
          width: 50px
          height: 40px
          border-radius: 20%
          z-index: 1
          transform: skew(-45deg)
        action: command
        actionCommand: channeldown
        actionItem: =props.item
    - component: oh-link
      config:
        color: white
        style:
          font-size: 20px
          position: absolute
          left: 178px
          top: 420px
          display: flex
          z-index: 2
        text: CH-
        action: command
        actionCommand: channeldown
        actionItem: =props.item
    - component: f7-badge
      config:
        bgColor: gray
        style:
          position: absolute
          left: 15px
          top: 465px
          width: 70px
          height: 100px
          border: gray solid 1px
          z-index: 0
    - component: oh-button
      config:
        color: black
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 415px
          width: 50px
          height: 40px
          border-radius: 20%
          z-index: 1
          transform: skew(45deg)
        action: command
        actionCommand: volumedown
        actionItem: =props.item
    - component: oh-link
      config:
        color: white
        style:
          position: absolute
          left: 35px
          top: 425px
          display: flex
          z-index: 2
        iconF7: speaker_1
        iconSize: 25
        action: command
        actionCommand: volumedown
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 470px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
          z-index: 1
        text: Subtitle
        iconSize: 30
        action: command
        actionCommand: subtitle
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 20px
          top: 520px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
          z-index: 1
        text: Source
        iconSize: 30
        action: command
        actionCommand: source
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 90px
          top: 470px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: EPG
        action: command
        actionCommand: guide
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 90px
          top: 520px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        text: Info
        action: command
        actionCommand: info
        actionItem: =props.item
    - component: f7-badge
      config:
        bgColor: gray
        style:
          position: absolute
          left: 155px
          top: 465px
          width: 70px
          height: 100px
          border: gray solid 1px
          z-index: 0
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 160px
          top: 470px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
        iconF7: arrow_2_circlepath
        iconSize: 25
        action: command
        actionCommand: recall
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 160px
          top: 520px
          width: 60px
          height: 40px
          border-radius: 12px
          display: flex
          z-index: 1
        text: Option
        action: command
        actionCommand: options
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 25px
          top: 570px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: red
        iconF7: circle_fill
        iconSize: 25
        action: command
        actionCommand: red
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 75px
          top: 570px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: green
        iconF7: circle_fill
        iconSize: 25
        action: command
        actionCommand: green
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 125px
          top: 570px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: yellow
        iconF7: circle_fill
        iconSize: 25
        action: command
        actionCommand: yellow
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 175px
          top: 570px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: blue
        iconF7: circle_fill
        iconSize: 25
        action: command
        actionCommand: blue
        actionItem: =props.item
    - component: f7-badge
      config:
        bgColor: gray
        style:
          position: absolute
          left: 20px
          top: 615px
          width: 200px
          height: 100px
          border: gray solid 1px
          z-index: 0
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 25px
          top: 620px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
          z-index: 1
        iconF7: backward
        iconSize: 25
        action: command
        actionCommand: rewind
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 75px
          top: 620px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
          z-index: 1
        iconF7: play_fill
        iconSize: 25
        action: command
        actionCommand: play
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 125px
          top: 620px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
          z-index: 1
        iconF7: pause
        iconSize: 25
        action: command
        actionCommand: pause
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 175px
          top: 620px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
          z-index: 1
        iconF7: forward
        iconSize: 25
        action: command
        actionCommand: forward
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 25px
          top: 670px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
          z-index: 1
        iconF7: backward_end_alt
        iconSize: 25
        action: command
        actionCommand: previous
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 75px
          top: 670px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
          z-index: 1
        iconF7: stop_fill
        iconSize: 25
        action: command
        actionCommand: stop
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 125px
          top: 670px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: red
          z-index: 1
        iconF7: circle_fill
        iconSize: 20
        action: command
        actionCommand: record
        actionItem: =props.item
    - component: oh-button
      config:
        color: white
        bgColor: black
        style:
          position: absolute
          left: 175px
          top: 670px
          width: 40px
          height: 40px
          border-radius: 12px
          display: flex
          color: white
          z-index: 1
        iconF7: forward_end_alt
        iconSize: 25
        action: command
        actionCommand: next
        actionItem: =props.item

Thanks to the person who created this remote is so handy.

1 Like

But you dont´neeed this external tool - the new Broadlink binding wich is short for release can do all the Magic now…

I added some more remotes in the first post. They are specific to my equipment, but might serve as templates for someone.

2 Likes

Thank you for sharing your templates from which I’ve built my own variant.

I’m now trying to display the widget standalone as a single page or popup so that it is nicely displayed and centered on the screen. I’ve tried to put it within a column of a page with various center styles options, but so far without success. Do you have any clue on how to achive this?

Create a layout page with a block, one row and 3 columns and put the widget in the middle column.
This works at least on my Desktop PC. Don’t know how it looks on smartphone screens or tablets.

config:
  label: Test
  sidebar: true
blocks:
  - component: oh-block
    config: {}
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config: {}
                slots:
                  default: []
              - component: oh-grid-col
                config: {}
                slots:
                  default:
                    - component: widget:UniversalRemote2
                      config: {}
              - component: oh-grid-col
                config: {}
                slots:
                  default: []
masonry: null

Thank you for this hint. However, this seems not to work well for smartphone screens.

Instead, I’ve found a solution for the widget where the card component is wrapped inside a row with proper styling

component: f7-row
config:
  style:
    display: flex
    justify-content: space-around
    flex-wrap: wrap
slots:
  default:
    - component: f7-card
      config:
        style:...

This ensures that the remote control widget is displayed horizontally centered within the page when added to a single column that spans the whole page.

I have problem with installation from marketplace on OH3.2.0-1. In log I get this error:

2022-04-20 12:00:58.217 [ERROR] [munity.CommunityUIWidgetAddonHandler] - Widget from marketplace is invalid: Couldn't find the widget in the add-on entry

I really like your remote widget and want to try to adapt it to my LG tv. I created some widgets that will turn on the tv etc, but I can’t figure out what type of command string your widget uses. You state that you put the key codes for items like TV_PHILIPS_POWER into a .mapfile, but I haven’t figured out what the command string would be. Could you post a few of your command strings from your map file?

The .map file is used by the broadlink-binding, which I use to send the IR commands.
See Map - Transformation Services | openHAB

My .map file contains entries like:

TV_PHILIPS_POWER=26002C005B1C101C100D100E101C1E0E0F0E100D100D100E100D100D100E0F0E100D100D100E1E0E101B100E10000D05000000000000000000000000
TV_PHILIPS_VOL_UP=26002A00591E0D1F0D100E0F2C2E0E0F0E0F0E100D100E0F0E100D100E0F0E0F0E101C1E0E100D100E0F0E000D050000000000000000000000000000
TV_PHILIPS_VOL_DOWN=26003000591E0D1F0D100E0F0E1E1C100E0F0E100D100E0F0E0F0E100D100E0F0E100D101C1E0E100D101C000AA2074D08000D050000000000000000

Thank you for your quick response. I hadn’t read the documentation on the Broadlink binding since I was using the lgwebos binding. I was thinking I was going to send an item channel command and had spent several hours trying to hack my way through. Your .map file examples helped me move on. However, the universal remote widget sends item channel commands, so I’m looking at the two remote widgets to understand how they function differently. I’m new to the widget development language, so it will take me a while to get up to speed.

Thanks again.