Universal Remote Widget

Hello all,

Basically I am working to create a single virtual universal remote widget to control everything in my home theatre setup (Projector/Receiver/KODI mainly today). I stumbled across and built upon this excellent Harmony widget as a starting point for my first custom widget (thanks a lot to @craigers and @matt1 here!):

https://community.openhab.org/t/oh3-harmony-widget/112172/7?u=d0t

To get started I was able to rapidly modify the widgets in the thread above, add some additional configurations, and create a single remote that could do mostly what I was after - controlling KODI for playback/pause/stop, and a rule for the power button which would power on/off both the PC/Receiver/BenQ Projector (thanks @mlobstein!), and have volume/mute controlled by the Receiver. It was relatively easy to wire in via YAML and control a set of devices/items mapped in the widgets config, by adding new Widget config options (Props > Parameters) for the items I wanted to control. But is it possible to dynamically switch Props configuration within a Widget, based on other options?

For example, in my screenshot below, I’d like the Screen button in the top right and corner popup and allow the user to select the device they want to control (defined when ‘picking’ which things to control in the Widget config), so its possible to more generically control and navigate through each devices menus using the same virtual remote/buttons. At the same time, I understand how this can ‘break down’ quick as you consider the many different types of things/items/states and how the mapping could be very different… And It’s unclear to me if handling such mappings are even possible today within the Widget definition itself, beyond just picking items. (i.e. ideally nesting of the configuration so that the selected device could map all Widget buttons to a different set of items)

After heavily revising the UI, here is where I am currently at, which was strongly inspired by my favorite physical remote - the Harmony One:

For you OH3 UI Widget guru’s out there - would you recommend that I just continue forward with one to one mappings for each button/item in the Widget configuration and drop the thought of device switching for now?

Resources

