Garagedoor widget

Hi, I am creating a widget for a garagedoor or an accessgate.

The functions of the widget are as follows: open or close a garage door or an access gate, display different icons when the door or gate is closed or open, show text indicating whether automatic closing is enabled or not (if the garagedoor/gate control has this function). This can be activated or deactivated by a long press on the widget. Provide text about whether the door is opening, closing, open, or closed, if the garagedoor/gate control has this capability.

  • I have the following issues: firstly, in areas where there is text or an icon, the widget cannot be pressed, only in the areas around the text and the icon.

  • Another problem is that I would like to make it possible to choose which Iconify icon is used via props, but I cannot find the right solution and have therefore currently hard-coded it.

  • One last thing is that I want to hide label areas if there are no items that match. As it is now, it says “Set Props” and there is a small line where the text indicating what the door is doing appears.

Here is what I have done so far.

uid: Garagedoor_Gate
tags: []
props:
  parameters:
    - description: Small title on top of the card
      label: Title
      name: title
      required: false
      type: TEXT
    - description: Name for auto-close in your own language
      label: auto-close
      name: auto_close
      required: false
      type: TEXT
    - description: Iconify icon for closes state
      label: Iconify icon for closes state
      name: icon_closed
      required: false
      type: TEXT
    - description: Iconify icon for open state
      label: Iconify icon for open state
      name: icon_open
      required: false
      type: TEXT
    - description: rgba or HEX
      label: Background Color when open
      name: bgcolor
      required: false
      type: TEXT
    - context: item
      description: sensor Item for open or closed state
      label: Item that has state of the door/gate
      name: sensor
      required: false
      type: TEXT
    - context: item
      description: String item which holds a text state from your garagedoor
      label: Item
      name: text_state
      required: false
      type: TEXT
    - description: A Word for the actionFeedback in your language
      label: actionFeedback
      name: name_for_actionFeedback
      required: false
    - context: item
      description: Item controlling the garagedoor/Gate
      label: Garagedoor/Gate
      name: Garagedoor_control_item
      required: false
      type: TEXT
    - context: item
      description: Item controlling auto-close
      label: auto-close
      name: autoclose_Control_item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Feb 28, 2024, 7:53:42 PM
component: f7-card
config:
  style:
    background-color: >
      =props.sensor && items[props.sensor].state === 'OPEN' ? props.bgcolor : ''
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: '=(items[props.Garagedoor_control_item].state === "ON") ? "3px 3px 10px 0px rgba(255,255,255,255)" : "var(--f7-card-expandable-box-shadow)"'
    class:
      - padding: 0px
    height: 150px
    margin-left: 5px
    margin-right: 5px
    noShadow: false
slots:
  content:
    - component: f7-block
      config:
        style:
          display: flex
          flex-direction: row
          left: 30px
          position: absolute
          top: -5px
      slots:
        default:
          - component: oh-icon
            config:
              height: 36
              icon: '= (items[props.sensor].state === "OPEN") ? "iconify:mdi:garage-open-variant" : "iconify:mdi:garage-variant"'
              style:
                margin-right: 10px
              visible: "=props.icon_open || props.icon_closed ? true : false"
          - component: Label
            config:
              style:
                font-size: 25px
                margin-top: 0px
              text: "=props.title ? props.title : ''"
    - component: f7-block
      config:
        style:
          bottom: -30px
          flex-direction: column
          left: 30px
          position: absolute
      slots:
        default:
          - component: Label
            config:
              style:
                font-size: 20px
                font-weight: 600
                margin-bottom: 18px
                margin-left: 0px
                margin-top: 0px
              text: >
                =props.auto_close ? 
                  (props.autoclose_Control_item && items[props.autoclose_Control_item].state === 'ON' ? 
                    props.auto_close + ' - On' : 
                    props.auto_close + ' - Off') 
                  : 'Set Props'
          - component: Label
            config:
              style:
                font-size: 18px
                margin-bottom: -50px
                margin-left: 32px
                margin-top: 0px
              text: "=items[props.text_state] ? items[props.text_state].state : ''"
              v-if: =props.text_state && items[props.text_state] && items[props.text_state].state !== undefined
    - component: oh-button
      config:
        action: toggle
        actionCommand: ON
        actionCommandAlt: OFF
        actionFeedback: =props.name_for_actionFeedback
        actionItem: =props.Garagedoor_control_item
        style:
          actionPosition: center
          height: 150px
          left: 0
          position: absolute
          top: 0
          width: 100%
        taphold_action: toggle
        taphold_actionCommand: ON
        taphold_actionCommandAlt: OFF
        taphold_actionItem: =props.autoclose_Control_item

The widget is built on the ‘Integer’ simple cell card: [OH3] Main UI Examples - #30 by Integer

In advance, thank you for any input you may provide.

Anders

There are two ways to fix this. 1) Just about anything that is in the way of clicking on the button can have the style pointer-events: none applied to it. This will cause click events to “pass-through” that element to the elements below it. 2) Probably the better solution long-term is to build all of the widget parts as children of the oh-button instead of trying to add the button in addition. So instead of the f7-block that holds all the icons and labels, just use the oh-button and it’s configuration there. The same styles that you add to the block can be applied to the button as well.

The icon property just needs to be a string with contains the icon name, so you just have to build the string out of the different static and dynamic pieces:

icon: '= (items[props.sensor].state === "OPEN") ? "iconify:" + props.icon_open : "iconify:" + props.icon_closed'

However, if you want the to be fully flexible, why restrict it to just the iconify icons. Instead you could just allow the user to input any icon string, oh, f7, or iconify in the property and just use

icon: '= (items[props.sensor].state === "OPEN") ? props.icon_open : props.icon_closed'

You have used the correct property in the oh-icon:

visible: "=props.icon_open || props.icon_closed ? true : false"

But not in the labels:

v-if: =props.text_state && items[props.text_state] && items[props.text_state].state !== undefined

v-if is a feature of the vue code that builds converts the widgets to the page html, but it is not recognized as a custom widget parameter. You can use the same visible property that you used for the oh-icon on any component in a widget.

However, your expressions are not doing what you expect.

props.icon_open || props.icon_closed ? true : false

The expression order of operations means that this expression is actually evaluated like this:

props.icon_open || (props.icon_closed ? true : false)

In this case it doesn’t actually matter because the results are the same. You also never need to use the true and false as the results of a ternary expression because that’s redundant. (test) ? true : false says “If my test returns true then return true and if my test returns false then return false.” You only need the ternary syntax when you want the result of a boolean expression to return something other than true or false. So in this case all you need is:

visible: =props.icon_open || props.icon_closed

For the label, your expression

props.text_state && items[props.text_state] && items[props.text_state].state !== undefined

will only return false if props.text_state has not been set in the widget. The two calls to the items object will never be undefined even if the item name given doesn’t exist. The items object is not a true dictionary in that it has a special property where it returns "-" as the state of any call to a non-existent item:
image

You can just test for that "-" state:

visible: =items[props.text_state].state != "-"
1 Like