(edit - @ysc: Added the code from post #4) & updated the screenshot

uid: harmonyOne-v5
tags: []
props:
  parameters:
    - context: item
      description: Select the Displays Power Channel (i.e. Projector or Television power switch)
      label: Select Item
      name: power
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Mute (i.e. Receiver)
      label: Select Item
      name: mute
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Volume (i.e. Receiver)
      label: Select Item
      name: volume
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Player Controls (i.e. KODI MediaControl)
      label: Select Item
      name: player
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Actions (i.e. KODI InputAction, a.k.a Execute An Action)
      label: Select Item
      name: inputaction
      required: true
      type: TEXT
    - context: item
      description: Select the item to display on the Virtual Screen (i.e. KODI Title)
      label: Select Item
      name: screen
      required: true
      type: TEXT
    - context: item
      description: Select the item to display when Virtual Screen is unavailable (i.e. Date/Time).
      label: Select Item
      name: date
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Mar 7, 2021, 5:55:58 PM
component: f7-card
config:
  style:
    background-color: rgb(0, 0, 0)
    --f7-card-margin-horizontal: 0px
    border-radius: 50px
    width: 20rem
    height: 44rem
    box-shadow: 0px 1px 4px -2px
    text-shadow: 0px -1px
slots:
  default:
    - component: Label
      config:
        style:
          position: absolute
          left: 125px
          top: 15px
          color: white
          font-size: 18px
          line-height: 32px
          white-space: nowrap
          overflow: hidden
          text-overflow: ellipsis
          text-shadow: -1px 1px 1px hsl(0,0%,66%)
    - component: oh-button
      config:
        iconF7: power
        iconSize: 15
        #textColor: white
        bgColor: black
        action: command
        actionCommand: "=(items[props.power].state === 'OFF') ? 'ON' : 'OFF' "
        actionItem: =props.power
        style:
          position: absolute
          left: 20px
          top: 15px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          color: "=(items[props.power].state === 'OFF') ? 'white' : 'red' "
          height: 34px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 110px
          left: 5px
          color: white
        iconF7: arrowtriangle_left_fill
        iconSize: 30
        action: command
        actionCommand: PLAY
        actionItem: =props.harmony+"_PlayerControl"
    - component: oh-button
      config:
        #text: "=(items[props.screen] && items[props.screen].state !== undefined ? items[props.screen].state : items[props.date].state)"
        #"=(props.forecastHours === undefined) ? 12 : Number(props.forecastHours)"
        #text: "=(props.screen !== undefined) ? props.screen : props.date"
        #text: "=(items[props.date].state)"
        #text: "=(items[props.screen] !== undefined) ? =(items[props.screen].state) : =(items[props.date].state)"
        text: "=(items[props.screen].state !== 'UNDEF' ? items[props.screen].state : items[props.date].state)"
        #text: "=(items[props.screen].state && items[props.screen].state !== 'UNDEF' ? items[props.screen].state : items[props.date].state)"
        raised: true
        large: true
        textColor: white
        bgColor: black
        #action: options
        #actionItem: =props.harmony+"_CurrentActivity"
        style:
          position: absolute
          right: 35px
          top: 60px
          width: 250px
          height: 130px
          #word-wrap: break-word
          word-break: break-word
          white-space: pre-wrap
          line-height: 1.5
          box-shadow: inset 0 0 2px
    - component: oh-link
      config:
        style:
          position: absolute
          top: 110px
          right: 5px
          color: white
        iconF7: arrowtriangle_right_fill
        iconSize: 30
        action: command
        actionCommand: PLAY
        actionItem: =props.harmony+"_PlayerControl"
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 130px
          top: 550px
          width: 60px
          height: 120px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 550px
          left: 132px
          color: white
          border-bottom: 1px solid gray
        iconF7: play
        iconSize: 60
        action: command
        actionCommand: PLAY
        actionItem: =props.player
    - component: oh-link
      config:
        style:
          position: absolute
          top: 625px
          left: 148px
          color: white
        iconF7: pause
        iconSize: 25
        action: command
        actionCommand: PAUSE
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 550px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 597px
          left: 65px
          color: white
        iconF7: backward_end_alt
        iconSize: 25
        action: command
        actionCommand: PREVIOUS
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 595px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 552px
          left: 65px
          color: white
        iconF7: backward
        iconSize: 25
        action: command
        actionCommand: REWIND
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 595px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 597px
          right: 65px
          color: white
        iconF7: forward_end_alt
        iconSize: 25
        action: command
        actionCommand: NEXT
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 550px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 552px
          right: 65px
          color: white
        iconF7: forward
        iconSize: 25
        action: command
        actionCommand: FASTFORWARD
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 640px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 642px
          left: 65px
          color: red
        iconF7: circle_fill
        iconSize: 25
        action: command
        actionCommand: record
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 640px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 642px
          right: 65px
          color: white
        iconF7: stop_fill
        iconSize: 25
        action: command
        actionCommand: stop
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 50px
          top: 210px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          $transform: skew(20deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 215px
          right: 60px
          color: white
        text: MENU
        action: command
        actionCommand: contextmenu
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 144px
          top: 195px
          width: 32px
          height: 50px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 200px
          left: 150px
          color: white
          border-bottom: 1px solid gray
        iconF7: arrowtriangle_up
        iconSize: 20
        action: command
        actionCommand: pageup
        actionItem: =props.inputaction
    - component: oh-link
      config:
        style:
          position: absolute
          top: 222px
          left: 150px
          color: white
        iconF7: arrowtriangle_down
        iconSize: 20
        action: command
        actionCommand: pagedown
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 50px
          top: 210px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          $transform: skew(-45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 215px
          left: 66px
          color: white
        text: EXIT
        action: command
        actionCommand: back
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 260px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(-45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 267px
          left: 47px
          color: white
        iconF7: speaker_3
        iconSize: 25
        action: command
        actionCommand: INCREASE
        actionItem: =props.volume
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 125px
          top: 255px
          width: 70px
          height: 40px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 267px
          left: 143px
          color: white
          z-index: 2
        iconF7: arrowtriangle_up
        iconSize: 35
        action: command
        actionCommand: up
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 260px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 268px
          right: 47px
          color: white
        iconF7: arrow_up_square
        iconSize: 25
        action: command
        actionCommand: channelup
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 65px
          top: 315px
          width: 60px
          height: 70px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 333px
          left: 71px
          color: white
          z-index: 2
        iconF7: arrowtriangle_left
        iconSize: 35
        action: command
        actionCommand: left
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 127px
          top: 318px
          width: 65px
          height: 65px
          border-radius: 50%
          z-index: 2
    - component: f7-badge
      config:
        bgColor: gray
        style:
          position: absolute
          left: 80px
          top: 270px
          width: 160px
          height: 160px
          transform: rotate(45deg)
          border-radius: 50px/50px
          background-image: "linear-gradient(300deg, #1C1C1C 10%, #494949 360%)"
          z-index: 1
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 130px
          top: 320px
          width: 60px
          height: 60px
          border-radius: 60px
          background-image: "linear-gradient(360deg, #1C1C1C 1%, #494949 90%)"
          z-index: 3
    - component: oh-link
      config:
        text: OK
        style:
          font-size: 18px
          position: absolute
          top: 337px
          left: 148px
          color: white
          z-index: 3
        action: command
        actionCommand: select
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 65px
          top: 315px
          width: 60px
          height: 70px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 333px
          right: 71px
          color: white
        iconF7: arrowtriangle_right
        iconSize: 35
        action: command
        actionCommand: right
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 125px
          top: 380px
          width: 70px
          height: 60px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 400px
          left: 142px
          color: white
        iconF7: arrowtriangle_down
        iconSize: 35
        action: command
        actionCommand: down
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 400px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 406px
          left: 47px
          color: white
        iconF7: speaker_1
        iconSize: 25
        action: command
        actionCommand: DECREASE
        actionItem: =props.volume
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 400px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(-45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 408px
          right: 47px
          color: white
        iconF7: arrow_down_square3
        iconSize: 25
        action: command
        actionCommand: channeldown
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 55px
          top: 455px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 457px
          left: 72px
          color: "=(items[props.mute].state === 'OFF') ? 'white' : 'red' "
        iconF7: speaker_slash_rtl
        iconSize: 25
        action: command
        actionCommand: "=(items[props.mute].state === 'OFF') ? 'ON' : 'OFF' "
        actionItem: =props.mute
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 55px
          top: 455px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          $transform: skew(-25deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 457px
          right: 73px
          color: white
        iconF7: arrow_uturn_left
        iconSize: 25
        action: command
        actionCommand: back
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 80px
          top: 500px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 505px
          left: 90px
          color: white
        text: GUIDE
        action: command
        actionCommand: osd
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 80px
          top: 500px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 505px
          right: 94px
          color: white
        text: INFO
        action: command
        actionCommand: info
        actionItem: =props.inputaction

2 Likes

Your remote looks good already. And the goal to make it more universal by adding not only routines but devices as well will give you/us a great widget. Hope you can make it and get the support here, if you need it. I can’t give technical help (OH-beginner) but maybe give feedback when it comes to functionality.

1 Like

Here is a pic of the latest version of this widget - which utilizes some layout and styling cues from the Harmony Elite…

All ears for any and all feedback here. Working to design the IDEAL virtual remote control for your home theatre, too! :slight_smile:

4 Likes

After studying all of the nuances between things/items/states, I decided to go for the one-to-one mappings between buttons & items to start; maybe in the future I’ll break down and just buy the Harmony Elite & Hub to handle the rest to make this truly ‘Universal’ - the easier way forward. Here is my latest code which works pretty darn good already, assuming your using KODI as the Media Player. A few notes:

  • For volume/mute/power controls, you may need to tweak the ActionCommand’s within the Widgets YML for your setup (i.e. the state/command your items/hardware expects).

  • Some KODI addons are a little quirky for how they update the OH items states.

  • The virtual screen needs better handling of ‘undefined’ when everything is powered off.

  • The virtual screen left/right buttons don’t do anything useful, yet…

Otherwise, this has been working great for my personal needs overall! The screenshot:

And finally, here is the latest working Widget YAML code! Eventually I’ll get this into a github repo, but here now for initial release:

uid: harmonyOne-v5
tags: []
props:
  parameters:
    - context: item
      description: Select the Displays Power Channel (i.e. Projector or Television power switch)
      label: Select Item
      name: power
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Mute (i.e. Receiver)
      label: Select Item
      name: mute
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Volume (i.e. Receiver)
      label: Select Item
      name: volume
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Player Controls (i.e. KODI MediaControl)
      label: Select Item
      name: player
      required: true
      type: TEXT
    - context: item
      description: Select the item to use for Actions (i.e. KODI InputAction, a.k.a Execute An Action)
      label: Select Item
      name: inputaction
      required: true
      type: TEXT
    - context: item
      description: Select the item to display on the Virtual Screen (i.e. KODI Title)
      label: Select Item
      name: screen
      required: true
      type: TEXT
    - context: item
      description: Select the item to display when Virtual Screen is unavailable (i.e. Date/Time).
      label: Select Item
      name: date
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Mar 7, 2021, 5:55:58 PM
component: f7-card
config:
  style:
    background-color: rgb(0, 0, 0)
    --f7-card-margin-horizontal: 0px
    border-radius: 50px
    width: 20rem
    height: 44rem
    box-shadow: 0px 1px 4px -2px
    text-shadow: 0px -1px
slots:
  default:
    - component: Label
      config:
        style:
          position: absolute
          left: 125px
          top: 15px
          color: white
          font-size: 18px
          line-height: 32px
          white-space: nowrap
          overflow: hidden
          text-overflow: ellipsis
          text-shadow: -1px 1px 1px hsl(0,0%,66%)
    - component: oh-button
      config:
        iconF7: power
        iconSize: 15
        #textColor: white
        bgColor: black
        action: command
        actionCommand: "=(items[props.power].state === 'OFF') ? 'ON' : 'OFF' "
        actionItem: =props.power
        style:
          position: absolute
          left: 20px
          top: 15px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          color: "=(items[props.power].state === 'OFF') ? 'white' : 'red' "
          height: 34px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 110px
          left: 5px
          color: white
        iconF7: arrowtriangle_left_fill
        iconSize: 30
        action: command
        actionCommand: PLAY
        actionItem: =props.harmony+"_PlayerControl"
    - component: oh-button
      config:
        #text: "=(items[props.screen] && items[props.screen].state !== undefined ? items[props.screen].state : items[props.date].state)"
        #"=(props.forecastHours === undefined) ? 12 : Number(props.forecastHours)"
        #text: "=(props.screen !== undefined) ? props.screen : props.date"
        #text: "=(items[props.date].state)"
        #text: "=(items[props.screen] !== undefined) ? =(items[props.screen].state) : =(items[props.date].state)"
        text: "=(items[props.screen].state !== 'UNDEF' ? items[props.screen].state : items[props.date].state)"
        #text: "=(items[props.screen].state && items[props.screen].state !== 'UNDEF' ? items[props.screen].state : items[props.date].state)"
        raised: true
        large: true
        textColor: white
        bgColor: black
        #action: options
        #actionItem: =props.harmony+"_CurrentActivity"
        style:
          position: absolute
          right: 35px
          top: 60px
          width: 250px
          height: 130px
          #word-wrap: break-word
          word-break: break-word
          white-space: pre-wrap
          line-height: 1.5
          box-shadow: inset 0 0 2px
    - component: oh-link
      config:
        style:
          position: absolute
          top: 110px
          right: 5px
          color: white
        iconF7: arrowtriangle_right_fill
        iconSize: 30
        action: command
        actionCommand: PLAY
        actionItem: =props.harmony+"_PlayerControl"
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 130px
          top: 550px
          width: 60px
          height: 120px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 550px
          left: 132px
          color: white
          border-bottom: 1px solid gray
        iconF7: play
        iconSize: 60
        action: command
        actionCommand: PLAY
        actionItem: =props.player
    - component: oh-link
      config:
        style:
          position: absolute
          top: 625px
          left: 148px
          color: white
        iconF7: pause
        iconSize: 25
        action: command
        actionCommand: PAUSE
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 550px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 597px
          left: 65px
          color: white
        iconF7: backward_end_alt
        iconSize: 25
        action: command
        actionCommand: PREVIOUS
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 595px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 552px
          left: 65px
          color: white
        iconF7: backward
        iconSize: 25
        action: command
        actionCommand: REWIND
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 595px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 597px
          right: 65px
          color: white
        iconF7: forward_end_alt
        iconSize: 25
        action: command
        actionCommand: NEXT
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 550px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 552px
          right: 65px
          color: white
        iconF7: forward
        iconSize: 25
        action: command
        actionCommand: FASTFORWARD
        actionItem: =props.player
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 640px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 642px
          left: 65px
          color: red
        iconF7: circle_fill
        iconSize: 25
        action: command
        actionCommand: record
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 640px
          width: 90px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 642px
          right: 65px
          color: white
        iconF7: stop_fill
        iconSize: 25
        action: command
        actionCommand: stop
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 50px
          top: 210px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          $transform: skew(20deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 215px
          right: 60px
          color: white
        text: MENU
        action: command
        actionCommand: contextmenu
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 144px
          top: 195px
          width: 32px
          height: 50px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 200px
          left: 150px
          color: white
          border-bottom: 1px solid gray
        iconF7: arrowtriangle_up
        iconSize: 20
        action: command
        actionCommand: pageup
        actionItem: =props.inputaction
    - component: oh-link
      config:
        style:
          position: absolute
          top: 222px
          left: 150px
          color: white
        iconF7: arrowtriangle_down
        iconSize: 20
        action: command
        actionCommand: pagedown
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 50px
          top: 210px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          $transform: skew(-45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 215px
          left: 66px
          color: white
        text: EXIT
        action: command
        actionCommand: back
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 260px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(-45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 267px
          left: 47px
          color: white
        iconF7: speaker_3
        iconSize: 25
        action: command
        actionCommand: INCREASE
        actionItem: =props.volume
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 125px
          top: 255px
          width: 70px
          height: 40px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 267px
          left: 143px
          color: white
          z-index: 2
        iconF7: arrowtriangle_up
        iconSize: 35
        action: command
        actionCommand: up
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 260px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 268px
          right: 47px
          color: white
        iconF7: arrow_up_square
        iconSize: 25
        action: command
        actionCommand: channelup
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 65px
          top: 315px
          width: 60px
          height: 70px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 333px
          left: 71px
          color: white
          z-index: 2
        iconF7: arrowtriangle_left
        iconSize: 35
        action: command
        actionCommand: left
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 127px
          top: 318px
          width: 65px
          height: 65px
          border-radius: 50%
          z-index: 2
    - component: f7-badge
      config:
        bgColor: gray
        style:
          position: absolute
          left: 80px
          top: 270px
          width: 160px
          height: 160px
          transform: rotate(45deg)
          border-radius: 50px/50px
          background-image: "linear-gradient(300deg, #1C1C1C 10%, #494949 360%)"
          z-index: 1
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 130px
          top: 320px
          width: 60px
          height: 60px
          border-radius: 60px
          background-image: "linear-gradient(360deg, #1C1C1C 1%, #494949 90%)"
          z-index: 3
    - component: oh-link
      config:
        text: OK
        style:
          font-size: 18px
          position: absolute
          top: 337px
          left: 148px
          color: white
          z-index: 3
        action: command
        actionCommand: select
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 65px
          top: 315px
          width: 60px
          height: 70px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 333px
          right: 71px
          color: white
        iconF7: arrowtriangle_right
        iconSize: 35
        action: command
        actionCommand: right
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 125px
          top: 380px
          width: 70px
          height: 60px
          border-radius: 50%
    - component: oh-link
      config:
        style:
          position: absolute
          top: 400px
          left: 142px
          color: white
        iconF7: arrowtriangle_down
        iconSize: 35
        action: command
        actionCommand: down
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 30px
          top: 400px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 406px
          left: 47px
          color: white
        iconF7: speaker_1
        iconSize: 25
        action: command
        actionCommand: DECREASE
        actionItem: =props.volume
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 30px
          top: 400px
          width: 60px
          height: 40px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          transform: skew(-45deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 408px
          right: 47px
          color: white
        iconF7: arrow_down_square3
        iconSize: 25
        action: command
        actionCommand: channeldown
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 55px
          top: 455px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 457px
          left: 72px
          color: "=(items[props.mute].state === 'OFF') ? 'white' : 'red' "
        iconF7: speaker_slash_rtl
        iconSize: 25
        action: command
        actionCommand: "=(items[props.mute].state === 'OFF') ? 'ON' : 'OFF' "
        actionItem: =props.mute
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 55px
          top: 455px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          $transform: skew(-25deg)
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 457px
          right: 73px
          color: white
        iconF7: arrow_uturn_left
        iconSize: 25
        action: command
        actionCommand: back
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          left: 80px
          top: 500px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 505px
          left: 90px
          color: white
        text: GUIDE
        action: command
        actionCommand: osd
        actionItem: =props.inputaction
    - component: f7-badge
      config:
        bgColor: black
        style:
          position: absolute
          right: 80px
          top: 500px
          width: 60px
          height: 30px
          border-radius: 12px
          box-shadow: 0px 2px 5px
          background-image: "linear-gradient(360deg, #1C1C1C 10%, #494949 360%)"
    - component: oh-link
      config:
        style:
          position: absolute
          top: 505px
          right: 94px
          color: white
        text: INFO
        action: command
        actionCommand: info
        actionItem: =props.inputaction

4 Likes

Bummer - Logitech is stopping production of Harmony remotes. Guessing the major task of supporting an ever increasing number of devices on the market played a role with this decision:

well that just sucks.

1 Like

@digitaldan - Agreed. Harmony Remotes are/were the best of breed for universal remotes!

That is disappointing. At least they say they’ll continue to keep the service running indefinitely. In the meantime, hopefully someone will come up with a way to program them without needing Logitech’s servers.

2 Likes

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

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

@d0t Your widget may need this to be installable.

work around until this is done, is to create the widget by cut and pasting the code into the developers tools yourself.